This commit is contained in:
Evgeniy Kulikov 2019-11-18 16:34:06 +03:00
commit 1cf33e5ffd
No known key found for this signature in database
GPG key ID: BF6AEE0A2A699BF2
87 changed files with 29835 additions and 0 deletions

68
refs/address.go Normal file
View file

@ -0,0 +1,68 @@
package refs
import (
"crypto/sha256"
"strings"
"github.com/nspcc-dev/neofs-proto/internal"
)
const (
joinSeparator = "/"
// ErrWrongAddress is raised when wrong address is passed to Address.Parse ParseAddress.
ErrWrongAddress = internal.Error("wrong address")
// ErrEmptyAddress is raised when empty address is passed to Address.Parse ParseAddress.
ErrEmptyAddress = internal.Error("empty address")
)
// ParseAddress parses address from string representation into new Address.
func ParseAddress(str string) (*Address, error) {
var addr Address
return &addr, addr.Parse(str)
}
// Parse parses address from string representation into current Address.
func (m *Address) Parse(addr string) error {
if m == nil {
return ErrEmptyAddress
}
items := strings.Split(addr, joinSeparator)
if len(items) != 2 {
return ErrWrongAddress
}
if err := m.CID.Parse(items[0]); err != nil {
return err
} else if err := m.ObjectID.Parse(items[1]); err != nil {
return err
}
return nil
}
// String returns string representation of Address.
func (m Address) String() string {
return strings.Join([]string{m.CID.String(), m.ObjectID.String()}, joinSeparator)
}
// IsFull checks that ContainerID and ObjectID is not empty.
func (m Address) IsFull() bool {
return !m.CID.Empty() && !m.ObjectID.Empty()
}
// Equal checks that current Address is equal to passed Address.
func (m Address) Equal(a2 *Address) bool {
return m.CID.Equal(a2.CID) && m.ObjectID.Equal(a2.ObjectID)
}
// Hash returns []byte that used as a key for storage bucket.
func (m Address) Hash() ([]byte, error) {
if !m.IsFull() {
return nil, ErrEmptyAddress
}
h := sha256.Sum256(append(m.ObjectID.Bytes(), m.CID.Bytes()...))
return h[:], nil
}

96
refs/cid.go Normal file
View file

@ -0,0 +1,96 @@
package refs
import (
"bytes"
"crypto/sha256"
"github.com/mr-tron/base58"
"github.com/pkg/errors"
)
// CIDForBytes creates CID for passed bytes.
func CIDForBytes(data []byte) CID { return sha256.Sum256(data) }
// CIDFromBytes parses CID from passed bytes.
func CIDFromBytes(data []byte) (cid CID, err error) {
if ln := len(data); ln != CIDSize {
return CID{}, errors.Wrapf(ErrWrongDataSize, "expect=%d, actual=%d", CIDSize, ln)
}
copy(cid[:], data)
return
}
// CIDFromString parses CID from string representation of CID.
func CIDFromString(c string) (CID, error) {
var cid CID
decoded, err := base58.Decode(c)
if err != nil {
return cid, err
}
return CIDFromBytes(decoded)
}
// Size returns size of CID (CIDSize).
func (c CID) Size() int { return CIDSize }
// Parse tries to parse CID from string representation.
func (c *CID) Parse(cid string) error {
var err error
if *c, err = CIDFromString(cid); err != nil {
return err
}
return nil
}
// Empty checks that current CID is empty.
func (c CID) Empty() bool { return bytes.Equal(c.Bytes(), emptyCID) }
// Equal checks that current CID is equal to passed CID.
func (c CID) Equal(cid CID) bool { return bytes.Equal(c.Bytes(), cid.Bytes()) }
// Marshal returns CID bytes representation.
func (c CID) Marshal() ([]byte, error) { return c.Bytes(), nil }
// MarshalBinary returns CID bytes representation.
func (c CID) MarshalBinary() ([]byte, error) { return c.Bytes(), nil }
// MarshalTo marshal CID to bytes representation into passed bytes.
func (c *CID) MarshalTo(data []byte) (int, error) { return copy(data, c.Bytes()), nil }
// ProtoMessage method to satisfy proto.Message interface.
func (c CID) ProtoMessage() {}
// String returns string representation of CID.
func (c CID) String() string { return base58.Encode(c[:]) }
// Reset resets current CID to zero value.
func (c *CID) Reset() { *c = CID{} }
// Bytes returns CID bytes representation.
func (c CID) Bytes() []byte {
buf := make([]byte, CIDSize)
copy(buf, c[:])
return buf
}
// UnmarshalBinary tries to parse bytes representation of CID.
func (c *CID) UnmarshalBinary(data []byte) error { return c.Unmarshal(data) }
// Unmarshal tries to parse bytes representation of CID.
func (c *CID) Unmarshal(data []byte) error {
if ln := len(data); ln != CIDSize {
return errors.Wrapf(ErrWrongDataSize, "expect=%d, actual=%d", CIDSize, ln)
}
copy((*c)[:], data)
return nil
}
// Verify validates that current CID is generated for passed bytes data.
func (c CID) Verify(data []byte) error {
if id := CIDForBytes(data); !bytes.Equal(c[:], id[:]) {
return errors.New("wrong hash for data")
}
return nil
}

