diff --git a/util/proto/marshal.go b/util/proto/marshal.go index 250db0f..66824b3 100644 --- a/util/proto/marshal.go +++ b/util/proto/marshal.go @@ -335,3 +335,28 @@ func NestedStructureSize(field int64, v stableMarshaller) (size int) { return size } + +func Fixed64Marshal(field int, buf []byte, v uint64) (int, error) { + if v == 0 { + return 0, nil + } + + prefix := field<<3 | 1 + + // buf length check can prevent panic at PutUvarint, but it will make + // marshaller a bit slower. + i := binary.PutUvarint(buf, uint64(prefix)) + binary.LittleEndian.PutUint64(buf[i:], v) + + return i + 8, nil +} + +func Fixed64Size(fNum int, v uint64) int { + if v == 0 { + return 0 + } + + prefix := fNum<<3 | 1 + + return VarUIntSize(uint64(prefix)) + 8 +} diff --git a/util/proto/marshal_test.go b/util/proto/marshal_test.go index 56e0a23..6844309 100644 --- a/util/proto/marshal_test.go +++ b/util/proto/marshal_test.go @@ -22,6 +22,7 @@ type stablePrimitives struct { FieldF int64 FieldG uint64 FieldH SomeEnum + FieldI uint64 // fixed64 } type stableRepPrimitives struct { @@ -122,6 +123,16 @@ func (s *stablePrimitives) stableMarshal(buf []byte, wrongField bool) ([]byte, e } i += offset + fieldNum = 205 + if wrongField { + fieldNum++ + } + offset, err = proto.Fixed64Marshal(fieldNum, buf, s.FieldI) + if err != nil { + return nil, errors.Wrap(err, "can't marshal field I") + } + i += offset + fieldNum = 300 if wrongField { fieldNum++ @@ -143,6 +154,7 @@ func (s *stablePrimitives) stableSize() int { proto.UInt32Size(202, s.FieldE) + proto.Int64Size(203, s.FieldF) + proto.UInt64Size(204, s.FieldG) + + proto.Fixed64Size(205, s.FieldI) + proto.EnumSize(300, int32(s.FieldH)) } @@ -430,6 +442,17 @@ func TestRepeatedUInt64Marshal(t *testing.T) { }) } +func TestFixed64Marshal(t *testing.T) { + t.Run("zero", func(t *testing.T) { + testFixed64Marshal(t, 0, false) + }) + + t.Run("non zero", func(t *testing.T) { + testFixed64Marshal(t, math.MaxUint64, false) + testFixed64Marshal(t, math.MaxUint64, true) + }) +} + func testMarshal(t *testing.T, c stablePrimitives, tr test.Primitives, wrongField bool) *test.Primitives { var ( wire []byte @@ -713,3 +736,18 @@ func testRepeatedUInt64Marshal(t *testing.T, n []uint64, wrongField bool) { require.Len(t, result.FieldF, 0) } } + +func testFixed64Marshal(t *testing.T, n uint64, wrongField bool) { + var ( + custom = stablePrimitives{FieldI: n} + transport = test.Primitives{FieldI: n} + ) + + result := testMarshal(t, custom, transport, wrongField) + + if !wrongField { + require.Equal(t, n, result.FieldI) + } else { + require.EqualValues(t, 0, result.FieldI) + } +} diff --git a/util/proto/test/test.pb.go b/util/proto/test/test.pb.go index 0254baa..a0808f8 100644 Binary files a/util/proto/test/test.pb.go and b/util/proto/test/test.pb.go differ diff --git a/util/proto/test/test.proto b/util/proto/test/test.proto index ea6125f..e9c2758 100644 --- a/util/proto/test/test.proto +++ b/util/proto/test/test.proto @@ -12,6 +12,7 @@ message Primitives { uint32 field_e = 202; int64 field_f = 203; uint64 field_g = 204; + fixed64 field_i = 205; enum SomeEnum { UNKNOWN = 0;