Skip to content

Commit 7b00b14

Browse files
committed
feat(dagcbor): mode to allow parsing undelimited streamed objects
1 parent db30294 commit 7b00b14

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

codec/dagcbor/nongreedy_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dagcbor
2+
3+
import (
4+
"bytes"
5+
"encoding/hex"
6+
"testing"
7+
8+
qt "github.com/frankban/quicktest"
9+
"github.com/ipld/go-ipld-prime"
10+
"github.com/ipld/go-ipld-prime/datamodel"
11+
"github.com/ipld/go-ipld-prime/fluent/qp"
12+
"github.com/ipld/go-ipld-prime/node/basicnode"
13+
)
14+
15+
func TestNonGreedy(t *testing.T) {
16+
// same as JSON version of this test: {"a": 1}{"b": 2}
17+
buf, err := hex.DecodeString("a1616101a1616202")
18+
qt.Assert(t, err, qt.IsNil)
19+
r := bytes.NewReader(buf)
20+
opts := DecodeOptions{
21+
DontParseBeyondEnd: true,
22+
}
23+
24+
// first object
25+
nb1 := basicnode.Prototype.Map.NewBuilder()
26+
err = opts.Decode(nb1, r)
27+
qt.Assert(t, err, qt.IsNil)
28+
expected, err := qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {
29+
qp.MapEntry(ma, "a", qp.Int(1))
30+
})
31+
qt.Assert(t, err, qt.IsNil)
32+
qt.Assert(t, ipld.DeepEqual(nb1.Build(), expected), qt.IsTrue)
33+
34+
// second object
35+
nb2 := basicnode.Prototype.Map.NewBuilder()
36+
err = opts.Decode(nb2, r)
37+
qt.Assert(t, err, qt.IsNil)
38+
expected, err = qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {
39+
qp.MapEntry(ma, "b", qp.Int(2))
40+
})
41+
qt.Assert(t, err, qt.IsNil)
42+
qt.Assert(t, ipld.DeepEqual(nb2.Build(), expected), qt.IsTrue)
43+
}

codec/dagcbor/unmarshal.go

+12
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ type DecodeOptions struct {
5454
//
5555
// Note that this option is experimental as it only implements partial strictness.
5656
ExperimentalDeterminism bool
57+
58+
// If true, the decoder stops reading from the stream at the end of a full,
59+
// valid CBOR object. This may be useful for parsing a stream of undelimited
60+
// CBOR objects.
61+
// As per standard IPLD behavior, in the default mode the parser considers the
62+
// entire block to be part of the CBOR object and will error if there is
63+
// extraneous data after the end of the object.
64+
DontParseBeyondEnd bool
5765
}
5866

5967
// Decode deserializes data from the given io.Reader and feeds it into the given datamodel.NodeAssembler.
@@ -77,6 +85,10 @@ func (cfg DecodeOptions) Decode(na datamodel.NodeAssembler, r io.Reader) error {
7785
return err
7886
}
7987

88+
if cfg.DontParseBeyondEnd {
89+
return nil
90+
}
91+
8092
var buf [1]byte
8193
_, err = io.ReadFull(r, buf[:])
8294
switch err {

0 commit comments

Comments
 (0)