Search Apps Documentation Source Content File Folder Download Copy Actions Download

rotree.gno

4.97 Kb · 151 lines
  1// Package rotree provides a read-only wrapper for bptree.BPTree with safe value transformation.
  2//
  3// It is useful when you want to expose a read-only view of a tree while ensuring that
  4// the sensitive data cannot be modified.
  5//
  6// Example:
  7//
  8//	// Define a user structure with sensitive data
  9//	type User struct {
 10//		Name     string
 11//		Balance  int
 12//		Internal string // sensitive field
 13//	}
 14//
 15//	// Create and populate the original tree
 16//	privateTree := bptree.NewBPTree32()
 17//	privateTree.Set("alice", &User{
 18//		Name:     "Alice",
 19//		Balance:  100,
 20//		Internal: "sensitive",
 21//	})
 22//
 23//	// Create a safe transformation function that copies the struct
 24//	// while excluding sensitive data
 25//	makeEntrySafeFn := func(v any) any {
 26//		u := v.(*User)
 27//		return &User{
 28//			Name:     u.Name,
 29//			Balance:  u.Balance,
 30//			Internal: "", // omit sensitive data
 31//		}
 32//	}
 33//
 34//	// Create a read-only view of the tree
 35//	PublicTree := rotree.Wrap(tree, makeEntrySafeFn)
 36//
 37//	// Safely access the data
 38//	value, _ := roTree.Get("alice")
 39//	user := value.(*User)
 40//	// user.Name == "Alice"
 41//	// user.Balance == 100
 42//	// user.Internal == "" (sensitive data is filtered)
 43package rotree
 44
 45import (
 46	"gno.land/p/nt/bptree/v0"
 47)
 48
 49// Wrap creates a new ReadOnlyTree from an existing bptree.BPTree and a safety transformation function.
 50// If makeEntrySafeFn is nil, values will be returned as-is without transformation.
 51func Wrap(tree *bptree.BPTree, makeEntrySafeFn func(any) any) *ReadOnlyTree {
 52	return &ReadOnlyTree{
 53		tree:            tree,
 54		makeEntrySafeFn: makeEntrySafeFn,
 55	}
 56}
 57
 58// ReadOnlyTree wraps a bptree.BPTree and provides read-only access.
 59type ReadOnlyTree struct {
 60	tree            *bptree.BPTree
 61	makeEntrySafeFn func(any) any
 62}
 63
 64// IReadOnlyTree defines the read-only operations available on a tree.
 65type IReadOnlyTree interface {
 66	Size() int
 67	Has(key string) bool
 68	Get(key string) (any, bool)
 69	GetByIndex(index int) (string, any)
 70	Iterate(start, end string, cb bptree.IterCbFn) bool
 71	ReverseIterate(start, end string, cb bptree.IterCbFn) bool
 72	IterateByOffset(offset int, count int, cb bptree.IterCbFn) bool
 73	ReverseIterateByOffset(offset int, count int, cb bptree.IterCbFn) bool
 74}
 75
 76// Verify that ReadOnlyTree implements both ITree and IReadOnlyTree
 77var (
 78	_ bptree.ITree  = (*ReadOnlyTree)(nil)
 79	_ IReadOnlyTree = (*ReadOnlyTree)(nil)
 80)
 81
 82// getSafeValue applies the makeEntrySafeFn if it exists, otherwise returns the original value
 83func (roTree *ReadOnlyTree) getSafeValue(value any) any {
 84	if roTree.makeEntrySafeFn == nil {
 85		return value
 86	}
 87	return roTree.makeEntrySafeFn(value)
 88}
 89
 90// Size returns the number of key-value pairs in the tree.
 91func (roTree *ReadOnlyTree) Size() int {
 92	return roTree.tree.Size()
 93}
 94
 95// Has checks whether a key exists in the tree.
 96func (roTree *ReadOnlyTree) Has(key string) bool {
 97	return roTree.tree.Has(key)
 98}
 99
100// Get retrieves the value associated with the given key, converted to a safe format.
101func (roTree *ReadOnlyTree) Get(key string) (any, bool) {
102	value, exists := roTree.tree.Get(key)
103	if !exists {
104		return nil, false
105	}
106	return roTree.getSafeValue(value), true
107}
108
109// GetByIndex retrieves the key-value pair at the specified index in the tree, with the value converted to a safe format.
110func (roTree *ReadOnlyTree) GetByIndex(index int) (string, any) {
111	key, value := roTree.tree.GetByIndex(index)
112	return key, roTree.getSafeValue(value)
113}
114
115// Iterate performs an in-order traversal of the tree within the specified key range.
116func (roTree *ReadOnlyTree) Iterate(start, end string, cb bptree.IterCbFn) bool {
117	return roTree.tree.Iterate(start, end, func(key string, value any) bool {
118		return cb(key, roTree.getSafeValue(value))
119	})
120}
121
122// ReverseIterate performs a reverse in-order traversal of the tree within the specified key range.
123func (roTree *ReadOnlyTree) ReverseIterate(start, end string, cb bptree.IterCbFn) bool {
124	return roTree.tree.ReverseIterate(start, end, func(key string, value any) bool {
125		return cb(key, roTree.getSafeValue(value))
126	})
127}
128
129// IterateByOffset performs an in-order traversal of the tree starting from the specified offset.
130func (roTree *ReadOnlyTree) IterateByOffset(offset int, count int, cb bptree.IterCbFn) bool {
131	return roTree.tree.IterateByOffset(offset, count, func(key string, value any) bool {
132		return cb(key, roTree.getSafeValue(value))
133	})
134}
135
136// ReverseIterateByOffset performs a reverse in-order traversal of the tree starting from the specified offset.
137func (roTree *ReadOnlyTree) ReverseIterateByOffset(offset int, count int, cb bptree.IterCbFn) bool {
138	return roTree.tree.ReverseIterateByOffset(offset, count, func(key string, value any) bool {
139		return cb(key, roTree.getSafeValue(value))
140	})
141}
142
143// Set is not supported on ReadOnlyTree and will panic.
144func (roTree *ReadOnlyTree) Set(key string, value any) bool {
145	panic("Set operation not supported on ReadOnlyTree")
146}
147
148// Remove is not supported on ReadOnlyTree and will panic.
149func (roTree *ReadOnlyTree) Remove(key string) (value any, removed bool) {
150	panic("Remove operation not supported on ReadOnlyTree")
151}