marshal.go 3.09 KB
Newer Older
Eric Myhre's avatar
Eric Myhre committed
1 2 3 4 5 6 7 8
package codec

import (
	"fmt"

	"github.com/polydawn/refmt/shared"
	"github.com/polydawn/refmt/tok"

tavit ohanian's avatar
tavit ohanian committed
9
	dms3ld "gitlab.dms3.io/ld/go-ld-prime"
Eric Myhre's avatar
Eric Myhre committed
10 11 12 13 14 15 16 17 18 19
)

// Marshal provides a very general node-to-tokens marshalling feature.
// It can handle either cbor or json by being combined with a refmt TokenSink.
//
// It is valid for all the data model types except links, which are only
// supported if the nodes are typed and provide additional information
// to clarify how links should be encoded through their type info.
// (The dag-cbor and dag-json formats can be used if links are of CID
// implementation and need to be encoded in a schemafree way.)
tavit ohanian's avatar
tavit ohanian committed
20
func Marshal(n dms3ld.Node, sink shared.TokenSink) error {
Eric Myhre's avatar
Eric Myhre committed
21
	var tk tok.Token
22 23 24
	return marshal(n, &tk, sink)
}

tavit ohanian's avatar
tavit ohanian committed
25
func marshal(n dms3ld.Node, tk *tok.Token, sink shared.TokenSink) error {
26
	switch n.Kind() {
tavit ohanian's avatar
tavit ohanian committed
27
	case dms3ld.Kind_Invalid:
28
		return fmt.Errorf("cannot traverse a node that is absent")
tavit ohanian's avatar
tavit ohanian committed
29
	case dms3ld.Kind_Null:
Eric Myhre's avatar
Eric Myhre committed
30
		tk.Type = tok.TNull
31
		_, err := sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
32
		return err
tavit ohanian's avatar
tavit ohanian committed
33
	case dms3ld.Kind_Map:
Eric Myhre's avatar
Eric Myhre committed
34 35
		// Emit start of map.
		tk.Type = tok.TMapOpen
36
		tk.Length = int(n.Length()) // TODO: overflow check
37
		if _, err := sink.Step(tk); err != nil {
Eric Myhre's avatar
Eric Myhre committed
38 39 40 41 42 43 44 45 46 47 48 49 50
			return err
		}
		// Emit map contents (and recurse).
		for itr := n.MapIterator(); !itr.Done(); {
			k, v, err := itr.Next()
			if err != nil {
				return err
			}
			tk.Type = tok.TString
			tk.Str, err = k.AsString()
			if err != nil {
				return err
			}
51
			if _, err := sink.Step(tk); err != nil {
Eric Myhre's avatar
Eric Myhre committed
52 53
				return err
			}
54
			if err := marshal(v, tk, sink); err != nil {
Eric Myhre's avatar
Eric Myhre committed
55 56 57 58 59
				return err
			}
		}
		// Emit map close.
		tk.Type = tok.TMapClose
60
		_, err := sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
61
		return err
tavit ohanian's avatar
tavit ohanian committed
62
	case dms3ld.Kind_List:
Eric Myhre's avatar
Eric Myhre committed
63 64 65
		// Emit start of list.
		tk.Type = tok.TArrOpen
		l := n.Length()
66
		tk.Length = int(l) // TODO: overflow check
67
		if _, err := sink.Step(tk); err != nil {
Eric Myhre's avatar
Eric Myhre committed
68 69 70
			return err
		}
		// Emit list contents (and recurse).
71
		for i := int64(0); i < l; i++ {
72
			v, err := n.LookupByIndex(i)
Eric Myhre's avatar
Eric Myhre committed
73 74 75
			if err != nil {
				return err
			}
76
			if err := marshal(v, tk, sink); err != nil {
Eric Myhre's avatar
Eric Myhre committed
77 78 79 80 81
				return err
			}
		}
		// Emit list close.
		tk.Type = tok.TArrClose
82
		_, err := sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
83
		return err
tavit ohanian's avatar
tavit ohanian committed
84
	case dms3ld.Kind_Bool:
Eric Myhre's avatar
Eric Myhre committed
85 86 87 88 89 90
		v, err := n.AsBool()
		if err != nil {
			return err
		}
		tk.Type = tok.TBool
		tk.Bool = v
91
		_, err = sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
92
		return err
tavit ohanian's avatar
tavit ohanian committed
93
	case dms3ld.Kind_Int:
Eric Myhre's avatar
Eric Myhre committed
94 95 96 97 98 99
		v, err := n.AsInt()
		if err != nil {
			return err
		}
		tk.Type = tok.TInt
		tk.Int = int64(v)
100
		_, err = sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
101
		return err
tavit ohanian's avatar
tavit ohanian committed
102
	case dms3ld.Kind_Float:
Eric Myhre's avatar
Eric Myhre committed
103 104 105 106 107 108
		v, err := n.AsFloat()
		if err != nil {
			return err
		}
		tk.Type = tok.TFloat64
		tk.Float64 = v
109
		_, err = sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
110
		return err
tavit ohanian's avatar
tavit ohanian committed
111
	case dms3ld.Kind_String:
Eric Myhre's avatar
Eric Myhre committed
112 113 114 115 116 117
		v, err := n.AsString()
		if err != nil {
			return err
		}
		tk.Type = tok.TString
		tk.Str = v
118
		_, err = sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
119
		return err
tavit ohanian's avatar
tavit ohanian committed
120
	case dms3ld.Kind_Bytes:
Eric Myhre's avatar
Eric Myhre committed
121 122 123 124 125 126
		v, err := n.AsBytes()
		if err != nil {
			return err
		}
		tk.Type = tok.TBytes
		tk.Bytes = v
127
		_, err = sink.Step(tk)
Eric Myhre's avatar
Eric Myhre committed
128
		return err
tavit ohanian's avatar
tavit ohanian committed
129
	case dms3ld.Kind_Link:
Eric Myhre's avatar
Eric Myhre committed
130 131 132 133 134
		return fmt.Errorf("link emission not supported by this codec without a schema!  (maybe you want dag-cbor or dag-json)")
	default:
		panic("unreachable")
	}
}