65
refs/owner.go Normal file
View file

@ -0,0 +1,65 @@
package refs
import (
"bytes"
"crypto/ecdsa"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-proto/chain"
"github.com/pkg/errors"
)
// NewOwnerID returns generated OwnerID from passed public keys.
func NewOwnerID(keys ...*ecdsa.PublicKey) (owner OwnerID, err error) {
if len(keys) == 0 {
return
}
var d []byte
d, err = base58.Decode(chain.KeysToAddress(keys...))
if err != nil {
return
}
copy(owner[:], d)
return owner, nil
}
// Size returns OwnerID size in bytes (OwnerIDSize).
func (OwnerID) Size() int { return OwnerIDSize }
// Empty checks that current OwnerID is empty value.
func (o OwnerID) Empty() bool { return bytes.Equal(o.Bytes(), emptyOwner) }
// Equal checks that current OwnerID is equal to passed OwnerID.
func (o OwnerID) Equal(id OwnerID) bool { return bytes.Equal(o.Bytes(), id.Bytes()) }
// Reset sets current OwnerID to empty value.
func (o *OwnerID) Reset() { *o = OwnerID{} }
// ProtoMessage method to satisfy proto.Message interface.
func (OwnerID) ProtoMessage() {}
// Marshal returns OwnerID bytes representation.
func (o OwnerID) Marshal() ([]byte, error) { return o.Bytes(), nil }
// MarshalTo copies OwnerID bytes representation into passed slice of bytes.
func (o OwnerID) MarshalTo(data []byte) (int, error) { return copy(data, o.Bytes()), nil }
// String returns string representation of OwnerID.
func (o OwnerID) String() string { return base58.Encode(o[:]) }
// Bytes returns OwnerID bytes representation.
func (o OwnerID) Bytes() []byte {
buf := make([]byte, OwnerIDSize)
copy(buf, o[:])
return buf
}
// Unmarshal tries to parse OwnerID bytes representation into current OwnerID.
func (o *OwnerID) Unmarshal(data []byte) error {
if ln := len(data); ln != OwnerIDSize {
return errors.Wrapf(ErrWrongDataSize, "expect=%d, actual=%d", OwnerIDSize, ln)
}
copy((*o)[:], data)
return nil
}

14
refs/sgid.go Normal file
View file

@ -0,0 +1,14 @@
package refs
import (
"github.com/pkg/errors"
)
// SGIDFromBytes parse bytes representation of SGID into new SGID value.
func SGIDFromBytes(data []byte) (sgid SGID, err error) {
if ln := len(data); ln != SGIDSize {
return SGID{}, errors.Wrapf(ErrWrongDataSize, "expect=%d, actual=%d", SGIDSize, ln)
}
copy(sgid[:], data)
return
}

106
refs/types.go Normal file
View file

