1#![doc = include_str!("../README.md")]
2
3use std::{
4 ops::{
5 Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive,
6 },
7 ptr::{slice_from_raw_parts, slice_from_raw_parts_mut},
8};
9use thiserror::Error;
10
11#[cfg(target_family = "windows")]
12mod windows;
13
14#[cfg(target_family = "windows")]
15use windows::*;
16
17#[cfg(target_os = "linux")]
18mod linux;
19
20#[cfg(target_os = "linux")]
21use linux::*;
22
23#[cfg(any(target_os = "macos", target_os = "ios"))]
24mod macos;
25
26#[cfg(any(target_os = "macos", target_os = "ios"))]
27use macos::*;
28
29#[derive(Debug, Error)]
33pub enum MagicBufferError {
34 #[error("out of memory")]
36 OOM,
37 #[error("invalid buffer len, {msg}")]
39 InvalidLen {
40 msg: String,
42 },
43}
44
45#[derive(Debug)]
46pub struct MagicBuffer {
47 addr: *mut u8,
48 len: usize,
49 mask: usize,
50}
51
52unsafe impl Send for MagicBuffer {}
55
56unsafe impl Sync for MagicBuffer {}
58
59#[allow(clippy::len_without_is_empty)]
80impl MagicBuffer {
81 pub fn new(len: usize) -> Result<Self, MagicBufferError> {
99 if len == 0 {
100 return Err(MagicBufferError::InvalidLen {
101 msg: "len must be greater than 0".to_string(),
102 });
103 }
104
105 if !len.is_power_of_two() {
106 return Err(MagicBufferError::InvalidLen {
107 msg: "len must be power of two".to_string(),
108 });
109 }
110
111 let min_len = Self::min_len();
112 if len % min_len != 0 {
113 return Err(MagicBufferError::InvalidLen {
114 msg: format!("len must be page aligned, {}", min_len),
115 });
116 }
117
118 Ok(Self {
119 addr: unsafe { magic_buf_alloc(len) }?,
120 mask: len - 1,
121 len,
122 })
123 }
124
125 pub fn min_len() -> usize {
130 unsafe { magic_buf_min_len() }
131 }
132
133 pub fn len(&self) -> usize {
135 self.len
136 }
137
138 pub fn as_ptr(&self, offset: usize) -> *const u8 {
161 unsafe { self.addr.add(self.fast_mod(offset)).cast_const() }
162 }
163
164 pub fn as_mut_ptr(&mut self, offset: usize) -> *mut u8 {
184 unsafe { self.addr.add(self.fast_mod(offset)) }
185 }
186
187 #[inline(always)]
188 unsafe fn as_slice(&self, offset: usize, len: usize) -> &[u8] {
189 &*(slice_from_raw_parts(self.addr.add(offset), len))
190 }
191
192 #[inline(always)]
193 unsafe fn as_slice_mut(&mut self, offset: usize, len: usize) -> &mut [u8] {
194 &mut *(slice_from_raw_parts_mut(self.addr.add(offset), len))
195 }
196
197 #[inline(always)]
198 fn fast_mod(&self, v: usize) -> usize {
199 v & self.mask
200 }
201}
202
203impl Drop for MagicBuffer {
204 fn drop(&mut self) {
205 unsafe { magic_buf_free(self.addr, self.len) }
206 }
207}
208
209impl Deref for MagicBuffer {
210 type Target = [u8];
211
212 fn deref(&self) -> &Self::Target {
213 unsafe { self.as_slice(0, self.len) }
214 }
215}
216
217impl DerefMut for MagicBuffer {
218 fn deref_mut(&mut self) -> &mut Self::Target {
219 unsafe { self.as_slice_mut(0, self.len) }
220 }
221}
222
223impl Index<usize> for MagicBuffer {
224 type Output = u8;
225
226 fn index(&self, index: usize) -> &Self::Output {
227 unsafe { &*self.addr.add(self.fast_mod(index)) }
228 }
229}
230
231impl IndexMut<usize> for MagicBuffer {
232 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
233 unsafe { &mut *self.addr.add(self.fast_mod(index)) }
234 }
235}
236
237macro_rules! index_impl {
238 ($from:ty, $to:ty) => {
239 impl Index<$from> for MagicBuffer {
240 type Output = u8;
241
242 fn index(&self, index: $from) -> &Self::Output {
243 &self[index as $to]
244 }
245 }
246
247 impl IndexMut<$from> for MagicBuffer {
248 fn index_mut(&mut self, index: $from) -> &mut Self::Output {
249 &mut self[index as $to]
250 }
251 }
252 };
253}
254
255index_impl!(i64, isize);
256index_impl!(i32, isize);
257index_impl!(i16, isize);
258index_impl!(i8, isize);
259
260index_impl!(u64, usize);
261index_impl!(u32, usize);
262index_impl!(u16, usize);
263index_impl!(u8, usize);
264
265impl Index<isize> for MagicBuffer {
266 type Output = u8;
267
268 fn index(&self, index: isize) -> &Self::Output {
269 let index = if index < 0 {
270 self.len - self.fast_mod((-index) as usize)
271 } else {
272 self.fast_mod(index as usize)
273 };
274 unsafe { &*self.addr.add(index) }
275 }
276}
277
278impl IndexMut<isize> for MagicBuffer {
279 fn index_mut(&mut self, index: isize) -> &mut Self::Output {
280 let index = if index < 0 {
281 self.len - self.fast_mod((-index) as usize)
282 } else {
283 self.fast_mod(index as usize)
284 };
285 unsafe { &mut *self.addr.add(index) }
286 }
287}
288
289impl Index<Range<usize>> for MagicBuffer {
290 type Output = [u8];
291
292 fn index(&self, index: Range<usize>) -> &Self::Output {
293 if index.start > index.end {
294 return &[];
295 }
296
297 let len = index.end - index.start;
298 if len > self.len {
299 panic!("out of bounds")
300 }
301
302 unsafe { self.as_slice(self.fast_mod(index.start), len) }
303 }
304}
305
306impl IndexMut<Range<usize>> for MagicBuffer {
307 fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
308 if index.start > index.end {
309 return &mut [];
310 }
311
312 let len = index.end - index.start;
313 if len > self.len {
314 panic!("out of bounds")
315 }
316
317 unsafe { self.as_slice_mut(self.fast_mod(index.start), len) }
318 }
319}
320
321impl Index<RangeTo<usize>> for MagicBuffer {
322 type Output = [u8];
323
324 fn index(&self, index: RangeTo<usize>) -> &Self::Output {
325 let start = index.end - self.len;
326 unsafe { self.as_slice(self.fast_mod(start), self.len) }
327 }
328}
329
330impl IndexMut<RangeTo<usize>> for MagicBuffer {
331 fn index_mut(&mut self, index: RangeTo<usize>) -> &mut Self::Output {
332 let start = index.end - self.len;
333 unsafe { self.as_slice_mut(self.fast_mod(start), self.len) }
334 }
335}
336
337impl Index<RangeFrom<usize>> for MagicBuffer {
338 type Output = [u8];
339
340 fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
341 unsafe { self.as_slice(self.fast_mod(index.start), self.len) }
342 }
343}
344
345impl IndexMut<RangeFrom<usize>> for MagicBuffer {
346 fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut Self::Output {
347 unsafe { self.as_slice_mut(self.fast_mod(index.start), self.len) }
348 }
349}
350
351impl Index<RangeToInclusive<usize>> for MagicBuffer {
352 type Output = [u8];
353
354 fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
355 let start = index.end - self.len + 1;
356 unsafe { self.as_slice(self.fast_mod(start), self.len) }
357 }
358}
359
360impl IndexMut<RangeToInclusive<usize>> for MagicBuffer {
361 fn index_mut(&mut self, index: RangeToInclusive<usize>) -> &mut Self::Output {
362 let start = index.end - self.len + 1;
363 unsafe { self.as_slice_mut(self.fast_mod(start), self.len) }
364 }
365}
366
367impl Index<RangeFull> for MagicBuffer {
368 type Output = [u8];
369
370 fn index(&self, _: RangeFull) -> &Self::Output {
371 unsafe { self.as_slice(0, self.len) }
372 }
373}
374
375impl IndexMut<RangeFull> for MagicBuffer {
376 fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
377 unsafe { self.as_slice_mut(0, self.len) }
378 }
379}
380
381#[cfg(test)]
382mod tests {
383 use super::*;
384
385 const VALID_BUF_LEN: usize = 1 << 16;
386 const INVALID_BUF_LEN_ALIGN: usize = 1 << 8;
387 const INVALID_BUF_LEN_POW2: usize = (1 << 16) + 5;
388
389 #[test]
390 fn allocates_buffer() {
391 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
392 drop(buf);
393 }
394
395 #[test]
396 fn requires_power_of_two() {
397 MagicBuffer::new(INVALID_BUF_LEN_POW2)
398 .map_err(|e| {
399 println!("{}", e);
400 e
401 })
402 .expect_err("should not allocate buffer");
403 }
404
405 #[test]
406 fn requires_aligned_len() {
407 MagicBuffer::new(INVALID_BUF_LEN_ALIGN)
408 .map_err(|e| {
409 println!("{}", e);
410 e
411 })
412 .expect_err("should not allocate buffer");
413 }
414
415 #[test]
416 fn writes_are_visible_wrap_around() {
417 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
418 buf[0] = b'a';
419 assert_eq!(buf[0], buf[VALID_BUF_LEN]);
420 }
421
422 #[test]
423 fn deref_as_slice() {
424 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
425 let slice: &[u8] = &buf;
426 assert_eq!(VALID_BUF_LEN, slice.len());
427 }
428
429 #[test]
430 fn deref_mut_as_slice() {
431 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
432 let slice: &mut [u8] = &mut buf;
433 assert_eq!(VALID_BUF_LEN, slice.len());
434 }
435
436 #[test]
437 fn closed_range() {
438 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
439 let slice = &buf[0..VALID_BUF_LEN];
440 assert_eq!(VALID_BUF_LEN, slice.len());
441 }
442
443 #[test]
444 fn closed_range_mut() {
445 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
446 let slice = &mut buf[0..VALID_BUF_LEN];
447 assert_eq!(VALID_BUF_LEN, slice.len());
448 }
449
450 #[test]
451 fn range_to() {
452 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
453 let slice = &buf[..VALID_BUF_LEN + 1];
454 assert_eq!(VALID_BUF_LEN, slice.len());
455 }
456
457 #[test]
458 fn range_to_mut() {
459 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
460 let slice = &mut buf[..VALID_BUF_LEN + 1];
461 assert_eq!(VALID_BUF_LEN, slice.len());
462 }
463
464 #[test]
465 fn range_from() {
466 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
467 let slice = &buf[1..];
468 assert_eq!(VALID_BUF_LEN, slice.len());
469 }
470
471 #[test]
472 fn range_from_mut() {
473 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
474 let slice = &mut buf[1..];
475 assert_eq!(VALID_BUF_LEN, slice.len());
476 }
477
478 #[test]
479 fn range_to_inclusive() {
480 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
481 let slice = &buf[..=VALID_BUF_LEN];
482 assert_eq!(VALID_BUF_LEN, slice.len());
483 }
484
485 #[test]
486 fn range_to_inclusive_mut() {
487 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
488 let slice = &mut buf[..=VALID_BUF_LEN];
489 assert_eq!(VALID_BUF_LEN, slice.len());
490 }
491
492 #[test]
493 fn range_full() {
494 let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
495 let slice = &buf[..];
496 assert_eq!(VALID_BUF_LEN, slice.len());
497 }
498
499 #[test]
500 fn range_full_mut() {
501 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
502 let slice = &mut buf[..];
503 assert_eq!(VALID_BUF_LEN, slice.len());
504 }
505
506 #[test]
507 fn index_wrap_around() {
508 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
509 buf[0] = b'1';
510 assert_eq!(b'1', buf[VALID_BUF_LEN]);
511 }
512
513 #[test]
514 fn index_negative() {
515 let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
516 buf[-1] = b'2';
517 assert_eq!(b'2', buf[VALID_BUF_LEN - 1]);
518 }
519}