├── .github ├── CODEOWNERS ├── release-please.yml └── workflows │ ├── apidiff.yaml │ └── tests.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── CONTRIBUTORS ├── LICENSE ├── README.md ├── dce.go ├── doc.go ├── go.mod ├── hash.go ├── json_test.go ├── marshal.go ├── node.go ├── node_js.go ├── node_net.go ├── null.go ├── null_test.go ├── seq_test.go ├── sql.go ├── sql_test.go ├── time.go ├── time_test.go ├── util.go ├── uuid.go ├── uuid_test.go ├── version1.go ├── version4.go ├── version6.go ├── version6_test.go └── version7.go /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Code owners file. 2 | # This file controls who is tagged for review for any given pull request. 3 | 4 | # For syntax help see: 5 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax 6 | * @google/go-uuid-contributors 7 | -------------------------------------------------------------------------------- /.github/release-please.yml: -------------------------------------------------------------------------------- 1 | handleGHRelease: true 2 | releaseType: go 3 | -------------------------------------------------------------------------------- /.github/workflows/apidiff.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: apidiff 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | permissions: 8 | contents: read 9 | jobs: 10 | compat: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/setup-go@v4 14 | with: 15 | go-version: 1.21 16 | - run: go install golang.org/x/exp/cmd/apidiff@latest 17 | - uses: actions/checkout@v3 18 | with: 19 | ref: master 20 | - run: apidiff -w uuid.baseline . 21 | - uses: actions/checkout@v3 22 | with: 23 | clean: false 24 | - run: | 25 | apidiff -incompatible uuid.baseline . > diff.txt 26 | cat diff.txt && ! [ -s diff.txt ] 27 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: tests 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | permissions: 8 | contents: read 9 | jobs: 10 | unit-tests: 11 | strategy: 12 | matrix: 13 | go-version: [1.19, 1.20.x, 1.21] 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: actions/setup-go@v4 18 | with: 19 | go-version: ${{ matrix.go-version }} 20 | - run: go test -v ./... 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) 4 | 5 | 6 | ### Features 7 | 8 | * add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) 14 | * Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) 15 | 16 | ## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) 17 | 18 | 19 | ### Features 20 | 21 | * Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) 22 | 23 | ## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) 24 | 25 | 26 | ### Features 27 | 28 | * UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) 29 | 30 | ### Fixes 31 | 32 | * Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) 33 | 34 | ## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) 40 | 41 | ## Changelog 42 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We definitely welcome patches and contribution to this project! 4 | 5 | ### Tips 6 | 7 | Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). 8 | 9 | Always try to include a test case! If it is not possible or not necessary, 10 | please explain why in the pull request description. 11 | 12 | ### Releasing 13 | 14 | Commits that would precipitate a SemVer change, as described in the Conventional 15 | Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) 16 | to create a release candidate pull request. Once submitted, `release-please` 17 | will create a release. 18 | 19 | For tips on how to work with `release-please`, see its documentation. 20 | 21 | ### Legal requirements 22 | 23 | In order to protect both you and ourselves, you will need to sign the 24 | [Contributor License Agreement](https://cla.developers.google.com/clas). 25 | 26 | You may have already signed it for other Google projects. 27 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Paul Borman 2 | bmatsuo 3 | shawnps 4 | theory 5 | jboverfelt 6 | dsymonds 7 | cd1 8 | wallclockbuilder 9 | dansouza 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009,2014 Google Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uuid 2 | The uuid package generates and inspects UUIDs based on 3 | [RFC 9562](https://datatracker.ietf.org/doc/html/rfc9562) 4 | and DCE 1.1: Authentication and Security Services. 5 | 6 | This package is based on the github.com/pborman/uuid package (previously named 7 | code.google.com/p/go-uuid). It differs from these earlier packages in that 8 | a UUID is a 16 byte array rather than a byte slice. One loss due to this 9 | change is the ability to represent an invalid UUID (vs a NIL UUID). 10 | 11 | ###### Install 12 | ```sh 13 | go get github.com/google/uuid 14 | ``` 15 | 16 | ###### Documentation 17 | [![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) 18 | 19 | Full `go doc` style documentation for the package can be viewed online without 20 | installing this package by using the GoDoc site here: 21 | https://pkg.go.dev/github.com/google/uuid 22 | -------------------------------------------------------------------------------- /dce.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | "fmt" 10 | "os" 11 | ) 12 | 13 | // A Domain represents a Version 2 domain 14 | type Domain byte 15 | 16 | // Domain constants for DCE Security (Version 2) UUIDs. 17 | const ( 18 | Person = Domain(0) 19 | Group = Domain(1) 20 | Org = Domain(2) 21 | ) 22 | 23 | // NewDCESecurity returns a DCE Security (Version 2) UUID. 24 | // 25 | // The domain should be one of Person, Group or Org. 26 | // On a POSIX system the id should be the users UID for the Person 27 | // domain and the users GID for the Group. The meaning of id for 28 | // the domain Org or on non-POSIX systems is site defined. 29 | // 30 | // For a given domain/id pair the same token may be returned for up to 31 | // 7 minutes and 10 seconds. 32 | func NewDCESecurity(domain Domain, id uint32) (UUID, error) { 33 | uuid, err := NewUUID() 34 | if err == nil { 35 | uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 36 | uuid[9] = byte(domain) 37 | binary.BigEndian.PutUint32(uuid[0:], id) 38 | } 39 | return uuid, err 40 | } 41 | 42 | // NewDCEPerson returns a DCE Security (Version 2) UUID in the person 43 | // domain with the id returned by os.Getuid. 44 | // 45 | // NewDCESecurity(Person, uint32(os.Getuid())) 46 | func NewDCEPerson() (UUID, error) { 47 | return NewDCESecurity(Person, uint32(os.Getuid())) 48 | } 49 | 50 | // NewDCEGroup returns a DCE Security (Version 2) UUID in the group 51 | // domain with the id returned by os.Getgid. 52 | // 53 | // NewDCESecurity(Group, uint32(os.Getgid())) 54 | func NewDCEGroup() (UUID, error) { 55 | return NewDCESecurity(Group, uint32(os.Getgid())) 56 | } 57 | 58 | // Domain returns the domain for a Version 2 UUID. Domains are only defined 59 | // for Version 2 UUIDs. 60 | func (uuid UUID) Domain() Domain { 61 | return Domain(uuid[9]) 62 | } 63 | 64 | // ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 65 | // UUIDs. 66 | func (uuid UUID) ID() uint32 { 67 | return binary.BigEndian.Uint32(uuid[0:4]) 68 | } 69 | 70 | func (d Domain) String() string { 71 | switch d { 72 | case Person: 73 | return "Person" 74 | case Group: 75 | return "Group" 76 | case Org: 77 | return "Org" 78 | } 79 | return fmt.Sprintf("Domain%d", int(d)) 80 | } 81 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package uuid generates and inspects UUIDs. 6 | // 7 | // UUIDs are based on RFC 9562(obsoletes RFC 4122) and DCE 1.1: Authentication and Security 8 | // Services. 9 | // 10 | // A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to 11 | // maps or compared directly. 12 | package uuid 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/uuid 2 | -------------------------------------------------------------------------------- /hash.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "crypto/md5" 9 | "crypto/sha1" 10 | "hash" 11 | ) 12 | 13 | // Well known namespace IDs and UUIDs 14 | var ( 15 | NameSpaceDNS = MustParse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 16 | NameSpaceURL = MustParse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") 17 | NameSpaceOID = MustParse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") 18 | NameSpaceX500 = MustParse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") 19 | Nil UUID // empty UUID, all zeros 20 | 21 | // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. 22 | Max = UUID{ 23 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 24 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 25 | } 26 | ) 27 | 28 | // NewHash returns a new UUID derived from the hash of space concatenated with 29 | // data generated by h. The hash should be at least 16 byte in length. The 30 | // first 16 bytes of the hash are used to form the UUID. The version of the 31 | // UUID will be the lower 4 bits of version. NewHash is used to implement 32 | // NewMD5 and NewSHA1. 33 | func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { 34 | h.Reset() 35 | h.Write(space[:]) //nolint:errcheck 36 | h.Write(data) //nolint:errcheck 37 | s := h.Sum(nil) 38 | var uuid UUID 39 | copy(uuid[:], s) 40 | uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) 41 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 9562 variant 42 | return uuid 43 | } 44 | 45 | // NewMD5 returns a new MD5 (Version 3) UUID based on the 46 | // supplied name space and data. It is the same as calling: 47 | // 48 | // NewHash(md5.New(), space, data, 3) 49 | func NewMD5(space UUID, data []byte) UUID { 50 | return NewHash(md5.New(), space, data, 3) 51 | } 52 | 53 | // NewSHA1 returns a new SHA1 (Version 5) UUID based on the 54 | // supplied name space and data. It is the same as calling: 55 | // 56 | // NewHash(sha1.New(), space, data, 5) 57 | func NewSHA1(space UUID, data []byte) UUID { 58 | return NewHash(sha1.New(), space, data, 5) 59 | } 60 | -------------------------------------------------------------------------------- /json_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/json" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | var testUUID = MustParse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 14 | 15 | func TestJSON(t *testing.T) { 16 | type S struct { 17 | ID1 UUID 18 | ID2 UUID 19 | } 20 | s1 := S{ID1: testUUID} 21 | data, err := json.Marshal(&s1) 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | var s2 S 26 | if err := json.Unmarshal(data, &s2); err != nil { 27 | t.Fatal(err) 28 | } 29 | if !reflect.DeepEqual(&s1, &s2) { 30 | t.Errorf("got %#v, want %#v", s2, s1) 31 | } 32 | } 33 | 34 | func TestJSONUnmarshal(t *testing.T) { 35 | type S struct { 36 | ID1 UUID 37 | ID2 UUID `json:"ID2,omitempty"` 38 | } 39 | 40 | testCases := map[string]struct { 41 | data []byte 42 | expectedError error 43 | expectedResult UUID 44 | }{ 45 | "success": { 46 | data: []byte(`{"ID1": "f47ac10b-58cc-0372-8567-0e02b2c3d479"}`), 47 | expectedError: nil, 48 | expectedResult: testUUID, 49 | }, 50 | "zero": { 51 | data: []byte(`{"ID1": "00000000-0000-0000-0000-000000000000"}`), 52 | expectedError: nil, 53 | expectedResult: Nil, 54 | }, 55 | "null": { 56 | data: []byte(`{"ID1": null}`), 57 | expectedError: nil, 58 | expectedResult: Nil, 59 | }, 60 | "empty": { 61 | data: []byte(`{"ID1": ""}`), 62 | expectedError: invalidLengthError{len: 0}, 63 | expectedResult: Nil, 64 | }, 65 | "omitempty": { 66 | data: []byte(`{"ID2": ""}`), 67 | expectedError: invalidLengthError{len: 0}, 68 | expectedResult: Nil, 69 | }, 70 | } 71 | 72 | for name, tc := range testCases { 73 | t.Run(name, func(t *testing.T) { 74 | var s S 75 | if err := json.Unmarshal(tc.data, &s); err != tc.expectedError { 76 | t.Errorf("unexpected error: got %v, want %v", err, tc.expectedError) 77 | } 78 | if !reflect.DeepEqual(s.ID1, tc.expectedResult) { 79 | t.Errorf("got %#v, want %#v", s.ID1, tc.expectedResult) 80 | } 81 | }) 82 | } 83 | } 84 | 85 | func BenchmarkUUID_MarshalJSON(b *testing.B) { 86 | x := &struct { 87 | UUID UUID `json:"uuid"` 88 | }{} 89 | var err error 90 | x.UUID, err = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 91 | if err != nil { 92 | b.Fatal(err) 93 | } 94 | for i := 0; i < b.N; i++ { 95 | js, err := json.Marshal(x) 96 | if err != nil { 97 | b.Fatalf("marshal json: %#v (%v)", js, err) 98 | } 99 | } 100 | } 101 | 102 | func BenchmarkUUID_UnmarshalJSON(b *testing.B) { 103 | js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`) 104 | var x *struct { 105 | UUID UUID `json:"uuid"` 106 | } 107 | for i := 0; i < b.N; i++ { 108 | err := json.Unmarshal(js, &x) 109 | if err != nil { 110 | b.Fatalf("marshal json: %#v (%v)", js, err) 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /marshal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import "fmt" 8 | 9 | // MarshalText implements encoding.TextMarshaler. 10 | func (uuid UUID) MarshalText() ([]byte, error) { 11 | var js [36]byte 12 | encodeHex(js[:], uuid) 13 | return js[:], nil 14 | } 15 | 16 | // UnmarshalText implements encoding.TextUnmarshaler. 17 | func (uuid *UUID) UnmarshalText(data []byte) error { 18 | id, err := ParseBytes(data) 19 | if err != nil { 20 | return err 21 | } 22 | *uuid = id 23 | return nil 24 | } 25 | 26 | // MarshalBinary implements encoding.BinaryMarshaler. 27 | func (uuid UUID) MarshalBinary() ([]byte, error) { 28 | return uuid[:], nil 29 | } 30 | 31 | // UnmarshalBinary implements encoding.BinaryUnmarshaler. 32 | func (uuid *UUID) UnmarshalBinary(data []byte) error { 33 | if len(data) != 16 { 34 | return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) 35 | } 36 | copy(uuid[:], data) 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /node.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "sync" 9 | ) 10 | 11 | var ( 12 | nodeMu sync.Mutex 13 | ifname string // name of interface being used 14 | nodeID [6]byte // hardware for version 1 UUIDs 15 | zeroID [6]byte // nodeID with only 0's 16 | ) 17 | 18 | // NodeInterface returns the name of the interface from which the NodeID was 19 | // derived. The interface "user" is returned if the NodeID was set by 20 | // SetNodeID. 21 | func NodeInterface() string { 22 | defer nodeMu.Unlock() 23 | nodeMu.Lock() 24 | return ifname 25 | } 26 | 27 | // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. 28 | // If name is "" then the first usable interface found will be used or a random 29 | // Node ID will be generated. If a named interface cannot be found then false 30 | // is returned. 31 | // 32 | // SetNodeInterface never fails when name is "". 33 | func SetNodeInterface(name string) bool { 34 | defer nodeMu.Unlock() 35 | nodeMu.Lock() 36 | return setNodeInterface(name) 37 | } 38 | 39 | func setNodeInterface(name string) bool { 40 | iname, addr := getHardwareInterface(name) // null implementation for js 41 | if iname != "" && addr != nil { 42 | ifname = iname 43 | copy(nodeID[:], addr) 44 | return true 45 | } 46 | 47 | // We found no interfaces with a valid hardware address. If name 48 | // does not specify a specific interface generate a random Node ID 49 | // (section 4.1.6) 50 | if name == "" { 51 | ifname = "random" 52 | randomBits(nodeID[:]) 53 | return true 54 | } 55 | return false 56 | } 57 | 58 | // NodeID returns a slice of a copy of the current Node ID, setting the Node ID 59 | // if not already set. 60 | func NodeID() []byte { 61 | defer nodeMu.Unlock() 62 | nodeMu.Lock() 63 | if nodeID == zeroID { 64 | setNodeInterface("") 65 | } 66 | nid := nodeID 67 | return nid[:] 68 | } 69 | 70 | // SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes 71 | // of id are used. If id is less than 6 bytes then false is returned and the 72 | // Node ID is not set. 73 | func SetNodeID(id []byte) bool { 74 | if len(id) < 6 { 75 | return false 76 | } 77 | defer nodeMu.Unlock() 78 | nodeMu.Lock() 79 | copy(nodeID[:], id) 80 | ifname = "user" 81 | return true 82 | } 83 | 84 | // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is 85 | // not valid. The NodeID is only well defined for version 1 and 2 UUIDs. 86 | func (uuid UUID) NodeID() []byte { 87 | var node [6]byte 88 | copy(node[:], uuid[10:]) 89 | return node[:] 90 | } 91 | -------------------------------------------------------------------------------- /node_js.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build js 6 | 7 | package uuid 8 | 9 | // getHardwareInterface returns nil values for the JS version of the code. 10 | // This removes the "net" dependency, because it is not used in the browser. 11 | // Using the "net" library inflates the size of the transpiled JS code by 673k bytes. 12 | func getHardwareInterface(name string) (string, []byte) { return "", nil } 13 | -------------------------------------------------------------------------------- /node_net.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !js 6 | 7 | package uuid 8 | 9 | import "net" 10 | 11 | var interfaces []net.Interface // cached list of interfaces 12 | 13 | // getHardwareInterface returns the name and hardware address of interface name. 14 | // If name is "" then the name and hardware address of one of the system's 15 | // interfaces is returned. If no interfaces are found (name does not exist or 16 | // there are no interfaces) then "", nil is returned. 17 | // 18 | // Only addresses of at least 6 bytes are returned. 19 | func getHardwareInterface(name string) (string, []byte) { 20 | if interfaces == nil { 21 | var err error 22 | interfaces, err = net.Interfaces() 23 | if err != nil { 24 | return "", nil 25 | } 26 | } 27 | for _, ifs := range interfaces { 28 | if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { 29 | return ifs.Name, ifs.HardwareAddr 30 | } 31 | } 32 | return "", nil 33 | } 34 | -------------------------------------------------------------------------------- /null.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "bytes" 9 | "database/sql/driver" 10 | "encoding/json" 11 | "fmt" 12 | ) 13 | 14 | var jsonNull = []byte("null") 15 | 16 | // NullUUID represents a UUID that may be null. 17 | // NullUUID implements the SQL driver.Scanner interface so 18 | // it can be used as a scan destination: 19 | // 20 | // var u uuid.NullUUID 21 | // err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) 22 | // ... 23 | // if u.Valid { 24 | // // use u.UUID 25 | // } else { 26 | // // NULL value 27 | // } 28 | // 29 | type NullUUID struct { 30 | UUID UUID 31 | Valid bool // Valid is true if UUID is not NULL 32 | } 33 | 34 | // Scan implements the SQL driver.Scanner interface. 35 | func (nu *NullUUID) Scan(value interface{}) error { 36 | if value == nil { 37 | nu.UUID, nu.Valid = Nil, false 38 | return nil 39 | } 40 | 41 | err := nu.UUID.Scan(value) 42 | if err != nil { 43 | nu.Valid = false 44 | return err 45 | } 46 | 47 | nu.Valid = true 48 | return nil 49 | } 50 | 51 | // Value implements the driver Valuer interface. 52 | func (nu NullUUID) Value() (driver.Value, error) { 53 | if !nu.Valid { 54 | return nil, nil 55 | } 56 | // Delegate to UUID Value function 57 | return nu.UUID.Value() 58 | } 59 | 60 | // MarshalBinary implements encoding.BinaryMarshaler. 61 | func (nu NullUUID) MarshalBinary() ([]byte, error) { 62 | if nu.Valid { 63 | return nu.UUID[:], nil 64 | } 65 | 66 | return []byte(nil), nil 67 | } 68 | 69 | // UnmarshalBinary implements encoding.BinaryUnmarshaler. 70 | func (nu *NullUUID) UnmarshalBinary(data []byte) error { 71 | if len(data) != 16 { 72 | return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) 73 | } 74 | copy(nu.UUID[:], data) 75 | nu.Valid = true 76 | return nil 77 | } 78 | 79 | // MarshalText implements encoding.TextMarshaler. 80 | func (nu NullUUID) MarshalText() ([]byte, error) { 81 | if nu.Valid { 82 | return nu.UUID.MarshalText() 83 | } 84 | 85 | return jsonNull, nil 86 | } 87 | 88 | // UnmarshalText implements encoding.TextUnmarshaler. 89 | func (nu *NullUUID) UnmarshalText(data []byte) error { 90 | id, err := ParseBytes(data) 91 | if err != nil { 92 | nu.Valid = false 93 | return err 94 | } 95 | nu.UUID = id 96 | nu.Valid = true 97 | return nil 98 | } 99 | 100 | // MarshalJSON implements json.Marshaler. 101 | func (nu NullUUID) MarshalJSON() ([]byte, error) { 102 | if nu.Valid { 103 | return json.Marshal(nu.UUID) 104 | } 105 | 106 | return jsonNull, nil 107 | } 108 | 109 | // UnmarshalJSON implements json.Unmarshaler. 110 | func (nu *NullUUID) UnmarshalJSON(data []byte) error { 111 | if bytes.Equal(data, jsonNull) { 112 | *nu = NullUUID{} 113 | return nil // valid null UUID 114 | } 115 | err := json.Unmarshal(data, &nu.UUID) 116 | nu.Valid = err == nil 117 | return err 118 | } 119 | -------------------------------------------------------------------------------- /null_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "bytes" 9 | "encoding/json" 10 | "testing" 11 | ) 12 | 13 | func TestNullUUIDScan(t *testing.T) { 14 | var u UUID 15 | var nu NullUUID 16 | 17 | uNilErr := u.Scan(nil) 18 | nuNilErr := nu.Scan(nil) 19 | if uNilErr != nil && 20 | nuNilErr != nil && 21 | uNilErr.Error() != nuNilErr.Error() { 22 | t.Errorf("expected errors to be equal, got %s, %s", uNilErr, nuNilErr) 23 | } 24 | 25 | uInvalidStringErr := u.Scan("test") 26 | nuInvalidStringErr := nu.Scan("test") 27 | if uInvalidStringErr != nil && 28 | nuInvalidStringErr != nil && 29 | uInvalidStringErr.Error() != nuInvalidStringErr.Error() { 30 | t.Errorf("expected errors to be equal, got %s, %s", uInvalidStringErr, nuInvalidStringErr) 31 | } 32 | 33 | valid := "12345678-abcd-1234-abcd-0123456789ab" 34 | uValidErr := u.Scan(valid) 35 | nuValidErr := nu.Scan(valid) 36 | if uValidErr != nuValidErr { 37 | t.Errorf("expected errors to be equal, got %s, %s", uValidErr, nuValidErr) 38 | } 39 | } 40 | 41 | func TestNullUUIDValue(t *testing.T) { 42 | var u UUID 43 | var nu NullUUID 44 | 45 | nuValue, nuErr := nu.Value() 46 | if nuErr != nil { 47 | t.Errorf("expected nil err, got err %s", nuErr) 48 | } 49 | if nuValue != nil { 50 | t.Errorf("expected nil value, got non-nil %s", nuValue) 51 | } 52 | 53 | u = MustParse("12345678-abcd-1234-abcd-0123456789ab") 54 | nu = NullUUID{ 55 | UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), 56 | Valid: true, 57 | } 58 | 59 | uValue, uErr := u.Value() 60 | nuValue, nuErr = nu.Value() 61 | if uErr != nil { 62 | t.Errorf("expected nil err, got err %s", uErr) 63 | } 64 | if nuErr != nil { 65 | t.Errorf("expected nil err, got err %s", nuErr) 66 | } 67 | if uValue != nuValue { 68 | t.Errorf("expected uuid %s and nulluuid %s to be equal ", uValue, nuValue) 69 | } 70 | } 71 | 72 | func TestNullUUIDMarshalText(t *testing.T) { 73 | tests := []struct { 74 | nullUUID NullUUID 75 | }{ 76 | { 77 | nullUUID: NullUUID{}, 78 | }, 79 | { 80 | nullUUID: NullUUID{ 81 | UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), 82 | Valid: true, 83 | }, 84 | }, 85 | } 86 | for _, test := range tests { 87 | var uText []byte 88 | var uErr error 89 | nuText, nuErr := test.nullUUID.MarshalText() 90 | if test.nullUUID.Valid { 91 | uText, uErr = test.nullUUID.UUID.MarshalText() 92 | } else { 93 | uText = []byte("null") 94 | } 95 | if nuErr != uErr { 96 | t.Errorf("expected error %e, got %e", nuErr, uErr) 97 | } 98 | if !bytes.Equal(nuText, uText) { 99 | t.Errorf("expected text data %s, got %s", string(nuText), string(uText)) 100 | } 101 | } 102 | } 103 | 104 | func TestNullUUIDUnmarshalText(t *testing.T) { 105 | tests := []struct { 106 | nullUUID NullUUID 107 | }{ 108 | { 109 | nullUUID: NullUUID{}, 110 | }, 111 | { 112 | nullUUID: NullUUID{ 113 | UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), 114 | Valid: true, 115 | }, 116 | }, 117 | } 118 | for _, test := range tests { 119 | var uText []byte 120 | var uErr error 121 | nuText, nuErr := test.nullUUID.MarshalText() 122 | if test.nullUUID.Valid { 123 | uText, uErr = test.nullUUID.UUID.MarshalText() 124 | } else { 125 | uText = []byte("null") 126 | } 127 | if nuErr != uErr { 128 | t.Errorf("expected error %e, got %e", nuErr, uErr) 129 | } 130 | if !bytes.Equal(nuText, uText) { 131 | t.Errorf("expected text data %s, got %s", string(nuText), string(uText)) 132 | } 133 | } 134 | } 135 | 136 | func TestNullUUIDMarshalBinary(t *testing.T) { 137 | tests := []struct { 138 | nullUUID NullUUID 139 | }{ 140 | { 141 | nullUUID: NullUUID{}, 142 | }, 143 | { 144 | nullUUID: NullUUID{ 145 | UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), 146 | Valid: true, 147 | }, 148 | }, 149 | } 150 | for _, test := range tests { 151 | var uBinary []byte 152 | var uErr error 153 | nuBinary, nuErr := test.nullUUID.MarshalBinary() 154 | if test.nullUUID.Valid { 155 | uBinary, uErr = test.nullUUID.UUID.MarshalBinary() 156 | } else { 157 | uBinary = []byte(nil) 158 | } 159 | if nuErr != uErr { 160 | t.Errorf("expected error %e, got %e", nuErr, uErr) 161 | } 162 | if !bytes.Equal(nuBinary, uBinary) { 163 | t.Errorf("expected binary data %s, got %s", string(nuBinary), string(uBinary)) 164 | } 165 | } 166 | } 167 | 168 | func TestNullUUIDMarshalJSON(t *testing.T) { 169 | jsonNull, _ := json.Marshal(nil) 170 | jsonUUID, _ := json.Marshal(MustParse("12345678-abcd-1234-abcd-0123456789ab")) 171 | tests := []struct { 172 | nullUUID NullUUID 173 | expected []byte 174 | expectedErr error 175 | }{ 176 | { 177 | nullUUID: NullUUID{}, 178 | expected: jsonNull, 179 | expectedErr: nil, 180 | }, 181 | { 182 | nullUUID: NullUUID{ 183 | UUID: MustParse(string(jsonUUID)), 184 | Valid: true, 185 | }, 186 | expected: []byte(`"12345678-abcd-1234-abcd-0123456789ab"`), 187 | expectedErr: nil, 188 | }, 189 | } 190 | for _, test := range tests { 191 | data, err := json.Marshal(&test.nullUUID) 192 | if err != test.expectedErr { 193 | t.Errorf("expected error %e, got %e", test.expectedErr, err) 194 | } 195 | if !bytes.Equal(data, test.expected) { 196 | t.Errorf("expected json data %s, got %s", string(test.expected), string(data)) 197 | } 198 | } 199 | } 200 | 201 | func TestNullUUIDUnmarshalJSON(t *testing.T) { 202 | jsonNull, _ := json.Marshal(nil) 203 | jsonUUID, _ := json.Marshal(MustParse("12345678-abcd-1234-abcd-0123456789ab")) 204 | 205 | var nu NullUUID 206 | err := json.Unmarshal(jsonNull, &nu) 207 | if err != nil || nu.Valid { 208 | t.Errorf("expected nil when unmarshalling null, got %s", err) 209 | } 210 | err = json.Unmarshal(jsonUUID, &nu) 211 | if err != nil || !nu.Valid { 212 | t.Errorf("expected nil when unmarshalling null, got %s", err) 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /seq_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "flag" 9 | "runtime" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | // This test is only run when --regressions is passed on the go test line. 15 | var regressions = flag.Bool("regressions", false, "run uuid regression tests") 16 | 17 | // TestClockSeqRace tests for a particular race condition of returning two 18 | // identical Version1 UUIDs. The duration of 1 minute was chosen as the race 19 | // condition, before being fixed, nearly always occurred in under 30 seconds. 20 | func TestClockSeqRace(t *testing.T) { 21 | if !*regressions { 22 | t.Skip("skipping regression tests") 23 | } 24 | duration := time.Minute 25 | 26 | done := make(chan struct{}) 27 | defer close(done) 28 | 29 | ch := make(chan UUID, 10000) 30 | ncpu := runtime.NumCPU() 31 | switch ncpu { 32 | case 0, 1: 33 | // We can't run the test effectively. 34 | t.Skip("skipping race test, only one CPU detected") 35 | return 36 | default: 37 | runtime.GOMAXPROCS(ncpu) 38 | } 39 | for i := 0; i < ncpu; i++ { 40 | go func() { 41 | for { 42 | select { 43 | case <-done: 44 | return 45 | case ch <- Must(NewUUID()): 46 | } 47 | } 48 | }() 49 | } 50 | 51 | uuids := make(map[string]bool) 52 | cnt := 0 53 | start := time.Now() 54 | for u := range ch { 55 | s := u.String() 56 | if uuids[s] { 57 | t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s) 58 | return 59 | } 60 | uuids[s] = true 61 | if time.Since(start) > duration { 62 | return 63 | } 64 | cnt++ 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sql.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "database/sql/driver" 9 | "fmt" 10 | ) 11 | 12 | // Scan implements sql.Scanner so UUIDs can be read from databases transparently. 13 | // Currently, database types that map to string and []byte are supported. Please 14 | // consult database-specific driver documentation for matching types. 15 | func (uuid *UUID) Scan(src interface{}) error { 16 | switch src := src.(type) { 17 | case nil: 18 | return nil 19 | 20 | case string: 21 | // if an empty UUID comes from a table, we return a null UUID 22 | if src == "" { 23 | return nil 24 | } 25 | 26 | // see Parse for required string format 27 | u, err := Parse(src) 28 | if err != nil { 29 | return fmt.Errorf("Scan: %v", err) 30 | } 31 | 32 | *uuid = u 33 | 34 | case []byte: 35 | // if an empty UUID comes from a table, we return a null UUID 36 | if len(src) == 0 { 37 | return nil 38 | } 39 | 40 | // assumes a simple slice of bytes if 16 bytes 41 | // otherwise attempts to parse 42 | if len(src) != 16 { 43 | return uuid.Scan(string(src)) 44 | } 45 | copy((*uuid)[:], src) 46 | 47 | default: 48 | return fmt.Errorf("Scan: unable to scan type %T into UUID", src) 49 | } 50 | 51 | return nil 52 | } 53 | 54 | // Value implements sql.Valuer so that UUIDs can be written to databases 55 | // transparently. Currently, UUIDs map to strings. Please consult 56 | // database-specific driver documentation for matching types. 57 | func (uuid UUID) Value() (driver.Value, error) { 58 | return uuid.String(), nil 59 | } 60 | -------------------------------------------------------------------------------- /sql_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | func TestScan(t *testing.T) { 13 | stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479" 14 | badTypeTest := 6 15 | invalidTest := "f47ac10b-58cc-0372-8567-0e02b2c3d4" 16 | 17 | byteTest := make([]byte, 16) 18 | byteTestUUID := MustParse(stringTest) 19 | copy(byteTest, byteTestUUID[:]) 20 | 21 | // sunny day tests 22 | 23 | var uuid UUID 24 | err := (&uuid).Scan(stringTest) 25 | if err != nil { 26 | t.Fatal(err) 27 | } 28 | 29 | err = (&uuid).Scan([]byte(stringTest)) 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | 34 | err = (&uuid).Scan(byteTest) 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | 39 | // bad type tests 40 | 41 | err = (&uuid).Scan(badTypeTest) 42 | if err == nil { 43 | t.Error("int correctly parsed and shouldn't have") 44 | } 45 | if !strings.Contains(err.Error(), "unable to scan type") { 46 | t.Error("attempting to parse an int returned an incorrect error message") 47 | } 48 | 49 | // invalid/incomplete uuids 50 | 51 | err = (&uuid).Scan(invalidTest) 52 | if err == nil { 53 | t.Error("invalid uuid was parsed without error") 54 | } 55 | if !strings.Contains(err.Error(), "invalid UUID") { 56 | t.Error("attempting to parse an invalid UUID returned an incorrect error message") 57 | } 58 | 59 | err = (&uuid).Scan(byteTest[:len(byteTest)-2]) 60 | if err == nil { 61 | t.Error("invalid byte uuid was parsed without error") 62 | } 63 | if !strings.Contains(err.Error(), "invalid UUID") { 64 | t.Error("attempting to parse an invalid byte UUID returned an incorrect error message") 65 | } 66 | 67 | // empty tests 68 | 69 | uuid = UUID{} 70 | var emptySlice []byte 71 | err = (&uuid).Scan(emptySlice) 72 | if err != nil { 73 | t.Fatal(err) 74 | } 75 | 76 | for _, v := range uuid { 77 | if v != 0 { 78 | t.Error("UUID was not nil after scanning empty byte slice") 79 | } 80 | } 81 | 82 | uuid = UUID{} 83 | var emptyString string 84 | err = (&uuid).Scan(emptyString) 85 | if err != nil { 86 | t.Fatal(err) 87 | } 88 | for _, v := range uuid { 89 | if v != 0 { 90 | t.Error("UUID was not nil after scanning empty byte slice") 91 | } 92 | } 93 | 94 | uuid = UUID{} 95 | err = (&uuid).Scan(nil) 96 | if err != nil { 97 | t.Fatal(err) 98 | } 99 | for _, v := range uuid { 100 | if v != 0 { 101 | t.Error("UUID was not nil after scanning nil") 102 | } 103 | } 104 | } 105 | 106 | func TestValue(t *testing.T) { 107 | stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479" 108 | uuid := MustParse(stringTest) 109 | val, _ := uuid.Value() 110 | if val != stringTest { 111 | t.Error("Value() did not return expected string") 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /time.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | // A Time represents a time as the number of 100's of nanoseconds since 15 Oct 14 | // 1582. 15 | type Time int64 16 | 17 | const ( 18 | lillian = 2299160 // Julian day of 15 Oct 1582 19 | unix = 2440587 // Julian day of 1 Jan 1970 20 | epoch = unix - lillian // Days between epochs 21 | g1582 = epoch * 86400 // seconds between epochs 22 | g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs 23 | ) 24 | 25 | var ( 26 | timeMu sync.Mutex 27 | lasttime uint64 // last time we returned 28 | clockSeq uint16 // clock sequence for this run 29 | 30 | timeNow = time.Now // for testing 31 | ) 32 | 33 | // UnixTime converts t the number of seconds and nanoseconds using the Unix 34 | // epoch of 1 Jan 1970. 35 | func (t Time) UnixTime() (sec, nsec int64) { 36 | sec = int64(t - g1582ns100) 37 | nsec = (sec % 10000000) * 100 38 | sec /= 10000000 39 | return sec, nsec 40 | } 41 | 42 | // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and 43 | // clock sequence as well as adjusting the clock sequence as needed. An error 44 | // is returned if the current time cannot be determined. 45 | func GetTime() (Time, uint16, error) { 46 | defer timeMu.Unlock() 47 | timeMu.Lock() 48 | return getTime(nil) 49 | } 50 | 51 | func getTime(customTime *time.Time) (Time, uint16, error) { 52 | var t time.Time 53 | if customTime == nil { // When not provided, use the current time 54 | t = timeNow() 55 | } else { 56 | t = *customTime 57 | } 58 | 59 | // If we don't have a clock sequence already, set one. 60 | if clockSeq == 0 { 61 | setClockSequence(-1) 62 | } 63 | now := uint64(t.UnixNano()/100) + g1582ns100 64 | 65 | // If time has gone backwards with this clock sequence then we 66 | // increment the clock sequence 67 | if now <= lasttime { 68 | clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 69 | } 70 | lasttime = now 71 | return Time(now), clockSeq, nil 72 | } 73 | 74 | // ClockSequence returns the current clock sequence, generating one if not 75 | // already set. The clock sequence is only used for Version 1 UUIDs. 76 | // 77 | // The uuid package does not use global static storage for the clock sequence or 78 | // the last time a UUID was generated. Unless SetClockSequence is used, a new 79 | // random clock sequence is generated the first time a clock sequence is 80 | // requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) 81 | func ClockSequence() int { 82 | defer timeMu.Unlock() 83 | timeMu.Lock() 84 | return clockSequence() 85 | } 86 | 87 | func clockSequence() int { 88 | if clockSeq == 0 { 89 | setClockSequence(-1) 90 | } 91 | return int(clockSeq & 0x3fff) 92 | } 93 | 94 | // SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to 95 | // -1 causes a new sequence to be generated. 96 | func SetClockSequence(seq int) { 97 | defer timeMu.Unlock() 98 | timeMu.Lock() 99 | setClockSequence(seq) 100 | } 101 | 102 | func setClockSequence(seq int) { 103 | if seq == -1 { 104 | var b [2]byte 105 | randomBits(b[:]) // clock sequence 106 | seq = int(b[0])<<8 | int(b[1]) 107 | } 108 | oldSeq := clockSeq 109 | clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant 110 | if oldSeq != clockSeq { 111 | lasttime = 0 112 | } 113 | } 114 | 115 | // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in 116 | // uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. 117 | func (uuid UUID) Time() Time { 118 | var t Time 119 | switch uuid.Version() { 120 | case 6: 121 | time := int64(binary.BigEndian.Uint32(uuid[0:4])) << 28 122 | time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 12 123 | time |= int64(binary.BigEndian.Uint16(uuid[6:8]) & 0xfff) 124 | t = Time(time) 125 | case 7: 126 | time := binary.BigEndian.Uint64(uuid[:8]) 127 | t = Time((time>>16)*10000 + g1582ns100) 128 | default: // forward compatible 129 | time := int64(binary.BigEndian.Uint32(uuid[0:4])) 130 | time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 131 | time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 132 | t = Time(time) 133 | } 134 | return t 135 | } 136 | 137 | // ClockSequence returns the clock sequence encoded in uuid. 138 | // The clock sequence is only well defined for version 1 and 2 UUIDs. 139 | func (uuid UUID) ClockSequence() int { 140 | return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff 141 | } 142 | -------------------------------------------------------------------------------- /time_test.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestGetTime(t *testing.T) { 9 | now := time.Now() 10 | tt := map[string]struct { 11 | input func() *time.Time 12 | expectedTime int64 13 | }{ 14 | "it should return the current time": { 15 | input: func() *time.Time { 16 | return nil 17 | }, 18 | expectedTime: now.Unix(), 19 | }, 20 | "it should return the provided time": { 21 | input: func() *time.Time { 22 | parsed, err := time.Parse(time.RFC3339, "2024-10-15T09:32:23Z") 23 | if err != nil { 24 | t.Errorf("timeParse unexpected error: %v", err) 25 | } 26 | return &parsed 27 | }, 28 | expectedTime: 1728984743, 29 | }, 30 | } 31 | 32 | for name, tc := range tt { 33 | t.Run(name, func(t *testing.T) { 34 | result, _, err := getTime(tc.input()) 35 | if err != nil { 36 | t.Errorf("getTime unexpected error: %v", err) 37 | } 38 | sec, _ := result.UnixTime() 39 | if sec != tc.expectedTime { 40 | t.Errorf("expected %v, got %v", tc.expectedTime, result) 41 | } 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "bytes" 9 | "io" 10 | ) 11 | 12 | // randomBits completely fills slice b with random data. 13 | func randomBits(b []byte) { 14 | if _, err := io.ReadFull(rander, b); err != nil { 15 | panic(err.Error()) // rand should never fail 16 | } 17 | } 18 | 19 | // xvalues returns the value of a byte as a hexadecimal digit or 255. 20 | var xvalues = [256]byte{ 21 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 22 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 23 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 24 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 25 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 26 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 27 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 28 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 29 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 30 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 32 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 33 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 34 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 35 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 36 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 37 | } 38 | 39 | // xtob converts hex characters x1 and x2 into a byte. 40 | func xtob(x1, x2 byte) (byte, bool) { 41 | b1 := xvalues[x1] 42 | b2 := xvalues[x2] 43 | return (b1 << 4) | b2, b1 != 255 && b2 != 255 44 | } 45 | 46 | // Compare returns an integer comparing two uuids lexicographically. The result will be 0 if a == b, -1 if a < b, and +1 if a > b. 47 | func Compare(a, b UUID) int { 48 | return bytes.Compare(a[:], b[:]) 49 | } 50 | -------------------------------------------------------------------------------- /uuid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "bytes" 9 | "crypto/rand" 10 | "encoding/hex" 11 | "errors" 12 | "fmt" 13 | "io" 14 | "strings" 15 | "sync" 16 | ) 17 | 18 | // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC 19 | // 9562. 20 | type UUID [16]byte 21 | 22 | // A Version represents a UUID's version. 23 | type Version byte 24 | 25 | // A Variant represents a UUID's variant. 26 | type Variant byte 27 | 28 | // Constants returned by Variant. 29 | const ( 30 | Invalid = Variant(iota) // Invalid UUID 31 | RFC4122 // The variant specified in RFC9562(obsoletes RFC4122). 32 | Reserved // Reserved, NCS backward compatibility. 33 | Microsoft // Reserved, Microsoft Corporation backward compatibility. 34 | Future // Reserved for future definition. 35 | ) 36 | 37 | // RFC9562 added V6 and V7 of UUID, but did not change specification of V1 and V4 38 | // implemented in this module. To avoid creating new major module version, 39 | // we still use RFC4122 for constant name. 40 | const Standard = RFC4122 41 | 42 | const randPoolSize = 16 * 16 43 | 44 | var ( 45 | rander = rand.Reader // random function 46 | poolEnabled = false 47 | poolMu sync.Mutex 48 | poolPos = randPoolSize // protected with poolMu 49 | pool [randPoolSize]byte // protected with poolMu 50 | 51 | ErrInvalidUUIDFormat = errors.New("invalid UUID format") 52 | ErrInvalidBracketedFormat = errors.New("invalid bracketed UUID format") 53 | ) 54 | 55 | type URNPrefixError struct { prefix string } 56 | 57 | func (e URNPrefixError) Error() string { 58 | return fmt.Sprintf("invalid urn prefix: %q", e.prefix) 59 | } 60 | 61 | func (e URNPrefixError) Is(target error) bool { 62 | _, ok := target.(URNPrefixError) 63 | return ok 64 | } 65 | 66 | var ErrInvalidURNPrefix = URNPrefixError{} 67 | 68 | type invalidLengthError struct{ len int } 69 | 70 | func (err invalidLengthError) Error() string { 71 | return fmt.Sprintf("invalid UUID length: %d", err.len) 72 | } 73 | 74 | func (e invalidLengthError) Is(target error) bool { 75 | _, ok := target.(invalidLengthError) 76 | return ok 77 | } 78 | 79 | var ErrInvalidLength = invalidLengthError{} 80 | 81 | // IsInvalidLengthError is matcher function for custom error invalidLengthError 82 | func IsInvalidLengthError(err error) bool { 83 | return errors.Is(err, ErrInvalidLength) 84 | } 85 | 86 | // Parse decodes s into a UUID or returns an error if it cannot be parsed. Both 87 | // the standard UUID forms defined in RFC 9562 88 | // (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and 89 | // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, 90 | // Parse accepts non-standard strings such as the raw hex encoding 91 | // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, 92 | // e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are 93 | // examined in the latter case. Parse should not be used to validate strings as 94 | // it parses non-standard encodings as indicated above. 95 | func Parse(s string) (UUID, error) { 96 | var uuid UUID 97 | switch len(s) { 98 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 99 | case 36: 100 | 101 | // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 102 | case 36 + 9: 103 | if !strings.EqualFold(s[:9], "urn:uuid:") { 104 | return uuid, URNPrefixError{s[:9]} 105 | } 106 | s = s[9:] 107 | 108 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 109 | case 36 + 2: 110 | s = s[1:] 111 | 112 | // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 113 | case 32: 114 | var ok bool 115 | for i := range uuid { 116 | uuid[i], ok = xtob(s[i*2], s[i*2+1]) 117 | if !ok { 118 | return uuid, ErrInvalidUUIDFormat 119 | } 120 | } 121 | return uuid, nil 122 | default: 123 | return uuid, invalidLengthError{len(s)} 124 | } 125 | // s is now at least 36 bytes long 126 | // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 127 | if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { 128 | return uuid, ErrInvalidUUIDFormat 129 | 130 | } 131 | for i, x := range [16]int{ 132 | 0, 2, 4, 6, 133 | 9, 11, 134 | 14, 16, 135 | 19, 21, 136 | 24, 26, 28, 30, 32, 34, 137 | } { 138 | v, ok := xtob(s[x], s[x+1]) 139 | if !ok { 140 | return uuid, ErrInvalidUUIDFormat 141 | } 142 | uuid[i] = v 143 | } 144 | return uuid, nil 145 | } 146 | 147 | // ParseBytes is like Parse, except it parses a byte slice instead of a string. 148 | func ParseBytes(b []byte) (UUID, error) { 149 | var uuid UUID 150 | switch len(b) { 151 | case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 152 | case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 153 | if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { 154 | return uuid, URNPrefixError{string(b[:9])} 155 | } 156 | b = b[9:] 157 | case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 158 | b = b[1:] 159 | case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 160 | var ok bool 161 | for i := 0; i < 32; i += 2 { 162 | uuid[i/2], ok = xtob(b[i], b[i+1]) 163 | if !ok { 164 | return uuid, ErrInvalidUUIDFormat 165 | } 166 | } 167 | return uuid, nil 168 | default: 169 | return uuid, invalidLengthError{len(b)} 170 | } 171 | // s is now at least 36 bytes long 172 | // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 173 | if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { 174 | return uuid, ErrInvalidUUIDFormat 175 | } 176 | for i, x := range [16]int{ 177 | 0, 2, 4, 6, 178 | 9, 11, 179 | 14, 16, 180 | 19, 21, 181 | 24, 26, 28, 30, 32, 34, 182 | } { 183 | v, ok := xtob(b[x], b[x+1]) 184 | if !ok { 185 | return uuid, ErrInvalidUUIDFormat 186 | } 187 | uuid[i] = v 188 | } 189 | return uuid, nil 190 | } 191 | 192 | // MustParse is like Parse but panics if the string cannot be parsed. 193 | // It simplifies safe initialization of global variables holding compiled UUIDs. 194 | func MustParse(s string) UUID { 195 | uuid, err := Parse(s) 196 | if err != nil { 197 | panic(`uuid: Parse(` + s + `): ` + err.Error()) 198 | } 199 | return uuid 200 | } 201 | 202 | // FromBytes creates a new UUID from a byte slice. Returns an error if the slice 203 | // does not have a length of 16. The bytes are copied from the slice. 204 | func FromBytes(b []byte) (uuid UUID, err error) { 205 | err = uuid.UnmarshalBinary(b) 206 | return uuid, err 207 | } 208 | 209 | // Must returns uuid if err is nil and panics otherwise. 210 | func Must(uuid UUID, err error) UUID { 211 | if err != nil { 212 | panic(err) 213 | } 214 | return uuid 215 | } 216 | 217 | // Validate returns an error if s is not a properly formatted UUID in one of the following formats: 218 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 219 | // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 220 | // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 221 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 222 | // It returns an error if the format is invalid, otherwise nil. 223 | func Validate(s string) error { 224 | switch len(s) { 225 | // Standard UUID format 226 | case 36: 227 | 228 | // UUID with "urn:uuid:" prefix 229 | case 36 + 9: 230 | if !strings.EqualFold(s[:9], "urn:uuid:") { 231 | return URNPrefixError{s[:9]} 232 | } 233 | s = s[9:] 234 | 235 | // UUID enclosed in braces 236 | case 36 + 2: 237 | if s[0] != '{' || s[len(s)-1] != '}' { 238 | return ErrInvalidBracketedFormat 239 | } 240 | s = s[1 : len(s)-1] 241 | 242 | // UUID without hyphens 243 | case 32: 244 | for i := 0; i < len(s); i += 2 { 245 | _, ok := xtob(s[i], s[i+1]) 246 | if !ok { 247 | return ErrInvalidUUIDFormat 248 | } 249 | } 250 | 251 | default: 252 | return invalidLengthError{len(s)} 253 | } 254 | 255 | // Check for standard UUID format 256 | if len(s) == 36 { 257 | if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { 258 | return ErrInvalidUUIDFormat 259 | } 260 | for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { 261 | if _, ok := xtob(s[x], s[x+1]); !ok { 262 | return ErrInvalidUUIDFormat 263 | } 264 | } 265 | } 266 | 267 | return nil 268 | } 269 | 270 | // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 271 | // , or "" if uuid is invalid. 272 | func (uuid UUID) String() string { 273 | var buf [36]byte 274 | encodeHex(buf[:], uuid) 275 | return string(buf[:]) 276 | } 277 | 278 | // URN returns the RFC 2141 URN form of uuid, 279 | // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. 280 | func (uuid UUID) URN() string { 281 | var buf [36 + 9]byte 282 | copy(buf[:], "urn:uuid:") 283 | encodeHex(buf[9:], uuid) 284 | return string(buf[:]) 285 | } 286 | 287 | func encodeHex(dst []byte, uuid UUID) { 288 | hex.Encode(dst, uuid[:4]) 289 | dst[8] = '-' 290 | hex.Encode(dst[9:13], uuid[4:6]) 291 | dst[13] = '-' 292 | hex.Encode(dst[14:18], uuid[6:8]) 293 | dst[18] = '-' 294 | hex.Encode(dst[19:23], uuid[8:10]) 295 | dst[23] = '-' 296 | hex.Encode(dst[24:], uuid[10:]) 297 | } 298 | 299 | // Variant returns the variant encoded in uuid. 300 | func (uuid UUID) Variant() Variant { 301 | switch { 302 | case (uuid[8] & 0xc0) == 0x80: 303 | return RFC4122 304 | case (uuid[8] & 0xe0) == 0xc0: 305 | return Microsoft 306 | case (uuid[8] & 0xe0) == 0xe0: 307 | return Future 308 | default: 309 | return Reserved 310 | } 311 | } 312 | 313 | // Version returns the version of uuid. 314 | func (uuid UUID) Version() Version { 315 | return Version(uuid[6] >> 4) 316 | } 317 | 318 | func (v Version) String() string { 319 | if v > 15 { 320 | return fmt.Sprintf("BAD_VERSION_%d", v) 321 | } 322 | return fmt.Sprintf("VERSION_%d", v) 323 | } 324 | 325 | func (v Variant) String() string { 326 | switch v { 327 | case RFC4122: 328 | return "RFC4122" 329 | case Reserved: 330 | return "Reserved" 331 | case Microsoft: 332 | return "Microsoft" 333 | case Future: 334 | return "Future" 335 | case Invalid: 336 | return "Invalid" 337 | } 338 | return fmt.Sprintf("BadVariant%d", int(v)) 339 | } 340 | 341 | // SetRand sets the random number generator to r, which implements io.Reader. 342 | // If r.Read returns an error when the package requests random data then 343 | // a panic will be issued. 344 | // 345 | // Calling SetRand with nil sets the random number generator to the default 346 | // generator. 347 | func SetRand(r io.Reader) { 348 | if r == nil { 349 | rander = rand.Reader 350 | return 351 | } 352 | rander = r 353 | } 354 | 355 | // EnableRandPool enables internal randomness pool used for Random 356 | // (Version 4) UUID generation. The pool contains random bytes read from 357 | // the random number generator on demand in batches. Enabling the pool 358 | // may improve the UUID generation throughput significantly. 359 | // 360 | // Since the pool is stored on the Go heap, this feature may be a bad fit 361 | // for security sensitive applications. 362 | // 363 | // Both EnableRandPool and DisableRandPool are not thread-safe and should 364 | // only be called when there is no possibility that New or any other 365 | // UUID Version 4 generation function will be called concurrently. 366 | func EnableRandPool() { 367 | poolEnabled = true 368 | } 369 | 370 | // DisableRandPool disables the randomness pool if it was previously 371 | // enabled with EnableRandPool. 372 | // 373 | // Both EnableRandPool and DisableRandPool are not thread-safe and should 374 | // only be called when there is no possibility that New or any other 375 | // UUID Version 4 generation function will be called concurrently. 376 | func DisableRandPool() { 377 | poolEnabled = false 378 | defer poolMu.Unlock() 379 | poolMu.Lock() 380 | poolPos = randPoolSize 381 | } 382 | 383 | // UUIDs is a slice of UUID types. 384 | type UUIDs []UUID 385 | 386 | // Strings returns a string slice containing the string form of each UUID in uuids. 387 | func (uuids UUIDs) Strings() []string { 388 | var uuidStrs = make([]string, len(uuids)) 389 | for i, uuid := range uuids { 390 | uuidStrs[i] = uuid.String() 391 | } 392 | return uuidStrs 393 | } 394 | -------------------------------------------------------------------------------- /uuid_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "fmt" 11 | "os" 12 | "runtime" 13 | "strings" 14 | "testing" 15 | "time" 16 | "unsafe" 17 | ) 18 | 19 | type test struct { 20 | in string 21 | version Version 22 | variant Variant 23 | isuuid bool 24 | } 25 | 26 | var tests = []test{ 27 | {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, 28 | {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, 29 | {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, 30 | {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, 31 | {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, 32 | {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, 33 | {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, 34 | {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, 35 | {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, 36 | {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, 37 | {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, 38 | {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, 39 | {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, 40 | {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, 41 | {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, 42 | {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, 43 | 44 | {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 45 | {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 46 | {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 47 | {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, 48 | {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, 49 | {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, 50 | {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, 51 | {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, 52 | {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, 53 | {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, 54 | {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, 55 | {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, 56 | {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, 57 | {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, 58 | {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, 59 | {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, 60 | {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, 61 | {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, 62 | 63 | {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, 64 | {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, 65 | {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, 66 | {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, 67 | {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, 68 | {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, 69 | 70 | {"{f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, RFC4122, true}, 71 | {"{f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, Invalid, false}, 72 | {"f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, Invalid, false}, 73 | 74 | {"f47ac10b58cc037285670e02b2c3d479", 0, RFC4122, true}, 75 | {"f47ac10b58cc037285670e02b2c3d4790", 0, Invalid, false}, 76 | {"f47ac10b58cc037285670e02b2c3d47", 0, Invalid, false}, 77 | 78 | {"01ee836c-e7c9-619d-929a-525400475911", 6, RFC4122, true}, 79 | {"018bd12c-58b0-7683-8a5b-8752d0e86651", 7, RFC4122, true}, 80 | } 81 | 82 | var constants = []struct { 83 | c interface{} 84 | name string 85 | }{ 86 | {Person, "Person"}, 87 | {Group, "Group"}, 88 | {Org, "Org"}, 89 | {Invalid, "Invalid"}, 90 | {RFC4122, "RFC4122"}, 91 | {Reserved, "Reserved"}, 92 | {Microsoft, "Microsoft"}, 93 | {Future, "Future"}, 94 | {Domain(17), "Domain17"}, 95 | {Variant(42), "BadVariant42"}, 96 | } 97 | 98 | func testTest(t *testing.T, in string, tt test) { 99 | uuid, err := Parse(in) 100 | if ok := (err == nil); ok != tt.isuuid { 101 | t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) 102 | } 103 | if err != nil { 104 | return 105 | } 106 | 107 | if v := uuid.Variant(); v != tt.variant { 108 | t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) 109 | } 110 | if v := uuid.Version(); v != tt.version { 111 | t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) 112 | } 113 | } 114 | 115 | func testBytes(t *testing.T, in []byte, tt test) { 116 | uuid, err := ParseBytes(in) 117 | if ok := (err == nil); ok != tt.isuuid { 118 | t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid) 119 | } 120 | if err != nil { 121 | return 122 | } 123 | suuid, _ := Parse(string(in)) 124 | if uuid != suuid { 125 | t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid) 126 | } 127 | } 128 | 129 | func TestUUID(t *testing.T) { 130 | for _, tt := range tests { 131 | testTest(t, tt.in, tt) 132 | testTest(t, strings.ToUpper(tt.in), tt) 133 | testBytes(t, []byte(tt.in), tt) 134 | } 135 | } 136 | 137 | func TestFromBytes(t *testing.T) { 138 | b := []byte{ 139 | 0x7d, 0x44, 0x48, 0x40, 140 | 0x9d, 0xc0, 141 | 0x11, 0xd1, 142 | 0xb2, 0x45, 143 | 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 144 | } 145 | uuid, err := FromBytes(b) 146 | if err != nil { 147 | t.Fatalf("%s", err) 148 | } 149 | for i := 0; i < len(uuid); i++ { 150 | if b[i] != uuid[i] { 151 | t.Fatalf("FromBytes() got %v expected %v\b", uuid[:], b) 152 | } 153 | } 154 | } 155 | 156 | func TestConstants(t *testing.T) { 157 | for x, tt := range constants { 158 | v, ok := tt.c.(fmt.Stringer) 159 | if !ok { 160 | t.Errorf("%x: %v: not a stringer", x, v) 161 | } else if s := v.String(); s != tt.name { 162 | v, _ := tt.c.(int) 163 | t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name) 164 | } 165 | } 166 | } 167 | 168 | func TestRandomUUID(t *testing.T) { 169 | m := make(map[string]bool) 170 | for x := 1; x < 32; x++ { 171 | uuid := New() 172 | s := uuid.String() 173 | if m[s] { 174 | t.Errorf("NewRandom returned duplicated UUID %s", s) 175 | } 176 | m[s] = true 177 | if v := uuid.Version(); v != 4 { 178 | t.Errorf("Random UUID of version %s", v) 179 | } 180 | if uuid.Variant() != RFC4122 { 181 | t.Errorf("Random UUID is variant %d", uuid.Variant()) 182 | } 183 | } 184 | } 185 | 186 | func TestRandomUUID_Pooled(t *testing.T) { 187 | defer DisableRandPool() 188 | EnableRandPool() 189 | m := make(map[string]bool) 190 | for x := 1; x < 128; x++ { 191 | uuid := New() 192 | s := uuid.String() 193 | if m[s] { 194 | t.Errorf("NewRandom returned duplicated UUID %s", s) 195 | } 196 | m[s] = true 197 | if v := uuid.Version(); v != 4 { 198 | t.Errorf("Random UUID of version %s", v) 199 | } 200 | if uuid.Variant() != RFC4122 { 201 | t.Errorf("Random UUID is variant %d", uuid.Variant()) 202 | } 203 | } 204 | } 205 | 206 | func TestNew(t *testing.T) { 207 | m := make(map[UUID]bool) 208 | for x := 1; x < 32; x++ { 209 | s := New() 210 | if m[s] { 211 | t.Errorf("New returned duplicated UUID %s", s) 212 | } 213 | m[s] = true 214 | uuid, err := Parse(s.String()) 215 | if err != nil { 216 | t.Errorf("New.String() returned %q which does not decode", s) 217 | continue 218 | } 219 | if v := uuid.Version(); v != 4 { 220 | t.Errorf("Random UUID of version %s", v) 221 | } 222 | if uuid.Variant() != RFC4122 { 223 | t.Errorf("Random UUID is variant %d", uuid.Variant()) 224 | } 225 | } 226 | } 227 | 228 | func TestClockSeq(t *testing.T) { 229 | // Fake time.Now for this test to return a monotonically advancing time; restore it at end. 230 | defer func(orig func() time.Time) { timeNow = orig }(timeNow) 231 | monTime := time.Now() 232 | timeNow = func() time.Time { 233 | monTime = monTime.Add(1 * time.Second) 234 | return monTime 235 | } 236 | 237 | SetClockSequence(-1) 238 | uuid1, err := NewUUID() 239 | if err != nil { 240 | t.Fatalf("could not create UUID: %v", err) 241 | } 242 | uuid2, err := NewUUID() 243 | if err != nil { 244 | t.Fatalf("could not create UUID: %v", err) 245 | } 246 | 247 | if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 { 248 | t.Errorf("clock sequence %d != %d", s1, s2) 249 | } 250 | 251 | SetClockSequence(-1) 252 | uuid2, err = NewUUID() 253 | if err != nil { 254 | t.Fatalf("could not create UUID: %v", err) 255 | } 256 | 257 | // Just on the very off chance we generated the same sequence 258 | // two times we try again. 259 | if uuid1.ClockSequence() == uuid2.ClockSequence() { 260 | SetClockSequence(-1) 261 | uuid2, err = NewUUID() 262 | if err != nil { 263 | t.Fatalf("could not create UUID: %v", err) 264 | } 265 | } 266 | if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 { 267 | t.Errorf("Duplicate clock sequence %d", s1) 268 | } 269 | 270 | SetClockSequence(0x1234) 271 | uuid1, err = NewUUID() 272 | if err != nil { 273 | t.Fatalf("could not create UUID: %v", err) 274 | } 275 | if seq := uuid1.ClockSequence(); seq != 0x1234 { 276 | t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq) 277 | } 278 | } 279 | 280 | func TestCoding(t *testing.T) { 281 | text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" 282 | urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" 283 | data := UUID{ 284 | 0x7d, 0x44, 0x48, 0x40, 285 | 0x9d, 0xc0, 286 | 0x11, 0xd1, 287 | 0xb2, 0x45, 288 | 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 289 | } 290 | if v := data.String(); v != text { 291 | t.Errorf("%x: encoded to %s, expected %s", data, v, text) 292 | } 293 | if v := data.URN(); v != urn { 294 | t.Errorf("%x: urn is %s, expected %s", data, v, urn) 295 | } 296 | 297 | uuid, err := Parse(text) 298 | if err != nil { 299 | t.Errorf("Parse returned unexpected error %v", err) 300 | } 301 | if data != uuid { 302 | t.Errorf("%s: decoded to %s, expected %s", text, uuid, data) 303 | } 304 | } 305 | 306 | func TestVersion1(t *testing.T) { 307 | uuid1, err := NewUUID() 308 | if err != nil { 309 | t.Fatalf("could not create UUID: %v", err) 310 | } 311 | uuid2, err := NewUUID() 312 | if err != nil { 313 | t.Fatalf("could not create UUID: %v", err) 314 | } 315 | 316 | if uuid1 == uuid2 { 317 | t.Errorf("%s:duplicate uuid", uuid1) 318 | } 319 | if v := uuid1.Version(); v != 1 { 320 | t.Errorf("%s: version %s expected 1", uuid1, v) 321 | } 322 | if v := uuid2.Version(); v != 1 { 323 | t.Errorf("%s: version %s expected 1", uuid2, v) 324 | } 325 | n1 := uuid1.NodeID() 326 | n2 := uuid2.NodeID() 327 | if !bytes.Equal(n1, n2) { 328 | t.Errorf("Different nodes %x != %x", n1, n2) 329 | } 330 | t1 := uuid1.Time() 331 | t2 := uuid2.Time() 332 | q1 := uuid1.ClockSequence() 333 | q2 := uuid2.ClockSequence() 334 | 335 | switch { 336 | case t1 == t2 && q1 == q2: 337 | t.Error("time stopped") 338 | case t1 > t2 && q1 == q2: 339 | t.Error("time reversed") 340 | case t1 < t2 && q1 != q2: 341 | t.Error("clock sequence changed unexpectedly") 342 | } 343 | } 344 | 345 | func TestNode(t *testing.T) { 346 | // This test is mostly to make sure we don't leave nodeMu locked. 347 | ifname = "" 348 | if ni := NodeInterface(); ni != "" { 349 | t.Errorf("NodeInterface got %q, want %q", ni, "") 350 | } 351 | if SetNodeInterface("xyzzy") { 352 | t.Error("SetNodeInterface succeeded on a bad interface name") 353 | } 354 | if !SetNodeInterface("") { 355 | t.Error("SetNodeInterface failed") 356 | } 357 | if runtime.GOARCH != "js" { 358 | if ni := NodeInterface(); ni == "" { 359 | t.Error("NodeInterface returned an empty string") 360 | } 361 | } 362 | 363 | ni := NodeID() 364 | if len(ni) != 6 { 365 | t.Errorf("ni got %d bytes, want 6", len(ni)) 366 | } 367 | hasData := false 368 | for _, b := range ni { 369 | if b != 0 { 370 | hasData = true 371 | } 372 | } 373 | if !hasData { 374 | t.Error("nodeid is all zeros") 375 | } 376 | 377 | id := []byte{1, 2, 3, 4, 5, 6, 7, 8} 378 | SetNodeID(id) 379 | ni = NodeID() 380 | if !bytes.Equal(ni, id[:6]) { 381 | t.Errorf("got nodeid %v, want %v", ni, id[:6]) 382 | } 383 | 384 | if ni := NodeInterface(); ni != "user" { 385 | t.Errorf("got interface %q, want %q", ni, "user") 386 | } 387 | } 388 | 389 | func TestNodeAndTime(t *testing.T) { 390 | // Time is February 5, 1998 12:30:23.136364800 AM GMT 391 | 392 | uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") 393 | if err != nil { 394 | t.Fatalf("Parser returned unexpected error %v", err) 395 | } 396 | node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} 397 | 398 | ts := uuid.Time() 399 | c := time.Unix(ts.UnixTime()) 400 | want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) 401 | if !c.Equal(want) { 402 | t.Errorf("Got time %v, want %v", c, want) 403 | } 404 | if !bytes.Equal(node, uuid.NodeID()) { 405 | t.Errorf("Expected node %v got %v", node, uuid.NodeID()) 406 | } 407 | } 408 | 409 | func TestMD5(t *testing.T) { 410 | uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String() 411 | want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" 412 | if uuid != want { 413 | t.Errorf("MD5: got %q expected %q", uuid, want) 414 | } 415 | } 416 | 417 | func TestSHA1(t *testing.T) { 418 | uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String() 419 | want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" 420 | if uuid != want { 421 | t.Errorf("SHA1: got %q expected %q", uuid, want) 422 | } 423 | } 424 | 425 | func TestNodeID(t *testing.T) { 426 | nid := []byte{1, 2, 3, 4, 5, 6} 427 | SetNodeInterface("") 428 | s := NodeInterface() 429 | if runtime.GOARCH != "js" { 430 | if s == "" || s == "user" { 431 | t.Errorf("NodeInterface %q after SetInterface", s) 432 | } 433 | } 434 | node1 := NodeID() 435 | if node1 == nil { 436 | t.Error("NodeID nil after SetNodeInterface", s) 437 | } 438 | SetNodeID(nid) 439 | s = NodeInterface() 440 | if s != "user" { 441 | t.Errorf("Expected NodeInterface %q got %q", "user", s) 442 | } 443 | node2 := NodeID() 444 | if node2 == nil { 445 | t.Error("NodeID nil after SetNodeID", s) 446 | } 447 | if bytes.Equal(node1, node2) { 448 | t.Error("NodeID not changed after SetNodeID", s) 449 | } else if !bytes.Equal(nid, node2) { 450 | t.Errorf("NodeID is %x, expected %x", node2, nid) 451 | } 452 | } 453 | 454 | func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) { 455 | if err != nil { 456 | t.Errorf("%s failed: %v", name, err) 457 | return 458 | } 459 | if v := uuid.Version(); v != 2 { 460 | t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v) 461 | return 462 | } 463 | if v := uuid.Domain(); v != domain { 464 | t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v) 465 | } 466 | if v := uuid.ID(); v != id { 467 | t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v) 468 | } 469 | } 470 | 471 | func TestDCE(t *testing.T) { 472 | uuid, err := NewDCESecurity(42, 12345678) 473 | testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678) 474 | uuid, err = NewDCEPerson() 475 | testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid())) 476 | uuid, err = NewDCEGroup() 477 | testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid())) 478 | } 479 | 480 | type badRand struct{} 481 | 482 | func (r badRand) Read(buf []byte) (int, error) { 483 | for i := range buf { 484 | buf[i] = byte(i) 485 | } 486 | return len(buf), nil 487 | } 488 | 489 | func TestBadRand(t *testing.T) { 490 | SetRand(badRand{}) 491 | uuid1 := New() 492 | uuid2 := New() 493 | if uuid1 != uuid2 { 494 | t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2) 495 | } 496 | SetRand(nil) 497 | uuid1 = New() 498 | uuid2 = New() 499 | if uuid1 == uuid2 { 500 | t.Errorf("unexpected duplicates, got %q", uuid1) 501 | } 502 | } 503 | 504 | func TestSetRand(t *testing.T) { 505 | myString := "805-9dd6-1a877cb526c678e71d38-7122-44c0-9b7c-04e7001cc78783ac3e82-47a3-4cc3-9951-13f3339d88088f5d685a-11f7-4078-ada9-de44ad2daeb7" 506 | 507 | SetRand(strings.NewReader(myString)) 508 | uuid1 := New() 509 | uuid2 := New() 510 | 511 | SetRand(strings.NewReader(myString)) 512 | uuid3 := New() 513 | uuid4 := New() 514 | 515 | if uuid1 != uuid3 { 516 | t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) 517 | } 518 | if uuid2 != uuid4 { 519 | t.Errorf("expected duplicates, got %q and %q", uuid2, uuid4) 520 | } 521 | } 522 | 523 | func TestRandomFromReader(t *testing.T) { 524 | myString := "8059ddhdle77cb52" 525 | r := bytes.NewReader([]byte(myString)) 526 | r2 := bytes.NewReader([]byte(myString)) 527 | uuid1, err := NewRandomFromReader(r) 528 | if err != nil { 529 | t.Errorf("failed generating UUID from a reader") 530 | } 531 | _, err = NewRandomFromReader(r) 532 | if err == nil { 533 | t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewRandomFromReader may not be using the provided reader") 534 | } 535 | uuid3, err := NewRandomFromReader(r2) 536 | if err != nil { 537 | t.Errorf("failed generating UUID from a reader") 538 | } 539 | if uuid1 != uuid3 { 540 | t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) 541 | } 542 | } 543 | 544 | func TestRandPool(t *testing.T) { 545 | myString := "8059ddhdle77cb52" 546 | EnableRandPool() 547 | SetRand(strings.NewReader(myString)) 548 | _, err := NewRandom() 549 | if err == nil { 550 | t.Errorf("expecting an error as reader has no more bytes") 551 | } 552 | DisableRandPool() 553 | SetRand(strings.NewReader(myString)) 554 | _, err = NewRandom() 555 | if err != nil { 556 | t.Errorf("failed generating UUID from a reader") 557 | } 558 | } 559 | 560 | func TestWrongLength(t *testing.T) { 561 | _, err := Parse("12345") 562 | if err == nil { 563 | t.Errorf("expected ‘12345’ was invalid") 564 | } else if err.Error() != "invalid UUID length: 5" { 565 | t.Errorf("expected a different error message for an invalid length") 566 | } 567 | } 568 | 569 | func TestIsWrongLength(t *testing.T) { 570 | _, err := Parse("12345") 571 | if !IsInvalidLengthError(err) { 572 | t.Errorf("IsInvalidLength returned incorrect type %T", err) 573 | } 574 | } 575 | 576 | func FuzzParse(f *testing.F) { 577 | for _, tt := range tests { 578 | f.Add(tt.in) 579 | f.Add(strings.ToUpper(tt.in)) 580 | } 581 | f.Fuzz(func(t *testing.T, in string) { 582 | Parse(in) 583 | }) 584 | } 585 | 586 | func FuzzParseBytes(f *testing.F) { 587 | for _, tt := range tests { 588 | f.Add([]byte(tt.in)) 589 | } 590 | f.Fuzz(func(t *testing.T, in []byte) { 591 | ParseBytes(in) 592 | }) 593 | } 594 | 595 | func FuzzFromBytes(f *testing.F) { 596 | // Copied from TestFromBytes. 597 | f.Add([]byte{ 598 | 0x7d, 0x44, 0x48, 0x40, 599 | 0x9d, 0xc0, 600 | 0x11, 0xd1, 601 | 0xb2, 0x45, 602 | 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 603 | }) 604 | f.Fuzz(func(t *testing.T, in []byte) { 605 | FromBytes(in) 606 | }) 607 | } 608 | 609 | // TestValidate checks various scenarios for the Validate function 610 | func TestValidate(t *testing.T) { 611 | testCases := []struct { 612 | name string 613 | input string 614 | expect error 615 | }{ 616 | {"Valid UUID", "123e4567-e89b-12d3-a456-426655440000", nil}, 617 | {"Valid UUID with URN", "urn:uuid:123e4567-e89b-12d3-a456-426655440000", nil}, 618 | {"Valid UUID with Braces", "{123e4567-e89b-12d3-a456-426655440000}", nil}, 619 | {"Valid UUID No Hyphens", "123e4567e89b12d3a456426655440000", nil}, 620 | {"Invalid UUID", "invalid-uuid", errors.New("invalid UUID length: 12")}, 621 | {"Invalid Length", "123", fmt.Errorf("invalid UUID length: %d", len("123"))}, 622 | {"Invalid URN Prefix", "urn:test:123e4567-e89b-12d3-a456-426655440000", fmt.Errorf("invalid urn prefix: %q", "urn:test:")}, 623 | {"Invalid Brackets", "[123e4567-e89b-12d3-a456-426655440000]", fmt.Errorf("invalid bracketed UUID format")}, 624 | {"Invalid UUID Format", "12345678gabc1234abcd1234abcd1234", fmt.Errorf("invalid UUID format")}, 625 | } 626 | 627 | for _, tc := range testCases { 628 | t.Run(tc.name, func(t *testing.T) { 629 | err := Validate(tc.input) 630 | if (err != nil) != (tc.expect != nil) || (err != nil && err.Error() != tc.expect.Error()) { 631 | t.Errorf("Validate(%q) = %v, want %v", tc.input, err, tc.expect) 632 | } 633 | }) 634 | } 635 | } 636 | 637 | var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479" 638 | var asBytes = []byte(asString) 639 | 640 | func BenchmarkParse(b *testing.B) { 641 | for i := 0; i < b.N; i++ { 642 | _, err := Parse(asString) 643 | if err != nil { 644 | b.Fatal(err) 645 | } 646 | } 647 | } 648 | 649 | func BenchmarkParseBytes(b *testing.B) { 650 | for i := 0; i < b.N; i++ { 651 | _, err := ParseBytes(asBytes) 652 | if err != nil { 653 | b.Fatal(err) 654 | } 655 | } 656 | } 657 | 658 | // parseBytesUnsafe is to benchmark using unsafe. 659 | func parseBytesUnsafe(b []byte) (UUID, error) { 660 | return Parse(*(*string)(unsafe.Pointer(&b))) 661 | } 662 | 663 | func BenchmarkParseBytesUnsafe(b *testing.B) { 664 | for i := 0; i < b.N; i++ { 665 | _, err := parseBytesUnsafe(asBytes) 666 | if err != nil { 667 | b.Fatal(err) 668 | } 669 | } 670 | } 671 | 672 | // parseBytesCopy is to benchmark not using unsafe. 673 | func parseBytesCopy(b []byte) (UUID, error) { 674 | return Parse(string(b)) 675 | } 676 | 677 | func BenchmarkParseBytesCopy(b *testing.B) { 678 | for i := 0; i < b.N; i++ { 679 | _, err := parseBytesCopy(asBytes) 680 | if err != nil { 681 | b.Fatal(err) 682 | } 683 | } 684 | } 685 | 686 | func BenchmarkNew(b *testing.B) { 687 | for i := 0; i < b.N; i++ { 688 | New() 689 | } 690 | } 691 | 692 | func BenchmarkUUID_String(b *testing.B) { 693 | uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 694 | if err != nil { 695 | b.Fatal(err) 696 | } 697 | for i := 0; i < b.N; i++ { 698 | if uuid.String() == "" { 699 | b.Fatal("invalid uuid") 700 | } 701 | } 702 | } 703 | 704 | func BenchmarkUUID_URN(b *testing.B) { 705 | uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 706 | if err != nil { 707 | b.Fatal(err) 708 | } 709 | for i := 0; i < b.N; i++ { 710 | if uuid.URN() == "" { 711 | b.Fatal("invalid uuid") 712 | } 713 | } 714 | } 715 | 716 | func BenchmarkParseBadLength(b *testing.B) { 717 | short := asString[:10] 718 | for i := 0; i < b.N; i++ { 719 | _, err := Parse(short) 720 | if err == nil { 721 | b.Fatalf("expected ‘%s’ was invalid", short) 722 | } 723 | } 724 | } 725 | 726 | func BenchmarkParseLen32Truncated(b *testing.B) { 727 | partial := asString[:len(asString)-4] 728 | for i := 0; i < b.N; i++ { 729 | _, err := Parse(partial) 730 | if err == nil { 731 | b.Fatalf("expected ‘%s’ was invalid", partial) 732 | } 733 | } 734 | } 735 | 736 | func BenchmarkParseLen36Corrupted(b *testing.B) { 737 | wrong := asString[:len(asString)-1] + "x" 738 | for i := 0; i < b.N; i++ { 739 | _, err := Parse(wrong) 740 | if err == nil { 741 | b.Fatalf("expected ‘%s’ was invalid", wrong) 742 | } 743 | } 744 | } 745 | 746 | func BenchmarkUUID_New(b *testing.B) { 747 | b.RunParallel(func(pb *testing.PB) { 748 | for pb.Next() { 749 | _, err := NewRandom() 750 | if err != nil { 751 | b.Fatal(err) 752 | } 753 | } 754 | }) 755 | } 756 | 757 | func BenchmarkUUID_NewPooled(b *testing.B) { 758 | EnableRandPool() 759 | b.RunParallel(func(pb *testing.PB) { 760 | for pb.Next() { 761 | _, err := NewRandom() 762 | if err != nil { 763 | b.Fatal(err) 764 | } 765 | } 766 | }) 767 | } 768 | 769 | func BenchmarkUUIDs_Strings(b *testing.B) { 770 | uuid1, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 771 | if err != nil { 772 | b.Fatal(err) 773 | } 774 | uuid2, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") 775 | if err != nil { 776 | b.Fatal(err) 777 | } 778 | uuids := UUIDs{uuid1, uuid2} 779 | for i := 0; i < b.N; i++ { 780 | uuids.Strings() 781 | } 782 | } 783 | 784 | func TestVersion6(t *testing.T) { 785 | uuid1, err := NewV6() 786 | if err != nil { 787 | t.Fatalf("could not create UUID: %v", err) 788 | } 789 | uuid2, err := NewV6() 790 | if err != nil { 791 | t.Fatalf("could not create UUID: %v", err) 792 | } 793 | 794 | if uuid1 == uuid2 { 795 | t.Errorf("%s:duplicate uuid", uuid1) 796 | } 797 | if v := uuid1.Version(); v != 6 { 798 | t.Errorf("%s: version %s expected 6", uuid1, v) 799 | } 800 | if v := uuid2.Version(); v != 6 { 801 | t.Errorf("%s: version %s expected 6", uuid2, v) 802 | } 803 | n1 := uuid1.NodeID() 804 | n2 := uuid2.NodeID() 805 | if !bytes.Equal(n1, n2) { 806 | t.Errorf("Different nodes %x != %x", n1, n2) 807 | } 808 | t1 := uuid1.Time() 809 | t2 := uuid2.Time() 810 | q1 := uuid1.ClockSequence() 811 | q2 := uuid2.ClockSequence() 812 | 813 | switch { 814 | case t1 == t2 && q1 == q2: 815 | t.Error("time stopped") 816 | case t1 > t2 && q1 == q2: 817 | t.Error("time reversed") 818 | case t1 < t2 && q1 != q2: 819 | t.Error("clock sequence changed unexpectedly") 820 | } 821 | } 822 | 823 | // uuid v7 time is only unix milliseconds, so 824 | // uuid1.Time() == uuid2.Time() is right, but uuid1 must != uuid2 825 | func TestVersion7(t *testing.T) { 826 | SetRand(nil) 827 | m := make(map[string]bool) 828 | for x := 1; x < 128; x++ { 829 | uuid, err := NewV7() 830 | if err != nil { 831 | t.Fatalf("could not create UUID: %v", err) 832 | } 833 | s := uuid.String() 834 | if m[s] { 835 | t.Errorf("NewV7 returned duplicated UUID %s", s) 836 | } 837 | m[s] = true 838 | if v := uuid.Version(); v != 7 { 839 | t.Errorf("UUID of version %s", v) 840 | } 841 | if uuid.Variant() != RFC4122 { 842 | t.Errorf("UUID is variant %d", uuid.Variant()) 843 | } 844 | } 845 | } 846 | 847 | // uuid v7 time is only unix milliseconds, so 848 | // uuid1.Time() == uuid2.Time() is right, but uuid1 must != uuid2 849 | func TestVersion7_pooled(t *testing.T) { 850 | SetRand(nil) 851 | EnableRandPool() 852 | defer DisableRandPool() 853 | 854 | m := make(map[string]bool) 855 | for x := 1; x < 128; x++ { 856 | uuid, err := NewV7() 857 | if err != nil { 858 | t.Fatalf("could not create UUID: %v", err) 859 | } 860 | s := uuid.String() 861 | if m[s] { 862 | t.Errorf("NewV7 returned duplicated UUID %s", s) 863 | } 864 | m[s] = true 865 | if v := uuid.Version(); v != 7 { 866 | t.Errorf("UUID of version %s", v) 867 | } 868 | if uuid.Variant() != RFC4122 { 869 | t.Errorf("UUID is variant %d", uuid.Variant()) 870 | } 871 | } 872 | } 873 | 874 | func TestVersion7FromReader(t *testing.T) { 875 | myString := "8059ddhdle77cb52" 876 | r := bytes.NewReader([]byte(myString)) 877 | _, err := NewV7FromReader(r) 878 | if err != nil { 879 | t.Errorf("failed generating UUID from a reader") 880 | } 881 | _, err = NewV7FromReader(r) 882 | if err == nil { 883 | t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewV7FromReader may not be using the provided reader") 884 | } 885 | } 886 | 887 | func TestVersion7Monotonicity(t *testing.T) { 888 | length := 10000 889 | u1 := Must(NewV7()).String() 890 | for i := 0; i < length; i++ { 891 | u2 := Must(NewV7()).String() 892 | if u2 <= u1 { 893 | t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1) 894 | break 895 | } 896 | u1 = u2 897 | } 898 | } 899 | 900 | type fakeRand struct{} 901 | 902 | func (g fakeRand) Read(bs []byte) (int, error) { 903 | for i, _ := range bs { 904 | bs[i] = 0x88 905 | } 906 | return len(bs), nil 907 | } 908 | 909 | func TestVersion7MonotonicityStrict(t *testing.T) { 910 | timeNow = func() time.Time { 911 | return time.Date(2008, 8, 8, 8, 8, 8, 8, time.UTC) 912 | } 913 | defer func() { 914 | timeNow = time.Now 915 | }() 916 | 917 | SetRand(fakeRand{}) 918 | defer SetRand(nil) 919 | 920 | length := 100000 // > 3906 921 | u1 := Must(NewV7()) 922 | for i := 0; i < length; i++ { 923 | u2 := Must(NewV7()) 924 | if Compare(u1, u2) >= 0 { 925 | t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1) 926 | break 927 | } 928 | u1 = u2 929 | } 930 | } 931 | -------------------------------------------------------------------------------- /version1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | ) 10 | 11 | // NewUUID returns a Version 1 UUID based on the current NodeID and clock 12 | // sequence, and the current time. If the NodeID has not been set by SetNodeID 13 | // or SetNodeInterface then it will be set automatically. If the NodeID cannot 14 | // be set NewUUID returns nil. If clock sequence has not been set by 15 | // SetClockSequence then it will be set automatically. If GetTime fails to 16 | // return the current NewUUID returns nil and an error. 17 | // 18 | // In most cases, New should be used. 19 | func NewUUID() (UUID, error) { 20 | var uuid UUID 21 | now, seq, err := GetTime() 22 | if err != nil { 23 | return uuid, err 24 | } 25 | 26 | timeLow := uint32(now & 0xffffffff) 27 | timeMid := uint16((now >> 32) & 0xffff) 28 | timeHi := uint16((now >> 48) & 0x0fff) 29 | timeHi |= 0x1000 // Version 1 30 | 31 | binary.BigEndian.PutUint32(uuid[0:], timeLow) 32 | binary.BigEndian.PutUint16(uuid[4:], timeMid) 33 | binary.BigEndian.PutUint16(uuid[6:], timeHi) 34 | binary.BigEndian.PutUint16(uuid[8:], seq) 35 | 36 | nodeMu.Lock() 37 | if nodeID == zeroID { 38 | setNodeInterface("") 39 | } 40 | copy(uuid[10:], nodeID[:]) 41 | nodeMu.Unlock() 42 | 43 | return uuid, nil 44 | } 45 | -------------------------------------------------------------------------------- /version4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import "io" 8 | 9 | // New creates a new random UUID or panics. New is equivalent to 10 | // the expression 11 | // 12 | // uuid.Must(uuid.NewRandom()) 13 | func New() UUID { 14 | return Must(NewRandom()) 15 | } 16 | 17 | // NewString creates a new random UUID and returns it as a string or panics. 18 | // NewString is equivalent to the expression 19 | // 20 | // uuid.New().String() 21 | func NewString() string { 22 | return Must(NewRandom()).String() 23 | } 24 | 25 | // NewRandom returns a Random (Version 4) UUID. 26 | // 27 | // The strength of the UUIDs is based on the strength of the crypto/rand 28 | // package. 29 | // 30 | // Uses the randomness pool if it was enabled with EnableRandPool. 31 | // 32 | // A note about uniqueness derived from the UUID Wikipedia entry: 33 | // 34 | // Randomly generated UUIDs have 122 random bits. One's annual risk of being 35 | // hit by a meteorite is estimated to be one chance in 17 billion, that 36 | // means the probability is about 0.00000000006 (6 × 10−11), 37 | // equivalent to the odds of creating a few tens of trillions of UUIDs in a 38 | // year and having one duplicate. 39 | func NewRandom() (UUID, error) { 40 | if !poolEnabled { 41 | return NewRandomFromReader(rander) 42 | } 43 | return newRandomFromPool() 44 | } 45 | 46 | // NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. 47 | func NewRandomFromReader(r io.Reader) (UUID, error) { 48 | var uuid UUID 49 | _, err := io.ReadFull(r, uuid[:]) 50 | if err != nil { 51 | return Nil, err 52 | } 53 | uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 54 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 55 | return uuid, nil 56 | } 57 | 58 | func newRandomFromPool() (UUID, error) { 59 | var uuid UUID 60 | poolMu.Lock() 61 | if poolPos == randPoolSize { 62 | _, err := io.ReadFull(rander, pool[:]) 63 | if err != nil { 64 | poolMu.Unlock() 65 | return Nil, err 66 | } 67 | poolPos = 0 68 | } 69 | copy(uuid[:], pool[poolPos:(poolPos+16)]) 70 | poolPos += 16 71 | poolMu.Unlock() 72 | 73 | uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 74 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 75 | return uuid, nil 76 | } 77 | -------------------------------------------------------------------------------- /version6.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | "time" 10 | ) 11 | 12 | // UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. 13 | // It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. 14 | // Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. 15 | // 16 | // see https://datatracker.ietf.org/doc/html/rfc9562#uuidv6 17 | // 18 | // NewV6 returns a Version 6 UUID based on the current NodeID and clock 19 | // sequence, and the current time. If the NodeID has not been set by SetNodeID 20 | // or SetNodeInterface then it will be set automatically. If the NodeID cannot 21 | // be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by 22 | // SetClockSequence then it will be set automatically. If GetTime fails to 23 | // return the current NewV6 returns Nil and an error. 24 | func NewV6() (UUID, error) { 25 | now, seq, err := GetTime() 26 | if err != nil { 27 | return Nil, err 28 | } 29 | return generateV6(now, seq), nil 30 | } 31 | 32 | // NewV6WithTime returns a Version 6 UUID based on the current NodeID, clock 33 | // sequence, and a specified time. It is similar to the NewV6 function, but allows 34 | // you to specify the time. If time is passed as nil, then the current time is used. 35 | // 36 | // There is a limit on how many UUIDs can be generated for the same time, so if you 37 | // are generating multiple UUIDs, it is recommended to increment the time. 38 | // If getTime fails to return the current NewV6WithTime returns Nil and an error. 39 | func NewV6WithTime(customTime *time.Time) (UUID, error) { 40 | now, seq, err := getTime(customTime) 41 | if err != nil { 42 | return Nil, err 43 | } 44 | 45 | return generateV6(now, seq), nil 46 | } 47 | 48 | func generateV6(now Time, seq uint16) UUID { 49 | var uuid UUID 50 | 51 | /* 52 | 0 1 2 3 53 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 54 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 55 | | time_high | 56 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 | | time_mid | time_low_and_version | 58 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 | |clk_seq_hi_res | clk_seq_low | node (0-1) | 60 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61 | | node (2-5) | 62 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 | */ 64 | 65 | timeHigh := uint32((now >> 28) & 0xffffffff) 66 | timeMid := uint16((now >> 12) & 0xffff) 67 | timeLow := uint16(now & 0x0fff) 68 | timeLow |= 0x6000 // Version 6 69 | 70 | binary.BigEndian.PutUint32(uuid[0:], timeHigh) 71 | binary.BigEndian.PutUint16(uuid[4:], timeMid) 72 | binary.BigEndian.PutUint16(uuid[6:], timeLow) 73 | binary.BigEndian.PutUint16(uuid[8:], seq) 74 | 75 | nodeMu.Lock() 76 | if nodeID == zeroID { 77 | setNodeInterface("") 78 | } 79 | copy(uuid[10:], nodeID[:]) 80 | nodeMu.Unlock() 81 | 82 | return uuid 83 | } 84 | -------------------------------------------------------------------------------- /version6_test.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestNewV6WithTime(t *testing.T) { 9 | testCases := map[string]string{ 10 | "test with current date": time.Now().Format(time.RFC3339), // now 11 | "test with past date": time.Now().Add(-1 * time.Hour * 24 * 365).Format(time.RFC3339), // 1 year ago 12 | "test with future date": time.Now().Add(time.Hour * 24 * 365).Format(time.RFC3339), // 1 year from now 13 | "test with different timezone": "2021-09-01T12:00:00+04:00", 14 | "test with negative timezone": "2021-09-01T12:00:00-12:00", 15 | "test with future date in different timezone": "2124-09-23T12:43:30+09:00", 16 | } 17 | 18 | for testName, inputTime := range testCases { 19 | t.Run(testName, func(t *testing.T) { 20 | customTime, err := time.Parse(time.RFC3339, inputTime) 21 | if err != nil { 22 | t.Errorf("time.Parse returned unexpected error %v", err) 23 | } 24 | id, err := NewV6WithTime(&customTime) 25 | if err != nil { 26 | t.Errorf("NewV6WithTime returned unexpected error %v", err) 27 | } 28 | 29 | if id.Version() != 6 { 30 | t.Errorf("got %d, want version 6", id.Version()) 31 | } 32 | unixTime := time.Unix(id.Time().UnixTime()) 33 | // Compare the times in UTC format, since the input time might have different timezone, 34 | // and the result is always in system timezone 35 | if customTime.UTC().Format(time.RFC3339) != unixTime.UTC().Format(time.RFC3339) { 36 | t.Errorf("got %s, want %s", unixTime.Format(time.RFC3339), customTime.Format(time.RFC3339)) 37 | } 38 | }) 39 | } 40 | } 41 | 42 | func TestNewV6FromTimeGeneratesUniqueUUIDs(t *testing.T) { 43 | now := time.Now() 44 | ids := make([]string, 0) 45 | runs := 26000 46 | 47 | for i := 0; i < runs; i++ { 48 | now = now.Add(time.Nanosecond) // Without this line, we can generate only 16384 UUIDs for the same timestamp 49 | id, err := NewV6WithTime(&now) 50 | if err != nil { 51 | t.Errorf("NewV6WithTime returned unexpected error %v", err) 52 | } 53 | if id.Version() != 6 { 54 | t.Errorf("got %d, want version 6", id.Version()) 55 | } 56 | 57 | // Make sure we add only unique values 58 | if !contains(t, ids, id.String()) { 59 | ids = append(ids, id.String()) 60 | } 61 | } 62 | 63 | // Check we added all the UIDs 64 | if len(ids) != runs { 65 | t.Errorf("got %d UUIDs, want %d", len(ids), runs) 66 | } 67 | } 68 | 69 | func BenchmarkNewV6WithTime(b *testing.B) { 70 | b.RunParallel(func(pb *testing.PB) { 71 | for pb.Next() { 72 | now := time.Now() 73 | _, err := NewV6WithTime(&now) 74 | if err != nil { 75 | b.Fatal(err) 76 | } 77 | } 78 | }) 79 | } 80 | 81 | func contains(t *testing.T, arr []string, str string) bool { 82 | t.Helper() 83 | 84 | for _, a := range arr { 85 | if a == str { 86 | return true 87 | } 88 | } 89 | 90 | return false 91 | } 92 | -------------------------------------------------------------------------------- /version7.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "io" 9 | ) 10 | 11 | // UUID version 7 features a time-ordered value field derived from the widely 12 | // implemented and well known Unix Epoch timestamp source, 13 | // the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. 14 | // As well as improved entropy characteristics over versions 1 or 6. 15 | // 16 | // see https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-7 17 | // 18 | // Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. 19 | // 20 | // NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). 21 | // Uses the randomness pool if it was enabled with EnableRandPool. 22 | // On error, NewV7 returns Nil and an error 23 | func NewV7() (UUID, error) { 24 | uuid, err := NewRandom() 25 | if err != nil { 26 | return uuid, err 27 | } 28 | makeV7(uuid[:]) 29 | return uuid, nil 30 | } 31 | 32 | // NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). 33 | // it use NewRandomFromReader fill random bits. 34 | // On error, NewV7FromReader returns Nil and an error. 35 | func NewV7FromReader(r io.Reader) (UUID, error) { 36 | uuid, err := NewRandomFromReader(r) 37 | if err != nil { 38 | return uuid, err 39 | } 40 | 41 | makeV7(uuid[:]) 42 | return uuid, nil 43 | } 44 | 45 | // makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) 46 | // uuid[8] already has the right version number (Variant is 10) 47 | // see function NewV7 and NewV7FromReader 48 | func makeV7(uuid []byte) { 49 | /* 50 | 0 1 2 3 51 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 52 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 53 | | unix_ts_ms | 54 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 55 | | unix_ts_ms | ver | rand_a (12 bit seq) | 56 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 | |var| rand_b | 58 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 | | rand_b | 60 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61 | */ 62 | _ = uuid[15] // bounds check 63 | 64 | t, s := getV7Time() 65 | 66 | uuid[0] = byte(t >> 40) 67 | uuid[1] = byte(t >> 32) 68 | uuid[2] = byte(t >> 24) 69 | uuid[3] = byte(t >> 16) 70 | uuid[4] = byte(t >> 8) 71 | uuid[5] = byte(t) 72 | 73 | uuid[6] = 0x70 | (0x0F & byte(s>>8)) 74 | uuid[7] = byte(s) 75 | } 76 | 77 | // lastV7time is the last time we returned stored as: 78 | // 79 | // 52 bits of time in milliseconds since epoch 80 | // 12 bits of (fractional nanoseconds) >> 8 81 | var lastV7time int64 82 | 83 | const nanoPerMilli = 1000000 84 | 85 | // getV7Time returns the time in milliseconds and nanoseconds / 256. 86 | // The returned (milli << 12 + seq) is guaranteed to be greater than 87 | // (milli << 12 + seq) returned by any previous call to getV7Time. 88 | func getV7Time() (milli, seq int64) { 89 | timeMu.Lock() 90 | defer timeMu.Unlock() 91 | 92 | nano := timeNow().UnixNano() 93 | milli = nano / nanoPerMilli 94 | // Sequence number is between 0 and 3906 (nanoPerMilli>>8) 95 | seq = (nano - milli*nanoPerMilli) >> 8 96 | now := milli<<12 + seq 97 | if now <= lastV7time { 98 | now = lastV7time + 1 99 | milli = now >> 12 100 | seq = now & 0xfff 101 | } 102 | lastV7time = now 103 | return milli, seq 104 | } 105 | --------------------------------------------------------------------------------