├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── UNLICENSE └── lib.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | env: 6 | RUST_BACKTRACE: 1 7 | 8 | jobs: 9 | check: 10 | name: Test 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | toolchain: [ stable, nightly ] 15 | use_std: [ std, nostd ] 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | # Test with std 20 | - uses: actions-rs/toolchain@v1 21 | name: Toolchain setup 22 | if: ${{ matrix.use_std == 'std' }} 23 | with: 24 | profile: minimal 25 | toolchain: ${{ matrix.toolchain }} 26 | override: true 27 | - uses: actions-rs/cargo@v1 28 | name: Test 29 | if: ${{ matrix.use_std == 'std' }} 30 | with: 31 | command: test 32 | args: --features=std 33 | 34 | # Check on nostd 35 | - uses: actions-rs/toolchain@v1 36 | name: Toolchain setup 37 | if: ${{ matrix.use_std == 'nostd' }} 38 | with: 39 | profile: minimal 40 | toolchain: ${{ matrix.toolchain }} 41 | target: thumbv6m-none-eabi 42 | override: true 43 | - uses: actions-rs/cargo@v1 44 | name: Check (nostd) 45 | if: ${{ matrix.use_std == 'nostd' }} 46 | with: 47 | command: check 48 | args: --target thumbv6m-none-eabi 49 | 50 | doc-check: 51 | name: Doc check 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v2 55 | name: Toolchain setup 56 | with: 57 | profile: minimal 58 | toolchain: stable 59 | - uses: actions-rs/install@v0.1 60 | name: Install cargo-deadlinks 61 | with: 62 | crate: cargo-deadlinks 63 | version: 0.8.0 64 | - name: Run cargo-deadlinks 65 | run: cargo deadlinks 66 | 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | (there are currently no unreleased changes) 10 | 11 | ## [0.3.2] - 2022-03-23 12 | ### Changed 13 | - `flat` will now detect integer overflow in obscure edge cases involving ZSTs. 14 | 15 | ## [0.3.1] - 2021-04-11 16 | ### Added 17 | - This crate is now `#![no_std]`. 18 | - Fix some links in docs. 19 | 20 | ## [0.3.0] - 2020-03-31 21 | ### Added 22 | - `IsSliceomorphic` is now implemented for **all** array sizes. Hurrah! 23 | - ...this includes `[T; 0]`, which couldn't be avoided. **Any attempt to call `nest::<[_; 0]>()` will panic!** 24 | ### Changed 25 | - The MSRV is bumped _significantly_ to 1.51 (the latest version of rust), for const generics. 26 | > Normally, MSRV is not tracked for `slice_of_array`, but this seemed big enough to warrant a major version bump. 27 | 28 | ## [0.2.1] - 2018-11-11 29 | ### Added 30 | - Added more implementations of the trait up to size 128, and some powers of 2 and 10. 31 | 32 | ## [0.2.0] - 2018-04-26 33 | ### Added 34 | - This change log. 35 | - `IsSliceomorphic` now explicitly supports the use case of impls on wrapper types around arrays, so that I can sleep at night. 36 | - `<[T]>::to_array()`, because type inference hates `as_array().clone()`. 37 | 38 | ### Changed 39 | - `IsSliceomorphic::array_len` has been replaced with `IsSliceomorphic::LEN`. 40 | - Accordingly, the minimum supported version of Rust has bumped to... hell, idunno. 41 | 42 | ## 0.1.1 - 2017-10-13 43 | ### Added 44 | - `<[[T; n]]>::flat` 45 | - `<[T]>::nest` 46 | - `<[T]>::as_array` 47 | - ...and `mut` variants. 48 | 49 | [Unreleased]: https://github.com/ExpHP/slice-of-array/compare/v0.3.2...HEAD 50 | [0.3.2]: https://github.com/ExpHP/slice-of-array/compare/v0.3.1...v0.3.2 51 | [0.3.1]: https://github.com/ExpHP/slice-of-array/compare/v0.3.0...v0.3.1 52 | [0.3.0]: https://github.com/ExpHP/slice-of-array/compare/v0.2.1...v0.3.0 53 | [0.2.1]: https://github.com/ExpHP/slice-of-array/compare/v0.2.0...v0.2.1 54 | [0.2.0]: https://github.com/ExpHP/slice-of-array/compare/v0.1.1...v0.2.0 55 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "slice-of-array" 3 | version = "0.3.2" 4 | authors = ["Michael Lamparski "] 5 | documentation = "https://docs.rs/slice-of-array" 6 | repository = "https://github.com/ExpHP/slice-of-array" 7 | description = "Extension traits for casting between slices and slices of arrays. (&[T] <-> &[[T; n]])" 8 | keywords = ["slice", "util", "no_std", "flatten", "nest"] 9 | categories = ["data-structures"] 10 | readme = "README.md" 11 | license = "Unlicense" 12 | edition = "2018" 13 | 14 | [lib] 15 | path = "lib.rs" 16 | 17 | [dependencies] 18 | 19 | [dev-dependencies] 20 | version-sync = "0.9" 21 | 22 | [features] 23 | # Link to std. In the future, may also enable features that interop with std. 24 | std = [] 25 | 26 | [package.metadata.docs.rs] 27 | all-features = true 28 | targets = ["x86_64-unknown-linux-gnu"] 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Crates.io](https://img.shields.io/crates/v/slice-of-array.svg)](https://crates.io/crates/slice-of-array) 2 | [![Docs.rs](https://docs.rs/slice-of-array/badge.svg)](https://docs.rs/slice-of-array/*/slice_of_array/) 3 | 4 | # `slice-of-array` 5 | 6 | Extension traits on `[T]` for converting to and from `[[T; n]]`. 7 | 8 | ```toml 9 | [dependencies] 10 | slice-of-array = "0.3.2" 11 | ``` 12 | 13 | ```rust 14 | extern crate slice_of_array; 15 | use ::slice_of_array::prelude::*; 16 | 17 | let vec = vec![[1, 0], [0, 1]]; 18 | let _: &[i32] = vec.flat(); 19 | let _: &[[[i32; 2]; 1]] = vec.nest(); 20 | let _: &[[i32; 2]; 2] = vec.as_array(); 21 | ``` 22 | 23 | **Use types like `&[[f64; 3]]` in your public interfaces without fear!** 24 | 25 | You'll be able to flatten that stuff just fine when delegating work to (insert your favorite linear algebra library here)! 26 | 27 | Not to mention everybody using your library will have no problem creating the necessary slice types to use your interface. 28 | 29 | ...uh, that is, assuming that they also have found this or a similar crate. And that they aren't internally using something like `(f64, f64, f64)` or some `#[repr(rust)]` struct. Or a structure of arrays. 30 | 31 | Can't win 'em all. 32 | 33 | ## Q&A 34 | 35 | ### Oh god not another slice-to-array library 36 | 37 | Hey hey hey, hold on here! This is **not** a slice-to-array library. It is a **slice _of_ array** library! Everybody and their mother has published their own crate for converting between `&[T]` and `&[T; n]` on crates.io, but **only** `slice-of-array`™ lets you convert between `&[T]` and `&[[T; n]]`. 38 | 39 | That said... uh, yes, one of its features is indeed casting slices to arrays. I'm sorry. 40 | 41 | ### Panics by default? 42 | 43 | Panics by default. 44 | 45 | It's main purpose is for bridging between APIs that work on flattened vectors and APIs that work on slices of arrays. In these places where it is intended to be used, you already know that your data is of the appropriate shape, and `Option` would get in the way. 46 | 47 | ### I want to make a `Vec<_>` instead of `&[_]` 48 | 49 | `.flat().to_vec()` or `.nest().to_vec()` 50 | 51 | ### No no no, I want to make a `Vec<_>` with *zero cost* 52 | 53 | Yikes! You're messing with metadata that's going to be handed to the allocator when your vec falls out of scope, and I don't think the allocator likes surprises. I don't want that on my conscience! 54 | 55 | If you're convinced that this problem has a solution, then please submit a PR. 56 | 57 | ## [Changelog](CHANGELOG.md) 58 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. 3 | 4 | In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | 8 | For more information, please refer to 9 | -------------------------------------------------------------------------------- /lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url = "https://docs.rs/slice-of-array/0.3.2")] 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | 4 | //! Extension traits for viewing a slice as a slice of arrays or vice versa. 5 | //! 6 | //! Provides the following methods on `[T]`: 7 | //! 8 | //! * **[`nest`]**: `&[T] -> &[[T; n]]` 9 | //! * **[`flat`]**: `&[[T; n]] -> &[T]` 10 | //! * **[`as_array`]**: `&[T] -> &[T; n]` (the reverse is 11 | //! already provided by a coercion) 12 | //! * **`nest_mut`, `flat_mut`, `as_mut_array`** for `&mut [_]`. 13 | //! 14 | //! Altogether, these let you swap between arbitrary representations 15 | //! of contiguous, `T`-aligned streams of `T` data. For instance, 16 | //! to view a `[[i32; 6]; 5]` as a `&[[[i32; 3]; 2]; 5]`, 17 | //! one could write 18 | //! 19 | //! ``` 20 | //! # // FIXME: Dumb/confusing example. I actually wrote it wrong 21 | //! # // the first time, calling `flat()` twice because it 22 | //! # // didn't occur to me that the outer '; 5' is already 23 | //! # // automatically eliminated by coercion. 24 | //! # // 25 | //! # // Almost makes a case for providing `.as_slice()` 26 | //! # // as an explicit form of this coercion. 27 | //! # 28 | //! # use slice_of_array::prelude::*; 29 | //! # let _ = || { 30 | //! # let x: [[i32; 6]; 5] = unimplemented!(); 31 | //! # let _: &[[[i32; 3]; 2]; 5] = 32 | //! x.flat().nest().nest().as_array() 33 | //! # ; 34 | //! # }; 35 | //! ``` 36 | //! 37 | //! Type inference generally works quite well, and as long as the 38 | //! final shape is unambiguous there is no need to annotate types 39 | //! in the middle of the method chain. 40 | //! 41 | //! In cases where type inference is unable to determine the target 42 | //! array size, one can use a turbofish: e.g .`x.nest::<[_; 3]>()`. 43 | //! 44 | //! ``` 45 | //! use ::slice_of_array::prelude::*; 46 | //! 47 | //! let vec = vec![[2i32, 2, 2], [7, 7, 7], [4, 4, 4], [1, 1, 1]]; 48 | //! assert_eq!(vec.flat(), &[2, 2, 2, 7, 7, 7, 4, 4, 4, 1, 1, 1]); 49 | //! 50 | //! // note: this requires an annotation only due to polymorphism in PartialEq 51 | //! let slc = vec.nest::<[_; 2]>(); 52 | //! assert_eq!(slc, &[[[2i32, 2, 2], [7, 7, 7]], [[4, 4, 4], [1, 1, 1]]]); 53 | //! ``` 54 | //! 55 | //! [`nest`] and [`as_array`] panic on failure rather than returning options. 56 | //! The rationale is that it is believed that these these conversions are 57 | //! seldom needed on arbitrary user data which may be the wrong size; rather, 58 | //! they are most likely used when bridging the gap between APIs that work 59 | //! with flattened slices and APIs that work with slices of arrays. 60 | //! 61 | //! Zero-cost conversions in owned data (e.g. between `Vec` 62 | //! and `Vec<[T; n]>`) are not provided, and are probably impossible 63 | //! in consideration of e.g. custom allocators. If you need to 64 | //! convert between such types, you can use these traits in tandem 65 | //! with `<[T]>::to_vec` to perform a copy: 66 | //! 67 | //! ``` 68 | //! # use ::slice_of_array::prelude::*; 69 | //! let vec = vec![[2i32, 2, 2], [7, 7, 7]]; 70 | //! 71 | //! // copying into a Vec 72 | //! let flattened = vec.flat().to_vec(); 73 | //! assert_eq!(flattened, vec![2i32, 2, 2, 7, 7, 7]); 74 | //! ``` 75 | //! 76 | //! [`nest`]: SliceNestExt::nest 77 | //! [`flat`]: SliceFlatExt::flat 78 | //! [`as_array`]: SliceArrayExt::as_array 79 | 80 | use core::slice; 81 | 82 | pub mod prelude { 83 | //! This module contains extension traits from `slice_of_array`. 84 | //! 85 | //! It is meant to be glob imported, by users who may find it obnoxious to remember 86 | //! the precise names of the traits that each method belongs to. 87 | //! 88 | //! ```rust 89 | //! use slice_of_array::prelude::*; 90 | //! ``` 91 | //! 92 | //! `slice_of_array` follows an opinionated policy on what preludes should and should 93 | //! not contain. This prelude will never contain anything that the user will likely 94 | //! want to refer to by name. 95 | 96 | pub use super::SliceFlatExt; 97 | pub use super::SliceNestExt; 98 | pub use super::SliceArrayExt; 99 | } 100 | 101 | /// Marker trait used in bounds of `Slice{Flat,Nest,Array}Ext`. 102 | /// 103 | /// This marks the array types approved for use with `slice_of_array`. 104 | /// 105 | /// # Safety 106 | /// 107 | /// For any implementation, `Self` must have the same size and 108 | /// alignment as `[Self::Element; Self::LEN]`. Furthermore, you 109 | /// must be comfortable with the possibility of `[Self]` being 110 | /// reinterpreted bitwise as `[[Self::Element; Self::LEN]]` (or 111 | /// vice versa) in any possible context. 112 | /// 113 | /// # Notice 114 | /// 115 | /// **Please do NOT use this trait in public interfaces in your code.** 116 | /// 117 | /// `slice_of_array` is not yet 1.0, is not ready (or even designed) 118 | /// to be used as a public dependency. 119 | /// 120 | /// However, feel free to implement this trait on your own private 121 | /// wrapper types around arrays and/or `#[repr(C)]` structs. (these use 122 | /// cases are explicitly supported because the author does it himself, 123 | /// and quite frankly, it's pretty convenient!) 124 | pub unsafe trait IsSliceomorphic: Sized { 125 | type Element; 126 | const LEN: usize; 127 | } 128 | 129 | unsafe impl IsSliceomorphic for [T; N] { 130 | type Element = T; 131 | const LEN: usize = N; 132 | } 133 | 134 | // Validate some known assumptions of IsSliceomorphic "at runtime," 135 | // in a manner which should get optimized into thin air. 136 | fn validate_alignment_and_size() { 137 | use core::mem::{align_of, size_of}; 138 | 139 | assert_eq!( 140 | align_of::(), 141 | align_of::(), 142 | ); 143 | 144 | assert_eq!( 145 | V::LEN * size_of::(), 146 | size_of::(), 147 | ); 148 | } 149 | 150 | /// Permits viewing a slice of arrays as a flat slice. 151 | /// 152 | /// # Panics 153 | /// 154 | /// Will panic if the new length exceeds `usize::MAX`. 155 | /// (in practice, this can only happen with zero-sized types) 156 | /// 157 | /// # Implementors 158 | /// 159 | /// The methods are available on `&[[T; n]]` and `&mut [[T; n]]` 160 | /// for all `T` and `n`. Of course, they are also available on 161 | /// `Vec<[T; n]>` and any other type that derefs or unsizes to `[[T; n]]`. 162 | /// 163 | /// `&[[T; 0]]` does support being flattened into an empty slice, however, 164 | /// please do mind that the inverse operation [`SliceNestExt::nest`] will panic 165 | /// (as it cannot possibly recover the original length of the slice). 166 | /// 167 | /// # Notice 168 | /// 169 | /// The existence of this trait is an implementation detail. Future versions may 170 | /// split it up, merge or rename it. 171 | /// Therefore, **please do NOT use this trait as a generic bound in your code.** 172 | /// 173 | /// (Prefer `[V] where V: `[`IsSliceomorphic`]`` instead) 174 | pub trait SliceFlatExt { 175 | /// View `&[[T; n]]` as `&[T]`. 176 | fn flat(&self) -> &[T]; 177 | 178 | /// View `&mut [[T; n]]` as `&mut [T]` 179 | fn flat_mut(&mut self) -> &mut [T]; 180 | } 181 | 182 | /// Permits viewing a slice as a slice of arrays. 183 | /// 184 | /// The new array dimension can often be inferred. 185 | /// When it is not, a turbofish can be used: `.nest::<[_; 3]>()`. 186 | /// 187 | /// # Panics 188 | /// 189 | /// All methods panic if the input length is not divisible by `n`. 190 | /// 191 | /// # Implementors 192 | /// 193 | /// The methods are available on `&[T]` and `&mut [T]` for all `T`. 194 | /// Of course, they are also available on `Vec` and any other type 195 | /// that derefs or unsizes to `[T]`. 196 | /// 197 | /// **The implementation for `N=0` panics!** (even if the length of the slice is 198 | /// zero, as in this case the length of the nested slice would be degenerate) 199 | /// 200 | /// # Notice 201 | /// 202 | /// The existence of this trait is an implementation detail. Future versions may 203 | /// split it up, merge or rename it. 204 | /// Therefore, **please do NOT use this trait as a generic bound in your code.** 205 | /// 206 | /// (Prefer ` where V: `[`IsSliceomorphic`]`` instead) 207 | pub trait SliceNestExt { 208 | /// View `&[T]` as `&[[T; n]]` without copying. 209 | fn nest>(&self) -> &[V]; 210 | 211 | /// View `&mut [T]` as `&mut [[T; n]]` without copying. 212 | fn nest_mut>(&mut self) -> &mut [V]; 213 | } 214 | 215 | /// Permits viewing a slice as an array. 216 | /// 217 | /// The output array length can often be inferred. 218 | /// When it is not, a turbofish can be used: `.as_array::<[_; 3]>()`. 219 | /// 220 | /// # Panics 221 | /// 222 | /// All methods panic if the slice is not exactly the requested length. 223 | /// 224 | /// # Implementors 225 | /// 226 | /// The methods are available on `&[T]` and `&mut [T]` for all `T`. 227 | /// Of course, they are also available on `Vec` and any other type 228 | /// that derefs or unsizes to `[T]`. 229 | /// 230 | /// # Notice 231 | /// 232 | /// The existence of this trait is an implementation detail. Future versions may 233 | /// split it up, merge or rename it. 234 | /// Therefore, **please do NOT use this trait as a generic bound in your code.** 235 | /// 236 | /// (Prefer `V where V: `[`IsSliceomorphic`]`` instead) 237 | pub trait SliceArrayExt { 238 | /// View `&[T]` as `&[T; n]`. 239 | fn as_array>(&self) -> &V; 240 | 241 | /// View `&mut [T]` as `&mut [T; n]`. 242 | fn as_mut_array>(&mut self) -> &mut V; 243 | 244 | /// Clone `&[T]` to `[T; n]`. 245 | /// 246 | /// This is provided because `.as_array().clone()` tends to cause trouble for 247 | /// type inference. 248 | fn to_array>(&self) -> V where V: Clone 249 | { self.as_array::().clone() } 250 | } 251 | 252 | impl SliceFlatExt for [V] { 253 | fn flat(&self) -> &[V::Element] { 254 | let new_len = checked_compute_flattened_len::(self.len()); 255 | 256 | // UNSAFETY: (::core::slice::from_raw_parts) 257 | // - pointer must be non-null (even for zero-length) 258 | // - pointer must be aligned 259 | // - pointer must be valid for given size 260 | // - lifetimes are unchecked 261 | unsafe { 262 | slice::from_raw_parts( 263 | self.as_ptr() as *const _, 264 | new_len, 265 | ) 266 | } 267 | } 268 | 269 | fn flat_mut(&mut self) -> &mut [V::Element] { 270 | let new_len = checked_compute_flattened_len::(self.len()); 271 | 272 | // UNSAFETY: (::core::slice::from_raw_parts_mut) 273 | // - pointer must be non-null (even for zero-length) 274 | // - pointer must be aligned 275 | // - pointer must be valid for given size 276 | // - lifetimes are unchecked 277 | // - aliasing guarantees of &mut are unchecked 278 | unsafe { 279 | slice::from_raw_parts_mut( 280 | self.as_mut_ptr() as *mut _, 281 | new_len, 282 | ) 283 | } 284 | } 285 | } 286 | 287 | #[inline(always)] 288 | fn checked_compute_flattened_len(len: usize) -> usize { 289 | validate_alignment_and_size::(); 290 | 291 | if core::mem::size_of::() == 0 { 292 | usize::checked_mul(len, V::LEN) 293 | .expect("overflow when computing length of flattened array") 294 | } else { 295 | // Given that each value occupies at least one byte, the mere existence 296 | // of the slice ensures that this will not overflow. 297 | len * V::LEN 298 | } 299 | } 300 | 301 | impl SliceNestExt for [T] { 302 | fn nest>(&self) -> &[V] { 303 | let new_len = checked_compute_nested_len::(self.len(), "&"); 304 | 305 | // UNSAFETY: (core::slice::from_raw_parts) 306 | // - pointer must be non-null (even for zero-length) 307 | // - pointer must be aligned 308 | // - pointer must be valid for given size 309 | // - lifetimes are unchecked 310 | unsafe { slice::from_raw_parts( 311 | self.as_ptr() as *const _, 312 | new_len, 313 | )} 314 | } 315 | 316 | fn nest_mut>(&mut self) -> &mut [V] { 317 | let new_len = checked_compute_nested_len::(self.len(), "&mut "); 318 | 319 | // UNSAFETY: (core::slice::from_raw_parts_mut) 320 | // - pointer must be non-null (even for zero-length) 321 | // - pointer must be aligned 322 | // - pointer must be valid for given size 323 | // - lifetimes are unchecked 324 | // - aliasing guarantees of &mut are unchecked 325 | unsafe { slice::from_raw_parts_mut( 326 | self.as_mut_ptr() as *mut _, 327 | new_len, 328 | )} 329 | } 330 | } 331 | 332 | #[inline(always)] 333 | fn checked_compute_nested_len(len: usize, prefix: &str) -> usize { 334 | validate_alignment_and_size::(); 335 | assert_ne!( 336 | 0, V::LEN, 337 | "cannot nest arrays of length 0", 338 | ); 339 | assert_eq!( 340 | 0, len % V::LEN, 341 | "cannot view slice of length {} as {}[[_; {}]]", 342 | len, prefix, V::LEN, 343 | ); 344 | 345 | len / V::LEN 346 | } 347 | 348 | impl SliceArrayExt for [T] { 349 | fn as_array>(&self) -> &V { 350 | validate_as_array_assumptions::(self.len(), "&"); 351 | 352 | // &self.nest()[0] // <-- would not work for V::LEN = 0 353 | 354 | // UNSAFETY: (<*const T>::as_ref) 355 | // - pointer must be aligned 356 | // - pointer must be valid for given size 357 | // - lifetimes are unchecked 358 | unsafe { (self.as_ptr() as *const V).as_ref().unwrap() } 359 | } 360 | 361 | fn as_mut_array>(&mut self) -> &mut V { 362 | validate_as_array_assumptions::(self.len(), "&mut "); 363 | 364 | // &mut self.nest_mut()[0] // <-- would not work for V::LEN = 0 365 | 366 | // UNSAFETY: (<*mut T>::as_mut) 367 | // - pointer must be aligned 368 | // - pointer must be valid for given size 369 | // - lifetimes are unchecked 370 | // - aliasing guarantees of &mut are unchecked 371 | unsafe { (self.as_mut_ptr() as *mut V).as_mut().unwrap() } 372 | } 373 | } 374 | 375 | #[inline(always)] 376 | fn validate_as_array_assumptions(len: usize, prefix: &str) { 377 | validate_alignment_and_size::(); 378 | assert_eq!( 379 | len, V::LEN, 380 | "cannot view slice of length {} as {}[_; {}]", 381 | len, prefix, V::LEN, 382 | ); 383 | } 384 | 385 | #[cfg(test)] 386 | mod tests { 387 | pub use super::prelude::*; 388 | 389 | #[test] 390 | fn inference_lattice() { 391 | // Checks that chaining nest().nest() or nest().as_array() 392 | // can be done without explicit annotations on the first method call. 393 | let v: &mut [()] = &mut [(); 9]; 394 | 395 | { let _: &[[(); 3]; 3] = v.nest().as_array(); } 396 | { let _: &[[[(); 3]; 3]] = v.nest().nest(); } 397 | { let _: &mut [[(); 3]; 3] = v.nest_mut().as_mut_array(); } 398 | { let _: &mut [[[(); 3]; 3]] = v.nest_mut().nest_mut(); } 399 | { let _: [[(); 3]; 3] = v.nest().to_array(); } 400 | 401 | #[cfg(feature = "std")] 402 | { let _: Vec<[(); 3]> = v.nest().to_vec(); } 403 | } 404 | 405 | #[test] 406 | fn test_flat_zst_and_non_zst() { 407 | let v: &mut [_] = &mut [[(); 234]; 456]; 408 | assert_eq!(v.flat(), &[(); 234*456] as &[()]); 409 | assert_eq!(v.flat_mut(), &[(); 234*456] as &[()]); 410 | 411 | let v: &mut [_] = &mut [[1; 23]; 45]; 412 | assert_eq!(v.flat(), &[1; 23*45] as &[i32]); 413 | assert_eq!(v.flat_mut(), &[1; 23*45] as &[i32]); 414 | } 415 | 416 | #[test] 417 | fn test_flat_zero() { 418 | let v: &mut [[(); 0]] = &mut [[(); 0]; 6]; 419 | assert_eq!(v.flat(), &[] as &[()]); 420 | assert_eq!(v.flat_mut(), &[] as &[()]); 421 | } 422 | 423 | #[test] 424 | fn test_array_zero() { 425 | let v: &mut [[(); 0]] = &mut [[], [], [], []]; 426 | assert_eq!(v.flat(), &[] as &[()]); 427 | assert_eq!(v.flat_mut(), &[] as &[()]); 428 | } 429 | 430 | mod failures { 431 | use super::super::*; 432 | 433 | // Two usizes that overflow when multiplied together. 434 | const BIG_1: usize = 0x30; 435 | const BIG_2: usize = usize::MAX >> 4; 436 | 437 | #[test] 438 | #[should_panic(expected = "overflow when computing length")] 439 | fn flat_zst_overflow() { 440 | let v: &[_] = &[[(); BIG_1]; BIG_2]; 441 | let _: &[()] = v.flat(); 442 | } 443 | 444 | #[test] 445 | #[should_panic(expected = "overflow when computing length")] 446 | fn flat_mut_zst_overflow() { 447 | let v: &mut [_] = &mut [[(); BIG_1]; BIG_2]; 448 | let _: &mut [()] = v.flat_mut(); 449 | } 450 | 451 | #[test] 452 | #[should_panic(expected = "cannot view slice of length 8")] 453 | fn nest_not_multiple() { 454 | let v: &[_] = &[(); 8]; 455 | let _: &[[(); 3]] = v.nest(); 456 | } 457 | 458 | #[test] 459 | #[should_panic(expected = "cannot view slice of length 8")] 460 | fn nest_mut_not_multiple() { 461 | let v: &mut [_] = &mut [(); 8]; 462 | let _: &mut [[(); 3]] = v.nest_mut(); 463 | } 464 | 465 | #[test] 466 | #[should_panic(expected = "cannot nest arrays of length 0")] 467 | fn nest_zero() { 468 | let v: &[_] = &[(); 0]; 469 | let _: &[[(); 0]] = v.nest(); 470 | } 471 | 472 | #[test] 473 | #[should_panic(expected = "cannot nest arrays of length 0")] 474 | fn nest_mut_zero() { 475 | let v: &mut [_] = &mut [(); 0]; 476 | let _: &mut [[(); 0]] = v.nest_mut(); 477 | } 478 | 479 | // bad array size tests; 480 | // we try converting slices of length 1 or 6 into a length 3 array. 481 | // These sizes were chosen to catch accidental acceptance in 482 | // the case of sizes that divide evenly 483 | #[test] 484 | #[should_panic(expected = "cannot view slice of length 1")] 485 | fn as_array_too_small() { 486 | let v: &[_] = &[(); 1]; 487 | let _: &[(); 3] = v.as_array(); 488 | } 489 | 490 | #[test] 491 | #[should_panic(expected = "cannot view slice of length 6")] 492 | fn as_array_too_large() { 493 | let v: &[_] = &[(); 6]; 494 | let _: &[(); 3] = v.as_array(); 495 | } 496 | 497 | #[test] 498 | #[should_panic(expected = "cannot view slice of length 6")] 499 | fn as_array_bad_zero() { 500 | let v: &[_] = &[(); 6]; 501 | let _: &[(); 0] = v.as_array(); 502 | } 503 | 504 | #[test] 505 | #[should_panic(expected = "cannot view slice of length 1")] 506 | fn as_mut_array_too_small() { 507 | let v: &mut [_] = &mut [(); 1]; 508 | let _: &mut [(); 3] = v.as_mut_array(); 509 | } 510 | 511 | #[test] 512 | #[should_panic(expected = "cannot view slice of length 6")] 513 | fn as_mut_array_too_large() { 514 | let v: &mut [_] = &mut [(); 6]; 515 | let _: &mut [(); 3] = v.as_mut_array(); 516 | } 517 | 518 | #[test] 519 | #[should_panic(expected = "cannot view slice of length 6")] 520 | fn as_mut_array_bad_zero() { 521 | let v: &mut [_] = &mut [(); 6]; 522 | let _: &[(); 0] = v.as_mut_array(); 523 | } 524 | } 525 | 526 | mod dox { 527 | #[test] 528 | fn test_readme_version() { 529 | version_sync::assert_markdown_deps_updated!("README.md"); 530 | } 531 | 532 | #[test] 533 | fn test_html_root_url() { 534 | version_sync::assert_html_root_url_updated!("lib.rs"); 535 | } 536 | } 537 | } 538 | --------------------------------------------------------------------------------