mcrypto: change UUID implementation to keep inner data as []byte instead of string

This commit is contained in:
Brian Picciano 2018-03-23 15:56:27 +00:00
parent 02a4cf7c30
commit d4c665c4d5

View File

@ -7,7 +7,6 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"time" "time"
"github.com/mediocregopher/mediocre-go-lib/mlog" "github.com/mediocregopher/mediocre-go-lib/mlog"
@ -25,11 +24,7 @@ var errMalformedUUID = errors.New("malformed UUID string")
// The string form of UUIDs (returned by String or MarshalText) are // The string form of UUIDs (returned by String or MarshalText) are
// lexigraphically order-able by their embedded timestamp. // lexigraphically order-able by their embedded timestamp.
type UUID struct { type UUID struct {
// the UUID type is actually just an opaque wrapper. For the most part b []byte
// UUID's don't ever need the information in them (like their timestamp)
// unpacked, so it's more efficient to just keep the string and unpack
// on-the-fly
str string
} }
// NewUUID populates and returns a new UUID instance which embeds the given time // NewUUID populates and returns a new UUID instance which embeds the given time
@ -39,28 +34,21 @@ func NewUUID(t time.Time) UUID {
if _, err := rand.Read(b[8:]); err != nil { if _, err := rand.Read(b[8:]); err != nil {
panic(err) panic(err)
} }
return UUID{ return UUID{b: b}
str: uuidV0 + hex.EncodeToString(b),
}
} }
func (u UUID) String() string { func (u UUID) String() string {
return u.str return uuidV0 + hex.EncodeToString(u.b)
} }
// Equal returns whether or not the two UUID's are the same value // Equal returns whether or not the two UUID's are the same value
func (u UUID) Equal(u2 UUID) bool { func (u UUID) Equal(u2 UUID) bool {
return u.str == u2.str return bytes.Equal(u.b, u2.b)
} }
// Time unpacks and returns the timestamp embedded in the UUID // Time unpacks and returns the timestamp embedded in the UUID
func (u UUID) Time() time.Time { func (u UUID) Time() time.Time {
b, err := hex.DecodeString(u.str[2:]) unixNano := int64(binary.BigEndian.Uint64(u.b[:8]))
if err != nil {
// once a UUID has been created it should always be valid
panic(fmt.Sprintf("malformed UUID: %q", u.str))
}
unixNano := int64(binary.BigEndian.Uint64(b[:8]))
return time.Unix(0, unixNano).Local() return time.Unix(0, unixNano).Local()
} }
@ -77,10 +65,16 @@ func (u UUID) MarshalText() ([]byte, error) {
// UnmarshalText implements the method for the encoding.TextUnmarshaler // UnmarshalText implements the method for the encoding.TextUnmarshaler
// interface // interface
func (u *UUID) UnmarshalText(b []byte) error { func (u *UUID) UnmarshalText(b []byte) error {
if !bytes.HasPrefix(b, []byte(uuidV0)) || len(b) != len(uuidV0)+32 { str := string(b)
return mlog.ErrWithKV(errMalformedUUID, mlog.KV{"uuidStr": string(b)}) strEnc, ok := stripPrefix(str, uuidV0)
if !ok || len(strEnc) != hex.EncodedLen(16) {
return mlog.ErrWithKV(errMalformedUUID, mlog.KV{"uuidStr": str})
} }
u.str = string(b) b, err := hex.DecodeString(strEnc)
if err != nil {
return mlog.ErrWithKV(err, mlog.KV{"uuidStr": str})
}
u.b = b
return nil return nil
} }