diff --git a/cid.go b/cid.go index 2cfdb1b..786dbf9 100644 --- a/cid.go +++ b/cid.go @@ -159,7 +159,7 @@ func NewCidV1(codecType uint64, mhash mh.Multihash) Cid { // - version uvarint // - codec uvarint // - hash mh.Multihash -type Cid struct{ string } +type Cid struct{ str string } var Nil = Cid{} @@ -296,7 +296,7 @@ func Cast(data []byte) (Cid, error) { // Version returns the Cid version. func (c Cid) Version() uint64 { - if len(c.string) == 34 && c.string[0] == 18 && c.string[1] == 32 { + if len(c.str) == 34 && c.str[0] == 18 && c.str[1] == 32 { return 0 } return 1 @@ -307,9 +307,8 @@ func (c Cid) Type() uint64 { if c.Version() == 0 { return DagProtobuf } - bytes := c.Bytes() - _, n := binary.Uvarint(bytes) - codec, _ := binary.Uvarint(bytes[n:]) + _, n := uvarint(c.str) + codec, _ := uvarint(c.str[n:]) return codec } @@ -382,7 +381,7 @@ func (c Cid) Hash() mh.Multihash { // The output of bytes can be parsed back into a Cid // with Cast(). func (c Cid) Bytes() []byte { - return []byte(c.string) + return []byte(c.str) } // Equals checks that two Cids are the same. @@ -431,7 +430,7 @@ func (c Cid) MarshalJSON() ([]byte, error) { // KeyString returns the binary representation of the Cid as a string func (c Cid) KeyString() string { - return c.string + return c.str } // Loggable returns a Loggable (as defined by diff --git a/varint.go b/varint.go new file mode 100644 index 0000000..391c1f4 --- /dev/null +++ b/varint.go @@ -0,0 +1,34 @@ +package cid + +// Version of varint function that work with a string rather than +// []byte to avoid unnecessary allocation + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license as given at https://golang.org/LICENSE + +// uvarint decodes a uint64 from buf and returns that value and the +// number of characters read (> 0). If an error occurred, the value is 0 +// and the number of bytes n is <= 0 meaning: +// +// n == 0: buf too small +// n < 0: value larger than 64 bits (overflow) +// and -n is the number of bytes read +// +func uvarint(buf string) (uint64, int) { + var x uint64 + var s uint + // we have a binary string so we can't use a range loope + for i := 0; i < len(buf); i++ { + b := buf[i] + if b < 0x80 { + if i > 9 || i == 9 && b > 1 { + return 0, -(i + 1) // overflow + } + return x | uint64(b)<