1 // Package kinds is a set of helpers for dealing with lists of kind numbers
2 // including comparisons and encoding.
3 package kind
4 5 import (
6 "next.orly.dev/pkg/nostr/encoders/ints"
7 "next.orly.dev/pkg/lol/chk"
8 "next.orly.dev/pkg/lol/errorf"
9 )
10 11 // S is an array of kind.K, used in filter.K and filter.S for searches.
12 type S struct {
13 K []*K
14 }
15 16 // NewS creates a new kinds.S, if no parameter is given it just creates an empty zero kinds.S.
17 func NewS(k ...*K) *S { return &S{k} }
18 19 // NewWithCap creates a new empty kinds.S with a given slice capacity.
20 func NewWithCap(c int) *S { return &S{make([]*K, 0, c)} }
21 22 // FromIntSlice converts a []int into a kinds.S.
23 func FromIntSlice(is []int) (k *S) {
24 k = &S{}
25 for i := range is {
26 k.K = append(k.K, New(uint16(is[i])))
27 }
28 return
29 }
30 31 // Len returns the number of elements in a kinds.S.
32 func (k *S) Len() (l int) {
33 if k == nil {
34 return
35 }
36 return len(k.K)
37 }
38 39 // Less returns which of two elements of a kinds.S is lower.
40 func (k *S) Less(i, j int) bool { return k.K[i].K < k.K[j].K }
41 42 // Swap switches the position of two kinds.S elements.
43 func (k *S) Swap(i, j int) {
44 k.K[i].K, k.K[j].K = k.K[j].K, k.K[i].K
45 }
46 47 // ToUint16 returns a []uint16 version of the kinds.S.
48 func (k *S) ToUint16() (o []uint16) {
49 for i := range k.K {
50 o = append(o, k.K[i].ToU16())
51 }
52 return
53 }
54 55 // Clone makes a new kind.K with the same members.
56 func (k *S) Clone() (c *S) {
57 c = &S{K: make([]*K, len(k.K))}
58 for i := range k.K {
59 c.K[i] = k.K[i]
60 }
61 return
62 }
63 64 // Contains returns true if the provided element is found in the kinds.S.
65 //
66 // Note that the request must use the typed kind.K or convert the number thus.
67 // Even if a custom number is found, this codebase does not have the logic to
68 // deal with the kind so such a search is pointless and for which reason static
69 // typing always wins. No mistakes possible with known quantities.
70 func (k *S) Contains(s uint16) bool {
71 for i := range k.K {
72 if k.K[i].Equal(s) {
73 return true
74 }
75 }
76 return false
77 }
78 79 // Equals checks that the provided kind.K matches.
80 func (k *S) Equals(t1 *S) bool {
81 if len(k.K) != len(t1.K) {
82 return false
83 }
84 for i := range k.K {
85 if k.K[i] != t1.K[i] {
86 return false
87 }
88 }
89 return true
90 }
91 92 // Marshal renders the kinds.S into a JSON array of integers.
93 func (k *S) Marshal(dst []byte) (b []byte) {
94 b = dst
95 b = append(b, '[')
96 for i := range k.K {
97 b = k.K[i].Marshal(b)
98 if i != len(k.K)-1 {
99 b = append(b, ',')
100 }
101 }
102 b = append(b, ']')
103 return
104 }
105 106 // Unmarshal decodes a provided JSON array of integers into a kinds.S.
107 func (k *S) Unmarshal(b []byte) (r []byte, err error) {
108 r = b
109 var openedBracket bool
110 for ; len(r) > 0; r = r[1:] {
111 if !openedBracket && r[0] == '[' {
112 openedBracket = true
113 continue
114 } else if openedBracket {
115 if r[0] == ']' {
116 // done
117 return
118 } else if r[0] == ',' {
119 continue
120 }
121 kk := ints.New(0)
122 if r, err = kk.Unmarshal(r); chk.E(err) {
123 return
124 }
125 k.K = append(k.K, New(kk.Uint16()))
126 if r[0] == ']' {
127 r = r[1:]
128 return
129 }
130 }
131 }
132 if !openedBracket {
133 return nil, errorf.E(
134 "kinds: failed to unmarshal\n%s\n%s\n%s", k,
135 b, r,
136 )
137 }
138 return
139 }
140 141 // IsPrivileged returns true if any of the elements of a kinds.S are privileged (ie, they should
142 // be privacy protected).
143 func (k *S) IsPrivileged() (priv bool) {
144 for i := range k.K {
145 if IsPrivileged(k.K[i].K) {
146 return true
147 }
148 }
149 return
150 }
151