1use crate::amx::Amx;
11use crate::cell::AmxCell;
12
13pub struct Args<'a> {
18 amx: &'a Amx,
19 params: *const i32,
20 offset: usize,
21}
22
23impl<'a> Args<'a> {
24 #[must_use]
44 pub fn new(amx: &'a Amx, params: *const i32) -> Args<'a> {
45 Args {
46 amx,
47 params,
48 offset: 0,
49 }
50 }
51
52 pub fn next_arg<T: AmxCell<'a> + 'a>(&mut self) -> Option<T> {
54 let result = self.get(self.offset);
55 self.offset += 1;
56
57 result
58 }
59
60 #[must_use]
62 pub fn get<T: AmxCell<'a> + 'a>(&self, offset: usize) -> Option<T> {
63 if offset >= self.count() {
64 return None;
65 }
66
67 unsafe { T::from_raw(self.amx, self.params.add(offset + 1).read()).ok() }
68 }
69
70 pub fn reset(&mut self) {
74 self.offset = 0;
75 }
76
77 #[must_use]
82 pub fn count(&self) -> usize {
83 let raw = unsafe { self.params.read() };
84 if raw <= 0 {
85 return 0;
86 }
87 #[allow(clippy::cast_sign_loss)]
89 let count = (raw / 4) as usize;
90 count
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn count_with_zero_returns_zero() {
100 let data: [i32; 1] = [0];
101 let amx = Amx::new(std::ptr::null_mut(), 0);
102 let args = Args::new(&amx, data.as_ptr());
103 assert_eq!(args.count(), 0);
104 }
105
106 #[test]
107 fn count_with_negative_returns_zero() {
108 let data: [i32; 1] = [-8];
109 let amx = Amx::new(std::ptr::null_mut(), 0);
110 let args = Args::new(&amx, data.as_ptr());
111 assert_eq!(args.count(), 0);
112 }
113
114 #[test]
115 fn count_with_valid_args() {
116 let data: [i32; 4] = [12, 100, 200, 300];
118 let amx = Amx::new(std::ptr::null_mut(), 0);
119 let args = Args::new(&amx, data.as_ptr());
120 assert_eq!(args.count(), 3);
121 }
122
123 #[test]
124 fn get_out_of_bounds_returns_none() {
125 let data: [i32; 2] = [4, 42]; let amx = Amx::new(std::ptr::null_mut(), 0);
127 let args = Args::new(&amx, data.as_ptr());
128 assert!(args.get::<crate::cell::Ref<i32>>(1).is_none());
130 }
131
132 #[test]
133 fn reset_resets_offset() {
134 let data: [i32; 1] = [0];
135 let amx = Amx::new(std::ptr::null_mut(), 0);
136 let mut args = Args::new(&amx, data.as_ptr());
137 args.offset = 5;
138 args.reset();
139 assert_eq!(args.offset, 0);
140 }
141
142 fn lcg(seed: &mut u64) -> u32 {
143 *seed = seed
144 .wrapping_mul(6_364_136_223_846_793_005)
145 .wrapping_add(1_442_695_040_888_963_407);
146 (*seed >> 33) as u32
147 }
148
149 #[test]
150 fn count_never_negative_or_absurd() {
151 let mut seed = 0xA5A5_1234_9999_0001u64;
154 for _ in 0..4000 {
155 let raw = lcg(&mut seed) as i32; let data: [i32; 1] = [raw];
157 let amx = Amx::new(std::ptr::null_mut(), 0);
158 let args = Args::new(&amx, data.as_ptr());
159 let count = args.count();
160 if raw <= 0 {
161 assert_eq!(count, 0);
162 } else {
163 assert_eq!(count, (raw / 4) as usize);
164 }
165 }
166 }
167
168 #[test]
169 fn get_beyond_count_is_none() {
170 let data: [i32; 3] = [2 * 4, 11, 22];
172 let amx = Amx::new(std::ptr::null_mut(), 0);
173 let args = Args::new(&amx, data.as_ptr());
174 assert!(args.get::<crate::cell::Ref<i32>>(2).is_none());
175 assert!(args.get::<crate::cell::Ref<i32>>(999).is_none());
176 }
177}