This repository has been archived by the owner on Jan 17, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
ulid.go
94 lines (84 loc) · 2.27 KB
/
ulid.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package ulid
import (
"crypto/rand"
"encoding/binary"
"time"
)
// A ULID is a 16 byte Universally Unique Lexicographically Sortable Identifier
type ULID [16]byte
const (
// Crockford"s Base32
// https://en.wikipedia.org/wiki/Base32
alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
alphabetSize = int64(len(alphabet))
encodedTimeLength = 10
encodedRandLength = 16
)
var (
rander = rand.Reader // random function
// Nil as empty value to handle errors
Nil ULID
)
// New is creates a new random ULID or panics. New is equivalent to
// the expression
//
// ulid.Must(ulid.NewRandom())
func New() ULID {
return Must(NewRandom())
}
// Must returns ulid if err is nil and panics otherwise.
func Must(ulid ULID, err error) ULID {
if err != nil {
panic(err)
}
return ulid
}
// NewRandom returns a ULID (binary implementation) or panics.
//
// The strength of the ULIDs is based on the strength of the crypto/rand
// package.
func NewRandom() (ULID, error) {
var (
ulid ULID
)
err := setRandom(&ulid)
if err != nil {
return Nil, err
}
setTime(&ulid, time.Now())
return ulid, err
}
func setTime(ulid *ULID, t time.Time) {
var x, y byte
timestamp := uint64(t.UnixNano() / int64(time.Millisecond))
// Backups [6] and [7] bytes to override them with their original values later.
x, y, ulid[6], ulid[7] = ulid[6], ulid[7], x, y
binary.LittleEndian.PutUint64(ulid[:], timestamp)
// Truncates at the 6th byte as designed in the original spec (48 bytes).
ulid[6], ulid[7] = x, y
}
func setRandom(ulid *ULID) (err error) {
_, err = rand.Read(ulid[6:])
return
}
// String returns the string form of ulid (26 characters, non-standard base 32)
func (ulid ULID) String() string {
var (
buf [26]byte
x, y byte
)
// Backups [6] and [7] bytes to override them with their original values later.
x, y, ulid[6], ulid[7] = ulid[6], ulid[7], x, y
timestamp := int64(binary.LittleEndian.Uint64(ulid[:8]))
// This is useful to shave some nanoseconds from copy() operations.
ulid[6], ulid[7] = x, y
for x := encodedTimeLength - 1; x >= 0; x-- {
mod := timestamp % alphabetSize
buf[x] = alphabet[mod]
timestamp = (timestamp - mod) / alphabetSize
}
for x := encodedTimeLength; x < len(ulid); x++ {
buf[x] = alphabet[int64(ulid[x])%alphabetSize]
}
return string(buf[:])
}