snapshot of eee7b5cfc0776c68816d7fdaa8af9d7a0e0da2e6 Annotations about the code that implements koment.

internal/store/ulid.go

1 package store
2
3 import (
4 "crypto/rand"
5 "encoding/binary"
6 "fmt"
7 "strings"
8 "time"
9 )
10
11 const (
12 crockfordAlphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
13
14 ulidLength = 26
15 bitsPerChar = 5
16 timestampBytes = 6
17 entropyBytes = 10
18
19 paddingBits = ulidLength*bitsPerChar - 8*(timestampBytes+entropyBytes)
20 )
21
22 // NewID returns a ULID: a 48-bit millisecond timestamp followed by 80 random
23 // bits, rendered as 26 Crockford base32 characters that sort by creation time.
24 func NewID(at time.Time) (string, error) {
25 milliseconds := at.UnixMilli()
26 if milliseconds < 0 || milliseconds>>(8*timestampBytes) != 0 {
27 return "", fmt.Errorf("timestamp %s does not fit in a ULID", at)
28 }
29
30 var id [timestampBytes + entropyBytes]byte
31 var wide [8]byte
32 binary.BigEndian.PutUint64(wide[:], uint64(milliseconds))
33 copy(id[:timestampBytes], wide[8-timestampBytes:])
34
35 if _, err := rand.Read(id[timestampBytes:]); err != nil {
36 return "", fmt.Errorf("reading ULID entropy: %w", err)
37 }
38 return encodeCrockford(id), nil
39 }
40
41 func ValidID(id string) bool {
42 if len(id) != ulidLength || id[0] > '7' {
43 return false
44 }
45 for _, character := range id {
46 if !strings.ContainsRune(crockfordAlphabet, character) {
47 return false
48 }
49 }
50 return true
51 }
52
53 func encodeCrockford(id [timestampBytes + entropyBytes]byte) string {
54 out := make([]byte, ulidLength)
55 for i := range out {
56 out[i] = crockfordAlphabet[fiveBitsAt(id, i*bitsPerChar)]
57 }
58 return string(out)
59 }
60
61 func fiveBitsAt(id [timestampBytes + entropyBytes]byte, offset int) byte {
62 var value byte
63 for i := range bitsPerChar {
64 value <<= 1
65 if bitSet(id, offset+i-paddingBits) {
66 value |= 1
67 }
68 }
69 return value
70 }
71
72 func bitSet(id [timestampBytes + entropyBytes]byte, n int) bool {
73 if n < 0 {
74 return false
75 }
76 return id[n/8]&(1<<(7-n%8)) != 0
77 }

Find an annotation

Search file paths, rationale, kinds, and authors.

moveEnter openEsc close