freeNode.go 4.95 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
	"fmt"
	"strconv"

Eric Myhre's avatar
Eric Myhre committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
	"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).

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

	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 {
29
	kind ipld.ReprKind
Eric Myhre's avatar
Eric Myhre committed
30

31 32 33 34 35 36 37 38
	_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'.
39
	_link   ipld.Link            // Value union.  Only one of these has meaning, depending on the value of 'Type'.
Eric Myhre's avatar
Eric Myhre committed
40 41
}

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

Eric Myhre's avatar
Eric Myhre committed
46 47 48
func (n *Node) IsNull() bool {
	return n.kind == ipld.ReprKind_Null
}
Eric Myhre's avatar
Eric Myhre committed
49
func (n *Node) AsBool() (v bool, _ error) {
50
	return n._bool, expectTyp(ipld.ReprKind_Bool, n.kind)
Eric Myhre's avatar
Eric Myhre committed
51
}
52 53 54 55 56 57
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
58
func (n *Node) AsString() (v string, _ error) {
59
	return n._str, expectTyp(ipld.ReprKind_String, n.kind)
Eric Myhre's avatar
Eric Myhre committed
60
}
61 62
func (n *Node) AsBytes() (v []byte, _ error) {
	return n._bytes, expectTyp(ipld.ReprKind_Bytes, n.kind)
Eric Myhre's avatar
Eric Myhre committed
63
}
64
func (n *Node) AsLink() (v ipld.Link, _ error) {
65 66 67
	return n._link, expectTyp(ipld.ReprKind_Link, n.kind)
}

68 69 70 71
func (n *Node) NodeBuilder() ipld.NodeBuilder {
	return nodeBuilder{n}
}

72
func (n *Node) Keys() ipld.KeyIterator {
73
	return &keyIterator{n, 0}
74 75
}

76
type keyIterator struct {
77 78 79 80
	node *Node
	idx  int
}

81
func (ki *keyIterator) Next() (string, error) {
82 83 84 85 86
	// TODO kind check and safer range handling.
	v := ki.node._mapOrd[ki.idx]
	ki.idx++
	return v, nil
}
87
func (ki *keyIterator) HasNext() bool {
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
	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
104 105 106
}

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

func (n *Node) TraverseIndex(idx int) (ipld.Node, error) {
140
	switch n.kind {
141 142
	case ipld.ReprKind_Invalid:
		return nil, fmt.Errorf("cannot traverse a node that is undefined")
143
	case ipld.ReprKind_Null:
144
		return nil, fmt.Errorf("cannot traverse terminals")
145
	case ipld.ReprKind_Map:
146 147
		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.
148
	case ipld.ReprKind_List:
149 150 151 152 153 154 155
		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
156 157 158 159 160 161
	case ipld.ReprKind_Bool,
		ipld.ReprKind_String,
		ipld.ReprKind_Bytes,
		ipld.ReprKind_Int,
		ipld.ReprKind_Float,
		ipld.ReprKind_Link:
162 163 164 165
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
Eric Myhre's avatar
Eric Myhre committed
166 167
}

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