extern "C" {
fn mt19937_new(seed: u32) -> *mut std::ffi::c_void;
fn mt19937_free(handle: *mut std::ffi::c_void);
fn binomial_sample(handle: *mut std::ffi::c_void, trials: u64, p: f64) -> u64;
}
pub struct CppMt19937 {
handle: *mut std::ffi::c_void,
}
unsafe impl Send for CppMt19937 {}
impl CppMt19937 {
pub fn new(seed: u32) -> Self {
let handle = unsafe { mt19937_new(seed) };
assert!(!handle.is_null(), "mt19937_new returned null");
Self { handle }
}
pub fn binomial(&mut self, trials: u64, p: f64) -> u64 {
unsafe { binomial_sample(self.handle, trials, p) }
}
}
impl Drop for CppMt19937 {
fn drop(&mut self) {
unsafe { mt19937_free(self.handle) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cpp_mt19937_creates_and_drops() {
let _rng = CppMt19937::new(42);
}
#[test]
fn test_binomial_deterministic() {
let mut rng1 = CppMt19937::new(1);
let mut rng2 = CppMt19937::new(1);
for _ in 0..20 {
let a = rng1.binomial(1000, 0.3);
let b = rng2.binomial(1000, 0.3);
assert_eq!(a, b, "Same seed must produce identical samples");
}
}
#[test]
fn test_binomial_edge_cases() {
let mut rng = CppMt19937::new(1);
for _ in 0..10 {
assert_eq!(rng.binomial(1000, 0.0), 0);
}
for _ in 0..10 {
assert_eq!(rng.binomial(1000, 1.0), 1000);
}
for _ in 0..10 {
assert_eq!(rng.binomial(0, 0.5), 0);
}
}
#[test]
fn test_binomial_range() {
let mut rng = CppMt19937::new(42);
for _ in 0..100 {
let trials = 500;
let sample = rng.binomial(trials, 0.5);
assert!(sample <= trials, "Sample {} > trials {}", sample, trials);
}
}
}