node.go 8 KB
Newer Older
Eric Myhre's avatar
Eric Myhre committed
1 2 3
package ipld

type Node interface {
4 5 6
	// Kind returns a value from the ReprKind enum describing what the
	// essential serializable kind of this node is (map, list, int, etc).
	// Most other handling of a node requires first switching upon the kind.
Eric Myhre's avatar
Eric Myhre committed
7
	ReprKind() ReprKind
8

9
	// GetField resolves a path in the the object and returns
10 11
	// either a primitive (e.g. string, int, etc), a link (type CID),
	// or another Node.
12 13 14 15 16 17
	//
	// If the Kind of this Node is not ReprKind_Map, a nil node and an error
	// will be returned.
	//
	// If the key does not exist, a nil node and an error will be returned.
	TraverseField(key string) (Node, error)
18 19 20 21 22

	// GetIndex is the equivalent of GetField but for indexing into an array
	// (or a numerically-keyed map).  Like GetField, it returns
	// either a primitive (e.g. string, int, etc), a link (type CID),
	// or another Node.
23 24 25 26 27
	//
	// If the Kind of this Node is not ReprKind_List, a nil node and an error
	// will be returned.
	//
	// If idx is out of range, a nil node and an error will be returned.
Eric Myhre's avatar
Eric Myhre committed
28
	TraverseIndex(idx int) (Node, error)
Eric Myhre's avatar
Eric Myhre committed
29

30 31
	// MapIterator returns an iterator which yields key-value pairs
	// traversing the node.
32 33
	// If the node kind is anything other than a map, the iterator will
	// yield error values.
34 35 36 37 38
	//
	// The iterator will yield every entry in the map; that is, it
	// can be expected that itr.Next will be called node.Length times
	// before itr.Done becomes true.
	MapIterator() MapIterator
39

40 41 42 43
	// ListIterator returns an iterator which yields key-value pairs
	// traversing the node.
	// If the node kind is anything other than a list, the iterator will
	// yield error values.
44
	//
45 46 47 48
	// The iterator will yield every entry in the list; that is, it
	// can be expected that itr.Next will be called node.Length times
	// before itr.Done becomes true.
	ListIterator() ListIterator
49 50 51 52

	// Length returns the length of a list, or the number of entries in a map,
	// or -1 if the node is not of list nor map kind.
	Length() int
53

Eric Myhre's avatar
Eric Myhre committed
54 55 56
	// Undefined nodes are returned when traversing a struct field that is
	// defined by a schema but unset in the data.  (Undefined nodes are not
	// possible otherwise; you'll only see them from `typed.Node`.)
57 58 59 60
	// The undefined flag is necessary so iterating over structs can
	// unambiguously make the distinction between values that are
	// present-and-null versus values that are absent.
	IsUndefined() bool
Eric Myhre's avatar
Eric Myhre committed
61

Eric Myhre's avatar
Eric Myhre committed
62
	IsNull() bool
Eric Myhre's avatar
Eric Myhre committed
63 64
	AsBool() (bool, error)
	AsInt() (int, error)
65 66 67
	AsFloat() (float64, error)
	AsString() (string, error)
	AsBytes() ([]byte, error)
68
	AsLink() (Link, error)
69 70 71 72 73 74 75 76 77 78 79 80 81

	// NodeBuilder returns a NodeBuilder which can be used to build
	// new nodes of the same implementation type as this one.
	//
	// For map and list nodes, the NodeBuilder's append-oriented methods
	// will work using this node's values as a base.
	// If this is a typed node, the NodeBuilder will carry the same
	// typesystem constraints as this Node.
	//
	// (This feature is used by the traversal package, especially in
	// e.g. traversal.Transform, for doing tree updates while keeping the
	// existing implementation preferences and doing as many operations
	// in copy-on-write fashions as possible.)
Eric Myhre's avatar
Eric Myhre committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
	//
	// ---
	//
	// More specifically, the contract of a NodeBuilder returned by this method
	// is that it should be able to "replace" this node with a new one of
	// similar properties.
	// E.g., for a string, the builder must be able to build a new string.
	// For a map, the builder must be able to build a new map.
	// For a *struct* (when using typed nodes), the builder must be able to
	// build new structs of the name type.
	// Note that the promise doesn't extend further: there's no requirement
	// that the builder be able to build maps if this node's kind is "string"
	// (you can see why this lack-of-contract is important when considering
	// typed nodes: if this node has a struct type, then should the builder
	// be able to build other structs of different types?  Of course not;
	// there'd be no way to define which other types to build!).
	// For nulls, this means the builder doesn't have to do much at all!
	//
	// (Some Nodes may return a NodeBuilder that can be used for much more
	// than replacing their own kind: for example, Node implementations from
	// the ipldfree package tend to return a NodeBuilder than can build any
	// other ipldfree.Node (e.g. even the builder obtained from a string node
	// will be able to build maps).  This is not required by the contract;
	// such packages only do so out of internal implementation convenience.)
106
	NodeBuilder() NodeBuilder
Eric Myhre's avatar
Eric Myhre committed
107
}
108

