Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

45 changed files with 99 additions and 273 deletions

View file

@ -50,7 +50,7 @@ linters:
- bidichk
- durationcheck
- exhaustive
- copyloopvar
- exportloopref
- gofmt
- goimports
- misspell

View file

@ -37,6 +37,6 @@ repos:
language: system
- repo: https://github.com/golangci/golangci-lint
rev: v1.60.3
rev: v1.56.2
hooks:
- id: golangci-lint

View file

@ -47,4 +47,4 @@ Initial public release.
This project is a fork of [NeoFS](https://github.com/nspcc-dev/neofs-api-go) from version v2.14.0.
To see CHANGELOG for older versions, refer to https://github.com/nspcc-dev/neofs-api-go/blob/master/CHANGELOG.md.
[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-api-go/compare/v2.16.0...master
[Unreleased]: https://github.com/TrueCloudLab/compare/v2.15.0...master

View file

@ -3,8 +3,8 @@
First, thank you for contributing! We love and encourage pull requests from
everyone. Please follow the guidelines:
- Check the open [issues](https://git.frostfs.info/TrueCloudLab/frostfs-api-go/issues) and
[pull requests](https://git.frostfs.info/TrueCloudLab/frostfs-api-go/pulls) for existing
- Check the open [issues](https://github.com/TrueCloudLab/frostfs-api-go/issues) and
[pull requests](https://github.com/TrueCloudLab/frostfs-api-go/pulls) for existing
discussions.
- Open an issue first, to discuss a new feature or enhancement.
@ -26,18 +26,18 @@ send a pull request. We encourage pull requests to discuss code changes. Here
are the steps in details:
### Set up your GitHub Repository
Fork [FrostFS node upstream](https://git.frostfs.info/TrueCloudLab/frostfs-api-go/fork) source
Fork [FrostFS node upstream](https://github.com/TrueCloudLab/frostfs-api-go/fork) source
repository to your own personal repository. Copy the URL of your fork (you will
need it for the `git clone` command below).
```sh
$ git clone https://git.frostfs.info/TrueCloudLab/frostfs-api-go
$ git clone https://github.com/TrueCloudLab/frostfs-api-go
```
### Set up git remote as ``upstream``
```sh
$ cd frostfs-api-go
$ git remote add upstream https://git.frostfs.info/TrueCloudLab/frostfs-api-go
$ git remote add upstream https://github.com/TrueCloudLab/frostfs-api-go
$ git fetch upstream
$ git merge upstream/master
...

View file

@ -6,20 +6,22 @@
</p>
---
![Tests](https://git.frostfs.info/TrueCloudLab/frostfs-api-go/badges/workflows/tests.yml/badge.svg)
[![Report](https://goreportcard.com/badge/git.frostfs.info/TrueCloudLab/frostfs-api-go)](https://goreportcard.com/report/git.frostfs.info/TrueCloudLab/frostfs-api-go)
[![Release](https://git.frostfs.info/TrueCloudLab/frostfs-api-go/badges/release.svg)](https://git.frostfs.info/TrueCloudLab/frostfs-api-go)
![Tests](https://github.com/TrueCloudLab/frostfs-api-go/workflows/frostfs-api-go%20tests/badge.svg)
[![codecov](https://codecov.io/gh/TrueCloudLab/frostfs-api-go/branch/master/graph/badge.svg)](https://codecov.io/gh/TrueCloudLab/frostfs-api-go)
[![Report](https://goreportcard.com/badge/github.com/TrueCloudLab/frostfs-api-go)](https://goreportcard.com/report/github.com/TrueCloudLab/frostfs-api-go)
[![GitHub release](https://img.shields.io/github/release/TrueCloudLab/frostfs-api-go.svg)](https://github.com/TrueCloudLab/frostfs-api-go)
![GitHub license](https://img.shields.io/github/license/TrueCloudLab/frostfs-api-go.svg?style=popout)
# Overview
Go implementation of recent [FrostFS API](https://git.frostfs.info/TrueCloudLab/frostfs-api)
versions. For a more high-level SDK see [FrostFS SDK](https://git.frostfs.info/TrueCloudLab/frostfs-sdk-go).
Go implementation of recent [FrostFS API](https://github.com/TrueCloudLab/frostfs-api)
versions. For a more high-level SDK see [FrostFS SDK](https://github.com/TrueCloudLab/frostfs-sdk-go).
## Frostfs-Api compatibility
|frostfs-api-go version|supported frostfs-api versions|
|:------------------:|:--------------------------:|
|v2.14.x|[v2.14.0](https://git.frostfs.info/TrueCloudLab/frostfs-api/releases/tag/v2.14.0)|
|v2.14.x|[v2.14.0](https://github.com/TrueCloudLab/frostfs-api/releases/tag/v2.14.0)|
## Contributing

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -32,7 +32,7 @@ func BenchmarkTable_ToGRPCMessage(b *testing.B) {
b.Run("to grpc message", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
raw := tb.ToGRPCMessage()
if len(tb.GetRecords()) != len(raw.(*aclGrpc.EACLTable).Records) {
b.FailNow()
@ -41,7 +41,7 @@ func BenchmarkTable_ToGRPCMessage(b *testing.B) {
})
b.Run("from grpc message", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
tb := new(acl.Table)
if tb.FromGRPCMessage(raw) != nil {
b.FailNow()

Binary file not shown.

View file

@ -330,18 +330,10 @@ func (bt *BearerTokenBody) SetEACL(v *Table) {
}
func (t *APEOverride) GetTarget() *ape.ChainTarget {
if t == nil {
return nil
}
return t.target
}
func (t *APEOverride) GetChains() []*ape.Chain {
if t == nil {
return nil
}
return t.chains
}

Binary file not shown.

View file

@ -53,10 +53,6 @@ func (c *Chain) SetKind(kind chainKind) {
}
func (c *Chain) GetKind() chainKind {
if c == nil {
return nil
}
return c.kind
}
@ -71,9 +67,5 @@ func (c *ChainRaw) SetRaw(raw []byte) {
}
func (c *ChainRaw) GetRaw() []byte {
if c == nil {
return nil
}
return c.Raw
}

Binary file not shown.

View file

@ -16,10 +16,6 @@ func (r *AddChainRequest) SetBody(body *AddChainRequestBody) {
}
func (r *AddChainRequest) GetBody() *AddChainRequestBody {
if r == nil {
return nil
}
return r.body
}
@ -34,10 +30,6 @@ func (rb *AddChainRequestBody) SetTarget(target *ape.ChainTarget) {
}
func (rb *AddChainRequestBody) GetTarget() *ape.ChainTarget {
if rb == nil {
return nil
}
return rb.target
}
@ -46,10 +38,6 @@ func (rb *AddChainRequestBody) SetChain(chain *ape.Chain) {
}
func (rb *AddChainRequestBody) GetChain() *ape.Chain {
if rb == nil {
return nil
}
return rb.chain
}
@ -64,10 +52,6 @@ func (r *AddChainResponse) SetBody(body *AddChainResponseBody) {
}
func (r *AddChainResponse) GetBody() *AddChainResponseBody {
if r == nil {
return nil
}
return r.body
}
@ -80,10 +64,6 @@ func (rb *AddChainResponseBody) SetChainID(chainID []byte) {
}
func (rb *AddChainResponseBody) GetChainID() []byte {
if rb == nil {
return nil
}
return rb.chainID
}
@ -98,10 +78,6 @@ func (r *RemoveChainRequest) SetBody(body *RemoveChainRequestBody) {
}
func (r *RemoveChainRequest) GetBody() *RemoveChainRequestBody {
if r == nil {
return nil
}
return r.body
}
@ -116,10 +92,6 @@ func (rb *RemoveChainRequestBody) SetTarget(target *ape.ChainTarget) {
}
func (rb *RemoveChainRequestBody) GetTarget() *ape.ChainTarget {
if rb == nil {
return nil
}
return rb.target
}
@ -128,10 +100,6 @@ func (rb *RemoveChainRequestBody) SetChainID(chainID []byte) {
}
func (rb *RemoveChainRequestBody) GetChainID() []byte {
if rb == nil {
return nil
}
return rb.chainID
}
@ -148,10 +116,6 @@ func (r *RemoveChainResponse) SetBody(body *RemoveChainResponseBody) {
}
func (r *RemoveChainResponse) GetBody() *RemoveChainResponseBody {
if r == nil {
return nil
}
return r.body
}
@ -166,10 +130,6 @@ func (r *ListChainsRequest) SetBody(body *ListChainsRequestBody) {
}
func (r *ListChainsRequest) GetBody() *ListChainsRequestBody {
if r == nil {
return nil
}
return r.body
}
@ -182,10 +142,6 @@ func (rb *ListChainsRequestBody) SetTarget(target *ape.ChainTarget) {
}
func (rb *ListChainsRequestBody) GetTarget() *ape.ChainTarget {
if rb == nil {
return nil
}
return rb.target
}
@ -200,10 +156,6 @@ func (r *ListChainsResponse) SetBody(body *ListChainsResponseBody) {
}
func (r *ListChainsResponse) GetBody() *ListChainsResponseBody {
if r == nil {
return nil
}
return r.body
}
@ -218,9 +170,5 @@ func (r *ListChainsResponseBody) SetChains(chains []*ape.Chain) {
}
func (r *ListChainsResponseBody) GetChains() []*ape.Chain {
if r == nil {
return nil
}
return r.chains
}

Binary file not shown.

Binary file not shown.

14
go.mod
View file

@ -7,9 +7,9 @@ require (
github.com/VictoriaMetrics/easyproto v0.1.4
github.com/mailru/easyjson v0.7.7
github.com/stretchr/testify v1.8.3
golang.org/x/sync v0.7.0
google.golang.org/grpc v1.66.2
google.golang.org/protobuf v1.34.1
golang.org/x/sync v0.6.0
google.golang.org/grpc v1.63.2
google.golang.org/protobuf v1.33.0
)
require (
@ -19,10 +19,10 @@ require (
github.com/kr/pretty v0.1.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

28
go.sum
View file

@ -26,20 +26,20 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

Binary file not shown.

View file

@ -525,7 +525,7 @@ func (x *NetworkConfig) ToGRPCMessage() grpc.Message {
if ln := len(x.ps); ln > 0 {
ps = make([]netmap.NetworkConfig_Parameter, 0, ln)
for i := range ln {
for i := 0; i < ln; i++ {
ps = append(ps, *x.ps[i].ToGRPCMessage().(*netmap.NetworkConfig_Parameter))
}
}
@ -552,7 +552,7 @@ func (x *NetworkConfig) FromGRPCMessage(m grpc.Message) error {
ps = make([]NetworkParameter, ln)
for i := range ln {
for i := 0; i < ln; i++ {
if err := ps[i].FromGRPCMessage(&psV2[i]); err != nil {
return err
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -335,10 +335,6 @@ func (p *PlacementPolicy) SetContainerBackupFactor(backupFactor uint32) {
}
func (p *PlacementPolicy) GetReplicas() []Replica {
if p == nil {
return nil
}
return p.replicas
}

View file

@ -26,7 +26,7 @@ func BenchmarkAttributesMarshal(b *testing.B) {
b.Run("marshal", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
res := AttributesToGRPC(attrs)
if len(res) != len(raw) {
b.FailNow()
@ -35,7 +35,7 @@ func BenchmarkAttributesMarshal(b *testing.B) {
})
b.Run("unmarshal", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
res, err := AttributesFromGRPC(raw)
if err != nil || len(res) != len(raw) {
b.FailNow()

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -24,7 +24,7 @@ func benchmarkObjectIDSlice(b *testing.B, size int) {
b.Run("to grpc message", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
raw := ObjectIDListToGRPCMessage(ids)
if len(raw) != len(ids) {
b.FailNow()
@ -33,7 +33,7 @@ func benchmarkObjectIDSlice(b *testing.B, size int) {
})
b.Run("from grpc message", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
ids, err := ObjectIDListFromGRPCMessage(raw)
if err != nil || len(raw) != len(ids) {
b.FailNow()
@ -42,7 +42,7 @@ func benchmarkObjectIDSlice(b *testing.B, size int) {
})
b.Run("marshal", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
buf := make([]byte, ObjectIDNestedListSize(1, ids))
n := ObjectIDNestedListMarshal(1, buf, ids)
if n != len(buf) {

Binary file not shown.

View file

@ -2,16 +2,13 @@ package client
import (
"context"
"google.golang.org/grpc"
)
// CallOption is a messaging session option within Protobuf RPC.
type CallOption func(*callParameters)
type callParameters struct {
ctx context.Context // nolint:containedctx
dialer func(context.Context, grpc.ClientConnInterface) error
ctx context.Context // nolint:containedctx
}
func defaultCallParameters() *callParameters {
@ -30,11 +27,3 @@ func WithContext(ctx context.Context) CallOption {
prm.ctx = ctx
}
}
// WithDialer returns option to specify grpc dialer. If passed, it will be
// called after the connection is successfully created.
func WithDialer(dialer func(context.Context, grpc.ClientConnInterface) error) CallOption {
return func(prm *callParameters) {
prm.dialer = dialer
}
}

View file

@ -12,7 +12,7 @@ import (
var errInvalidEndpoint = errors.New("invalid endpoint options")
func (c *Client) openGRPCConn(ctx context.Context, dialer func(ctx context.Context, cc grpcstd.ClientConnInterface) error) error {
func (c *Client) openGRPCConn(ctx context.Context) error {
if c.conn != nil {
return nil
}
@ -21,21 +21,15 @@ func (c *Client) openGRPCConn(ctx context.Context, dialer func(ctx context.Conte
return errInvalidEndpoint
}
dialCtx, cancel := context.WithTimeout(ctx, c.dialTimeout)
var err error
c.conn, err = grpcstd.NewClient(c.addr, c.grpcDialOpts...)
c.conn, err = grpcstd.DialContext(dialCtx, c.addr, c.grpcDialOpts...)
cancel()
if err != nil {
return fmt.Errorf("gRPC new client: %w", err)
}
if dialer != nil {
ctx, cancel := context.WithTimeout(ctx, c.dialTimeout)
defer cancel()
if err := dialer(ctx, c.conn); err != nil {
_ = c.conn.Close()
return fmt.Errorf("gRPC dial: %w", err)
}
return fmt.Errorf("gRPC dial: %w", err)
}
return nil

View file

@ -46,7 +46,7 @@ func (c *Client) Init(info common.CallMethodInfo, opts ...CallOption) (MessageRe
opt(prm)
}
if err := c.openGRPCConn(prm.ctx, prm.dialer); err != nil {
if err := c.openGRPCConn(prm.ctx); err != nil {
return nil, err
}

View file

@ -37,6 +37,7 @@ func (c *cfg) initDefault() {
c.dialTimeout = defaultDialTimeout
c.rwTimeout = defaultRWTimeout
c.grpcDialOpts = []grpc.DialOption{
grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
}
}

Binary file not shown.

Binary file not shown.

View file

@ -77,7 +77,7 @@ func BenchmarkSignRequest(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
b.StopTimer()
dec := new(accounting.Decimal)
dec.SetValue(100)
@ -103,7 +103,7 @@ func BenchmarkVerifyRequest(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for range b.N {
for i := 0; i < b.N; i++ {
b.StopTimer()
dec := new(accounting.Decimal)
dec.SetValue(100)

View file

@ -53,7 +53,7 @@ func (x *Status) ToGRPCMessage() grpc.Message {
if ln := len(x.details); ln > 0 {
ds = make([]status.Status_Detail, 0, ln)
for i := range ln {
for i := 0; i < ln; i++ {
ds = append(ds, *x.details[i].ToGRPCMessage().(*status.Status_Detail))
}
}
@ -80,7 +80,7 @@ func (x *Status) FromGRPCMessage(m grpc.Message) error {
ds = make([]Detail, ln)
for i := range ln {
for i := 0; i < ln; i++ {
if err := ds[i].FromGRPCMessage(&dsV2[i]); err != nil {
return err
}

Binary file not shown.

View file

@ -63,8 +63,6 @@ const (
SignatureVerificationFail
// NodeUnderMaintenance is a local Code value for NODE_UNDER_MAINTENANCE status.
NodeUnderMaintenance
// InvalidArgument is a local Code value for INVALID_ARGUMENT status.
InvalidArgument
)
const (

Binary file not shown.

View file

@ -26,34 +26,11 @@ func nonZero[T protoInt]() T {
func TestStableMarshalSingle(t *testing.T) {
t.Run("empty", func(t *testing.T) {
t.Run("proto", func(t *testing.T) {
input := &generated.Primitives{}
require.Zero(t, input.StableSize())
input := &generated.Primitives{}
require.Zero(t, input.StableSize())
r := input.MarshalProtobuf(nil)
require.Empty(t, r)
})
t.Run("json", func(t *testing.T) {
input := &generated.Primitives{}
r, err := input.MarshalJSON()
require.NoError(t, err)
require.NotEmpty(t, r)
var actual test.Primitives
require.NoError(t, protojson.Unmarshal(r, &actual))
t.Run("protojson compatibility", func(t *testing.T) {
data, err := protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(&actual)
require.NoError(t, err)
require.JSONEq(t, string(data), string(r))
})
var actualFrostfs generated.Primitives
require.NoError(t, actualFrostfs.UnmarshalJSON(r))
require.Equal(t, input, &actualFrostfs)
primitivesEqual(t, input, &actual)
})
r := input.MarshalProtobuf(nil)
require.Empty(t, r)
})
marshalCases := []struct {
@ -99,12 +76,6 @@ func TestStableMarshalSingle(t *testing.T) {
var actual test.Primitives
require.NoError(t, protojson.Unmarshal(r, &actual))
t.Run("protojson compatibility", func(t *testing.T) {
data, err := protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(&actual)
require.NoError(t, err)
require.JSONEq(t, string(data), string(r))
})
var actualFrostfs generated.Primitives
require.NoError(t, actualFrostfs.UnmarshalJSON(r))
require.Equal(t, tc.input, &actualFrostfs)
@ -117,7 +88,6 @@ func TestStableMarshalSingle(t *testing.T) {
func primitivesEqual(t *testing.T, a *generated.Primitives, b *test.Primitives) {
// Compare each field directly, because proto-generated code has private fields.
require.Equal(t, len(a.FieldA), len(b.FieldA))
require.Equal(t, a.FieldA, b.FieldA)
require.Equal(t, a.FieldB, b.FieldB)
require.Equal(t, a.FieldC, b.FieldC)

Binary file not shown.

View file

@ -59,35 +59,6 @@ func emitJSONUnmarshal(g *protogen.GeneratedFile, msg *protogen.Message) {
g.P("}")
}
func emitJSONParseInteger(g *protogen.GeneratedFile, ident string, method string, bitSize int, typ string) {
g.P("r := in.JsonNumber()")
g.P("n := r.String()")
g.P("v, err := ", strconvPackage.Ident(method), "(n, 10, ", bitSize, ")")
g.P("if err != nil {")
g.P(" in.AddError(err)")
g.P(" return")
g.P("}")
g.P(ident, " := ", typ, "(v)")
}
func emitJSONReadEnum(g *protogen.GeneratedFile, name string, enumType string) {
g.P(`switch v := in.Interface().(type) {
case string:
if vv, ok := `+enumType+`_value[v]; ok {
`+name+` = `+enumType+`(vv)
break
}
vv, err := `, strconvPackage.Ident("ParseInt"), `(v, 10, 32)
if err != nil {
in.AddError(err)
return
}
`+name+` = `+enumType+`(vv)
case float64:
`+name+` = `+enumType+`(v)
}`)
}
func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string) {
g.P("{")
defer g.P("}")
@ -112,20 +83,30 @@ func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string
enumType := fieldType(g, f).String()
g.P("var parsedValue " + enumType)
emitJSONReadEnum(g, "parsedValue", enumType)
g.P(`switch v := in.Interface().(type) {
case string:
if vv, ok := `+enumType+`_value[v]; ok {
parsedValue = `+enumType+`(vv)
break
}
vv, err := `, strconvPackage.Ident("ParseInt"), `(v, 10, 32)
if err != nil {
in.AddError(err)
return
}
parsedValue = `+enumType+`(vv)
case float64:
parsedValue = `+enumType+`(v)
}`)
template = "%s = parsedValue"
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
emitJSONParseInteger(g, "pv", "ParseInt", 32, "int32")
template = "%s = pv"
template = "%s = in.Int32()"
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
emitJSONParseInteger(g, "pv", "ParseUint", 32, "uint32")
template = "%s = pv"
template = "%s = in.Uint32()"
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
emitJSONParseInteger(g, "pv", "ParseInt", 64, "int64")
template = "%s = pv"
template = "%s = in.Int64()"
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
emitJSONParseInteger(g, "pv", "ParseUint", 64, "uint64")
template = "%s = pv"
template = "%s = in.Uint64()"
case protoreflect.FloatKind:
template = "%s = in.Float32()"
case protoreflect.DoubleKind:
@ -133,17 +114,7 @@ func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string
case protoreflect.StringKind:
template = "%s = in.String()"
case protoreflect.BytesKind:
// Since some time ago proto3 support optional keyword, thus the presence is not tracked by default:
// https://github.com/protocolbuffers/protobuf-go/blob/fb995f184a1719ec42b247a3771d1036d92adf67/internal/impl/message_reflect_field.go#L327
// We do not explicitly support `optional` keyword, protoc will fail on such fileds.
// Thus, treat empty string as `[]byte(nil)`.
template = `{
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
%s = tmp
}`
template = "%s = in.Bytes()"
case protoreflect.MessageKind:
if f.Desc.IsList() {
g.P("f = ", fieldType(g, f)[2:], "{}")
@ -176,11 +147,8 @@ func emitJSONMarshal(g *protogen.GeneratedFile, msg *protogen.Message) {
g.P("func (x *", msg.GoIdent.GoName, ") MarshalEasyJSON(out *", jwriterPackage.Ident("Writer"), ") {")
g.P(`if x == nil { out.RawString("null"); return }`)
if len(msg.Fields) != 0 {
g.P("first := true")
}
g.P("out.RawByte('{')")
for _, f := range msg.Fields {
for i, f := range msg.Fields {
if f.Oneof != nil {
if f.Oneof.Fields[0] != f {
continue
@ -189,38 +157,29 @@ func emitJSONMarshal(g *protogen.GeneratedFile, msg *protogen.Message) {
g.P("switch xx := x.", f.Oneof.GoName, ".(type) {")
for _, ff := range f.Oneof.Fields {
g.P("case *", ff.GoIdent, ":")
emitJSONFieldWrite(g, ff, "xx")
emitJSONFieldWrite(g, ff, "xx", i == 0)
}
g.P("}")
continue
}
emitJSONFieldWrite(g, f, "x")
emitJSONFieldWrite(g, f, "x", i == 0)
}
g.P("out.RawByte('}')")
g.P("}")
}
func emitJSONFieldWrite(g *protogen.GeneratedFile, f *protogen.Field, name string) {
func emitJSONFieldWrite(g *protogen.GeneratedFile, f *protogen.Field, name string, first bool) {
g.P("{")
defer g.P("}")
g.P("const prefix string = ", `",\"`, fieldJSONName(f), `\":"`)
if first {
g.P("out.RawString(prefix[1:])")
} else {
g.P("out.RawString(prefix)")
}
selector := name + "." + f.GoName
// This code is responsible for ignoring default values.
// We will restore it after having parametrized JSON marshaling.
//
// isNotDefault := notNil
// if f.Desc.IsList() {
// isNotDefault = notEmpty
// } else if f.Desc.Kind() != protoreflect.MessageKind {
// _, isNotDefault = easyprotoKindInfo(f.Desc.Kind())
// }
// g.P("if ", isNotDefault(selector), "{")
// defer g.P("}")
g.P("if !first { out.RawByte(','); } else { first = false; }")
g.P("const prefix string = ", `"\"`, fieldJSONName(f), `\":"`)
g.P("out.RawString(prefix)")
if f.Desc.IsList() {
selector += "[i]"
g.P("out.RawByte('[')")
@ -236,27 +195,15 @@ func emitJSONFieldWrite(g *protogen.GeneratedFile, f *protogen.Field, name strin
case protoreflect.BoolKind:
template = "out.Bool(%s)"
case protoreflect.EnumKind:
enumType := fieldType(g, f).String()
template = `v := int32(%s)
if vv, ok := ` + enumType + `_name[v]; ok {
out.String(vv)
} else {
out.Int32(v)
}`
template = "out.Int32(int32(%s))"
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
template = "out.Int32(%s)"
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
template = "out.Uint32(%s)"
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
g.P("out.RawByte('\"')")
g.P("out.Buffer.Buf = ", strconvPackage.Ident("AppendInt"), "(out.Buffer.Buf, ", selector, ", 10)")
g.P("out.RawByte('\"')")
return
template = "out.Int64(%s)"
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
g.P("out.RawByte('\"')")
g.P("out.Buffer.Buf = ", strconvPackage.Ident("AppendUint"), "(out.Buffer.Buf, ", selector, ", 10)")
g.P("out.RawByte('\"')")
return
template = "out.Uint64(%s)"
case protoreflect.FloatKind:
template = "out.Float32(%s)"
case protoreflect.DoubleKind:
@ -264,10 +211,7 @@ func emitJSONFieldWrite(g *protogen.GeneratedFile, f *protogen.Field, name strin
case protoreflect.StringKind:
template = "out.String(%s)"
case protoreflect.BytesKind:
g.P("if ", selector, "!= nil {")
g.P("out.Base64Bytes(", selector, ")")
g.P("} else { out.String(\"\") }")
return
template = "out.Base64Bytes(%s)"
case protoreflect.MessageKind:
template = "%s.MarshalEasyJSON(out)"
case protoreflect.GroupKind: