filters.mx raw

   1  package filter
   2  
   3  import (
   4  	"git.smesh.lol/moxie/pkg/mxutil"
   5  	"git.smesh.lol/nostr/pkg/event"
   6  	"git.smesh.lol/nostr/pkg/lol/errorf"
   7  )
   8  
   9  // S is a list of filters. It is a struct holding the slice, not a named slice:
  10  // methods belong on the struct that holds the slice (moxie bans named slice
  11  // types), and every mutation lands in a receiver field the compiler relocates.
  12  type S struct {
  13  	F []*F
  14  }
  15  
  16  func NewS(ff ...*F) (s *S) {
  17  	s = &S{F: ff}
  18  	return
  19  }
  20  
  21  func (s *S) Match(ev *event.E) (ok bool) {
  22  	for _, f := range s.F {
  23  		if f.Matches(ev) {
  24  			return true
  25  		}
  26  	}
  27  	return false
  28  }
  29  
  30  func (s *S) Marshal(dst []byte) (b []byte) {
  31  	if s == nil {
  32  		panic("nil filter slice")
  33  	}
  34  	b = dst
  35  	b = b | "["
  36  	first := false
  37  	for _, f := range s.F {
  38  		if f == nil {
  39  			continue
  40  		}
  41  		if first {
  42  			b = b | ","
  43  		} else {
  44  			first = true
  45  		}
  46  		b = f.Marshal(b)
  47  	}
  48  	b = b | "]"
  49  	return
  50  }
  51  
  52  // UnmarshalFilters parses a filter array, optionally wrapped in '[', and
  53  // returns it by value so the backing array is relocated into the caller's arena.
  54  func UnmarshalFilters(b []byte) (out S, r []byte, err error) {
  55  	r = b
  56  	if len(r) == 0 {
  57  		return
  58  	}
  59  	isArrayWrapped := r[0] == '['
  60  	if isArrayWrapped {
  61  		r = r[1:]
  62  		if len(r) > 0 && r[0] == ']' {
  63  			r = r[1:]
  64  			return
  65  		}
  66  	}
  67  	for {
  68  		if len(r) == 0 {
  69  			return
  70  		}
  71  		f := New()
  72  		var rem []byte
  73  		if rem, err = f.Unmarshal(r); err != nil {
  74  			return
  75  		}
  76  		out.F = mxutil.Ensure(out.F, 1)
  77  		out.F = push(out.F, f)
  78  		r = rem
  79  		if len(r) == 0 {
  80  			return
  81  		}
  82  		if r[0] == ',' {
  83  			r = r[1:]
  84  			continue
  85  		}
  86  		if r[0] == ']' {
  87  			if isArrayWrapped {
  88  				r = r[1:]
  89  			}
  90  			return
  91  		}
  92  		err = errorf.E(
  93  			[]byte("filters.Unmarshal: expected ',' or ']' after filter, got: %q"),
  94  			r[0],
  95  		)
  96  		return
  97  	}
  98  }
  99  
 100  func (s *S) MatchIgnoringTimestampConstraints(ev *event.E) (ok bool) {
 101  	for _, ff := range s.F {
 102  		if ff.MatchesIgnoringTimestampConstraints(ev) {
 103  			return true
 104  		}
 105  	}
 106  	return false
 107  }
 108