1use crate::amx::Amx;
4use crate::error::{AmxError, AmxResult};
5
6pub trait AmxCell<'amx>
16where
17 Self: Sized,
18{
19 fn from_raw(_amx: &'amx Amx, _cell: i32) -> AmxResult<Self>
26 where
27 Self: 'amx,
28 {
29 Err(AmxError::General)
30 }
31
32 fn as_cell(&self) -> i32;
33}
34
35pub unsafe trait AmxPrimitive
45where
46 Self: Sized,
47{
48}
49
50pub trait CellConvert: Sized {
79 fn from_cell(raw: i32) -> Self;
81
82 fn into_cell(self) -> i32;
84}
85
86impl<'a, T: AmxCell<'a>> AmxCell<'a> for &'a T {
87 fn as_cell(&self) -> i32 {
88 (**self).as_cell()
89 }
90}
91
92impl<'a, T: AmxCell<'a>> AmxCell<'a> for &'a mut T {
93 fn as_cell(&self) -> i32 {
94 (**self).as_cell()
95 }
96}
97
98macro_rules! impl_for_primitive {
103 ($type:ty) => {
104 #[allow(
105 clippy::cast_possible_truncation,
106 clippy::cast_possible_wrap,
107 clippy::cast_sign_loss,
108 clippy::cast_lossless
109 )]
110 impl AmxCell<'_> for $type {
111 fn from_raw(_amx: &Amx, cell: i32) -> AmxResult<Self> {
112 Ok(cell as Self)
113 }
114
115 fn as_cell(&self) -> i32 {
116 *self as i32
117 }
118 }
119
120 #[allow(
121 clippy::cast_possible_truncation,
122 clippy::cast_possible_wrap,
123 clippy::cast_sign_loss,
124 clippy::cast_lossless
125 )]
126 impl CellConvert for $type {
127 #[inline]
128 fn from_cell(raw: i32) -> Self {
129 raw as Self
130 }
131
132 #[inline]
133 fn into_cell(self) -> i32 {
134 self as i32
135 }
136 }
137
138 unsafe impl AmxPrimitive for $type {}
139 };
140}
141
142impl_for_primitive!(i8);
143impl_for_primitive!(u8);
144impl_for_primitive!(i16);
145impl_for_primitive!(u16);
146impl_for_primitive!(i32);
147impl_for_primitive!(u32);
148impl_for_primitive!(usize);
149impl_for_primitive!(isize);
150
151impl AmxCell<'_> for f32 {
155 fn from_raw(_amx: &Amx, cell: i32) -> AmxResult<f32> {
156 #[allow(clippy::cast_sign_loss)]
157 let bits = cell as u32;
158 Ok(f32::from_bits(bits))
159 }
160
161 fn as_cell(&self) -> i32 {
162 f32::to_bits(*self).cast_signed()
163 }
164}
165
166impl CellConvert for f32 {
167 #[inline]
168 fn from_cell(raw: i32) -> Self {
169 #[allow(clippy::cast_sign_loss)]
170 let bits = raw as u32;
171 f32::from_bits(bits)
172 }
173
174 #[inline]
175 fn into_cell(self) -> i32 {
176 f32::to_bits(self).cast_signed()
177 }
178}
179
180impl AmxCell<'_> for bool {
181 fn from_raw(_amx: &Amx, cell: i32) -> AmxResult<bool> {
182 Ok(cell != 0)
185 }
186
187 fn as_cell(&self) -> i32 {
188 i32::from(*self)
189 }
190}
191
192impl CellConvert for bool {
193 #[inline]
194 fn from_cell(raw: i32) -> Self {
195 raw != 0
196 }
197
198 #[inline]
199 fn into_cell(self) -> i32 {
200 i32::from(self)
201 }
202}
203
204unsafe impl AmxPrimitive for f32 {}
205unsafe impl AmxPrimitive for bool {}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn i32_as_cell_identity() {
213 for v in [0, 1, -1, 42, i32::MAX, i32::MIN] {
214 assert_eq!(v.as_cell(), v);
215 }
216 }
217
218 #[test]
219 fn f32_as_cell_preserves_bits() {
220 for v in [0.0f32, 1.0, -1.0, 42.5, f32::MAX, f32::MIN, f32::EPSILON] {
221 let cell = v.as_cell();
222 let recovered = f32::from_bits(cell.cast_unsigned());
223 assert_eq!(
224 v.to_bits(),
225 recovered.to_bits(),
226 "f32 {v} did not preserve bits"
227 );
228 }
229 }
230
231 #[test]
232 fn bool_as_cell() {
233 assert_eq!(true.as_cell(), 1);
234 assert_eq!(false.as_cell(), 0);
235 }
236
237 #[test]
238 fn u8_as_cell() {
239 assert_eq!(0u8.as_cell(), 0);
240 assert_eq!(255u8.as_cell(), 255);
241 }
242
243 #[test]
244 fn i8_as_cell() {
245 assert_eq!(0i8.as_cell(), 0);
246 assert_eq!((-1i8).as_cell(), -1);
247 assert_eq!(127i8.as_cell(), 127);
248 }
249
250 #[test]
251 fn u16_as_cell() {
252 assert_eq!(0u16.as_cell(), 0);
253 assert_eq!(65535u16.as_cell(), 65535);
254 }
255
256 #[test]
257 fn i16_as_cell() {
258 assert_eq!(0i16.as_cell(), 0);
259 assert_eq!((-1i16).as_cell(), -1);
260 }
261
262 #[test]
263 fn ref_delegates_to_inner() {
264 let val = 42i32;
265 let r = &val;
266 assert_eq!(r.as_cell(), 42);
267 }
268
269 #[test]
270 fn mut_ref_delegates_to_inner() {
271 let mut val = 42i32;
272 let r = &mut val;
273 assert_eq!(r.as_cell(), 42);
274 }
275}