From 00439572fbcc87ce8f1b0aa134964283ba195e10 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 19 Feb 2019 16:41:20 +0000 Subject: [PATCH] Let Cid implement Binary[Un]Marshaler and Text[Un]Marshaler interfaces. This makes Cid implement https://golang.org/pkg/encoding/#BinaryMarshaler which is used by go-codec to decide if things know how to serialize themselves (currently we need do manual wrapping for anything containing a CID). Since I was at it, I did the TextMarshaling one too. --- cid.go | 40 ++++++++++++++++++++++++++++++++++++++++ cid_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/cid.go b/cid.go index 553731b..ae9deb8 100644 --- a/cid.go +++ b/cid.go @@ -21,6 +21,7 @@ package cid import ( "bytes" + "encoding" "encoding/binary" "encoding/json" "errors" @@ -167,6 +168,11 @@ func NewCidV1(codecType uint64, mhash mh.Multihash) Cid { return Cid{string(buf[:n+hashlen])} } +var _ encoding.BinaryMarshaler = Cid{} +var _ encoding.BinaryUnmarshaler = (*Cid)(nil) +var _ encoding.TextMarshaler = Cid{} +var _ encoding.TextUnmarshaler = (*Cid)(nil) + // Cid represents a self-describing content addressed // identifier. It is formed by a Version, a Codec (which indicates // a multicodec-packed content type) and a Multihash. @@ -314,6 +320,28 @@ func Cast(data []byte) (Cid, error) { return Cid{string(data[0 : n+cn+len(h)])}, nil } +// UnmarshalBinary is equivalent to Cast(). It implements the +// encoding.BinaryUnmarshaler interface. +func (c *Cid) UnmarshalBinary(data []byte) error { + casted, err := Cast(data) + if err != nil { + return err + } + c.str = casted.str + return nil +} + +// UnmarshalText is equivalent to Decode(). It implements the +// encoding.TextUnmarshaler interface. +func (c *Cid) UnmarshalText(text []byte) error { + decodedCid, err := Decode(string(text)) + if err != nil { + return err + } + c.str = decodedCid.str + return nil +} + // Version returns the Cid version. func (c Cid) Version() uint64 { if len(c.str) == 34 && c.str[0] == 18 && c.str[1] == 32 { @@ -404,6 +432,18 @@ func (c Cid) Bytes() []byte { return []byte(c.str) } +// MarshalBinary is equivalent to Bytes(). It implements the +// encoding.BinaryMarshaler interface. +func (c Cid) MarshalBinary() ([]byte, error) { + return c.Bytes(), nil +} + +// MarshalText is equivalent to String(). It implements the +// encoding.TextMarshaler interface. +func (c Cid) MarshalText() ([]byte, error) { + return []byte(c.String()), nil +} + // Equals checks that two Cids are the same. // In order for two Cids to be considered equal, the // Version, the Codec and the Multihash must match. diff --git a/cid_test.go b/cid_test.go index c05acd6..899b723 100644 --- a/cid_test.go +++ b/cid_test.go @@ -158,6 +158,44 @@ func TestBasesMarshaling(t *testing.T) { } } +func TestBinaryMarshaling(t *testing.T) { + data := []byte("this is some test content") + hash, _ := mh.Sum(data, mh.SHA2_256, -1) + c := NewCidV1(DagCBOR, hash) + var c2 Cid + + data, err := c.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = c2.UnmarshalBinary(data) + if err != nil { + t.Fatal(err) + } + if !c.Equals(c2) { + t.Errorf("cids should be the same: %s %s", c, c2) + } +} + +func TestTextMarshaling(t *testing.T) { + data := []byte("this is some test content") + hash, _ := mh.Sum(data, mh.SHA2_256, -1) + c := NewCidV1(DagCBOR, hash) + var c2 Cid + + data, err := c.MarshalText() + if err != nil { + t.Fatal(err) + } + err = c2.UnmarshalText(data) + if err != nil { + t.Fatal(err) + } + if !c.Equals(c2) { + t.Errorf("cids should be the same: %s %s", c, c2) + } +} + func TestEmptyString(t *testing.T) { _, err := Decode("") if err == nil {