///|
/// Identifiers from a clock and a source of random bytes the caller
/// supplies, keeping what the time-based versions need between calls:
/// version 1 and 6 timestamps never repeat or go back, and version 7 ids
/// made within one millisecond count up, so they sort in the order made.
pub struct Generator {
priv clock : () -> Int64
priv random : (Int32) -> Bytes
priv mut last_ticks : Int64?
priv mut last_ticks_v6 : Int64?
priv mut last_millis : Int64?
priv mut last_counter : UInt64
}
///|
/// `clock` gives nanoseconds since 1970; `random` gives that many random
/// bytes.
pub fn Generator::new(
clock~ : () -> Int64,
random~ : (Int32) -> Bytes,
) -> Generator {
{
clock,
random,
last_ticks: None,
last_ticks_v6: None,
last_millis: None,
last_counter: 0UL,
}
}
///|
fn Generator::bytes(self : Generator, n : Int32) -> Bytes raise Refused {
let got = (self.random)(n)
if got.length() != n {
raise Size(want=n, got=got.length())
}
got
}
///|
/// A 14-bit clock sequence from the random source.
fn Generator::clock_seq(self : Generator) -> Int32 raise Refused {
let b = self.bytes(2)
((b[0].to_int() << 8) | b[1].to_int()) & 0x3FFF
}
///|
fn next_ticks(now : Int64, last : Int64?) -> Int64 {
let t = ticks_of(now)
match last {
Some(prev) if t <= prev => prev + 1L
_ => t
}
}
///|
/// Version 1 with `node`; the clock sequence is random unless given.
pub fn Generator::v1(
self : Generator,
node~ : Int64,
clock_seq? : Int32,
) -> Uuid raise Refused {
let ticks = next_ticks((self.clock)(), self.last_ticks)
self.last_ticks = Some(ticks)
let clock_seq = match clock_seq {
Some(c) => c
None => self.clock_seq()
}
v1(ticks~, clock_seq~, node~)
}
///|
/// Version 6 with `node`; the clock sequence is random unless given.
pub fn Generator::v6(
self : Generator,
node~ : Int64,
clock_seq? : Int32,
) -> Uuid raise Refused {
let ticks = next_ticks((self.clock)(), self.last_ticks_v6)
self.last_ticks_v6 = Some(ticks)
let clock_seq = match clock_seq {
Some(c) => c
None => self.clock_seq()
}
v6(ticks~, clock_seq~, node~)
}
///|
/// Version 4 from 16 random bytes.
pub fn Generator::v4(self : Generator) -> Uuid raise Refused {
v4(self.bytes(16))
}
///|
/// Version 7. Within one millisecond the counter goes up by one with a
/// fresh random tail; when the clock steps back, the millisecond after the
/// last one is used; when the counter runs out, the millisecond moves on.
pub fn Generator::v7(self : Generator) -> Uuid raise Refused {
let mut millis = (self.clock)() / 1_000_000L
let (counter, tail) = match self.last_millis {
Some(prev) if millis <= prev => {
if millis < prev {
millis = prev + 1L
}
let counter = self.last_counter + 1UL
if counter > 0x3FFFFFFFFFFUL {
millis += 1L
counter_and_tail(self.bytes(10))
} else {
let b = self.bytes(4)
let tail = (b[0].to_uint64() << 24) |
(b[1].to_uint64() << 16) |
(b[2].to_uint64() << 8) |
b[3].to_uint64()
(counter, tail)
}
}
_ => counter_and_tail(self.bytes(10))
}
self.last_millis = Some(millis)
self.last_counter = counter
seven(millis.reinterpret_as_uint64(), counter, tail)
}