Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new Builder interface for creating CIDs. #53

Merged
merged 9 commits into from
Aug 10, 2018
74 changes: 74 additions & 0 deletions builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package cid

import (
mh "github.com/multiformats/go-multihash"
)

type Builder interface {
Sum(data []byte) (*Cid, error)
GetCodec() uint64
WithCodec(uint64) Builder
}

type V0Builder struct{}

type V1Builder struct {
Codec uint64
MhType uint64
MhLength int // MhLength <= 0 means the default length
}

func (p Prefix) GetCodec() uint64 {
return p.Codec
}

func (p Prefix) WithCodec(c uint64) Builder {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should comment that this will auto-upgrade to CIDv1 if necessary. Actually, I wonder if this should return a prefix or just return a builder (V1/V0).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that is intentional. I don't see any reason why this should return a builder V1/V0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was just a thought. I don't really see any benefit one way or the other.

if c == p.Codec {
return p
}
p.Codec = c
if c != DagProtobuf {
p.Version = 1
}
return p
}

func (p V0Builder) Sum(data []byte) (*Cid, error) {
hash, err := mh.Sum(data, mh.SHA2_256, -1)
if err != nil {
return nil, err
}
return NewCidV0(hash), nil
}

func (p V0Builder) GetCodec() uint64 {
return DagProtobuf
}

func (p V0Builder) WithCodec(c uint64) Builder {
if c == DagProtobuf {
return p
}
return V1Builder{Codec: c, MhType: mh.SHA2_256}
}

func (p V1Builder) Sum(data []byte) (*Cid, error) {
mhLen := p.MhLength
if mhLen <= 0 {
mhLen = -1
}
hash, err := mh.Sum(data, p.MhType, mhLen)
if err != nil {
return nil, err
}
return NewCidV1(p.Codec, hash), nil
}

func (p V1Builder) GetCodec() uint64 {
return p.Codec
}

func (p V1Builder) WithCodec(c uint64) Builder {
p.Codec = c
return p
}
92 changes: 92 additions & 0 deletions builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cid

import (
"testing"

mh "github.com/multiformats/go-multihash"
)

func TestV0Builder(t *testing.T) {
data := []byte("this is some test content")

// Construct c1
format := V0Builder{}
c1, err := format.Sum(data)
if err != nil {
t.Fatal(err)
}

// Construct c2
hash, err := mh.Sum(data, mh.SHA2_256, -1)
if err != nil {
t.Fatal(err)
}
c2 := NewCidV0(hash)

if !c1.Equals(c2) {
t.Fatal("cids mismatch")
}
if c1.Prefix() != c2.Prefix() {
t.Fatal("prefixes mismatch")
}
}

func TestV1Builder(t *testing.T) {
data := []byte("this is some test content")

// Construct c1
format := V1Builder{Codec: DagCBOR, MhType: mh.SHA2_256}
c1, err := format.Sum(data)
if err != nil {
t.Fatal(err)
}

// Construct c2
hash, err := mh.Sum(data, mh.SHA2_256, -1)
if err != nil {
t.Fatal(err)
}
c2 := NewCidV1(DagCBOR, hash)

if !c1.Equals(c2) {
t.Fatal("cids mismatch")
}
if c1.Prefix() != c2.Prefix() {
t.Fatal("prefixes mismatch")
}
}

func TestCodecChange(t *testing.T) {
t.Run("Prefix-CidV0", func(t *testing.T) {
p := Prefix{Version: 0, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: mh.DefaultLengths[mh.SHA2_256]}
testCodecChange(t, p)
})
t.Run("Prefix-CidV1", func(t *testing.T) {
p := Prefix{Version: 1, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: mh.DefaultLengths[mh.SHA2_256]}
testCodecChange(t, p)
})
t.Run("V0Builder", func(t *testing.T) {
testCodecChange(t, V0Builder{})
})
t.Run("V1Builder", func(t *testing.T) {
testCodecChange(t, V1Builder{Codec: DagProtobuf, MhType: mh.SHA2_256})
})
}

func testCodecChange(t *testing.T, b Builder) {
data := []byte("this is some test content")

if b.GetCodec() != DagProtobuf {
t.Fatal("original builder not using Protobuf codec")
}

b = b.WithCodec(Raw)
c, err := b.Sum(data)
if err != nil {
t.Fatal(err)
}

if c.Type() != Raw {
t.Fatal("new cid codec did not change to Raw")
}
}
23 changes: 2 additions & 21 deletions cid.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,27 +144,6 @@ func NewCidV1(codecType uint64, mhash mh.Multihash) *Cid {
}
}

// NewPrefixV0 returns a CIDv0 prefix with the specified multihash type.
func NewPrefixV0(mhType uint64) Prefix {
return Prefix{
MhType: mhType,
MhLength: mh.DefaultLengths[mhType],
Version: 0,
Codec: DagProtobuf,
}
}

// NewPrefixV1 returns a CIDv1 prefix with the specified codec and multihash
// type.
func NewPrefixV1(codecType uint64, mhType uint64) Prefix {
return Prefix{
MhType: mhType,
MhLength: mh.DefaultLengths[mhType],
Version: 1,
Codec: codecType,
}
}

// Cid represents a self-describing content adressed
// identifier. It is formed by a Version, a Codec (which indicates
// a multicodec-packed content type) and a Multihash.
Expand Down Expand Up @@ -442,6 +421,8 @@ func (c *Cid) Prefix() Prefix {
// that is, the Version, the Codec, the Multihash type
// and the Multihash length. It does not contains
// any actual content information.
// NOTE: The use -1 in MhLength to mean default length is deprecated,
// use the V0Builder or V1Builder structures instead
type Prefix struct {
Version uint64
Codec uint64
Expand Down
28 changes: 28 additions & 0 deletions deprecated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cid

import (
mh "github.com/multiformats/go-multihash"
)

// NewPrefixV0 returns a CIDv0 prefix with the specified multihash type.
// DEPRECATED: Use V0Builder
func NewPrefixV0(mhType uint64) Prefix {
return Prefix{
MhType: mhType,
MhLength: mh.DefaultLengths[mhType],
Version: 0,
Codec: DagProtobuf,
}
}

// NewPrefixV1 returns a CIDv1 prefix with the specified codec and multihash
// type.
// DEPRECATED: Use V1Builder
func NewPrefixV1(codecType uint64, mhType uint64) Prefix {
return Prefix{
MhType: mhType,
MhLength: mh.DefaultLengths[mhType],
Version: 1,
Codec: codecType,
}
}