Completed
Push — main ( 788e73...fbce6d )
by Igor
28s queued 12s
created

validate.newCharSet   A

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
dl 0
loc 8
rs 10
c 0
b 0
f 0
nop 1
1
package validate
2
3
import "errors"
4
5
var (
6
	ErrTooShort          = errors.New("too short")
7
	ErrTooLong           = errors.New("too long")
8
	ErrTooLarge          = errors.New("too large")
9
	ErrInvalidCharacters = errors.New("invalid characters")
10
)
11
12
var ulidChars = newCharSet("0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz")
13
14
// ULID validates whether the value is a valid ULID (Universally Unique Lexicographically Sortable Identifier).
15
// See https://github.com/ulid/spec for ULID specifications.
16
//
17
// Possible errors:
18
//   - [ErrTooShort] on values with length less than 26;
19
//   - [ErrTooLong] on values with length greater than 26;
20
//   - [ErrInvalidCharacters] on values with unexpected characters;
21
//   - [ErrTooLarge] on too big value (larger than '7ZZZZZZZZZZZZZZZZZZZZZZZZZ').
22
func ULID(value string) error {
23
	if len(value) < 26 {
24
		return ErrTooShort
25
	}
26
	if len(value) > 26 {
27
		return ErrTooLong
28
	}
29
30
	for _, c := range value {
31
		if !ulidChars.Contains(c) {
32
			return ErrInvalidCharacters
33
		}
34
	}
35
36
	// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
37
	// See https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
38
	if value[0] > '7' {
39
		return ErrTooLarge
40
	}
41
42
	return nil
43
}
44
45
type charSet map[rune]struct{}
46
47
func (s charSet) Contains(c rune) bool {
48
	_, exist := s[c]
49
50
	return exist
51
}
52
53
func newCharSet(s string) charSet {
54
	chars := make(charSet, len(s))
55
56
	for _, c := range s {
57
		chars[c] = struct{}{}
58
	}
59
60
	return chars
61
}
62