diff --git a/builder.go b/builder.go new file mode 100644 index 0000000..af33aac --- /dev/null +++ b/builder.go @@ -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 { + 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 +} diff --git a/builder_test.go b/builder_test.go new file mode 100644 index 0000000..dc6f35c --- /dev/null +++ b/builder_test.go @@ -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") + } +} diff --git a/cid.go b/cid.go index 99a26a6..4c91344 100644 --- a/cid.go +++ b/cid.go @@ -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. @@ -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 diff --git a/deprecated.go b/deprecated.go new file mode 100644 index 0000000..cd889f9 --- /dev/null +++ b/deprecated.go @@ -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, + } +}