diff --git a/meta.go b/meta.go index 1ff8344..f06c6e7 100644 --- a/meta.go +++ b/meta.go @@ -6,6 +6,17 @@ func ReadGeneric(r Reader, createFunc StructFactory, field string) (Readable, er if err := r.BeginContainer(field); err != nil { return nil, err } + size, err := r.ContainerSize() + if err != nil { + return nil, err + } + if size == 0 { + if err := r.EndContainer(); err != nil { + return nil, err + } + + return nil, nil + } var classId uint32 if err := r.ReadUint32(&classId, classField); err != nil { diff --git a/msgpack_assoc_reader.go b/msgpack_assoc_reader.go index 01dfc27..d8a0ad3 100644 --- a/msgpack_assoc_reader.go +++ b/msgpack_assoc_reader.go @@ -559,6 +559,19 @@ func (rd *msgpackAssocReader) beginContainer(field string) error { } switch { + case code == msgpcode.Nil: + if err := rd.dec.DecodeNil(); err != nil { + return errors.WithStack(err) + } + rd.stack = append(rd.stack, rd.curr) + rd.curr = assocReadContainer{ + started: true, + length: 0, + assoc: true, + values: make(map[string]msgpack.RawMessage), + reader: rd.dec.Buffered(), + } + case msgpcode.IsFixedMap(code), code == msgpcode.Map16, code == msgpcode.Map32: l, err := rd.dec.DecodeMapLen() if err != nil { diff --git a/msgpack_assoc_reader_test.go b/msgpack_assoc_reader_test.go index e0e0d12..20ef495 100644 --- a/msgpack_assoc_reader_test.go +++ b/msgpack_assoc_reader_test.go @@ -11,8 +11,8 @@ import ( func TestAssocMsgpackReader(t *testing.T) { t.Run("reading parent", func(t *testing.T) { - // {"f1":"blabla","f3":[2,4,6],"f2":{"field":1},"f4":[{"field":10},{"field":1024}]} - src := "84a26631a6626c61626c61a2663393020406a2663281a56669656c6401a266349281a56669656c640a81a56669656c64cd0400" + // {"f1":"blabla","f3":[2,4,6],"f2":{"field":1},"f4":[{"field":10},{"field":1024}],"f5":null} + src := "85A26631A6626C61626C61A2663393020406A2663281A56669656C6401A266349281A56669656C640A81A56669656C64CD0400A26635C0" expected := TestParent{ Field1: "blabla", @@ -39,7 +39,7 @@ func TestAssocMsgpackReader(t *testing.T) { t.Run("reading child", func(t *testing.T) { // {"f":"qwerty","f1":"blabla","f3":[2,4,6],"f2":{"field":1},"f4":[{"field":10},{"field":1024}]} - src := "85a166a6717765727479a26631a6626c61626c61a2663393020406a2663281a56669656c6401a266349281a56669656c640a81a56669656c64cd0400" + src := "85A166A6717765727479A26631A6626C61626C61A2663393020406A2663281A56669656C6401A266349281A56669656C640A81A56669656C64CD0400" expected := TestChild{ Field: "qwerty", @@ -68,8 +68,8 @@ func TestAssocMsgpackReader(t *testing.T) { }) t.Run("fail reading parent as array", func(t *testing.T) { - // ["blabla",[1],[2,4,6],[[10],[1024]]] - src := "94a6626c61626c6191019302040692910a91cd0400" + // ["blabla",[1],[2,4,6],[[10],[1024]],null] + src := "95A6626C61626C6191019302040692910A91CD0400C0" expected := TestParent{} @@ -85,8 +85,8 @@ func TestAssocMsgpackReader(t *testing.T) { }) t.Run("fail reading parent as array with maps", func(t *testing.T) { - // ["blabla",{"field":1},[2,4,6],[{"field":10},{"field":1024}]] - src := "94a6626c61626c6181a56669656c6401930204069281a56669656c640a81a56669656c64cd0400" + // ["blabla",{"field":1},[2,4,6],[{"field":10},{"field":1024}],null] + src := "95A6626C61626C6181A56669656C6401930204069281A56669656C640A81A56669656C64CD0400C0" expected := TestParent{} @@ -102,8 +102,8 @@ func TestAssocMsgpackReader(t *testing.T) { }) t.Run("fail reading child as array", func(t *testing.T) { - // ["blabla",[1],[2,4,6],[[10],[1024]],"qwerty"] - src := "95a6626c61626c6191019302040692910a91cd0400a6717765727479" + // ["blabla",[1],[2,4,6],[[10],[1024]],null,"qwerty"] + src := "96A6626C61626C6191019302040692910A91CD0400C0A6717765727479" expected := TestChild{} diff --git a/msgpack_reader.go b/msgpack_reader.go index 0799666..7d1a88f 100644 --- a/msgpack_reader.go +++ b/msgpack_reader.go @@ -139,6 +139,15 @@ func (rd *msgpackReader) beginContainer(field string) error { } switch { + case code == msgpcode.Nil: + if err := rd.dec.DecodeNil(); err != nil { + return errors.WithStack(err) + } + rd.stack = append(rd.stack, rd.curr) + rd.curr = readContainer{ + length: 0, + } + case msgpcode.IsFixedArray(code), code == msgpcode.Array16, code == msgpcode.Array32: l, err := rd.dec.DecodeArrayLen() if err != nil { diff --git a/msgpack_reader_test.go b/msgpack_reader_test.go index 49c57af..f791b7b 100644 --- a/msgpack_reader_test.go +++ b/msgpack_reader_test.go @@ -11,8 +11,8 @@ import ( func TestMsgpackReader(t *testing.T) { t.Run("reading parent", func(t *testing.T) { - // ["blabla",[1],[2,4,6],[[10],[1024]]] - src := "94a6626c61626c6191019302040692910a91cd0400" + // ["blabla",[1],[2,4,6],[[10],[1024]],null] + src := "95A6626C61626C6191019302040692910A91CD0400C0" expected := TestParent{ Field1: "blabla", @@ -38,8 +38,8 @@ func TestMsgpackReader(t *testing.T) { }) t.Run("reading child", func(t *testing.T) { - // ["blabla",[1],[2,4,6],[[10],[1024]],"qwerty"] - src := "95a6626c61626c6191019302040692910a91cd0400a6717765727479" + // ["blabla",[1],[2,4,6],[[10],[1024]],null,"qwerty"] + src := "96A6626C61626C6191019302040692910A91CD0400C0A6717765727479" expected := TestChild{ Field: "qwerty", diff --git a/structs_test.go b/structs_test.go index 71b323f..a34637f 100644 --- a/structs_test.go +++ b/structs_test.go @@ -2,13 +2,39 @@ package meta_test import ( "git.bit5.ru/backend/meta/v5" + "github.com/pkg/errors" ) +func CreateTestParent(id uint32) (meta.Readable, error) { + if id == 111 { + return &TestParent{}, nil + } + return nil, errors.Errorf("wrong id") +} + type TestParent struct { - Field1 string `json:"f1" msgpack:"f1"` - Field2 TestFoo `json:"f2" msgpack:"f2"` - Field3 []int8 `json:"f3" msgpack:"f3"` - Field4 []TestFoo `json:"f4" msgpack:"f4"` + Field1 string `json:"f1" msgpack:"f1"` + Field2 TestFoo `json:"f2" msgpack:"f2"` + Field3 []int8 `json:"f3" msgpack:"f3"` + Field4 []TestFoo `json:"f4" msgpack:"f4"` + Field5 ITestParent `json:"f5" msgpack:"f5"` +} + +type ITestParent interface { + meta.Struct + PtrTestParent() *TestParent +} + +func (s *TestParent) PtrTestParent() *TestParent { + return s +} + +func (s *TestParent) ClassId() uint32 { + return 111 +} + +func (s *TestParent) ClassName() string { + return "TestParent" } func (s *TestParent) Reset() { @@ -26,6 +52,8 @@ func (s *TestParent) Reset() { s.Field4 = s.Field4[:0] } + s.Field5 = nil + } func (s *TestParent) Read(reader meta.Reader) error { @@ -46,8 +74,8 @@ func (s *TestParent) ReadFields(reader meta.Reader) error { return err } - if contSize < 4 { - contSize = 4 + if contSize < 5 { + contSize = 5 } if contSize <= 0 { @@ -128,6 +156,21 @@ func (s *TestParent) ReadFields(reader meta.Reader) error { return err } + if contSize <= 0 { + return nil + } + + contSize-- + if v, err := meta.ReadGeneric(reader, CreateTestParent, "f5"); err != nil { + if err != meta.FieldNotFound { + return err + } + } else { + if v != nil { + s.Field5 = v.(ITestParent) + } + } + return nil } @@ -191,6 +234,10 @@ func (s *TestParent) WriteFields(writer meta.Writer) error { return nil } +func (s *TestParent) FieldsCount() int { + return 5 +} + type TestChild struct { TestParent