Add stable marshaler for enums

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2020-08-14 17:10:15 +03:00 committed by Stanislav Bogatyrev
parent f8482381fd
commit a7a8fc33bb
4 changed files with 163 additions and 17 deletions

View file

@ -120,6 +120,14 @@ func Int32Size(field int, v int32) int {
return UInt64Size(field, uint64(v))
}
func EnumMarshal(field int, buf []byte, v int32) (int, error) {
return UInt64Marshal(field, buf, uint64(v))
}
func EnumSize(field int, v int32) int {
return UInt64Size(field, uint64(v))
}
// varUIntSize returns length of varint byte sequence for uint64 value 'x'.
func VarUIntSize(x uint64) int {
return (bits.Len64(x|1) + 6) / 7

View file

@ -10,6 +10,8 @@ import (
"github.com/stretchr/testify/require"
)
type SomeEnum int32
type stablePrimitives struct {
FieldA []byte
FieldB string
@ -18,8 +20,15 @@ type stablePrimitives struct {
FieldE uint32
FieldF int64
FieldG uint64
FieldH SomeEnum
}
const (
ENUM_UNKNOWN SomeEnum = 0
ENUM_POSITIVE = 1
ENUM_NEGATIVE = -1
)
func (s *stablePrimitives) stableMarshal(buf []byte, wrongField bool) ([]byte, error) {
if s == nil {
return []byte{}, nil
@ -103,6 +112,16 @@ func (s *stablePrimitives) stableMarshal(buf []byte, wrongField bool) ([]byte, e
}
i += offset
fieldNum = 300
if wrongField {
fieldNum++
}
offset, err = proto.EnumMarshal(fieldNum, buf, int32(s.FieldH))
if err != nil {
return nil, errors.Wrap(err, "can't marshal field g")
}
i += offset
return buf, nil
}
@ -113,7 +132,8 @@ func (s *stablePrimitives) stableSize() int {
proto.Int32Size(201, s.FieldD) +
proto.UInt32Size(202, s.FieldE) +
proto.Int64Size(203, s.FieldF) +
proto.UInt64Size(204, s.FieldG)
proto.UInt64Size(204, s.FieldG) +
proto.EnumSize(300, int32(s.FieldH))
}
func TestBytesMarshal(t *testing.T) {
@ -209,6 +229,14 @@ func TestUInt64Marshal(t *testing.T) {
})
}
func TestEnumMarshal(t *testing.T) {
testEnumMarshal(t, ENUM_UNKNOWN, false)
testEnumMarshal(t, ENUM_POSITIVE, false)
testEnumMarshal(t, ENUM_POSITIVE, true)
testEnumMarshal(t, ENUM_NEGATIVE, false)
testEnumMarshal(t, ENUM_NEGATIVE, true)
}
func testBytesMarshal(t *testing.T, data []byte, wrongField bool) {
var (
wire []byte
@ -398,3 +426,36 @@ func testUInt64Marshal(t *testing.T, n uint64, wrongField bool) {
require.EqualValues(t, 0, result.FieldG)
}
}
func testEnumMarshal(t *testing.T, e SomeEnum, wrongField bool) {
var (
wire []byte
err error
custom = stablePrimitives{FieldH: e}
transport = test.Primitives{FieldH: test.Primitives_SomeEnum(e)}
)
wire, err = custom.stableMarshal(nil, wrongField)
require.NoError(t, err)
wireGen, err := transport.Marshal()
require.NoError(t, err)
if !wrongField {
// we can check equality because single field cannot be unstable marshalled
require.Equal(t, wireGen, wire)
} else {
require.NotEqual(t, wireGen, wire)
}
result := new(test.Primitives)
err = result.Unmarshal(wire)
require.NoError(t, err)
if !wrongField {
require.EqualValues(t, custom.FieldH, result.FieldH)
} else {
require.EqualValues(t, 0, result.FieldH)
}
}

View file

@ -22,17 +22,46 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Primitives_SomeEnum int32
const (
Primitives_UNKNOWN Primitives_SomeEnum = 0
Primitives_POSITIVE Primitives_SomeEnum = 1
Primitives_NEGATIVE Primitives_SomeEnum = -1
)
var Primitives_SomeEnum_name = map[int32]string{
0: "UNKNOWN",
1: "POSITIVE",
-1: "NEGATIVE",
}
var Primitives_SomeEnum_value = map[string]int32{
"UNKNOWN": 0,
"POSITIVE": 1,
"NEGATIVE": -1,
}
func (x Primitives_SomeEnum) String() string {
return proto.EnumName(Primitives_SomeEnum_name, int32(x))
}
func (Primitives_SomeEnum) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_998ad0e1a3de8558, []int{0, 0}
}
type Primitives struct {
FieldA []byte `protobuf:"bytes,1,opt,name=field_a,json=fieldA,proto3" json:"field_a,omitempty"`
FieldB string `protobuf:"bytes,2,opt,name=field_b,json=fieldB,proto3" json:"field_b,omitempty"`
FieldC bool `protobuf:"varint,200,opt,name=field_c,json=fieldC,proto3" json:"field_c,omitempty"`
FieldD int32 `protobuf:"varint,201,opt,name=field_d,json=fieldD,proto3" json:"field_d,omitempty"`
FieldE uint32 `protobuf:"varint,202,opt,name=field_e,json=fieldE,proto3" json:"field_e,omitempty"`
FieldF int64 `protobuf:"varint,203,opt,name=field_f,json=fieldF,proto3" json:"field_f,omitempty"`
FieldG uint64 `protobuf:"varint,204,opt,name=field_g,json=fieldG,proto3" json:"field_g,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
FieldA []byte `protobuf:"bytes,1,opt,name=field_a,json=fieldA,proto3" json:"field_a,omitempty"`
FieldB string `protobuf:"bytes,2,opt,name=field_b,json=fieldB,proto3" json:"field_b,omitempty"`
FieldC bool `protobuf:"varint,200,opt,name=field_c,json=fieldC,proto3" json:"field_c,omitempty"`
FieldD int32 `protobuf:"varint,201,opt,name=field_d,json=fieldD,proto3" json:"field_d,omitempty"`
FieldE uint32 `protobuf:"varint,202,opt,name=field_e,json=fieldE,proto3" json:"field_e,omitempty"`
FieldF int64 `protobuf:"varint,203,opt,name=field_f,json=fieldF,proto3" json:"field_f,omitempty"`
FieldG uint64 `protobuf:"varint,204,opt,name=field_g,json=fieldG,proto3" json:"field_g,omitempty"`
FieldH Primitives_SomeEnum `protobuf:"varint,300,opt,name=field_h,json=fieldH,proto3,enum=test.Primitives_SomeEnum" json:"field_h,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Primitives) Reset() { *m = Primitives{} }
@ -117,26 +146,38 @@ func (m *Primitives) GetFieldG() uint64 {
return 0
}
func (m *Primitives) GetFieldH() Primitives_SomeEnum {
if m != nil {
return m.FieldH
}
return Primitives_UNKNOWN
}
func init() {
proto.RegisterEnum("test.Primitives_SomeEnum", Primitives_SomeEnum_name, Primitives_SomeEnum_value)
proto.RegisterType((*Primitives)(nil), "test.Primitives")
}
func init() { proto.RegisterFile("util/proto/test/test.proto", fileDescriptor_998ad0e1a3de8558) }
var fileDescriptor_998ad0e1a3de8558 = []byte{
// 178 bytes of a gzipped FileDescriptorProto
// 254 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2a, 0x2d, 0xc9, 0xcc,
0xd1, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x2f, 0x49, 0x2d, 0x2e, 0x01, 0x13, 0x7a, 0x60, 0xbe,
0x10, 0x0b, 0x88, 0xad, 0x74, 0x80, 0x91, 0x8b, 0x2b, 0xa0, 0x28, 0x33, 0x37, 0xb3, 0x24, 0xb3,
0x10, 0x0b, 0x88, 0xad, 0xb4, 0x99, 0x89, 0x8b, 0x2b, 0xa0, 0x28, 0x33, 0x37, 0xb3, 0x24, 0xb3,
0x2c, 0xb5, 0x58, 0x48, 0x9c, 0x8b, 0x3d, 0x2d, 0x33, 0x35, 0x27, 0x25, 0x3e, 0x51, 0x82, 0x51,
0x81, 0x51, 0x83, 0x27, 0x88, 0x0d, 0xcc, 0x75, 0x44, 0x48, 0x24, 0x49, 0x30, 0x29, 0x30, 0x6a,
0x70, 0x42, 0x25, 0x9c, 0x84, 0x24, 0x60, 0x12, 0xc9, 0x12, 0x27, 0x40, 0x5a, 0x38, 0xa0, 0x32,
0xce, 0x08, 0x99, 0x14, 0x89, 0x93, 0x20, 0x19, 0x56, 0xa8, 0x8c, 0x0b, 0x42, 0x26, 0x55, 0xe2,
0x14, 0x48, 0x86, 0x17, 0x2a, 0xe3, 0x8a, 0x90, 0x49, 0x93, 0x38, 0x0d, 0x92, 0x61, 0x86, 0xca,
0xb8, 0x21, 0x64, 0xd2, 0x25, 0xce, 0x80, 0x64, 0x58, 0xa0, 0x32, 0xee, 0x4e, 0x02, 0x27, 0x1e,
0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8c, 0xc7, 0x72, 0x0c, 0x49,
0x6c, 0x60, 0x1f, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xee, 0x55, 0x82, 0xff, 0x00,
0x00, 0x00,
0xb8, 0x21, 0x64, 0xd2, 0x25, 0xce, 0x80, 0x64, 0x58, 0xa0, 0x32, 0xee, 0x42, 0xc6, 0x30, 0x99,
0x0c, 0x89, 0x35, 0x20, 0xb7, 0xf1, 0x19, 0x49, 0xea, 0x81, 0xfd, 0x89, 0xf0, 0x97, 0x5e, 0x70,
0x7e, 0x6e, 0xaa, 0x6b, 0x5e, 0x69, 0x2e, 0x54, 0x93, 0x87, 0x92, 0x0d, 0x17, 0x07, 0x4c, 0x4c,
0x88, 0x9b, 0x8b, 0x3d, 0xd4, 0xcf, 0xdb, 0xcf, 0x3f, 0xdc, 0x4f, 0x80, 0x41, 0x88, 0x87, 0x8b,
0x23, 0xc0, 0x3f, 0xd8, 0x33, 0xc4, 0x33, 0xcc, 0x55, 0x80, 0x51, 0x48, 0x94, 0x8b, 0xc3, 0xcf,
0xd5, 0xdd, 0x11, 0xcc, 0xfb, 0x0f, 0x03, 0x8c, 0x4e, 0x02, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78,
0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8c, 0xc7, 0x72, 0x0c, 0x49, 0x6c, 0xe0, 0x40, 0x35,
0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x10, 0xfa, 0xa0, 0xf4, 0x72, 0x01, 0x00, 0x00,
}
func (m *Primitives) Marshal() (dAtA []byte, err error) {
@ -163,6 +204,13 @@ func (m *Primitives) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.FieldH != 0 {
i = encodeVarintTest(dAtA, i, uint64(m.FieldH))
i--
dAtA[i] = 0x12
i--
dAtA[i] = 0xe0
}
if m.FieldG != 0 {
i = encodeVarintTest(dAtA, i, uint64(m.FieldG))
i--
@ -260,6 +308,9 @@ func (m *Primitives) Size() (n int) {
if m.FieldG != 0 {
n += 2 + sovTest(uint64(m.FieldG))
}
if m.FieldH != 0 {
n += 2 + sovTest(uint64(m.FieldH))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@ -463,6 +514,25 @@ func (m *Primitives) Unmarshal(dAtA []byte) error {
break
}
}
case 300:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field FieldH", wireType)
}
m.FieldH = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTest
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.FieldH |= Primitives_SomeEnum(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTest(dAtA[iNdEx:])

View file

@ -10,4 +10,11 @@ message Primitives {
uint32 field_e = 202;
int64 field_f = 203;
uint64 field_g = 204;
enum SomeEnum {
UNKNOWN = 0;
POSITIVE = 1;
NEGATIVE = -1;
}
SomeEnum field_h = 300;
}