Skip to content

Commit

Permalink
Merge pull request #103 from thaJeztah/perf_and_shadow_nits
Browse files Browse the repository at this point in the history
address some linting issues, and small refactor, performance optimizations
  • Loading branch information
dmcgowan authored Jan 15, 2025
2 parents 22b78e4 + 247c259 commit 8ab41e4
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 42 deletions.
26 changes: 12 additions & 14 deletions algorithm.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,14 @@ func RegisterAlgorithm(algorithm Algorithm, implementation CryptoHash) bool {
algorithmsLock.Lock()
defer algorithmsLock.Unlock()

if !algorithmRegexp.MatchString(string(algorithm)) {
panic(fmt.Sprintf("Algorithm %s has a name which does not fit within the allowed grammar", algorithm))
}

if _, ok := algorithms[algorithm]; ok {
return false
}

if !algorithmRegexp.MatchString(string(algorithm)) {
panic(fmt.Sprintf("Algorithm %s has a name which does not fit within the allowed grammar", algorithm))
}

algorithms[algorithm] = implementation
// We can do this since the Digest function below only implements a hex digest. If we open this in the future
// we need to allow for alternative digest algorithms to be implemented and for the user to pass their own
Expand All @@ -156,8 +156,8 @@ func RegisterAlgorithm(algorithm Algorithm, implementation CryptoHash) bool {

// hexDigestRegex can be used to generate a regex for RegisterAlgorithm.
func hexDigestRegex(cryptoHash CryptoHash) *regexp.Regexp {
hexdigestbytes := cryptoHash.Size() * 2
return regexp.MustCompile(fmt.Sprintf("^[a-f0-9]{%d}$", hexdigestbytes))
hexDigestBytes := cryptoHash.Size() * 2
return regexp.MustCompile(fmt.Sprintf("^[a-f0-9]{%d}$", hexDigestBytes))
}

// Available returns true if the digest type is available for use. If this
Expand Down Expand Up @@ -254,20 +254,18 @@ func (a Algorithm) Encode(d []byte) string {

// FromReader returns the digest of the reader using the algorithm.
func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
digester := a.Digester()

if _, err := io.Copy(digester.Hash(), rd); err != nil {
d := a.Digester()
if _, err := io.Copy(d.Hash(), rd); err != nil {
return "", err
}

return digester.Digest(), nil
return d.Digest(), nil
}

// FromBytes digests the input and returns a Digest.
func (a Algorithm) FromBytes(p []byte) Digest {
digester := a.Digester()

if _, err := digester.Hash().Write(p); err != nil {
d := a.Digester()
if _, err := d.Hash().Write(p); err != nil {
// Writes to a Hash should never fail. None of the existing
// hash implementations in the stdlib or hashes vendored
// here can return errors from Write. Having a panic in this
Expand All @@ -276,7 +274,7 @@ func (a Algorithm) FromBytes(p []byte) Digest {
panic("write to hash function returned error: " + err.Error())
}

return digester.Digest()
return d.Digest()
}

// FromString digests the string input and returns a Digest.
Expand Down
3 changes: 2 additions & 1 deletion algorithm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"bytes"
"crypto"
"crypto/rand"
"errors"
"flag"
"fmt"
"strings"
Expand Down Expand Up @@ -56,7 +57,7 @@ func TestFlagInterface(t *testing.T) {
} {
t.Run(testcase.Name, func(t *testing.T) {
alg = Canonical
if err := flagSet.Parse(testcase.Args); err != testcase.Err {
if err := flagSet.Parse(testcase.Args); !errors.Is(err, testcase.Err) {
if testcase.Err == nil {
t.Fatal("unexpected error", err)
}
Expand Down
13 changes: 7 additions & 6 deletions digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package digest

import (
"errors"
"fmt"
"hash"
"io"
Expand Down Expand Up @@ -46,19 +47,19 @@ func NewDigest(alg Algorithm, h hash.Hash) Digest {
// functions. This is also useful for rebuilding digests from binary
// serializations.
func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
return NewDigestFromEncoded(alg, alg.Encode(p))
return Digest(string(alg) + ":" + alg.Encode(p))
}

// NewDigestFromHex returns a Digest from alg and the hex encoded digest.
//
// Deprecated: use [NewDigestFromEncoded] instead.
func NewDigestFromHex(alg, hex string) Digest {
return NewDigestFromEncoded(Algorithm(alg), hex)
return Digest(alg + ":" + hex)
}

// NewDigestFromEncoded returns a Digest from alg and the encoded digest.
func NewDigestFromEncoded(alg Algorithm, encoded string) Digest {
return Digest(fmt.Sprintf("%s:%s", alg, encoded))
return Digest(string(alg) + ":" + encoded)
}

// DigestRegexp matches valid digest types.
Expand All @@ -69,13 +70,13 @@ var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)

var (
// ErrDigestInvalidFormat returned when digest format invalid.
ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
ErrDigestInvalidFormat = errors.New("invalid checksum digest format")

// ErrDigestInvalidLength returned when digest has invalid length.
ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
ErrDigestInvalidLength = errors.New("invalid checksum digest length")

// ErrDigestUnsupported returned when the digest algorithm is unsupported.
ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
ErrDigestUnsupported = errors.New("unsupported digest algorithm")
)

// Parse parses s and returns the validated digest object. An error will
Expand Down
19 changes: 19 additions & 0 deletions digest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package digest_test

import (
"crypto/sha256"
"testing"

"github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -118,3 +119,21 @@ func TestParseDigest(t *testing.T) {
})
}
}

func BenchmarkNewDigestFromEncoded(b *testing.B) {
b.ReportAllocs()

for i := 0; i < b.N; i++ {
_ = digest.NewDigestFromEncoded("sha256", "e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b")
}
}

func BenchmarkNewDigestFromBytes(b *testing.B) {
s := sha256.Sum256([]byte("hello world"))

b.ReportAllocs()

for i := 0; i < b.N; i++ {
_ = digest.NewDigestFromBytes("sha256", s[:])
}
}
4 changes: 2 additions & 2 deletions digestset/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"strings"
"sync"

digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
)

var (
Expand Down Expand Up @@ -93,7 +93,7 @@ func (dst *Set) Lookup(d string) (digest.Digest, error) {
hex string
)
dgst, err := digest.Parse(d)
if err == digest.ErrDigestInvalidFormat {
if errors.Is(err, digest.ErrDigestInvalidFormat) {
hex = d
searchFunc = func(i int) bool {
return dst.entries[i].val >= d
Expand Down
6 changes: 5 additions & 1 deletion digestset/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"math/rand"
"testing"

digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
)

func assertEqualDigests(t *testing.T, d1, d2 digest.Digest) {
Expand Down Expand Up @@ -257,6 +257,7 @@ func createDigests(count int) ([]digest.Digest, error) {
}

func benchAddNTable(b *testing.B, n int) {
b.ReportAllocs()
digests, err := createDigests(n)
if err != nil {
b.Fatal(err)
Expand All @@ -273,6 +274,7 @@ func benchAddNTable(b *testing.B, n int) {
}

func benchLookupNTable(b *testing.B, n int, shortLen int) {
b.ReportAllocs()
digests, err := createDigests(n)
if err != nil {
b.Fatal(err)
Expand All @@ -297,6 +299,7 @@ func benchLookupNTable(b *testing.B, n int, shortLen int) {
}

func benchRemoveNTable(b *testing.B, n int) {
b.ReportAllocs()
digests, err := createDigests(n)
if err != nil {
b.Fatal(err)
Expand All @@ -320,6 +323,7 @@ func benchRemoveNTable(b *testing.B, n int) {
}

func benchShortCodeNTable(b *testing.B, n int, shortLen int) {
b.ReportAllocs()
digests, err := createDigests(n)
if err != nil {
b.Fatal(err)
Expand Down
37 changes: 19 additions & 18 deletions testdigest/testdigest.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// testdigest is a separate package, because it has some testing utilities in it that may be useful
// to other internal Algorithm implementors.
// Package testdigest is a separate package, because it has some testing
// utilities that may be useful to other internal Algorithm implementors.
//
// It is not a stable interface and not meant for consumption outside of digest developers.

// It is not a stable interface and not meant for consumption outside of
// digest developers.
package testdigest

import (
"errors"
"testing"

pkgdigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
)

type TestCase struct {
Expand All @@ -31,41 +32,41 @@ type TestCase struct {
// If err is non-nil, then the parsing of Input is expected to return this error
Err error
// Algorithm should be an available or registered algorithm
Algorithm pkgdigest.Algorithm
Algorithm digest.Algorithm
// Encoded is the the encoded portion of the digest to expect, for example e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b
Encoded string
}

func RunTestCase(t *testing.T, testcase TestCase) {
digest, err := pkgdigest.Parse(testcase.Input)
if err != testcase.Err {
dgst, err := digest.Parse(testcase.Input)
if !errors.Is(err, testcase.Err) {
t.Fatalf("error differed from expected while parsing %q: %v != %v", testcase.Input, err, testcase.Err)
}

if testcase.Err != nil {
return
}

if digest.Algorithm() != testcase.Algorithm {
t.Fatalf("incorrect Algorithm for parsed digest: %q != %q", digest.Algorithm(), testcase.Algorithm)
if dgst.Algorithm() != testcase.Algorithm {
t.Fatalf("incorrect Algorithm for parsed digest: %q != %q", dgst.Algorithm(), testcase.Algorithm)
}

if digest.Encoded() != testcase.Encoded {
t.Fatalf("incorrect hex for parsed digest: %q != %q", digest.Encoded(), testcase.Encoded)
if dgst.Encoded() != testcase.Encoded {
t.Fatalf("incorrect hex for parsed digest: %q != %q", dgst.Encoded(), testcase.Encoded)
}

// Parse string return value and check equality
newParsed, err := pkgdigest.Parse(digest.String())
newParsed, err := digest.Parse(dgst.String())
if err != nil {
t.Fatalf("unexpected error parsing Input %q: %v", testcase.Input, err)
}

if newParsed != digest {
t.Fatalf("expected equal: %q != %q", newParsed, digest)
if newParsed != dgst {
t.Fatalf("expected equal: %q != %q", newParsed, dgst)
}

newFromHex := pkgdigest.NewDigestFromEncoded(newParsed.Algorithm(), newParsed.Encoded())
if newFromHex != digest {
t.Fatalf("%v != %v", newFromHex, digest)
newFromHex := digest.NewDigestFromEncoded(newParsed.Algorithm(), newParsed.Encoded())
if newFromHex != dgst {
t.Fatalf("%v != %v", newFromHex, dgst)
}
}

0 comments on commit 8ab41e4

Please sign in to comment.