Compare commits

..

4 Commits

9 changed files with 167 additions and 19 deletions

View File

@ -1,12 +1,18 @@
package meta package meta
import "bytes"
type ChangedFields struct { type ChangedFields struct {
fieldNames map[string]struct{} fieldNames map[string]struct{}
fieldsKey *bytes.Buffer
} }
func NewChangedFields(fieldCount int) ChangedFields { func NewChangedFields(fieldCount int) ChangedFields {
keyBuffer := bytes.NewBuffer(make([]byte, 0, fieldCount*2))
cf := ChangedFields{ cf := ChangedFields{
fieldNames: make(map[string]struct{}, fieldCount), fieldNames: make(map[string]struct{}, fieldCount),
fieldsKey: keyBuffer,
} }
return cf return cf
} }
@ -32,7 +38,12 @@ func (cf *ChangedFields) SetChanged(fields ...string) {
} }
for _, field := range fields { for _, field := range fields {
if _, exists := cf.fieldNames[field]; exists {
continue
}
cf.fieldNames[field] = struct{}{} cf.fieldNames[field] = struct{}{}
cf.fieldsKey.WriteString(field)
} }
} }
@ -43,3 +54,7 @@ func (cf ChangedFields) Empty() bool {
func (cf ChangedFields) IsNil() bool { func (cf ChangedFields) IsNil() bool {
return cf.fieldNames == nil return cf.fieldNames == nil
} }
func (cf ChangedFields) GetFieldsKey() string {
return cf.fieldsKey.String()
}

33
changed_fields_test.go Normal file
View File

@ -0,0 +1,33 @@
package meta
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestChangedFields(t *testing.T) {
t.Run("#SetChanged", func(t *testing.T) {
changedFields := NewChangedFields(3)
expectedFieldsMap := map[string]struct{}{
"a": {},
"b": {},
"c": {},
}
changedFields.SetChanged("a", "b", "c", "a")
assert.Equal(t, expectedFieldsMap, changedFields.fieldNames)
})
t.Run("#GetFieldsKey", func(t *testing.T) {
changedFields := NewChangedFields(3)
changedFields.SetChanged("b", "c", "a")
expectedKey := "bca"
actualKey := changedFields.GetFieldsKey()
assert.Equal(t, expectedKey, actualKey)
})
}

View File

@ -94,3 +94,8 @@ type WritableClass interface {
Class Class
Writable Writable
} }
type ReadableWritable interface {
Readable
Writable
}

11
meta.go
View File

