PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/ulist/lplist/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / ulist / lplist
Files
3 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/ulist/lplist/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • lplist.gnogno
lplist.gnogno
1// Package lplist provides a layered proxy implementation for lists that allows transparent2// migration of data between different schema versions.3//4// LayeredProxyList wraps an existing list (source) with a new list (target) and optionally5// applies migrations to source data when it's accessed. This enables schema evolution without6// requiring upfront migration of all data, making it ideal for large datasets or when7// preserving original data is important.8//9// Key features:10// - Lazy migration: Data is only transformed when accessed, not stored in migrated form11// - Append-only source: Source data is treated as immutable to preserve original data12// - Chaining: Multiple LayeredProxyLists can be stacked for multi-step migrations13//14// Example usage:15//16//	// Define data types for different schema versions17//	type UserV1 struct {18//	    Name string19//	    Age int20//	}21//22//	type UserV2 struct {23//	    FullName string24//	    Age int25//	    Active bool26//	}27//28//	// Create source list with old schema29//	sourceList := ulist.New()30//	sourceList.Append(31//	    UserV1{Name: "Alice", Age: 30},32//	    UserV1{Name: "Bob", Age: 25},33//	)34//35//	// Define migration function from V1 to V236//	migrateUserV1ToV2 := func(v any) any {37//	    user := v.(UserV1)38//	    return UserV2{39//	        FullName: user.Name,  // Name field renamed to FullName40//	        Age: user.Age,41//	        Active: true,         // New field with default value42//	    }43//	}44//45//	// Create layered proxy with migration46//	proxy := NewLayeredProxyList(sourceList, migrateUserV1ToV2)47//48//	// Add new data directly in V2 format49//	proxy.Append(UserV2{FullName: "Charlie", Age: 40, Active: false})50//51//	// All access through proxy returns data in V2 format52//	for i := 0; i < proxy.Size(); i++ {53//	    user := proxy.Get(i).(UserV2)54//	    fmt.Printf("User: %s, Age: %d, Active: %t\n", user.FullName, user.Age, user.Active)55//	}56package lplist5758import (59	"errors"6061	"gno.land/p/moul/ulist/v0"62)6364// MigratorFn is a function type that lazily converts values from source to target65type MigratorFn func(any) any6667// LayeredProxyList represents a wrapper around an existing List that handles migration68type LayeredProxyList struct {69	source       ulist.IList70	target       *ulist.List71	migrator     MigratorFn72	sourceHeight int // Store initial source size to optimize lookups73}7475// NewLayeredProxyList creates a new LayeredProxyList instance that wraps an existing List76func NewLayeredProxyList(source ulist.IList, migrator MigratorFn) *LayeredProxyList {77	sourceHeight := source.TotalSize()78	target := ulist.New()79	return &LayeredProxyList{80		source:       source,81		target:       target,82		migrator:     migrator,83		sourceHeight: sourceHeight,84	}85}8687// Get retrieves the value at the specified index88// Uses sourceHeight to efficiently route requests89func (l *LayeredProxyList) Get(index int) any {90	if index < l.sourceHeight {91		// Direct access to source for indices below sourceHeight92		val := l.source.Get(index)93		if val == nil {94			return nil95		}96		// Only apply migrator if it exists97		if l.migrator != nil {98			return l.migrator(val)99		}100		return val101	}102	// For indices >= sourceHeight, adjust index to be relative to target list starting at 0103	targetIndex := index - l.sourceHeight104	return l.target.Get(targetIndex)105}106107// Append adds one or more values to the target list108func (l *LayeredProxyList) Append(values ...any) {109	l.target.Append(values...)110}111112// Delete marks elements as deleted in the appropriate list113func (l *LayeredProxyList) Delete(indices ...int) error {114	for _, index := range indices {115		if index < l.sourceHeight {116			err := l.source.Delete(index)117			if err != nil {118				return err119			}120		}121	}122123	for _, index := range indices {124		targetIndex := index - l.sourceHeight125		err := l.target.Delete(targetIndex)126		if err != nil {127			return err128		}129	}130	return nil131}132133// Size returns the total number of active elements134func (l *LayeredProxyList) Size() int {135	return l.source.Size() + l.target.Size()136}137138// TotalSize returns the total number of elements in the list139func (l *LayeredProxyList) TotalSize() int {140	return l.sourceHeight + l.target.TotalSize()141}142143// MustDelete deletes elements, panicking on error144func (l *LayeredProxyList) MustDelete(indices ...int) {145	if err := l.Delete(indices...); err != nil {146		panic(err)147	}148}149150// MustGet retrieves a value, panicking if not found151func (l *LayeredProxyList) MustGet(index int) any {152	val := l.Get(index)153	if val == nil {154		panic(ulist.ErrDeleted)155	}156	return val157}158159// GetRange returns elements between start and end indices160func (l *LayeredProxyList) GetRange(start, end int) []ulist.Entry {161	var entries []ulist.Entry162	l.Iterator(start, end, func(index int, value any) bool {163		entries = append(entries, ulist.Entry{Index: index, Value: value})164		return false165	})166	return entries167}168169// GetRangeByOffset returns elements starting from offset170func (l *LayeredProxyList) GetRangeByOffset(offset int, count int) []ulist.Entry {171	var entries []ulist.Entry172	l.IteratorByOffset(offset, count, func(index int, value any) bool {173		entries = append(entries, ulist.Entry{Index: index, Value: value})174		return false175	})176	return entries177}178179// Iterator performs iteration between start and end indices180func (l *LayeredProxyList) Iterator(start, end int, cb ulist.IterCbFn) bool {181	// For empty list or invalid range182	if start < 0 && end < 0 {183		return false184	}185186	// Normalize indices187	if start < 0 {188		start = 0189	}190	if end < 0 {191		end = 0192	}193194	totalSize := l.TotalSize()195	if end >= totalSize {196		end = totalSize - 1197	}198	if start >= totalSize {199		start = totalSize - 1200	}201202	// Handle reverse iteration203	if start > end {204		for i := start; i >= end; i-- {205			val := l.Get(i)206			if val != nil {207				if cb(i, val) {208					return true209				}210			}211		}212		return false213	}214215	// Handle forward iteration216	for i := start; i <= end; i++ {217		val := l.Get(i)218		if val != nil {219			if cb(i, val) {220				return true221			}222		}223	}224	return false225}226227// IteratorByOffset performs iteration starting from offset228func (l *LayeredProxyList) IteratorByOffset(offset int, count int, cb ulist.IterCbFn) bool {229	if count == 0 {230		return false231	}232233	// Normalize offset234	if offset < 0 {235		offset = 0236	}237	totalSize := l.TotalSize()238	if offset >= totalSize {239		offset = totalSize - 1240	}241242	// Determine end based on count direction243	var end int244	if count > 0 {245		end = totalSize - 1246	} else {247		end = 0248	}249250	wrapperReturned := false251252	// Calculate absolute value manually instead of using abs function253	remaining := count254	if remaining < 0 {255		remaining = -remaining256	}257258	wrapper := func(index int, value any) bool {259		if remaining <= 0 {260			wrapperReturned = true261			return true262		}263		remaining--264		return cb(index, value)265	}266267	ret := l.Iterator(offset, end, wrapper)268	if wrapperReturned {269		return false270	}271	return ret272}273274// Set updates the value at the specified index275func (l *LayeredProxyList) Set(index int, value any) error {276	if index < l.sourceHeight {277		// Cannot modify source list directly278		return errors.New("cannot modify source list directly")279	}280281	// Adjust index to be relative to target list starting at 0282	targetIndex := index - l.sourceHeight283	return l.target.Set(targetIndex, value)284}285286// MustSet updates the value at the specified index, panicking on error287func (l *LayeredProxyList) MustSet(index int, value any) {288	if err := l.Set(index, value); err != nil {289		panic(err)290	}291}292293// GetByOffset returns elements starting from offset with count determining direction294func (l *LayeredProxyList) GetByOffset(offset int, count int) []ulist.Entry {295	var entries []ulist.Entry296	l.IteratorByOffset(offset, count, func(index int, value any) bool {297		entries = append(entries, ulist.Entry{Index: index, Value: value})298		return false299	})300	return entries301}302303// Verify that LayeredProxyList implements IList304var _ ulist.IList = (*LayeredProxyList)(nil)305

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.