Module: ULID::Parse

Includes:
Constants
Included in:
Identifier
Defined in:
lib/ulid/parse.rb

Constant Summary

Constants included from Constants

Constants::B32REF, Constants::ENCODING, Constants::MAX_ENTROPY, Constants::MAX_TIME, Constants::MIN_ENTROPY, Constants::MIN_TIME

Instance Method Summary collapse

Instance Method Details

#decode(v) ⇒ Object

v should be a Base32 encoded ULID string. This method decodes it into a 16 byte raw ULID with 48 bit time and 64 bit random parts.



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
# File 'lib/ulid/parse.rb', line 9

def decode(v)
  out = []

  # hand optimized, unrolled ULID-Base32 format decoder based on
  # https://github.com/oklog/ulid/blob/c3c01856f7e43fa64133819126887124d5f05e39/ulid.go#L234

  # 6 bytes timestamp (48 bits)
  out << ((B32REF[v[0]] << 5) |  B32REF[v[1]])
  out << ((B32REF[v[2]] << 3) | (B32REF[v[3]] >> 2))
  out << ((B32REF[v[3]] << 6) | (B32REF[v[4]] << 1) | (B32REF[v[5]] >> 4))
  out << ((B32REF[v[5]] << 4) | (B32REF[v[6]] >> 1))
  out << ((B32REF[v[6]] << 7) | (B32REF[v[7]] << 2) | (B32REF[v[8]] >> 3))
  out << ((B32REF[v[8]] << 5) |  B32REF[v[9]])

  # 10 bytes of entropy (80 bits)
  out << ((B32REF[v[10]] << 3) | (B32REF[v[11]] >> 2))
  out << ((B32REF[v[11]] << 6) | (B32REF[v[12]] << 1) | (B32REF[v[13]] >> 4))
  out << ((B32REF[v[13]] << 4) | (B32REF[v[14]] >> 1))
  out << ((B32REF[v[14]] << 7) | (B32REF[v[15]] << 2) | (B32REF[v[16]] >> 3))
  out << ((B32REF[v[16]] << 5) | B32REF[v[17]])
  out << ((B32REF[v[18]] << 3) | B32REF[v[19]]>>2)
  out << ((B32REF[v[19]] << 6) | (B32REF[v[20]] << 1) | (B32REF[v[21]] >> 4))
  out << ((B32REF[v[21]] << 4) | (B32REF[v[22]] >> 1))
  out << ((B32REF[v[22]] << 7) | (B32REF[v[23]] << 2) | (B32REF[v[24]] >> 3))
  out << ((B32REF[v[24]] << 5) | B32REF[v[25]])

  # get the array as a string, coercing each value to a single byte
  out = out.pack('C' * 16)

  out
end

#unpack_decoded_bytes(packed_bytes) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ulid/parse.rb', line 41

def unpack_decoded_bytes(packed_bytes)
  time_bytes = packed_bytes[0..5].bytes.map(&:to_i)
  seed = packed_bytes[6..-1]

  # and unpack it immedieately into the original milliseconds timestamp
  # via https://github.com/oklog/ulid/blob/c3c01856f7e43fa64133819126887124d5f05e39/ulid.go#L265
  time_int = time_bytes[5].to_i |
    (time_bytes[4].to_i << 8) |
    (time_bytes[3].to_i << 16) |
    (time_bytes[2].to_i << 24) |
    (time_bytes[1].to_i << 32) |
    (time_bytes[0].to_i << 40)

  [ Time.at( time_int * 1/1000r ).utc, seed ]
end