Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ jobs:
- name: Test
env:
GOFLAGS: ${{ matrix.flags }}
run: go test -coverprofile=profile.out -covermode=atomic -v -coverpkg=./... ./...
run: go test -coverprofile=profile-go${{ matrix.go-version }}${{ matrix.flags }}.out -covermode=atomic -v -coverpkg=./... ./...

- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage
name: coverage-go${{ matrix.go-version }}${{ matrix.flags }}
path: |
profile.out
profile-go${{ matrix.go-version }}${{ matrix.flags }}.out
if-no-files-found: error
retention-days: 1

Expand All @@ -52,9 +52,10 @@ jobs:
uses: actions/checkout@v4

- name: Download artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: coverage
pattern: coverage-*
merge-multiple: true

- name: Send coverage
uses: codecov/codecov-action@v3
Expand Down
38 changes: 38 additions & 0 deletions insane.go
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,44 @@ func (n *Node) MutateToStrict() *StrictNode {
return &StrictNode{n}
}

// CopyFromNode copies all data from the src node to the current node.
// `root` must be a root of the current node to utilize the same node pool.
// If the `src` node is a node tree, the whole tree will be copied recursively.
// This function is designed to use for copying data from node of one JSON tree
// to another so they don't mutate each others data and utilize their own node
// pools so the garbage collector can clean released nodes correctly.
func (n *Node) CopyFromNode(root *Root, src *Node) *Node {
if n == nil || src == nil {
return nil
}

n.bits = src.bits
n.data = strings.Clone(src.data)
n.next = n.getNode(root)
n.next.parent = n.parent
n.next.CopyFromNode(root, src.next)

if len(src.nodes) > 0 {
n.nodes = make([]*Node, 0, len(src.nodes))
for _, child := range src.nodes {
newChild := n.getNode(root)
newChild.parent = n
n.nodes = append(n.nodes, newChild.CopyFromNode(root, child))
}
}

if src.fields != nil {
srcFields := *src.fields
newFields := make(map[string]int, len(srcFields))
for k, v := range srcFields {
newFields[k] = v
}
n.fields = &newFields
}

return n
}

func (n *Node) DigField(path ...string) *Node {
if n == nil || len(path) == 0 {
return nil
Expand Down
25 changes: 23 additions & 2 deletions insane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ func TestDecodeErr(t *testing.T) {
{json: `falsenull`, err: ErrUnexpectedJSONEnding},
{json: `null:`, err: ErrUnexpectedJSONEnding},


// ok
{json: `0`, err: nil},
{json: `1.0`, err: nil},
Expand Down Expand Up @@ -374,7 +373,7 @@ func TestAddElement(t *testing.T) {
for index := 0; index < test.count; index++ {
root.AddElement()
l := len(root.AsArray())
assert.True(t, root.Dig(strconv.Itoa(l - 1)).IsNull(), "wrong node type")
assert.True(t, root.Dig(strconv.Itoa(l-1)).IsNull(), "wrong node type")
}
assert.Equal(t, test.result, root.EncodeToString(), "wrong encoding")
Release(root)
Expand Down Expand Up @@ -1054,3 +1053,25 @@ func TestIndex(t *testing.T) {

assert.Equal(t, index, node.getIndex(), "wrong index")
}

func TestCopyFromNode(t *testing.T) {
json := `{"first":["s1","s2","s3"],"second":[{"s4":true},{"s5":false}]}`
root1, err := DecodeString(json)
assert.NoError(t, err, "error while decoding")
assert.NotNil(t, root1, "node shouldn't be nil")

root2 := Spawn()
clonedRoot := root2.CopyFromNode(root2, root1.Node)
assert.NotNil(t, clonedRoot, "node shouldn't be nil")

array1 := root1.Dig("first").AsArray()
array2 := root2.Dig("first").AsArray()
assert.Equal(t, len(array1), len(array2))
for i := range array1 {
assert.Equal(t, array1[i].AsString(), array2[i].AsString())
}

origVal := strings.Clone(array1[0].data)
array2[0].data = "newData"
assert.NotEqual(t, array1[0].AsString(), array2[0].AsString(), "values must be different, first value must be %q, but it was changed to %q", origVal, array1[0].data)
}