Search Apps Documentation Source Content File Folder Download Copy Actions Download

flag_storage.gno

2.50 Kb · 105 lines
  1package boards
  2
  3import (
  4	"strings"
  5
  6	"gno.land/p/nt/avl/v0"
  7	"gno.land/p/nt/ufmt/v0"
  8)
  9
 10type (
 11	// Flag defines a type for post flags
 12	Flag struct {
 13		// User is the user that flagged the post.
 14		User address
 15
 16		// Reason is the reason that describes why post is flagged.
 17		Reason string
 18	}
 19
 20	// FlagIterFn defines a function type to iterate post flags.
 21	FlagIterFn func(Flag) bool
 22
 23	// FlagStorage defines an interface for storing posts flagging information.
 24	FlagStorage interface {
 25		// Exists checks if a flag from a user exists
 26		Exists(address) bool
 27
 28		// Add adds a new flag from a user.
 29		Add(Flag) error
 30
 31		// Remove removes a user flag.
 32		Remove(address) (removed bool)
 33
 34		// Size returns the number of flags in the storage.
 35		Size() int
 36
 37		// Iterate iterates post flags.
 38		// To reverse iterate flags use a negative count.
 39		// If the callback returns true, the iteration is stopped.
 40		Iterate(start, count int, fn FlagIterFn) bool
 41	}
 42)
 43
 44// NewFlagStorage creates a new storage for post flags.
 45// The new storage uses an AVL tree to store flagging info.
 46func NewFlagStorage() FlagStorage {
 47	return &flagStorage{avl.NewTree()}
 48}
 49
 50type flagStorage struct {
 51	flags *avl.Tree // address -> string(reason)
 52}
 53
 54// Exists checks if a flag from a user exists
 55func (s flagStorage) Exists(addr address) bool {
 56	return s.flags.Has(addr.String())
 57}
 58
 59// Add adds a new flag from a user.
 60// It fails if a flag from the same user exists.
 61func (s *flagStorage) Add(f Flag) error {
 62	if !f.User.IsValid() {
 63		return ufmt.Errorf("post flagging error, invalid user address: %s", f.User)
 64	}
 65
 66	k := f.User.String()
 67	if s.flags.Has(k) {
 68		return ufmt.Errorf("flag from user already exists: %s", f.User)
 69	}
 70
 71	s.flags.Set(k, strings.TrimSpace(f.Reason))
 72	return nil
 73}
 74
 75// Remove removes a user flag.
 76func (s *flagStorage) Remove(addr address) bool {
 77	_, removed := s.flags.Remove(addr.String())
 78	return removed
 79}
 80
 81// Size returns the number of flags in the storage.
 82func (s flagStorage) Size() int {
 83	return s.flags.Size()
 84}
 85
 86// Iterate iterates post flags.
 87// To reverse iterate flags use a negative count.
 88// If the callback returns true, the iteration is stopped.
 89func (s flagStorage) Iterate(start, count int, fn FlagIterFn) bool {
 90	if count < 0 {
 91		return s.flags.ReverseIterateByOffset(start, -count, func(k string, v any) bool {
 92			return fn(Flag{
 93				User:   address(k),
 94				Reason: v.(string),
 95			})
 96		})
 97	}
 98
 99	return s.flags.IterateByOffset(start, count, func(k string, v any) bool {
100		return fn(Flag{
101			User:   address(k),
102			Reason: v.(string),
103		})
104	})
105}