diff --git a/go.mod b/go.mod index ba43d5b..5c5a576 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/hrw v1.0.9 - github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211118144033-580f6c5554ff + github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211124141318-d93828f46514 github.com/nspcc-dev/neofs-crypto v0.3.0 github.com/nspcc-dev/rfc6979 v0.2.0 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index b98906a..132d5c2 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= -github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211118144033-580f6c5554ff h1:j3NbdVKYPMh9/cQLD/LhY7gGKyVA6qtOIsJ/cKiXWUQ= -github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211118144033-580f6c5554ff/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= +github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211124141318-d93828f46514 h1:ccZ+d8nJa8H2IWCLlr6YSanqwtTP6YiWa8RmCtT8aOs= +github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211124141318-d93828f46514/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM= github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= diff --git a/subnet/id/id.go b/subnet/id/id.go new file mode 100644 index 0000000..3ae4a86 --- /dev/null +++ b/subnet/id/id.go @@ -0,0 +1,89 @@ +package subnetid + +import ( + "fmt" + + "github.com/nspcc-dev/neofs-api-go/v2/refs" +) + +// ID represents NeoFS subnet identifier. +// +// The type is compatible with the corresponding message from NeoFS API V2 protocol. +// +// Zero value and nil pointer is equivalent to zero subnet ID. +type ID refs.SubnetID + +// FromV2 initializes ID from refs.SubnetID message structure. Must not be called on nil. +// +// Note: nil refs.SubnetID corresponds to zero ID value or nil pointer to it. +func (x *ID) FromV2(msg refs.SubnetID) { + *x = ID(msg) +} + +// WriteToV2 writes ID to refs.SubnetID message structure. The message must not be nil. +// +// Note: nil ID corresponds to zero refs.SubnetID value or nil pointer to it. +func (x ID) WriteToV2(msg *refs.SubnetID) { + *msg = refs.SubnetID(x) +} + +// Equals returns true iff both instances identify the same subnet. +// +// Method is NPE-safe: nil pointer equals to pointer to zero value. +func (x *ID) Equals(x2 *ID) bool { + return (*refs.SubnetID)(x).GetValue() == (*refs.SubnetID)(x2).GetValue() +} + +// MarshalText encodes ID into text format according to particular NeoFS API protocol. +// Supported versions: +// * V2 (see refs.SubnetID type). +// +// Implements encoding.TextMarshaler. +func (x *ID) MarshalText() ([]byte, error) { + return (*refs.SubnetID)(x).MarshalText() +} + +// UnmarshalText decodes ID from the text according to particular NeoFS API protocol. +// Must not be called on nil. Supported versions: +// * V2 (see refs.SubnetID type). +// +// Implements encoding.TextUnmarshaler. +func (x *ID) UnmarshalText(text []byte) error { + return (*refs.SubnetID)(x).UnmarshalText(text) +} + +// String returns string representation of ID using MarshalText. +// Returns string with message on error. +// +// Implements fmt.Stringer. +func (x *ID) String() string { + text, err := x.MarshalText() + if err != nil { + return fmt.Sprintf(" %v", err) + } + + return string(text) +} + +// Marshal encodes ID into a binary format of NeoFS API V2 protocol (Protocol Buffers with direct field order). +func (x *ID) Marshal() ([]byte, error) { + return (*refs.SubnetID)(x).StableMarshal(nil) +} + +// Unmarshal decodes ID from NeoFS API V2 binary format (see Marshal). Must not be called on nil. +// +// Note: empty data corresponds to zero ID value or nil pointer to it. +func (x *ID) Unmarshal(data []byte) error { + return (*refs.SubnetID)(x).Unmarshal(data) +} + +// SetNumber sets ID value in uint32 format. Must not be called on nil. +// By default, number is 0 which refers to zero subnet. +func (x *ID) SetNumber(num uint32) { + (*refs.SubnetID)(x).SetValue(num) +} + +// IsZero returns true iff the ID refers to zero subnet. +func IsZero(id ID) bool { + return id.Equals(nil) +} diff --git a/subnet/id/id_test.go b/subnet/id/id_test.go new file mode 100644 index 0000000..21e0f12 --- /dev/null +++ b/subnet/id/id_test.go @@ -0,0 +1,94 @@ +package subnetid_test + +import ( + "testing" + + "github.com/nspcc-dev/neofs-api-go/v2/refs" + subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id" + subnetidtest "github.com/nspcc-dev/neofs-sdk-go/subnet/id/test" + "github.com/stretchr/testify/require" +) + +func TestIsZero(t *testing.T) { + var id subnetid.ID + + require.True(t, subnetid.IsZero(id)) + + id.SetNumber(13) + require.False(t, subnetid.IsZero(id)) + + id.SetNumber(0) + require.True(t, subnetid.IsZero(id)) +} + +func TestID_FromV2(t *testing.T) { + const num = 13 + + var id1 subnetid.ID + id1.SetNumber(num) + + var idv2 refs.SubnetID + idv2.SetValue(num) + + var id2 subnetid.ID + id2.FromV2(idv2) + + require.True(t, id1.Equals(&id2)) +} + +func TestID_WriteToV2(t *testing.T) { + const num = 13 + + var ( + id subnetid.ID + idv2 refs.SubnetID + ) + + id.WriteToV2(&idv2) + require.Zero(t, idv2.GetValue()) + + id.SetNumber(num) + + id.WriteToV2(&idv2) + require.EqualValues(t, num, idv2.GetValue()) +} + +func TestID_Equals(t *testing.T) { + const num = 13 + + var id1, id2, idOther, id0 subnetid.ID + + id0.Equals(nil) + + id1.SetNumber(num) + id2.SetNumber(num) + idOther.SetNumber(num + 1) + + require.True(t, id1.Equals(&id2)) + require.False(t, id1.Equals(&idOther)) + require.False(t, id2.Equals(&idOther)) +} + +func TestSubnetIDEncoding(t *testing.T) { + id := subnetidtest.GenerateID() + + t.Run("binary", func(t *testing.T) { + data, err := id.Marshal() + require.NoError(t, err) + + var id2 subnetid.ID + require.NoError(t, id2.Unmarshal(data)) + + require.True(t, id2.Equals(id)) + }) + + t.Run("text", func(t *testing.T) { + data, err := id.MarshalText() + require.NoError(t, err) + + var id2 subnetid.ID + require.NoError(t, id2.UnmarshalText(data)) + + require.True(t, id2.Equals(id)) + }) +} diff --git a/subnet/id/test/id.go b/subnet/id/test/id.go new file mode 100644 index 0000000..2d92f1c --- /dev/null +++ b/subnet/id/test/id.go @@ -0,0 +1,16 @@ +package subnetidtest + +import ( + "math/rand" + + subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id" +) + +// GenerateID generates and returns random subnetid.ID using math/rand.Uint32. +func GenerateID() *subnetid.ID { + var id subnetid.ID + + id.SetNumber(rand.Uint32()) + + return &id +}