diff --git a/interface.go b/interface.go index a57f2bd..b543530 100644 --- a/interface.go +++ b/interface.go @@ -112,6 +112,9 @@ type Interface interface { // Marshal serializes first root node to w. Marshal(w io.Writer) error + // Populate fills map "to" with top root node data. + Populate(to map[string]any) + // ErrorOffset returns last error offset. ErrorOffset() int // Prealloc prepares space for further parse. diff --git a/node.go b/node.go index deab586..2482c3e 100644 --- a/node.go +++ b/node.go @@ -6,6 +6,7 @@ import ( "strconv" "unsafe" + "github.com/koykov/byteconv" "github.com/koykov/entry" "github.com/koykov/indirect" ) @@ -371,6 +372,33 @@ func (n *Node) LastChild() *Node { return nullNode } +// Populate fills map "to" with node data. +func (n *Node) Populate(to map[string]any) { + if to == nil { + return + } + switch n.Type() { + case TypeObject: + n.Each(func(_ int, node *Node) { + to[node.KeyString()] = node + }) + case TypeArray: + if vec := n.indirectVector(); vec != nil { + n.Each(func(c int, node *Node) { + key := byteconv.B2S(vec.BufferizeInt(int64(c))) + to[key] = node + }) + } + case TypeUnknown: + case TypeNull: + return + default: + if key := n.KeyString(); len(key) > 0 { + to[key] = n + } + } +} + // SortKeys sorts child nodes by key in AB order. func (n *Node) SortKeys() *Node { if n.Type() != TypeObject { diff --git a/vector.go b/vector.go index 398adfa..1b10f68 100644 --- a/vector.go +++ b/vector.go @@ -197,6 +197,13 @@ func (vec *Vector) RootTop() *Node { return &vec.nodes[rootRow[len(rootRow)-1]] } +// Populate fills map "to" with top root node data. +func (vec *Vector) Populate(to map[string]any) { + if root := vec.Root(); root != nil { + root.Populate(to) + } +} + // Each applies custom function to each root node. func (vec *Vector) Each(fn func(idx int, node *Node)) { rootRow := vec.Index.GetRow(0) diff --git a/vector_test.go b/vector_test.go index c652d9b..02e5c08 100644 --- a/vector_test.go +++ b/vector_test.go @@ -1,5 +1,34 @@ package vector -import "sync" +import ( + "sync" + "testing" +) var testPool = sync.Pool{New: func() any { return &Vector{} }} + +func TestVector(t *testing.T) { + t.Run("populate", func(t *testing.T) { + var vec Vector + _ = vec.SetSrc([]byte("zzz"), false) + r, ri := vec.AcquireNode(0) + r.SetType(TypeObject) + + n, i := vec.AcquireChildWithType(r, 1, TypeString) + n.Key().InitString("foo", 0, 3) + n.Value().InitString("qwerty", 0, 6) + r.ReleaseChild(i, n) + + n, i = vec.AcquireChildWithType(r, 1, TypeString) + n.Key().InitString("bar", 0, 3) + n.Value().InitString("asdfgh", 0, 6) + r.ReleaseChild(i, n) + + vec.ReleaseNode(ri, r) + + m := make(map[string]any) + vec.Populate(m) + + // assert m + }) +}