Skip to content

Commit

Permalink
object: Handle API updates
Browse files Browse the repository at this point in the history
Includes stable marshaling, testing and a few convenient helper funcs.

Signed-off-by: Pavel Karpy <[email protected]>
  • Loading branch information
carpawell committed Feb 9, 2024
1 parent e7d37cf commit cca9610
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 3 deletions.
18 changes: 18 additions & 0 deletions link/grpc/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package link

import grpc "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc"

// SetId sets object ID.
func (x *Link_MeasuredObject) SetId(v *grpc.ObjectID) {
x.Id = v
}

// SetSize sets object size.
func (x *Link_MeasuredObject) SetSize(v uint32) {
x.Size = v
}

// SetChildren sets object's children.
func (x *Link) SetChildren(v []*Link_MeasuredObject) {
x.Children = v
}
30 changes: 30 additions & 0 deletions object/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func (h *SplitHeader) ToGRPCMessage() grpc.Message {
m.SetParentSignature(h.parSig.ToGRPCMessage().(*refsGRPC.Signature))
m.SetChildren(refs.ObjectIDListToGRPCMessage(h.children))
m.SetSplitId(h.splitID)
m.SetFirst(h.first.ToGRPCMessage().(*refsGRPC.ObjectID))
}

return m
Expand Down Expand Up @@ -224,6 +225,20 @@ func (h *SplitHeader) FromGRPCMessage(m grpc.Message) error {
}
}

first := v.GetFirst()
if first == nil {
h.first = nil
} else {
if h.first == nil {
h.first = new(refs.ObjectID)

Check warning on line 233 in object/convert.go

View check run for this annotation

Codecov / codecov/patch

object/convert.go#L232-L233

Added lines #L232 - L233 were not covered by tests
}

err = h.first.FromGRPCMessage(first)
if err != nil {
return err

Check warning on line 238 in object/convert.go

View check run for this annotation

Codecov / codecov/patch

object/convert.go#L236-L238

Added lines #L236 - L238 were not covered by tests
}
}

parHdr := v.GetParentHeader()
if parHdr == nil {
h.parHdr = nil
Expand Down Expand Up @@ -529,6 +544,7 @@ func (s *SplitInfo) ToGRPCMessage() grpc.Message {

m.SetLastPart(s.lastPart.ToGRPCMessage().(*refsGRPC.ObjectID))
m.SetLink(s.link.ToGRPCMessage().(*refsGRPC.ObjectID))
m.SetFirstPart(s.firstPart.ToGRPCMessage().(*refsGRPC.ObjectID))
m.SetSplitId(s.splitID)
}

Expand Down Expand Up @@ -571,6 +587,20 @@ func (s *SplitInfo) FromGRPCMessage(m grpc.Message) error {
}
}

first := v.GetFirstPart()
if first == nil {
s.firstPart = nil
} else {
if s.firstPart == nil {
s.firstPart = new(refs.ObjectID)

Check warning on line 595 in object/convert.go

View check run for this annotation

Codecov / codecov/patch

object/convert.go#L594-L595

Added lines #L594 - L595 were not covered by tests
}

err = s.firstPart.FromGRPCMessage(first)
if err != nil {
return err

Check warning on line 600 in object/convert.go

View check run for this annotation

Codecov / codecov/patch

object/convert.go#L598-L600

Added lines #L598 - L600 were not covered by tests
}
}

s.splitID = v.GetSplitId()

return nil
Expand Down
9 changes: 9 additions & 0 deletions object/grpc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (m *Header_Split) SetSplitId(v []byte) {
m.SplitId = v
}

func (m *Header_Split) SetFirst(v *refs.ObjectID) {
m.First = v
}

