ugorji / go

idiomatic codec and rpc lib for msgpack, cbor, json, etc. msgpack.org[Go]
MIT License
1.86k stars 295 forks source link

CodecEncodeSelf() does not return output buffer for BytesEncoder #200

Closed shory152 closed 7 years ago

shory152 commented 7 years ago

msg_test.go:

package shory

import "reflect"
import "github.com/ugorji/go/codec"
import "testing"

func TestMsg(t *testing.T){

    var mh codec.MsgpackHandle
    var h *codec.MsgpackHandle

    mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
    mh.SliceType = reflect.TypeOf([]interface{}(nil))
    mh.EncodeOptions.StructToArray = true
    h = &mh

    msg1 := Msg{ID:1,Name:"msg1",Value:"value1"}
    var pkgbuf []byte
    enc := codec.NewEncoderBytes(&pkgbuf,h)
    msg1.CodecEncodeSelf(enc)
        //
    // **NOTE: after encoding, the pkgbuf is still nil !!! **
        // That is to say, CodecEncodeSelf(enc) does NOT set the output buffer to pkgbuf.
        // So, I can not get the package encoded by CodecEncodeSelf() ! 
        //
    if pkgbuf != nil {
        t.Log("encode msg OK:", msg1)
    } else {
        t.Fatal("encode msg ERR: no output!", msg1)
    }

    dec := codec.NewDecoderBytes(pkgbuf,h)
    var msg2 Msg
    msg2.CodecDecodeSelf(dec)

    if msg1.ID == msg2.ID && msg1.Name == msg2.Name && msg1.Value == msg2.Value {
        t.Log("decode msg OK:", msg2)
    } else {
        t.Error("decode msg ERR:", msg2)
    }
}
shory152 commented 7 years ago

the msg.go like below:

package shory

import "github.com/ugorji/go/codec"

type Msg struct {
    ID int
    Name string
    Value string
}

type MsgSlice []Msg

type Dummy struct{}
func (d *Dummy)CodecEncodeSelf(encoder *codec.Encoder){}
func (d *Dummy)CodecDecodeSelf(decoder *codec.Decoder){}

codecgen -o msg_gen.go msg.go

ugorji commented 7 years ago

Please State what you are trying to do, what you expect to happen, what happens, and how to reproduce it. Right now, you just gave me code, and I don't know what to do with it.

Time is tight. I depend on you being clear.

ugorji commented 7 years ago

duplicate of #199

shory152 commented 7 years ago

Thank you very much.

In fact this is another problem.

Calling CodecEncodeSelf() with bytes encoder, the output slice is nil. e.g.

        msg1 := Msg{ID:1,Name:"msg1",Value:"value1"}
    var pkgbuf []byte
    enc := codec.NewEncoderBytes(&pkgbuf,h)
    msg1.CodecEncodeSelf(enc)

NOTE: pkgbuf is still nil. since the enc.w.atEndOfEncode() was NOT called.

If export a new func enc.FlushBytes(), the encoded slice can be catched by user. e.g.

func (e *Encoder) FlushBytes() {
    e.w.atEndOfEncode()
}

after calls enc.FlushBytes, the pkgbuf contains expected msg.

ugorji commented 7 years ago

That's the slippery slope I'm not happy with. I would rather ensure that the use-case of encoding or decoding is done completely from the enc.Encode call, and that handles the orchestration. You are doing it wrong, by calling CodecEncodeSelf yourself.

I fixed the other one, because it worked as a side effect of enc.Decode calling "TryDecodeAsNil", which will call a readn1() first. I didn't fix it because I expected calling Codec(En|De)codeSelf to work. You should use the published methods of enc.Encode or dec.Decode.

Exposing FlushBytes, when it only applies to []byte writer, but not io.Writer, is fraught with peril. It complicates the API and is not universally needed.

There's a single, simple API to use. Use it. If there are performance issues, we have worked hard to reduce them, and it will get better with enhancements in the go runtime.