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

def unpack_decoded_bytes(packed_bytes)
  time_bytes = packed_bytes[0..5]
  seed = packed_bytes[6..-1]

  # and unpack it immedieately into the original milliseconds timestamp
  time_int = ("\x00\x00" + time_bytes).unpack('Q>')[0]

  [ Time.at( time_int / 10_000.0 ).utc, seed ]
end