// SetContainerId sets identifier of the container.
func (m *Header) SetContainerId(v *refs.ContainerID) {
m.ContainerId = v
Expand Down Expand Up @@ -170,6 +174,11 @@ func (m *SplitInfo) SetLink(v *refs.ObjectID) {
m.Link = v
}

// SetFirstPart sets id of initializing object in split hierarchy.
func (m *SplitInfo) SetFirstPart(v *refs.ObjectID) {
m.FirstPart = v
}

// FromString parses ObjectType from a string representation,
// It is a reverse action to String().
//
Expand Down
230 changes: 230 additions & 0 deletions object/link.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package object

import (
"errors"
"fmt"

link "github.com/nspcc-dev/neofs-api-go/v2/link/grpc"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
refsGRPC "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc"
"github.com/nspcc-dev/neofs-api-go/v2/rpc/grpc"
"github.com/nspcc-dev/neofs-api-go/v2/rpc/message"
"github.com/nspcc-dev/neofs-api-go/v2/util/proto"
)

// Link represents object Link message from NeoFS API V2 protocol.
type Link struct {
children []MeasuredObject
}

// NumberOfChildren returns length of children list.
func (x *Link) NumberOfChildren() int {
if x != nil {
return len(x.children)

Check warning on line 23 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L21-L23

Added lines #L21 - L23 were not covered by tests
}

return 0

Check warning on line 26 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L26

Added line #L26 was not covered by tests
}

// IterateChildren passes members of the link list to f.
func (x *Link) IterateChildren(f func(MeasuredObject)) {
if x != nil {
for i := range x.children {
f(x.children[i])

Check warning on line 33 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L30-L33

Added lines #L30 - L33 were not covered by tests
}
}
}

// SetChildren sets a list of the child objects.
// Arg must not be mutated for the duration of the Link.
func (x *Link) SetChildren(chs []MeasuredObject) {
x.children = chs
}

const (
_ = iota
linkFNumChildren
)

const (
_ = iota
measuredObjectFNumID
measuredObjectFNumSize
)

// StableMarshal encodes the Link into Protocol Buffers binary format
// with direct field order.
func (x *Link) StableMarshal(buf []byte) []byte {
if x == nil || len(x.children) == 0 {
return []byte{}

Check warning on line 59 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L59

Added line #L59 was not covered by tests
}

if buf == nil {
buf = make([]byte, x.StableSize())
}

var offset int

for i := range x.children {
offset += proto.NestedStructureMarshal(linkFNumChildren, buf[offset:], &x.children[i])
}

return buf
}

// StableSize size of the buffer required to write the Link in Protocol Buffers
// binary format.
func (x *Link) StableSize() int {
var size int

if x != nil {
for i := range x.children {
size += proto.NestedStructureSize(linkFNumChildren, &x.children[i])
}
}

return size
}

// Unmarshal decodes the Link from its Protocol Buffers binary format.
func (x *Link) Unmarshal(data []byte) error {
return message.Unmarshal(x, data, new(link.Link))
}

func (x *Link) ToGRPCMessage() grpc.Message {
var m *link.Link

if x != nil {
m = new(link.Link)

var children []*link.Link_MeasuredObject

if x.children != nil {
children = make([]*link.Link_MeasuredObject, len(x.children))

for i := range x.children {
children[i] = x.children[i].ToGRPCMessage().(*link.Link_MeasuredObject)
}
}

m.Children = children
}

return m
}

func (x *Link) FromGRPCMessage(m grpc.Message) error {
v, ok := m.(*link.Link)
if !ok {
return message.NewUnexpectedMessageType(m, v)
}

children := v.GetChildren()
if children == nil {
x.children = nil

Check warning on line 124 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L124

Added line #L124 was not covered by tests
} else {
x.children = make([]MeasuredObject, len(children))
var err error

for i := range x.children {
err = x.children[i].FromGRPCMessage(children[i])
if err != nil {
return err

Check warning on line 132 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L132

Added line #L132 was not covered by tests
}
}
}

return nil
}

// MeasuredObject groups object descriptor and object's length.
type MeasuredObject struct {
ID refs.ObjectID
Size uint32
}

// StableSize size of the buffer required to write the MeasuredObject in Protocol Buffers
// binary format.
func (x *MeasuredObject) StableSize() int {
var size int

size += proto.NestedStructureSize(measuredObjectFNumID, &x.ID)
size += proto.UInt32Size(measuredObjectFNumSize, x.Size)

return size
}

// StableMarshal encodes the MeasuredObject into Protocol Buffers binary format
// with direct field order.
func (x *MeasuredObject) StableMarshal(buf []byte) []byte {
if buf == nil {
buf = make([]byte, x.StableSize())

Check warning on line 161 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L161

Added line #L161 was not covered by tests
}

var offset int

offset += proto.NestedStructureMarshal(measuredObjectFNumID, buf[offset:], &x.ID)
proto.UInt32Marshal(measuredObjectFNumSize, buf[offset:], x.Size)

return buf
}

// Unmarshal decodes the Link from its Protocol Buffers binary format.
func (x *MeasuredObject) Unmarshal(data []byte) error {
return message.Unmarshal(x, data, new(link.Link_MeasuredObject))

Check warning on line 174 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L173-L174

Added lines #L173 - L174 were not covered by tests
}

func (x *MeasuredObject) FromGRPCMessage(m grpc.Message) error {
v, ok := m.(*link.Link_MeasuredObject)
if !ok {
return message.NewUnexpectedMessageType(m, v)

Check warning on line 180 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L180

Added line #L180 was not covered by tests
}

if v.Id != nil {
err := x.ID.FromGRPCMessage(v.Id)
if err != nil {
return err

Check warning on line 186 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L186

Added line #L186 was not covered by tests
}
}

x.Size = v.Size

return nil
}

func (x *MeasuredObject) ToGRPCMessage() grpc.Message {
m := new(link.Link_MeasuredObject)

m.Id = x.ID.ToGRPCMessage().(*refsGRPC.ObjectID)
m.Size = x.Size

return m
}

// WriteLink writes Link to the Object as a payload content.
// The object must not be nil.
func WriteLink(obj *Object, link Link) {
hdr := obj.GetHeader()
if hdr == nil {
hdr = new(Header)
obj.SetHeader(hdr)
}

payload := link.StableMarshal(nil)
obj.SetPayload(payload)
}

// ReadLink reads Link from the Object payload content.
func ReadLink(link *Link, obj Object) error {
payload := obj.GetPayload()
if len(payload) == 0 {
return errors.New("empty payload")
}

err := link.Unmarshal(payload)
if err != nil {
return fmt.Errorf("decode link content from payload: %w", err)

Check warning on line 226 in object/link.go

View check run for this annotation

Codecov / codecov/patch

object/link.go#L226

Added line #L226 was not covered by tests
}

return nil
}
26 changes: 26 additions & 0 deletions object/link_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package object_test

import (
"testing"

"github.com/nspcc-dev/neofs-api-go/v2/object"
objecttest "github.com/nspcc-dev/neofs-api-go/v2/object/test"
"github.com/stretchr/testify/require"
)

func TestLinkRW(t *testing.T) {
var l object.Link
var obj object.Object

require.Error(t, object.ReadLink(&l, obj))

l = *objecttest.GenerateLink(false)

object.WriteLink(&obj, l)

var l2 object.Link

require.NoError(t, object.ReadLink(&l2, obj))

require.Equal(t, l, l2)
}
Loading

0 comments on commit cca9610

Please sign in to comment.