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

	"github.com/ipfs/go-cid"
Eric Myhre's avatar
Eric Myhre committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
	"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).

	The "zero" value of this struct is interpreted as an empty map.

	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 {
	typ typ

Eric Myhre's avatar
Eric Myhre committed
32 33 34 35 36 37
	// n.b. maps values are all ptr so the returned node interface can be mutable.

	_map   map[string]*Node // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_map2  map[int]*Node    // Value union.  Only one of these has meaning, depending on the value of 'Type'.
	_arr   []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'.
38
	_str   string           // Value union.  Only one of these has meaning, depending on the value of 'Type'.
Eric Myhre's avatar
Eric Myhre committed
39 40
	_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'.
41
	_bytes []byte           // Value union.  Only one of these has meaning, depending on the value of 'Type'.
42
	_link  cid.Cid          // Value union.  Only one of these has meaning, depending on the value of 'Type'.
Eric Myhre's avatar
Eric Myhre committed
43 44 45 46 47
}

type typ struct{ t byte }

var (
Eric Myhre's avatar
Eric Myhre committed
48
	tNil   = typ{}
Eric Myhre's avatar
Eric Myhre committed
49 50 51
	tMap   = typ{'{'}
	tArr   = typ{'['}
	tBool  = typ{'b'}
52
	tStr   = typ{'s'}
Eric Myhre's avatar
Eric Myhre committed
53 54
	tInt   = typ{'i'}
	tFloat = typ{'f'}
55
	tBytes = typ{'x'}
Eric Myhre's avatar
Eric Myhre committed
56
	tLink  = typ{'/'}
Eric Myhre's avatar
Eric Myhre committed
57 58
)

Eric Myhre's avatar
Eric Myhre committed
59 60 61 62 63 64 65 66 67 68
func (n *Node) AsBool() (v bool, _ error) {
	return n._bool, expectTyp(tBool, n.typ)
}
func (n *Node) AsString() (v string, _ error) {
	return n._str, expectTyp(tStr, n.typ)
}
func (n *Node) AsInt() (v int, _ error) {
	return n._int, expectTyp(tInt, n.typ)
}
func (n *Node) AsLink() (v cid.Cid, _ error) {
69
	return n._link, expectTyp(tLink, n.typ)
Eric Myhre's avatar
Eric Myhre committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
}

func (n *Node) TraverseField(pth string) (ipld.Node, error) {
	switch n.typ {
	case tNil:
		return nil, fmt.Errorf("cannot traverse terminals")
	case tMap:
		switch {
		case n._map != nil:
			v, _ := n._map[pth]
			return v, nil
		case n._map2 != nil:
			i, err := strconv.Atoi(pth)
			if err != nil {
				return nil, fmt.Errorf("404")
			}
			v, _ := n._map2[i]
			return v, nil
		default:
			panic("unreachable")
		}
	case tArr:
		i, err := strconv.Atoi(pth)
		if err != nil {
			return nil, fmt.Errorf("404")
		}
		if i >= len(n._arr) {
			return nil, fmt.Errorf("404")
		}
		v := &n._arr[i]
		return v, nil
101
	case tStr, tBytes, tBool, tInt, tFloat, tLink:
Eric Myhre's avatar
Eric Myhre committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
		return nil, fmt.Errorf("cannot traverse terminals")
	default:
		panic("unreachable")
	}
}

func (n *Node) TraverseIndex(idx int) (ipld.Node, error) {
	panic("NYI")
}

func expectTyp(expect, actual typ) error {
	if expect == actual {
		return nil
	}
	return fmt.Errorf("woof")
Eric Myhre's avatar
Eric Myhre committed
117
}