109 110 111
// MapIterator is an interface for traversing map nodes.
// Sequential calls to Next() will yield key-value pairs;
// Done() describes whether iteration should continue.
112
//
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
// Iteration order is defined to be stable: two separate MapIterator
// created to iterate the same Node will yield the same key-value pairs
// in the same order.
// The order itself may be defined by the Node implementation: some
// Nodes may retain insertion order, and some may return iterators which
// always yield data in sorted order, for example.
type MapIterator interface {
	// Next returns the next key-value pair.
	//
	// An error value can also be returned at any step: in the case of advanced
	// data structures with incremental loading, it's possible to encounter
	// cancellation or I/O errors at any point in iteration.
	// If an error is returned, the boolean will always be false (so it's
	// correct to check the bool first and short circuit to continuing if true).
	// If an error is returned, the key and value may be nil.
	Next() (key Node, value Node, err error)

	// Done returns false as long as there's at least one more entry to iterate.
Matthias Beyer's avatar
Fix doc  
Matthias Beyer committed
131
	// When Done returns true, iteration can stop.
132
	//
Eric Myhre's avatar
Eric Myhre committed
133 134
	// Note when implementing iterators for advanced data layouts (e.g. more than
	// one chunk of backing data, which is loaded incrementally): if your
135
	// implementation does any I/O during the Done method, and it encounters
Eric Myhre's avatar
Eric Myhre committed
136
	// an error, it must return 'false', so that the following Next call
137 138 139 140 141 142 143
	// has an opportunity to return the error.
	Done() bool
}

// ListIterator is an interface for traversing list nodes.
// Sequential calls to Next() will yield index-value pairs;
// Done() describes whether iteration should continue.
144
//
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
// A loop which iterates from 0 to Node.Length is a valid
// alternative to using a ListIterator.
type ListIterator interface {
	// Next returns the next index and value.
	//
	// An error value can also be returned at any step: in the case of advanced
	// data structures with incremental loading, it's possible to encounter
	// cancellation or I/O errors at any point in iteration.
	// If an error is returned, the boolean will always be false (so it's
	// correct to check the bool first and short circuit to continuing if true).
	// If an error is returned, the key and value may be nil.
	Next() (idx int, value Node, err error)

	// Done returns false as long as there's at least one more entry to iterate.
	// When Done returns false, iteration can stop.
	//
Eric Myhre's avatar
Eric Myhre committed
161 162
	// Note when implementing iterators for advanced data layouts (e.g. more than
	// one chunk of backing data, which is loaded incrementally): if your
163
	// implementation does any I/O during the Done method, and it encounters
Eric Myhre's avatar
Eric Myhre committed
164
	// an error, it must return 'false', so that the following Next call
165 166
	// has an opportunity to return the error.
	Done() bool
167 168 169 170 171
}

// REVIEW: immediate-mode AsBytes() method (as opposed to e.g. returning
// an io.Reader instance) might be problematic, esp. if we introduce
// AdvancedLayouts which support large bytes natively.
172 173 174 175 176 177 178 179 180 181
//
// Probable solution is having both immediate and iterator return methods.
// Returning a reader for bytes when you know you want a slice already
// is going to be high friction without purpose in many common uses.
//
// Unclear what SetByteStream() would look like for advanced layouts.
// One could try to encapsulate the chunking entirely within the advlay
// node impl... but would it be graceful?  Not sure.  Maybe.  Hopefully!
// Yes?  The advlay impl would still tend to use SetBytes for the raw
// data model layer nodes its composing, so overall, it shakes out nicely.