freeNode.go 4.9 KB
Newer Older
Eric Myhre's avatar
Eric Myhre committed
1 2 3
package ipldfree

import (
Eric Myhre's avatar
Eric Myhre committed
4 5 6 7
	"fmt"
	"strconv"

	"github.com/ipfs/go-cid"
Eric Myhre's avatar
Eric Myhre committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
	"github.com/ipld/go-ipld-prime"
)

var (
	_ ipld.Node = &Node{}
)

/*
	Node has some internal

	This implementation of `ipld.Node` is pretty comparable to `ipldbind.Node`,
	but is somewhat simpler in implementation because values of this type can
	only be produced by its own builder patterns (and thus it requires much
	less reflection and in particular does not depend on refmt for object mapping).

23
	The "zero" value of this struct has a kind of ReprKind_Invalid.
Eric Myhre's avatar
Eric Myhre committed
24 25 26 27 28 29

	This binding does not provide a serialization valid for hashing; to
	compute a CID, you'll have to convert to another kind of node.
	If you're not sure which kind serializable node to use, try `ipldcbor.Node`.
*/
type Node struct {
30
	kind ipld.ReprKind
Eric Myhre's avatar
Eric Myhre committed
31

32 33 34 35 36 37 38 39 40
	_map    map[string]ipld.Node // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_mapOrd []string             // Conjugate to _map, only has meaning depending on the value of 'Type'.
	_arr    []ipld.Node          // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_bool   bool                 // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_int    int                  // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_float  float64              // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_str    string               // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_bytes  []byte               // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_link   cid.Cid              // Value union.  Only one of these has meaning, depending on the value of 'Type'.
Eric Myhre's avatar
Eric Myhre committed
41 42
}

43 44 45
func (n *Node) Kind() ipld.ReprKind {
	return n.kind
}
Eric Myhre's avatar
Eric Myhre committed
46

Eric Myhre's avatar
Eric Myhre committed
47 48 49
func (n *Node) IsNull() bool {
	return n.kind == ipld.ReprKind_Null
}
Eric Myhre's avatar
Eric Myhre committed
50
func (n *Node) AsBool() (v bool, _ error) {
51
	return n._bool, expectTyp(ipld.ReprKind_Bool, n.kind)
Eric Myhre's avatar
Eric Myhre committed
52
}
53 54 55 56 57 58
func (n *Node) AsInt() (v int, _ error) {
	return n._int, expectTyp(ipld.ReprKind_Int, n.kind)
}
func (n *Node) AsFloat() (v float64, _ error) {
	return n._float, expectTyp(ipld.ReprKind_Float, n.kind)
}
Eric Myhre's avatar
Eric Myhre committed
59
func (n *Node) AsString() (v string, _ error) {
60
	return n._str, expectTyp(ipld.ReprKind_String, n.kind)
Eric Myhre's avatar
Eric Myhre committed
61
}
62 63
func (n *Node) AsBytes() (v []byte, _ error) {
	return n._bytes, expectTyp(ipld.ReprKind_Bytes, n.kind)
Eric Myhre's avatar
Eric Myhre committed
64 65
}
func (n *Node) AsLink() (v cid.Cid, _ error) {
66 67 68
	return n._link, expectTyp(ipld.ReprKind_Link, n.kind)
}

69
func (n *Node) Keys() ipld.KeyIterator {
70
	return &keyIterator{n, 0}
71 72
}

73
type keyIterator struct {
74 75 76 77
	node *Node
	idx  int
}

78
func (ki *keyIterator) Next() (string, error) {
79 80 81 82 83
	// TODO kind check and safer range handling.
	v := ki.node._mapOrd[ki.idx]
	ki.idx++
	return v, nil
}
84
func (ki *keyIterator) HasNext() bool {
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	return len(ki.node._mapOrd) > ki.idx
}

func (n *Node) KeysImmediate() ([]string, error) {
	return n._mapOrd, expectTyp(ipld.ReprKind_Map, n.kind)
}

func (n *Node) Length() int {
	switch n.Kind() {
	case ipld.ReprKind_Map:
		return len(n._mapOrd)
	case ipld.ReprKind_List:
		return len(n._arr)
	default:
		return -1
	}
Eric Myhre's avatar
Eric Myhre committed
101 102 103
}

func (n *Node) TraverseField(pth string) (ipld.Node, error) {
104
	switch n.kind {
105 106
	case ipld.ReprKind_Invalid:
		return nil, fmt.Errorf("cannot traverse a node that is undefined")
107
	case ipld.ReprKind_Null:
Eric Myhre's avatar
Eric Myhre committed
108
		return nil, fmt.Errorf("cannot traverse terminals")
109
	case ipld.ReprKind_Map:
110 111 112
		v, exists := n._map[pth]
		if !exists {
			return nil, fmt.Errorf("404")
Eric Myhre's avatar
Eric Myhre committed
113
		}
114
		return v, nil
115
	case ipld.ReprKind_List:
Eric Myhre's avatar
Eric Myhre committed
116 117 118 119 120 121 122
		i, err := strconv.Atoi(pth)
		if err != nil {
			return nil, fmt.Errorf("404")
		}
		if i >= len(n._arr) {
			return nil, fmt.Errorf("404")
		}
123
		return n._arr[i], nil
124 125 126 127 128 129
	case ipld.ReprKind_Bool,
		ipld.ReprKind_String,
		ipld.ReprKind_Bytes,
		ipld.ReprKind_Int,
		ipld.ReprKind_Float,
		ipld.ReprKind_Link:
Eric Myhre's avatar
Eric Myhre committed
130 131 132 133 134 135 136
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
}

func (n *Node) TraverseIndex(idx int) (ipld.Node, error) {
137
	switch n.kind {
138 139
	case ipld.ReprKind_Invalid:
		return nil, fmt.Errorf("cannot traverse a node that is undefined")
140
	case ipld.ReprKind_Null:
141
		return nil, fmt.Errorf("cannot traverse terminals")
142
	case ipld.ReprKind_Map:
143 144
		return nil, fmt.Errorf("cannot traverse map by numeric index")
		// REVIEW: there's an argument that maybe we should support this; would be '_map2' code.
145
	case ipld.ReprKind_List:
146 147 148 149 150 151 152
		if idx >= len(n._arr) {
			return nil, fmt.Errorf("404")
		}
		if n._arr[idx] == nil {
			return nil, fmt.Errorf("404")
		}
		return n._arr[idx], nil
153 154 155 156 157 158
	case ipld.ReprKind_Bool,
		ipld.ReprKind_String,
		ipld.ReprKind_Bytes,
		ipld.ReprKind_Int,
		ipld.ReprKind_Float,
		ipld.ReprKind_Link:
159 160 161 162
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
Eric Myhre's avatar
Eric Myhre committed
163 164
}

165
func expectTyp(expect, actual ipld.ReprKind) error {
Eric Myhre's avatar
Eric Myhre committed
166 167 168
	if expect == actual {
		return nil
	}
169
	return fmt.Errorf("type assertion rejected: node is %q, assertion was for %q", actual, expect)
Eric Myhre's avatar
Eric Myhre committed
170
}