amagi 0.1.4

Rust SDK, CLI, and Web API service skeleton for multi-platform social web adapters.
Documentation
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};

static SEED_COUNTER: AtomicU64 = AtomicU64::new(0x9e37_79b9_7f4a_7c15);

#[derive(Debug, Clone)]
pub(crate) struct PseudoRandom {
    state: u64,
}

impl PseudoRandom {
    pub(crate) fn new(seed: u64) -> Self {
        Self {
            state: if seed == 0 {
                0x4d59_5df4_d0f3_3173
            } else {
                seed
            },
        }
    }

    pub(crate) fn from_system() -> Self {
        let now = now_unix_nanos();
        let counter = SEED_COUNTER.fetch_add(0x9e37_79b9, Ordering::Relaxed);
        Self::new(now ^ counter)
    }

    pub(crate) fn next_u32(&mut self) -> u32 {
        self.next_u64() as u32
    }

    pub(crate) fn next_mod(&mut self, modulus: u32) -> u32 {
        if modulus == 0 {
            0
        } else {
            self.next_u32() % modulus
        }
    }

    pub(crate) fn fill_bytes(&mut self, bytes: &mut [u8]) {
        for byte in bytes {
            *byte = (self.next_u32() & 0xff) as u8;
        }
    }

    fn next_u64(&mut self) -> u64 {
        let mut x = self.state;
        x ^= x >> 12;
        x ^= x << 25;
        x ^= x >> 27;
        self.state = x;
        x.wrapping_mul(0x2545_f491_4f6c_dd1d)
    }
}

pub(crate) fn now_unix_ms() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|duration| duration.as_millis() as u64)
        .unwrap_or_default()
}

pub(crate) fn now_unix_secs() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|duration| duration.as_secs())
        .unwrap_or_default()
}

pub(crate) fn base36_u64(mut value: u64) -> String {
    if value == 0 {
        return "0".to_owned();
    }

    let mut digits = Vec::new();
    while value > 0 {
        let remainder = (value % 36) as u8;
        let ch = match remainder {
            0..=9 => (b'0' + remainder) as char,
            _ => (b'a' + (remainder - 10)) as char,
        };
        digits.push(ch);
        value /= 36;
    }
    digits.iter().rev().collect()
}

fn now_unix_nanos() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|duration| duration.as_nanos() as u64)
        .unwrap_or_default()
}