From ec4af83d19f89c2ea68ac4a948d2cb394a713444 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 23 Aug 2013 13:30:18 -0500 Subject: [PATCH] pkg/blob: implement Go 1.2's encoding.BinaryMarshaler Change-Id: Ic9fbbd4cdd99fbf19ed2467f9fc151c688ec048f --- pkg/blob/ref.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ pkg/blob/ref_test.go | 19 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pkg/blob/ref.go b/pkg/blob/ref.go index e1e8ad564..14ebd487a 100644 --- a/pkg/blob/ref.go +++ b/pkg/blob/ref.go @@ -20,6 +20,7 @@ package blob import ( "bytes" "crypto/sha1" + "errors" "fmt" "hash" "reflect" @@ -366,6 +367,9 @@ func ValidRefString(s string) bool { } func (r *Ref) UnmarshalJSON(d []byte) error { + if r.digest != nil { + return errors.New("Can't UnmarshalJSON into a non-zero Ref") + } if len(d) < 2 || d[0] != '"' || d[len(d)-1] != '"' { return fmt.Errorf("blob: expecting a JSON string to unmarshal, got %q", d) } @@ -382,3 +386,43 @@ func (r Ref) MarshalJSON() ([]byte, error) { // TODO: do just one allocation here if we cared. return []byte(fmt.Sprintf("%q", r.String())), nil } + +// MarshalBinary implements Go's encoding.BinaryMarshaler interface. +func (r Ref) MarshalBinary() (data []byte, err error) { + dname := r.digest.digestName() + bs := r.digest.bytes() + data = make([]byte, 0, len(dname)+1+len(bs)) + data = append(data, dname...) + data = append(data, '-') + data = append(data, bs...) + return +} + +// UnmarshalBinary implements Go's encoding.BinaryUnmarshaler interface. +func (r *Ref) UnmarshalBinary(data []byte) error { + if r.digest != nil { + return errors.New("Can't UnmarshalBinary into a non-zero Ref") + } + i := bytes.IndexByte(data, '-') + if i < 1 { + return errors.New("no digest name") + } + + digName := string(data[:i]) + buf := data[i+1:] + + meta, ok := metaFromString[digName] + if !ok { + r2, ok := parseUnknown(digName, fmt.Sprintf("%x", buf)) + if !ok { + return errors.New("invalid blobref binary data") + } + *r = r2 + return nil + } + if len(buf) != meta.size { + return errors.New("wrong size of data for digest " + digName) + } + r.digest = meta.ctor(buf) + return nil +} diff --git a/pkg/blob/ref_test.go b/pkg/blob/ref_test.go index 8adf34da1..20a6ab259 100644 --- a/pkg/blob/ref_test.go +++ b/pkg/blob/ref_test.go @@ -140,3 +140,22 @@ func TestSizedBlobRefString(t *testing.T) { t.Errorf("SizedRef.String() = %q, want %q", got, want) } } + +func TestMarshalBinary(t *testing.T) { + br := MustParse("abc-00ff4869") + data, _ := br.MarshalBinary() + if got, want := string(data), "abc-\x00\xffHi"; got != want { + t.Fatalf("MarshalBinary = %q; want %q", got, want) + } + br2 := new(Ref) + if err := br2.UnmarshalBinary(data); err != nil { + t.Fatal(err) + } + if *br2 != br { + t.Error("UnmarshalBinary result != original") + } + + if err := br2.UnmarshalBinary(data); err == nil { + t.Error("expect error on second UnmarshalBinary") + } +}