rolist.gno

3.34 Kb ยท 119 lines
  1// Package rolist provides a read-only wrapper for list.List with safe value transformation.
  2//
  3// It is useful when you want to expose a read-only view of a list 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 list
 16//	privateList := list.New()
 17//	privateList.Append(&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 list
 35//	publicList := rolist.Wrap(list, makeEntrySafeFn)
 36//
 37//	// Safely access the data
 38//	value := publicList.Get(0)
 39//	user := value.(*User)
 40//	// user.Name == "Alice"
 41//	// user.Balance == 100
 42//	// user.Internal == "" (sensitive data is filtered)
 43package rolist
 44
 45import (
 46	"gno.land/p/demo/avl/list"
 47)
 48
 49// IReadOnlyList defines the read-only operations available on a list.
 50type IReadOnlyList interface {
 51	Len() int
 52	Get(index int) any
 53	Slice(startIndex, endIndex int) []any
 54	ForEach(fn func(index int, value any) bool)
 55}
 56
 57// ReadOnlyList wraps a list.List and provides read-only access.
 58type ReadOnlyList struct {
 59	list            *list.List
 60	makeEntrySafeFn func(any) any
 61}
 62
 63// Verify interface implementations
 64var _ IReadOnlyList = (*ReadOnlyList)(nil)
 65var _ IReadOnlyList = (interface{ list.IList })(nil) // is subset of list.IList
 66
 67// Wrap creates a new ReadOnlyList from an existing list.List and a safety transformation function.
 68// If makeEntrySafeFn is nil, values will be returned as-is without transformation.
 69func Wrap(list *list.List, makeEntrySafeFn func(any) any) *ReadOnlyList {
 70	return &ReadOnlyList{
 71		list:            list,
 72		makeEntrySafeFn: makeEntrySafeFn,
 73	}
 74}
 75
 76// getSafeValue applies the makeEntrySafeFn if it exists, otherwise returns the original value
 77func (rol *ReadOnlyList) getSafeValue(value any) any {
 78	if rol.makeEntrySafeFn == nil {
 79		return value
 80	}
 81	return rol.makeEntrySafeFn(value)
 82}
 83
 84// Len returns the number of elements in the list.
 85func (rol *ReadOnlyList) Len() int {
 86	return rol.list.Len()
 87}
 88
 89// Get returns the value at the specified index, converted to a safe format.
 90// Returns nil if index is out of bounds.
 91func (rol *ReadOnlyList) Get(index int) any {
 92	value := rol.list.Get(index)
 93	if value == nil {
 94		return nil
 95	}
 96	return rol.getSafeValue(value)
 97}
 98
 99// Slice returns a slice of values from startIndex (inclusive) to endIndex (exclusive),
100// with all values converted to a safe format.
101func (rol *ReadOnlyList) Slice(startIndex, endIndex int) []any {
102	values := rol.list.Slice(startIndex, endIndex)
103	if values == nil {
104		return nil
105	}
106
107	result := make([]any, len(values))
108	for i, v := range values {
109		result[i] = rol.getSafeValue(v)
110	}
111	return result
112}
113
114// ForEach iterates through all elements in the list, providing safe versions of the values.
115func (rol *ReadOnlyList) ForEach(fn func(index int, value any) bool) {
116	rol.list.ForEach(func(index int, value any) bool {
117		return fn(index, rol.getSafeValue(value))
118	})
119}