github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/list/list.go (about)

     1  package list
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
     8  
     9  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    10  )
    11  
    12  // Key for the length of the list
    13  func LengthKey() []byte {
    14  	return []byte{0x00}
    15  }
    16  
    17  // Key for the elements of the list
    18  func ElemKey(index uint64) []byte {
    19  	return append([]byte{0x01}, []byte(fmt.Sprintf("%020d", index))...)
    20  }
    21  
    22  // List defines an integer indexable mapper
    23  // It panics when the element type cannot be (un/)marshalled by the codec
    24  type List struct {
    25  	cdc   *codec.Codec
    26  	store types.KVStore
    27  }
    28  
    29  // NewList constructs new List
    30  func NewList(cdc *codec.Codec, store types.KVStore) List {
    31  	return List{
    32  		cdc:   cdc,
    33  		store: store,
    34  	}
    35  }
    36  
    37  // Len() returns the length of the list
    38  // The length is only increased by Push() and not decreased
    39  // List dosen't check if an index is in bounds
    40  // The user should check Len() before doing any actions
    41  func (m List) Len() (res uint64) {
    42  	bz := m.store.Get(LengthKey())
    43  	if bz == nil {
    44  		return 0
    45  	}
    46  
    47  	m.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res)
    48  	return
    49  }
    50  
    51  // Get() returns the element by its index
    52  func (m List) Get(index uint64, ptr interface{}) error {
    53  	bz := m.store.Get(ElemKey(index))
    54  	return m.cdc.UnmarshalBinaryLengthPrefixed(bz, ptr)
    55  }
    56  
    57  // Set() stores the element to the given position
    58  // Setting element out of range will break length counting
    59  // Use Push() instead of Set() to append a new element
    60  func (m List) Set(index uint64, value interface{}) {
    61  	bz := m.cdc.MustMarshalBinaryLengthPrefixed(value)
    62  	m.store.Set(ElemKey(index), bz)
    63  }
    64  
    65  // Delete() deletes the element in the given position
    66  // Other elements' indices are preserved after deletion
    67  // Panics when the index is out of range
    68  func (m List) Delete(index uint64) {
    69  	m.store.Delete(ElemKey(index))
    70  }
    71  
    72  // Push() inserts the element to the end of the list
    73  // It will increase the length when it is called
    74  func (m List) Push(value interface{}) {
    75  	length := m.Len()
    76  	m.Set(length, value)
    77  	m.store.Set(LengthKey(), m.cdc.MustMarshalBinaryLengthPrefixed(length+1))
    78  }
    79  
    80  // Iterate() is used to iterate over all existing elements in the list
    81  // Return true in the continuation to break
    82  // The second element of the continuation will indicate the position of the element
    83  // Using it with Get() will return the same one with the provided element
    84  
    85  // CONTRACT: No writes may happen within a domain while iterating over it.
    86  func (m List) Iterate(ptr interface{}, fn func(uint64) bool) {
    87  	iter := types.KVStorePrefixIterator(m.store, []byte{0x01})
    88  	defer iter.Close()
    89  	for ; iter.Valid(); iter.Next() {
    90  		v := iter.Value()
    91  		m.cdc.MustUnmarshalBinaryLengthPrefixed(v, ptr)
    92  
    93  		k := iter.Key()
    94  		s := string(k[len(k)-20:])
    95  
    96  		index, err := strconv.ParseUint(s, 10, 64)
    97  		if err != nil {
    98  			panic(err)
    99  		}
   100  
   101  		if fn(index) {
   102  			break
   103  		}
   104  	}
   105  }