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

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

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

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

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

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