use crate::amx::Amx;
use crate::cell::AmxCell;
pub struct Args<'a> {
amx: &'a Amx,
params: *const i32,
offset: usize,
}
impl<'a> Args<'a> {
#[must_use]
pub fn new(amx: &'a Amx, params: *const i32) -> Args<'a> {
Args {
amx,
params,
offset: 0,
}
}
pub fn next_arg<T: AmxCell<'a> + 'a>(&mut self) -> Option<T> {
let result = self.get(self.offset);
self.offset += 1;
result
}
#[must_use]
pub fn get<T: AmxCell<'a> + 'a>(&self, offset: usize) -> Option<T> {
if offset >= self.count() {
return None;
}
unsafe { T::from_raw(self.amx, self.params.add(offset + 1).read()).ok() }
}
pub fn reset(&mut self) {
self.offset = 0;
}
#[must_use]
pub fn count(&self) -> usize {
let raw = unsafe { self.params.read() };
if raw <= 0 {
return 0;
}
#[allow(clippy::cast_sign_loss)]
let count = (raw / 4) as usize;
count
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn count_with_zero_returns_zero() {
let data: [i32; 1] = [0];
let amx = Amx::new(std::ptr::null_mut(), 0);
let args = Args::new(&amx, data.as_ptr());
assert_eq!(args.count(), 0);
}
#[test]
fn count_with_negative_returns_zero() {
let data: [i32; 1] = [-8];
let amx = Amx::new(std::ptr::null_mut(), 0);
let args = Args::new(&amx, data.as_ptr());
assert_eq!(args.count(), 0);
}
#[test]
fn count_with_valid_args() {
let data: [i32; 4] = [12, 100, 200, 300];
let amx = Amx::new(std::ptr::null_mut(), 0);
let args = Args::new(&amx, data.as_ptr());
assert_eq!(args.count(), 3);
}
#[test]
fn get_out_of_bounds_returns_none() {
let data: [i32; 2] = [4, 42]; let amx = Amx::new(std::ptr::null_mut(), 0);
let args = Args::new(&amx, data.as_ptr());
assert!(args.get::<crate::cell::Ref<i32>>(1).is_none());
}
#[test]
fn reset_resets_offset() {
let data: [i32; 1] = [0];
let amx = Amx::new(std::ptr::null_mut(), 0);
let mut args = Args::new(&amx, data.as_ptr());
args.offset = 5;
args.reset();
assert_eq!(args.offset, 0);
}
fn lcg(seed: &mut u64) -> u32 {
*seed = seed
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
(*seed >> 33) as u32
}
#[test]
fn count_never_negative_or_absurd() {
let mut seed = 0xA5A5_1234_9999_0001u64;
for _ in 0..4000 {
let raw = lcg(&mut seed) as i32; let data: [i32; 1] = [raw];
let amx = Amx::new(std::ptr::null_mut(), 0);
let args = Args::new(&amx, data.as_ptr());
let count = args.count();
if raw <= 0 {
assert_eq!(count, 0);
} else {
assert_eq!(count, (raw / 4) as usize);
}
}
}
#[test]
fn get_beyond_count_is_none() {
let data: [i32; 3] = [2 * 4, 11, 22];
let amx = Amx::new(std::ptr::null_mut(), 0);
let args = Args::new(&amx, data.as_ptr());
assert!(args.get::<crate::cell::Ref<i32>>(2).is_none());
assert!(args.get::<crate::cell::Ref<i32>>(999).is_none());
}
}