diff options
| author | Rutger Broekhoff | 2023-12-29 21:31:53 +0100 |
|---|---|---|
| committer | Rutger Broekhoff | 2023-12-29 21:31:53 +0100 |
| commit | 404aeae4545d2426c089a5f8d5e82dae56f5212b (patch) | |
| tree | 2d84e00af272b39fc04f3795ae06bc48970e57b5 /vendor/github.com/rs/xid | |
| parent | 209d8b0187ed025dec9ac149ebcced3462877bff (diff) | |
| download | gitolfs3-404aeae4545d2426c089a5f8d5e82dae56f5212b.tar.gz gitolfs3-404aeae4545d2426c089a5f8d5e82dae56f5212b.zip | |
Make Nix builds work
Diffstat (limited to 'vendor/github.com/rs/xid')
| -rw-r--r-- | vendor/github.com/rs/xid/.appveyor.yml | 27 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/.golangci.yml | 5 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/.travis.yml | 8 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/LICENSE | 19 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/README.md | 119 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/error.go | 11 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/hostid_darwin.go | 9 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/hostid_fallback.go | 9 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/hostid_freebsd.go | 9 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/hostid_linux.go | 13 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/hostid_windows.go | 38 | ||||
| -rw-r--r-- | vendor/github.com/rs/xid/id.go | 391 |
12 files changed, 658 insertions, 0 deletions
diff --git a/vendor/github.com/rs/xid/.appveyor.yml b/vendor/github.com/rs/xid/.appveyor.yml new file mode 100644 index 0000000..c73bb33 --- /dev/null +++ b/vendor/github.com/rs/xid/.appveyor.yml | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | version: 1.0.0.{build} | ||
| 2 | |||
| 3 | platform: x64 | ||
| 4 | |||
| 5 | branches: | ||
| 6 | only: | ||
| 7 | - master | ||
| 8 | |||
| 9 | clone_folder: c:\gopath\src\github.com\rs\xid | ||
| 10 | |||
| 11 | environment: | ||
| 12 | GOPATH: c:\gopath | ||
| 13 | |||
| 14 | install: | ||
| 15 | - echo %PATH% | ||
| 16 | - echo %GOPATH% | ||
| 17 | - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% | ||
| 18 | - go version | ||
| 19 | - go env | ||
| 20 | - go get -t . | ||
| 21 | |||
| 22 | build_script: | ||
| 23 | - go build | ||
| 24 | |||
| 25 | test_script: | ||
| 26 | - go test | ||
| 27 | |||
diff --git a/vendor/github.com/rs/xid/.golangci.yml b/vendor/github.com/rs/xid/.golangci.yml new file mode 100644 index 0000000..7929600 --- /dev/null +++ b/vendor/github.com/rs/xid/.golangci.yml | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | run: | ||
| 2 | tests: false | ||
| 3 | |||
| 4 | output: | ||
| 5 | sort-results: true | ||
diff --git a/vendor/github.com/rs/xid/.travis.yml b/vendor/github.com/rs/xid/.travis.yml new file mode 100644 index 0000000..b37da15 --- /dev/null +++ b/vendor/github.com/rs/xid/.travis.yml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | language: go | ||
| 2 | go: | ||
| 3 | - "1.9" | ||
| 4 | - "1.10" | ||
| 5 | - "master" | ||
| 6 | matrix: | ||
| 7 | allow_failures: | ||
| 8 | - go: "master" | ||
diff --git a/vendor/github.com/rs/xid/LICENSE b/vendor/github.com/rs/xid/LICENSE new file mode 100644 index 0000000..47c5e9d --- /dev/null +++ b/vendor/github.com/rs/xid/LICENSE | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | Copyright (c) 2015 Olivier Poitrey <[email protected]> | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 4 | of this software and associated documentation files (the "Software"), to deal | ||
| 5 | in the Software without restriction, including without limitation the rights | ||
| 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 7 | copies of the Software, and to permit persons to whom the Software is furnished | ||
| 8 | to do so, subject to the following conditions: | ||
| 9 | |||
| 10 | The above copyright notice and this permission notice shall be included in all | ||
| 11 | copies or substantial portions of the Software. | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 19 | THE SOFTWARE. | ||
diff --git a/vendor/github.com/rs/xid/README.md b/vendor/github.com/rs/xid/README.md new file mode 100644 index 0000000..974e67d --- /dev/null +++ b/vendor/github.com/rs/xid/README.md | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | # Globally Unique ID Generator | ||
| 2 | |||
| 3 | [](https://godoc.org/github.com/rs/xid) [](https://raw.githubusercontent.com/rs/xid/master/LICENSE) [](https://travis-ci.org/rs/xid) [](http://gocover.io/github.com/rs/xid) | ||
| 4 | |||
| 5 | Package xid is a globally unique id generator library, ready to safely be used directly in your server code. | ||
| 6 | |||
| 7 | Xid uses the Mongo Object ID algorithm to generate globally unique ids with a different serialization (base64) to make it shorter when transported as a string: | ||
| 8 | https://docs.mongodb.org/manual/reference/object-id/ | ||
| 9 | |||
| 10 | - 4-byte value representing the seconds since the Unix epoch, | ||
| 11 | - 3-byte machine identifier, | ||
| 12 | - 2-byte process id, and | ||
| 13 | - 3-byte counter, starting with a random value. | ||
| 14 | |||
| 15 | The binary representation of the id is compatible with Mongo 12 bytes Object IDs. | ||
| 16 | The string representation is using base32 hex (w/o padding) for better space efficiency | ||
| 17 | when stored in that form (20 bytes). The hex variant of base32 is used to retain the | ||
| 18 | sortable property of the id. | ||
| 19 | |||
| 20 | Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an | ||
| 21 | issue when transported as a string between various systems. Base36 wasn't retained either | ||
| 22 | because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned) | ||
| 23 | and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long, | ||
| 24 | all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`). | ||
| 25 | |||
| 26 | UUIDs are 16 bytes (128 bits) and 36 chars as string representation. Twitter Snowflake | ||
| 27 | ids are 8 bytes (64 bits) but require machine/data-center configuration and/or central | ||
| 28 | generator servers. xid stands in between with 12 bytes (96 bits) and a more compact | ||
| 29 | URL-safe string representation (20 chars). No configuration or central generator server | ||
| 30 | is required so it can be used directly in server's code. | ||
| 31 | |||
| 32 | | Name | Binary Size | String Size | Features | ||
| 33 | |-------------|-------------|----------------|---------------- | ||
| 34 | | [UUID] | 16 bytes | 36 chars | configuration free, not sortable | ||
| 35 | | [shortuuid] | 16 bytes | 22 chars | configuration free, not sortable | ||
| 36 | | [Snowflake] | 8 bytes | up to 20 chars | needs machine/DC configuration, needs central server, sortable | ||
| 37 | | [MongoID] | 12 bytes | 24 chars | configuration free, sortable | ||
| 38 | | xid | 12 bytes | 20 chars | configuration free, sortable | ||
| 39 | |||
| 40 | [UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier | ||
| 41 | [shortuuid]: https://github.com/stochastic-technologies/shortuuid | ||
| 42 | [Snowflake]: https://blog.twitter.com/2010/announcing-snowflake | ||
| 43 | [MongoID]: https://docs.mongodb.org/manual/reference/object-id/ | ||
| 44 | |||
| 45 | Features: | ||
| 46 | |||
| 47 | - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake | ||
| 48 | - Base32 hex encoded by default (20 chars when transported as printable string, still sortable) | ||
| 49 | - Non configured, you don't need set a unique machine and/or data center id | ||
| 50 | - K-ordered | ||
| 51 | - Embedded time with 1 second precision | ||
| 52 | - Unicity guaranteed for 16,777,216 (24 bits) unique ids per second and per host/process | ||
| 53 | - Lock-free (i.e.: unlike UUIDv1 and v2) | ||
| 54 | |||
| 55 | Best used with [zerolog](https://github.com/rs/zerolog)'s | ||
| 56 | [RequestIDHandler](https://godoc.org/github.com/rs/zerolog/hlog#RequestIDHandler). | ||
| 57 | |||
| 58 | Notes: | ||
| 59 | |||
| 60 | - Xid is dependent on the system time, a monotonic counter and so is not cryptographically secure. If unpredictability of IDs is important, you should not use Xids. It is worth noting that most other UUID-like implementations are also not cryptographically secure. You should use libraries that rely on cryptographically secure sources (like /dev/urandom on unix, crypto/rand in golang), if you want a truly random ID generator. | ||
| 61 | |||
| 62 | References: | ||
| 63 | |||
| 64 | - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems | ||
| 65 | - https://en.wikipedia.org/wiki/Universally_unique_identifier | ||
| 66 | - https://blog.twitter.com/2010/announcing-snowflake | ||
| 67 | - Python port by [Graham Abbott](https://github.com/graham): https://github.com/graham/python_xid | ||
| 68 | - Scala port by [Egor Kolotaev](https://github.com/kolotaev): https://github.com/kolotaev/ride | ||
| 69 | - Rust port by [Jérôme Renard](https://github.com/jeromer/): https://github.com/jeromer/libxid | ||
| 70 | - Ruby port by [Valar](https://github.com/valarpirai/): https://github.com/valarpirai/ruby_xid | ||
| 71 | - Java port by [0xShamil](https://github.com/0xShamil/): https://github.com/0xShamil/java-xid | ||
| 72 | - Dart port by [Peter Bwire](https://github.com/pitabwire): https://pub.dev/packages/xid | ||
| 73 | - PostgreSQL port by [Rasmus Holm](https://github.com/crholm): https://github.com/modfin/pg-xid | ||
| 74 | - Swift port by [Uditha Atukorala](https://github.com/uditha-atukorala): https://github.com/uditha-atukorala/swift-xid | ||
| 75 | - C++ port by [Uditha Atukorala](https://github.com/uditha-atukorala): https://github.com/uditha-atukorala/libxid | ||
| 76 | |||
| 77 | ## Install | ||
| 78 | |||
| 79 | go get github.com/rs/xid | ||
| 80 | |||
| 81 | ## Usage | ||
| 82 | |||
| 83 | ```go | ||
| 84 | guid := xid.New() | ||
| 85 | |||
| 86 | println(guid.String()) | ||
| 87 | // Output: 9m4e2mr0ui3e8a215n4g | ||
| 88 | ``` | ||
| 89 | |||
| 90 | Get `xid` embedded info: | ||
| 91 | |||
| 92 | ```go | ||
| 93 | guid.Machine() | ||
| 94 | guid.Pid() | ||
| 95 | guid.Time() | ||
| 96 | guid.Counter() | ||
| 97 | ``` | ||
| 98 | |||
| 99 | ## Benchmark | ||
| 100 | |||
| 101 | Benchmark against Go [Maxim Bublis](https://github.com/satori)'s [UUID](https://github.com/satori/go.uuid). | ||
| 102 | |||
| 103 | ``` | ||
| 104 | BenchmarkXID 20000000 91.1 ns/op 32 B/op 1 allocs/op | ||
| 105 | BenchmarkXID-2 20000000 55.9 ns/op 32 B/op 1 allocs/op | ||
| 106 | BenchmarkXID-4 50000000 32.3 ns/op 32 B/op 1 allocs/op | ||
| 107 | BenchmarkUUIDv1 10000000 204 ns/op 48 B/op 1 allocs/op | ||
| 108 | BenchmarkUUIDv1-2 10000000 160 ns/op 48 B/op 1 allocs/op | ||
| 109 | BenchmarkUUIDv1-4 10000000 195 ns/op 48 B/op 1 allocs/op | ||
| 110 | BenchmarkUUIDv4 1000000 1503 ns/op 64 B/op 2 allocs/op | ||
| 111 | BenchmarkUUIDv4-2 1000000 1427 ns/op 64 B/op 2 allocs/op | ||
| 112 | BenchmarkUUIDv4-4 1000000 1452 ns/op 64 B/op 2 allocs/op | ||
| 113 | ``` | ||
| 114 | |||
| 115 | Note: UUIDv1 requires a global lock, hence the performance degradation as we add more CPUs. | ||
| 116 | |||
| 117 | ## Licenses | ||
| 118 | |||
| 119 | All source code is licensed under the [MIT License](https://raw.github.com/rs/xid/master/LICENSE). | ||
diff --git a/vendor/github.com/rs/xid/error.go b/vendor/github.com/rs/xid/error.go new file mode 100644 index 0000000..ea25374 --- /dev/null +++ b/vendor/github.com/rs/xid/error.go | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | package xid | ||
| 2 | |||
| 3 | const ( | ||
| 4 | // ErrInvalidID is returned when trying to unmarshal an invalid ID. | ||
| 5 | ErrInvalidID strErr = "xid: invalid ID" | ||
| 6 | ) | ||
| 7 | |||
| 8 | // strErr allows declaring errors as constants. | ||
| 9 | type strErr string | ||
| 10 | |||
| 11 | func (err strErr) Error() string { return string(err) } | ||
diff --git a/vendor/github.com/rs/xid/hostid_darwin.go b/vendor/github.com/rs/xid/hostid_darwin.go new file mode 100644 index 0000000..08351ff --- /dev/null +++ b/vendor/github.com/rs/xid/hostid_darwin.go | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // +build darwin | ||
| 2 | |||
| 3 | package xid | ||
| 4 | |||
| 5 | import "syscall" | ||
| 6 | |||
| 7 | func readPlatformMachineID() (string, error) { | ||
| 8 | return syscall.Sysctl("kern.uuid") | ||
| 9 | } | ||
diff --git a/vendor/github.com/rs/xid/hostid_fallback.go b/vendor/github.com/rs/xid/hostid_fallback.go new file mode 100644 index 0000000..7fbd3c0 --- /dev/null +++ b/vendor/github.com/rs/xid/hostid_fallback.go | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // +build !darwin,!linux,!freebsd,!windows | ||
| 2 | |||
| 3 | package xid | ||
| 4 | |||
| 5 | import "errors" | ||
| 6 | |||
| 7 | func readPlatformMachineID() (string, error) { | ||
| 8 | return "", errors.New("not implemented") | ||
| 9 | } | ||
diff --git a/vendor/github.com/rs/xid/hostid_freebsd.go b/vendor/github.com/rs/xid/hostid_freebsd.go new file mode 100644 index 0000000..be25a03 --- /dev/null +++ b/vendor/github.com/rs/xid/hostid_freebsd.go | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // +build freebsd | ||
| 2 | |||
| 3 | package xid | ||
| 4 | |||
| 5 | import "syscall" | ||
| 6 | |||
| 7 | func readPlatformMachineID() (string, error) { | ||
| 8 | return syscall.Sysctl("kern.hostuuid") | ||
| 9 | } | ||
diff --git a/vendor/github.com/rs/xid/hostid_linux.go b/vendor/github.com/rs/xid/hostid_linux.go new file mode 100644 index 0000000..837b204 --- /dev/null +++ b/vendor/github.com/rs/xid/hostid_linux.go | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // +build linux | ||
| 2 | |||
| 3 | package xid | ||
| 4 | |||
| 5 | import "io/ioutil" | ||
| 6 | |||
| 7 | func readPlatformMachineID() (string, error) { | ||
| 8 | b, err := ioutil.ReadFile("/etc/machine-id") | ||
| 9 | if err != nil || len(b) == 0 { | ||
| 10 | b, err = ioutil.ReadFile("/sys/class/dmi/id/product_uuid") | ||
| 11 | } | ||
| 12 | return string(b), err | ||
| 13 | } | ||
diff --git a/vendor/github.com/rs/xid/hostid_windows.go b/vendor/github.com/rs/xid/hostid_windows.go new file mode 100644 index 0000000..ec2593e --- /dev/null +++ b/vendor/github.com/rs/xid/hostid_windows.go | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // +build windows | ||
| 2 | |||
| 3 | package xid | ||
| 4 | |||
| 5 | import ( | ||
| 6 | "fmt" | ||
| 7 | "syscall" | ||
| 8 | "unsafe" | ||
| 9 | ) | ||
| 10 | |||
| 11 | func readPlatformMachineID() (string, error) { | ||
| 12 | // source: https://github.com/shirou/gopsutil/blob/master/host/host_syscall.go | ||
| 13 | var h syscall.Handle | ||
| 14 | err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, syscall.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, syscall.KEY_READ|syscall.KEY_WOW64_64KEY, &h) | ||
| 15 | if err != nil { | ||
| 16 | return "", err | ||
| 17 | } | ||
| 18 | defer syscall.RegCloseKey(h) | ||
| 19 | |||
| 20 | const syscallRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16 | ||
| 21 | const uuidLen = 36 | ||
| 22 | |||
| 23 | var regBuf [syscallRegBufLen]uint16 | ||
| 24 | bufLen := uint32(syscallRegBufLen) | ||
| 25 | var valType uint32 | ||
| 26 | err = syscall.RegQueryValueEx(h, syscall.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) | ||
| 27 | if err != nil { | ||
| 28 | return "", err | ||
| 29 | } | ||
| 30 | |||
| 31 | hostID := syscall.UTF16ToString(regBuf[:]) | ||
| 32 | hostIDLen := len(hostID) | ||
| 33 | if hostIDLen != uuidLen { | ||
| 34 | return "", fmt.Errorf("HostID incorrect: %q\n", hostID) | ||
| 35 | } | ||
| 36 | |||
| 37 | return hostID, nil | ||
| 38 | } | ||
diff --git a/vendor/github.com/rs/xid/id.go b/vendor/github.com/rs/xid/id.go new file mode 100644 index 0000000..fcd7a04 --- /dev/null +++ b/vendor/github.com/rs/xid/id.go | |||
| @@ -0,0 +1,391 @@ | |||
| 1 | // Package xid is a globally unique id generator suited for web scale | ||
| 2 | // | ||
| 3 | // Xid is using Mongo Object ID algorithm to generate globally unique ids: | ||
| 4 | // https://docs.mongodb.org/manual/reference/object-id/ | ||
| 5 | // | ||
| 6 | // - 4-byte value representing the seconds since the Unix epoch, | ||
| 7 | // - 3-byte machine identifier, | ||
| 8 | // - 2-byte process id, and | ||
| 9 | // - 3-byte counter, starting with a random value. | ||
| 10 | // | ||
| 11 | // The binary representation of the id is compatible with Mongo 12 bytes Object IDs. | ||
| 12 | // The string representation is using base32 hex (w/o padding) for better space efficiency | ||
| 13 | // when stored in that form (20 bytes). The hex variant of base32 is used to retain the | ||
| 14 | // sortable property of the id. | ||
| 15 | // | ||
| 16 | // Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an | ||
| 17 | // issue when transported as a string between various systems. Base36 wasn't retained either | ||
| 18 | // because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned) | ||
| 19 | // and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long, | ||
| 20 | // all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`). | ||
| 21 | // | ||
| 22 | // UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between | ||
| 23 | // with 12 bytes with a more compact string representation ready for the web and no | ||
| 24 | // required configuration or central generation server. | ||
| 25 | // | ||
| 26 | // Features: | ||
| 27 | // | ||
| 28 | // - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake | ||
| 29 | // - Base32 hex encoded by default (16 bytes storage when transported as printable string) | ||
| 30 | // - Non configured, you don't need set a unique machine and/or data center id | ||
| 31 | // - K-ordered | ||
| 32 | // - Embedded time with 1 second precision | ||
| 33 | // - Unicity guaranteed for 16,777,216 (24 bits) unique ids per second and per host/process | ||
| 34 | // | ||
| 35 | // Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler). | ||
| 36 | // | ||
| 37 | // References: | ||
| 38 | // | ||
| 39 | // - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems | ||
| 40 | // - https://en.wikipedia.org/wiki/Universally_unique_identifier | ||
| 41 | // - https://blog.twitter.com/2010/announcing-snowflake | ||
| 42 | package xid | ||
| 43 | |||
| 44 | import ( | ||
| 45 | "bytes" | ||
| 46 | "crypto/sha256" | ||
| 47 | "crypto/rand" | ||
| 48 | "database/sql/driver" | ||
| 49 | "encoding/binary" | ||
| 50 | "fmt" | ||
| 51 | "hash/crc32" | ||
| 52 | "io/ioutil" | ||
| 53 | "os" | ||
| 54 | "sort" | ||
| 55 | "sync/atomic" | ||
| 56 | "time" | ||
| 57 | "unsafe" | ||
| 58 | ) | ||
| 59 | |||
| 60 | // Code inspired from mgo/bson ObjectId | ||
| 61 | |||
| 62 | // ID represents a unique request id | ||
| 63 | type ID [rawLen]byte | ||
| 64 | |||
| 65 | const ( | ||
| 66 | encodedLen = 20 // string encoded len | ||
| 67 | rawLen = 12 // binary raw len | ||
| 68 | |||
| 69 | // encoding stores a custom version of the base32 encoding with lower case | ||
| 70 | // letters. | ||
| 71 | encoding = "0123456789abcdefghijklmnopqrstuv" | ||
| 72 | ) | ||
| 73 | |||
| 74 | var ( | ||
| 75 | // objectIDCounter is atomically incremented when generating a new ObjectId. It's | ||
| 76 | // used as the counter part of an id. This id is initialized with a random value. | ||
| 77 | objectIDCounter = randInt() | ||
| 78 | |||
| 79 | // machineID is generated once and used in subsequent calls to the New* functions. | ||
| 80 | machineID = readMachineID() | ||
| 81 | |||
| 82 | // pid stores the current process id | ||
| 83 | pid = os.Getpid() | ||
| 84 | |||
| 85 | nilID ID | ||
| 86 | |||
| 87 | // dec is the decoding map for base32 encoding | ||
| 88 | dec [256]byte | ||
| 89 | ) | ||
| 90 | |||
| 91 | func init() { | ||
| 92 | for i := 0; i < len(dec); i++ { | ||
| 93 | dec[i] = 0xFF | ||
| 94 | } | ||
| 95 | for i := 0; i < len(encoding); i++ { | ||
| 96 | dec[encoding[i]] = byte(i) | ||
| 97 | } | ||
| 98 | |||
| 99 | // If /proc/self/cpuset exists and is not /, we can assume that we are in a | ||
| 100 | // form of container and use the content of cpuset xor-ed with the PID in | ||
| 101 | // order get a reasonable machine global unique PID. | ||
| 102 | b, err := ioutil.ReadFile("/proc/self/cpuset") | ||
| 103 | if err == nil && len(b) > 1 { | ||
| 104 | pid ^= int(crc32.ChecksumIEEE(b)) | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | // readMachineID generates a machine ID, derived from a platform-specific machine ID | ||
| 109 | // value, or else the machine's hostname, or else a randomly-generated number. | ||
| 110 | // It panics if all of these methods fail. | ||
| 111 | func readMachineID() []byte { | ||
| 112 | id := make([]byte, 3) | ||
| 113 | hid, err := readPlatformMachineID() | ||
| 114 | if err != nil || len(hid) == 0 { | ||
| 115 | hid, err = os.Hostname() | ||
| 116 | } | ||
| 117 | if err == nil && len(hid) != 0 { | ||
| 118 | hw := sha256.New() | ||
| 119 | hw.Write([]byte(hid)) | ||
| 120 | copy(id, hw.Sum(nil)) | ||
| 121 | } else { | ||
| 122 | // Fallback to rand number if machine id can't be gathered | ||
| 123 | if _, randErr := rand.Reader.Read(id); randErr != nil { | ||
| 124 | panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr)) | ||
| 125 | } | ||
| 126 | } | ||
| 127 | return id | ||
| 128 | } | ||
| 129 | |||
| 130 | // randInt generates a random uint32 | ||
| 131 | func randInt() uint32 { | ||
| 132 | b := make([]byte, 3) | ||
| 133 | if _, err := rand.Reader.Read(b); err != nil { | ||
| 134 | panic(fmt.Errorf("xid: cannot generate random number: %v;", err)) | ||
| 135 | } | ||
| 136 | return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]) | ||
| 137 | } | ||
| 138 | |||
| 139 | // New generates a globally unique ID | ||
| 140 | func New() ID { | ||
| 141 | return NewWithTime(time.Now()) | ||
| 142 | } | ||
| 143 | |||
| 144 | // NewWithTime generates a globally unique ID with the passed in time | ||
| 145 | func NewWithTime(t time.Time) ID { | ||
| 146 | var id ID | ||
| 147 | // Timestamp, 4 bytes, big endian | ||
| 148 | binary.BigEndian.PutUint32(id[:], uint32(t.Unix())) | ||
| 149 | // Machine ID, 3 bytes | ||
| 150 | id[4] = machineID[0] | ||
| 151 | id[5] = machineID[1] | ||
| 152 | id[6] = machineID[2] | ||
| 153 | // Pid, 2 bytes, specs don't specify endianness, but we use big endian. | ||
| 154 | id[7] = byte(pid >> 8) | ||
| 155 | id[8] = byte(pid) | ||
| 156 | // Increment, 3 bytes, big endian | ||
| 157 | i := atomic.AddUint32(&objectIDCounter, 1) | ||
| 158 | id[9] = byte(i >> 16) | ||
| 159 | id[10] = byte(i >> 8) | ||
| 160 | id[11] = byte(i) | ||
| 161 | return id | ||
| 162 | } | ||
| 163 | |||
| 164 | // FromString reads an ID from its string representation | ||
| 165 | func FromString(id string) (ID, error) { | ||
| 166 | i := &ID{} | ||
| 167 | err := i.UnmarshalText([]byte(id)) | ||
| 168 | return *i, err | ||
| 169 | } | ||
| 170 | |||
| 171 | // String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v). | ||
| 172 | func (id ID) String() string { | ||
| 173 | text := make([]byte, encodedLen) | ||
| 174 | encode(text, id[:]) | ||
| 175 | return *(*string)(unsafe.Pointer(&text)) | ||
| 176 | } | ||
| 177 | |||
| 178 | // Encode encodes the id using base32 encoding, writing 20 bytes to dst and return it. | ||
| 179 | func (id ID) Encode(dst []byte) []byte { | ||
| 180 | encode(dst, id[:]) | ||
| 181 | return dst | ||
| 182 | } | ||
| 183 | |||
| 184 | // MarshalText implements encoding/text TextMarshaler interface | ||
| 185 | func (id ID) MarshalText() ([]byte, error) { | ||
| 186 | text := make([]byte, encodedLen) | ||
| 187 | encode(text, id[:]) | ||
| 188 | return text, nil | ||
| 189 | } | ||
| 190 | |||
| 191 | // MarshalJSON implements encoding/json Marshaler interface | ||
| 192 | func (id ID) MarshalJSON() ([]byte, error) { | ||
| 193 | if id.IsNil() { | ||
| 194 | return []byte("null"), nil | ||
| 195 | } | ||
| 196 | text := make([]byte, encodedLen+2) | ||
| 197 | encode(text[1:encodedLen+1], id[:]) | ||
| 198 | text[0], text[encodedLen+1] = '"', '"' | ||
| 199 | return text, nil | ||
| 200 | } | ||
| 201 | |||
| 202 | // encode by unrolling the stdlib base32 algorithm + removing all safe checks | ||
| 203 | func encode(dst, id []byte) { | ||
| 204 | _ = dst[19] | ||
| 205 | _ = id[11] | ||
| 206 | |||
| 207 | dst[19] = encoding[(id[11]<<4)&0x1F] | ||
| 208 | dst[18] = encoding[(id[11]>>1)&0x1F] | ||
| 209 | dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] | ||
| 210 | dst[16] = encoding[id[10]>>3] | ||
| 211 | dst[15] = encoding[id[9]&0x1F] | ||
| 212 | dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F] | ||
| 213 | dst[13] = encoding[(id[8]>>2)&0x1F] | ||
| 214 | dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F] | ||
| 215 | dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F] | ||
| 216 | dst[10] = encoding[(id[6]>>1)&0x1F] | ||
| 217 | dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F] | ||
| 218 | dst[8] = encoding[id[5]>>3] | ||
| 219 | dst[7] = encoding[id[4]&0x1F] | ||
| 220 | dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F] | ||
| 221 | dst[5] = encoding[(id[3]>>2)&0x1F] | ||
| 222 | dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F] | ||
| 223 | dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F] | ||
| 224 | dst[2] = encoding[(id[1]>>1)&0x1F] | ||
| 225 | dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F] | ||
| 226 | dst[0] = encoding[id[0]>>3] | ||
| 227 | } | ||
| 228 | |||
| 229 | // UnmarshalText implements encoding/text TextUnmarshaler interface | ||
| 230 | func (id *ID) UnmarshalText(text []byte) error { | ||
| 231 | if len(text) != encodedLen { | ||
| 232 | return ErrInvalidID | ||
| 233 | } | ||
| 234 | for _, c := range text { | ||
| 235 | if dec[c] == 0xFF { | ||
| 236 | return ErrInvalidID | ||
| 237 | } | ||
| 238 | } | ||
| 239 | if !decode(id, text) { | ||
| 240 | *id = nilID | ||
| 241 | return ErrInvalidID | ||
| 242 | } | ||
| 243 | return nil | ||
| 244 | } | ||
| 245 | |||
| 246 | // UnmarshalJSON implements encoding/json Unmarshaler interface | ||
| 247 | func (id *ID) UnmarshalJSON(b []byte) error { | ||
| 248 | s := string(b) | ||
| 249 | if s == "null" { | ||
| 250 | *id = nilID | ||
| 251 | return nil | ||
| 252 | } | ||
| 253 | // Check the slice length to prevent panic on passing it to UnmarshalText() | ||
| 254 | if len(b) < 2 { | ||
| 255 | return ErrInvalidID | ||
| 256 | } | ||
| 257 | return id.UnmarshalText(b[1 : len(b)-1]) | ||
| 258 | } | ||
| 259 | |||
| 260 | // decode by unrolling the stdlib base32 algorithm + customized safe check. | ||
| 261 | func decode(id *ID, src []byte) bool { | ||
| 262 | _ = src[19] | ||
| 263 | _ = id[11] | ||
| 264 | |||
| 265 | id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4 | ||
| 266 | // check the last byte | ||
| 267 | if encoding[(id[11]<<4)&0x1F] != src[19] { | ||
| 268 | return false | ||
| 269 | } | ||
| 270 | id[10] = dec[src[16]]<<3 | dec[src[17]]>>2 | ||
| 271 | id[9] = dec[src[14]]<<5 | dec[src[15]] | ||
| 272 | id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3 | ||
| 273 | id[7] = dec[src[11]]<<4 | dec[src[12]]>>1 | ||
| 274 | id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4 | ||
| 275 | id[5] = dec[src[8]]<<3 | dec[src[9]]>>2 | ||
| 276 | id[4] = dec[src[6]]<<5 | dec[src[7]] | ||
| 277 | id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3 | ||
| 278 | id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 | ||
| 279 | id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 | ||
| 280 | id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 | ||
| 281 | return true | ||
| 282 | } | ||
| 283 | |||
| 284 | // Time returns the timestamp part of the id. | ||
| 285 | // It's a runtime error to call this method with an invalid id. | ||
| 286 | func (id ID) Time() time.Time { | ||
| 287 | // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. | ||
| 288 | secs := int64(binary.BigEndian.Uint32(id[0:4])) | ||
| 289 | return time.Unix(secs, 0) | ||
| 290 | } | ||
| 291 | |||
| 292 | // Machine returns the 3-byte machine id part of the id. | ||
| 293 | // It's a runtime error to call this method with an invalid id. | ||
| 294 | func (id ID) Machine() []byte { | ||
| 295 | return id[4:7] | ||
| 296 | } | ||
| 297 | |||
| 298 | // Pid returns the process id part of the id. | ||
| 299 | // It's a runtime error to call this method with an invalid id. | ||
| 300 | func (id ID) Pid() uint16 { | ||
| 301 | return binary.BigEndian.Uint16(id[7:9]) | ||
| 302 | } | ||
| 303 | |||
| 304 | // Counter returns the incrementing value part of the id. | ||
| 305 | // It's a runtime error to call this method with an invalid id. | ||
| 306 | func (id ID) Counter() int32 { | ||
| 307 | b := id[9:12] | ||
| 308 | // Counter is stored as big-endian 3-byte value | ||
| 309 | return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) | ||
| 310 | } | ||
| 311 | |||
| 312 | // Value implements the driver.Valuer interface. | ||
| 313 | func (id ID) Value() (driver.Value, error) { | ||
| 314 | if id.IsNil() { | ||
| 315 | return nil, nil | ||
| 316 | } | ||
| 317 | b, err := id.MarshalText() | ||
| 318 | return string(b), err | ||
| 319 | } | ||
| 320 | |||
| 321 | // Scan implements the sql.Scanner interface. | ||
| 322 | func (id *ID) Scan(value interface{}) (err error) { | ||
| 323 | switch val := value.(type) { | ||
| 324 | case string: | ||
| 325 | return id.UnmarshalText([]byte(val)) | ||
| 326 | case []byte: | ||
| 327 | return id.UnmarshalText(val) | ||
| 328 | case nil: | ||
| 329 | *id = nilID | ||
| 330 | return nil | ||
| 331 | default: | ||
| 332 | return fmt.Errorf("xid: scanning unsupported type: %T", value) | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | // IsNil Returns true if this is a "nil" ID | ||
| 337 | func (id ID) IsNil() bool { | ||
| 338 | return id == nilID | ||
| 339 | } | ||
| 340 | |||
| 341 | // Alias of IsNil | ||
| 342 | func (id ID) IsZero() bool { | ||
| 343 | return id.IsNil() | ||
| 344 | } | ||
| 345 | |||
| 346 | // NilID returns a zero value for `xid.ID`. | ||
| 347 | func NilID() ID { | ||
| 348 | return nilID | ||
| 349 | } | ||
| 350 | |||
| 351 | // Bytes returns the byte array representation of `ID` | ||
| 352 | func (id ID) Bytes() []byte { | ||
| 353 | return id[:] | ||
| 354 | } | ||
| 355 | |||
| 356 | // FromBytes convert the byte array representation of `ID` back to `ID` | ||
| 357 | func FromBytes(b []byte) (ID, error) { | ||
| 358 | var id ID | ||
| 359 | if len(b) != rawLen { | ||
| 360 | return id, ErrInvalidID | ||
| 361 | } | ||
| 362 | copy(id[:], b) | ||
| 363 | return id, nil | ||
| 364 | } | ||
| 365 | |||
| 366 | // Compare returns an integer comparing two IDs. It behaves just like `bytes.Compare`. | ||
| 367 | // The result will be 0 if two IDs are identical, -1 if current id is less than the other one, | ||
| 368 | // and 1 if current id is greater than the other. | ||
| 369 | func (id ID) Compare(other ID) int { | ||
| 370 | return bytes.Compare(id[:], other[:]) | ||
| 371 | } | ||
| 372 | |||
| 373 | type sorter []ID | ||
| 374 | |||
| 375 | func (s sorter) Len() int { | ||
| 376 | return len(s) | ||
| 377 | } | ||
| 378 | |||
| 379 | func (s sorter) Less(i, j int) bool { | ||
| 380 | return s[i].Compare(s[j]) < 0 | ||
| 381 | } | ||
| 382 | |||
| 383 | func (s sorter) Swap(i, j int) { | ||
| 384 | s[i], s[j] = s[j], s[i] | ||
| 385 | } | ||
| 386 | |||
| 387 | // Sort sorts an array of IDs inplace. | ||
| 388 | // It works by wrapping `[]ID` and use `sort.Sort`. | ||
| 389 | func Sort(ids []ID) { | ||
| 390 | sort.Sort(sorter(ids)) | ||
| 391 | } | ||