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