@ -0,0 +1,106 @@
// This package contains basic structures implemented in Go, such as
//
// CID - container id
// OwnerID - owner id
// ObjectID - object id
// SGID - storage group id
// Address - contains object id and container id
// UUID - a 128 bit (16 byte) Universal Unique Identifier as defined in RFC 4122
package refs
import (
"crypto/sha256"
"github.com/google/uuid"
"github.com/nspcc-dev/neofs-proto/chain"
"github.com/nspcc-dev/neofs-proto/internal"
)
type (
// CID is implementation of ContainerID.
CID [CIDSize]byte
// UUID wrapper over github.com/google/uuid.UUID.
UUID uuid.UUID
// SGID is type alias of UUID.
SGID = UUID
// ObjectID is type alias of UUID.
ObjectID = UUID
// MessageID is type alias of UUID.
MessageID = UUID
// OwnerID is wrapper over neofs-proto/chain.WalletAddress.
OwnerID chain.WalletAddress
)
const (
// UUIDSize contains size of UUID.
UUIDSize = 16
// SGIDSize contains size of SGID.
SGIDSize = UUIDSize
// CIDSize contains size of CID.
CIDSize = sha256.Size
// OwnerIDSize contains size of OwnerID.
OwnerIDSize = chain.AddressLength
// ErrWrongDataSize is raised when passed bytes into Unmarshal have wrong size.
ErrWrongDataSize = internal.Error("wrong data size")
// ErrEmptyOwner is raised when empty OwnerID is passed into container.New.
ErrEmptyOwner = internal.Error("owner cant be empty")
// ErrEmptyCapacity is raised when empty Capacity is passed container.New.
ErrEmptyCapacity = internal.Error("capacity cant be empty")
// ErrEmptyContainer is raised when it CID method is called for an empty container.
ErrEmptyContainer = internal.Error("cannot return ID for empty container")
)
var (
emptyCID = (CID{}).Bytes()
emptyUUID = (UUID{}).Bytes()
emptyOwner = (OwnerID{}).Bytes()
_ internal.Custom = (*CID)(nil)
_ internal.Custom = (*SGID)(nil)
_ internal.Custom = (*UUID)(nil)
_ internal.Custom = (*OwnerID)(nil)
_ internal.Custom = (*ObjectID)(nil)
_ internal.Custom = (*MessageID)(nil)
// NewSGID method alias.
NewSGID = NewUUID
// NewObjectID method alias.
NewObjectID = NewUUID
// NewMessageID method alias.
NewMessageID = NewUUID
)
// NewUUID returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewUUID() (UUID, error) {
id, err := uuid.NewRandom()
if err != nil {
return UUID{}, err
}
return UUID(id), nil
}

368
refs/types.pb.go Normal file
View file

