Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

rotree.gno

5.00 Kb · 152 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
 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.
101// It returns the value if the key exists, or nil if it doesn't.
102func (roTree *ReadOnlyTree) Get(key string) any {
103	value := roTree.tree.Get(key)
104	if value == nil {
105		return nil
106	}
107	return roTree.getSafeValue(value)
108}
109
110// GetByIndex retrieves the key-value pair at the specified index in the tree, with the value converted to a safe format.
111func (roTree *ReadOnlyTree) GetByIndex(index int) (string, any) {
112	key, value := roTree.tree.GetByIndex(index)
113	return key, roTree.getSafeValue(value)
114}
115
116// Iterate performs an in-order traversal of the tree within the specified key range.
117func (roTree *ReadOnlyTree) Iterate(start, end string, cb bptree.IterCbFn) bool {
118	return roTree.tree.Iterate(start, end, func(key string, value any) bool {
119		return cb(key, roTree.getSafeValue(value))
120	})
121}
122
123// ReverseIterate performs a reverse in-order traversal of the tree within the specified key range.
124func (roTree *ReadOnlyTree) ReverseIterate(start, end string, cb bptree.IterCbFn) bool {
125	return roTree.tree.ReverseIterate(start, end, func(key string, value any) bool {
126		return cb(key, roTree.getSafeValue(value))
127	})
128}
129
130// IterateByOffset performs an in-order traversal of the tree starting from the specified offset.
131func (roTree *ReadOnlyTree) IterateByOffset(offset int, count int, cb bptree.IterCbFn) bool {
132	return roTree.tree.IterateByOffset(offset, count, func(key string, value any) bool {
133		return cb(key, roTree.getSafeValue(value))
134	})
135}
136
137// ReverseIterateByOffset performs a reverse in-order traversal of the tree starting from the specified offset.
138func (roTree *ReadOnlyTree) ReverseIterateByOffset(offset int, count int, cb bptree.IterCbFn) bool {
139	return roTree.tree.ReverseIterateByOffset(offset, count, func(key string, value any) bool {
140		return cb(key, roTree.getSafeValue(value))
141	})
142}
143
144// Set is not supported on ReadOnlyTree and will panic.
145func (roTree *ReadOnlyTree) Set(key string, value any) bool {
146	panic("Set operation not supported on ReadOnlyTree")
147}
148
149// Remove is not supported on ReadOnlyTree and will panic.
150func (roTree *ReadOnlyTree) Remove(key string) (value any, removed bool) {
151	panic("Remove operation not supported on ReadOnlyTree")
152}