github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/common/tuple.go (about) 1 package common 2 3 import ( 4 "runtime" 5 6 "github.com/authzed/spicedb/pkg/datastore" 7 "github.com/authzed/spicedb/pkg/datastore/options" 8 core "github.com/authzed/spicedb/pkg/proto/core/v1" 9 ) 10 11 // NewSliceRelationshipIterator creates a datastore.TupleIterator instance from a materialized slice of tuples. 12 func NewSliceRelationshipIterator(tuples []*core.RelationTuple, order options.SortOrder) datastore.RelationshipIterator { 13 iter := &sliceRelationshipIterator{tuples: tuples, order: order} 14 runtime.SetFinalizer(iter, MustIteratorBeClosed) 15 return iter 16 } 17 18 type sliceRelationshipIterator struct { 19 tuples []*core.RelationTuple 20 order options.SortOrder 21 last *core.RelationTuple 22 closed bool 23 err error 24 } 25 26 // Next implements TupleIterator 27 func (sti *sliceRelationshipIterator) Next() *core.RelationTuple { 28 if sti.closed { 29 sti.err = datastore.ErrClosedIterator 30 return nil 31 } 32 33 if len(sti.tuples) > 0 { 34 first := sti.tuples[0] 35 sti.tuples = sti.tuples[1:] 36 sti.last = first 37 return first 38 } 39 40 return nil 41 } 42 43 func (sti *sliceRelationshipIterator) Cursor() (options.Cursor, error) { 44 switch { 45 case sti.closed: 46 return nil, datastore.ErrClosedIterator 47 case sti.order == options.Unsorted: 48 return nil, datastore.ErrCursorsWithoutSorting 49 case sti.last == nil: 50 return nil, datastore.ErrCursorEmpty 51 default: 52 return sti.last, nil 53 } 54 } 55 56 // Err implements TupleIterator 57 func (sti *sliceRelationshipIterator) Err() error { 58 return sti.err 59 } 60 61 // Close implements TupleIterator 62 func (sti *sliceRelationshipIterator) Close() { 63 if sti.closed { 64 return 65 } 66 67 sti.tuples = nil 68 sti.closed = true 69 } 70 71 // MustIteratorBeClosed is a function which can be used as a finalizer to make sure that 72 // tuples are getting closed before they are garbage collected. 73 func MustIteratorBeClosed(iter *sliceRelationshipIterator) { 74 if !iter.closed { 75 panic("Tuple iterator garbage collected before Close() was called") 76 } 77 }