@ -0,0 +1,368 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: refs/types.proto
package refs
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/golang/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Address struct {
ObjectID ObjectID `protobuf:"bytes,1,opt,name=ObjectID,proto3,customtype=ObjectID" json:"ObjectID"`
CID CID `protobuf:"bytes,2,opt,name=CID,proto3,customtype=CID" json:"CID"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Address) Reset() { *m = Address{} }
func (*Address) ProtoMessage() {}
func (*Address) Descriptor() ([]byte, []int) {
return fileDescriptor_063a64a96d952d31, []int{0}
}
func (m *Address) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
func (m *Address) XXX_Merge(src proto.Message) {
xxx_messageInfo_Address.Merge(m, src)
}
func (m *Address) XXX_Size() int {
return m.Size()
}
func (m *Address) XXX_DiscardUnknown() {
xxx_messageInfo_Address.DiscardUnknown(m)
}
var xxx_messageInfo_Address proto.InternalMessageInfo
func init() {
proto.RegisterType((*Address)(nil), "refs.Address")
}
func init() { proto.RegisterFile("refs/types.proto", fileDescriptor_063a64a96d952d31) }
var fileDescriptor_063a64a96d952d31 = []byte{
// 199 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x28, 0x4a, 0x4d, 0x2b,
0xd6, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x01, 0x89,
0x48, 0xe9, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xa7,
0xe7, 0xeb, 0x83, 0x25, 0x93, 0x4a, 0xd3, 0xc0, 0x3c, 0x30, 0x07, 0xcc, 0x82, 0x68, 0x52, 0x0a,
0xe3, 0x62, 0x77, 0x4c, 0x49, 0x29, 0x4a, 0x2d, 0x2e, 0x16, 0xd2, 0xe1, 0xe2, 0xf0, 0x4f, 0xca,
0x4a, 0x4d, 0x2e, 0xf1, 0x74, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x71, 0x12, 0x38, 0x71, 0x4f,
0x9e, 0xe1, 0xd6, 0x3d, 0x79, 0xb8, 0x78, 0x10, 0x9c, 0x25, 0x24, 0xcb, 0xc5, 0xec, 0xec, 0xe9,
0x22, 0xc1, 0x04, 0x56, 0xc8, 0x0d, 0x55, 0x08, 0x12, 0x0a, 0x02, 0x11, 0x4e, 0xce, 0x37, 0x1e,
0xca, 0x31, 0x34, 0x3c, 0x92, 0x63, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x1b,
0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf1, 0x58, 0x8e, 0x21, 0x4a, 0x15, 0xc9, 0x91,
0x79, 0xc5, 0x05, 0xc9, 0xc9, 0xba, 0x29, 0xa9, 0x65, 0xfa, 0x79, 0xa9, 0xf9, 0x69, 0xc5, 0xba,
0x10, 0x27, 0x82, 0xfc, 0x92, 0xc4, 0x06, 0x66, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xfd,
0xb6, 0x0b, 0x68, 0xec, 0x00, 0x00, 0x00,
}
func (m *Address) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Address) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Address) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
{
size := m.CID.Size()
i -= size
if _, err := m.CID.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
{
size := m.ObjectID.Size()
i -= size
if _, err := m.ObjectID.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func encodeVarintTypes(dAtA []byte, offset int, v uint64) int {
offset -= sovTypes(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Address) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = m.ObjectID.Size()
n += 1 + l + sovTypes(uint64(l))
l = m.CID.Size()
n += 1 + l + sovTypes(uint64(l))
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovTypes(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozTypes(x uint64) (n int) {
return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Address) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Address: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Address: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ObjectID", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.ObjectID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CID", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.CID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipTypes(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTypes
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTypes
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTypes
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthTypes
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupTypes
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthTypes
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group")
)

15
refs/types.proto Normal file
View file

@ -0,0 +1,15 @@
syntax = "proto3";
package refs;
option go_package = "github.com/nspcc-dev/neofs-proto/refs";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.stable_marshaler_all) = true;
option (gogoproto.stringer_all) = false;
option (gogoproto.goproto_stringer_all) = false;
message Address {
bytes ObjectID = 1[(gogoproto.customtype) = "ObjectID", (gogoproto.nullable) = false]; // UUID
bytes CID = 2[(gogoproto.customtype) = "CID", (gogoproto.nullable) = false]; // sha256
}

112
refs/types_test.go Normal file
View file

@ -0,0 +1,112 @@
package refs
import (
"strings"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/google/uuid"
"github.com/nspcc-dev/neofs-crypto/test"
"github.com/stretchr/testify/require"
)
func TestSGID(t *testing.T) {
t.Run("check that marshal/unmarshal works like expected", func(t *testing.T) {
var sgid1, sgid2 UUID
sgid1, err := NewSGID()
require.NoError(t, err)
data, err := proto.Marshal(&sgid1)
require.NoError(t, err)
require.NoError(t, sgid2.Unmarshal(data))
require.Equal(t, sgid1, sgid2)
})
}
func TestUUID(t *testing.T) {
t.Run("parse should work like expected", func(t *testing.T) {
var u UUID
id, err := uuid.NewRandom()
require.NoError(t, err)
require.NoError(t, u.Parse(id.String()))
require.Equal(t, id.String(), u.String())
})
t.Run("check that marshal/unmarshal works like expected", func(t *testing.T) {
var u1, u2 UUID
u1 = UUID{0x8f, 0xe4, 0xeb, 0xa0, 0xb8, 0xfb, 0x49, 0x3b, 0xbb, 0x1d, 0x1d, 0x13, 0x6e, 0x69, 0xfc, 0xf7}
data, err := proto.Marshal(&u1)
require.NoError(t, err)
require.NoError(t, u2.Unmarshal(data))
require.Equal(t, u1, u2)
})
t.Run("check that marshal/unmarshal works like expected even for msg id", func(t *testing.T) {
var u2 MessageID
u1, err := NewMessageID()
require.NoError(t, err)
data, err := proto.Marshal(&u1)
require.NoError(t, err)
require.NoError(t, u2.Unmarshal(data))
require.Equal(t, u1, u2)
})
}
func TestOwnerID(t *testing.T) {
t.Run("check that marshal/unmarshal works like expected", func(t *testing.T) {
var u1, u2 OwnerID
owner, err := NewOwnerID()
require.NoError(t, err)
require.True(t, owner.Empty())
key := test.DecodeKey(0)
u1, err = NewOwnerID(&key.PublicKey)
require.NoError(t, err)
data, err := proto.Marshal(&u1)
require.NoError(t, err)
require.NoError(t, u2.Unmarshal(data))
require.Equal(t, u1, u2)
})
}
func TestAddress(t *testing.T) {
cid := CIDForBytes([]byte("test"))
id, err := NewObjectID()
require.NoError(t, err)
expect := strings.Join([]string{
cid.String(),
id.String(),
}, joinSeparator)
require.NotPanics(t, func() {
actual := (Address{
ObjectID: id,
CID: cid,
}).String()
require.Equal(t, expect, actual)
})
var temp Address
require.NoError(t, temp.Parse(expect))
require.Equal(t, expect, temp.String())
actual, err := ParseAddress(expect)
require.NoError(t, err)
require.Equal(t, expect, actual.String())
}

76
refs/uuid.go Normal file
View file

@ -0,0 +1,76 @@
package refs
import (
"bytes"
"encoding/hex"
"github.com/google/uuid"
"github.com/pkg/errors"
)
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Size returns size in bytes of UUID (UUIDSize).
func (UUID) Size() int { return UUIDSize }
// Empty checks that current UUID is empty value.
func (u UUID) Empty() bool { return bytes.Equal(u.Bytes(), emptyUUID) }
// Reset sets current UUID to empty value.
func (u *UUID) Reset() { *u = [UUIDSize]byte{} }
// ProtoMessage method to satisfy proto.Message.
func (UUID) ProtoMessage() {}
// Marshal returns UUID bytes representation.
func (u UUID) Marshal() ([]byte, error) { return u.Bytes(), nil }
// MarshalTo returns UUID bytes representation.
func (u UUID) MarshalTo(data []byte) (int, error) { return copy(data, u[:]), nil }
// Bytes returns UUID bytes representation.
func (u UUID) Bytes() []byte {
buf := make([]byte, UUIDSize)
copy(buf, u[:])
return buf
}
// Equal checks that current UUID is equal to passed UUID.
func (u UUID) Equal(u2 UUID) bool { return bytes.Equal(u.Bytes(), u2.Bytes()) }
func (u UUID) String() string {
var buf [36]byte
encodeHex(buf[:], u)
return string(buf[:])
}
// Unmarshal tries to parse UUID bytes representation.
func (u *UUID) Unmarshal(data []byte) error {
if ln := len(data); ln != UUIDSize {
return errors.Wrapf(ErrWrongDataSize, "expect=%d, actual=%d", UUIDSize, ln)
}
copy((*u)[:], data)
return nil
}
// Parse tries to parse UUID string representation.
func (u *UUID) Parse(id string) error {
tmp, err := uuid.Parse(id)
if err != nil {
return errors.Wrapf(err, "could not parse `%s`", id)
}
copy((*u)[:], tmp[:])
return nil
}