diff options
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 | [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/xid) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/xid/master/LICENSE) [![Build Status](https://travis-ci.org/rs/xid.svg?branch=master)](https://travis-ci.org/rs/xid) [![Coverage](http://gocover.io/_badge/github.com/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 | } | ||