1use std::ops::{Deref, DerefMut};
5
6use super::{AmxCell, Ref};
7use crate::amx::Amx;
8use crate::cell::repr::CellConvert;
9use crate::cell::string;
10use crate::error::AmxResult;
11
12pub struct Buffer<'amx> {
32 inner: Ref<'amx, i32>,
33 len: usize,
34}
35
36impl<'amx> Buffer<'amx> {
37 #[must_use]
39 pub fn new(reference: Ref<'amx, i32>, len: usize) -> Buffer<'amx> {
40 Buffer {
41 inner: reference,
42 len,
43 }
44 }
45
46 #[must_use]
48 pub fn len(&self) -> usize {
49 self.len
50 }
51
52 #[must_use]
54 pub fn is_empty(&self) -> bool {
55 self.len == 0
56 }
57
58 #[inline]
60 #[must_use]
61 pub fn as_slice(&self) -> &[i32] {
62 unsafe { std::slice::from_raw_parts(self.inner.as_ptr(), self.len) }
63 }
64
65 #[inline]
67 pub fn as_mut_slice(&mut self) -> &mut [i32] {
68 unsafe { std::slice::from_raw_parts_mut(self.inner.as_mut_ptr(), self.len) }
69 }
70
71 pub fn iter_as<T: CellConvert>(&self) -> impl Iterator<Item = T> + '_ {
81 self.as_slice().iter().map(|&raw| T::from_cell(raw))
82 }
83
84 #[must_use]
86 pub fn get_as<T: CellConvert>(&self, index: usize) -> Option<T> {
87 self.as_slice().get(index).map(|&raw| T::from_cell(raw))
88 }
89
90 pub fn set_as<T: CellConvert>(&mut self, index: usize, value: T) -> bool {
94 if let Some(cell) = self.as_mut_slice().get_mut(index) {
95 *cell = value.into_cell();
96 true
97 } else {
98 false
99 }
100 }
101
102 pub fn write_str(&mut self, s: &str) -> AmxResult<()> {
109 string::put_in_buffer(self, s)
110 }
111}
112
113impl<'amx> AmxCell<'amx> for Buffer<'amx> {
116 #[inline]
117 fn as_cell(&self) -> i32 {
118 self.inner.as_cell()
119 }
120}
121
122impl Deref for Buffer<'_> {
123 type Target = [i32];
124
125 fn deref(&self) -> &[i32] {
126 self.as_slice()
127 }
128}
129
130impl DerefMut for Buffer<'_> {
131 fn deref_mut(&mut self) -> &mut [i32] {
132 self.as_mut_slice()
133 }
134}
135
136impl std::fmt::Debug for Buffer<'_> {
137 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
138 write!(f, "{:?}", self.as_slice())
139 }
140}
141
142pub struct UnsizedBuffer<'amx> {
150 inner: Ref<'amx, i32>,
151}
152
153impl<'amx> UnsizedBuffer<'amx> {
154 #[must_use]
160 pub fn into_sized_buffer(self, len: usize) -> Buffer<'amx> {
161 const MAX_BUFFER_CELLS: usize = 1024 * 1024;
162 debug_assert!(
163 len <= MAX_BUFFER_CELLS,
164 "into_sized_buffer() received len={len} above the {MAX_BUFFER_CELLS} limit"
165 );
166 let len = len.min(MAX_BUFFER_CELLS);
167 Buffer::new(self.inner, len)
168 }
169
170 #[inline]
172 #[must_use]
173 pub fn as_ptr(&self) -> *const i32 {
174 self.inner.as_ptr()
175 }
176
177 #[inline]
179 pub fn as_mut_ptr(&mut self) -> *mut i32 {
180 self.inner.as_mut_ptr()
181 }
182
183 #[doc(hidden)]
185 #[must_use]
186 pub fn from_raw_parts(inner: Ref<'amx, i32>) -> Self {
187 UnsizedBuffer { inner }
188 }
189
190 pub fn write_str(self, max_len: usize, s: &str) -> AmxResult<()> {
199 let mut buf = self.into_sized_buffer(max_len);
200 string::put_in_buffer(&mut buf, s)
201 }
202}
203
204impl<'amx> AmxCell<'amx> for UnsizedBuffer<'amx> {
205 fn from_raw(amx: &'amx Amx, cell: i32) -> AmxResult<UnsizedBuffer<'amx>> {
206 Ok(UnsizedBuffer {
207 inner: amx.get_ref(cell)?,
208 })
209 }
210
211 #[inline]
212 fn as_cell(&self) -> i32 {
213 self.inner.as_cell()
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220 use crate::cell::Ref;
221 use crate::cell::repr::CellConvert;
222
223 fn make_ref(data: &mut Vec<i32>) -> Ref<'_, i32> {
224 unsafe { Ref::new(0, data.as_mut_ptr()) }
225 }
226
227 fn make_buffer(data: &mut Vec<i32>) -> Buffer<'_> {
228 let len = data.len();
229 let r = make_ref(data);
230 Buffer::new(r, len)
231 }
232
233 fn make_unsized(data: &mut Vec<i32>) -> UnsizedBuffer<'_> {
234 UnsizedBuffer {
235 inner: make_ref(data),
236 }
237 }
238
239 #[test]
242 fn buffer_len_and_is_empty() {
243 let mut data = vec![0i32; 4];
244 let buf = make_buffer(&mut data);
245 assert_eq!(buf.len(), 4);
246 assert!(!buf.is_empty());
247
248 let mut empty = vec![];
249 let empty_buf = make_buffer(&mut empty);
250 assert_eq!(empty_buf.len(), 0);
251 assert!(empty_buf.is_empty());
252 }
253
254 #[test]
255 fn buffer_deref_reads_values() {
256 let mut data = vec![10i32, 20, 30];
257 let buf = make_buffer(&mut data);
258 assert_eq!(&buf[..], &[10, 20, 30]);
259 assert_eq!(buf[0], 10);
260 assert_eq!(buf[2], 30);
261 }
262
263 #[test]
264 fn buffer_deref_mut_writes_values() {
265 let mut data = vec![0i32; 3];
266 let mut buf = make_buffer(&mut data);
267 buf[0] = 100;
268 buf[1] = 200;
269 buf[2] = 300;
270 assert_eq!(&data, &[100, 200, 300]);
271 }
272
273 #[test]
274 fn buffer_iter_works() {
275 let mut data = vec![1i32, 2, 3, 4];
276 let buf = make_buffer(&mut data);
277 let sum: i32 = buf.iter().sum();
278 assert_eq!(sum, 10);
279 }
280
281 #[test]
282 fn buffer_iter_mut_modifies_in_place() {
283 let mut data = vec![1i32, 2, 3];
284 let mut buf = make_buffer(&mut data);
285 buf.iter_mut().for_each(|x| *x *= 2);
286 assert_eq!(&data, &[2, 4, 6]);
287 }
288
289 #[test]
290 fn buffer_debug_format() {
291 let mut data = vec![1i32, 2, 3];
292 let buf = make_buffer(&mut data);
293 assert_eq!(format!("{buf:?}"), "[1, 2, 3]");
294 }
295
296 #[test]
297 fn buffer_as_cell_returns_amx_addr() {
298 let mut data = vec![0i32; 4];
299 let buf = make_buffer(&mut data);
300 assert_eq!(buf.as_cell(), 0);
302 }
303
304 #[test]
307 fn unsized_into_sized_normal_len() {
308 let mut data = vec![1i32, 2, 3, 4, 5];
309 let ub = make_unsized(&mut data);
310 let buf = ub.into_sized_buffer(3);
311 assert_eq!(buf.len(), 3);
312 assert_eq!(buf[0], 1);
313 assert_eq!(buf[2], 3);
314 }
315
316 #[test]
319 #[cfg_attr(
320 debug_assertions,
321 should_panic(expected = "into_sized_buffer() received len=")
322 )]
323 fn unsized_into_sized_clamps_to_max_in_release() {
324 let mut data = vec![0i32; 8];
325 let ub = make_unsized(&mut data);
326 let buf = ub.into_sized_buffer(1024 * 1024 + 1);
327 assert_eq!(buf.len(), 1024 * 1024);
329 }
330
331 #[test]
332 fn unsized_into_sized_at_exact_max() {
333 let mut data = vec![0i32; 8];
334 let ub = make_unsized(&mut data);
335 let buf = ub.into_sized_buffer(1024 * 1024);
336 assert_eq!(buf.len(), 1024 * 1024);
337 }
338
339 #[test]
340 fn unsized_as_ptr_not_null() {
341 let mut data = vec![42i32];
342 let ub = make_unsized(&mut data);
343 assert!(!ub.as_ptr().is_null());
344 }
345
346 #[test]
347 fn unsized_as_cell_returns_amx_addr() {
348 let mut data = vec![0i32];
349 let ub = make_unsized(&mut data);
350 assert_eq!(ub.as_cell(), 0);
351 }
352
353 #[test]
356 fn get_as_i32_reads_value() {
357 let mut data = vec![10i32, 20, 30];
358 let buf = make_buffer(&mut data);
359 assert_eq!(buf.get_as::<i32>(0), Some(10));
360 assert_eq!(buf.get_as::<i32>(2), Some(30));
361 }
362
363 #[test]
364 fn get_as_out_of_bounds_returns_none() {
365 let mut data = vec![1i32, 2];
366 let buf = make_buffer(&mut data);
367 assert_eq!(buf.get_as::<i32>(2), None);
368 assert_eq!(buf.get_as::<i32>(99), None);
369 }
370
371 #[test]
372 fn set_as_i32_writes_value() {
373 let mut data = vec![0i32; 3];
374 let mut buf = make_buffer(&mut data);
375 assert!(buf.set_as(1, 42i32));
376 assert_eq!(data[1], 42);
377 }
378
379 #[test]
380 fn set_as_out_of_bounds_returns_false() {
381 let mut data = vec![0i32; 2];
382 let mut buf = make_buffer(&mut data);
383 assert!(!buf.set_as(5, 99i32));
384 }
385
386 #[test]
387 fn get_as_f32_roundtrip() {
388 let value = 1.5f32; let mut data = vec![value.into_cell()];
390 let buf = make_buffer(&mut data);
391 let recovered: f32 = buf.get_as::<f32>(0).unwrap();
392 assert!(
393 (recovered - value).abs() < f32::EPSILON,
394 "f32 roundtrip failed: {recovered} != {value}"
395 );
396 }
397
398 #[test]
399 fn set_as_f32_stores_bits_correctly() {
400 let mut data = vec![0i32];
401 let mut buf = make_buffer(&mut data);
402 buf.set_as(0, 1.5f32);
403 assert_eq!(data[0].cast_unsigned(), 1.5f32.to_bits());
404 }
405
406 #[test]
407 fn get_as_bool_true_and_false() {
408 let mut data = vec![1i32, 0, 42];
409 let buf = make_buffer(&mut data);
410 assert_eq!(buf.get_as::<bool>(0), Some(true));
411 assert_eq!(buf.get_as::<bool>(1), Some(false));
412 assert_eq!(buf.get_as::<bool>(2), Some(true));
414 }
415
416 #[test]
417 fn set_as_bool_writes_zero_and_one() {
418 let mut data = vec![0i32; 2];
419 let mut buf = make_buffer(&mut data);
420 buf.set_as(0, true);
421 buf.set_as(1, false);
422 assert_eq!(data[0], 1);
423 assert_eq!(data[1], 0);
424 }
425
426 #[test]
427 fn get_as_u8_reads_byte() {
428 let mut data = vec![255i32];
429 let buf = make_buffer(&mut data);
430 assert_eq!(buf.get_as::<u8>(0), Some(255u8));
431 }
432
433 #[test]
436 fn iter_as_i32_collects_all() {
437 let mut data = vec![1i32, 2, 3, 4];
438 let buf = make_buffer(&mut data);
439 let vals: Vec<i32> = buf.iter_as::<i32>().collect();
440 assert_eq!(vals, vec![1, 2, 3, 4]);
441 }
442
443 #[test]
444 fn iter_as_i32_sum() {
445 let mut data = vec![10i32, 20, 30];
446 let buf = make_buffer(&mut data);
447 let sum: i32 = buf.iter_as::<i32>().sum();
448 assert_eq!(sum, 60);
449 }
450
451 #[test]
452 fn iter_as_f32_roundtrip() {
453 let values = [1.0f32, 2.5, 1.25];
454 let mut data: Vec<i32> = values.iter().map(|&v| v.into_cell()).collect();
455 let buf = make_buffer(&mut data);
456 let recovered: Vec<f32> = buf.iter_as::<f32>().collect();
457 for (orig, got) in values.iter().zip(recovered.iter()) {
458 assert!((orig - got).abs() < f32::EPSILON, "{orig} != {got}");
459 }
460 }
461
462 #[test]
463 fn iter_as_bool_any_and_all() {
464 let mut data = vec![1i32, 0, 1, 1];
465 let buf = make_buffer(&mut data);
466 assert!(buf.iter_as::<bool>().any(|v| !v));
467 assert!(!buf.iter_as::<bool>().all(|v| v));
468 }
469
470 #[test]
471 fn iter_as_empty_buffer() {
472 let mut data: Vec<i32> = vec![];
473 let buf = make_buffer(&mut data);
474 assert_eq!(buf.iter_as::<i32>().count(), 0);
475 }
476
477 #[test]
478 fn iter_as_matches_get_as_loop() {
479 let mut data = vec![10i32, 20, 30, 40];
480 let buf = make_buffer(&mut data);
481 let via_iter: Vec<i32> = buf.iter_as::<i32>().collect();
482 let via_loop: Vec<i32> = (0..buf.len())
483 .filter_map(|i| buf.get_as::<i32>(i))
484 .collect();
485 assert_eq!(via_iter, via_loop);
486 }
487
488 #[test]
491 fn write_str_encodes_string_into_cells() {
492 let mut data = vec![0i32; 3];
494 let mut buf = make_buffer(&mut data);
495 assert!(buf.write_str("hi").is_ok());
496 assert_eq!(data[0], i32::from(b'h'));
497 assert_eq!(data[1], i32::from(b'i'));
498 assert_eq!(data[2], 0); }
500
501 #[test]
502 fn write_str_empty_string_writes_null_terminator() {
503 let mut data = vec![99i32; 2];
504 let mut buf = make_buffer(&mut data);
505 assert!(buf.write_str("").is_ok());
506 assert_eq!(data[0], 0);
507 }
508
509 #[test]
510 fn write_str_exact_fit_fails() {
511 let mut data = vec![0i32; 3];
513 let mut buf = make_buffer(&mut data);
514 assert!(buf.write_str("abc").is_err());
515 }
516
517 #[test]
520 fn unsized_write_str_sizes_and_writes() {
521 let mut data = vec![0i32; 5];
522 let ub = make_unsized(&mut data);
523 assert!(ub.write_str(5, "hi").is_ok());
524 assert_eq!(data[0], i32::from(b'h'));
525 assert_eq!(data[1], i32::from(b'i'));
526 assert_eq!(data[2], 0);
527 }
528
529 #[test]
530 fn unsized_write_str_too_long_returns_err() {
531 let mut data = vec![0i32; 3];
532 let ub = make_unsized(&mut data);
533 assert!(ub.write_str(3, "abc").is_err());
534 }
535}