diff --git a/v2/refs/marshal.go b/v2/refs/marshal.go new file mode 100644 index 0000000..2a835fd --- /dev/null +++ b/v2/refs/marshal.go @@ -0,0 +1,157 @@ +package refs + +import ( + "encoding/binary" + + "github.com/nspcc-dev/neofs-api-go/util/proto" +) + +const ( + OwnerIDValField = 1 + + ContainerIDValField = 1 + + ObjectIDValField = 1 + + AddressContainerField = 1 + AddressObjectField = 2 +) + +func (o *OwnerID) StableMarshal(buf []byte) ([]byte, error) { + if o == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, o.StableSize()) + } + + _, err := proto.BytesMarshal(OwnerIDValField, buf, o.val) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (o *OwnerID) StableSize() int { + if o == nil { + return 0 + } + return proto.BytesSize(OwnerIDValField, o.val) +} + +func (c *ContainerID) StableMarshal(buf []byte) ([]byte, error) { + if c == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, c.StableSize()) + } + + _, err := proto.BytesMarshal(ContainerIDValField, buf, c.val) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (c *ContainerID) StableSize() int { + if c == nil { + return 0 + } + return proto.BytesSize(ContainerIDValField, c.val) +} + +func (o *ObjectID) StableMarshal(buf []byte) ([]byte, error) { + if o == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, o.StableSize()) + } + + _, err := proto.BytesMarshal(ObjectIDValField, buf, o.val) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (o *ObjectID) StableSize() int { + if o == nil { + return 0 + } + + return proto.BytesSize(ObjectIDValField, o.val) +} + +func (a *Address) StableMarshal(buf []byte) ([]byte, error) { + if a == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, a.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if a.cid != nil { + prefix, _ = proto.NestedStructurePrefix(AddressContainerField) + offset = binary.PutUvarint(buf, prefix) + + n = a.cid.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = a.cid.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + } + + offset += n + } + + if a.oid != nil { + prefix, _ = proto.NestedStructurePrefix(AddressObjectField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = a.oid.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = a.oid.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + } + } + + return buf, nil +} + +func (a *Address) StableSize() (size int) { + if a == nil { + return 0 + } + + if a.cid != nil { + _, ln := proto.NestedStructurePrefix(AddressContainerField) + n := a.cid.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if a.oid != nil { + _, ln := proto.NestedStructurePrefix(AddressObjectField) + n := a.oid.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} diff --git a/v2/refs/marshal_test.go b/v2/refs/marshal_test.go new file mode 100644 index 0000000..0e9f7ac --- /dev/null +++ b/v2/refs/marshal_test.go @@ -0,0 +1,89 @@ +package refs_test + +import ( + "testing" + + "github.com/nspcc-dev/neofs-api-go/v2/refs" + grpc "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc" + "github.com/stretchr/testify/require" +) + +func TestOwnerID_StableMarshal(t *testing.T) { + ownerFrom := new(refs.OwnerID) + ownerTransport := new(grpc.OwnerID) + + t.Run("non empty", func(t *testing.T) { + ownerFrom.SetValue([]byte("Owner ID")) + + wire, err := ownerFrom.StableMarshal(nil) + require.NoError(t, err) + + err = ownerTransport.Unmarshal(wire) + require.NoError(t, err) + + ownerTo := refs.OwnerIDFromGRPCMessage(ownerTransport) + require.Equal(t, ownerFrom, ownerTo) + }) +} + +func TestContainerID_StableMarshal(t *testing.T) { + cnrFrom := new(refs.ContainerID) + cnrTransport := new(grpc.ContainerID) + + t.Run("non empty", func(t *testing.T) { + cnrFrom.SetValue([]byte("Container ID")) + + wire, err := cnrFrom.StableMarshal(nil) + require.NoError(t, err) + + err = cnrTransport.Unmarshal(wire) + require.NoError(t, err) + + cnrTo := refs.ContainerIDFromGRPCMessage(cnrTransport) + require.Equal(t, cnrFrom, cnrTo) + }) +} + +func TestObjectID_StableMarshal(t *testing.T) { + objectIDFrom := new(refs.ObjectID) + objectIDTransport := new(grpc.ObjectID) + + t.Run("non empty", func(t *testing.T) { + objectIDFrom.SetValue([]byte("Object ID")) + + wire, err := objectIDFrom.StableMarshal(nil) + require.NoError(t, err) + + err = objectIDTransport.Unmarshal(wire) + require.NoError(t, err) + + objectIDTo := refs.ObjectIDFromGRPCMessage(objectIDTransport) + require.Equal(t, objectIDFrom, objectIDTo) + }) +} + +func TestAddress_StableMarshal(t *testing.T) { + addressFrom := new(refs.Address) + + cnr := new(refs.ContainerID) + cnr.SetValue([]byte("Container ID")) + + objectID := new(refs.ObjectID) + objectID.SetValue([]byte("Object ID")) + + addressTransport := new(grpc.Address) + + t.Run("non empty", func(t *testing.T) { + addressFrom.SetContainerID(cnr) + addressFrom.SetObjectID(objectID) + + wire, err := addressFrom.StableMarshal(nil) + require.NoError(t, err) + + err = addressTransport.Unmarshal(wire) + require.NoError(t, err) + + addressTo := refs.AddressFromGRPCMessage(addressTransport) + require.Equal(t, addressFrom, addressTo) + }) +}