1package state 2 3import ( 4 "bytes" 5 "errors" 6 "fmt" 7) 8 9// indexerSingle implements both memdb.Indexer and memdb.SingleIndexer. It may 10// be used in a memdb.IndexSchema to specify functions that generate the index 11// value for memdb.Txn operations. 12type indexerSingle struct { 13 // readIndex is used by memdb for Txn.Get, Txn.First, and other operations 14 // that read data. 15 readIndex 16 // writeIndex is used by memdb for Txn.Insert, Txn.Delete, for operations 17 // that write data to the index. 18 writeIndex 19} 20 21// indexerMulti implements both memdb.Indexer and memdb.MultiIndexer. It may 22// be used in a memdb.IndexSchema to specify functions that generate the index 23// value for memdb.Txn operations. 24type indexerMulti struct { 25 // readIndex is used by memdb for Txn.Get, Txn.First, and other operations 26 // that read data. 27 readIndex 28 // writeIndexMulti is used by memdb for Txn.Insert, Txn.Delete, for operations 29 // that write data to the index. 30 writeIndexMulti 31} 32 33// indexerSingleWithPrefix is a indexerSingle which also supports prefix queries. 34type indexerSingleWithPrefix struct { 35 readIndex 36 writeIndex 37 prefixIndex 38} 39 40// readIndex implements memdb.Indexer. It exists so that a function can be used 41// to provide the interface. 42// 43// Unlike memdb.Indexer, a readIndex function accepts only a single argument. To 44// generate an index from multiple values, use a struct type with multiple fields. 45type readIndex func(arg interface{}) ([]byte, error) 46 47func (f readIndex) FromArgs(args ...interface{}) ([]byte, error) { 48 if len(args) != 1 { 49 return nil, fmt.Errorf("index supports only a single arg") 50 } 51 return f(args[0]) 52} 53 54var errMissingValueForIndex = fmt.Errorf("object is missing a value for this index") 55 56// writeIndex implements memdb.SingleIndexer. It exists so that a function 57// can be used to provide this interface. 58// 59// Instead of a bool return value, writeIndex expects errMissingValueForIndex to 60// indicate that an index could not be build for the object. It will translate 61// this error into a false value to satisfy the memdb.SingleIndexer interface. 62type writeIndex func(raw interface{}) ([]byte, error) 63 64func (f writeIndex) FromObject(raw interface{}) (bool, []byte, error) { 65 v, err := f(raw) 66 if errors.Is(err, errMissingValueForIndex) { 67 return false, nil, nil 68 } 69 return err == nil, v, err 70} 71 72// writeIndexMulti implements memdb.MultiIndexer. It exists so that a function 73// can be used to provide this interface. 74// 75// Instead of a bool return value, writeIndexMulti expects errMissingValueForIndex to 76// indicate that an index could not be build for the object. It will translate 77// this error into a false value to satisfy the memdb.MultiIndexer interface. 78type writeIndexMulti func(raw interface{}) ([][]byte, error) 79 80func (f writeIndexMulti) FromObject(raw interface{}) (bool, [][]byte, error) { 81 v, err := f(raw) 82 if errors.Is(err, errMissingValueForIndex) { 83 return false, nil, nil 84 } 85 return err == nil, v, err 86} 87 88// prefixIndex implements memdb.PrefixIndexer. It exists so that a function 89// can be used to provide this interface. 90type prefixIndex func(args interface{}) ([]byte, error) 91 92func (f prefixIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { 93 if len(args) != 1 { 94 return nil, fmt.Errorf("index supports only a single arg") 95 } 96 return f(args[0]) 97} 98 99const null = "\x00" 100 101// indexBuilder is a buffer used to construct memdb index values. 102type indexBuilder bytes.Buffer 103 104func newIndexBuilder(cap int) *indexBuilder { 105 buff := make([]byte, 0, cap) 106 b := bytes.NewBuffer(buff) 107 return (*indexBuilder)(b) 108} 109 110// String appends the string and a null terminator to the buffer. 111func (b *indexBuilder) String(v string) { 112 (*bytes.Buffer)(b).WriteString(v) 113 (*bytes.Buffer)(b).WriteString(null) 114} 115 116// Raw appends the bytes without a null terminator to the buffer. Raw should 117// only be used when v has a fixed length, or when building the last segment of 118// a prefix index. 119func (b *indexBuilder) Raw(v []byte) { 120 (*bytes.Buffer)(b).Write(v) 121} 122 123func (b *indexBuilder) Bytes() []byte { 124 return (*bytes.Buffer)(b).Bytes() 125} 126