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}