freeNode.go 5.51 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
}

Eric Myhre's avatar
Eric Myhre committed
42
func (n *Node) ReprKind() ipld.ReprKind {
43 44
	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 73
func (n *Node) MapIterator() ipld.MapIterator {
	return &mapIterator{n, 0, expectTyp(ipld.ReprKind_Map, n.kind)}
74 75
}

76
type mapIterator struct {
77 78
	node *Node
	idx  int
79
	err  error
80 81
}

82 83 84 85 86 87 88 89 90 91 92 93 94 95
func (itr *mapIterator) Next() (ipld.Node, ipld.Node, error) {
	if itr.err != nil {
		return nil, nil, itr.err
	}
	k := itr.node._mapOrd[itr.idx]
	v := itr.node._map[k]
	itr.idx++
	return &Node{kind: ipld.ReprKind_String, _str: k}, v, nil
}
func (itr *mapIterator) Done() bool {
	if itr.err != nil {
		return false
	}
	return itr.idx >= len(itr.node._mapOrd)
96
}
97 98 99

func (n *Node) ListIterator() ipld.ListIterator {
	return &listIterator{n, 0, expectTyp(ipld.ReprKind_List, n.kind)}
100 101
}

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
type listIterator struct {
	node *Node
	idx  int
	err  error
}

func (itr *listIterator) Next() (int, ipld.Node, error) {
	if itr.err != nil {
		return -1, nil, itr.err
	}
	v := itr.node._arr[itr.idx]
	idx := itr.idx
	itr.idx++
	return idx, v, nil
}
func (itr *listIterator) Done() bool {
	if itr.err != nil {
		return false
	}
	return itr.idx >= len(itr.node._arr)
122 123 124
}

func (n *Node) Length() int {
Eric Myhre's avatar
Eric Myhre committed
125
	switch n.ReprKind() {
126 127 128 129 130 131 132
	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
133 134 135
}

func (n *Node) TraverseField(pth string) (ipld.Node, error) {
136
	switch n.kind {
137 138
	case ipld.ReprKind_Invalid:
		return nil, fmt.Errorf("cannot traverse a node that is undefined")
139
	case ipld.ReprKind_Null:
Eric Myhre's avatar
Eric Myhre committed
140
		return nil, fmt.Errorf("cannot traverse terminals")
141
	case ipld.ReprKind_Map:
142 143 144
		v, exists := n._map[pth]
		if !exists {
			return nil, fmt.Errorf("404")
Eric Myhre's avatar
Eric Myhre committed
145
		}
146
		return v, nil
147
	case ipld.ReprKind_List:
Eric Myhre's avatar
Eric Myhre committed
148 149 150 151 152 153 154
		i, err := strconv.Atoi(pth)
		if err != nil {
			return nil, fmt.Errorf("404")
		}
		if i >= len(n._arr) {
			return nil, fmt.Errorf("404")
		}
155
		return n._arr[i], 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:
Eric Myhre's avatar
Eric Myhre committed
162 163 164 165 166 167 168
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
}

func (n *Node) TraverseIndex(idx int) (ipld.Node, error) {
169
	switch n.kind {
170 171
	case ipld.ReprKind_Invalid:
		return nil, fmt.Errorf("cannot traverse a node that is undefined")
172
	case ipld.ReprKind_Null:
173
		return nil, fmt.Errorf("cannot traverse terminals")
174
	case ipld.ReprKind_Map:
175 176
		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.
177
	case ipld.ReprKind_List:
178 179 180 181 182 183 184
		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
185 186 187 188 189 190
	case ipld.ReprKind_Bool,
		ipld.ReprKind_String,
		ipld.ReprKind_Bytes,
		ipld.ReprKind_Int,
		ipld.ReprKind_Float,
		ipld.ReprKind_Link:
191 192 193 194
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
Eric Myhre's avatar
Eric Myhre committed
195 196
}

197
func expectTyp(expect, actual ipld.ReprKind) error {
Eric Myhre's avatar
Eric Myhre committed
198 199 200
	if expect == actual {
		return nil
	}
201
	return fmt.Errorf("type assertion rejected: node is %q, assertion was for %q", actual, expect)
Eric Myhre's avatar
Eric Myhre committed
202
}