forked from filecoin-project/go-hamt-ipld
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pointer_cbor.go
103 lines (81 loc) · 2 KB
/
pointer_cbor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
101
102
103
package hamt
import (
"fmt"
"io"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
)
// implemented as a kinded union - a "Pointer" is either a Link (child node) or
// an Array (bucket)
func (t *Pointer) MarshalCBOR(w io.Writer) error {
if t.Link != cid.Undef && len(t.KVs) > 0 {
return fmt.Errorf("hamt Pointer cannot have both a link and KVs")
}
cw := cbg.NewCborWriter(w)
if t.Link != cid.Undef {
if err := cbg.WriteCid(cw, t.Link); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.KVs))); err != nil {
return err
}
for _, kv := range t.KVs {
if err := kv.MarshalCBOR(cw); err != nil {
return err
}
}
}
return nil
}
func (t *Pointer) UnmarshalCBOR(r io.Reader) error {
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
if maj == cbg.MajTag {
if extra != 42 {
return fmt.Errorf("expected tag 42 for child node link")
}
ba, err := cbg.ReadByteArray(cr, 512)
if err != nil {
return err
}
c, err := bufToCid(ba)
if err != nil {
return err
}
t.Link = c
return nil
} else if maj == cbg.MajArray {
length := extra
if length > 32 {
return fmt.Errorf("KV array in CBOR input for pointer was too long")
}
t.KVs = make([]*KV, length)
for i := 0; i < int(length); i++ {
var kv KV
if err := kv.UnmarshalCBOR(cr); err != nil {
return err
}
t.KVs[i] = &kv
}
return nil
} else {
return fmt.Errorf("expected CBOR child node link or array")
}
}
// from https://github.com/whyrusleeping/cbor-gen/blob/211df3b9e24c6e0d0c338b440e6ab4ab298505b2/utils.go#L530
func bufToCid(buf []byte) (cid.Cid, error) {
if len(buf) == 0 {
return cid.Undef, fmt.Errorf("undefined CID")
}
if len(buf) < 2 {
return cid.Undef, fmt.Errorf("DAG-CBOR serialized CIDs must have at least two bytes")
}
if buf[0] != 0 {
return cid.Undef, fmt.Errorf("DAG-CBOR serialized CIDs must have binary multibase")
}
return cid.Cast(buf[1:])
}