diff --git a/examples/gno.land/p/demo/avl/pager/pager.gno b/examples/gno.land/p/demo/avl/pager/pager.gno index cb48e8f5ba4..900320cb96c 100644 --- a/examples/gno.land/p/demo/avl/pager/pager.gno +++ b/examples/gno.land/p/demo/avl/pager/pager.gno @@ -7,30 +7,55 @@ import ( // NewPager creates a new Pager with default values. func NewPager(tree avl.ITree, defaultPageSize int, reversed bool) *pageable.Pager { - wrappedTree := NewAVLWrapper(tree) + wrappedTree := NewWrapper(tree) return pageable.NewPager(wrappedTree, defaultPageSize, reversed) } -// AVLWrapper adapts an avl.ITree to implement Pageable -type AVLWrapper struct { +// Wrapper adapts an avl.ITree to implement Pageable +type Wrapper struct { tree avl.ITree } -func NewAVLWrapper(tree avl.ITree) *AVLWrapper { - return &AVLWrapper{tree: tree} +func NewWrapper(tree avl.ITree) *Wrapper { + return &Wrapper{tree: tree} } -func (w *AVLWrapper) Size() int { +func (w *Wrapper) Size() int { return w.tree.Size() } -func (w *AVLWrapper) IterateByOffset(offset int, count int, cb func(index interface{}, value interface{}) bool) bool { - if count < 0 { - return w.tree.ReverseIterateByOffset(offset, count, func(key string, value interface{}) bool { - return cb(key, value) - }) +func (w *Wrapper) IterateByOffset(offset int, count int, cb func(index interface{}, value interface{}) bool) bool { + if count == 0 { + return false } + + size := w.tree.Size() + if size == 0 { + return false + } + + if offset >= size { + return false + } + + // Use the tree's IterateByOffset with the full count + // (positive for forward, negative for reverse) return w.tree.IterateByOffset(offset, count, func(key string, value interface{}) bool { return cb(key, value) }) } + +// Helper functions +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/examples/gno.land/p/demo/avl/pager/z_filetest.gno b/examples/gno.land/p/demo/avl/pager/z_filetest.gno index 6342888d6b4..0d3aacf56c1 100644 --- a/examples/gno.land/p/demo/avl/pager/z_filetest.gno +++ b/examples/gno.land/p/demo/avl/pager/z_filetest.gno @@ -23,7 +23,7 @@ func main() { println(ufmt.Sprintf("## Page %d of %d", page.PageNumber, page.TotalPages)) for idx, item := range page.Items { - println(ufmt.Sprintf("- idx=%d key=%s value=%d", idx, item.Key, item.Value)) + println(ufmt.Sprintf("- idx=%d index=%s value=%d", idx, item.Index, item.Value)) } println(page.Picker()) println() @@ -38,63 +38,63 @@ func main() { // _0_ | [1](?page=1) | [2](?page=2) | … | [6](?page=6) // // ## Page 1 of 6 -// - idx=0 key=0000001 value=0 -// - idx=1 key=0000002 value=1 -// - idx=2 key=0000003 value=2 -// - idx=3 key=0000004 value=3 -// - idx=4 key=0000005 value=4 -// - idx=5 key=0000006 value=5 -// - idx=6 key=0000007 value=6 +// - idx=0 index=0000001 value=0 +// - idx=1 index=0000002 value=1 +// - idx=2 index=0000003 value=2 +// - idx=3 index=0000004 value=3 +// - idx=4 index=0000005 value=4 +// - idx=5 index=0000006 value=5 +// - idx=6 index=0000007 value=6 // **1** | [2](?page=2) | [3](?page=3) | … | [6](?page=6) // // ## Page 2 of 6 -// - idx=0 key=0000008 value=7 -// - idx=1 key=0000009 value=8 -// - idx=2 key=000000a value=9 -// - idx=3 key=000000b value=10 -// - idx=4 key=000000c value=11 -// - idx=5 key=000000d value=12 -// - idx=6 key=000000e value=13 +// - idx=0 index=0000008 value=7 +// - idx=1 index=0000009 value=8 +// - idx=2 index=000000a value=9 +// - idx=3 index=000000b value=10 +// - idx=4 index=000000c value=11 +// - idx=5 index=000000d value=12 +// - idx=6 index=000000e value=13 // [1](?page=1) | **2** | [3](?page=3) | [4](?page=4) | … | [6](?page=6) // // ## Page 3 of 6 -// - idx=0 key=000000f value=14 -// - idx=1 key=000000g value=15 -// - idx=2 key=000000h value=16 -// - idx=3 key=000000j value=17 -// - idx=4 key=000000k value=18 -// - idx=5 key=000000m value=19 -// - idx=6 key=000000n value=20 +// - idx=0 index=000000f value=14 +// - idx=1 index=000000g value=15 +// - idx=2 index=000000h value=16 +// - idx=3 index=000000j value=17 +// - idx=4 index=000000k value=18 +// - idx=5 index=000000m value=19 +// - idx=6 index=000000n value=20 // [1](?page=1) | [2](?page=2) | **3** | [4](?page=4) | [5](?page=5) | [6](?page=6) // // ## Page 4 of 6 -// - idx=0 key=000000p value=21 -// - idx=1 key=000000q value=22 -// - idx=2 key=000000r value=23 -// - idx=3 key=000000s value=24 -// - idx=4 key=000000t value=25 -// - idx=5 key=000000v value=26 -// - idx=6 key=000000w value=27 +// - idx=0 index=000000p value=21 +// - idx=1 index=000000q value=22 +// - idx=2 index=000000r value=23 +// - idx=3 index=000000s value=24 +// - idx=4 index=000000t value=25 +// - idx=5 index=000000v value=26 +// - idx=6 index=000000w value=27 // [1](?page=1) | [2](?page=2) | [3](?page=3) | **4** | [5](?page=5) | [6](?page=6) // // ## Page 5 of 6 -// - idx=0 key=000000x value=28 -// - idx=1 key=000000y value=29 -// - idx=2 key=000000z value=30 -// - idx=3 key=0000010 value=31 -// - idx=4 key=0000011 value=32 -// - idx=5 key=0000012 value=33 -// - idx=6 key=0000013 value=34 +// - idx=0 index=000000x value=28 +// - idx=1 index=000000y value=29 +// - idx=2 index=000000z value=30 +// - idx=3 index=0000010 value=31 +// - idx=4 index=0000011 value=32 +// - idx=5 index=0000012 value=33 +// - idx=6 index=0000013 value=34 // [1](?page=1) | … | [3](?page=3) | [4](?page=4) | **5** | [6](?page=6) // // ## Page 6 of 6 -// - idx=0 key=0000014 value=35 -// - idx=1 key=0000015 value=36 -// - idx=2 key=0000016 value=37 -// - idx=3 key=0000017 value=38 -// - idx=4 key=0000018 value=39 -// - idx=5 key=0000019 value=40 -// - idx=6 key=000001a value=41 +// - idx=0 index=0000014 value=35 +// - idx=1 index=0000015 value=36 +// - idx=2 index=0000016 value=37 +// - idx=3 index=0000017 value=38 +// - idx=4 index=0000018 value=39 +// - idx=5 index=0000019 value=40 +// - idx=6 index=000001a value=41 // [1](?page=1) | … | [4](?page=4) | [5](?page=5) | **6** // // ## Page 7 of 6 diff --git a/examples/gno.land/p/moul/pageable/pageable.gno b/examples/gno.land/p/moul/pageable/pageable.gno index a4dd8a3eca0..9ee01ee40f1 100644 --- a/examples/gno.land/p/moul/pageable/pageable.gno +++ b/examples/gno.land/p/moul/pageable/pageable.gno @@ -1,4 +1,15 @@ -// Package pageable provides a generic pagination system +// Package pageable implements a flexible pagination system that can be used with any data structure +// that implements the Pageable interface. It provides functionality for: +// +// - Paginating through collections of items +// - Configurable page sizes +// - Forward and reverse iteration +// - URL query parameter parsing +// - Markdown-based pagination UI +// +// This package is currently used by: +// - gno.land/p/demo/avl/pager: implementation for AVL trees. +// - gno.land/p/moul/ulist/pager: implementation for ulist package pageable import ( @@ -9,13 +20,26 @@ import ( "gno.land/p/demo/ufmt" ) -// Pageable defines the minimal interface required for pagination +// Pageable defines the minimal interface required for pagination. +// This interface is intentionally lightweight, requiring only two methods. +// While some data structures (like AVL trees) might have separate methods for forward +// and reverse iteration, this interface consolidates both directions into a single +// IterateByOffset method. It's the responsibility of the implementing wrapper to +// handle the direction logic internally based on the offset and count parameters. type Pageable interface { // Size returns the total number of items Size() int - // IterateByOffset performs iteration starting from offset for count elements - // The callback receives an index and a value, returns true to stop iteration + // IterateByOffset performs iteration starting from offset for count elements. + // The callback receives an index and a value, returns true to stop iteration. + // + // For reverse iteration, the implementation should handle the direction internally + // by adjusting how it interprets the offset and count parameters. For example: + // - In forward mode: offset 0, count 5 would return items [0,1,2,3,4] + // - In reverse mode: offset 0, count 5 would return items [4,3,2,1,0] + // + // This approach allows the interface to remain simple while supporting + // bidirectional iteration through the implementation layer. IterateByOffset(offset int, count int, cb func(index interface{}, value interface{}) bool) bool } @@ -120,23 +144,12 @@ func (p *Pager) GetPageWithSize(pageNumber, pageSize int) *Page { // Collect items for the current page var items []Item if p.Reversed { - // For reversed order, iterate from the end of the array - if offset == 0 && iterCount == 1 { - // Special case for last partial page - p.Source.IterateByOffset(0, 1, func(index interface{}, value interface{}) bool { - items = append(items, Item{Index: index, Value: value}) - return true - }) - } else { - startIndex := page.TotalItems - offset - 1 - endIndex := startIndex - iterCount + 1 - for i := startIndex; i >= endIndex && i >= 0; i-- { - p.Source.IterateByOffset(i, 1, func(index interface{}, value interface{}) bool { - items = append(items, Item{Index: index, Value: value}) - return true - }) - } - } + // For reversed order, use negative count to indicate reverse iteration + offset = page.TotalItems - offset - iterCount + p.Source.IterateByOffset(offset, -iterCount, func(index interface{}, value interface{}) bool { + items = append(items, Item{Index: index, Value: value}) + return false + }) } else { p.Source.IterateByOffset(offset, iterCount, func(index interface{}, value interface{}) bool { items = append(items, Item{Index: index, Value: value}) diff --git a/examples/gno.land/p/moul/pageable/pageable_test.gno b/examples/gno.land/p/moul/pageable/pageable_test.gno index 2cbce82c7f5..db3da0b7546 100644 --- a/examples/gno.land/p/moul/pageable/pageable_test.gno +++ b/examples/gno.land/p/moul/pageable/pageable_test.gno @@ -136,7 +136,7 @@ func TestReversedPager(t *testing.T) { } // Check if items are in reverse order - if page.Items[0].Value.(int) != 2 || page.Items[1].Value.(int) != 1 { + if page.Items[0].Value.(int) != 5 || page.Items[1].Value.(int) != 4 { t.Errorf("items not in reverse order: got %v", page.Items) } }