-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpath.go
More file actions
134 lines (116 loc) · 2.43 KB
/
path.go
File metadata and controls
134 lines (116 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package html
// Note: this file is WASM-linked. Per RFC §7 the WASM build must stay under the
// 3.5 MB raw / 1 MB gzip size budget, so we deliberately avoid importing
// dappco.re/go/core here — it transitively pulls in fmt/os/log (~500 KB+).
// stdlib strings is safe for WASM.
// ParseBlockID extracts the slot sequence from a data-block ID.
// Usage example: slots := ParseBlockID("C.0.1")
// It accepts the current dotted coordinate form and the older hyphenated
// form for compatibility. Mixed separators and malformed coordinates are
// rejected.
func ParseBlockID(id string) []byte {
if id == "" {
return nil
}
tokens := make([]string, 0, 4)
sepKind := byte(0)
for i := 0; i < len(id); {
start := i
for i < len(id) && id[i] != '.' && id[i] != '-' {
i++
}
token := id[start:i]
if token == "" {
return nil
}
tokens = append(tokens, token)
if i == len(id) {
break
}
sep := id[i]
if sepKind == 0 {
sepKind = sep
} else if sepKind != sep {
return nil
}
i++
if i == len(id) {
return nil
}
}
switch sepKind {
case 0, '.':
return parseDottedBlockID(tokens)
case '-':
return parseHyphenatedBlockID(tokens)
default:
return nil
}
}
func parseDottedBlockID(tokens []string) []byte {
if len(tokens) == 0 || !isSlotToken(tokens[0]) {
return nil
}
if len(tokens) > 1 && isSlotToken(tokens[len(tokens)-1]) {
return nil
}
slots := make([]byte, 0, len(tokens))
slots = append(slots, tokens[0][0])
prevWasSlot := true
for i := 1; i < len(tokens); i++ {
token := tokens[i]
if isSlotToken(token) {
if prevWasSlot {
return nil
}
slots = append(slots, token[0])
prevWasSlot = true
continue
}
if !allDigits(token) {
return nil
}
prevWasSlot = false
}
return slots
}
func parseHyphenatedBlockID(tokens []string) []byte {
if len(tokens) < 2 || len(tokens)%2 != 0 {
return nil
}
if !isSlotToken(tokens[0]) {
return nil
}
slots := make([]byte, 0, len(tokens)/2)
for i, token := range tokens {
switch {
case i%2 == 0:
if !isSlotToken(token) {
return nil
}
slots = append(slots, token[0])
case token != "0":
return nil
}
}
return slots
}
func isSlotToken(token string) bool {
if len(token) != 1 {
return false
}
_, ok := slotRegistry[token[0]]
return ok
}
func allDigits(s string) bool {
if s == "" {
return false
}
for i := 0; i < len(s); i++ {
ch := s[i]
if ch < '0' || ch > '9' {
return false
}
}
return true
}