kinds.mx raw
1 package kind
2
3 import (
4 "git.smesh.lol/moxie/pkg/mxutil"
5 "git.smesh.lol/nostr/pkg/ints"
6 "git.smesh.lol/nostr/pkg/lol/chk"
7 "git.smesh.lol/nostr/pkg/lol/errorf"
8 )
9
10 type S struct {
11 K []*K
12 }
13
14 func NewS(k ...*K) (s *S) { return &S{k} }
15
16 func (k *S) String() (s string) { return k.Marshal(nil) }
17
18 func NewWithCap(c int32) (s *S) { return &S{[]*K{:0:c}} }
19
20 func FromIntSlice(is []int32) (k *S) {
21 k = &S{}
22 for i := range is {
23 k.K = mxutil.Ensure(k.K, 1)
24 k.K = push(k.K, New(uint16(is[i])))
25 }
26 return
27 }
28
29 func (k *S) Len() (n int32) {
30 if k == nil {
31 return 0
32 }
33 return len(k.K)
34 }
35
36 func (k *S) Less(i, j int32) (ok bool) { return k.K[i].K < k.K[j].K }
37
38 func (k *S) Swap(i, j int32) {
39 k.K[i].K, k.K[j].K = k.K[j].K, k.K[i].K
40 }
41
42 func (k *S) ToUint16() (o []uint16) {
43 for i := range k.K {
44 o = mxutil.Ensure(o, 1)
45 o = push(o, k.K[i].ToU16())
46 }
47 return
48 }
49
50 func (k *S) Clone() (c *S) {
51 c = &S{K: []*K{:len(k.K)}}
52 for i := range k.K {
53 c.K[i] = k.K[i]
54 }
55 return
56 }
57
58 func (k *S) Contains(s uint16) (ok bool) {
59 for i := range k.K {
60 if k.K[i].Equal(s) {
61 return true
62 }
63 }
64 return false
65 }
66
67 func (k *S) Equals(t1 *S) (ok bool) {
68 if len(k.K) != len(t1.K) {
69 return false
70 }
71 for i := range k.K {
72 if k.K[i] != t1.K[i] {
73 return false
74 }
75 }
76 return true
77 }
78
79 func (k *S) Marshal(dst []byte) (b []byte) {
80 b = dst
81 b = b | "["
82 for i := range k.K {
83 b = k.K[i].Marshal(b)
84 if i != len(k.K)-1 {
85 b = b | ","
86 }
87 }
88 b = b | "]"
89 return
90 }
91
92 func (k *S) Unmarshal(b []byte) (r []byte, err error) {
93 r = b
94 var openedBracket bool
95 // Declared outside the loop: a declaration in the body of a self-mutating
96 // method allocates in the sovereign arena on every iteration.
97 var kk *ints.T
98 for ; len(r) > 0; r = r[1:] {
99 if !openedBracket && r[0] == '[' {
100 openedBracket = true
101 continue
102 } else if openedBracket {
103 if r[0] == ']' {
104 return
105 } else if r[0] == ',' {
106 continue
107 }
108 kk = ints.New(0)
109 if r, err = kk.Unmarshal(r); chk.E(err) {
110 return
111 }
112 // push does not grow: a filter with more kinds than the first
113 // lazy-init batch (4) must reserve room first, or parsing a real
114 // filter panics with "push past end of slice capacity".
115 k.K = mxutil.Ensure(k.K, 1)
116 k.K = push(k.K, New(kk.Uint16()))
117 // The remainder can be empty here: `[1` (a truncated kinds array)
118 // read one past the end and the relay died on a malformed REQ.
119 if len(r) > 0 && r[0] == ']' {
120 r = r[1:]
121 return
122 }
123 }
124 }
125 if !openedBracket {
126 return nil, errorf.E([]byte("kinds: failed to unmarshal\n%s\n%s\n%s"), k, b, r)
127 }
128 // An opened list that runs out of input simply ends, the contract `[`
129 // already documented; the bound above is what keeps a truncated array from
130 // reading past its end.
131 return
132 }
133
134 func (k *S) IsPrivileged() (ok bool) {
135 for i := range k.K {
136 if IsPrivileged(k.K[i].K) {
137 return true
138 }
139 }
140 return false
141 }
142