| // 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" |
| "fmt" |
| "io" |
| "strings" |
| ) |
| |
| // 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 |
| } |
| uuid := make([]byte, 16) |
| for i, x := range []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) |
| } |
| |
| // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| // , or "" if uuid is invalid. |
| func (uuid UUID) String() string { |
| if uuid == nil || len(uuid) != 16 { |
| return "" |
| } |
| b := []byte(uuid) |
| return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", |
| b[:4], b[4:6], b[6:8], b[8:10], b[10:]) |
| } |
| |
| // 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 uuid == nil || len(uuid) != 16 { |
| return "" |
| } |
| b := []byte(uuid) |
| return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x", |
| b[:4], b[4:6], b[6:8], b[8:10], b[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 |
| } |
| panic("unreachable") |
| } |
| |
| // Version returns the verison 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 implents 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 |
| } |