From 9e8cb4ad418d689818fac2ac4b52bb629e327519 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Mon, 16 Sep 2024 23:59:08 +0300 Subject: [PATCH] update codec to allow reuse buffers Signed-off-by: Vasiliy Tolstov --- codec_test.go | 15 +---- jsonpb.go | 177 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 113 insertions(+), 79 deletions(-) diff --git a/codec_test.go b/codec_test.go index 86bc568..c02815b 100644 --- a/codec_test.go +++ b/codec_test.go @@ -28,7 +28,7 @@ func TestFrameFlatten(t *testing.T) { Name: &codec.Frame{Data: []byte("test")}, } - buf, err := NewCodec().Marshal(s) + buf, err := NewCodec(codec.Flatten(true)).Marshal(s) if err != nil { t.Fatal(err) } @@ -36,16 +36,3 @@ func TestFrameFlatten(t *testing.T) { t.Fatalf("bytes not equal %s != %s", buf, `test`) } } - -func TestReadBody(t *testing.T) { - t.Skip("skip without proto message") - s := &struct { - Name string - }{} - c := NewCodec() - b := bytes.NewReader(nil) - err := c.ReadBody(b, s) - if err != nil { - t.Fatal(err) - } -} diff --git a/jsonpb.go b/jsonpb.go index 8f332df..d611275 100644 --- a/jsonpb.go +++ b/jsonpb.go @@ -1,9 +1,7 @@ -// Package jsonpb provides a json codec -package jsonpb // import "go.unistack.org/micro-codec-jsonpb/v3" +// Package jsonpb provides a json protobuf codec +package jsonpb import ( - "io" - pb "go.unistack.org/micro-proto/v3/codec" "go.unistack.org/micro/v3/codec" rutil "go.unistack.org/micro/v3/util/reflect" @@ -29,8 +27,13 @@ type jsonpbCodec struct { opts codec.Options } -const ( - flattenTag = "flatten" +type jsonpbCodecV2 struct { + opts codec.Options +} + +var ( + _ codec.Codec = (*jsonpbCodec)(nil) + _ codec.CodecV2 = (*jsonpbCodecV2)(nil) ) func (c *jsonpbCodec) Marshal(v interface{}, opts ...codec.Option) ([]byte, error) { @@ -43,8 +46,10 @@ func (c *jsonpbCodec) Marshal(v interface{}, opts ...codec.Option) ([]byte, erro o(&options) } - if nv, nerr := rutil.StructFieldByTag(v, options.TagName, flattenTag); nerr == nil { - v = nv + if options.Flatten { + if nv, nerr := rutil.StructFieldByTag(v, options.TagName, "flatten"); nerr == nil { + v = nv + } } switch m := v.(type) { @@ -52,20 +57,17 @@ func (c *jsonpbCodec) Marshal(v interface{}, opts ...codec.Option) ([]byte, erro return m.Data, nil case *pb.Frame: return m.Data, nil - } - - if _, ok := v.(proto.Message); !ok { + case proto.Message: + marshalOptions := DefaultMarshalOptions + if options.Context != nil { + if f, ok := options.Context.Value(marshalOptionsKey{}).(jsonpb.MarshalOptions); ok { + marshalOptions = f + } + } + return marshalOptions.Marshal(m) + default: return nil, codec.ErrInvalidMessage } - - marshalOptions := DefaultMarshalOptions - if options.Context != nil { - if f, ok := options.Context.Value(marshalOptionsKey{}).(jsonpb.MarshalOptions); ok { - marshalOptions = f - } - } - - return marshalOptions.Marshal(v.(proto.Message)) } func (c *jsonpbCodec) Unmarshal(d []byte, v interface{}, opts ...codec.Option) error { @@ -78,8 +80,10 @@ func (c *jsonpbCodec) Unmarshal(d []byte, v interface{}, opts ...codec.Option) e o(&options) } - if nv, nerr := rutil.StructFieldByTag(v, options.TagName, flattenTag); nerr == nil { - v = nv + if options.Flatten { + if nv, nerr := rutil.StructFieldByTag(v, options.TagName, "flatten"); nerr == nil { + v = nv + } } switch m := v.(type) { @@ -89,52 +93,17 @@ func (c *jsonpbCodec) Unmarshal(d []byte, v interface{}, opts ...codec.Option) e case *pb.Frame: m.Data = d return nil - } - - if _, ok := v.(proto.Message); !ok { - return codec.ErrInvalidMessage - } - - unmarshalOptions := DefaultUnmarshalOptions - if options.Context != nil { - if f, ok := options.Context.Value(unmarshalOptionsKey{}).(jsonpb.UnmarshalOptions); ok { - unmarshalOptions = f + case proto.Message: + unmarshalOptions := DefaultUnmarshalOptions + if options.Context != nil { + if f, ok := options.Context.Value(unmarshalOptionsKey{}).(jsonpb.UnmarshalOptions); ok { + unmarshalOptions = f + } } - } - - return unmarshalOptions.Unmarshal(d, v.(proto.Message)) -} - -func (c *jsonpbCodec) ReadHeader(conn io.Reader, m *codec.Message, t codec.MessageType) error { - return nil -} - -func (c *jsonpbCodec) ReadBody(conn io.Reader, v interface{}) error { - if v == nil { - return nil - } - buf, err := io.ReadAll(conn) - if err != nil { - return err - } else if len(buf) == 0 { - return nil - } - return c.Unmarshal(buf, v) -} - -func (c *jsonpbCodec) Write(conn io.Writer, m *codec.Message, v interface{}) error { - if v == nil { - return nil - } - - buf, err := c.Marshal(v) - if err != nil { - return err - } else if len(buf) == 0 { + return unmarshalOptions.Unmarshal(d, m) + default: return codec.ErrInvalidMessage } - _, err = conn.Write(buf) - return err } func (c *jsonpbCodec) String() string { @@ -144,3 +113,81 @@ func (c *jsonpbCodec) String() string { func NewCodec(opts ...codec.Option) codec.Codec { return &jsonpbCodec{opts: codec.NewOptions(opts...)} } + +func (c *jsonpbCodecV2) Marshal(d []byte, v interface{}, opts ...codec.Option) ([]byte, error) { + if v == nil { + return nil, nil + } + + options := c.opts + for _, o := range opts { + o(&options) + } + + if options.Flatten { + if nv, nerr := rutil.StructFieldByTag(v, options.TagName, "flatten"); nerr == nil { + v = nv + } + } + + switch m := v.(type) { + case *codec.Frame: + return m.Data, nil + case *pb.Frame: + return m.Data, nil + case proto.Message: + marshalOptions := DefaultMarshalOptions + if options.Context != nil { + if f, ok := options.Context.Value(marshalOptionsKey{}).(jsonpb.MarshalOptions); ok { + marshalOptions = f + } + } + return marshalOptions.MarshalAppend(d, m) + default: + return nil, codec.ErrInvalidMessage + } +} + +func (c *jsonpbCodecV2) Unmarshal(d []byte, v interface{}, opts ...codec.Option) error { + if v == nil || len(d) == 0 { + return nil + } + + options := c.opts + for _, o := range opts { + o(&options) + } + + if options.Flatten { + if nv, nerr := rutil.StructFieldByTag(v, options.TagName, "flatten"); nerr == nil { + v = nv + } + } + + switch m := v.(type) { + case *codec.Frame: + m.Data = d + return nil + case *pb.Frame: + m.Data = d + return nil + case proto.Message: + unmarshalOptions := DefaultUnmarshalOptions + if options.Context != nil { + if f, ok := options.Context.Value(unmarshalOptionsKey{}).(jsonpb.UnmarshalOptions); ok { + unmarshalOptions = f + } + } + return unmarshalOptions.Unmarshal(d, m) + default: + return codec.ErrInvalidMessage + } +} + +func (c *jsonpbCodecV2) String() string { + return "jsonpb" +} + +func NewCodecV2(opts ...codec.Option) codec.CodecV2 { + return &jsonpbCodecV2{opts: codec.NewOptions(opts...)} +}