freeNode.go 4.67 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
func (n *Node) Keys() ipld.KeyIterator {
68
	return &keyIterator{n, 0}
69 70
}

71
type keyIterator struct {
72 73 74 75
	node *Node
	idx  int
}

76
func (ki *keyIterator) Next() (string, error) {
77 78 79 80 81
	// TODO kind check and safer range handling.
	v := ki.node._mapOrd[ki.idx]
	ki.idx++
	return v, nil
}
82
func (ki *keyIterator) HasNext() bool {
83 84 85 86 87 88 89 90
	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 {
Eric Myhre's avatar
Eric Myhre committed
91
	switch n.ReprKind() {
92 93 94 95 96 97 98
	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
99 100 101
}

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

func (n *Node) TraverseIndex(idx int) (ipld.Node, error) {
135
	switch n.kind {
136 137
	case ipld.ReprKind_Invalid:
		return nil, fmt.Errorf("cannot traverse a node that is undefined")
138
	case ipld.ReprKind_Null:
139
		return nil, fmt.Errorf("cannot traverse terminals")
140
	case ipld.ReprKind_Map:
141 142
		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.
143
	case ipld.ReprKind_List:
144 145 146 147 148 149 150
		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
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:
157 158 159 160
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
Eric Myhre's avatar
Eric Myhre committed
161 162
}

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