Compare commits

..

15 commits

Author SHA1 Message Date
17bed735a1 [#20] Update api version
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-17 11:10:12 +03:00
022f818735 [#20] Remove storage groups
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-17 11:10:08 +03:00
d989c8d2a3 [#54] *: Fix linter warnings
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-11 15:21:27 +03:00
0671f42ee1 [#54] .forgejo: Add DCO action
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-11 15:21:27 +03:00
9a7b47d769 [#50] util: Use protowire for util/proto helpers
* Use methods to calculate size

Signed-off-by: Airat Arifullin a.arifullin@yadro.com
2023-08-10 16:40:53 +00:00
67b18d3550 [#53] Bump min go version to go1.20
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-09 09:55:51 +03:00
964c3edb3f [#51] *: Do not panic in StableSize()
After #49 it can be called on nil structures.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-02 10:55:10 +03:00
3072090c77 [#51] protogen: Do not panic in StableSize()
Refs TrueCloudLab/frostfs-node#554 .

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-08-02 10:47:14 +03:00
7a5ee927c8 [#49] util/proto: Do not allocate in StringSize()
It was not catched by the test because most of the time the function is
inlined. However, I've seen it allocating with pprof in one of the
earlier builds.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-07-26 18:52:59 +03:00
7133a01ccf [#49] message/test: Add test for zero-alloc StableSize()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-07-26 18:32:17 +03:00
43ad0f114c [#49] session: Make StableSize() zero-alloc
For this to work, it is necessary that `NestedStructureSize` is a generic function.
Otherwise, we would allocate to put it in the interface.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-07-26 18:31:31 +03:00
6e92d7d5de [#49] util/proto: Make NestedStructure* generic
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-07-26 18:31:23 +03:00
849de02bc3 [#49] util/proto: Calculate repeated field size without allocations
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-07-26 18:31:23 +03:00
59c8421597 [#49] util/proto: Use StableSize() to determine if the struct is empty
`reflect` is not necessary here, and checking `StableSize` is what we
_want_ anyway.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-07-26 18:31:00 +03:00
582d94c81c [#47] types: Fix unique flag conversion
Signed-off-by: Airat Arifullin a.arifullin@yadro.com
2023-07-19 13:03:35 +03:00
47 changed files with 163 additions and 443 deletions

View file

@ -0,0 +1,21 @@
name: DCO action
on: [pull_request]
jobs:
dco:
name: DCO
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
- name: Run commit format checker
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v2
with:
from: 'origin/${{ github.event.pull_request.base.ref }}'

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
acl/grpc/types.pb.go generated

Binary file not shown.

BIN
audit/grpc/types.pb.go generated

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
go.mod
View file

@ -1,6 +1,6 @@
module git.frostfs.info/TrueCloudLab/frostfs-api-go/v2
go 1.19
go 1.20
require (
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0

View file

@ -1,15 +0,0 @@
package random
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
// Uint32 returns random uint32 value [0, max).
func Uint32(max uint32) uint32 {
return rand.Uint32() % max
}

BIN
lock/grpc/types.pb.go generated

Binary file not shown.

View file

@ -198,6 +198,7 @@ func (p *PlacementPolicy) ToGRPCMessage() grpc.Message {
m.SetSelectors(SelectorsToGRPC(p.selectors))
m.SetReplicas(ReplicasToGRPC(p.replicas))
m.SetContainerBackupFactor(p.backupFactor)
m.SetUnique(p.unique)
}
return m
@ -228,6 +229,8 @@ func (p *PlacementPolicy) FromGRPCMessage(m grpc.Message) error {
p.backupFactor = v.GetContainerBackupFactor()
p.unique = v.GetUnique()
return nil
}

Binary file not shown.

Binary file not shown.

View file

@ -20,6 +20,11 @@ func (m *PlacementPolicy) SetFilters(v []*Filter) {
m.Filters = v
}
// SetUnique of placement policy.
func (m *PlacementPolicy) SetUnique(unique bool) {
m.Unique = unique
}
// SetName of placement filter.
func (m *Filter) SetName(v string) {
m.Name = v

BIN
netmap/grpc/types.pb.go generated

Binary file not shown.

View file

@ -65,6 +65,10 @@ func (f *Filter) StableMarshal(buf []byte) []byte {
}
func (f *Filter) StableSize() (size int) {
if f == nil {
return 0
}
size += protoutil.StringSize(nameFilterField, f.name)
size += protoutil.StringSize(keyFilterField, f.key)
size += protoutil.EnumSize(opFilterField, int32(f.op))
@ -101,6 +105,10 @@ func (s *Selector) StableMarshal(buf []byte) []byte {
}
func (s *Selector) StableSize() (size int) {
if s == nil {
return 0
}
size += protoutil.StringSize(nameSelectorField, s.name)
size += protoutil.UInt32Size(countSelectorField, s.count)
size += protoutil.EnumSize(countSelectorField, int32(s.clause))
@ -132,6 +140,10 @@ func (r *Replica) StableMarshal(buf []byte) []byte {
}
func (r *Replica) StableSize() (size int) {
if r == nil {
return 0
}
size += protoutil.UInt32Size(countReplicaField, r.count)
size += protoutil.StringSize(selectorReplicaField, r.selector)
@ -173,6 +185,10 @@ func (p *PlacementPolicy) StableMarshal(buf []byte) []byte {
}
func (p *PlacementPolicy) StableSize() (size int) {
if p == nil {
return 0
}
for i := range p.replicas {
size += protoutil.NestedStructureSize(replicasPolicyField, &p.replicas[i])
}

View file

@ -102,6 +102,7 @@ func GeneratePlacementPolicy(empty bool) *netmap.PlacementPolicy {
m.SetFilters(GenerateFilters(false))
m.SetSelectors(GenerateSelectors(false))
m.SetReplicas(GenerateReplicas(false))
m.SetUnique(true)
}
return m

Binary file not shown.

Binary file not shown.

BIN
object/grpc/types.pb.go generated

Binary file not shown.

View file

@ -1,7 +1,9 @@
package objecttest
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/internal/random"
"math/rand"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refstest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/test"
@ -186,7 +188,7 @@ func GenerateGetResponseBody(empty bool) *object.GetResponseBody {
m := new(object.GetResponseBody)
if !empty {
switch random.Uint32(3) {
switch randomInt(3) {
case 0:
m.SetObjectPart(GenerateGetObjectPartInit(false))
case 1:
@ -240,7 +242,7 @@ func GeneratePutRequestBody(empty bool) *object.PutRequestBody {
m := new(object.PutRequestBody)
if !empty {
switch random.Uint32(2) {
switch randomInt(2) {
case 0:
m.SetObjectPart(GeneratePutObjectPartInit(false))
case 1:
@ -362,7 +364,7 @@ func GenerateHeadResponseBody(empty bool) *object.HeadResponseBody {
m := new(object.HeadResponseBody)
if !empty {
switch random.Uint32(3) {
switch randomInt(3) {
case 0:
m.SetHeaderPart(GenerateHeaderWithSignature(false))
case 1:
@ -524,7 +526,7 @@ func GenerateGetRangeResponseBody(empty bool) *object.GetRangeResponseBody {
m := new(object.GetRangeResponseBody)
if !empty {
switch random.Uint32(2) {
switch randomInt(2) {
case 0:
m.SetRangePart(GenerateGetRangePartChunk(false))
case 1:
@ -642,3 +644,7 @@ func GeneratePutSingleResponse(empty bool) *object.PutSingleResponse {
m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty))
return m
}
func randomInt(n int) int {
return rand.New(rand.NewSource(time.Now().UnixNano())).Intn(n)
}

View file

@ -324,7 +324,7 @@ type PutSingleResponse struct {
const (
TypeRegular Type = iota
TypeTombstone
TypeStorageGroup
_
TypeLock
)

BIN
refs/grpc/types.pb.go generated

Binary file not shown.

View file

@ -6,6 +6,7 @@ import (
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto"
"google.golang.org/protobuf/encoding/protowire"
)
const (
@ -116,7 +117,7 @@ func (o *ObjectID) StableSize() int {
// ObjectIDNestedListMarshal writes protobuf repeated ObjectID field
// with fNum number to buf.
func ObjectIDNestedListMarshal(fNum int64, buf []byte, ids []ObjectID) (off int) {
prefix, _ := proto.NestedStructurePrefix(fNum)
prefix := protowire.EncodeTag(protowire.Number(fNum), protowire.BytesType)
for i := range ids {
off += binary.PutUvarint(buf[off:], prefix)

View file

@ -17,6 +17,7 @@ type jsonMessage interface {
type binaryMessage interface {
StableMarshal([]byte) []byte
StableSize() int
Unmarshal([]byte) error
}
@ -53,6 +54,11 @@ func TestRPCMessage(t *testing.T, msgGens ...func(empty bool) message.Message) {
}
if bm, ok := msg.(binaryMessage); ok {
t.Run(fmt.Sprintf("%T.StableSize() does no allocations", bm), func(t *testing.T) {
require.Zero(t, testing.AllocsPerRun(1000, func() {
_ = bm.StableSize()
}))
})
t.Run(fmt.Sprintf("Binary_%T", msg), func(t *testing.T) {
data := bm.StableMarshal(nil)

Binary file not shown.

Binary file not shown.

BIN
session/grpc/types.pb.go generated

Binary file not shown.

View file

@ -211,7 +211,7 @@ func (c *ObjectSessionContext) StableMarshal(buf []byte) []byte {
}
offset := proto.EnumMarshal(objectCtxVerbField, buf, int32(c.verb))
proto.NestedStructureMarshal(objectCtxTargetField, buf[offset:], &objectSessionContextTarget{
proto.NestedStructureMarshal(objectCtxTargetField, buf[offset:], objectSessionContextTarget{
cnr: c.cnr,
objs: c.objs,
})
@ -225,7 +225,7 @@ func (c *ObjectSessionContext) StableSize() (size int) {
}
size += proto.EnumSize(objectCtxVerbField, int32(c.verb))
size += proto.NestedStructureSize(objectCtxTargetField, &objectSessionContextTarget{
size += proto.NestedStructureSize(objectCtxTargetField, objectSessionContextTarget{
cnr: c.cnr,
objs: c.objs,
})

View file

@ -1,8 +1,10 @@
package sessiontest
import (
"math/rand"
"time"
acltest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/test"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/internal/random"
refstest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/test"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
statustest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/test"
@ -167,7 +169,7 @@ func GenerateSessionTokenBody(empty bool) *session.TokenBody {
m.SetOwnerID(refstest.GenerateOwnerID(false))
m.SetLifetime(GenerateTokenLifetime(false))
switch random.Uint32(2) {
switch randomInt(2) {
case 0:
m.SetContext(GenerateObjectSessionContext(false))
case 1:
@ -236,3 +238,7 @@ func GenerateXHeaders(empty bool) []session.XHeader {
return xs
}
func randomInt(n int) int {
return rand.New(rand.NewSource(time.Now().UnixNano())).Intn(n)
}

View file

@ -50,10 +50,6 @@ func signServiceRequest(key *ecdsa.PrivateKey, v serviceRequest) error {
if err := signMessageParts(key, body, meta, header, header != nil, result); err != nil {
return err
}
if err := verifyServiceMessagePart(body, result.GetBodySignature); err != nil {
return fmt.Errorf("DEBUG POINT: could not verify body: %w", err)
}
result.SetOrigin(header)
v.SetVerificationHeader(result)
return nil

BIN
status/grpc/types.pb.go generated

Binary file not shown.

View file

@ -30,6 +30,10 @@ func (x *Detail) StableMarshal(buf []byte) []byte {
}
func (x *Detail) StableSize() (size int) {
if x == nil {
return 0
}
size += protoutil.UInt32Size(detailIDFNum, x.id)
size += protoutil.BytesSize(detailValueFNum, x.val)
@ -69,6 +73,10 @@ func (x *Status) StableMarshal(buf []byte) []byte {
}
func (x *Status) StableSize() (size int) {
if x == nil {
return 0
}
size += protoutil.UInt32Size(statusCodeFNum, CodeToGRPC(x.code))
size += protoutil.StringSize(statusMsgFNum, x.msg)

View file

@ -1,59 +0,0 @@
package storagegroup
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message"
sg "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/storagegroup/grpc"
)
func (s *StorageGroup) ToGRPCMessage() grpc.Message {
m := new(sg.StorageGroup)
if s != nil {
m = new(sg.StorageGroup)
m.SetMembers(refs.ObjectIDListToGRPCMessage(s.members))
//nolint:staticcheck
m.SetExpirationEpoch(s.exp)
m.SetValidationDataSize(s.size)
m.SetValidationHash(s.hash.ToGRPCMessage().(*refsGRPC.Checksum))
}
return m
}
func (s *StorageGroup) FromGRPCMessage(m grpc.Message) error {
v, ok := m.(*sg.StorageGroup)
if !ok {
return message.NewUnexpectedMessageType(m, v)
}
var err error
hash := v.GetValidationHash()
if hash == nil {
s.hash = nil
} else {
if s.hash == nil {
s.hash = new(refs.Checksum)
}
err = s.hash.FromGRPCMessage(hash)
if err != nil {
return err
}
}
s.members, err = refs.ObjectIDListFromGRPCMessage(v.GetMembers())
if err != nil {
return err
}
//nolint:staticcheck
s.exp = v.GetExpirationEpoch()
s.size = v.GetValidationDataSize()
return nil
}

View file

@ -1,27 +0,0 @@
package storagegroup
import (
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
)
// SetValidationDataSize sets the total size of the payloads of the storage group.
func (m *StorageGroup) SetValidationDataSize(v uint64) {
m.ValidationDataSize = v
}
// SetValidationHash sets total homomorphic hash of the storage group payloads.
func (m *StorageGroup) SetValidationHash(v *refs.Checksum) {
m.ValidationHash = v
}
// SetExpirationEpoch sets number of the last epoch of the storage group lifetime.
//
// Deprecated: do not use, `expiration_epoch` field is deprecated in protocol.
func (m *StorageGroup) SetExpirationEpoch(v uint64) {
m.ExpirationEpoch = v
}
// SetMembers sets list of the identifiers of the storage group members.
func (m *StorageGroup) SetMembers(v []*refs.ObjectID) {
m.Members = v
}

Binary file not shown.

View file

@ -1,14 +0,0 @@
package storagegroup
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message"
storagegroup "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/storagegroup/grpc"
)
func (s *StorageGroup) MarshalJSON() ([]byte, error) {
return message.MarshalJSON(s)
}
func (s *StorageGroup) UnmarshalJSON(data []byte) error {
return message.UnmarshalJSON(s, data, new(storagegroup.StorageGroup))
}

View file

@ -1,54 +0,0 @@
package storagegroup
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message"
storagegroup "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/storagegroup/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto"
)
const (
sizeField = 1
hashField = 2
expirationField = 3
objectIDsField = 4
)
// StableMarshal marshals unified storage group structure in a protobuf
// compatible way without field order shuffle.
func (s *StorageGroup) StableMarshal(buf []byte) []byte {
if s == nil {
return []byte{}
}
if buf == nil {
buf = make([]byte, s.StableSize())
}
var offset int
offset += proto.UInt64Marshal(sizeField, buf[offset:], s.size)
offset += proto.NestedStructureMarshal(hashField, buf[offset:], s.hash)
offset += proto.UInt64Marshal(expirationField, buf[offset:], s.exp)
refs.ObjectIDNestedListMarshal(objectIDsField, buf[offset:], s.members)
return buf
}
// StableSize of storage group structure marshalled by StableMarshal function.
func (s *StorageGroup) StableSize() (size int) {
if s == nil {
return 0
}
size += proto.UInt64Size(sizeField, s.size)
size += proto.NestedStructureSize(hashField, s.hash)
size += proto.UInt64Size(expirationField, s.exp)
size += refs.ObjectIDNestedListSize(objectIDsField, s.members)
return size
}
func (s *StorageGroup) Unmarshal(data []byte) error {
return message.Unmarshal(s, data, new(storagegroup.StorageGroup))
}

View file

@ -1,15 +0,0 @@
package storagegroup_test
import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message"
messagetest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/message/test"
storagegrouptest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/storagegroup/test"
)
func TestMessageConvert(t *testing.T) {
messagetest.TestRPCMessage(t,
func(empty bool) message.Message { return storagegrouptest.GenerateStorageGroup(empty) },
)
}

View file

@ -1,21 +0,0 @@
package storagegrouptest
import (
refstest "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/test"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/storagegroup"
)
func GenerateStorageGroup(empty bool) *storagegroup.StorageGroup {
m := new(storagegroup.StorageGroup)
if !empty {
m.SetValidationDataSize(44)
//nolint:staticcheck
m.SetExpirationEpoch(55)
m.SetMembers(refstest.GenerateObjectIDs(false))
}
m.SetValidationHash(refstest.GenerateChecksum(empty))
return m
}

View file

@ -1,79 +0,0 @@
package storagegroup
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
)
// StorageGroup is a unified structure of StorageGroup
// message from proto definition.
type StorageGroup struct {
size uint64
hash *refs.Checksum
exp uint64
members []refs.ObjectID
}
// GetValidationDataSize of unified storage group structure.
func (s *StorageGroup) GetValidationDataSize() uint64 {
if s != nil {
return s.size
}
return 0
}
// SetValidationDataSize into unified storage group structure.
func (s *StorageGroup) SetValidationDataSize(v uint64) {
s.size = v
}
// GetValidationHash of unified storage group structure.
func (s *StorageGroup) GetValidationHash() *refs.Checksum {
if s != nil {
return s.hash
}
return nil
}
// SetValidationHash into unified storage group structure.
func (s *StorageGroup) SetValidationHash(v *refs.Checksum) {
s.hash = v
}
// GetExpirationEpoch of unified storage group structure.
//
// Deprecated: Do not use.
func (s *StorageGroup) GetExpirationEpoch() uint64 {
if s != nil {
return s.exp
}
return 0
}
// SetExpirationEpoch into unified storage group structure.
//
// Deprecated: Do not use.
func (s *StorageGroup) SetExpirationEpoch(v uint64) {
s.exp = v
}
// GetMembers of unified storage group structure. Members are objects of
// storage group.
func (s *StorageGroup) GetMembers() []refs.ObjectID {
if s != nil {
return s.members
}
return nil
}
// SetMembers into unified storage group structure. Members are objects of
// storage group.
func (s *StorageGroup) SetMembers(v []refs.ObjectID) {
s.members = v
}

Binary file not shown.

View file

@ -10,7 +10,8 @@ import (
"encoding/binary"
"math"
"math/bits"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
)
type (
@ -21,14 +22,22 @@ type (
)
func BytesMarshal(field int, buf, v []byte) int {
if len(v) == 0 {
return 0
}
return bytesMarshal(field, buf, v)
}
func bytesMarshal(field int, buf, v []byte) int {
prefix := field<<3 | 0x2
func BytesSize(field int, v []byte) int {
return bytesSize(field, v)
}
func bytesMarshal[T ~[]byte | ~string](field int, buf []byte, v T) int {
if len(v) == 0 {
return 0
}
return bytesMarshalNoCheck(field, buf, v)
}
func bytesMarshalNoCheck[T ~[]byte | ~string](field int, buf []byte, v T) int {
prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType)
// buf length check can prevent panic at PutUvarint, but it will make
// marshaller a bit slower.
@ -39,26 +48,23 @@ func bytesMarshal(field int, buf, v []byte) int {
return i
}
func BytesSize(field int, v []byte) int {
ln := len(v)
if ln == 0 {
func bytesSize[T ~[]byte | ~string](field int, v T) int {
if len(v) == 0 {
return 0
}
return bytesSize(field, v)
return bytesSizeNoCheck(field, v)
}
func bytesSize(field int, v []byte) int {
prefix := field<<3 | 0x2
return VarUIntSize(uint64(prefix)) + VarUIntSize(uint64(len(v))) + len(v)
func bytesSizeNoCheck[T ~[]byte | ~string](field int, v T) int {
return protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(len(v)))
}
func StringMarshal(field int, buf []byte, v string) int {
return BytesMarshal(field, buf, []byte(v))
return bytesMarshal(field, buf, v)
}
func StringSize(field int, v string) int {
return BytesSize(field, []byte(v))
return bytesSize(field, v)
}
func BoolMarshal(field int, buf []byte, v bool) int {
@ -66,12 +72,13 @@ func BoolMarshal(field int, buf []byte, v bool) int {
return 0
}
prefix := field << 3
prefix := protowire.EncodeTag(protowire.Number(field), protowire.VarintType)
// buf length check can prevent panic at PutUvarint, but it will make
// marshaller a bit slower.
i := binary.PutUvarint(buf, uint64(prefix))
buf[i] = 0x1
const boolTrueValue = 0x1
buf[i] = boolTrueValue
return i + 1
}
@ -80,10 +87,8 @@ func BoolSize(field int, v bool) int {
if !v {
return 0
}
prefix := field << 3
return VarUIntSize(uint64(prefix)) + 1 // bool is always 1 byte long
const boolLength = 1
return protowire.SizeGroup(protowire.Number(field), boolLength)
}
func UInt64Marshal(field int, buf []byte, v uint64) int {
@ -91,7 +96,7 @@ func UInt64Marshal(field int, buf []byte, v uint64) int {
return 0
}
prefix := field << 3
prefix := protowire.EncodeTag(protowire.Number(field), protowire.VarintType)
// buf length check can prevent panic at PutUvarint, but it will make
// marshaller a bit slower.
@ -105,10 +110,7 @@ func UInt64Size(field int, v uint64) int {
if v == 0 {
return 0
}
prefix := field << 3
return VarUIntSize(uint64(prefix)) + VarUIntSize(v)
return protowire.SizeGroup(protowire.Number(field), protowire.SizeVarint(v))
}
func Int64Marshal(field int, buf []byte, v int64) int {
@ -147,7 +149,7 @@ func RepeatedBytesMarshal(field int, buf []byte, v [][]byte) int {
var offset int
for i := range v {
offset += bytesMarshal(field, buf[offset:], v[i])
offset += bytesMarshalNoCheck(field, buf[offset:], v[i])
}
return offset
@ -155,7 +157,7 @@ func RepeatedBytesMarshal(field int, buf []byte, v [][]byte) int {
func RepeatedBytesSize(field int, v [][]byte) (size int) {
for i := range v {
size += bytesSize(field, v[i])
size += bytesSizeNoCheck(field, v[i])
}
return size
@ -165,7 +167,7 @@ func RepeatedStringMarshal(field int, buf []byte, v []string) int {
var offset int
for i := range v {
offset += bytesMarshal(field, buf[offset:], []byte(v[i]))
offset += bytesMarshalNoCheck(field, buf[offset:], v[i])
}
return offset
@ -173,123 +175,73 @@ func RepeatedStringMarshal(field int, buf []byte, v []string) int {
func RepeatedStringSize(field int, v []string) (size int) {
for i := range v {
size += bytesSize(field, []byte(v[i]))
size += bytesSizeNoCheck(field, v[i])
}
return size
}
func RepeatedUInt64Marshal(field int, buf []byte, v []uint64) int {
func repeatedUIntSize[T ~uint64 | ~int64 | ~uint32 | ~int32](field int, v []T) (size, arraySize int) {
if len(v) == 0 {
return 0, 0
}
for i := range v {
arraySize += protowire.SizeVarint(uint64(v[i]))
}
size = protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(arraySize))
return
}
func repeatedUIntMarshal[T ~uint64 | ~int64 | ~uint32 | ~int32](field int, buf []byte, v []T) int {
if len(v) == 0 {
return 0
}
prefix := field<<3 | 0x02
prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType)
offset := binary.PutUvarint(buf, uint64(prefix))
_, arrSize := RepeatedUInt64Size(field, v)
_, arrSize := repeatedUIntSize(field, v)
offset += binary.PutUvarint(buf[offset:], uint64(arrSize))
for i := range v {
offset += binary.PutUvarint(buf[offset:], v[i])
offset += binary.PutUvarint(buf[offset:], uint64(v[i]))
}
return offset
}
func RepeatedUInt64Marshal(field int, buf []byte, v []uint64) int {
return repeatedUIntMarshal(field, buf, v)
}
func RepeatedUInt64Size(field int, v []uint64) (size, arraySize int) {
if len(v) == 0 {
return 0, 0
}
for i := range v {
size += VarUIntSize(v[i])
}
arraySize = size
size += VarUIntSize(uint64(size))
prefix := field<<3 | 0x2
size += VarUIntSize(uint64(prefix))
return size, arraySize
return repeatedUIntSize(field, v)
}
func RepeatedInt64Marshal(field int, buf []byte, v []int64) int {
if len(v) == 0 {
return 0
}
convert := make([]uint64, len(v))
for i := range v {
convert[i] = uint64(v[i])
}
return RepeatedUInt64Marshal(field, buf, convert)
return repeatedUIntMarshal(field, buf, v)
}
func RepeatedInt64Size(field int, v []int64) (size, arraySize int) {
if len(v) == 0 {
return 0, 0
}
convert := make([]uint64, len(v))
for i := range v {
convert[i] = uint64(v[i])
}
return RepeatedUInt64Size(field, convert)
return repeatedUIntSize(field, v)
}
func RepeatedUInt32Marshal(field int, buf []byte, v []uint32) int {
if len(v) == 0 {
return 0
}
convert := make([]uint64, len(v))
for i := range v {
convert[i] = uint64(v[i])
}
return RepeatedUInt64Marshal(field, buf, convert)
return repeatedUIntMarshal(field, buf, v)
}
func RepeatedUInt32Size(field int, v []uint32) (size, arraySize int) {
if len(v) == 0 {
return 0, 0
}
convert := make([]uint64, len(v))
for i := range v {
convert[i] = uint64(v[i])
}
return RepeatedUInt64Size(field, convert)
return repeatedUIntSize(field, v)
}
func RepeatedInt32Marshal(field int, buf []byte, v []int32) int {
if len(v) == 0 {
return 0
}
convert := make([]uint64, len(v))
for i := range v {
convert[i] = uint64(v[i])
}
return RepeatedUInt64Marshal(field, buf, convert)
return repeatedUIntMarshal(field, buf, v)
}
func RepeatedInt32Size(field int, v []int32) (size, arraySize int) {
if len(v) == 0 {
return 0, 0
}
convert := make([]uint64, len(v))
for i := range v {
convert[i] = uint64(v[i])
}
return RepeatedUInt64Size(field, convert)
return repeatedUIntSize(field, v)
}
// VarUIntSize returns length of varint byte sequence for uint64 value 'x'.
@ -297,36 +249,27 @@ func VarUIntSize(x uint64) int {
return (bits.Len64(x|1) + 6) / 7
}
func NestedStructurePrefix(field int64) (prefix uint64, ln int) {
prefix = uint64(field<<3 | 0x02)
return prefix, VarUIntSize(prefix)
}
func NestedStructureMarshal(field int64, buf []byte, v stableMarshaller) int {
if v == nil || reflect.ValueOf(v).IsNil() {
func NestedStructureMarshal[T stableMarshaller](field int64, buf []byte, v T) int {
n := v.StableSize()
if n == 0 {
return 0
}
prefix, _ := NestedStructurePrefix(field)
prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType)
offset := binary.PutUvarint(buf, prefix)
n := v.StableSize()
offset += binary.PutUvarint(buf[offset:], uint64(n))
v.StableMarshal(buf[offset:])
return offset + n
}
func NestedStructureSize(field int64, v stableMarshaller) (size int) {
if v == nil || reflect.ValueOf(v).IsNil() {
func NestedStructureSize[T stableMarshaller](field int64, v T) (size int) {
n := v.StableSize()
if n == 0 {
return 0
}
_, ln := NestedStructurePrefix(field)
n := v.StableSize()
size = ln + VarUIntSize(uint64(n)) + n
return size
size = protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(n))
return
}
func Fixed64Marshal(field int, buf []byte, v uint64) int {
@ -334,7 +277,7 @@ func Fixed64Marshal(field int, buf []byte, v uint64) int {
return 0
}
prefix := field<<3 | 1
prefix := protowire.EncodeTag(protowire.Number(field), protowire.Fixed64Type)
// buf length check can prevent panic at PutUvarint, but it will make
// marshaller a bit slower.
@ -348,10 +291,7 @@ func Fixed64Size(fNum int, v uint64) int {
if v == 0 {
return 0
}
prefix := fNum<<3 | 1
return VarUIntSize(uint64(prefix)) + 8
return protowire.SizeGroup(protowire.Number(fNum), protowire.SizeFixed64())
}
func Float64Marshal(field int, buf []byte, v float64) int {
@ -359,7 +299,7 @@ func Float64Marshal(field int, buf []byte, v float64) int {
return 0
}
prefix := field<<3 | 1
prefix := protowire.EncodeTag(protowire.Number(field), protowire.Fixed64Type)
i := binary.PutUvarint(buf, uint64(prefix))
binary.LittleEndian.PutUint64(buf[i:], math.Float64bits(v))
@ -371,10 +311,7 @@ func Float64Size(fNum int, v float64) int {
if v == 0 {
return 0
}
prefix := fNum<<3 | 1
return VarUIntSize(uint64(prefix)) + 8
return protowire.SizeGroup(protowire.Number(fNum), protowire.SizeFixed64())
}
// Fixed32Marshal encodes uint32 value to Protocol Buffers fixed32 field with specified number,
@ -386,7 +323,7 @@ func Fixed32Marshal(field int, buf []byte, v uint32) int {
return 0
}
prefix := field<<3 | 5
prefix := protowire.EncodeTag(protowire.Number(field), protowire.Fixed32Type)
// buf length check can prevent panic at PutUvarint, but it will make
// marshaller a bit slower.
@ -402,8 +339,5 @@ func Fixed32Size(fNum int, v uint32) int {
if v == 0 {
return 0
}
prefix := fNum<<3 | 5
return VarUIntSize(uint64(prefix)) + 4
return protowire.SizeGroup(protowire.Number(fNum), protowire.SizeFixed32())
}

Binary file not shown.

View file

@ -59,6 +59,7 @@ func emitMessage(g *protogen.GeneratedFile, msg *protogen.Message) {
g.P("//")
g.P("// Structures with the same field values have the same binary size.")
g.P("func (x *", msg.GoIdent.GoName, ") StableSize() (size int) {")
g.P("if x == nil { return 0 }")
if len(fs) != 0 {
for _, f := range fs {
if f.Desc.IsList() && marshalers[f.Desc.Kind()].RepeatedDouble {