package kind import ( "git.smesh.lol/moxie/pkg/mxutil" "git.smesh.lol/nostr/pkg/ints" "git.smesh.lol/nostr/pkg/lol/chk" "git.smesh.lol/nostr/pkg/lol/errorf" ) type S struct { K []*K } func NewS(k ...*K) (s *S) { return &S{k} } func (k *S) String() (s string) { return k.Marshal(nil) } func NewWithCap(c int32) (s *S) { return &S{[]*K{:0:c}} } func FromIntSlice(is []int32) (k *S) { k = &S{} for i := range is { k.K = mxutil.Ensure(k.K, 1) k.K = push(k.K, New(uint16(is[i]))) } return } func (k *S) Len() (n int32) { if k == nil { return 0 } return len(k.K) } func (k *S) Less(i, j int32) (ok bool) { return k.K[i].K < k.K[j].K } func (k *S) Swap(i, j int32) { k.K[i].K, k.K[j].K = k.K[j].K, k.K[i].K } func (k *S) ToUint16() (o []uint16) { for i := range k.K { o = mxutil.Ensure(o, 1) o = push(o, k.K[i].ToU16()) } return } func (k *S) Clone() (c *S) { c = &S{K: []*K{:len(k.K)}} for i := range k.K { c.K[i] = k.K[i] } return } func (k *S) Contains(s uint16) (ok bool) { for i := range k.K { if k.K[i].Equal(s) { return true } } return false } func (k *S) Equals(t1 *S) (ok bool) { if len(k.K) != len(t1.K) { return false } for i := range k.K { if k.K[i] != t1.K[i] { return false } } return true } func (k *S) Marshal(dst []byte) (b []byte) { b = dst b = b | "[" for i := range k.K { b = k.K[i].Marshal(b) if i != len(k.K)-1 { b = b | "," } } b = b | "]" return } func (k *S) Unmarshal(b []byte) (r []byte, err error) { r = b var openedBracket bool // Declared outside the loop: a declaration in the body of a self-mutating // method allocates in the sovereign arena on every iteration. var kk *ints.T for ; len(r) > 0; r = r[1:] { if !openedBracket && r[0] == '[' { openedBracket = true continue } else if openedBracket { if r[0] == ']' { return } else if r[0] == ',' { continue } kk = ints.New(0) if r, err = kk.Unmarshal(r); chk.E(err) { return } // push does not grow: a filter with more kinds than the first // lazy-init batch (4) must reserve room first, or parsing a real // filter panics with "push past end of slice capacity". k.K = mxutil.Ensure(k.K, 1) k.K = push(k.K, New(kk.Uint16())) // The remainder can be empty here: `[1` (a truncated kinds array) // read one past the end and the relay died on a malformed REQ. if len(r) > 0 && r[0] == ']' { r = r[1:] return } } } if !openedBracket { return nil, errorf.E([]byte("kinds: failed to unmarshal\n%s\n%s\n%s"), k, b, r) } // An opened list that runs out of input simply ends, the contract `[` // already documented; the bound above is what keeps a truncated array from // reading past its end. return } func (k *S) IsPrivileged() (ok bool) { for i := range k.K { if IsPrivileged(k.K[i].K) { return true } } return false }