@ -6,6 +6,17 @@ func ReadGeneric(r Reader, createFunc StructFactory, field string) (Readable, er
if err := r.BeginContainer(field); err != nil { if err := r.BeginContainer(field); err != nil {
return nil, err 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 var classId uint32
if err := r.ReadUint32(&classId, classField); err != nil { if err := r.ReadUint32(&classId, classField); err != nil {

View File

@ -559,6 +559,19 @@ func (rd *msgpackAssocReader) beginContainer(field string) error {
} }
switch { 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: case msgpcode.IsFixedMap(code), code == msgpcode.Map16, code == msgpcode.Map32:
l, err := rd.dec.DecodeMapLen() l, err := rd.dec.DecodeMapLen()
if err != nil { if err != nil {

View File

@ -11,8 +11,8 @@ import (
func TestAssocMsgpackReader(t *testing.T) { func TestAssocMsgpackReader(t *testing.T) {
t.Run("reading parent", func(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}]} // {"f1":"blabla","f3":[2,4,6],"f2":{"field":1},"f4":[{"field":10},{"field":1024}],"f5":null}
src := "84a26631a6626c61626c61a2663393020406a2663281a56669656c6401a266349281a56669656c640a81a56669656c64cd0400" src := "85A26631A6626C61626C61A2663393020406A2663281A56669656C6401A266349281A56669656C640A81A56669656C64CD0400A26635C0"
expected := TestParent{ expected := TestParent{
Field1: "blabla", Field1: "blabla",
@ -39,7 +39,7 @@ func TestAssocMsgpackReader(t *testing.T) {
t.Run("reading child", func(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}]} // {"f":"qwerty","f1":"blabla","f3":[2,4,6],"f2":{"field":1},"f4":[{"field":10},{"field":1024}]}
src := "85a166a6717765727479a26631a6626c61626c61a2663393020406a2663281a56669656c6401a266349281a56669656c640a81a56669656c64cd0400" src := "85A166A6717765727479A26631A6626C61626C61A2663393020406A2663281A56669656C6401A266349281A56669656C640A81A56669656C64CD0400"
expected := TestChild{ expected := TestChild{
Field: "qwerty", Field: "qwerty",
@ -68,8 +68,8 @@ func TestAssocMsgpackReader(t *testing.T) {
}) })
t.Run("fail reading parent as array", func(t *testing.T) { t.Run("fail reading parent as array", func(t *testing.T) {
// ["blabla",[1],[2,4,6],[[10],[1024]]] // ["blabla",[1],[2,4,6],[[10],[1024]],null]
src := "94a6626c61626c6191019302040692910a91cd0400" src := "95A6626C61626C6191019302040692910A91CD0400C0"
expected := TestParent{} expected := TestParent{}
@ -85,8 +85,8 @@ func TestAssocMsgpackReader(t *testing.T) {
}) })
t.Run("fail reading parent as array with maps", func(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}]] // ["blabla",{"field":1},[2,4,6],[{"field":10},{"field":1024}],null]
src := "94a6626c61626c6181a56669656c6401930204069281a56669656c640a81a56669656c64cd0400" src := "95A6626C61626C6181A56669656C6401930204069281A56669656C640A81A56669656C64CD0400C0"
expected := TestParent{} expected := TestParent{}
@ -102,8 +102,8 @@ func TestAssocMsgpackReader(t *testing.T) {
}) })
t.Run("fail reading child as array", func(t *testing.T) { t.Run("fail reading child as array", func(t *testing.T) {
// ["blabla",[1],[2,4,6],[[10],[1024]],"qwerty"] // ["blabla",[1],[2,4,6],[[10],[1024]],null,"qwerty"]
src := "95a6626c61626c6191019302040692910a91cd0400a6717765727479" src := "96A6626C61626C6191019302040692910A91CD0400C0A6717765727479"
expected := TestChild{} expected := TestChild{}

View File

@ -139,6 +139,15 @@ func (rd *msgpackReader) beginContainer(field string) error {
} }
switch { 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: case msgpcode.IsFixedArray(code), code == msgpcode.Array16, code == msgpcode.Array32:
l, err := rd.dec.DecodeArrayLen() l, err := rd.dec.DecodeArrayLen()
if err != nil { if err != nil {
@ -246,6 +255,21 @@ func decodeBool(dec *msgpack.Decoder, v *bool) error {
} }
func decodeFloat32(dec *msgpack.Decoder, v *float32) error { func decodeFloat32(dec *msgpack.Decoder, v *float32) error {
code, err := dec.PeekCode()
if err != nil {
return errors.WithStack(err)
}
if code == msgpcode.Double {
var tmp float64
if err := decodeFloat64(dec, &tmp); err != nil {
return err
}
*v = float32(tmp)
return nil
}
tmp, err := dec.DecodeFloat32() tmp, err := dec.DecodeFloat32()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)

View File

@ -11,8 +11,8 @@ import (
func TestMsgpackReader(t *testing.T) { func TestMsgpackReader(t *testing.T) {
t.Run("reading parent", func(t *testing.T) { t.Run("reading parent", func(t *testing.T) {
// ["blabla",[1],[2,4,6],[[10],[1024]]] // ["blabla",[1],[2,4,6],[[10],[1024]],null]
src := "94a6626c61626c6191019302040692910a91cd0400" src := "95A6626C61626C6191019302040692910A91CD0400C0"
expected := TestParent{ expected := TestParent{
Field1: "blabla", Field1: "blabla",
@ -38,8 +38,8 @@ func TestMsgpackReader(t *testing.T) {
}) })
t.Run("reading child", func(t *testing.T) { t.Run("reading child", func(t *testing.T) {
// ["blabla",[1],[2,4,6],[[10],[1024]],"qwerty"] // ["blabla",[1],[2,4,6],[[10],[1024]],null,"qwerty"]
src := "95a6626c61626c6191019302040692910a91cd0400a6717765727479" src := "96A6626C61626C6191019302040692910A91CD0400C0A6717765727479"
expected := TestChild{ expected := TestChild{
Field: "qwerty", Field: "qwerty",

View File

@ -2,13 +2,39 @@ package meta_test
import ( import (
"git.bit5.ru/backend/meta/v5" "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 { type TestParent struct {
Field1 string `json:"f1" msgpack:"f1"` Field1 string `json:"f1" msgpack:"f1"`
Field2 TestFoo `json:"f2" msgpack:"f2"` Field2 TestFoo `json:"f2" msgpack:"f2"`
Field3 []int8 `json:"f3" msgpack:"f3"` Field3 []int8 `json:"f3" msgpack:"f3"`
Field4 []TestFoo `json:"f4" msgpack:"f4"` 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() { func (s *TestParent) Reset() {
@ -26,6 +52,8 @@ func (s *TestParent) Reset() {
s.Field4 = s.Field4[:0] s.Field4 = s.Field4[:0]
} }
s.Field5 = nil
} }
func (s *TestParent) Read(reader meta.Reader) error { func (s *TestParent) Read(reader meta.Reader) error {
@ -46,8 +74,8 @@ func (s *TestParent) ReadFields(reader meta.Reader) error {
return err return err
} }
if contSize < 4 { if contSize < 5 {
contSize = 4 contSize = 5
} }
if contSize <= 0 { if contSize <= 0 {
@ -128,6 +156,21 @@ func (s *TestParent) ReadFields(reader meta.Reader) error {
return err 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 return nil
} }
@ -191,6 +234,10 @@ func (s *TestParent) WriteFields(writer meta.Writer) error {
return nil return nil
} }
func (s *TestParent) FieldsCount() int {
return 5
}
type TestChild struct { type TestChild struct {
TestParent TestParent