| 1 | //! This package contains just four macros, which enable the creation |
| 2 | //! of array references to portions of arrays or slices (or things |
| 3 | //! that can be sliced). |
| 4 | //! |
| 5 | //! # Examples |
| 6 | //! |
| 7 | //! Here is a simple example of slicing and dicing a slice into array |
| 8 | //! references with these macros. Here we implement a simple |
| 9 | //! little-endian conversion from bytes to `u16`, and demonstrate code |
| 10 | //! that uses `array_ref!` to extract an array reference from a larger |
| 11 | //! array. Note that the documentation for each macro also has an |
| 12 | //! example of its use. |
| 13 | //! |
| 14 | //! ``` |
| 15 | //! #[macro_use] |
| 16 | //! extern crate arrayref; |
| 17 | //! |
| 18 | //! fn read_u16(bytes: &[u8; 2]) -> u16 { |
| 19 | //! bytes[0] as u16 + ((bytes[1] as u16) << 8) |
| 20 | //! } |
| 21 | //! // ... |
| 22 | //! # fn main() { |
| 23 | //! let data = [0,1,2,3,4,0,6,7,8,9]; |
| 24 | //! assert_eq!(256, read_u16(array_ref![data,0,2])); |
| 25 | //! assert_eq!(4, read_u16(array_ref![data,4,2])); |
| 26 | //! # } |
| 27 | //! ``` |
| 28 | #![deny (warnings)] |
| 29 | #![no_std ] |
| 30 | |
| 31 | #[cfg (test)] |
| 32 | #[macro_use ] |
| 33 | extern crate std; |
| 34 | |
| 35 | /// You can use `array_ref` to generate an array reference to a subset |
| 36 | /// of a sliceable bit of data (which could be an array, or a slice, |
| 37 | /// or a Vec). |
| 38 | /// |
| 39 | /// **Panics** if the slice is out of bounds. |
| 40 | /// |
| 41 | /// ``` |
| 42 | /// #[macro_use] |
| 43 | /// extern crate arrayref; |
| 44 | /// |
| 45 | /// fn read_u16(bytes: &[u8; 2]) -> u16 { |
| 46 | /// bytes[0] as u16 + ((bytes[1] as u16) << 8) |
| 47 | /// } |
| 48 | /// // ... |
| 49 | /// # fn main() { |
| 50 | /// let data = [0,1,2,3,4,0,6,7,8,9]; |
| 51 | /// assert_eq!(256, read_u16(array_ref![data,0,2])); |
| 52 | /// assert_eq!(4, read_u16(array_ref![data,4,2])); |
| 53 | /// # } |
| 54 | /// ``` |
| 55 | |
| 56 | #[macro_export ] |
| 57 | macro_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 | /// You can use `array_refs` to generate a series of array references |
| 75 | /// to an input array reference. The idea is if you want to break an |
| 76 | /// array into a series of contiguous and non-overlapping arrays. |
| 77 | /// `array_refs` is a bit funny in that it insists on slicing up the |
| 78 | /// *entire* array. This is intentional, as I find it handy to make |
| 79 | /// me ensure that my sub-arrays add up to the entire array. This |
| 80 | /// macro will *never* panic, since the sizes are all checked at |
| 81 | /// compile time. |
| 82 | /// |
| 83 | /// Note that unlike `array_ref!`, `array_refs` *requires* that the |
| 84 | /// first argument be an array reference. The following arguments are |
| 85 | /// the lengths of each subarray you wish a reference to. The total |
| 86 | /// of these arguments *must* equal the size of the array itself. |
| 87 | /// |
| 88 | /// ``` |
| 89 | /// #[macro_use] |
| 90 | /// extern crate arrayref; |
| 91 | /// |
| 92 | /// fn read_u16(bytes: &[u8; 2]) -> u16 { |
| 93 | /// bytes[0] as u16 + ((bytes[1] as u16) << 8) |
| 94 | /// } |
| 95 | /// // ... |
| 96 | /// # fn main() { |
| 97 | /// let data = [0,1,2,3,4,0,6,7]; |
| 98 | /// let (a,b,c) = array_refs![&data,2,2,4]; |
| 99 | /// assert_eq!(read_u16(a), 256); |
| 100 | /// assert_eq!(read_u16(b), 3*256+2); |
| 101 | /// assert_eq!(*c, [4,0,6,7]); |
| 102 | /// # } |
| 103 | /// ``` |
| 104 | #[macro_export ] |
| 105 | macro_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 | /// You can use `mut_array_refs` to generate a series of mutable array |
| 162 | /// references to an input mutable array reference. The idea is if |
| 163 | /// you want to break an array into a series of contiguous and |
| 164 | /// non-overlapping mutable array references. Like `array_refs!`, |
| 165 | /// `mut_array_refs!` is a bit funny in that it insists on slicing up |
| 166 | /// the *entire* array. This is intentional, as I find it handy to |
| 167 | /// make me ensure that my sub-arrays add up to the entire array. |
| 168 | /// This macro will *never* panic, since the sizes are all checked at |
| 169 | /// compile time. |
| 170 | /// |
| 171 | /// Note that unlike `array_mut_ref!`, `mut_array_refs` *requires* |
| 172 | /// that the first argument be a mutable array reference. The |
| 173 | /// following arguments are the lengths of each subarray you wish a |
| 174 | /// reference to. The total of these arguments *must* equal the size |
| 175 | /// of the array itself. Also note that this macro allows you to take |
| 176 | /// out multiple mutable references to a single object, which is both |
| 177 | /// weird and powerful. |
| 178 | /// |
| 179 | /// ``` |
| 180 | /// #[macro_use] |
| 181 | /// extern crate arrayref; |
| 182 | /// |
| 183 | /// fn write_u16(bytes: &mut [u8; 2], num: u16) { |
| 184 | /// bytes[0] = num as u8; |
| 185 | /// bytes[1] = (num >> 8) as u8; |
| 186 | /// } |
| 187 | /// fn write_u32(bytes: &mut [u8; 4], num: u32) { |
| 188 | /// bytes[0] = num as u8; |
| 189 | /// bytes[1] = (num >> 8) as u8; // this is buggy to save space... |
| 190 | /// } |
| 191 | /// // ... |
| 192 | /// # fn main() { |
| 193 | /// let mut data = [0,1,2,3,4,0,6,7]; |
| 194 | /// let (a,b,c) = mut_array_refs![&mut data,2,2,4]; |
| 195 | /// // let's write out some nice prime numbers! |
| 196 | /// write_u16(a, 37); |
| 197 | /// write_u16(b, 73); |
| 198 | /// write_u32(c, 137); // approximate inverse of the fine structure constant! |
| 199 | /// # } |
| 200 | /// ``` |
| 201 | #[macro_export ] |
| 202 | macro_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 | /// You can use `array_mut_ref` to generate a mutable array reference |
| 259 | /// to a subset of a sliceable bit of data (which could be an array, |
| 260 | /// or a slice, or a Vec). |
| 261 | /// |
| 262 | /// **Panics** if the slice is out of bounds. |
| 263 | /// |
| 264 | /// ``` |
| 265 | /// #[macro_use] |
| 266 | /// extern crate arrayref; |
| 267 | /// |
| 268 | /// fn write_u16(bytes: &mut [u8; 2], num: u16) { |
| 269 | /// bytes[0] = num as u8; |
| 270 | /// bytes[1] = (num >> 8) as u8; |
| 271 | /// } |
| 272 | /// // ... |
| 273 | /// # fn main() { |
| 274 | /// let mut data = [0,1,2,3,4,0,6,7,8,9]; |
| 275 | /// write_u16(array_mut_ref![data,0,2], 1); |
| 276 | /// write_u16(array_mut_ref![data,2,2], 5); |
| 277 | /// assert_eq!(*array_ref![data,0,4], [1,0,5,0]); |
| 278 | /// *array_mut_ref![data,4,5] = [4,3,2,1,0]; |
| 279 | /// assert_eq!(data, [1,0,5,0,4,3,2,1,0,9]); |
| 280 | /// # } |
| 281 | /// ``` |
| 282 | #[macro_export ] |
| 283 | macro_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)] |
| 302 | mod test { |
| 303 | |
| 304 | extern crate quickcheck; |
| 305 | |
| 306 | use std::vec::Vec; |
| 307 | |
| 308 | // use super::*; |
| 309 | |
| 310 | #[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 | // Compute the following, with correct results even if the sum would overflow: |
| 343 | // if data.len() < offset + 5 |
| 344 | 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 | // Compute the following, with correct results even if the sum would overflow: |
| 357 | // if data.len() >= offset + 5 |
| 358 | 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 | // Compute the following, with correct results even if the sum would overflow: |
| 372 | // if data.len() < offset + 7 |
| 373 | 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 | // Compute the following, with correct results even if the sum would overflow: |
| 387 | // if data.len() >= offset + 32 |
| 388 | 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 | // temporarily borrow the data to modify it. |
| 441 | 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 | // temporarily borrow the data to modify it. |
| 464 | 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 | } // mod test |
| 505 | |