freeNode.go 5.22 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
	"github.com/ipld/go-ipld-prime"
)

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

/*
15
	Node is an implementatin of `ipld.Node` that can contain any content.
Eric Myhre's avatar
Eric Myhre committed
16

17 18
	This implementation is extremely simple; it is general-purpose,
	but not optimized for any particular purpose.
Eric Myhre's avatar
Eric Myhre committed
19

20
	The "zero" value of this struct has a kind of ReprKind_Invalid.
21
	NodeBuilder must be used to produce valid instances of Node.
Eric Myhre's avatar
Eric Myhre committed
22 23
*/
type Node struct {
24
	kind ipld.ReprKind
Eric Myhre's avatar
Eric Myhre committed
25

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

Eric Myhre's avatar
Eric Myhre committed
37
func (n *Node) ReprKind() ipld.ReprKind {
38 39
	return n.kind
}
Eric Myhre's avatar
Eric Myhre committed
40

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

63 64 65 66
func (n *Node) NodeBuilder() ipld.NodeBuilder {
	return nodeBuilder{n}
}

67 68
func (n *Node) MapIterator() ipld.MapIterator {
	return &mapIterator{n, 0, expectTyp(ipld.ReprKind_Map, n.kind)}
69 70
}

71
type mapIterator struct {
72 73
	node *Node
	idx  int
74
	err  error
75 76
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90
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)
91
}
92 93 94

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

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
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)
117 118 119
}

func (n *Node) Length() int {
Eric Myhre's avatar
Eric Myhre committed
120
	switch n.ReprKind() {
121 122 123 124 125 126 127
	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
128 129 130
}

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

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

192
func expectTyp(expect, actual ipld.ReprKind) error {
Eric Myhre's avatar
Eric Myhre committed
193 194 195
	if expect == actual {
		return nil
	}
196
	return fmt.Errorf("type assertion rejected: node is %q, assertion was for %q", actual, expect)
Eric Myhre's avatar
Eric Myhre committed
197
}