Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Leonard Lyubich <[email protected]>
  • Loading branch information
cthulhu-rider committed May 29, 2024
1 parent 705a328 commit 5234f05
Show file tree
Hide file tree
Showing 166 changed files with 35,208 additions and 6,785 deletions.
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

0 comments on commit 5234f05

Please sign in to comment.