Add stable marshal for container structure
Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
18df156e61
commit
c37fca9e0d
4 changed files with 324 additions and 418 deletions
238
container/v2/marshal.go
Normal file
238
container/v2/marshal.go
Normal file
|
@ -0,0 +1,238 @@
|
|||
package v2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// StableMarshal marshals auto-generated container structure into
|
||||
// protobuf-compatible stable byte sequence.
|
||||
func (m *Container) StableMarshal(buf []byte) ([]byte, error) {
|
||||
if m == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if buf == nil {
|
||||
buf = make([]byte, m.StableSize())
|
||||
}
|
||||
|
||||
var (
|
||||
i, n, offset int
|
||||
)
|
||||
|
||||
// Write owner id field.
|
||||
|
||||
if m.OwnerId != nil {
|
||||
buf[i] = 0x0A // id:0x1 << 3 | wiretype:0x2
|
||||
n = m.OwnerId.StableSize()
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(n))
|
||||
|
||||
_, err := m.OwnerId.StableMarshal(buf[i+1+offset:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't marshal owner id")
|
||||
}
|
||||
|
||||
i += 1 + offset + n
|
||||
}
|
||||
|
||||
// Write salt field.
|
||||
|
||||
buf[i] = 0x12 // id:0x2 << 3 | wiretype:0x2
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(len(m.Nonce)))
|
||||
n = copy(buf[i+1+offset:], m.Nonce)
|
||||
i += 1 + offset + n
|
||||
|
||||
// Write basic acl field.
|
||||
|
||||
buf[i] = 0x18 // id:0x3 << 3 | wiretype:0x0
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(m.BasicAcl))
|
||||
i += 1 + offset
|
||||
|
||||
// Write attributes field.
|
||||
|
||||
for j := range m.Attributes {
|
||||
buf[i] = 0x22 // id:0x4 << 3 | wiretype:0x2
|
||||
n = m.Attributes[j].StableSize()
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(n))
|
||||
|
||||
_, err := m.Attributes[j].StableMarshal(buf[i+1+offset:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't marshal attribute %v",
|
||||
m.Attributes[i].Key)
|
||||
}
|
||||
|
||||
i += 1 + offset + n
|
||||
}
|
||||
|
||||
// Write placement rule field.
|
||||
|
||||
if m.Rules != nil {
|
||||
buf[i] = 0x2A // id:0x5 << 3 | wiretype:0x2
|
||||
n = m.Rules.StableSize()
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(n))
|
||||
|
||||
_, err := m.Rules.StableMarshal(buf[i+1+offset:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't marshal attribute %v",
|
||||
m.Attributes[i].Key)
|
||||
}
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (m *Container) StableSize() int {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
var (
|
||||
ln, size int
|
||||
)
|
||||
|
||||
if m.OwnerId != nil {
|
||||
ln = m.OwnerId.StableSize()
|
||||
}
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + bytes length + bytes
|
||||
|
||||
ln = len(m.Nonce) // size of salt field
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + bytes length + bytes
|
||||
|
||||
// size of basic acl field
|
||||
size += 1 + uvarIntSize(uint64(m.BasicAcl)) // wiretype + varint
|
||||
|
||||
// size of attributes
|
||||
for i := range m.Attributes {
|
||||
ln = m.Attributes[i].StableSize()
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of struct + struct
|
||||
}
|
||||
|
||||
// size of placement rule
|
||||
if m.Rules != nil {
|
||||
ln = m.Rules.StableSize()
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of struct + struct
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
func (m *Container_Attribute) StableMarshal(buf []byte) ([]byte, error) {
|
||||
if m == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if buf == nil {
|
||||
buf = make([]byte, m.StableSize())
|
||||
}
|
||||
|
||||
var (
|
||||
i, n, offset int
|
||||
)
|
||||
|
||||
// Write key field.
|
||||
|
||||
buf[i] = 0x0A // id:0x1 << 3 | wiretype:0x2
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(len(m.Key)))
|
||||
n = copy(buf[i+1+offset:], m.Key)
|
||||
i += 1 + offset + n
|
||||
|
||||
// Write value field.
|
||||
|
||||
buf[i] = 0x12 // id:0x2 << 3 | wiretype:0x2
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(len(m.Value)))
|
||||
copy(buf[i+1+offset:], m.Value)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (m *Container_Attribute) StableSize() int {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
var (
|
||||
ln, size int
|
||||
)
|
||||
|
||||
ln = len(m.Key) // size of key field
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of string + string
|
||||
|
||||
ln = len(m.Value) // size of value field
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of string + string
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
func (m *PutRequest_Body) StableMarshal(buf []byte) ([]byte, error) {
|
||||
if m == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if buf == nil {
|
||||
buf = make([]byte, m.StableSize())
|
||||
}
|
||||
|
||||
var (
|
||||
i, n, offset int
|
||||
)
|
||||
|
||||
// Write container field.
|
||||
|
||||
if m.Container != nil {
|
||||
buf[i] = 0x0A // id:0x1 << 3 | wiretype:0x2
|
||||
n = m.Container.StableSize()
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(n))
|
||||
|
||||
_, err := m.Container.StableMarshal(buf[i+1+offset:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't marshal container")
|
||||
}
|
||||
|
||||
i += 1 + offset + n
|
||||
}
|
||||
|
||||
// Write public key field.
|
||||
|
||||
buf[i] = 0x12 // id:0x2 << 3 | wiretype:0x2
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(len(m.PublicKey)))
|
||||
n = copy(buf[i+1+offset:], m.PublicKey)
|
||||
i += 1 + offset + n
|
||||
|
||||
// Write signature field.
|
||||
|
||||
buf[i] = 0x1A // id:0x3 << 3 | wiretype:0x2
|
||||
offset = binary.PutUvarint(buf[i+1:], uint64(len(m.Signature)))
|
||||
copy(buf[i+1+offset:], m.Signature)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (m *PutRequest_Body) StableSize() int {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
var (
|
||||
ln, size int
|
||||
)
|
||||
|
||||
if m.Container != nil {
|
||||
ln = m.Container.StableSize()
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of string + string
|
||||
}
|
||||
|
||||
ln = len(m.PublicKey)
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of string + string
|
||||
|
||||
ln = len(m.Signature)
|
||||
size += 1 + uvarIntSize(uint64(ln)) + ln // wiretype + size of string + string
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
// uvarIntSize returns length of varint byte sequence for uint64 value 'x'.
|
||||
func uvarIntSize(x uint64) int {
|
||||
return (bits.Len64(x|1) + 6) / 7
|
||||
}
|
77
container/v2/marshal_test.go
Normal file
77
container/v2/marshal_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package v2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
netmap "github.com/nspcc-dev/neofs-api-go/netmap/v2"
|
||||
refs "github.com/nspcc-dev/neofs-api-go/refs/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
cnr = &Container{
|
||||
OwnerId: &refs.OwnerID{Value: []byte("Owner")},
|
||||
Nonce: []byte("Salt"),
|
||||
BasicAcl: 505,
|
||||
Attributes: []*Container_Attribute{
|
||||
{
|
||||
Key: "Hello",
|
||||
Value: "World",
|
||||
},
|
||||
{
|
||||
Key: "Privet",
|
||||
Value: "Mir",
|
||||
},
|
||||
},
|
||||
Rules: &netmap.PlacementRule{
|
||||
ReplFactor: 4,
|
||||
SfGroups: []*netmap.PlacementRule_SFGroup{
|
||||
{
|
||||
Selectors: []*netmap.PlacementRule_SFGroup_Selector{
|
||||
{
|
||||
Count: 1,
|
||||
Key: "Node",
|
||||
},
|
||||
},
|
||||
Filters: []*netmap.PlacementRule_SFGroup_Filter{
|
||||
{
|
||||
Key: "City",
|
||||
},
|
||||
{
|
||||
Key: "Datacenter",
|
||||
},
|
||||
},
|
||||
Exclude: []uint32{4, 5, 6},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestContainer_StableMarshal(t *testing.T) {
|
||||
newCnr := new(Container)
|
||||
|
||||
wire, err := cnr.StableMarshal(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = newCnr.Unmarshal(wire)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, cnr, newCnr)
|
||||
}
|
||||
|
||||
func TestPutRequest_Body_StableMarshal(t *testing.T) {
|
||||
expectedBody := new(PutRequest_Body)
|
||||
expectedBody.Container = cnr
|
||||
expectedBody.PublicKey = []byte{1, 2, 3, 4}
|
||||
expectedBody.Signature = []byte{5, 6, 7, 8}
|
||||
|
||||
wire, err := expectedBody.StableMarshal(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
gotBody := new(PutRequest_Body)
|
||||
err = gotBody.Unmarshal(wire)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, expectedBody, gotBody)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue