Commit 259c1f45 authored by Eric Myhre's avatar Eric Myhre

Merge branch 'traversal-benchmarks'

parents 61ebf6e2 55eebc40
......@@ -21,18 +21,22 @@ import (
// implementation and need to be encoded in a schemafree way.)
func Marshal(n ipld.Node, sink shared.TokenSink) error {
var tk tok.Token
return marshal(n, &tk, sink)
}
func marshal(n ipld.Node, tk *tok.Token, sink shared.TokenSink) error {
switch n.ReprKind() {
case ipld.ReprKind_Invalid:
return fmt.Errorf("cannot traverse a node that is undefined")
case ipld.ReprKind_Null:
tk.Type = tok.TNull
_, err := sink.Step(&tk)
_, err := sink.Step(tk)
return err
case ipld.ReprKind_Map:
// Emit start of map.
tk.Type = tok.TMapOpen
tk.Length = n.Length()
if _, err := sink.Step(&tk); err != nil {
if _, err := sink.Step(tk); err != nil {
return err
}
// Emit map contents (and recurse).
......@@ -46,23 +50,23 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
if err != nil {
return err
}
if _, err := sink.Step(&tk); err != nil {
if _, err := sink.Step(tk); err != nil {
return err
}
if err := Marshal(v, sink); err != nil {
if err := marshal(v, tk, sink); err != nil {
return err
}
}
// Emit map close.
tk.Type = tok.TMapClose
_, err := sink.Step(&tk)
_, err := sink.Step(tk)
return err
case ipld.ReprKind_List:
// Emit start of list.
tk.Type = tok.TArrOpen
l := n.Length()
tk.Length = l
if _, err := sink.Step(&tk); err != nil {
if _, err := sink.Step(tk); err != nil {
return err
}
// Emit list contents (and recurse).
......@@ -71,13 +75,13 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
if err != nil {
return err
}
if err := Marshal(v, sink); err != nil {
if err := marshal(v, tk, sink); err != nil {
return err
}
}
// Emit list close.
tk.Type = tok.TArrClose
_, err := sink.Step(&tk)
_, err := sink.Step(tk)
return err
case ipld.ReprKind_Bool:
v, err := n.AsBool()
......@@ -86,7 +90,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk.Type = tok.TBool
tk.Bool = v
_, err = sink.Step(&tk)
_, err = sink.Step(tk)
return err
case ipld.ReprKind_Int:
v, err := n.AsInt()
......@@ -95,7 +99,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk.Type = tok.TInt
tk.Int = int64(v)
_, err = sink.Step(&tk)
_, err = sink.Step(tk)
return err
case ipld.ReprKind_Float:
v, err := n.AsFloat()
......@@ -104,7 +108,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk.Type = tok.TFloat64
tk.Float64 = v
_, err = sink.Step(&tk)
_, err = sink.Step(tk)
return err
case ipld.ReprKind_String:
v, err := n.AsString()
......@@ -113,7 +117,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk.Type = tok.TString
tk.Str = v
_, err = sink.Step(&tk)
_, err = sink.Step(tk)
return err
case ipld.ReprKind_Bytes:
v, err := n.AsBytes()
......@@ -122,7 +126,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk.Type = tok.TBytes
tk.Bytes = v
_, err = sink.Step(&tk)
_, err = sink.Step(tk)
return err
case ipld.ReprKind_Link:
return fmt.Errorf("link emission not supported by this codec without a schema! (maybe you want dag-cbor or dag-json)")
......
......@@ -31,13 +31,19 @@ func BenchmarkMapStrInt_25n_Iteration(b *testing.B) {
tests.SpecBenchmarkMapStrInt_25n_Iteration(b, Style__Map{})
}
func BenchmarkUnmarshalMapStrInt_3n(b *testing.B) {
tests.SpecBenchmarkUnmarshalMapStrInt_3n(b, Style__Map{})
func BenchmarkSpec_Marshal_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Marshal_Map3StrInt(b, Style__Map{})
}
func BenchmarkSpec_Marshal_Map3StrInt_CodecNull(b *testing.B) {
tests.BenchmarkSpec_Marshal_Map3StrInt_CodecNull(b, Style__Map{})
}
func BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Marshal_MapNStrMap3StrInt(b, Style__Map{})
}
func BenchmarkMarshalMapStrInt_3n(b *testing.B) {
tests.SpecBenchmarkMarshalMapStrInt_3n(b, Style__Map{})
func BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Unmarshal_Map3StrInt(b, Style__Map{})
}
func BenchmarkMarshalToNullMapStrInt_3n(b *testing.B) {
tests.SpecBenchmarkMarshalToNullMapStrInt_3n(b, Style__Map{})
func BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b, Style__Map{})
}
......@@ -2,6 +2,7 @@ package tests
import (
"bytes"
"fmt"
"testing"
refmtjson "github.com/polydawn/refmt/json"
......@@ -10,6 +11,7 @@ import (
ipld "github.com/ipld/go-ipld-prime/_rsrch/nodesolution"
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution/codec"
"github.com/ipld/go-ipld-prime/must"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
......@@ -21,7 +23,7 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
func SpecBenchmarkMarshalMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
func BenchmarkSpec_Marshal_Map3StrInt(b *testing.B, ns ipld.NodeStyle) {
nb := ns.NewBuilder()
must.NotError(codec.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(`{"whee":1,"woot":2,"waga":3}`))))
n := nb.Build()
......@@ -37,7 +39,7 @@ func SpecBenchmarkMarshalMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
}
}
func SpecBenchmarkMarshalToNullMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
func BenchmarkSpec_Marshal_Map3StrInt_CodecNull(b *testing.B, ns ipld.NodeStyle) {
nb := ns.NewBuilder()
must.NotError(codec.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(`{"whee":1,"woot":2,"waga":3}`))))
n := nb.Build()
......@@ -59,3 +61,28 @@ type nullTokenSink struct{}
func (nullTokenSink) Step(_ *tok.Token) (bool, error) {
return false, nil
}
func BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B, ns ipld.NodeStyle) {
for _, n := range []int{0, 1, 2, 4, 8, 16, 32} {
b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
msg := corpus.MapNStrMap3StrInt(n)
node := mustNodeFromJsonString(ns.NewBuilder(), msg)
b.ResetTimer()
var buf bytes.Buffer
var err error
for i := 0; i < b.N; i++ {
buf = bytes.Buffer{}
err = codec.Marshal(node, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
}
b.StopTimer()
if err != nil {
b.Fatalf("marshal errored: %s", err)
}
if buf.String() != msg {
b.Fatalf("marshal didn't match corpus")
}
})
}
}
......@@ -2,12 +2,14 @@ package tests
import (
"bytes"
"fmt"
"testing"
refmtjson "github.com/polydawn/refmt/json"
ipld "github.com/ipld/go-ipld-prime/_rsrch/nodesolution"
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution/codec"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
......@@ -19,7 +21,7 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
func SpecBenchmarkUnmarshalMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
func BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B, ns ipld.NodeStyle) {
var err error
for i := 0; i < b.N; i++ {
nb := ns.NewBuilder()
......@@ -30,3 +32,31 @@ func SpecBenchmarkUnmarshalMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
panic(err)
}
}
func BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B, ns ipld.NodeStyle) {
for _, n := range []int{0, 1, 2, 4, 8, 16, 32} {
b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
msg := corpus.MapNStrMap3StrInt(n)
b.ResetTimer()
var node ipld.Node
var err error
nb := ns.NewBuilder()
for i := 0; i < b.N; i++ {
err = codec.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(msg)))
node = nb.Build()
nb.Reset()
}
b.StopTimer()
if err != nil {
b.Fatalf("unmarshal errored: %s", err)
}
var buf bytes.Buffer
codec.Marshal(node, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
if buf.String() != msg {
b.Fatalf("remarshal didn't match corpus")
}
})
}
}
package tests
import (
"bytes"
refmtjson "github.com/polydawn/refmt/json"
ipld "github.com/ipld/go-ipld-prime/_rsrch/nodesolution"
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution/codec"
)
// various benchmarks assign their final result here,
// in order to defuse the possibility of their work being elided.
var sink interface{}
func mustNodeFromJsonString(nb ipld.NodeBuilder, str string) ipld.Node {
err := codec.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(str)))
if err != nil {
panic(err)
}
return nb.Build()
}
......@@ -86,18 +86,27 @@ func BenchmarkMap25nGenericMapIterationSimpleKeys(b *testing.B) {
// benchmarks covering encoding -->
func BenchmarkUnmarshalMapStrInt_3n(b *testing.B) {
tests.SpecBenchmarkUnmarshalMapStrInt_3n(b, NodeBuilder())
func BenchmarkSpec_Marshal_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Marshal_Map3StrInt(b, NodeBuilder())
}
func BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Marshal_MapNStrMap3StrInt(b, NodeBuilder())
}
func BenchmarkMarshalMapStrInt_3n(b *testing.B) {
tests.SpecBenchmarkMarshalMapStrInt_3n(b, NodeBuilder())
func BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Unmarshal_Map3StrInt(b, NodeBuilder())
}
func BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b, NodeBuilder())
}
// benchmarks covering traversal -->
func BenchmarkWalkMapStrInt_3n(b *testing.B) {
tests.SpecBenchmarkWalkMapStrInt_3n(b, NodeBuilder())
func BenchmarkSpec_Walk_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Walk_Map3StrInt(b, NodeBuilder())
}
func BenchmarkSpec_Walk_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Walk_MapNStrMap3StrInt(b, NodeBuilder())
}
// copy of helper functions from must package, because import cycles, sigh -->
......
HACKME
======
This package is for reusable tests and benchmarks.
These test and benchmark functions work over the Node and NodeBuilder interfaces,
so they should work to test compatibility and compare performance of various implementations of Node.
This is easier said than done.
Naming conventions
------------------
### name prefix
All reusable test functions start with the name prefix `TestSpec_`.
All reusable benchmarks start with the name prefix `BenchmarkSpec_`.
The "Test" and "Benchmark" prefixes are as per the requirements of the
golang standard `testing` package. They take `*testing.T` and `*testing.B`
arguments respectively. They also take at least one interface argument
which is how you give your Node implementation to the test spec.
The word "Spec" reflects on the fact that these are reusable/standardized tests.
We recommend you copy-paste these method names outright into the package of your Node implementation.
It's not necessary, but it's nice for consistency.
(In the future, there may be tooling to help make automated comparisons
of different Node implementation's relative performance; this would
necessarily rely on consistent names across packages.)
If your Node implementation package has *more* tests and benchmarks that
*are not* from this reusable set, that's great -- but don't use the "Spec"
word as a segment of their name; it'll make processing bulk output easier.
### full pattern
The full pattern is:
`BenchmarkSpec_{Application}_{FixtureCohort}/codec={codec}/n={size}`
- `{Application}` means what feature or big-picture behavior we're testing.
Examples include "Marshal", "Unmarshal", "Walk", etc.
- `{FixtureCohort}` means... well, see the names from the 'corpus' subpackage;
it should be literally one of those strings.
- `n={size}` will be present for variable-scale benchmarks.
You'll have to consider the Application and FixtureCohort to understand the
context of what part of the data is being varied in size, though.
- `codec={codec}` is an example of extra info that might exist for some applications.
For example, it might include "json" and "cbor" for "Marshal" and "Unmarshal",
but will not be seen at all in other applications like "Walk".
The parts after the slash are those which are handled internally.
For those, you call the `BenchmarkSpec_*` function name (stopping before the first slash),
and that function will call `b.Run` to make sub-tests for all the variations.
For example, when you call `BenchmarkSpec_Walk_MapNStrMap3StrInt`, that one call
will result in a suite of tests for various sizes, each of which will be denoted
in the output by `BenchmarkSpec_Walk_MapNStrMap3StrInt/n=1`, then `.../n=2`, etc.
### variable scale benchmarks
Some corpuses have fixed sizes. Some are variable.
With fixed-size corpuses, you'll see an integer in the "FixtureCohort" name.
For variable-size corpuses, you'll see the letter "N" in place of an integer.
See the docs in the 'corpus' subpackage for more discussion of this.
......@@ -49,3 +49,10 @@ func MapNStrInt(n int) string {
return fmt.Sprintf(`"k%d":%d`, i, i)
}) + `}`
}
func MapNStrMap3StrInt(n int) string {
return `{` + ents(n, func(i int) string {
return fmt.Sprintf(`"k%d":`, i) +
fmt.Sprintf(`{"whee":%d,"woot":%d,"waga":%d}`, i*3+1, i*3+2, i*3+3)
}) + `}`
}
......@@ -16,4 +16,7 @@ func TestCorpusValidity(t *testing.T) {
must.True(json.Valid([]byte(MapNStrInt(0))))
must.True(json.Valid([]byte(MapNStrInt(1))))
must.True(json.Valid([]byte(MapNStrInt(2))))
must.True(json.Valid([]byte(MapNStrMap3StrInt(0))))
must.True(json.Valid([]byte(MapNStrMap3StrInt(1))))
must.True(json.Valid([]byte(MapNStrMap3StrInt(2))))
}
......@@ -2,12 +2,14 @@ package tests
import (
"bytes"
"fmt"
"testing"
refmtjson "github.com/polydawn/refmt/json"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
......@@ -19,18 +21,48 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
func SpecBenchmarkMarshalMapStrInt_3n(b *testing.B, nb ipld.NodeBuilder) {
n, err := encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(`{"whee":1,"woot":2,"waga":3}`)))
if err != nil {
panic(err)
}
func BenchmarkSpec_Marshal_Map3StrInt(b *testing.B, nb ipld.NodeBuilder) {
msg := corpus.Map3StrInt()
node := mustNodeFromJsonString(nb, msg)
b.ResetTimer()
var buf bytes.Buffer
var err error
for i := 0; i < b.N; i++ {
var buf bytes.Buffer
err = encoding.Marshal(n, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
sink = buf
buf = bytes.Buffer{}
err = encoding.Marshal(node, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
}
b.StopTimer()
if err != nil {
panic(err)
b.Fatalf("marshal errored: %s", err)
}
if buf.String() != msg {
b.Fatalf("marshal didn't match corpus")
}
}
func BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B, nb ipld.NodeBuilder) {
for _, n := range []int{0, 1, 2, 4, 8, 16, 32} {
b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
msg := corpus.MapNStrMap3StrInt(n)
node := mustNodeFromJsonString(nb, msg)
b.ResetTimer()
var buf bytes.Buffer
var err error
for i := 0; i < b.N; i++ {
buf = bytes.Buffer{}
err = encoding.Marshal(node, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
}
b.StopTimer()
if err != nil {
b.Fatalf("marshal errored: %s", err)
}
if buf.String() != msg {
b.Fatalf("marshal didn't match corpus")
}
})
}
}
package tests
import (
"bytes"
"fmt"
"testing"
refmtjson "github.com/polydawn/refmt/json"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/tests/corpus"
"github.com/ipld/go-ipld-prime/traversal"
"github.com/ipld/go-ipld-prime/traversal/selector"
)
func SpecBenchmarkWalkMapStrInt_3n(b *testing.B, nb ipld.NodeBuilder) {
n, err := encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(corpus.Map3StrInt())))
if err != nil {
panic(err)
}
seldefn, err := encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(`{"a":{">":{".":{}}}}`)))
if err != nil {
panic(err)
}
sel, err := selector.ParseSelector(seldefn)
if err != nil {
panic(err)
}
func BenchmarkSpec_Walk_Map3StrInt(b *testing.B, nb ipld.NodeBuilder) {
node := mustNodeFromJsonString(nb, corpus.Map3StrInt())
sel := mustSelectorFromJsonString(nb, `{"a":{">":{".":{}}}}`)
b.ResetTimer()
var visitCountSanityCheck int
for i := 0; i < b.N; i++ {
traversal.WalkMatching(n, sel, func(tp traversal.Progress, n ipld.Node) error {
return nil // no need to do anything here; just care about exercising the walk internals.
visitCountSanityCheck = 0
traversal.WalkMatching(node, sel, func(tp traversal.Progress, n ipld.Node) error {
visitCountSanityCheck++ // this sanity check is sufficiently cheap to be worth it
return nil // no need to do anything here; just care about exercising the walk internals.
})
}
if visitCountSanityCheck != 3 {
b.Fatalf("visitCountSanityCheck should be 3, got %d", visitCountSanityCheck)
}
}
func BenchmarkSpec_Walk_MapNStrMap3StrInt(b *testing.B, nb ipld.NodeBuilder) {
sel := mustSelectorFromJsonString(nb, `{"a":{">":{"a":{">":{".":{}}}}}}`)
for _, n := range []int{0, 1, 2, 4, 8, 16, 32} {
b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
node := mustNodeFromJsonString(nb, corpus.MapNStrMap3StrInt(n))
b.ResetTimer()
var visitCountSanityCheck int
for i := 0; i < b.N; i++ {
visitCountSanityCheck = 0
traversal.WalkMatching(node, sel, func(tp traversal.Progress, n ipld.Node) error {
visitCountSanityCheck++ // this sanity check is sufficiently cheap to be worth it
return nil // no need to do anything here; just care about exercising the walk internals.
})
}
if visitCountSanityCheck != 3*n {
b.Fatalf("visitCountSanityCheck should be %d, got %d", n*3, visitCountSanityCheck)
}
})
}
}
......@@ -2,12 +2,14 @@ package tests
import (
"bytes"
"fmt"
"testing"
refmtjson "github.com/polydawn/refmt/json"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
......@@ -19,14 +21,48 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
var sink interface{}
func BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B, nb ipld.NodeBuilder) {
msg := corpus.Map3StrInt()
b.ResetTimer()
func SpecBenchmarkUnmarshalMapStrInt_3n(b *testing.B, nb ipld.NodeBuilder) {
var node ipld.Node
var err error
for i := 0; i < b.N; i++ {
sink, err = encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(`{"whee":1,"woot":2,"waga":3}`)))
node, err = encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(msg)))
}
b.StopTimer()
if err != nil {
panic(err)
b.Fatalf("unmarshal errored: %s", err)
}
var buf bytes.Buffer
encoding.Marshal(node, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
if buf.String() != msg {
b.Fatalf("remarshal didn't match corpus")
}
}
func BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B, nb ipld.NodeBuilder) {
for _, n := range []int{0, 1, 2, 4, 8, 16, 32} {
b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
msg := corpus.MapNStrMap3StrInt(n)
b.ResetTimer()
var node ipld.Node
var err error
for i := 0; i < b.N; i++ {
node, err = encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(msg)))
}
b.StopTimer()
if err != nil {
b.Fatalf("unmarshal errored: %s", err)
}
var buf bytes.Buffer
encoding.Marshal(node, refmtjson.NewEncoder(&buf, refmtjson.EncodeOptions{}))
if buf.String() != msg {
b.Fatalf("remarshal didn't match corpus")
}
})
}
}
package tests
import (
"bytes"
refmtjson "github.com/polydawn/refmt/json"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/must"
"github.com/ipld/go-ipld-prime/traversal/selector"
)
func mustNodeFromJsonString(nb ipld.NodeBuilder, str string) ipld.Node {
return must.Node(encoding.Unmarshal(nb, refmtjson.NewDecoder(bytes.NewBufferString(str))))
}
func mustSelectorFromJsonString(nb ipld.NodeBuilder, str string) selector.Selector {
// Needing an 'nb' parameter here is sort of off-topic, to be honest.
// Someday the selector package will probably contain codegen'd nodes of its own schema, and we'll use those unconditionally.
// For now... we'll just use whatever node you're already testing, because it oughta work
// (and because it avoids hardcoding any other implementation that might cause import cycle funtimes.).
seldefn := mustNodeFromJsonString(nb, str)
sel, err := selector.ParseSelector(seldefn)
must.NotError(err)
return sel
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment