pax_global_header00006660000000000000000000000064145540055140014515gustar00rootroot0000000000000052 comment=0f11ee6918f41a04c201eceeadf612a377bc7fbc uuid-1.6.0/000077500000000000000000000000001455400551400124675ustar00rootroot00000000000000uuid-1.6.0/.github/000077500000000000000000000000001455400551400140275ustar00rootroot00000000000000uuid-1.6.0/.github/CODEOWNERS000066400000000000000000000004111455400551400154160ustar00rootroot00000000000000# Code owners file. # This file controls who is tagged for review for any given pull request. # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax * @google/go-uuid-contributors uuid-1.6.0/.github/release-please.yml000066400000000000000000000000461455400551400174410ustar00rootroot00000000000000handleGHRelease: true releaseType: go uuid-1.6.0/.github/workflows/000077500000000000000000000000001455400551400160645ustar00rootroot00000000000000uuid-1.6.0/.github/workflows/apidiff.yaml000066400000000000000000000011111455400551400203440ustar00rootroot00000000000000--- name: apidiff on: pull_request: branches: - master permissions: contents: read jobs: compat: runs-on: ubuntu-latest steps: - uses: actions/setup-go@v4 with: go-version: 1.21 - run: go install golang.org/x/exp/cmd/apidiff@latest - uses: actions/checkout@v3 with: ref: master - run: apidiff -w uuid.baseline . - uses: actions/checkout@v3 with: clean: false - run: | apidiff -incompatible uuid.baseline . > diff.txt cat diff.txt && ! [ -s diff.txt ] uuid-1.6.0/.github/workflows/tests.yaml000066400000000000000000000005751455400551400201210ustar00rootroot00000000000000--- name: tests on: pull_request: branches: - master permissions: contents: read jobs: unit-tests: strategy: matrix: go-version: [1.19, 1.20.x, 1.21] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 with: go-version: ${{ matrix.go-version }} - run: go test -v ./... uuid-1.6.0/CHANGELOG.md000066400000000000000000000031601455400551400143000ustar00rootroot00000000000000# Changelog ## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) ### Features * add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) ### Bug Fixes * fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) * Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) ## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) ### Features * Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) ## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) ### Features * UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) ### Fixes * Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) ## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) ### Bug Fixes * Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) ## Changelog uuid-1.6.0/CONTRIBUTING.md000066400000000000000000000016741455400551400147300ustar00rootroot00000000000000# How to contribute We definitely welcome patches and contribution to this project! ### Tips Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). Always try to include a test case! If it is not possible or not necessary, please explain why in the pull request description. ### Releasing Commits that would precipitate a SemVer change, as described in the Conventional Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) to create a release candidate pull request. Once submitted, `release-please` will create a release. For tips on how to work with `release-please`, see its documentation. ### Legal requirements In order to protect both you and ourselves, you will need to sign the [Contributor License Agreement](https://cla.developers.google.com/clas). You may have already signed it for other Google projects. uuid-1.6.0/CONTRIBUTORS000066400000000000000000000001511455400551400143440ustar00rootroot00000000000000Paul Borman bmatsuo shawnps theory jboverfelt dsymonds cd1 wallclockbuilder dansouza uuid-1.6.0/LICENSE000066400000000000000000000027101455400551400134740ustar00rootroot00000000000000Copyright (c) 2009,2014 Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. uuid-1.6.0/README.md000066400000000000000000000015071455400551400137510ustar00rootroot00000000000000# uuid The uuid package generates and inspects UUIDs based on [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) and DCE 1.1: Authentication and Security Services. This package is based on the github.com/pborman/uuid package (previously named code.google.com/p/go-uuid). It differs from these earlier packages in that a UUID is a 16 byte array rather than a byte slice. One loss due to this change is the ability to represent an invalid UUID (vs a NIL UUID). ###### Install ```sh go get github.com/google/uuid ``` ###### Documentation [![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here: http://pkg.go.dev/github.com/google/uuid uuid-1.6.0/dce.go000066400000000000000000000040301455400551400135460ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "encoding/binary" "fmt" "os" ) // A Domain represents a Version 2 domain type Domain byte // Domain constants for DCE Security (Version 2) UUIDs. const ( Person = Domain(0) Group = Domain(1) Org = Domain(2) ) // NewDCESecurity returns a DCE Security (Version 2) UUID. // // The domain should be one of Person, Group or Org. // On a POSIX system the id should be the users UID for the Person // domain and the users GID for the Group. The meaning of id for // the domain Org or on non-POSIX systems is site defined. // // For a given domain/id pair the same token may be returned for up to // 7 minutes and 10 seconds. func NewDCESecurity(domain Domain, id uint32) (UUID, error) { uuid, err := NewUUID() if err == nil { uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 uuid[9] = byte(domain) binary.BigEndian.PutUint32(uuid[0:], id) } return uuid, err } // NewDCEPerson returns a DCE Security (Version 2) UUID in the person // domain with the id returned by os.Getuid. // // NewDCESecurity(Person, uint32(os.Getuid())) func NewDCEPerson() (UUID, error) { return NewDCESecurity(Person, uint32(os.Getuid())) } // NewDCEGroup returns a DCE Security (Version 2) UUID in the group // domain with the id returned by os.Getgid. // // NewDCESecurity(Group, uint32(os.Getgid())) func NewDCEGroup() (UUID, error) { return NewDCESecurity(Group, uint32(os.Getgid())) } // Domain returns the domain for a Version 2 UUID. Domains are only defined // for Version 2 UUIDs. func (uuid UUID) Domain() Domain { return Domain(uuid[9]) } // ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 // UUIDs. func (uuid UUID) ID() uint32 { return binary.BigEndian.Uint32(uuid[0:4]) } func (d Domain) String() string { switch d { case Person: return "Person" case Group: return "Group" case Org: return "Org" } return fmt.Sprintf("Domain%d", int(d)) } uuid-1.6.0/doc.go000066400000000000000000000006271455400551400135700ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package uuid generates and inspects UUIDs. // // UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security // Services. // // A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to // maps or compared directly. package uuid uuid-1.6.0/go.mod000066400000000000000000000000361455400551400135740ustar00rootroot00000000000000module github.com/google/uuid uuid-1.6.0/hash.go000066400000000000000000000036531455400551400137500ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "crypto/md5" "crypto/sha1" "hash" ) // Well known namespace IDs and UUIDs var ( NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) Nil UUID // empty UUID, all zeros // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. Max = UUID{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } ) // NewHash returns a new UUID derived from the hash of space concatenated with // data generated by h. The hash should be at least 16 byte in length. The // first 16 bytes of the hash are used to form the UUID. The version of the // UUID will be the lower 4 bits of version. NewHash is used to implement // NewMD5 and NewSHA1. func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { h.Reset() h.Write(space[:]) //nolint:errcheck h.Write(data) //nolint:errcheck s := h.Sum(nil) var uuid UUID copy(uuid[:], s) uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant return uuid } // NewMD5 returns a new MD5 (Version 3) UUID based on the // supplied name space and data. It is the same as calling: // // NewHash(md5.New(), space, data, 3) func NewMD5(space UUID, data []byte) UUID { return NewHash(md5.New(), space, data, 3) } // NewSHA1 returns a new SHA1 (Version 5) UUID based on the // supplied name space and data. It is the same as calling: // // NewHash(sha1.New(), space, data, 5) func NewSHA1(space UUID, data []byte) UUID { return NewHash(sha1.New(), space, data, 5) } uuid-1.6.0/json_test.go000066400000000000000000000046651455400551400150410ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "encoding/json" "reflect" "testing" ) var testUUID = Must(Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")) func TestJSON(t *testing.T) { type S struct { ID1 UUID ID2 UUID } s1 := S{ID1: testUUID} data, err := json.Marshal(&s1) if err != nil { t.Fatal(err) } var s2 S if err := json.Unmarshal(data, &s2); err != nil { t.Fatal(err) } if !reflect.DeepEqual(&s1, &s2) { t.Errorf("got %#v, want %#v", s2, s1) } } func TestJSONUnmarshal(t *testing.T) { type S struct { ID1 UUID ID2 UUID `json:"ID2,omitempty"` } testCases := map[string]struct { data []byte expectedError error expectedResult UUID }{ "success": { data: []byte(`{"ID1": "f47ac10b-58cc-0372-8567-0e02b2c3d479"}`), expectedError: nil, expectedResult: testUUID, }, "zero": { data: []byte(`{"ID1": "00000000-0000-0000-0000-000000000000"}`), expectedError: nil, expectedResult: Nil, }, "null": { data: []byte(`{"ID1": null}`), expectedError: nil, expectedResult: Nil, }, "empty": { data: []byte(`{"ID1": ""}`), expectedError: invalidLengthError{len: 0}, expectedResult: Nil, }, "omitempty": { data: []byte(`{"ID2": ""}`), expectedError: invalidLengthError{len: 0}, expectedResult: Nil, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { var s S if err := json.Unmarshal(tc.data, &s); err != tc.expectedError { t.Errorf("unexpected error: got %v, want %v", err, tc.expectedError) } if !reflect.DeepEqual(s.ID1, tc.expectedResult) { t.Errorf("got %#v, want %#v", s.ID1, tc.expectedResult) } }) } } func BenchmarkUUID_MarshalJSON(b *testing.B) { x := &struct { UUID UUID `json:"uuid"` }{} var err error x.UUID, err = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { js, err := json.Marshal(x) if err != nil { b.Fatalf("marshal json: %#v (%v)", js, err) } } } func BenchmarkUUID_UnmarshalJSON(b *testing.B) { js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`) var x *struct { UUID UUID `json:"uuid"` } for i := 0; i < b.N; i++ { err := json.Unmarshal(js, &x) if err != nil { b.Fatalf("marshal json: %#v (%v)", js, err) } } } uuid-1.6.0/marshal.go000066400000000000000000000016131455400551400144460ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import "fmt" // MarshalText implements encoding.TextMarshaler. func (uuid UUID) MarshalText() ([]byte, error) { var js [36]byte encodeHex(js[:], uuid) return js[:], nil } // UnmarshalText implements encoding.TextUnmarshaler. func (uuid *UUID) UnmarshalText(data []byte) error { id, err := ParseBytes(data) if err != nil { return err } *uuid = id return nil } // MarshalBinary implements encoding.BinaryMarshaler. func (uuid UUID) MarshalBinary() ([]byte, error) { return uuid[:], nil } // UnmarshalBinary implements encoding.BinaryUnmarshaler. func (uuid *UUID) UnmarshalBinary(data []byte) error { if len(data) != 16 { return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) } copy(uuid[:], data) return nil } uuid-1.6.0/node.go000066400000000000000000000044231455400551400137460ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "sync" ) var ( nodeMu sync.Mutex ifname string // name of interface being used nodeID [6]byte // hardware for version 1 UUIDs zeroID [6]byte // nodeID with only 0's ) // NodeInterface returns the name of the interface from which the NodeID was // derived. The interface "user" is returned if the NodeID was set by // SetNodeID. func NodeInterface() string { defer nodeMu.Unlock() nodeMu.Lock() return ifname } // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. // If name is "" then the first usable interface found will be used or a random // Node ID will be generated. If a named interface cannot be found then false // is returned. // // SetNodeInterface never fails when name is "". func SetNodeInterface(name string) bool { defer nodeMu.Unlock() nodeMu.Lock() return setNodeInterface(name) } func setNodeInterface(name string) bool { iname, addr := getHardwareInterface(name) // null implementation for js if iname != "" && addr != nil { ifname = iname copy(nodeID[:], addr) return true } // We found no interfaces with a valid hardware address. If name // does not specify a specific interface generate a random Node ID // (section 4.1.6) if name == "" { ifname = "random" randomBits(nodeID[:]) return true } return false } // NodeID returns a slice of a copy of the current Node ID, setting the Node ID // if not already set. func NodeID() []byte { defer nodeMu.Unlock() nodeMu.Lock() if nodeID == zeroID { setNodeInterface("") } nid := nodeID return nid[:] } // SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes // of id are used. If id is less than 6 bytes then false is returned and the // Node ID is not set. func SetNodeID(id []byte) bool { if len(id) < 6 { return false } defer nodeMu.Unlock() nodeMu.Lock() copy(nodeID[:], id) ifname = "user" return true } // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is // not valid. The NodeID is only well defined for version 1 and 2 UUIDs. func (uuid UUID) NodeID() []byte { var node [6]byte copy(node[:], uuid[10:]) return node[:] } uuid-1.6.0/node_js.go000066400000000000000000000007621455400551400144440ustar00rootroot00000000000000// Copyright 2017 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build js package uuid // getHardwareInterface returns nil values for the JS version of the code. // This removes the "net" dependency, because it is not used in the browser. // Using the "net" library inflates the size of the transpiled JS code by 673k bytes. func getHardwareInterface(name string) (string, []byte) { return "", nil } uuid-1.6.0/node_net.go000066400000000000000000000016651455400551400146210ustar00rootroot00000000000000// Copyright 2017 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !js package uuid import "net" var interfaces []net.Interface // cached list of interfaces // getHardwareInterface returns the name and hardware address of interface name. // If name is "" then the name and hardware address of one of the system's // interfaces is returned. If no interfaces are found (name does not exist or // there are no interfaces) then "", nil is returned. // // Only addresses of at least 6 bytes are returned. func getHardwareInterface(name string) (string, []byte) { if interfaces == nil { var err error interfaces, err = net.Interfaces() if err != nil { return "", nil } } for _, ifs := range interfaces { if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { return ifs.Name, ifs.HardwareAddr } } return "", nil } uuid-1.6.0/null.go000066400000000000000000000046351455400551400140000ustar00rootroot00000000000000// Copyright 2021 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "bytes" "database/sql/driver" "encoding/json" "fmt" ) var jsonNull = []byte("null") // NullUUID represents a UUID that may be null. // NullUUID implements the SQL driver.Scanner interface so // it can be used as a scan destination: // // var u uuid.NullUUID // err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) // ... // if u.Valid { // // use u.UUID // } else { // // NULL value // } // type NullUUID struct { UUID UUID Valid bool // Valid is true if UUID is not NULL } // Scan implements the SQL driver.Scanner interface. func (nu *NullUUID) Scan(value interface{}) error { if value == nil { nu.UUID, nu.Valid = Nil, false return nil } err := nu.UUID.Scan(value) if err != nil { nu.Valid = false return err } nu.Valid = true return nil } // Value implements the driver Valuer interface. func (nu NullUUID) Value() (driver.Value, error) { if !nu.Valid { return nil, nil } // Delegate to UUID Value function return nu.UUID.Value() } // MarshalBinary implements encoding.BinaryMarshaler. func (nu NullUUID) MarshalBinary() ([]byte, error) { if nu.Valid { return nu.UUID[:], nil } return []byte(nil), nil } // UnmarshalBinary implements encoding.BinaryUnmarshaler. func (nu *NullUUID) UnmarshalBinary(data []byte) error { if len(data) != 16 { return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) } copy(nu.UUID[:], data) nu.Valid = true return nil } // MarshalText implements encoding.TextMarshaler. func (nu NullUUID) MarshalText() ([]byte, error) { if nu.Valid { return nu.UUID.MarshalText() } return jsonNull, nil } // UnmarshalText implements encoding.TextUnmarshaler. func (nu *NullUUID) UnmarshalText(data []byte) error { id, err := ParseBytes(data) if err != nil { nu.Valid = false return err } nu.UUID = id nu.Valid = true return nil } // MarshalJSON implements json.Marshaler. func (nu NullUUID) MarshalJSON() ([]byte, error) { if nu.Valid { return json.Marshal(nu.UUID) } return jsonNull, nil } // UnmarshalJSON implements json.Unmarshaler. func (nu *NullUUID) UnmarshalJSON(data []byte) error { if bytes.Equal(data, jsonNull) { *nu = NullUUID{} return nil // valid null UUID } err := json.Unmarshal(data, &nu.UUID) nu.Valid = err == nil return err } uuid-1.6.0/null_test.go000066400000000000000000000116611455400551400150340ustar00rootroot00000000000000// Copyright 2021 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "bytes" "encoding/json" "testing" ) func TestNullUUIDScan(t *testing.T) { var u UUID var nu NullUUID uNilErr := u.Scan(nil) nuNilErr := nu.Scan(nil) if uNilErr != nil && nuNilErr != nil && uNilErr.Error() != nuNilErr.Error() { t.Errorf("expected errors to be equal, got %s, %s", uNilErr, nuNilErr) } uInvalidStringErr := u.Scan("test") nuInvalidStringErr := nu.Scan("test") if uInvalidStringErr != nil && nuInvalidStringErr != nil && uInvalidStringErr.Error() != nuInvalidStringErr.Error() { t.Errorf("expected errors to be equal, got %s, %s", uInvalidStringErr, nuInvalidStringErr) } valid := "12345678-abcd-1234-abcd-0123456789ab" uValidErr := u.Scan(valid) nuValidErr := nu.Scan(valid) if uValidErr != nuValidErr { t.Errorf("expected errors to be equal, got %s, %s", uValidErr, nuValidErr) } } func TestNullUUIDValue(t *testing.T) { var u UUID var nu NullUUID nuValue, nuErr := nu.Value() if nuErr != nil { t.Errorf("expected nil err, got err %s", nuErr) } if nuValue != nil { t.Errorf("expected nil value, got non-nil %s", nuValue) } u = MustParse("12345678-abcd-1234-abcd-0123456789ab") nu = NullUUID{ UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), Valid: true, } uValue, uErr := u.Value() nuValue, nuErr = nu.Value() if uErr != nil { t.Errorf("expected nil err, got err %s", uErr) } if nuErr != nil { t.Errorf("expected nil err, got err %s", nuErr) } if uValue != nuValue { t.Errorf("expected uuid %s and nulluuid %s to be equal ", uValue, nuValue) } } func TestNullUUIDMarshalText(t *testing.T) { tests := []struct { nullUUID NullUUID }{ { nullUUID: NullUUID{}, }, { nullUUID: NullUUID{ UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), Valid: true, }, }, } for _, test := range tests { var uText []byte var uErr error nuText, nuErr := test.nullUUID.MarshalText() if test.nullUUID.Valid { uText, uErr = test.nullUUID.UUID.MarshalText() } else { uText = []byte("null") } if nuErr != uErr { t.Errorf("expected error %e, got %e", nuErr, uErr) } if !bytes.Equal(nuText, uText) { t.Errorf("expected text data %s, got %s", string(nuText), string(uText)) } } } func TestNullUUIDUnmarshalText(t *testing.T) { tests := []struct { nullUUID NullUUID }{ { nullUUID: NullUUID{}, }, { nullUUID: NullUUID{ UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), Valid: true, }, }, } for _, test := range tests { var uText []byte var uErr error nuText, nuErr := test.nullUUID.MarshalText() if test.nullUUID.Valid { uText, uErr = test.nullUUID.UUID.MarshalText() } else { uText = []byte("null") } if nuErr != uErr { t.Errorf("expected error %e, got %e", nuErr, uErr) } if !bytes.Equal(nuText, uText) { t.Errorf("expected text data %s, got %s", string(nuText), string(uText)) } } } func TestNullUUIDMarshalBinary(t *testing.T) { tests := []struct { nullUUID NullUUID }{ { nullUUID: NullUUID{}, }, { nullUUID: NullUUID{ UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), Valid: true, }, }, } for _, test := range tests { var uBinary []byte var uErr error nuBinary, nuErr := test.nullUUID.MarshalBinary() if test.nullUUID.Valid { uBinary, uErr = test.nullUUID.UUID.MarshalBinary() } else { uBinary = []byte(nil) } if nuErr != uErr { t.Errorf("expected error %e, got %e", nuErr, uErr) } if !bytes.Equal(nuBinary, uBinary) { t.Errorf("expected binary data %s, got %s", string(nuBinary), string(uBinary)) } } } func TestNullUUIDMarshalJSON(t *testing.T) { jsonNull, _ := json.Marshal(nil) jsonUUID, _ := json.Marshal(MustParse("12345678-abcd-1234-abcd-0123456789ab")) tests := []struct { nullUUID NullUUID expected []byte expectedErr error }{ { nullUUID: NullUUID{}, expected: jsonNull, expectedErr: nil, }, { nullUUID: NullUUID{ UUID: MustParse(string(jsonUUID)), Valid: true, }, expected: []byte(`"12345678-abcd-1234-abcd-0123456789ab"`), expectedErr: nil, }, } for _, test := range tests { data, err := json.Marshal(&test.nullUUID) if err != test.expectedErr { t.Errorf("expected error %e, got %e", test.expectedErr, err) } if !bytes.Equal(data, test.expected) { t.Errorf("expected json data %s, got %s", string(test.expected), string(data)) } } } func TestNullUUIDUnmarshalJSON(t *testing.T) { jsonNull, _ := json.Marshal(nil) jsonUUID, _ := json.Marshal(MustParse("12345678-abcd-1234-abcd-0123456789ab")) var nu NullUUID err := json.Unmarshal(jsonNull, &nu) if err != nil || nu.Valid { t.Errorf("expected nil when unmarshaling null, got %s", err) } err = json.Unmarshal(jsonUUID, &nu) if err != nil || !nu.Valid { t.Errorf("expected nil when unmarshaling null, got %s", err) } } uuid-1.6.0/seq_test.go000066400000000000000000000026431455400551400146520ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "flag" "runtime" "testing" "time" ) // This test is only run when --regressions is passed on the go test line. var regressions = flag.Bool("regressions", false, "run uuid regression tests") // TestClockSeqRace tests for a particular race condition of returning two // identical Version1 UUIDs. The duration of 1 minute was chosen as the race // condition, before being fixed, nearly always occurred in under 30 seconds. func TestClockSeqRace(t *testing.T) { if !*regressions { t.Skip("skipping regression tests") } duration := time.Minute done := make(chan struct{}) defer close(done) ch := make(chan UUID, 10000) ncpu := runtime.NumCPU() switch ncpu { case 0, 1: // We can't run the test effectively. t.Skip("skipping race test, only one CPU detected") return default: runtime.GOMAXPROCS(ncpu) } for i := 0; i < ncpu; i++ { go func() { for { select { case <-done: return case ch <- Must(NewUUID()): } } }() } uuids := make(map[string]bool) cnt := 0 start := time.Now() for u := range ch { s := u.String() if uuids[s] { t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s) return } uuids[s] = true if time.Since(start) > duration { return } cnt++ } } uuid-1.6.0/sql.go000066400000000000000000000026631455400551400136240ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "database/sql/driver" "fmt" ) // Scan implements sql.Scanner so UUIDs can be read from databases transparently. // Currently, database types that map to string and []byte are supported. Please // consult database-specific driver documentation for matching types. func (uuid *UUID) Scan(src interface{}) error { switch src := src.(type) { case nil: return nil case string: // if an empty UUID comes from a table, we return a null UUID if src == "" { return nil } // see Parse for required string format u, err := Parse(src) if err != nil { return fmt.Errorf("Scan: %v", err) } *uuid = u case []byte: // if an empty UUID comes from a table, we return a null UUID if len(src) == 0 { return nil } // assumes a simple slice of bytes if 16 bytes // otherwise attempts to parse if len(src) != 16 { return uuid.Scan(string(src)) } copy((*uuid)[:], src) default: return fmt.Errorf("Scan: unable to scan type %T into UUID", src) } return nil } // Value implements sql.Valuer so that UUIDs can be written to databases // transparently. Currently, UUIDs map to strings. Please consult // database-specific driver documentation for matching types. func (uuid UUID) Value() (driver.Value, error) { return uuid.String(), nil } uuid-1.6.0/sql_test.go000066400000000000000000000045101455400551400146540ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "strings" "testing" ) func TestScan(t *testing.T) { stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479" badTypeTest := 6 invalidTest := "f47ac10b-58cc-0372-8567-0e02b2c3d4" byteTest := make([]byte, 16) byteTestUUID := Must(Parse(stringTest)) copy(byteTest, byteTestUUID[:]) // sunny day tests var uuid UUID err := (&uuid).Scan(stringTest) if err != nil { t.Fatal(err) } err = (&uuid).Scan([]byte(stringTest)) if err != nil { t.Fatal(err) } err = (&uuid).Scan(byteTest) if err != nil { t.Fatal(err) } // bad type tests err = (&uuid).Scan(badTypeTest) if err == nil { t.Error("int correctly parsed and shouldn't have") } if !strings.Contains(err.Error(), "unable to scan type") { t.Error("attempting to parse an int returned an incorrect error message") } // invalid/incomplete uuids err = (&uuid).Scan(invalidTest) if err == nil { t.Error("invalid uuid was parsed without error") } if !strings.Contains(err.Error(), "invalid UUID") { t.Error("attempting to parse an invalid UUID returned an incorrect error message") } err = (&uuid).Scan(byteTest[:len(byteTest)-2]) if err == nil { t.Error("invalid byte uuid was parsed without error") } if !strings.Contains(err.Error(), "invalid UUID") { t.Error("attempting to parse an invalid byte UUID returned an incorrect error message") } // empty tests uuid = UUID{} var emptySlice []byte err = (&uuid).Scan(emptySlice) if err != nil { t.Fatal(err) } for _, v := range uuid { if v != 0 { t.Error("UUID was not nil after scanning empty byte slice") } } uuid = UUID{} var emptyString string err = (&uuid).Scan(emptyString) if err != nil { t.Fatal(err) } for _, v := range uuid { if v != 0 { t.Error("UUID was not nil after scanning empty byte slice") } } uuid = UUID{} err = (&uuid).Scan(nil) if err != nil { t.Fatal(err) } for _, v := range uuid { if v != 0 { t.Error("UUID was not nil after scanning nil") } } } func TestValue(t *testing.T) { stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479" uuid := Must(Parse(stringTest)) val, _ := uuid.Value() if val != stringTest { t.Error("Value() did not return expected string") } } uuid-1.6.0/time.go000066400000000000000000000073231455400551400137610ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "encoding/binary" "sync" "time" ) // A Time represents a time as the number of 100's of nanoseconds since 15 Oct // 1582. type Time int64 const ( lillian = 2299160 // Julian day of 15 Oct 1582 unix = 2440587 // Julian day of 1 Jan 1970 epoch = unix - lillian // Days between epochs g1582 = epoch * 86400 // seconds between epochs g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs ) var ( timeMu sync.Mutex lasttime uint64 // last time we returned clockSeq uint16 // clock sequence for this run timeNow = time.Now // for testing ) // UnixTime converts t the number of seconds and nanoseconds using the Unix // epoch of 1 Jan 1970. func (t Time) UnixTime() (sec, nsec int64) { sec = int64(t - g1582ns100) nsec = (sec % 10000000) * 100 sec /= 10000000 return sec, nsec } // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and // clock sequence as well as adjusting the clock sequence as needed. An error // is returned if the current time cannot be determined. func GetTime() (Time, uint16, error) { defer timeMu.Unlock() timeMu.Lock() return getTime() } func getTime() (Time, uint16, error) { t := timeNow() // If we don't have a clock sequence already, set one. if clockSeq == 0 { setClockSequence(-1) } now := uint64(t.UnixNano()/100) + g1582ns100 // If time has gone backwards with this clock sequence then we // increment the clock sequence if now <= lasttime { clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 } lasttime = now return Time(now), clockSeq, nil } // ClockSequence returns the current clock sequence, generating one if not // already set. The clock sequence is only used for Version 1 UUIDs. // // The uuid package does not use global static storage for the clock sequence or // the last time a UUID was generated. Unless SetClockSequence is used, a new // random clock sequence is generated the first time a clock sequence is // requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) func ClockSequence() int { defer timeMu.Unlock() timeMu.Lock() return clockSequence() } func clockSequence() int { if clockSeq == 0 { setClockSequence(-1) } return int(clockSeq & 0x3fff) } // SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to // -1 causes a new sequence to be generated. func SetClockSequence(seq int) { defer timeMu.Unlock() timeMu.Lock() setClockSequence(seq) } func setClockSequence(seq int) { if seq == -1 { var b [2]byte randomBits(b[:]) // clock sequence seq = int(b[0])<<8 | int(b[1]) } oldSeq := clockSeq clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant if oldSeq != clockSeq { lasttime = 0 } } // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in // uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. func (uuid UUID) Time() Time { var t Time switch uuid.Version() { case 6: time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 t = Time(time) case 7: time := binary.BigEndian.Uint64(uuid[:8]) t = Time((time>>16)*10000 + g1582ns100) default: // forward compatible time := int64(binary.BigEndian.Uint32(uuid[0:4])) time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 t = Time(time) } return t } // ClockSequence returns the clock sequence encoded in uuid. // The clock sequence is only well defined for version 1 and 2 UUIDs. func (uuid UUID) ClockSequence() int { return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff } uuid-1.6.0/util.go000066400000000000000000000036001455400551400137720ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "io" ) // randomBits completely fills slice b with random data. func randomBits(b []byte) { if _, err := io.ReadFull(rander, b); err != nil { panic(err.Error()) // rand should never fail } } // xvalues returns the value of a byte as a hexadecimal digit or 255. var xvalues = [256]byte{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, } // xtob converts hex characters x1 and x2 into a byte. func xtob(x1, x2 byte) (byte, bool) { b1 := xvalues[x1] b2 := xvalues[x2] return (b1 << 4) | b2, b1 != 255 && b2 != 255 } uuid-1.6.0/uuid.go000066400000000000000000000226411455400551400137710ustar00rootroot00000000000000// Copyright 2018 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "bytes" "crypto/rand" "encoding/hex" "errors" "fmt" "io" "strings" "sync" ) // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC // 4122. type UUID [16]byte // A Version represents a UUID's version. type Version byte // A Variant represents a UUID's variant. type Variant byte // Constants returned by Variant. const ( Invalid = Variant(iota) // Invalid UUID RFC4122 // The variant specified in RFC4122 Reserved // Reserved, NCS backward compatibility. Microsoft // Reserved, Microsoft Corporation backward compatibility. Future // Reserved for future definition. ) const randPoolSize = 16 * 16 var ( rander = rand.Reader // random function poolEnabled = false poolMu sync.Mutex poolPos = randPoolSize // protected with poolMu pool [randPoolSize]byte // protected with poolMu ) type invalidLengthError struct{ len int } func (err invalidLengthError) Error() string { return fmt.Sprintf("invalid UUID length: %d", err.len) } // IsInvalidLengthError is matcher function for custom error invalidLengthError func IsInvalidLengthError(err error) bool { _, ok := err.(invalidLengthError) return ok } // Parse decodes s into a UUID or returns an error if it cannot be parsed. Both // the standard UUID forms defined in RFC 4122 // (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, // Parse accepts non-standard strings such as the raw hex encoding // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, // e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are // examined in the latter case. Parse should not be used to validate strings as // it parses non-standard encodings as indicated above. func Parse(s string) (UUID, error) { var uuid UUID switch len(s) { // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: if !strings.EqualFold(s[:9], "urn:uuid:") { return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) } s = s[9:] // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} case 36 + 2: s = s[1:] // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx case 32: var ok bool for i := range uuid { uuid[i], ok = xtob(s[i*2], s[i*2+1]) if !ok { return uuid, errors.New("invalid UUID format") } } return uuid, nil default: return uuid, invalidLengthError{len(s)} } // s is now at least 36 bytes long // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { return uuid, errors.New("invalid UUID format") } for i, x := range [16]int{ 0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34, } { v, ok := xtob(s[x], s[x+1]) if !ok { return uuid, errors.New("invalid UUID format") } uuid[i] = v } return uuid, nil } // ParseBytes is like Parse, except it parses a byte slice instead of a string. func ParseBytes(b []byte) (UUID, error) { var uuid UUID switch len(b) { case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) } b = b[9:] case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} b = b[1:] case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx var ok bool for i := 0; i < 32; i += 2 { uuid[i/2], ok = xtob(b[i], b[i+1]) if !ok { return uuid, errors.New("invalid UUID format") } } return uuid, nil default: return uuid, invalidLengthError{len(b)} } // s is now at least 36 bytes long // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { return uuid, errors.New("invalid UUID format") } for i, x := range [16]int{ 0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34, } { v, ok := xtob(b[x], b[x+1]) if !ok { return uuid, errors.New("invalid UUID format") } uuid[i] = v } return uuid, nil } // MustParse is like Parse but panics if the string cannot be parsed. // It simplifies safe initialization of global variables holding compiled UUIDs. func MustParse(s string) UUID { uuid, err := Parse(s) if err != nil { panic(`uuid: Parse(` + s + `): ` + err.Error()) } return uuid } // FromBytes creates a new UUID from a byte slice. Returns an error if the slice // does not have a length of 16. The bytes are copied from the slice. func FromBytes(b []byte) (uuid UUID, err error) { err = uuid.UnmarshalBinary(b) return uuid, err } // Must returns uuid if err is nil and panics otherwise. func Must(uuid UUID, err error) UUID { if err != nil { panic(err) } return uuid } // Validate returns an error if s is not a properly formatted UUID in one of the following formats: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} // It returns an error if the format is invalid, otherwise nil. func Validate(s string) error { switch len(s) { // Standard UUID format case 36: // UUID with "urn:uuid:" prefix case 36 + 9: if !strings.EqualFold(s[:9], "urn:uuid:") { return fmt.Errorf("invalid urn prefix: %q", s[:9]) } s = s[9:] // UUID enclosed in braces case 36 + 2: if s[0] != '{' || s[len(s)-1] != '}' { return fmt.Errorf("invalid bracketed UUID format") } s = s[1 : len(s)-1] // UUID without hyphens case 32: for i := 0; i < len(s); i += 2 { _, ok := xtob(s[i], s[i+1]) if !ok { return errors.New("invalid UUID format") } } default: return invalidLengthError{len(s)} } // Check for standard UUID format if len(s) == 36 { if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { return errors.New("invalid UUID format") } for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { if _, ok := xtob(s[x], s[x+1]); !ok { return errors.New("invalid UUID format") } } } return nil } // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // , or "" if uuid is invalid. func (uuid UUID) String() string { var buf [36]byte encodeHex(buf[:], uuid) return string(buf[:]) } // URN returns the RFC 2141 URN form of uuid, // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. func (uuid UUID) URN() string { var buf [36 + 9]byte copy(buf[:], "urn:uuid:") encodeHex(buf[9:], uuid) return string(buf[:]) } func encodeHex(dst []byte, uuid UUID) { hex.Encode(dst, uuid[:4]) dst[8] = '-' hex.Encode(dst[9:13], uuid[4:6]) dst[13] = '-' hex.Encode(dst[14:18], uuid[6:8]) dst[18] = '-' hex.Encode(dst[19:23], uuid[8:10]) dst[23] = '-' hex.Encode(dst[24:], uuid[10:]) } // Variant returns the variant encoded in uuid. func (uuid UUID) Variant() Variant { switch { case (uuid[8] & 0xc0) == 0x80: return RFC4122 case (uuid[8] & 0xe0) == 0xc0: return Microsoft case (uuid[8] & 0xe0) == 0xe0: return Future default: return Reserved } } // Version returns the version of uuid. func (uuid UUID) Version() Version { return Version(uuid[6] >> 4) } func (v Version) String() string { if v > 15 { return fmt.Sprintf("BAD_VERSION_%d", v) } return fmt.Sprintf("VERSION_%d", v) } func (v Variant) String() string { switch v { case RFC4122: return "RFC4122" case Reserved: return "Reserved" case Microsoft: return "Microsoft" case Future: return "Future" case Invalid: return "Invalid" } return fmt.Sprintf("BadVariant%d", int(v)) } // SetRand sets the random number generator to r, which implements io.Reader. // If r.Read returns an error when the package requests random data then // a panic will be issued. // // Calling SetRand with nil sets the random number generator to the default // generator. func SetRand(r io.Reader) { if r == nil { rander = rand.Reader return } rander = r } // EnableRandPool enables internal randomness pool used for Random // (Version 4) UUID generation. The pool contains random bytes read from // the random number generator on demand in batches. Enabling the pool // may improve the UUID generation throughput significantly. // // Since the pool is stored on the Go heap, this feature may be a bad fit // for security sensitive applications. // // Both EnableRandPool and DisableRandPool are not thread-safe and should // only be called when there is no possibility that New or any other // UUID Version 4 generation function will be called concurrently. func EnableRandPool() { poolEnabled = true } // DisableRandPool disables the randomness pool if it was previously // enabled with EnableRandPool. // // Both EnableRandPool and DisableRandPool are not thread-safe and should // only be called when there is no possibility that New or any other // UUID Version 4 generation function will be called concurrently. func DisableRandPool() { poolEnabled = false defer poolMu.Unlock() poolMu.Lock() poolPos = randPoolSize } // UUIDs is a slice of UUID types. type UUIDs []UUID // Strings returns a string slice containing the string form of each UUID in uuids. func (uuids UUIDs) Strings() []string { var uuidStrs = make([]string, len(uuids)) for i, uuid := range uuids { uuidStrs[i] = uuid.String() } return uuidStrs } uuid-1.6.0/uuid_test.go000066400000000000000000000553671455400551400150430ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "bytes" "errors" "fmt" "os" "runtime" "strings" "testing" "time" "unsafe" ) type test struct { in string version Version variant Variant isuuid bool } var tests = []test{ {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, {"{f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, RFC4122, true}, {"{f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, Invalid, false}, {"f47ac10b58cc037285670e02b2c3d479", 0, RFC4122, true}, {"f47ac10b58cc037285670e02b2c3d4790", 0, Invalid, false}, {"f47ac10b58cc037285670e02b2c3d47", 0, Invalid, false}, {"01ee836c-e7c9-619d-929a-525400475911", 6, RFC4122, true}, {"018bd12c-58b0-7683-8a5b-8752d0e86651", 7, RFC4122, true}, } var constants = []struct { c interface{} name string }{ {Person, "Person"}, {Group, "Group"}, {Org, "Org"}, {Invalid, "Invalid"}, {RFC4122, "RFC4122"}, {Reserved, "Reserved"}, {Microsoft, "Microsoft"}, {Future, "Future"}, {Domain(17), "Domain17"}, {Variant(42), "BadVariant42"}, } func testTest(t *testing.T, in string, tt test) { uuid, err := Parse(in) if ok := (err == nil); ok != tt.isuuid { t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) } if err != nil { return } if v := uuid.Variant(); v != tt.variant { t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) } if v := uuid.Version(); v != tt.version { t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) } } func testBytes(t *testing.T, in []byte, tt test) { uuid, err := ParseBytes(in) if ok := (err == nil); ok != tt.isuuid { t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid) } if err != nil { return } suuid, _ := Parse(string(in)) if uuid != suuid { t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid) } } func TestUUID(t *testing.T) { for _, tt := range tests { testTest(t, tt.in, tt) testTest(t, strings.ToUpper(tt.in), tt) testBytes(t, []byte(tt.in), tt) } } func TestFromBytes(t *testing.T) { b := []byte{ 0x7d, 0x44, 0x48, 0x40, 0x9d, 0xc0, 0x11, 0xd1, 0xb2, 0x45, 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, } uuid, err := FromBytes(b) if err != nil { t.Fatalf("%s", err) } for i := 0; i < len(uuid); i++ { if b[i] != uuid[i] { t.Fatalf("FromBytes() got %v expected %v\b", uuid[:], b) } } } func TestConstants(t *testing.T) { for x, tt := range constants { v, ok := tt.c.(fmt.Stringer) if !ok { t.Errorf("%x: %v: not a stringer", x, v) } else if s := v.String(); s != tt.name { v, _ := tt.c.(int) t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name) } } } func TestRandomUUID(t *testing.T) { m := make(map[string]bool) for x := 1; x < 32; x++ { uuid := New() s := uuid.String() if m[s] { t.Errorf("NewRandom returned duplicated UUID %s", s) } m[s] = true if v := uuid.Version(); v != 4 { t.Errorf("Random UUID of version %s", v) } if uuid.Variant() != RFC4122 { t.Errorf("Random UUID is variant %d", uuid.Variant()) } } } func TestRandomUUID_Pooled(t *testing.T) { defer DisableRandPool() EnableRandPool() m := make(map[string]bool) for x := 1; x < 128; x++ { uuid := New() s := uuid.String() if m[s] { t.Errorf("NewRandom returned duplicated UUID %s", s) } m[s] = true if v := uuid.Version(); v != 4 { t.Errorf("Random UUID of version %s", v) } if uuid.Variant() != RFC4122 { t.Errorf("Random UUID is variant %d", uuid.Variant()) } } } func TestNew(t *testing.T) { m := make(map[UUID]bool) for x := 1; x < 32; x++ { s := New() if m[s] { t.Errorf("New returned duplicated UUID %s", s) } m[s] = true uuid, err := Parse(s.String()) if err != nil { t.Errorf("New.String() returned %q which does not decode", s) continue } if v := uuid.Version(); v != 4 { t.Errorf("Random UUID of version %s", v) } if uuid.Variant() != RFC4122 { t.Errorf("Random UUID is variant %d", uuid.Variant()) } } } func TestClockSeq(t *testing.T) { // Fake time.Now for this test to return a monotonically advancing time; restore it at end. defer func(orig func() time.Time) { timeNow = orig }(timeNow) monTime := time.Now() timeNow = func() time.Time { monTime = monTime.Add(1 * time.Second) return monTime } SetClockSequence(-1) uuid1, err := NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } uuid2, err := NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 { t.Errorf("clock sequence %d != %d", s1, s2) } SetClockSequence(-1) uuid2, err = NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } // Just on the very off chance we generated the same sequence // two times we try again. if uuid1.ClockSequence() == uuid2.ClockSequence() { SetClockSequence(-1) uuid2, err = NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } } if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 { t.Errorf("Duplicate clock sequence %d", s1) } SetClockSequence(0x1234) uuid1, err = NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } if seq := uuid1.ClockSequence(); seq != 0x1234 { t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq) } } func TestCoding(t *testing.T) { text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" data := UUID{ 0x7d, 0x44, 0x48, 0x40, 0x9d, 0xc0, 0x11, 0xd1, 0xb2, 0x45, 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, } if v := data.String(); v != text { t.Errorf("%x: encoded to %s, expected %s", data, v, text) } if v := data.URN(); v != urn { t.Errorf("%x: urn is %s, expected %s", data, v, urn) } uuid, err := Parse(text) if err != nil { t.Errorf("Parse returned unexpected error %v", err) } if data != uuid { t.Errorf("%s: decoded to %s, expected %s", text, uuid, data) } } func TestVersion1(t *testing.T) { uuid1, err := NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } uuid2, err := NewUUID() if err != nil { t.Fatalf("could not create UUID: %v", err) } if uuid1 == uuid2 { t.Errorf("%s:duplicate uuid", uuid1) } if v := uuid1.Version(); v != 1 { t.Errorf("%s: version %s expected 1", uuid1, v) } if v := uuid2.Version(); v != 1 { t.Errorf("%s: version %s expected 1", uuid2, v) } n1 := uuid1.NodeID() n2 := uuid2.NodeID() if !bytes.Equal(n1, n2) { t.Errorf("Different nodes %x != %x", n1, n2) } t1 := uuid1.Time() t2 := uuid2.Time() q1 := uuid1.ClockSequence() q2 := uuid2.ClockSequence() switch { case t1 == t2 && q1 == q2: t.Error("time stopped") case t1 > t2 && q1 == q2: t.Error("time reversed") case t1 < t2 && q1 != q2: t.Error("clock sequence changed unexpectedly") } } func TestNode(t *testing.T) { // This test is mostly to make sure we don't leave nodeMu locked. ifname = "" if ni := NodeInterface(); ni != "" { t.Errorf("NodeInterface got %q, want %q", ni, "") } if SetNodeInterface("xyzzy") { t.Error("SetNodeInterface succeeded on a bad interface name") } if !SetNodeInterface("") { t.Error("SetNodeInterface failed") } if runtime.GOARCH != "js" { if ni := NodeInterface(); ni == "" { t.Error("NodeInterface returned an empty string") } } ni := NodeID() if len(ni) != 6 { t.Errorf("ni got %d bytes, want 6", len(ni)) } hasData := false for _, b := range ni { if b != 0 { hasData = true } } if !hasData { t.Error("nodeid is all zeros") } id := []byte{1, 2, 3, 4, 5, 6, 7, 8} SetNodeID(id) ni = NodeID() if !bytes.Equal(ni, id[:6]) { t.Errorf("got nodeid %v, want %v", ni, id[:6]) } if ni := NodeInterface(); ni != "user" { t.Errorf("got interface %q, want %q", ni, "user") } } func TestNodeAndTime(t *testing.T) { // Time is February 5, 1998 12:30:23.136364800 AM GMT uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") if err != nil { t.Fatalf("Parser returned unexpected error %v", err) } node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} ts := uuid.Time() c := time.Unix(ts.UnixTime()) want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) if !c.Equal(want) { t.Errorf("Got time %v, want %v", c, want) } if !bytes.Equal(node, uuid.NodeID()) { t.Errorf("Expected node %v got %v", node, uuid.NodeID()) } } func TestMD5(t *testing.T) { uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String() want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" if uuid != want { t.Errorf("MD5: got %q expected %q", uuid, want) } } func TestSHA1(t *testing.T) { uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String() want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" if uuid != want { t.Errorf("SHA1: got %q expected %q", uuid, want) } } func TestNodeID(t *testing.T) { nid := []byte{1, 2, 3, 4, 5, 6} SetNodeInterface("") s := NodeInterface() if runtime.GOARCH != "js" { if s == "" || s == "user" { t.Errorf("NodeInterface %q after SetInterface", s) } } node1 := NodeID() if node1 == nil { t.Error("NodeID nil after SetNodeInterface", s) } SetNodeID(nid) s = NodeInterface() if s != "user" { t.Errorf("Expected NodeInterface %q got %q", "user", s) } node2 := NodeID() if node2 == nil { t.Error("NodeID nil after SetNodeID", s) } if bytes.Equal(node1, node2) { t.Error("NodeID not changed after SetNodeID", s) } else if !bytes.Equal(nid, node2) { t.Errorf("NodeID is %x, expected %x", node2, nid) } } func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) { if err != nil { t.Errorf("%s failed: %v", name, err) return } if v := uuid.Version(); v != 2 { t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v) return } if v := uuid.Domain(); v != domain { t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v) } if v := uuid.ID(); v != id { t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v) } } func TestDCE(t *testing.T) { uuid, err := NewDCESecurity(42, 12345678) testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678) uuid, err = NewDCEPerson() testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid())) uuid, err = NewDCEGroup() testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid())) } type badRand struct{} func (r badRand) Read(buf []byte) (int, error) { for i := range buf { buf[i] = byte(i) } return len(buf), nil } func TestBadRand(t *testing.T) { SetRand(badRand{}) uuid1 := New() uuid2 := New() if uuid1 != uuid2 { t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2) } SetRand(nil) uuid1 = New() uuid2 = New() if uuid1 == uuid2 { t.Errorf("unexpected duplicates, got %q", uuid1) } } func TestSetRand(t *testing.T) { myString := "805-9dd6-1a877cb526c678e71d38-7122-44c0-9b7c-04e7001cc78783ac3e82-47a3-4cc3-9951-13f3339d88088f5d685a-11f7-4078-ada9-de44ad2daeb7" SetRand(strings.NewReader(myString)) uuid1 := New() uuid2 := New() SetRand(strings.NewReader(myString)) uuid3 := New() uuid4 := New() if uuid1 != uuid3 { t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) } if uuid2 != uuid4 { t.Errorf("expected duplicates, got %q and %q", uuid2, uuid4) } } func TestRandomFromReader(t *testing.T) { myString := "8059ddhdle77cb52" r := bytes.NewReader([]byte(myString)) r2 := bytes.NewReader([]byte(myString)) uuid1, err := NewRandomFromReader(r) if err != nil { t.Errorf("failed generating UUID from a reader") } _, err = NewRandomFromReader(r) if err == nil { t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewRandomFromReader may not be using the provided reader") } uuid3, err := NewRandomFromReader(r2) if err != nil { t.Errorf("failed generating UUID from a reader") } if uuid1 != uuid3 { t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) } } func TestRandPool(t *testing.T) { myString := "8059ddhdle77cb52" EnableRandPool() SetRand(strings.NewReader(myString)) _, err := NewRandom() if err == nil { t.Errorf("expecting an error as reader has no more bytes") } DisableRandPool() SetRand(strings.NewReader(myString)) _, err = NewRandom() if err != nil { t.Errorf("failed generating UUID from a reader") } } func TestWrongLength(t *testing.T) { _, err := Parse("12345") if err == nil { t.Errorf("expected ‘12345’ was invalid") } else if err.Error() != "invalid UUID length: 5" { t.Errorf("expected a different error message for an invalid length") } } func TestIsWrongLength(t *testing.T) { _, err := Parse("12345") if !IsInvalidLengthError(err) { t.Errorf("expected error type is invalidLengthError") } } func FuzzParse(f *testing.F) { for _, tt := range tests { f.Add(tt.in) f.Add(strings.ToUpper(tt.in)) } f.Fuzz(func(t *testing.T, in string) { Parse(in) }) } func FuzzParseBytes(f *testing.F) { for _, tt := range tests { f.Add([]byte(tt.in)) } f.Fuzz(func(t *testing.T, in []byte) { ParseBytes(in) }) } func FuzzFromBytes(f *testing.F) { // Copied from TestFromBytes. f.Add([]byte{ 0x7d, 0x44, 0x48, 0x40, 0x9d, 0xc0, 0x11, 0xd1, 0xb2, 0x45, 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, }) f.Fuzz(func(t *testing.T, in []byte) { FromBytes(in) }) } // TestValidate checks various scenarios for the Validate function func TestValidate(t *testing.T) { testCases := []struct { name string input string expect error }{ {"Valid UUID", "123e4567-e89b-12d3-a456-426655440000", nil}, {"Valid UUID with URN", "urn:uuid:123e4567-e89b-12d3-a456-426655440000", nil}, {"Valid UUID with Braces", "{123e4567-e89b-12d3-a456-426655440000}", nil}, {"Valid UUID No Hyphens", "123e4567e89b12d3a456426655440000", nil}, {"Invalid UUID", "invalid-uuid", errors.New("invalid UUID length: 12")}, {"Invalid Length", "123", fmt.Errorf("invalid UUID length: %d", len("123"))}, {"Invalid URN Prefix", "urn:test:123e4567-e89b-12d3-a456-426655440000", fmt.Errorf("invalid urn prefix: %q", "urn:test:")}, {"Invalid Brackets", "[123e4567-e89b-12d3-a456-426655440000]", fmt.Errorf("invalid bracketed UUID format")}, {"Invalid UUID Format", "12345678gabc1234abcd1234abcd1234", fmt.Errorf("invalid UUID format")}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := Validate(tc.input) if (err != nil) != (tc.expect != nil) || (err != nil && err.Error() != tc.expect.Error()) { t.Errorf("Validate(%q) = %v, want %v", tc.input, err, tc.expect) } }) } } var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479" var asBytes = []byte(asString) func BenchmarkParse(b *testing.B) { for i := 0; i < b.N; i++ { _, err := Parse(asString) if err != nil { b.Fatal(err) } } } func BenchmarkParseBytes(b *testing.B) { for i := 0; i < b.N; i++ { _, err := ParseBytes(asBytes) if err != nil { b.Fatal(err) } } } // parseBytesUnsafe is to benchmark using unsafe. func parseBytesUnsafe(b []byte) (UUID, error) { return Parse(*(*string)(unsafe.Pointer(&b))) } func BenchmarkParseBytesUnsafe(b *testing.B) { for i := 0; i < b.N; i++ { _, err := parseBytesUnsafe(asBytes) if err != nil { b.Fatal(err) } } } // parseBytesCopy is to benchmark not using unsafe. func parseBytesCopy(b []byte) (UUID, error) { return Parse(string(b)) } func BenchmarkParseBytesCopy(b *testing.B) { for i := 0; i < b.N; i++ { _, err := parseBytesCopy(asBytes) if err != nil { b.Fatal(err) } } } func BenchmarkNew(b *testing.B) { for i := 0; i < b.N; i++ { New() } } func BenchmarkUUID_String(b *testing.B) { uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { if uuid.String() == "" { b.Fatal("invalid uuid") } } } func BenchmarkUUID_URN(b *testing.B) { uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { if uuid.URN() == "" { b.Fatal("invalid uuid") } } } func BenchmarkParseBadLength(b *testing.B) { short := asString[:10] for i := 0; i < b.N; i++ { _, err := Parse(short) if err == nil { b.Fatalf("expected ‘%s’ was invalid", short) } } } func BenchmarkParseLen32Truncated(b *testing.B) { partial := asString[:len(asString)-4] for i := 0; i < b.N; i++ { _, err := Parse(partial) if err == nil { b.Fatalf("expected ‘%s’ was invalid", partial) } } } func BenchmarkParseLen36Corrupted(b *testing.B) { wrong := asString[:len(asString)-1] + "x" for i := 0; i < b.N; i++ { _, err := Parse(wrong) if err == nil { b.Fatalf("expected ‘%s’ was invalid", wrong) } } } func BenchmarkUUID_New(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _, err := NewRandom() if err != nil { b.Fatal(err) } } }) } func BenchmarkUUID_NewPooled(b *testing.B) { EnableRandPool() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _, err := NewRandom() if err != nil { b.Fatal(err) } } }) } func BenchmarkUUIDs_Strings(b *testing.B) { uuid1, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") if err != nil { b.Fatal(err) } uuid2, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") if err != nil { b.Fatal(err) } uuids := UUIDs{uuid1, uuid2} for i := 0; i < b.N; i++ { uuids.Strings() } } func TestVersion6(t *testing.T) { uuid1, err := NewV6() if err != nil { t.Fatalf("could not create UUID: %v", err) } uuid2, err := NewV6() if err != nil { t.Fatalf("could not create UUID: %v", err) } if uuid1 == uuid2 { t.Errorf("%s:duplicate uuid", uuid1) } if v := uuid1.Version(); v != 6 { t.Errorf("%s: version %s expected 6", uuid1, v) } if v := uuid2.Version(); v != 6 { t.Errorf("%s: version %s expected 6", uuid2, v) } n1 := uuid1.NodeID() n2 := uuid2.NodeID() if !bytes.Equal(n1, n2) { t.Errorf("Different nodes %x != %x", n1, n2) } t1 := uuid1.Time() t2 := uuid2.Time() q1 := uuid1.ClockSequence() q2 := uuid2.ClockSequence() switch { case t1 == t2 && q1 == q2: t.Error("time stopped") case t1 > t2 && q1 == q2: t.Error("time reversed") case t1 < t2 && q1 != q2: t.Error("clock sequence changed unexpectedly") } } // uuid v7 time is only unix milliseconds, so // uuid1.Time() == uuid2.Time() is right, but uuid1 must != uuid2 func TestVersion7(t *testing.T) { SetRand(nil) m := make(map[string]bool) for x := 1; x < 128; x++ { uuid, err := NewV7() if err != nil { t.Fatalf("could not create UUID: %v", err) } s := uuid.String() if m[s] { t.Errorf("NewV7 returned duplicated UUID %s", s) } m[s] = true if v := uuid.Version(); v != 7 { t.Errorf("UUID of version %s", v) } if uuid.Variant() != RFC4122 { t.Errorf("UUID is variant %d", uuid.Variant()) } } } // uuid v7 time is only unix milliseconds, so // uuid1.Time() == uuid2.Time() is right, but uuid1 must != uuid2 func TestVersion7_pooled(t *testing.T) { SetRand(nil) EnableRandPool() defer DisableRandPool() m := make(map[string]bool) for x := 1; x < 128; x++ { uuid, err := NewV7() if err != nil { t.Fatalf("could not create UUID: %v", err) } s := uuid.String() if m[s] { t.Errorf("NewV7 returned duplicated UUID %s", s) } m[s] = true if v := uuid.Version(); v != 7 { t.Errorf("UUID of version %s", v) } if uuid.Variant() != RFC4122 { t.Errorf("UUID is variant %d", uuid.Variant()) } } } func TestVersion7FromReader(t *testing.T) { myString := "8059ddhdle77cb52" r := bytes.NewReader([]byte(myString)) _, err := NewV7FromReader(r) if err != nil { t.Errorf("failed generating UUID from a reader") } _, err = NewV7FromReader(r) if err == nil { t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewV7FromReader may not be using the provided reader") } } func TestVersion7Monotonicity(t *testing.T) { length := 10000 u1 := Must(NewV7()).String() for i := 0; i < length; i++ { u2 := Must(NewV7()).String() if u2 <= u1 { t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1) break } u1 = u2 } } type fakeRand struct{} func (g fakeRand) Read(bs []byte) (int, error) { for i, _ := range bs { bs[i] = 0x88 } return len(bs), nil } func TestVersion7MonotonicityStrict(t *testing.T) { timeNow = func() time.Time { return time.Date(2008, 8, 8, 8, 8, 8, 8, time.UTC) } defer func() { timeNow = time.Now }() SetRand(fakeRand{}) defer SetRand(nil) length := 100000 // > 3906 u1 := Must(NewV7()).String() for i := 0; i < length; i++ { u2 := Must(NewV7()).String() if u2 <= u1 { t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1) break } u1 = u2 } } uuid-1.6.0/version1.go000066400000000000000000000023511455400551400145650ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "encoding/binary" ) // NewUUID returns a Version 1 UUID based on the current NodeID and clock // sequence, and the current time. If the NodeID has not been set by SetNodeID // or SetNodeInterface then it will be set automatically. If the NodeID cannot // be set NewUUID returns nil. If clock sequence has not been set by // SetClockSequence then it will be set automatically. If GetTime fails to // return the current NewUUID returns nil and an error. // // In most cases, New should be used. func NewUUID() (UUID, error) { var uuid UUID now, seq, err := GetTime() if err != nil { return uuid, err } timeLow := uint32(now & 0xffffffff) timeMid := uint16((now >> 32) & 0xffff) timeHi := uint16((now >> 48) & 0x0fff) timeHi |= 0x1000 // Version 1 binary.BigEndian.PutUint32(uuid[0:], timeLow) binary.BigEndian.PutUint16(uuid[4:], timeMid) binary.BigEndian.PutUint16(uuid[6:], timeHi) binary.BigEndian.PutUint16(uuid[8:], seq) nodeMu.Lock() if nodeID == zeroID { setNodeInterface("") } copy(uuid[10:], nodeID[:]) nodeMu.Unlock() return uuid, nil } uuid-1.6.0/version4.go000066400000000000000000000040111455400551400145630ustar00rootroot00000000000000// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import "io" // New creates a new random UUID or panics. New is equivalent to // the expression // // uuid.Must(uuid.NewRandom()) func New() UUID { return Must(NewRandom()) } // NewString creates a new random UUID and returns it as a string or panics. // NewString is equivalent to the expression // // uuid.New().String() func NewString() string { return Must(NewRandom()).String() } // NewRandom returns a Random (Version 4) UUID. // // The strength of the UUIDs is based on the strength of the crypto/rand // package. // // Uses the randomness pool if it was enabled with EnableRandPool. // // A note about uniqueness derived from the UUID Wikipedia entry: // // Randomly generated UUIDs have 122 random bits. One's annual risk of being // hit by a meteorite is estimated to be one chance in 17 billion, that // means the probability is about 0.00000000006 (6 × 10−11), // equivalent to the odds of creating a few tens of trillions of UUIDs in a // year and having one duplicate. func NewRandom() (UUID, error) { if !poolEnabled { return NewRandomFromReader(rander) } return newRandomFromPool() } // NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. func NewRandomFromReader(r io.Reader) (UUID, error) { var uuid UUID _, err := io.ReadFull(r, uuid[:]) if err != nil { return Nil, err } uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 return uuid, nil } func newRandomFromPool() (UUID, error) { var uuid UUID poolMu.Lock() if poolPos == randPoolSize { _, err := io.ReadFull(rander, pool[:]) if err != nil { poolMu.Unlock() return Nil, err } poolPos = 0 } copy(uuid[:], pool[poolPos:(poolPos+16)]) poolPos += 16 poolMu.Unlock() uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 return uuid, nil } uuid-1.6.0/version6.go000066400000000000000000000042451455400551400145760ustar00rootroot00000000000000// Copyright 2023 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import "encoding/binary" // UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. // It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. // Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. // // see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 // // NewV6 returns a Version 6 UUID based on the current NodeID and clock // sequence, and the current time. If the NodeID has not been set by SetNodeID // or SetNodeInterface then it will be set automatically. If the NodeID cannot // be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by // SetClockSequence then it will be set automatically. If GetTime fails to // return the current NewV6 returns Nil and an error. func NewV6() (UUID, error) { var uuid UUID now, seq, err := GetTime() if err != nil { return uuid, err } /* 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time_high | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time_mid | time_low_and_version | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |clk_seq_hi_res | clk_seq_low | node (0-1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | node (2-5) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ binary.BigEndian.PutUint64(uuid[0:], uint64(now)) binary.BigEndian.PutUint16(uuid[8:], seq) uuid[6] = 0x60 | (uuid[6] & 0x0F) uuid[8] = 0x80 | (uuid[8] & 0x3F) nodeMu.Lock() if nodeID == zeroID { setNodeInterface("") } copy(uuid[10:], nodeID[:]) nodeMu.Unlock() return uuid, nil } uuid-1.6.0/version7.go000066400000000000000000000064531455400551400146020ustar00rootroot00000000000000// Copyright 2023 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uuid import ( "io" ) // UUID version 7 features a time-ordered value field derived from the widely // implemented and well known Unix Epoch timestamp source, // the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. // As well as improved entropy characteristics over versions 1 or 6. // // see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 // // Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. // // NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). // Uses the randomness pool if it was enabled with EnableRandPool. // On error, NewV7 returns Nil and an error func NewV7() (UUID, error) { uuid, err := NewRandom() if err != nil { return uuid, err } makeV7(uuid[:]) return uuid, nil } // NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). // it use NewRandomFromReader fill random bits. // On error, NewV7FromReader returns Nil and an error. func NewV7FromReader(r io.Reader) (UUID, error) { uuid, err := NewRandomFromReader(r) if err != nil { return uuid, err } makeV7(uuid[:]) return uuid, nil } // makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) // uuid[8] already has the right version number (Variant is 10) // see function NewV7 and NewV7FromReader func makeV7(uuid []byte) { /* 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | unix_ts_ms | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | unix_ts_ms | ver | rand_a (12 bit seq) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |var| rand_b | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | rand_b | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ _ = uuid[15] // bounds check t, s := getV7Time() uuid[0] = byte(t >> 40) uuid[1] = byte(t >> 32) uuid[2] = byte(t >> 24) uuid[3] = byte(t >> 16) uuid[4] = byte(t >> 8) uuid[5] = byte(t) uuid[6] = 0x70 | (0x0F & byte(s>>8)) uuid[7] = byte(s) } // lastV7time is the last time we returned stored as: // // 52 bits of time in milliseconds since epoch // 12 bits of (fractional nanoseconds) >> 8 var lastV7time int64 const nanoPerMilli = 1000000 // getV7Time returns the time in milliseconds and nanoseconds / 256. // The returned (milli << 12 + seq) is guarenteed to be greater than // (milli << 12 + seq) returned by any previous call to getV7Time. func getV7Time() (milli, seq int64) { timeMu.Lock() defer timeMu.Unlock() nano := timeNow().UnixNano() milli = nano / nanoPerMilli // Sequence number is between 0 and 3906 (nanoPerMilli>>8) seq = (nano - milli*nanoPerMilli) >> 8 now := milli<<12 + seq if now <= lastV7time { now = lastV7time + 1 milli = now >> 12 seq = now & 0xfff } lastV7time = now return milli, seq }