drand48 0.2.0

drand48 - POSIX.1 standard LCG random number generator
Documentation
/*
DRAND48 Linear congruential generator
implementation by Radim Kolar <hsn@sendmail.cz> 2025
https://gitlab.com/hsn10/drand48

This is free and unencumbered software released into the public domain.
SPDX-License-Identifier: Unlicense OR CC0-1.0

For more information, please refer to <http://unlicense.org/>
*/

/// Extracts the top quality 3 bytes (24 most significant bits) from a 48-bit drand48 output.
///
/// Assumes the input is the raw 48-bit output,
/// as typically returned by a `next()` function in a drand48 implementation.
///
/// # Arguments
/// * `drand48_output` - A `i64` representing the 48-bit internal state
///     (should be < 2^48) and not negative.
///
/// # Returns
/// A `[u8; 3]` array where:
/// - index 0 contains bits 40–47 (most significant)
/// - index 1 contains bits 32–39
/// - index 2 contains bits 24–31
pub const fn get_bytes3(drand48_output: i64) -> [u8; 3] {
    [
        ((drand48_output >> 40) & 0xFF) as u8,
        ((drand48_output >> 32) & 0xFF) as u8,
        ((drand48_output >> 24) & 0xFF) as u8,
    ]
}

/// Extracts good quality 4 bytes (32 most significant bits) from a 48-bit `drand48` output.
///
/// Assumes the input is the raw 48-bit output,
/// as typically returned by the `next()` function in a `drand48` implementation.
///
/// # Arguments
/// * `drand48_output` - A `i64` representing the 48-bit internal state
///     (must be in range `0..2^48` and not negative).
///
/// # Returns
/// A `[u8; 4]` array where:
/// - index 0 contains bits 40–47 (most significant)
/// - index 1 contains bits 32–39
/// - index 2 contains bits 24–31
/// - index 3 contains bits 16–23
pub const fn get_bytes(drand48_output: i64) -> [u8; 4] {
    let value = drand48_output as u64;

    [
        ((value >> 40) & 0xFF) as u8,
        ((value >> 32) & 0xFF) as u8,
        ((value >> 24) & 0xFF) as u8,
        ((value >> 16) & 0xFF) as u8,
    ]
}

/// Extracts the top 15 bits from a 48-bit `drand48` output as a non-negative `i16`.
///
/// Bits 33–47 of the 48-bit state are used, giving 15 bits of high-quality randomness.
/// The returned value is always in the range `0..=32767` (i.e., fits in `i16` without sign).
///
/// # Arguments
/// * `drand48_output` - A 48-bit integer (`i64`) representing the internal LCG state.
///
/// # Returns
/// A non-negative `i16` containing the top 15 bits of the input.
pub const fn get_i16(drand48_output: i64) -> i16 {
    // Convert to u64, shift right by 33 to get bits 33–47 into position 0–14.
    // Then mask to ensure only 15 bits are used, and safely cast to i16.
    ((drand48_output as u64 >> 33) & 0x7FFF) as i16
}

/// Extracts the top 16 bits from a 48-bit `drand48` output as an unsigned 16-bit integer.
///
/// # Arguments
/// * `drand48_output` - A 48-bit integer (`i64`) representing the internal LCG state.
///
/// # Returns
/// A `u16` containing bits 32–47 (the most significant 16 bits).
pub const fn get_u16(drand48_output: i64) -> u16 {
    ((drand48_output as u64) >> 32) as u16
}

/// Fills buffer with random bytes generated by provided DRAND48.
///
/// This function splits the buffer into chunks of up to 4 bytes and fills each chunk
/// with bytes derived from a `i64` value generated by `DRAND48.next()`.
///
/// # Parameters
///
/// - `buffer`: A mutable reference to a slice of bytes (`&mut [u8]`) that will be filled with random data.
/// - `rng`: A mutable reference to DRAND48.
///
/// # Examples
///
/// ```
/// use drand48::DRAND48;
///
/// let mut data = [0u8; 16];
/// drand48::extract::fill_bytes(&mut data, &mut DRAND48::new());
///
/// println!("{:?}", data); // Randomized output
/// ```
pub fn fill_bytes(buffer: &mut [u8], rng: &mut super::DRAND48)
{
    if buffer.is_empty() {
        return; // No need to process an empty slice
    }

    for chunk in buffer.chunks_mut(4) {
        let random_bytes = get_bytes(rng.next());
        chunk.copy_from_slice(&random_bytes[..chunk.len()]);
    }
}

#[cfg(test)]
#[path = "extract_test.rs"]
mod tests;