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
92 changes: 92 additions & 0 deletions builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
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
HashFun uint64
HashLen int // HashLen <= 0 means the default length
}

func PrefixToBuilder(p Prefix) Builder {
if p.Version == 0 {
return V0Builder{}
}
mhLen := p.MhLength
if p.MhType == mh.ID {
mhLen = 0
}
if mhLen < 0 {
mhLen = 0
}
return V1Builder{
Codec: p.Codec,
HashFun: p.MhType,
HashLen: mhLen,
}
}

func (p Prefix) GetCodec() uint64 {
Copy link
Member

Choose a reason for hiding this comment

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

If Prefix is going to implement Builder, PrefixToBuilder(p).Sum(...) should be functionally equivalent to p.Sum(...). My solution would be to just put the logic in PrefixToBuilder into Prefix.Sum but the alternative is to just call PrefixToBuilder in Sum (actually, that may just be the better solution).

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, HashFun: mh.SHA2_256}
}

func (p V1Builder) Sum(data []byte) (*Cid, error) {
mhLen := p.HashLen
if mhLen <= 0 {
mhLen = -1
}
hash, err := mh.Sum(data, p.HashFun, 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
}
57 changes: 57 additions & 0 deletions builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cid

import (
"testing"

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

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

// Construct c1
format := V1Builder{Codec: DagCBOR, HashFun: 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 TestFormatV0(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")
}
}
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 FormatV0
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 FormatV1
func NewPrefixV1(codecType uint64, mhType uint64) Prefix {
return Prefix{
MhType: mhType,
MhLength: mh.DefaultLengths[mhType],
Version: 1,
Codec: codecType,
}
}