glyde/rng

Deterministic randomness: every draw is a pure function of a caller-supplied seed threaded through the state. Discord asks for a jittered first heartbeat and a randomised wait before reconnecting.

Never use it for a websocket mask, a handshake nonce or a token. Knowing the seed is knowing every draw.

Types

A generator: seed or at for the real one, fixed for a test.

Opaque because the cycle only holds for a state in [1, modulus - 1]. State 0 is the fixed point, so every reconnect would draw the same jitter, and a negative state draws negative jitter and arms a timer in the past.

pub opaque type Rng

Values

pub fn at(state: Int) -> Rng

A generator on an exact cycle position, folded like seed but not scrambled, so at(1) really is state 1. A shard wants seed; this is for a test that names the sequence.

pub fn below(rng: Rng, bound: Int) -> #(Rng, Int)

A value in [0, bound). A non-positive bound gives 0 rather than crashing: a state machine may not panic.

pub fn between(
  rng: Rng,
  low low: Int,
  high high: Int,
) -> #(Rng, Int)

A value in [low, high). An empty range yields low.

pub fn fixed(value: Int) -> Rng

A generator that never advances, reading its value as billionths of whatever is asked for: fixed(0) pins the low end of every range, fixed(500_000_000) the middle, fixed(999_999_999) the high end.

pub fn seed(n: Int) -> Rng

Any n works, folded onto the cycle. Distinct seeds below 2^31 stay distinct; system_time_ms % 2_000_000_000 is a fine source.

pub fn state(rng: Rng) -> option.Option(Int)

Where a generator sits on the cycle. None for Fixed, which has no position.

pub fn unit(rng: Rng) -> #(Rng, Float)

A float in [0, 1). Discord’s heartbeat rule is interval * jitter.

Search Document