fastjson icon indicating copy to clipboard operation
fastjson copied to clipboard

MarshalTo doesn't actually append to the passed in slice

Open mmacdermaid opened this issue 6 years ago • 5 comments

func TestMarshalTo(t *testing.T) {
	var p fastjson.Parser
	v, err := p.Parse(`{
			"str": "bar",
			"int": 123,
			"float": 1.23,
			"bool": true,
			"arr": [1, "foo", {}]
	}`)
	if err != nil {
		log.Fatal(err)
	}

	out := make([]byte, 0, 50000)
	log.Println(string(v.MarshalTo(out)))
	log.Println(string(out))
}
2019/01/24 12:15:45: {"str":"bar","int":123,"float":1.23,"bool":true,"arr":[1,"foo",{}]}
2019/01/24 12:15:45:

You are returning a newly appended slice instead of attempting to append to the passed in slice. Passed in slice needs to be *[]byte for it to work as I think you have intended.

Or you can just copy() instead of append as append will cause allocations if the slice isn't large enough.

mmacdermaid avatar Jan 24 '19 17:01 mmacdermaid

MarshalTo must append data to the passed in slice. Just len(out) = 0 in the code above, so its' length must be extended before comparison. Try running the following code:

out := make([]byte, 0, 50000)
outNew := v.MarshalTo(out)
// Verify whether MarshalTo added data to out or put it to another memory
outExtended := out[:len(outNew)]
if bytes.Equal(outNew, outExtended) {
  log.Println("outNew points to out memory")
} else {
  log.Println("outNew points to another memory")
}

valyala avatar Jan 24 '19 17:01 valyala

See https://blog.golang.org/go-slices-usage-and-internals to understand better how slices in Go work

valyala avatar Jan 24 '19 17:01 valyala

Are you saying the proper use case for MarshalTo should then be.

out := make([]byte, 0, 50000) //or some other form of pre-allocation
out = v.MarshalTo(out)

mmacdermaid avatar Jan 24 '19 18:01 mmacdermaid

The proper use case for MarshalTo is:

// The out slice is defined once and re-used multiple times
// inside the loop for marshaling different values.
var out []byte
for {
    // obtain v here
    out = v.MarshalTo(out[:0])
    // use out here
}

valyala avatar Jan 24 '19 19:01 valyala

:+1: thanks

mmacdermaid avatar Jan 24 '19 19:01 mmacdermaid