Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop neofs-api-go dependency #583

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 46 additions & 32 deletions accounting/decimal.go
Original file line number Diff line number Diff line change
@@ -1,93 +1,107 @@
package accounting

import (
"github.com/nspcc-dev/neofs-api-go/v2/accounting"
"fmt"

"github.com/nspcc-dev/neofs-sdk-go/api/accounting"
"google.golang.org/protobuf/proto"
)

// Decimal represents decimal number for accounting operations.
//
// Decimal is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/accounting.Decimal
// message. See ReadFromV2 / WriteToV2 methods.
// Decimal is mutually compatible with [accounting.Decimal] message. See
// [Decimal.ReadFromV2] / [Decimal.WriteToV2] methods.
//
// Instances can be created using built-in var declaration.
//
// Note that direct typecast is not safe and may result in loss of compatibility:
//
// _ = Decimal(accounting.Decimal{}) // not recommended
type Decimal accounting.Decimal
type Decimal struct {
val int64
prec uint32
}

// ReadFromV2 reads Decimal from the accounting.Decimal message. Checks if the
// message conforms to NeoFS API V2 protocol.
// ReadFromV2 reads Decimal from the [accounting.Decimal] message. Returns an
// error if the message is malformed according to the NeoFS API V2 protocol. The
// message must not be nil.
//
// See also WriteToV2.
func (d *Decimal) ReadFromV2(m accounting.Decimal) error {
*d = Decimal(m)
// ReadFromV2 is intended to be used by the NeoFS API V2 client/server
// implementation only and is not expected to be directly used by applications.
//
// See also [Decimal.WriteToV2].
func (d *Decimal) ReadFromV2(m *accounting.Decimal) error {
d.val = m.Value
d.prec = m.Precision
return nil
}

// WriteToV2 writes Decimal to the accounting.Decimal message.
// The message must not be nil.
// WriteToV2 writes Decimal to the [accounting.Decimal] message of the NeoFS API
// protocol.
//
// WriteToV2 is intended to be used by the NeoFS API V2 client/server
// implementation only and is not expected to be directly used by applications.
//
// See also ReadFromV2.
// See also [Decimal.ReadFromV2].
func (d Decimal) WriteToV2(m *accounting.Decimal) {
*m = (accounting.Decimal)(d)
m.Value = d.val
m.Precision = d.prec
}

// Value returns value of the decimal number.
//
// Zero Decimal has zero value.
//
// See also SetValue.
// See also [Decimal.SetValue].
func (d Decimal) Value() int64 {
return (*accounting.Decimal)(&d).GetValue()
return d.val
}

// SetValue sets value of the decimal number.
//
// See also Value.
// See also [Decimal.Value].
func (d *Decimal) SetValue(v int64) {
(*accounting.Decimal)(d).SetValue(v)
d.val = v
}

// Precision returns precision of the decimal number.
//
// Zero Decimal has zero precision.
//
// See also SetPrecision.
// See also [Decimal.SetPrecision].
func (d Decimal) Precision() uint32 {
return (*accounting.Decimal)(&d).GetPrecision()
return d.prec
}

// SetPrecision sets precision of the decimal number.
//
// See also Precision.
// See also [Decimal.Precision].
func (d *Decimal) SetPrecision(p uint32) {
(*accounting.Decimal)(d).SetPrecision(p)
d.prec = p
}

// TODO: why needed? if so, can be non-deterministic?

// Marshal encodes Decimal into a binary format of the NeoFS API protocol
// (Protocol Buffers with direct field order).
//
// See also Unmarshal.
// See also [Decimal.Unmarshal].
func (d Decimal) Marshal() []byte {
var m accounting.Decimal
d.WriteToV2(&m)

return m.StableMarshal(nil)
b := make([]byte, m.MarshaledSize())
m.MarshalStable(b)
return b
}

// Unmarshal decodes NeoFS API protocol binary format into the Decimal
// (Protocol Buffers with direct field order). Returns an error describing
// a format violation.
//
// See also Marshal.
// See also [Decimal.Marshal].
func (d *Decimal) Unmarshal(data []byte) error {
var m accounting.Decimal

err := m.Unmarshal(data)
err := proto.Unmarshal(data, &m)
if err != nil {
return err
return fmt.Errorf("decode protobuf")
}

return d.ReadFromV2(m)
return d.ReadFromV2(&m)
}
82 changes: 51 additions & 31 deletions accounting/decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,74 @@ package accounting_test
import (
"testing"

v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
"github.com/nspcc-dev/neofs-sdk-go/accounting"
accountingtest "github.com/nspcc-dev/neofs-sdk-go/accounting/test"
apiaccounting "github.com/nspcc-dev/neofs-sdk-go/api/accounting"
"github.com/stretchr/testify/require"
)

func TestDecimalData(t *testing.T) {
const v, p = 4, 2
func TestDecimal_Unmarshal(t *testing.T) {
t.Run("invalid binary", func(t *testing.T) {
var d accounting.Decimal
msg := []byte("definitely_not_protobuf")
err := d.Unmarshal(msg)
require.ErrorContains(t, err, "decode protobuf")
})
}

func testDecimalField[Type uint32 | int64](t *testing.T, get func(accounting.Decimal) Type, set func(*accounting.Decimal, Type),
getAPI func(info *apiaccounting.Decimal) Type) {
var d accounting.Decimal

require.Zero(t, d.Value())
require.Zero(t, d.Precision())
require.Zero(t, get(d))

d.SetValue(v)
d.SetPrecision(p)
const val = 13
set(&d, val)
require.EqualValues(t, val, get(d))

require.EqualValues(t, v, d.Value())
require.EqualValues(t, p, d.Precision())
}
const valOther = 42
set(&d, valOther)
require.EqualValues(t, valOther, get(d))

func TestDecimalMessageV2(t *testing.T) {
var (
d accounting.Decimal
m v2accounting.Decimal
)
t.Run("encoding", func(t *testing.T) {
t.Run("binary", func(t *testing.T) {
var src, dst accounting.Decimal

m.SetValue(7)
m.SetPrecision(8)
set(&dst, val)

require.NoError(t, d.ReadFromV2(m))
require.NoError(t, dst.Unmarshal(src.Marshal()))
require.Zero(t, get(dst))

require.EqualValues(t, m.GetValue(), d.Value())
require.EqualValues(t, m.GetPrecision(), d.Precision())
set(&src, val)

var m2 v2accounting.Decimal
require.NoError(t, dst.Unmarshal(src.Marshal()))
require.EqualValues(t, val, get(dst))
})
t.Run("api", func(t *testing.T) {
var src, dst accounting.Decimal
var msg apiaccounting.Decimal

d.WriteToV2(&m2)
set(&dst, val)

require.EqualValues(t, d.Value(), m2.GetValue())
require.EqualValues(t, d.Precision(), m2.GetPrecision())
}
src.WriteToV2(&msg)
require.Zero(t, getAPI(&msg))
require.NoError(t, dst.ReadFromV2(&msg))
require.Zero(t, get(dst))

func TestDecimal_Marshal(t *testing.T) {
d := accountingtest.Decimal()
set(&src, val)

var d2 accounting.Decimal
require.NoError(t, d2.Unmarshal(d.Marshal()))
src.WriteToV2(&msg)
require.EqualValues(t, val, getAPI(&msg))
err := dst.ReadFromV2(&msg)
require.NoError(t, err)
require.EqualValues(t, val, get(dst))
})
})
}

func TestDecimal_SetValue(t *testing.T) {
testDecimalField(t, accounting.Decimal.Value, (*accounting.Decimal).SetValue, (*apiaccounting.Decimal).GetValue)
}

require.Equal(t, d, d2)
func TestDecimal_SetPrecision(t *testing.T) {
testDecimalField(t, accounting.Decimal.Precision, (*accounting.Decimal).SetPrecision, (*apiaccounting.Decimal).GetPrecision)
}
7 changes: 3 additions & 4 deletions accounting/example_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package accounting_test

import (
apiGoAccounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
"github.com/nspcc-dev/neofs-sdk-go/accounting"
apiaccounting "github.com/nspcc-dev/neofs-sdk-go/api/accounting"
)

func Example() {
Expand All @@ -16,11 +16,10 @@ func Example() {

// On the client side.

// import apiGoAccounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
var msg apiGoAccounting.Decimal
var msg apiaccounting.Decimal
dec.WriteToV2(&msg)
// *send message*

// On the server side.
_ = dec.ReadFromV2(msg)
_ = dec.ReadFromV2(&msg)
}
25 changes: 25 additions & 0 deletions accounting/test/decimal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package accountingtest_test

import (
"testing"

"github.com/nspcc-dev/neofs-sdk-go/accounting"
accountingtest "github.com/nspcc-dev/neofs-sdk-go/accounting/test"
apiaccounting "github.com/nspcc-dev/neofs-sdk-go/api/accounting"
"github.com/stretchr/testify/require"
)

func TestDecimal(t *testing.T) {
d := accountingtest.Decimal()
require.NotEqual(t, d, accountingtest.Decimal())

var d2 accounting.Decimal
require.NoError(t, d2.Unmarshal(d.Marshal()))
require.Equal(t, d, d2)

var m apiaccounting.Decimal
d.WriteToV2(&m)
var d3 accounting.Decimal
require.NoError(t, d3.ReadFromV2(&m))
require.Equal(t, d, d3)
}
65 changes: 65 additions & 0 deletions api/accounting/encoding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package accounting

import (
"github.com/nspcc-dev/neofs-sdk-go/internal/proto"
)

const (
_ = iota
fieldDecimalValue
fieldDecimalPrecision
)

func (x *Decimal) MarshaledSize() int {
var sz int
if x != nil {
sz = proto.SizeVarint(fieldDecimalValue, x.Value) +
proto.SizeVarint(fieldDecimalPrecision, x.Precision)
}
return sz
}

func (x *Decimal) MarshalStable(b []byte) {
if x != nil {
off := proto.MarshalVarint(b, fieldDecimalValue, x.Value)
proto.MarshalVarint(b[off:], fieldDecimalPrecision, x.Precision)
}
}

const (
_ = iota
fieldBalanceReqOwner
)

func (x *BalanceRequest_Body) MarshaledSize() int {
var sz int
if x != nil {
sz = proto.SizeNested(fieldBalanceReqOwner, x.OwnerId)
}
return sz
}

func (x *BalanceRequest_Body) MarshalStable(b []byte) {
if x != nil {
proto.MarshalNested(b, fieldBalanceReqOwner, x.OwnerId)
}
}

const (
_ = iota
fieldBalanceRespBalance
)

func (x *BalanceResponse_Body) MarshaledSize() int {
var sz int
if x != nil {
sz = proto.SizeNested(fieldBalanceRespBalance, x.Balance)
}
return sz
}

func (x *BalanceResponse_Body) MarshalStable(b []byte) {
if x != nil {
proto.MarshalNested(b, fieldBalanceRespBalance, x.Balance)
}
}
Loading
Loading