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