rolist.gno
3.52 Kb ยท 127 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// var privateList list.List
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(privateList, 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/nt/avl/list"
47 "gno.land/p/nt/avl/rotree"
48)
49
50// IReadOnlyList defines the read-only operations available on a list.
51type IReadOnlyList interface {
52 Len() int
53 Get(index int) any
54 Slice(startIndex, endIndex int) []any
55 ForEach(fn func(index int, value any) bool)
56}
57
58// ReadOnlyList wraps a list.List and provides read-only access.
59type ReadOnlyList struct {
60 list *list.List
61 makeEntrySafeFn func(any) any
62}
63
64// Verify interface implementations
65var (
66 _ IReadOnlyList = (*ReadOnlyList)(nil)
67 _ IReadOnlyList = (interface{ list.IList })(nil) // is subset of list.IList
68)
69
70// Wrap creates a new ReadOnlyList from an existing list.List and a safety transformation function.
71// If makeEntrySafeFn is nil, values will be returned as-is without transformation.
72func Wrap(list *list.List, makeEntrySafeFn func(any) any) *ReadOnlyList {
73 return &ReadOnlyList{
74 list: list,
75 makeEntrySafeFn: makeEntrySafeFn,
76 }
77}
78
79// getSafeValue applies the makeEntrySafeFn if it exists, otherwise returns the original value
80func (rol *ReadOnlyList) getSafeValue(value any) any {
81 if rol.makeEntrySafeFn == nil {
82 return value
83 }
84 return rol.makeEntrySafeFn(value)
85}
86
87// Len returns the number of elements in the list.
88func (rol *ReadOnlyList) Len() int {
89 return rol.list.Len()
90}
91
92// Get returns the value at the specified index, converted to a safe format.
93// Returns nil if index is out of bounds.
94func (rol *ReadOnlyList) Get(index int) any {
95 value := rol.list.Get(index)
96 if value == nil {
97 return nil
98 }
99 return rol.getSafeValue(value)
100}
101
102// Slice returns a slice of values from startIndex (inclusive) to endIndex (exclusive),
103// with all values converted to a safe format.
104func (rol *ReadOnlyList) Slice(startIndex, endIndex int) []any {
105 values := rol.list.Slice(startIndex, endIndex)
106 if values == nil {
107 return nil
108 }
109
110 result := make([]any, len(values))
111 for i, v := range values {
112 result[i] = rol.getSafeValue(v)
113 }
114 return result
115}
116
117// ForEach iterates through all elements in the list, providing safe versions of the values.
118func (rol *ReadOnlyList) ForEach(fn func(index int, value any) bool) {
119 rol.list.ForEach(func(index int, value any) bool {
120 return fn(index, rol.getSafeValue(value))
121 })
122}
123
124// Tree returns a read-only pointer to the underlying AVL tree.
125func (rol *ReadOnlyList) Tree() *rotree.ReadOnlyTree {
126 return rol.list.Tree()
127}