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}