| // Copyright 2011 Google Inc. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package uuid |
| |
| import ( |
| "bytes" |
| "crypto/rand" |
| "encoding/hex" |
| "fmt" |
| "io" |
| "strings" |
| ) |
| |
| // Array is a pass-by-value UUID that can be used as an effecient key in a map. |
| type Array [16]byte |
| |
| // UUID converts uuid into a slice. |
| func (uuid Array) UUID() UUID { |
| return uuid[:] |
| } |
| |
| // String returns the string representation of uuid, |
| // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. |
| func (uuid Array) String() string { |
| return uuid.UUID().String() |
| } |
| |
| // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC |
| // 4122. |
| type UUID []byte |
| |
| // A Version represents a UUIDs version. |
| type Version byte |
| |
| // A Variant represents a UUIDs variant. |
| type Variant byte |
| |
| // Constants returned by Variant. |
| const ( |
| Invalid = Variant(iota) // Invalid UUID |
| RFC4122 // The variant specified in RFC4122 |
| Reserved // Reserved, NCS backward compatibility. |
| Microsoft // Reserved, Microsoft Corporation backward compatibility. |
| Future // Reserved for future definition. |
| ) |
| |
| var rander = rand.Reader // random function |
| |
| // New returns a new random (version 4) UUID as a string. It is a convenience |
| // function for NewRandom().String(). |
| func New() string { |
| return NewRandom().String() |
| } |
| |
| // Parse decodes s into a UUID or returns nil. Both the UUID form of |
| // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and |
| // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. |
| func Parse(s string) UUID { |
| if len(s) == 36+9 { |
| if strings.ToLower(s[:9]) != "urn:uuid:" { |
| return nil |
| } |
| s = s[9:] |
| } else if len(s) != 36 { |
| return nil |
| } |
| if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { |
| return nil |
| } |
| var uuid [16]byte |
| for i, x := range [16]int{ |
| 0, 2, 4, 6, |
| 9, 11, |
| 14, 16, |
| 19, 21, |
| 24, 26, 28, 30, 32, 34} { |
| if v, ok := xtob(s[x:]); !ok { |
| return nil |
| } else { |
| uuid[i] = v |
| } |
| } |
| return uuid[:] |
| } |
| |
| // Equal returns true if uuid1 and uuid2 are equal. |
| func Equal(uuid1, uuid2 UUID) bool { |
| return bytes.Equal(uuid1, uuid2) |
| } |
| |
| // Array returns an array representation of uuid that can be used as a map key. |
| // Array panics if uuid is not valid. |
| func (uuid UUID) Array() Array { |
| if len(uuid) != 16 { |
| panic("invalid uuid") |
| } |
| var a Array |
| copy(a[:], uuid) |
| return a |
| } |
| |
| // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| // , or "" if uuid is invalid. |
| func (uuid UUID) String() string { |
| if len(uuid) != 16 { |
| return "" |
| } |
| var buf [36]byte |
| encodeHex(buf[:], uuid) |
| return string(buf[:]) |
| } |
| |
| // URN returns the RFC 2141 URN form of uuid, |
| // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. |
| func (uuid UUID) URN() string { |
| if len(uuid) != 16 { |
| return "" |
| } |
| var buf [36 + 9]byte |
| copy(buf[:], "urn:uuid:") |
| encodeHex(buf[9:], uuid) |
| return string(buf[:]) |
| } |
| |
| func encodeHex(dst []byte, uuid UUID) { |
| hex.Encode(dst[:], uuid[:4]) |
| dst[8] = '-' |
| hex.Encode(dst[9:13], uuid[4:6]) |
| dst[13] = '-' |
| hex.Encode(dst[14:18], uuid[6:8]) |
| dst[18] = '-' |
| hex.Encode(dst[19:23], uuid[8:10]) |
| dst[23] = '-' |
| hex.Encode(dst[24:], uuid[10:]) |
| } |
| |
| // Variant returns the variant encoded in uuid. It returns Invalid if |
| // uuid is invalid. |
| func (uuid UUID) Variant() Variant { |
| if len(uuid) != 16 { |
| return Invalid |
| } |
| switch { |
| case (uuid[8] & 0xc0) == 0x80: |
| return RFC4122 |
| case (uuid[8] & 0xe0) == 0xc0: |
| return Microsoft |
| case (uuid[8] & 0xe0) == 0xe0: |
| return Future |
| default: |
| return Reserved |
| } |
| } |
| |
| // Version returns the version of uuid. It returns false if uuid is not |
| // valid. |
| func (uuid UUID) Version() (Version, bool) { |
| if len(uuid) != 16 { |
| return 0, false |
| } |
| return Version(uuid[6] >> 4), true |
| } |
| |
| func (v Version) String() string { |
| if v > 15 { |
| return fmt.Sprintf("BAD_VERSION_%d", v) |
| } |
| return fmt.Sprintf("VERSION_%d", v) |
| } |
| |
| func (v Variant) String() string { |
| switch v { |
| case RFC4122: |
| return "RFC4122" |
| case Reserved: |
| return "Reserved" |
| case Microsoft: |
| return "Microsoft" |
| case Future: |
| return "Future" |
| case Invalid: |
| return "Invalid" |
| } |
| return fmt.Sprintf("BadVariant%d", int(v)) |
| } |
| |
| // SetRand sets the random number generator to r, which implements io.Reader. |
| // If r.Read returns an error when the package requests random data then |
| // a panic will be issued. |
| // |
| // Calling SetRand with nil sets the random number generator to the default |
| // generator. |
| func SetRand(r io.Reader) { |
| if r == nil { |
| rander = rand.Reader |
| return |
| } |
| rander = r |
| } |