@@ -6,10 +6,13 @@ import (
6
6
"strings"
7
7
8
8
blocks "github.com/ipfs/go-block-format"
9
- pb "github.com/ipfs/go-merkledag/pb"
10
-
11
9
cid "github.com/ipfs/go-cid"
12
- ipld "github.com/ipfs/go-ipld-format"
10
+ format "github.com/ipfs/go-ipld-format"
11
+ pb "github.com/ipfs/go-merkledag/pb"
12
+ dagpb "github.com/ipld/go-codec-dagpb"
13
+ ipld "github.com/ipld/go-ipld-prime"
14
+ "github.com/ipld/go-ipld-prime/fluent/qp"
15
+ cidlink "github.com/ipld/go-ipld-prime/linking/cid"
13
16
)
14
17
15
18
// Make sure the user doesn't upgrade this file.
@@ -22,38 +25,84 @@ const _ = pb.DoNotUpgradeFileEverItWillChangeYourHashes
22
25
23
26
// unmarshal decodes raw data into a *Node instance.
24
27
// The conversion uses an intermediate PBNode.
25
- func ( n * ProtoNode ) unmarshal (encoded []byte ) error {
26
- var pbn pb. PBNode
27
- if err := pbn . Unmarshal ( encoded ); err != nil {
28
- return fmt . Errorf ( "unmarshal failed. %v" , err )
28
+ func unmarshal (encodedBytes []byte ) ( * ProtoNode , error ) {
29
+ nb := dagpb . Type . PBNode . NewBuilder ()
30
+ if err := dagpb . DecodeBytes ( nb , encodedBytes ); err != nil {
31
+ return nil , err
29
32
}
33
+ nd := nb .Build ()
34
+ return fromImmutableNode (& immutableProtoNode {encodedBytes , nd .(dagpb.PBNode )}), nil
35
+ }
30
36
31
- pbnl := pbn .GetLinks ()
32
- n .links = make ([]* ipld.Link , len (pbnl ))
33
- for i , l := range pbnl {
34
- n .links [i ] = & ipld.Link {Name : l .GetName (), Size : l .GetTsize ()}
35
- c , err := cid .Cast (l .GetHash ())
36
- if err != nil {
37
- return fmt .Errorf ("link hash #%d is not valid multihash. %v" , i , err )
37
+ func fromImmutableNode (encoded * immutableProtoNode ) * ProtoNode {
38
+ n := new (ProtoNode )
39
+ n .encoded = encoded
40
+ if n .encoded .PBNode .Data .Exists () {
41
+ n .data = n .encoded .PBNode .Data .Must ().Bytes ()
42
+ }
43
+ numLinks := n .encoded .PBNode .Links .Length ()
44
+ n .links = make ([]* format.Link , numLinks )
45
+ linkAllocs := make ([]format.Link , numLinks )
46
+ for i := int64 (0 ); i < numLinks ; i ++ {
47
+ next := n .encoded .PBNode .Links .Lookup (i )
48
+ name := ""
49
+ if next .FieldName ().Exists () {
50
+ name = next .FieldName ().Must ().String ()
38
51
}
39
- n .links [i ].Cid = c
52
+ c := cid .Undef
53
+ c = next .FieldHash ().Link ().(cidlink.Link ).Cid
54
+ size := uint64 (0 )
55
+ if next .FieldTsize ().Exists () {
56
+ size = uint64 (next .FieldTsize ().Must ().Int ())
57
+ }
58
+ link := & linkAllocs [i ]
59
+ link .Name = name
60
+ link .Size = size
61
+ link .Cid = c
62
+ n .links [i ] = link
63
+ }
64
+ return n
65
+ }
66
+ func (n * ProtoNode ) marshalImmutable () (* immutableProtoNode , error ) {
67
+ nd , err := qp .BuildMap (dagpb .Type .PBNode , 2 , func (ma ipld.MapAssembler ) {
68
+ qp .MapEntry (ma , "Links" , qp .List (int64 (len (n .links )), func (la ipld.ListAssembler ) {
69
+ for _ , link := range n .links {
70
+ qp .ListEntry (la , qp .Map (3 , func (ma ipld.MapAssembler ) {
71
+ if link .Cid .Defined () {
72
+ qp .MapEntry (ma , "Hash" , qp .Link (cidlink.Link {Cid : link .Cid }))
73
+ }
74
+ qp .MapEntry (ma , "Name" , qp .String (link .Name ))
75
+ qp .MapEntry (ma , "Tsize" , qp .Int (int64 (link .Size )))
76
+ }))
77
+ }
78
+ }))
79
+ if n .data != nil {
80
+ qp .MapEntry (ma , "Data" , qp .Bytes (n .data ))
81
+ }
82
+ })
83
+ if err != nil {
84
+ return nil , err
40
85
}
41
- sort .Stable (LinkSlice (n .links )) // keep links sorted
42
86
43
- n .data = pbn .GetData ()
44
- n .encoded = encoded
45
- return nil
87
+ // 1KiB can be allocated on the stack, and covers most small nodes
88
+ // without having to grow the buffer and cause allocations.
89
+ enc := make ([]byte , 0 , 1024 )
90
+
91
+ enc , err = dagpb .AppendEncode (enc , nd )
92
+ if err != nil {
93
+ return nil , err
94
+ }
95
+ return & immutableProtoNode {enc , nd .(dagpb.PBNode )}, nil
46
96
}
47
97
48
98
// Marshal encodes a *Node instance into a new byte slice.
49
99
// The conversion uses an intermediate PBNode.
50
100
func (n * ProtoNode ) Marshal () ([]byte , error ) {
51
- pbn := n .GetPBNode ()
52
- data , err := pbn .Marshal ()
101
+ enc , err := n .marshalImmutable ()
53
102
if err != nil {
54
- return data , fmt . Errorf ( "marshal failed. %v" , err )
103
+ return nil , err
55
104
}
56
- return data , nil
105
+ return enc . encoded , nil
57
106
}
58
107
59
108
// GetPBNode converts *ProtoNode into it's protocol buffer variant.
@@ -88,28 +137,27 @@ func (n *ProtoNode) EncodeProtobuf(force bool) ([]byte, error) {
88
137
if n .encoded == nil || force {
89
138
n .cached = cid .Undef
90
139
var err error
91
- n .encoded , err = n .Marshal ()
140
+ n .encoded , err = n .marshalImmutable ()
92
141
if err != nil {
93
142
return nil , err
94
143
}
95
144
}
96
145
97
146
if ! n .cached .Defined () {
98
- c , err := n .CidBuilder ().Sum (n .encoded )
147
+ c , err := n .CidBuilder ().Sum (n .encoded . encoded )
99
148
if err != nil {
100
149
return nil , err
101
150
}
102
151
103
152
n .cached = c
104
153
}
105
154
106
- return n .encoded , nil
155
+ return n .encoded . encoded , nil
107
156
}
108
157
109
158
// DecodeProtobuf decodes raw data and returns a new Node instance.
110
159
func DecodeProtobuf (encoded []byte ) (* ProtoNode , error ) {
111
- n := new (ProtoNode )
112
- err := n .unmarshal (encoded )
160
+ n , err := unmarshal (encoded )
113
161
if err != nil {
114
162
return nil , fmt .Errorf ("incorrectly formatted merkledag node: %s" , err )
115
163
}
@@ -118,7 +166,7 @@ func DecodeProtobuf(encoded []byte) (*ProtoNode, error) {
118
166
119
167
// DecodeProtobufBlock is a block decoder for protobuf IPLD nodes conforming to
120
168
// node.DecodeBlockFunc
121
- func DecodeProtobufBlock (b blocks.Block ) (ipld .Node , error ) {
169
+ func DecodeProtobufBlock (b blocks.Block ) (format .Node , error ) {
122
170
c := b .Cid ()
123
171
if c .Type () != cid .DagProtobuf {
124
172
return nil , fmt .Errorf ("this function can only decode protobuf nodes" )
@@ -138,4 +186,4 @@ func DecodeProtobufBlock(b blocks.Block) (ipld.Node, error) {
138
186
}
139
187
140
188
// Type assertion
141
- var _ ipld .DecodeBlockFunc = DecodeProtobufBlock
189
+ var _ format .DecodeBlockFunc = DecodeProtobufBlock
0 commit comments