ugorji / go

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

Decoding a slice of structs encoded as arrays into a slice of structs without the same number of fields #391

Closed partomatl closed 1 year ago

partomatl commented 1 year ago

Since v1.2.9, using codecgen'erated code, decoding a slice of structs that are encoded as arrays into a slice of structs with missing trailing fields fails.

The code below works perfectly with version 1.2.8 with or without codecgen'erated code. It has been working well since (at least) v1.1.1. Note that types.D does not have a Field2 field.

With 1.2.9 and 1.2.10, it works well without codecgen'erated code. But with codecgen'erated code (cd types && go generate), the decoding fails with msgpack decode error [pos 4]: only encoded map or array can be decoded into a struct.

I am using Go 1.19 with codecgen v1.2.10 (internal version 26) works with github.com/ugorji/go/codec library v1.2.8 +

main.go

package main

import (
  "bufio"
  "bytes"
  "fmt"
  "log"

  "codecgen-fail/types"

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

func main() {
  eslice := []types.E{
      {Field1: 1, Field2: 2},
      {Field1: 3, Field2: 4},
  }

  payload, err := encode(eslice)
  if err != nil {
      log.Fatal(err)
  }

  dslice, err := decode(payload)
  if err != nil {
      log.Fatal(err)
  }

  fmt.Println(dslice)
}

func encode(eslice []types.E) ([]byte, error) {
  var h codec.MsgpackHandle
  h.StructToArray = true

  var w bytes.Buffer
  var bw = bufio.NewWriter(&w)
  var enc = codec.NewEncoder(bw, &h)

  if err := enc.Encode(eslice); err != nil {
      return nil, err
  }

  if err := bw.Flush(); err != nil {
      return nil, err
  }

  return w.Bytes(), nil
}

func decode(payload []byte) ([]types.D, error) {
  var h codec.MsgpackHandle
  var br = bufio.NewReader(bytes.NewReader(payload))
  var dec = codec.NewDecoder(br, &h)

  var obj []types.D
  if err := dec.Decode(&obj); err != nil {
      return nil, err
  }

  return obj, nil
}

types/codec.go

package types

//go:generate codecgen -o codecgen.go codec.go

type E struct {
  Field1 int64 `codec:"field1"`
  Field2 int64 `codec:"field2"`
}

type D struct {
  Field1 int64 `codec:"field1"`
}
partomatl commented 1 year ago

@ugorji thanks! Do you know when this fix will be released?

ugorji commented 1 year ago

@partomatl v1.2.11 was just released. See