aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/rs/xid
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/rs/xid')
-rw-r--r--vendor/github.com/rs/xid/.appveyor.yml27
-rw-r--r--vendor/github.com/rs/xid/.golangci.yml5
-rw-r--r--vendor/github.com/rs/xid/.travis.yml8
-rw-r--r--vendor/github.com/rs/xid/LICENSE19
-rw-r--r--vendor/github.com/rs/xid/README.md119
-rw-r--r--vendor/github.com/rs/xid/error.go11
-rw-r--r--vendor/github.com/rs/xid/hostid_darwin.go9
-rw-r--r--vendor/github.com/rs/xid/hostid_fallback.go9
-rw-r--r--vendor/github.com/rs/xid/hostid_freebsd.go9
-rw-r--r--vendor/github.com/rs/xid/hostid_linux.go13
-rw-r--r--vendor/github.com/rs/xid/hostid_windows.go38
-rw-r--r--vendor/github.com/rs/xid/id.go391
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 @@
1version: 1.0.0.{build}
2
3platform: x64
4
5branches:
6 only:
7 - master
8
9clone_folder: c:\gopath\src\github.com\rs\xid
10
11environment:
12 GOPATH: c:\gopath
13
14install:
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
22build_script:
23 - go build
24
25test_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 @@
1run:
2 tests: false
3
4output:
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 @@
1language: go
2go:
3- "1.9"
4- "1.10"
5- "master"
6matrix:
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 @@
1Copyright (c) 2015 Olivier Poitrey <[email protected]>
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE 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
5Package xid is a globally unique id generator library, ready to safely be used directly in your server code.
6
7Xid 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:
8https://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
15The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
16The string representation is using base32 hex (w/o padding) for better space efficiency
17when stored in that form (20 bytes). The hex variant of base32 is used to retain the
18sortable property of the id.
19
20Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
21issue when transported as a string between various systems. Base36 wasn't retained either
22because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
23and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
24all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
25
26UUIDs are 16 bytes (128 bits) and 36 chars as string representation. Twitter Snowflake
27ids are 8 bytes (64 bits) but require machine/data-center configuration and/or central
28generator servers. xid stands in between with 12 bytes (96 bits) and a more compact
29URL-safe string representation (20 chars). No configuration or central generator server
30is 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
45Features:
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
55Best used with [zerolog](https://github.com/rs/zerolog)'s
56[RequestIDHandler](https://godoc.org/github.com/rs/zerolog/hlog#RequestIDHandler).
57
58Notes:
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
62References:
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
84guid := xid.New()
85
86println(guid.String())
87// Output: 9m4e2mr0ui3e8a215n4g
88```
89
90Get `xid` embedded info:
91
92```go
93guid.Machine()
94guid.Pid()
95guid.Time()
96guid.Counter()
97```
98
99## Benchmark
100
101Benchmark against Go [Maxim Bublis](https://github.com/satori)'s [UUID](https://github.com/satori/go.uuid).
102
103```
104BenchmarkXID 20000000 91.1 ns/op 32 B/op 1 allocs/op
105BenchmarkXID-2 20000000 55.9 ns/op 32 B/op 1 allocs/op
106BenchmarkXID-4 50000000 32.3 ns/op 32 B/op 1 allocs/op
107BenchmarkUUIDv1 10000000 204 ns/op 48 B/op 1 allocs/op
108BenchmarkUUIDv1-2 10000000 160 ns/op 48 B/op 1 allocs/op
109BenchmarkUUIDv1-4 10000000 195 ns/op 48 B/op 1 allocs/op
110BenchmarkUUIDv4 1000000 1503 ns/op 64 B/op 2 allocs/op
111BenchmarkUUIDv4-2 1000000 1427 ns/op 64 B/op 2 allocs/op
112BenchmarkUUIDv4-4 1000000 1452 ns/op 64 B/op 2 allocs/op
113```
114
115Note: UUIDv1 requires a global lock, hence the performance degradation as we add more CPUs.
116
117## Licenses
118
119All 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 @@
1package xid
2
3const (
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.
9type strErr string
10
11func (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
3package xid
4
5import "syscall"
6
7func 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
3package xid
4
5import "errors"
6
7func 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
3package xid
4
5import "syscall"
6
7func 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
3package xid
4
5import "io/ioutil"
6
7func 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
3package xid
4
5import (
6 "fmt"
7 "syscall"
8 "unsafe"
9)
10
11func 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(&regBuf[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
42package xid
43
44import (
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
63type ID [rawLen]byte
64
65const (
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
74var (
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
91func 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.
111func 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
131func 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
140func New() ID {
141 return NewWithTime(time.Now())
142}
143
144// NewWithTime generates a globally unique ID with the passed in time
145func 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
165func 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).
172func (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.
179func (id ID) Encode(dst []byte) []byte {
180 encode(dst, id[:])
181 return dst
182}
183
184// MarshalText implements encoding/text TextMarshaler interface
185func (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
192func (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
203func 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
230func (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
247func (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.
261func 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.
286func (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.
294func (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.
300func (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.
306func (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.
313func (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.
322func (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
337func (id ID) IsNil() bool {
338 return id == nilID
339}
340
341// Alias of IsNil
342func (id ID) IsZero() bool {
343 return id.IsNil()
344}
345
346// NilID returns a zero value for `xid.ID`.
347func NilID() ID {
348 return nilID
349}
350
351// Bytes returns the byte array representation of `ID`
352func (id ID) Bytes() []byte {
353 return id[:]
354}
355
356// FromBytes convert the byte array representation of `ID` back to `ID`
357func 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.
369func (id ID) Compare(other ID) int {
370 return bytes.Compare(id[:], other[:])
371}
372
373type sorter []ID
374
375func (s sorter) Len() int {
376 return len(s)
377}
378
379func (s sorter) Less(i, j int) bool {
380 return s[i].Compare(s[j]) < 0
381}
382
383func (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`.
389func Sort(ids []ID) {
390 sort.Sort(sorter(ids))
391}