1#![deny(warnings)]
29#![no_std]
30
31#[cfg(test)]
32#[macro_use]
33extern crate std;
34
35#[macro_export]
57macro_rules! array_ref {
58 ($arr:expr, $offset:expr, $len:expr) => {{
59 {
60 #[inline]
61 const unsafe fn as_array<T>(slice: &[T]) -> &[T; $len] {
62 &*(slice.as_ptr() as *const [_; $len])
63 }
64 let offset = $offset;
65 let slice = &$arr[offset..offset + $len];
66 #[allow(unused_unsafe)]
67 unsafe {
68 as_array(slice)
69 }
70 }
71 }};
72}
73
74#[macro_export]
105macro_rules! array_refs {
106 ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{
107 {
108 use core::slice;
109 #[inline]
110 #[allow(unused_assignments)]
111 #[allow(clippy::eval_order_dependence)]
112 const unsafe fn as_arrays<T>(a: &[T]) -> ( $( &[T; $pre], )* &[T], $( &[T; $post], )*) {
113 const MIN_LEN: usize = 0usize $( .saturating_add($pre) )* $( .saturating_add($post) )*;
114 assert!(MIN_LEN < usize::MAX, "Your arrays are too big, are you trying to hack yourself?!");
115 let var_len = a.len() - MIN_LEN;
116 assert!(a.len() >= MIN_LEN);
117 let mut p = a.as_ptr();
118 ( $( {
119 let aref = & *(p as *const [T; $pre]);
120 p = p.add($pre);
121 aref
122 }, )* {
123 let sl = slice::from_raw_parts(p as *const T, var_len);
124 p = p.add(var_len);
125 sl
126 }, $( {
127 let aref = & *(p as *const [T; $post]);
128 p = p.add($post);
129 aref
130 }, )*)
131 }
132 let input = $arr;
133 #[allow(unused_unsafe)]
134 unsafe {
135 as_arrays(input)
136 }
137 }
138 }};
139 ( $arr:expr, $( $len:expr ),* ) => {{
140 {
141 #[inline]
142 #[allow(unused_assignments)]
143 #[allow(clippy::eval_order_dependence)]
144 const unsafe fn as_arrays<T>(a: &[T; $( $len + )* 0 ]) -> ( $( &[T; $len], )* ) {
145 let mut p = a.as_ptr();
146 ( $( {
147 let aref = &*(p as *const [T; $len]);
148 p = p.offset($len as isize);
149 aref
150 }, )* )
151 }
152 let input = $arr;
153 #[allow(unused_unsafe)]
154 unsafe {
155 as_arrays(input)
156 }
157 }
158 }}
159}
160
161#[macro_export]
202macro_rules! mut_array_refs {
203 ( $arr:expr, $( $pre:expr ),* ; .. ; $( $post:expr ),* ) => {{
204 {
205 use core::slice;
206 #[inline]
207 #[allow(unused_assignments)]
208 #[allow(clippy::eval_order_dependence)]
209 unsafe fn as_arrays<T>(a: &mut [T]) -> ( $( &mut [T; $pre], )* &mut [T], $( &mut [T; $post], )*) {
210 const MIN_LEN: usize = 0usize $( .saturating_add($pre) )* $( .saturating_add($post) )*;
211 assert!(MIN_LEN < usize::MAX, "Your arrays are too big, are you trying to hack yourself?!");
212 let var_len = a.len() - MIN_LEN;
213 assert!(a.len() >= MIN_LEN);
214 let mut p = a.as_mut_ptr();
215 ( $( {
216 let aref = &mut *(p as *mut [T; $pre]);
217 p = p.add($pre);
218 aref
219 }, )* {
220 let sl = slice::from_raw_parts_mut(p as *mut T, var_len);
221 p = p.add(var_len);
222 sl
223 }, $( {
224 let aref = &mut *(p as *mut [T; $post]);
225 p = p.add($post);
226 aref
227 }, )*)
228 }
229 let input = $arr;
230 #[allow(unused_unsafe)]
231 unsafe {
232 as_arrays(input)
233 }
234 }
235 }};
236 ( $arr:expr, $( $len:expr ),* ) => {{
237 {
238 #[inline]
239 #[allow(unused_assignments)]
240 #[allow(clippy::eval_order_dependence)]
241 unsafe fn as_arrays<T>(a: &mut [T; $( $len + )* 0 ]) -> ( $( &mut [T; $len], )* ) {
242 let mut p = a.as_mut_ptr();
243 ( $( {
244 let aref = &mut *(p as *mut [T; $len]);
245 p = p.add($len);
246 aref
247 }, )* )
248 }
249 let input = $arr;
250 #[allow(unused_unsafe)]
251 unsafe {
252 as_arrays(input)
253 }
254 }
255 }};
256}
257
258#[macro_export]
283macro_rules! array_mut_ref {
284 ($arr:expr, $offset:expr, $len:expr) => {{
285 {
286 #[inline]
287 unsafe fn as_array<T>(slice: &mut [T]) -> &mut [T; $len] {
288 &mut *(slice.as_mut_ptr() as *mut [_; $len])
289 }
290 let offset = $offset;
291 let slice = &mut $arr[offset..offset + $len];
292 #[allow(unused_unsafe)]
293 unsafe {
294 as_array(slice)
295 }
296 }
297 }};
298}
299
300#[allow(clippy::all)]
301#[cfg(test)]
302mod test {
303
304 extern crate quickcheck;
305
306 use std::vec::Vec;
307
308 #[test]
311 #[should_panic]
312 fn checks_bounds() {
313 let foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
314 let bar = array_ref!(foo, 1, 11);
315 println!("I am checking that I can dereference bar[0] = {}", bar[0]);
316 }
317
318 #[test]
319 fn simple_case_works() {
320 fn check(expected: [u8; 3], actual: &[u8; 3]) {
321 for (e, a) in (&expected).iter().zip(actual.iter()) {
322 assert_eq!(e, a)
323 }
324 }
325 let mut foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
326 {
327 let bar = array_ref!(foo, 2, 3);
328 check([2, 3, 4], bar);
329 }
330 check([0, 1, 2], array_ref!(foo, 0, 3));
331 fn zero2(x: &mut [u8; 2]) {
332 x[0] = 0;
333 x[1] = 0;
334 }
335 zero2(array_mut_ref!(foo, 8, 2));
336 check([0, 0, 10], array_ref!(foo, 8, 3));
337 }
338
339 #[test]
340 fn check_array_ref_5() {
341 fn f(data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
342 if data.len() < 5 || data.len() - 5 < offset {
345 return quickcheck::TestResult::discard();
346 }
347 let out = array_ref!(data, offset, 5);
348 quickcheck::TestResult::from_bool(out.len() == 5)
349 }
350 quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
351 }
352
353 #[test]
354 fn check_array_ref_out_of_bounds_5() {
355 fn f(data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
356 if data.len() >= 5 && data.len() - 5 >= offset {
359 return quickcheck::TestResult::discard();
360 }
361 quickcheck::TestResult::must_fail(move || {
362 array_ref!(data, offset, 5);
363 })
364 }
365 quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
366 }
367
368 #[test]
369 fn check_array_mut_ref_7() {
370 fn f(mut data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
371 if data.len() < 7 || data.len() - 7 < offset {
374 return quickcheck::TestResult::discard();
375 }
376 let out = array_mut_ref!(data, offset, 7);
377 out[6] = 3;
378 quickcheck::TestResult::from_bool(out.len() == 7)
379 }
380 quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
381 }
382
383 #[test]
384 fn check_array_mut_ref_out_of_bounds_32() {
385 fn f(mut data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
386 if data.len() >= 32 && data.len() - 32 >= offset {
389 return quickcheck::TestResult::discard();
390 }
391 quickcheck::TestResult::must_fail(move || {
392 array_mut_ref!(data, offset, 32);
393 })
394 }
395 quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
396 }
397
398 #[test]
399 fn test_5_array_refs() {
400 let mut data: [usize; 128] = [0; 128];
401 for i in 0..128 {
402 data[i] = i;
403 }
404 let data = data;
405 let (a, b, c, d, e) = array_refs!(&data, 1, 14, 3, 100, 10);
406 assert_eq!(a.len(), 1 as usize);
407 assert_eq!(b.len(), 14 as usize);
408 assert_eq!(c.len(), 3 as usize);
409 assert_eq!(d.len(), 100 as usize);
410 assert_eq!(e.len(), 10 as usize);
411 assert_eq!(a, array_ref![data, 0, 1]);
412 assert_eq!(b, array_ref![data, 1, 14]);
413 assert_eq!(c, array_ref![data, 15, 3]);
414 assert_eq!(e, array_ref![data, 118, 10]);
415 }
416
417 #[test]
418 fn test_5_array_refs_dotdot() {
419 let mut data: [usize; 128] = [0; 128];
420 for i in 0..128 {
421 data[i] = i;
422 }
423 let data = data;
424 let (a, b, c, d, e) = array_refs!(&data, 1, 14, 3; ..; 10);
425 assert_eq!(a.len(), 1 as usize);
426 assert_eq!(b.len(), 14 as usize);
427 assert_eq!(c.len(), 3 as usize);
428 assert_eq!(d.len(), 100 as usize);
429 assert_eq!(e.len(), 10 as usize);
430 assert_eq!(a, array_ref![data, 0, 1]);
431 assert_eq!(b, array_ref![data, 1, 14]);
432 assert_eq!(c, array_ref![data, 15, 3]);
433 assert_eq!(e, array_ref![data, 118, 10]);
434 }
435
436 #[test]
437 fn test_5_mut_xarray_refs() {
438 let mut data: [usize; 128] = [0; 128];
439 {
440 let (a, b, c, d, e) = mut_array_refs!(&mut data, 1, 14, 3, 100, 10);
442 assert_eq!(a.len(), 1 as usize);
443 assert_eq!(b.len(), 14 as usize);
444 assert_eq!(c.len(), 3 as usize);
445 assert_eq!(d.len(), 100 as usize);
446 assert_eq!(e.len(), 10 as usize);
447 *a = [1; 1];
448 *b = [14; 14];
449 *c = [3; 3];
450 *d = [100; 100];
451 *e = [10; 10];
452 }
453 assert_eq!(&[1; 1], array_ref![data, 0, 1]);
454 assert_eq!(&[14; 14], array_ref![data, 1, 14]);
455 assert_eq!(&[3; 3], array_ref![data, 15, 3]);
456 assert_eq!(&[10; 10], array_ref![data, 118, 10]);
457 }
458
459 #[test]
460 fn test_5_mut_xarray_refs_with_dotdot() {
461 let mut data: [usize; 128] = [0; 128];
462 {
463 let (a, b, c, d, e) = mut_array_refs!(&mut data, 1, 14, 3; ..; 10);
465 assert_eq!(a.len(), 1 as usize);
466 assert_eq!(b.len(), 14 as usize);
467 assert_eq!(c.len(), 3 as usize);
468 assert_eq!(d.len(), 100 as usize);
469 assert_eq!(e.len(), 10 as usize);
470 *a = [1; 1];
471 *b = [14; 14];
472 *c = [3; 3];
473 *e = [10; 10];
474 }
475 assert_eq!(&[1; 1], array_ref![data, 0, 1]);
476 assert_eq!(&[14; 14], array_ref![data, 1, 14]);
477 assert_eq!(&[3; 3], array_ref![data, 15, 3]);
478 assert_eq!(&[10; 10], array_ref![data, 118, 10]);
479 }
480
481 #[forbid(clippy::ptr_offset_with_cast)]
482 #[test]
483 fn forbidden_clippy_lints_do_not_fire() {
484 let mut data = [0u8; 32];
485 let _ = array_refs![&data, 8; .. ;];
486 let _ = mut_array_refs![&mut data, 8; .. ; 10];
487 }
488
489 #[test]
490 fn single_arg_refs() {
491 let mut data = [0u8; 8];
492 let (_,) = array_refs![&data, 8];
493 let (_,) = mut_array_refs![&mut data, 8];
494
495 let (_, _) = array_refs![&data, 4; ..;];
496 let (_, _) = mut_array_refs![&mut data, 4; ..;];
497
498 let (_, _) = array_refs![&data,; ..; 4];
499 let (_, _) = mut_array_refs![&mut data,; ..; 4];
500
501 let (_,) = array_refs![&data,; ..;];
502 let (_,) = mut_array_refs![&mut data,; ..;];
503 }
504}