1package boards23import (4 "errors"56 "gno.land/p/nt/bptree/v0"7)89type (10 // PostIterFn defines a function type to iterate posts.11 PostIterFn func(*Post) bool1213 // PostStorage defines an interface for posts storage.14 PostStorage interface {15 // Get retruns a post that matches an ID.16 Get(ID) (_ *Post, found bool)1718 // Remove removes a post from the storage.19 Remove(ID) (_ *Post, removed bool)2021 // Add adds a post in the storage.22 Add(*Post) error2324 // Size returns the number of posts in the storage.25 Size() int2627 // Iterate iterates posts.28 // To reverse iterate posts use a negative count.29 // If the callback returns true, the iteration is stopped.30 Iterate(start, count int, fn PostIterFn) bool31 }32)3334// NewPostStorage creates a new storage for posts.35// The new storage uses an AVL tree to store posts.36func NewPostStorage() PostStorage {37 return &postStorage{bptree.NewBPTree32()}38}3940type postStorage struct {41 posts *bptree.BPTree // string(Post.ID) -> *Post42}4344// Get retruns a post that matches an ID.45func (s postStorage) Get(id ID) (*Post, bool) {46 k := makePostKey(id)47 v := s.posts.Get(k)48 if v == nil {49 return nil, false50 }51 return v.(*Post), true52}5354// Remove removes a post from the storage.55func (s *postStorage) Remove(id ID) (*Post, bool) {56 k := makePostKey(id)57 v, removed := s.posts.Remove(k)58 if !removed {59 return nil, false60 }61 return v.(*Post), true62}6364// Add adds a post in the storage.65// It updates existing posts when storage contains one with the same ID.66func (s *postStorage) Add(p *Post) error {67 if p == nil {68 return errors.New("saving nil posts is not allowed")69 }7071 s.posts.Set(makePostKey(p.ID), p)72 return nil73}7475// Size returns the number of posts in the storage.76func (s postStorage) Size() int {77 return s.posts.Size()78}7980// Iterate iterates posts.81// To reverse iterate posts use a negative count.82// If the callback returns true, the iteration is stopped.83func (s postStorage) Iterate(start, count int, fn PostIterFn) bool {84 if count < 0 {85 return s.posts.ReverseIterateByOffset(start, -count, func(_ string, v any) bool {86 return fn(v.(*Post))87 })88 }8990 return s.posts.IterateByOffset(start, count, func(_ string, v any) bool {91 return fn(v.(*Post))92 })93}9495func makePostKey(postID ID) string {96 return postID.PaddedString()97}98Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.