@ -0,0 +1,27 @@ | |||||
Copyright (c) 2009,2014 Google Inc. All rights reserved. | |||||
Redistribution and use in source and binary forms, with or without | |||||
modification, are permitted provided that the following conditions are | |||||
met: | |||||
* Redistributions of source code must retain the above copyright | |||||
notice, this list of conditions and the following disclaimer. | |||||
* Redistributions in binary form must reproduce the above | |||||
copyright notice, this list of conditions and the following disclaimer | |||||
in the documentation and/or other materials provided with the | |||||
distribution. | |||||
* Neither the name of Google Inc. nor the names of its | |||||
contributors may be used to endorse or promote products derived from | |||||
this software without specific prior written permission. | |||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,84 @@ | |||||
// 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 ( | |||||
"encoding/binary" | |||||
"fmt" | |||||
"os" | |||||
) | |||||
// A Domain represents a Version 2 domain | |||||
type Domain byte | |||||
// Domain constants for DCE Security (Version 2) UUIDs. | |||||
const ( | |||||
Person = Domain(0) | |||||
Group = Domain(1) | |||||
Org = Domain(2) | |||||
) | |||||
// NewDCESecurity returns a DCE Security (Version 2) UUID. | |||||
// | |||||
// The domain should be one of Person, Group or Org. | |||||
// On a POSIX system the id should be the users UID for the Person | |||||
// domain and the users GID for the Group. The meaning of id for | |||||
// the domain Org or on non-POSIX systems is site defined. | |||||
// | |||||
// For a given domain/id pair the same token may be returned for up to | |||||
// 7 minutes and 10 seconds. | |||||
func NewDCESecurity(domain Domain, id uint32) UUID { | |||||
uuid := NewUUID() | |||||
if uuid != nil { | |||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 | |||||
uuid[9] = byte(domain) | |||||
binary.BigEndian.PutUint32(uuid[0:], id) | |||||
} | |||||
return uuid | |||||
} | |||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person | |||||
// domain with the id returned by os.Getuid. | |||||
// | |||||
// NewDCEPerson(Person, uint32(os.Getuid())) | |||||
func NewDCEPerson() UUID { | |||||
return NewDCESecurity(Person, uint32(os.Getuid())) | |||||
} | |||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group | |||||
// domain with the id returned by os.Getgid. | |||||
// | |||||
// NewDCEGroup(Group, uint32(os.Getgid())) | |||||
func NewDCEGroup() UUID { | |||||
return NewDCESecurity(Group, uint32(os.Getgid())) | |||||
} | |||||
// Domain returns the domain for a Version 2 UUID or false. | |||||
func (uuid UUID) Domain() (Domain, bool) { | |||||
if v, _ := uuid.Version(); v != 2 { | |||||
return 0, false | |||||
} | |||||
return Domain(uuid[9]), true | |||||
} | |||||
// Id returns the id for a Version 2 UUID or false. | |||||
func (uuid UUID) Id() (uint32, bool) { | |||||
if v, _ := uuid.Version(); v != 2 { | |||||
return 0, false | |||||
} | |||||
return binary.BigEndian.Uint32(uuid[0:4]), true | |||||
} | |||||
func (d Domain) String() string { | |||||
switch d { | |||||
case Person: | |||||
return "Person" | |||||
case Group: | |||||
return "Group" | |||||
case Org: | |||||
return "Org" | |||||
} | |||||
return fmt.Sprintf("Domain%d", int(d)) | |||||
} |
@ -0,0 +1,8 @@ | |||||
// 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. | |||||
// The uuid package generates and inspects UUIDs. | |||||
// | |||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. | |||||
package uuid |
@ -0,0 +1,53 @@ | |||||
// 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 ( | |||||
"crypto/md5" | |||||
"crypto/sha1" | |||||
"hash" | |||||
) | |||||
// Well known Name Space IDs and UUIDs | |||||
var ( | |||||
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") | |||||
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") | |||||
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") | |||||
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") | |||||
NIL = Parse("00000000-0000-0000-0000-000000000000") | |||||
) | |||||
// NewHash returns a new UUID dervied from the hash of space concatenated with | |||||
// data generated by h. The hash should be at least 16 byte in length. The | |||||
// first 16 bytes of the hash are used to form the UUID. The version of the | |||||
// UUID will be the lower 4 bits of version. NewHash is used to implement | |||||
// NewMD5 and NewSHA1. | |||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { | |||||
h.Reset() | |||||
h.Write(space) | |||||
h.Write([]byte(data)) | |||||
s := h.Sum(nil) | |||||
uuid := make([]byte, 16) | |||||
copy(uuid, s) | |||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) | |||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant | |||||
return uuid | |||||
} | |||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the | |||||
// supplied name space and data. | |||||
// | |||||
// NewHash(md5.New(), space, data, 3) | |||||
func NewMD5(space UUID, data []byte) UUID { | |||||
return NewHash(md5.New(), space, data, 3) | |||||
} | |||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the | |||||
// supplied name space and data. | |||||
// | |||||
// NewHash(sha1.New(), space, data, 5) | |||||
func NewSHA1(space UUID, data []byte) UUID { | |||||
return NewHash(sha1.New(), space, data, 5) | |||||
} |
@ -0,0 +1,30 @@ | |||||
// Copyright 2014 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 "errors" | |||||
func (u UUID) MarshalJSON() ([]byte, error) { | |||||
if len(u) == 0 { | |||||
return []byte(`""`), nil | |||||
} | |||||
return []byte(`"` + u.String() + `"`), nil | |||||
} | |||||
func (u *UUID) UnmarshalJSON(data []byte) error { | |||||
if len(data) == 0 || string(data) == `""` { | |||||
return nil | |||||
} | |||||
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { | |||||
return errors.New("invalid UUID format") | |||||
} | |||||
data = data[1 : len(data)-1] | |||||
uu := Parse(string(data)) | |||||
if uu == nil { | |||||
return errors.New("invalid UUID format") | |||||
} | |||||
*u = uu | |||||
return nil | |||||
} |
@ -0,0 +1,32 @@ | |||||
// Copyright 2014 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 ( | |||||
"encoding/json" | |||||
"reflect" | |||||
"testing" | |||||
) | |||||
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") | |||||
func TestJSON(t *testing.T) { | |||||
type S struct { | |||||
ID1 UUID | |||||
ID2 UUID | |||||
} | |||||
s1 := S{ID1: testUUID} | |||||
data, err := json.Marshal(&s1) | |||||
if err != nil { | |||||
t.Fatal(err) | |||||
} | |||||
var s2 S | |||||
if err := json.Unmarshal(data, &s2); err != nil { | |||||
t.Fatal(err) | |||||
} | |||||
if !reflect.DeepEqual(&s1, &s2) { | |||||
t.Errorf("got %#v, want %#v", s2, s1) | |||||
} | |||||
} |
@ -0,0 +1,101 @@ | |||||
// 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 "net" | |||||
var ( | |||||
interfaces []net.Interface // cached list of interfaces | |||||
ifname string // name of interface being used | |||||
nodeID []byte // hardware for version 1 UUIDs | |||||
) | |||||
// NodeInterface returns the name of the interface from which the NodeID was | |||||
// derived. The interface "user" is returned if the NodeID was set by | |||||
// SetNodeID. | |||||
func NodeInterface() string { | |||||
return ifname | |||||
} | |||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. | |||||
// If name is "" then the first usable interface found will be used or a random | |||||
// Node ID will be generated. If a named interface cannot be found then false | |||||
// is returned. | |||||
// | |||||
// SetNodeInterface never fails when name is "". | |||||
func SetNodeInterface(name string) bool { | |||||
if interfaces == nil { | |||||
var err error | |||||
interfaces, err = net.Interfaces() | |||||
if err != nil && name != "" { | |||||
return false | |||||
} | |||||
} | |||||
for _, ifs := range interfaces { | |||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { | |||||
if setNodeID(ifs.HardwareAddr) { | |||||
ifname = ifs.Name | |||||
return true | |||||
} | |||||
} | |||||
} | |||||
// We found no interfaces with a valid hardware address. If name | |||||
// does not specify a specific interface generate a random Node ID | |||||
// (section 4.1.6) | |||||
if name == "" { | |||||
if nodeID == nil { | |||||
nodeID = make([]byte, 6) | |||||
} | |||||
randomBits(nodeID) | |||||
return true | |||||
} | |||||
return false | |||||
} | |||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID | |||||
// if not already set. | |||||
func NodeID() []byte { | |||||
if nodeID == nil { | |||||
SetNodeInterface("") | |||||
} | |||||
nid := make([]byte, 6) | |||||
copy(nid, nodeID) | |||||
return nid | |||||
} | |||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes | |||||
// of id are used. If id is less than 6 bytes then false is returned and the | |||||
// Node ID is not set. | |||||
func SetNodeID(id []byte) bool { | |||||
if setNodeID(id) { | |||||
ifname = "user" | |||||
return true | |||||
} | |||||
return false | |||||
} | |||||
func setNodeID(id []byte) bool { | |||||
if len(id) < 6 { | |||||
return false | |||||
} | |||||
if nodeID == nil { | |||||
nodeID = make([]byte, 6) | |||||
} | |||||
copy(nodeID, id) | |||||
return true | |||||
} | |||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is | |||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. | |||||
func (uuid UUID) NodeID() []byte { | |||||
if len(uuid) != 16 { | |||||
return nil | |||||
} | |||||
node := make([]byte, 6) | |||||
copy(node, uuid[10:]) | |||||
return node | |||||
} |
@ -0,0 +1,66 @@ | |||||
// Copyright 2014 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 ( | |||||
"flag" | |||||
"runtime" | |||||
"testing" | |||||
"time" | |||||
) | |||||
// This test is only run when --regressions is passed on the go test line. | |||||
var regressions = flag.Bool("regressions", false, "run uuid regression tests") | |||||
// TestClockSeqRace tests for a particular race condition of returning two | |||||
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race | |||||
// condition, before being fixed, nearly always occured in under 30 seconds. | |||||
func TestClockSeqRace(t *testing.T) { | |||||
if !*regressions { | |||||
t.Skip("skipping regression tests") | |||||
} | |||||
duration := time.Minute | |||||
done := make(chan struct{}) | |||||
defer close(done) | |||||
ch := make(chan UUID, 10000) | |||||
ncpu := runtime.NumCPU() | |||||
switch ncpu { | |||||
case 0, 1: | |||||
// We can't run the test effectively. | |||||
t.Skip("skipping race test, only one CPU detected") | |||||
return | |||||
default: | |||||
runtime.GOMAXPROCS(ncpu) | |||||
} | |||||
for i := 0; i < ncpu; i++ { | |||||
go func() { | |||||
for { | |||||
select { | |||||
case <-done: | |||||
return | |||||
case ch <- NewUUID(): | |||||
} | |||||
} | |||||
}() | |||||
} | |||||
uuids := make(map[string]bool) | |||||
cnt := 0 | |||||
start := time.Now() | |||||
for u := range ch { | |||||
s := u.String() | |||||
if uuids[s] { | |||||
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s) | |||||
return | |||||
} | |||||
uuids[s] = true | |||||
if time.Since(start) > duration { | |||||
return | |||||
} | |||||
cnt++ | |||||
} | |||||
} |
@ -0,0 +1,132 @@ | |||||
// Copyright 2014 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 ( | |||||
"encoding/binary" | |||||
"sync" | |||||
"time" | |||||
) | |||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct | |||||
// 1582. | |||||
type Time int64 | |||||
const ( | |||||
lillian = 2299160 // Julian day of 15 Oct 1582 | |||||
unix = 2440587 // Julian day of 1 Jan 1970 | |||||
epoch = unix - lillian // Days between epochs | |||||
g1582 = epoch * 86400 // seconds between epochs | |||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs | |||||
) | |||||
var ( | |||||
mu sync.Mutex | |||||
lasttime uint64 // last time we returned | |||||
clock_seq uint16 // clock sequence for this run | |||||
timeNow = time.Now // for testing | |||||
) | |||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix | |||||
// epoch of 1 Jan 1970. | |||||
func (t Time) UnixTime() (sec, nsec int64) { | |||||
sec = int64(t - g1582ns100) | |||||
nsec = (sec % 10000000) * 100 | |||||
sec /= 10000000 | |||||
return sec, nsec | |||||
} | |||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and | |||||
// clock sequence as well as adjusting the clock sequence as needed. An error | |||||
// is returned if the current time cannot be determined. | |||||
func GetTime() (Time, uint16, error) { | |||||
defer mu.Unlock() | |||||
mu.Lock() | |||||
return getTime() | |||||
} | |||||
func getTime() (Time, uint16, error) { | |||||
t := timeNow() | |||||
// If we don't have a clock sequence already, set one. | |||||
if clock_seq == 0 { | |||||
setClockSequence(-1) | |||||
} | |||||
now := uint64(t.UnixNano()/100) + g1582ns100 | |||||
// If time has gone backwards with this clock sequence then we | |||||
// increment the clock sequence | |||||
if now <= lasttime { | |||||
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000 | |||||
} | |||||
lasttime = now | |||||
return Time(now), clock_seq, nil | |||||
} | |||||
// ClockSequence returns the current clock sequence, generating one if not | |||||
// already set. The clock sequence is only used for Version 1 UUIDs. | |||||
// | |||||
// The uuid package does not use global static storage for the clock sequence or | |||||
// the last time a UUID was generated. Unless SetClockSequence a new random | |||||
// clock sequence is generated the first time a clock sequence is requested by | |||||
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated | |||||
// for | |||||
func ClockSequence() int { | |||||
defer mu.Unlock() | |||||
mu.Lock() | |||||
return clockSequence() | |||||
} | |||||
func clockSequence() int { | |||||
if clock_seq == 0 { | |||||
setClockSequence(-1) | |||||
} | |||||
return int(clock_seq & 0x3fff) | |||||
} | |||||
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to | |||||
// -1 causes a new sequence to be generated. | |||||
func SetClockSequence(seq int) { | |||||
defer mu.Unlock() | |||||
mu.Lock() | |||||
setClockSequence(seq) | |||||
} | |||||
func setClockSequence(seq int) { | |||||
if seq == -1 { | |||||
var b [2]byte | |||||
randomBits(b[:]) // clock sequence | |||||
seq = int(b[0])<<8 | int(b[1]) | |||||
} | |||||
old_seq := clock_seq | |||||
clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant | |||||
if old_seq != clock_seq { | |||||
lasttime = 0 | |||||
} | |||||
} | |||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in | |||||
// uuid. It returns false if uuid is not valid. The time is only well defined | |||||
// for version 1 and 2 UUIDs. | |||||
func (uuid UUID) Time() (Time, bool) { | |||||
if len(uuid) != 16 { | |||||
return 0, false | |||||
} | |||||
time := int64(binary.BigEndian.Uint32(uuid[0:4])) | |||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 | |||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 | |||||
return Time(time), true | |||||
} | |||||
// ClockSequence returns the clock sequence encoded in uuid. It returns false | |||||
// if uuid is not valid. The clock sequence is only well defined for version 1 | |||||
// and 2 UUIDs. | |||||
func (uuid UUID) ClockSequence() (int, bool) { | |||||
if len(uuid) != 16 { | |||||
return 0, false | |||||
} | |||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true | |||||
} |
@ -0,0 +1,43 @@ | |||||
// 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 ( | |||||
"io" | |||||
) | |||||
// randomBits completely fills slice b with random data. | |||||
func randomBits(b []byte) { | |||||
if _, err := io.ReadFull(rander, b); err != nil { | |||||
panic(err.Error()) // rand should never fail | |||||
} | |||||
} | |||||
// xvalues returns the value of a byte as a hexadecimal digit or 255. | |||||
var xvalues = []byte{ | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, | |||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||||
} | |||||
// xtob converts the the first two hex bytes of x into a byte. | |||||
func xtob(x string) (byte, bool) { | |||||
b1 := xvalues[x[0]] | |||||
b2 := xvalues[x[1]] | |||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255 | |||||
} |
@ -0,0 +1,163 @@ | |||||
// 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 | |||||
} |
@ -0,0 +1,390 @@ | |||||
// 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" | |||||
"fmt" | |||||
"os" | |||||
"strings" | |||||
"testing" | |||||
"time" | |||||
) | |||||
type test struct { | |||||
in string | |||||
version Version | |||||
variant Variant | |||||
isuuid bool | |||||
} | |||||
var tests = []test{ | |||||
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, | |||||
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, | |||||
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, | |||||
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, | |||||
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, | |||||
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, | |||||
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, | |||||
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, | |||||
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, | |||||
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, | |||||
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, | |||||
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, | |||||
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, | |||||
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, | |||||
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, | |||||
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, | |||||
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, | |||||
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, | |||||
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, | |||||
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, | |||||
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, | |||||
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, | |||||
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, | |||||
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, | |||||
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, | |||||
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, | |||||
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, | |||||
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, | |||||
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, | |||||
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, | |||||
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, | |||||
} | |||||
var constants = []struct { | |||||
c interface{} | |||||
name string | |||||
}{ | |||||
{Person, "Person"}, | |||||
{Group, "Group"}, | |||||
{Org, "Org"}, | |||||
{Invalid, "Invalid"}, | |||||
{RFC4122, "RFC4122"}, | |||||
{Reserved, "Reserved"}, | |||||
{Microsoft, "Microsoft"}, | |||||
{Future, "Future"}, | |||||
{Domain(17), "Domain17"}, | |||||
{Variant(42), "BadVariant42"}, | |||||
} | |||||
func testTest(t *testing.T, in string, tt test) { | |||||
uuid := Parse(in) | |||||
if ok := (uuid != nil); ok != tt.isuuid { | |||||
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) | |||||
} | |||||
if uuid == nil { | |||||
return | |||||
} | |||||
if v := uuid.Variant(); v != tt.variant { | |||||
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) | |||||
} | |||||
if v, _ := uuid.Version(); v != tt.version { | |||||
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) | |||||
} | |||||
} | |||||
func TestUUID(t *testing.T) { | |||||
for _, tt := range tests { | |||||
testTest(t, tt.in, tt) | |||||
testTest(t, strings.ToUpper(tt.in), tt) | |||||
} | |||||
} | |||||
func TestConstants(t *testing.T) { | |||||
for x, tt := range constants { | |||||
v, ok := tt.c.(fmt.Stringer) | |||||
if !ok { | |||||
t.Errorf("%x: %v: not a stringer", x, v) | |||||
} else if s := v.String(); s != tt.name { | |||||
v, _ := tt.c.(int) | |||||
t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name) | |||||
} | |||||
} | |||||
} | |||||
func TestRandomUUID(t *testing.T) { | |||||
m := make(map[string]bool) | |||||
for x := 1; x < 32; x++ { | |||||
uuid := NewRandom() | |||||
s := uuid.String() | |||||
if m[s] { | |||||
t.Errorf("NewRandom returned duplicated UUID %s\n", s) | |||||
} | |||||
m[s] = true | |||||
if v, _ := uuid.Version(); v != 4 { | |||||
t.Errorf("Random UUID of version %s\n", v) | |||||
} | |||||
if uuid.Variant() != RFC4122 { | |||||
t.Errorf("Random UUID is variant %d\n", uuid.Variant()) | |||||
} | |||||
} | |||||
} | |||||
func TestNew(t *testing.T) { | |||||
m := make(map[string]bool) | |||||
for x := 1; x < 32; x++ { | |||||
s := New() | |||||
if m[s] { | |||||
t.Errorf("New returned duplicated UUID %s\n", s) | |||||
} | |||||
m[s] = true | |||||
uuid := Parse(s) | |||||
if uuid == nil { | |||||
t.Errorf("New returned %q which does not decode\n", s) | |||||
continue | |||||
} | |||||
if v, _ := uuid.Version(); v != 4 { | |||||
t.Errorf("Random UUID of version %s\n", v) | |||||
} | |||||
if uuid.Variant() != RFC4122 { | |||||
t.Errorf("Random UUID is variant %d\n", uuid.Variant()) | |||||
} | |||||
} | |||||
} | |||||
func clockSeq(t *testing.T, uuid UUID) int { | |||||
seq, ok := uuid.ClockSequence() | |||||
if !ok { | |||||
t.Fatalf("%s: invalid clock sequence\n", uuid) | |||||
} | |||||
return seq | |||||
} | |||||
func TestClockSeq(t *testing.T) { | |||||
// Fake time.Now for this test to return a monotonically advancing time; restore it at end. | |||||
defer func(orig func() time.Time) { timeNow = orig }(timeNow) | |||||
monTime := time.Now() | |||||
timeNow = func() time.Time { | |||||
monTime = monTime.Add(1 * time.Second) | |||||
return monTime | |||||
} | |||||
SetClockSequence(-1) | |||||
uuid1 := NewUUID() | |||||
uuid2 := NewUUID() | |||||
if clockSeq(t, uuid1) != clockSeq(t, uuid2) { | |||||
t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2)) | |||||
} | |||||
SetClockSequence(-1) | |||||
uuid2 = NewUUID() | |||||
// Just on the very off chance we generated the same sequence | |||||
// two times we try again. | |||||
if clockSeq(t, uuid1) == clockSeq(t, uuid2) { | |||||
SetClockSequence(-1) | |||||
uuid2 = NewUUID() | |||||
} | |||||
if clockSeq(t, uuid1) == clockSeq(t, uuid2) { | |||||
t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1)) | |||||
} | |||||
SetClockSequence(0x1234) | |||||
uuid1 = NewUUID() | |||||
if seq := clockSeq(t, uuid1); seq != 0x1234 { | |||||
t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq) | |||||
} | |||||
} | |||||
func TestCoding(t *testing.T) { | |||||
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" | |||||
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" | |||||
data := UUID{ | |||||
0x7d, 0x44, 0x48, 0x40, | |||||
0x9d, 0xc0, | |||||
0x11, 0xd1, | |||||
0xb2, 0x45, | |||||
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, | |||||
} | |||||
if v := data.String(); v != text { | |||||
t.Errorf("%x: encoded to %s, expected %s\n", data, v, text) | |||||
} | |||||
if v := data.URN(); v != urn { | |||||
t.Errorf("%x: urn is %s, expected %s\n", data, v, urn) | |||||
} | |||||
uuid := Parse(text) | |||||
if !Equal(uuid, data) { | |||||
t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data) | |||||
} | |||||
} | |||||
func TestVersion1(t *testing.T) { | |||||
uuid1 := NewUUID() | |||||
uuid2 := NewUUID() | |||||
if Equal(uuid1, uuid2) { | |||||
t.Errorf("%s:duplicate uuid\n", uuid1) | |||||
} | |||||
if v, _ := uuid1.Version(); v != 1 { | |||||
t.Errorf("%s: version %s expected 1\n", uuid1, v) | |||||
} | |||||
if v, _ := uuid2.Version(); v != 1 { | |||||
t.Errorf("%s: version %s expected 1\n", uuid2, v) | |||||
} | |||||
n1 := uuid1.NodeID() | |||||
n2 := uuid2.NodeID() | |||||
if !bytes.Equal(n1, n2) { | |||||
t.Errorf("Different nodes %x != %x\n", n1, n2) | |||||
} | |||||
t1, ok := uuid1.Time() | |||||
if !ok { | |||||
t.Errorf("%s: invalid time\n", uuid1) | |||||
} | |||||
t2, ok := uuid2.Time() | |||||
if !ok { | |||||
t.Errorf("%s: invalid time\n", uuid2) | |||||
} | |||||
q1, ok := uuid1.ClockSequence() | |||||
if !ok { | |||||
t.Errorf("%s: invalid clock sequence\n", uuid1) | |||||
} | |||||
q2, ok := uuid2.ClockSequence() | |||||
if !ok { | |||||
t.Errorf("%s: invalid clock sequence", uuid2) | |||||
} | |||||
switch { | |||||
case t1 == t2 && q1 == q2: | |||||
t.Errorf("time stopped\n") | |||||
case t1 > t2 && q1 == q2: | |||||
t.Errorf("time reversed\n") | |||||
case t1 < t2 && q1 != q2: | |||||
t.Errorf("clock sequence chaned unexpectedly\n") | |||||
} | |||||
} | |||||
func TestNodeAndTime(t *testing.T) { | |||||
// Time is February 5, 1998 12:30:23.136364800 AM GMT | |||||
uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") | |||||
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} | |||||
ts, ok := uuid.Time() | |||||
if ok { | |||||
c := time.Unix(ts.UnixTime()) | |||||
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) | |||||
if !c.Equal(want) { | |||||
t.Errorf("Got time %v, want %v", c, want) | |||||
} | |||||
} else { | |||||
t.Errorf("%s: bad time\n", uuid) | |||||
} | |||||
if !bytes.Equal(node, uuid.NodeID()) { | |||||
t.Errorf("Expected node %v got %v\n", node, uuid.NodeID()) | |||||
} | |||||
} | |||||
func TestMD5(t *testing.T) { | |||||
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String() | |||||
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" | |||||
if uuid != want { | |||||
t.Errorf("MD5: got %q expected %q\n", uuid, want) | |||||
} | |||||
} | |||||
func TestSHA1(t *testing.T) { | |||||
uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String() | |||||
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" | |||||
if uuid != want { | |||||
t.Errorf("SHA1: got %q expected %q\n", uuid, want) | |||||
} | |||||
} | |||||
func TestNodeID(t *testing.T) { | |||||
nid := []byte{1, 2, 3, 4, 5, 6} | |||||
SetNodeInterface("") | |||||
s := NodeInterface() | |||||
if s == "" || s == "user" { | |||||
t.Errorf("NodeInterface %q after SetInteface\n", s) | |||||
} | |||||
node1 := NodeID() | |||||
if node1 == nil { | |||||
t.Errorf("NodeID nil after SetNodeInterface\n", s) | |||||
} | |||||
SetNodeID(nid) | |||||
s = NodeInterface() | |||||
if s != "user" { | |||||
t.Errorf("Expected NodeInterface %q got %q\n", "user", s) | |||||
} | |||||
node2 := NodeID() | |||||
if node2 == nil { | |||||
t.Errorf("NodeID nil after SetNodeID\n", s) | |||||
} | |||||
if bytes.Equal(node1, node2) { | |||||
t.Errorf("NodeID not changed after SetNodeID\n", s) | |||||
} else if !bytes.Equal(nid, node2) { | |||||
t.Errorf("NodeID is %x, expected %x\n", node2, nid) | |||||
} | |||||
} | |||||
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) { | |||||
if uuid == nil { | |||||
t.Errorf("%s failed\n", name) | |||||
return | |||||
} | |||||
if v, _ := uuid.Version(); v != 2 { | |||||
t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v) | |||||
return | |||||
} | |||||
if v, ok := uuid.Domain(); !ok || v != domain { | |||||
if !ok { | |||||
t.Errorf("%s: %d: Domain failed\n", name, uuid) | |||||
} else { | |||||
t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v) | |||||
} | |||||
} | |||||
if v, ok := uuid.Id(); !ok || v != id { | |||||
if !ok { | |||||
t.Errorf("%s: %d: Id failed\n", name, uuid) | |||||
} else { | |||||
t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v) | |||||
} | |||||
} | |||||
} | |||||
func TestDCE(t *testing.T) { | |||||
testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678) | |||||
testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid())) | |||||
testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid())) | |||||
} | |||||
type badRand struct{} | |||||
func (r badRand) Read(buf []byte) (int, error) { | |||||
for i, _ := range buf { | |||||
buf[i] = byte(i) | |||||
} | |||||
return len(buf), nil | |||||
} | |||||
func TestBadRand(t *testing.T) { | |||||
SetRand(badRand{}) | |||||
uuid1 := New() | |||||
uuid2 := New() | |||||
if uuid1 != uuid2 { | |||||
t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2) | |||||
} | |||||
SetRand(nil) | |||||
uuid1 = New() | |||||
uuid2 = New() | |||||
if uuid1 == uuid2 { | |||||
t.Errorf("unexecpted duplicates, got %q\n", uuid1) | |||||
} | |||||
} |
@ -0,0 +1,41 @@ | |||||
// 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 ( | |||||
"encoding/binary" | |||||
) | |||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock | |||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID | |||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot | |||||
// be set NewUUID returns nil. If clock sequence has not been set by | |||||
// SetClockSequence then it will be set automatically. If GetTime fails to | |||||
// return the current NewUUID returns nil. | |||||
func NewUUID() UUID { | |||||
if nodeID == nil { | |||||
SetNodeInterface("") | |||||
} | |||||
now, seq, err := GetTime() | |||||
if err != nil { | |||||
return nil | |||||
} | |||||
uuid := make([]byte, 16) | |||||
time_low := uint32(now & 0xffffffff) | |||||
time_mid := uint16((now >> 32) & 0xffff) | |||||
time_hi := uint16((now >> 48) & 0x0fff) | |||||
time_hi |= 0x1000 // Version 1 | |||||
binary.BigEndian.PutUint32(uuid[0:], time_low) | |||||
binary.BigEndian.PutUint16(uuid[4:], time_mid) | |||||
binary.BigEndian.PutUint16(uuid[6:], time_hi) | |||||
binary.BigEndian.PutUint16(uuid[8:], seq) | |||||
copy(uuid[10:], nodeID) | |||||
return uuid | |||||
} |
@ -0,0 +1,25 @@ | |||||
// 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 | |||||
// Random returns a Random (Version 4) UUID or panics. | |||||
// | |||||
// The strength of the UUIDs is based on the strength of the crypto/rand | |||||
// package. | |||||
// | |||||
// A note about uniqueness derived from from the UUID Wikipedia entry: | |||||
// | |||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being | |||||
// hit by a meteorite is estimated to be one chance in 17 billion, that | |||||
// means the probability is about 0.00000000006 (6 × 10−11), | |||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a | |||||
// year and having one duplicate. | |||||
func NewRandom() UUID { | |||||
uuid := make([]byte, 16) | |||||
randomBits([]byte(uuid)) | |||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 | |||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 | |||||
return uuid | |||||
} |