├── .github └── workflows │ └── byte-slice-cast.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src └── lib.rs /.github/workflows/byte-slice-cast.yml: -------------------------------------------------------------------------------- 1 | name: byte-slice-cast 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | rustfmt-clippy: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Install stable 20 | uses: actions-rs/toolchain@v1 21 | with: 22 | profile: minimal 23 | toolchain: stable 24 | override: true 25 | components: clippy, rustfmt 26 | 27 | - name: Run rustfmt 28 | uses: actions-rs/cargo@v1 29 | with: 30 | command: fmt 31 | args: -- --check 32 | 33 | - name: Run clippy 34 | uses: actions-rs/clippy-check@v1 35 | with: 36 | token: ${{ secrets.GITHUB_TOKEN }} 37 | args: --all-targets --all-features -- -D warnings 38 | 39 | ubuntu-tests: 40 | 41 | runs-on: ubuntu-latest 42 | 43 | strategy: 44 | matrix: 45 | toolchain: [stable, beta, nightly] 46 | 47 | steps: 48 | - uses: actions/checkout@v2 49 | 50 | - name: Install ${{ matrix.toolchain }} 51 | uses: actions-rs/toolchain@v1 52 | with: 53 | profile: minimal 54 | toolchain: ${{ matrix.toolchain }} 55 | override: true 56 | 57 | - name: Run tests 58 | run: | 59 | cargo test 60 | 61 | - name: Run tests --no-default-features 62 | run: | 63 | cargo test --no-default-features 64 | -------------------------------------------------------------------------------- /.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 | specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field). 7 | 8 | ## [1.2.3] - 2025-03-03 9 | ### Changed 10 | - Fix tests for Rust 1.81. 11 | - Declare Rust 1.51 as MSRV. 12 | 13 | ## [1.2.2] - 2022-10-28 14 | ### Changed 15 | - Fix a couple of clippy warnings in the tests. 16 | 17 | ## [1.2.1] - 2022-02-25 18 | ### Changed 19 | - Make trait methods `#[inline]`. This allows the compiler to make the call a 20 | no-op in many cases. 21 | 22 | ## [1.2.0] - 2021-10-19 23 | ### Added 24 | - Trait impls for converting between `&[[T; N]]` and `&[u8]` for specific `T`. 25 | 26 | ## [1.1.0] - 2021-09-16 27 | ### Added 28 | - `ToByteSlice` and `ToMutByteSlice` impl for `&[()]`. This always produces an 29 | empty byte slice. 30 | 31 | ## [1.0.0] - 2020-10-13 32 | ### Removed 33 | - Support for casting between `Vec` and `Vec`. This was actually 34 | unsound as the alloc trait requires that memory is deallocated with exactly 35 | the same alignment as it was allocated with. 36 | 37 | ### Fixed 38 | - `usize` tests on 16/32 bit architectures. 39 | 40 | ### Changed 41 | - Various documentation improvements. 42 | 43 | ## [0.3.5] - 2019-12-22 44 | ### Changed 45 | - Improve documentation and examples 46 | 47 | ### Fixed 48 | - Fix running of tests on 16/32 bit architectures 49 | 50 | ## [0.3.4] - 2019-11-11 51 | ### Added 52 | - Support for casting between `Vec` and `Vec` 53 | 54 | ## [0.3.3] - 2019-11-02 55 | ### Added 56 | - Support for `usize` and `isize` 57 | 58 | ## [0.3.2] - 2019-07-26 59 | ### Changed 60 | - Add `no_std` support 61 | - Migrate to 2018 edition 62 | 63 | ## [0.3.1] - 2019-06-05 64 | ### Fixed 65 | - Casting of empty slices works correctly now instead of failing with an 66 | alignment mismatch error. 67 | 68 | ## [0.3.0] - 2019-05-11 69 | ### Added 70 | - The `Error` type now implements `Clone`. 71 | 72 | ### Changed 73 | - `AsByteSlice::as_byte_slice` and `ToByteSlice::to_byte_slice` were changed 74 | to always return `&[u8]` instead of `Result<&[u8], Error>`. 75 | - `AsMutByteSlice::as_mut_byte_slice` and `ToMutByteSlice::to_mut_byte_slice` 76 | were changed to always return `&mut [u8]` instead of `Result<&mut [u8], 77 | Error>`. 78 | - The `Display` impl for `Error` now produces more detailed error messages. 79 | - The variants of the `Error` enum were renamed. 80 | 81 | ## [0.2.0] - 2018-06-01 82 | ### Changed 83 | - Major refactoring of how the traits work. It is now possible to work 84 | directly on `AsRef<[T]>` and `AsMut<[T]>`, e.g. on `Vec` and `Box<[T]>`. 85 | 86 | ### Added 87 | - Trait impls for i128 and u128. 88 | 89 | ## [0.1.0] - 2017-08-14 90 | - Initial release of the `byte-slice-cast` crate. 91 | 92 | [Unreleased]: https://github.com/sdroege/byte-slice-cast/compare/1.2.3...HEAD 93 | [1.2.3]: https://github.com/sdroege/byte-slice-cast/compare/1.2.2...1.2.3 94 | [1.2.2]: https://github.com/sdroege/byte-slice-cast/compare/1.2.1...1.2.2 95 | [1.2.1]: https://github.com/sdroege/byte-slice-cast/compare/1.2.0...1.2.1 96 | [1.2.0]: https://github.com/sdroege/byte-slice-cast/compare/1.1.0...1.2.0 97 | [1.1.0]: https://github.com/sdroege/byte-slice-cast/compare/1.0.0...1.1.0 98 | [1.0.0]: https://github.com/sdroege/byte-slice-cast/compare/0.3.5...1.0.0 99 | [0.3.5]: https://github.com/sdroege/byte-slice-cast/compare/0.3.4...0.3.5 100 | [0.3.4]: https://github.com/sdroege/byte-slice-cast/compare/0.3.3...0.3.4 101 | [0.3.3]: https://github.com/sdroege/byte-slice-cast/compare/0.3.2...0.3.3 102 | [0.3.2]: https://github.com/sdroege/byte-slice-cast/compare/0.3.1...0.3.2 103 | [0.3.1]: https://github.com/sdroege/byte-slice-cast/compare/0.3.0...0.3.1 104 | [0.3.0]: https://github.com/sdroege/byte-slice-cast/compare/0.2.0...0.3.0 105 | [0.2.0]: https://github.com/sdroege/byte-slice-cast/compare/0.1.0...0.2.0 106 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "byte-slice-cast" 3 | version = "1.2.3" 4 | authors = ["Sebastian Dröge "] 5 | description = "Safely cast bytes slices from/to slices of built-in fundamental numeric types" 6 | keywords = ["no_std"] 7 | repository = "https://github.com/sdroege/bytes-num-slice-cast" 8 | license = "MIT" 9 | readme = "README.md" 10 | include = [ 11 | "src/lib.rs", 12 | "Cargo.toml", 13 | "LICENSE", 14 | "README.md", 15 | "CHANGELOG.md", 16 | ] 17 | edition = "2018" 18 | rust-version = "1.51.0" 19 | 20 | [dependencies] 21 | 22 | [features] 23 | default = ["std"] 24 | std = [] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Sebastian Dröge . 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # byte-slice-cast [![crates.io](https://img.shields.io/crates/v/byte-slice-cast.svg)](https://crates.io/crates/byte-slice-cast) [![Actions Status](https://github.com/sdroege/byte-slice-cast/workflows/byte-slice-cast/badge.svg)](https://github.com/sdroege/byte-slice-cast/actions) [![docs.rs](https://docs.rs/byte-slice-cast/badge.svg)](https://docs.rs/byte-slice-cast) 2 | 3 | Safely cast between byte slices and slices of another built-in fundamental number type. 4 | 5 | ## LICENSE 6 | 7 | byte-slice-cast is licensed under the MIT license ([LICENSE](LICENSE) or 8 | http://opensource.org/licenses/MIT). 9 | 10 | ## Contribution 11 | 12 | Any kinds of contributions are welcome as a pull request. 13 | 14 | Unless you explicitly state otherwise, any contribution intentionally 15 | submitted for inclusion in byte-slice-cast by you shall be licensed under the 16 | MIT license as above, without any additional terms or conditions. 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017,2018 Sebastian Dröge 2 | // 3 | // Licensed under the MIT license, see the LICENSE file or 4 | 5 | #![cfg_attr(not(feature = "std"), no_std)] 6 | #![allow(clippy::missing_safety_doc)] 7 | 8 | //! Safely cast bytes slices from/to slices of built-in fundamental numeric types. 9 | //! 10 | //! The provided traits here allow safe casting between byte slices and slices of fundamental 11 | //! numeric types, like integers and floating point numbers. During casting, checks are performed 12 | //! to ensure that the output slice is safe to use: the input slice must be properly aligned for 13 | //! the output type and contain an integer number of values. 14 | //! 15 | //! Instead of working only on slices, the traits work on `AsRef<[T]>` in the immutable case and on 16 | //! `AsMut<[T]>` for the mutable case. As such, it is possible to directly work on e.g. `Vec` 17 | //! and `Box<[T]>` too. 18 | //! 19 | //! The content of the output slice will be bitwise equivalent to the input slice, as such extra 20 | //! care has to be taken with regard to endianness. 21 | //! 22 | //! # Example with slices 23 | //! ``` 24 | //! # extern crate byte_slice_cast; 25 | //! # fn main() { 26 | //! use byte_slice_cast::*; 27 | //! 28 | //! let slice = [0x0102u16, 0x0304u16, 0x0506u16]; 29 | //! 30 | //! let converted_slice = slice.as_byte_slice(); 31 | //! 32 | //! if cfg!(target_endian = "big") { 33 | //! assert_eq!(converted_slice, &[1, 2, 3, 4, 5, 6]); 34 | //! } else { 35 | //! assert_eq!(converted_slice, &[2, 1, 4, 3, 6, 5]); 36 | //! } 37 | //! 38 | //! let converted_back_slice = converted_slice.as_slice_of::().unwrap(); 39 | //! 40 | //! assert_eq!(converted_back_slice, &slice); 41 | //! # } 42 | //! ``` 43 | //! 44 | //! # Example with mutable slices 45 | //! ``` 46 | //! # extern crate byte_slice_cast; 47 | //! # fn main() { 48 | //! use byte_slice_cast::*; 49 | //! 50 | //! let mut slice = [0u32; 1]; 51 | //! let mut converted_slice = slice.as_mut_byte_slice(); 52 | //! converted_slice.copy_from_slice(&[0x12, 0x34, 0x56, 0x78]); 53 | //! 54 | //! let mut converted_slice = converted_slice.as_mut_slice_of::().unwrap(); 55 | //! converted_slice[0] = 0xffff; 56 | //! 57 | //! if cfg!(target_endian = "big") { 58 | //! assert_eq!(&slice, &[0xffff5678]); 59 | //! } else { 60 | //! assert_eq!(&slice, &[0x7856ffff]); 61 | //! } 62 | //! 63 | //! # } 64 | //! ``` 65 | 66 | use core::{fmt, mem, slice}; 67 | 68 | #[cfg(feature = "std")] 69 | use std::error::Error as StdError; 70 | 71 | /// Possible errors during slice conversion. 72 | #[derive(Clone, Debug, PartialEq, Eq)] 73 | pub enum Error { 74 | /// The input slice is not properly aligned for the 75 | /// output data type. E.g. for an `u32` output slice 76 | /// the memory must be 4-byte aligned. 77 | AlignmentMismatch { 78 | dst_type: &'static str, 79 | dst_minimum_alignment: usize, 80 | }, 81 | /// A non-integer number of values from the output 82 | /// type would be in the output slice. 83 | LengthMismatch { 84 | dst_type: &'static str, 85 | src_slice_size: usize, 86 | dst_type_size: usize, 87 | }, 88 | } 89 | 90 | impl fmt::Display for Error { 91 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 92 | match self { 93 | Error::AlignmentMismatch { 94 | dst_type, 95 | dst_minimum_alignment, 96 | } => { 97 | write!( 98 | f, 99 | "cannot cast a &[u8] into a &[{}]: the slice's address is not divisible by the minimum alignment ({}) of {}", 100 | dst_type, 101 | dst_minimum_alignment, 102 | dst_type 103 | )?; 104 | } 105 | Error::LengthMismatch { 106 | dst_type, 107 | src_slice_size, 108 | dst_type_size, 109 | } => { 110 | write!( 111 | f, 112 | "cannot cast a &[u8] into a &[{}]: the size ({}) of the slice is not divisible by the size ({}) of {}", 113 | dst_type, 114 | src_slice_size, 115 | dst_type_size, 116 | dst_type 117 | )?; 118 | } 119 | } 120 | 121 | Ok(()) 122 | } 123 | } 124 | 125 | trait TypeName { 126 | const TYPE_NAME: &'static str; 127 | } 128 | 129 | #[cfg(feature = "std")] 130 | impl StdError for Error { 131 | fn description(&self) -> &str { 132 | use self::Error::*; 133 | 134 | match *self { 135 | AlignmentMismatch { .. } => "Alignment Mismatch", 136 | LengthMismatch { .. } => "Length Mismatch", 137 | } 138 | } 139 | } 140 | 141 | fn check_alignment(data: &T) -> Result 142 | where 143 | U: TypeName, 144 | T: AsRef<[u8]> + ?Sized, 145 | { 146 | let alignment = mem::align_of::(); 147 | 148 | if (data.as_ref().as_ptr() as usize) % alignment != 0 { 149 | let err = Error::AlignmentMismatch { 150 | dst_type: U::TYPE_NAME, 151 | dst_minimum_alignment: alignment, 152 | }; 153 | return Err(err); 154 | } 155 | Ok(alignment) 156 | } 157 | 158 | fn check_length(data: &T) -> Result 159 | where 160 | U: TypeName, 161 | T: AsRef<[u8]> + ?Sized, 162 | { 163 | let size_out = mem::size_of::(); 164 | if data.as_ref().len() % size_out != 0 { 165 | let err = Error::LengthMismatch { 166 | dst_type: U::TYPE_NAME, 167 | src_slice_size: data.as_ref().len(), 168 | dst_type_size: size_out, 169 | }; 170 | return Err(err); 171 | } 172 | Ok(size_out) 173 | } 174 | 175 | fn check_constraints(data: &[u8]) -> Result 176 | where 177 | U: TypeName, 178 | { 179 | if data.is_empty() { 180 | return Ok(0); 181 | } 182 | 183 | check_alignment::<[u8], U>(data)?; 184 | let size_out = check_length::<[u8], U>(data)?; 185 | 186 | Ok(data.len() / size_out) 187 | } 188 | 189 | macro_rules! impl_trait( 190 | ($to:ty) => { 191 | impl TypeName for $to { 192 | const TYPE_NAME: &'static str = stringify!($to); 193 | } 194 | 195 | unsafe impl FromByteSlice for $to { 196 | #[inline] 197 | fn from_byte_slice + ?Sized>(slice: &T) -> Result<&[$to], Error> { 198 | let slice = slice.as_ref(); 199 | let len = check_constraints::<$to>(slice)?; 200 | 201 | // Need to handle the empty case separately as even an empty slices 202 | // must have a correctly aligned data pointer 203 | if len == 0 { 204 | Ok(&[]) 205 | } else { 206 | #[allow(clippy::cast_ptr_alignment)] 207 | unsafe { 208 | Ok(slice::from_raw_parts(slice.as_ptr() as *const $to, len)) 209 | } 210 | } 211 | } 212 | 213 | #[inline] 214 | fn from_mut_byte_slice + ?Sized>(slice: &mut T) -> Result<&mut [$to], Error> { 215 | let slice = slice.as_mut(); 216 | let len = check_constraints::<$to>(slice)?; 217 | 218 | // Need to handle the empty case separately as even an empty slices 219 | // must have a correctly aligned data pointer 220 | if len == 0 { 221 | Ok(&mut []) 222 | } else { 223 | #[allow(clippy::cast_ptr_alignment)] 224 | unsafe { 225 | Ok(slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut $to, len)) 226 | } 227 | } 228 | } 229 | } 230 | 231 | unsafe impl ToByteSlice for $to { 232 | #[inline] 233 | fn to_byte_slice + ?Sized>(slice: &T) -> &[u8] { 234 | let slice = slice.as_ref(); 235 | let len = slice.len() * mem::size_of::<$to>(); 236 | unsafe { 237 | slice::from_raw_parts(slice.as_ptr() as *const u8, len) 238 | } 239 | } 240 | } 241 | 242 | unsafe impl ToMutByteSlice for $to { 243 | #[inline] 244 | fn to_mut_byte_slice + ?Sized>(slice: &mut T) -> &mut [u8] { 245 | let slice = slice.as_mut(); 246 | let len = slice.len() * mem::size_of::<$to>(); 247 | unsafe { 248 | slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, len) 249 | } 250 | } 251 | } 252 | }; 253 | ); 254 | 255 | macro_rules! impl_trait_array ( 256 | ($to:ty) => { 257 | impl TypeName for [$to; N] { 258 | const TYPE_NAME: &'static str = stringify!([$to; N]); 259 | } 260 | 261 | unsafe impl FromByteSlice for [$to; N] { 262 | #[inline] 263 | fn from_byte_slice + ?Sized>(slice: &T) -> Result<&[[$to; N]], Error> { 264 | let slice = slice.as_ref(); 265 | let len = check_constraints::<[$to; N]>(slice)?; 266 | 267 | // Need to handle the empty case separately as even an empty slices 268 | // must have a correctly aligned data pointer 269 | if len == 0 { 270 | Ok(&[]) 271 | } else { 272 | #[allow(clippy::cast_ptr_alignment)] 273 | unsafe { 274 | Ok(slice::from_raw_parts(slice.as_ptr() as *const [$to; N], len)) 275 | } 276 | } 277 | } 278 | 279 | #[inline] 280 | fn from_mut_byte_slice + ?Sized>(slice: &mut T) -> Result<&mut [[$to; N]], Error> { 281 | let slice = slice.as_mut(); 282 | let len = check_constraints::<[$to; N]>(slice)?; 283 | 284 | // Need to handle the empty case separately as even an empty slices 285 | // must have a correctly aligned data pointer 286 | if len == 0 { 287 | Ok(&mut []) 288 | } else { 289 | #[allow(clippy::cast_ptr_alignment)] 290 | unsafe { 291 | Ok(slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut [$to; N], len)) 292 | } 293 | } 294 | } 295 | } 296 | 297 | unsafe impl ToByteSlice for [$to; N] { 298 | #[inline] 299 | fn to_byte_slice + ?Sized>(slice: &T) -> &[u8] { 300 | let slice = slice.as_ref(); 301 | let len = slice.len() * mem::size_of::<[$to; N]>(); 302 | unsafe { 303 | slice::from_raw_parts(slice.as_ptr() as *const u8, len) 304 | } 305 | } 306 | } 307 | 308 | unsafe impl ToMutByteSlice for [$to; N] { 309 | #[inline] 310 | fn to_mut_byte_slice + ?Sized>(slice: &mut T) -> &mut [u8] { 311 | let slice = slice.as_mut(); 312 | let len = slice.len() * mem::size_of::<[$to; N]>(); 313 | unsafe { 314 | slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, len) 315 | } 316 | } 317 | } 318 | }; 319 | ); 320 | 321 | /// Trait for converting from a byte slice to a slice of a fundamental, built-in numeric type. 322 | /// 323 | /// This trait is an implementation detail. Use the [`AsSliceOf`] and [`AsMutSliceOf`] traits. 324 | /// 325 | /// [`AsSliceOf`]: trait.AsSliceOf.html 326 | /// [`AsMutSliceOf`]: trait.AsMutSliceOf.html 327 | pub unsafe trait FromByteSlice 328 | where 329 | Self: Sized, 330 | { 331 | /// Convert from an immutable byte slice to a immutable slice of a fundamental, built-in 332 | /// numeric type 333 | fn from_byte_slice + ?Sized>(slice: &T) -> Result<&[Self], Error>; 334 | /// Convert from an mutable byte slice to a mutable slice of a fundamental, built-in numeric 335 | /// type 336 | fn from_mut_byte_slice + ?Sized>(slice: &mut T) -> Result<&mut [Self], Error>; 337 | } 338 | 339 | /// Trait for converting from an immutable slice of a fundamental, built-in numeric type to an 340 | /// immutable byte slice. 341 | /// 342 | /// This trait is an implementation detail. Use the [`AsByteSlice`] trait. 343 | /// 344 | /// [`AsByteSlice`]: trait.AsByteSlice.html 345 | pub unsafe trait ToByteSlice 346 | where 347 | Self: Sized, 348 | { 349 | /// Convert from an immutable slice of a fundamental, built-in numeric type to an immutable 350 | /// byte slice 351 | fn to_byte_slice + ?Sized>(slice: &T) -> &[u8]; 352 | } 353 | 354 | /// Trait for converting from a mutable slice of a fundamental, built-in numeric type to a mutable 355 | /// byte slice. 356 | /// 357 | /// This trait is an implementation detail. Use the [`AsMutByteSlice`] trait. 358 | /// 359 | /// [`AsMutByteSlice`]: trait.AsMutByteSlice.html 360 | pub unsafe trait ToMutByteSlice 361 | where 362 | Self: Sized, 363 | { 364 | /// Convert from a mutable slice of a fundamental, built-in numeric type to a mutable byte 365 | /// slice 366 | fn to_mut_byte_slice + ?Sized>(slice: &mut T) -> &mut [u8]; 367 | } 368 | 369 | /// Trait for converting from a byte slice to a slice of a fundamental, built-in numeric type. 370 | /// 371 | /// # Example 372 | /// ```no_run 373 | /// # extern crate byte_slice_cast; 374 | /// # fn main() { 375 | /// use byte_slice_cast::*; 376 | /// 377 | /// let slice = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]; 378 | /// let converted_slice = slice.as_slice_of::().unwrap(); 379 | /// 380 | /// if cfg!(target_endian = "big") { 381 | /// assert_eq!(converted_slice, &[0x0102, 0x0304, 0x0506]); 382 | /// } else { 383 | /// assert_eq!(converted_slice, &[0x0201, 0x0403, 0x0605]); 384 | /// } 385 | /// # } 386 | /// ``` 387 | pub trait AsSliceOf { 388 | fn as_slice_of(&self) -> Result<&[T], Error>; 389 | } 390 | 391 | impl + ?Sized> AsSliceOf for U { 392 | #[inline] 393 | fn as_slice_of(&self) -> Result<&[T], Error> { 394 | FromByteSlice::from_byte_slice(self) 395 | } 396 | } 397 | 398 | /// Trait for converting from a mutable byte slice to a mutable slice of a fundamental, built-in 399 | /// numeric type. 400 | /// 401 | /// # Example 402 | /// ```no_run 403 | /// # extern crate byte_slice_cast; 404 | /// # fn main() { 405 | /// use byte_slice_cast::*; 406 | /// 407 | /// let mut slice = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]; 408 | /// let converted_slice = slice.as_mut_slice_of::().unwrap(); 409 | /// 410 | /// if cfg!(target_endian = "big") { 411 | /// assert_eq!(converted_slice, &[0x0102, 0x0304, 0x0506]); 412 | /// } else { 413 | /// assert_eq!(converted_slice, &[0x0201, 0x0403, 0x0605]); 414 | /// } 415 | /// # } 416 | /// ``` 417 | pub trait AsMutSliceOf { 418 | fn as_mut_slice_of(&mut self) -> Result<&mut [T], Error>; 419 | } 420 | 421 | impl + ?Sized> AsMutSliceOf for U { 422 | #[inline] 423 | fn as_mut_slice_of(&mut self) -> Result<&mut [T], Error> { 424 | FromByteSlice::from_mut_byte_slice(self) 425 | } 426 | } 427 | 428 | /// Trait for converting from an immutable slice of a fundamental, built-in numeric type to an 429 | /// immutable byte slice. 430 | /// 431 | /// # Example 432 | /// ```no_run 433 | /// # extern crate byte_slice_cast; 434 | /// # fn main() { 435 | /// use byte_slice_cast::*; 436 | /// 437 | /// let slice: [u16; 3] = [0x0102, 0x0304, 0x0506]; 438 | /// let converted_slice = slice.as_byte_slice(); 439 | /// 440 | /// if cfg!(target_endian = "big") { 441 | /// assert_eq!(converted_slice, &[1u8, 2u8, 3u8, 4u8, 5u8, 6u8]); 442 | /// } else { 443 | /// assert_eq!(converted_slice, &[2u8, 1u8, 4u8, 3u8, 6u8, 5u8]); 444 | /// } 445 | /// # } 446 | /// ``` 447 | pub trait AsByteSlice { 448 | fn as_byte_slice(&self) -> &[u8]; 449 | } 450 | 451 | impl + ?Sized> AsByteSlice for U { 452 | #[inline] 453 | fn as_byte_slice(&self) -> &[u8] { 454 | ToByteSlice::to_byte_slice(self) 455 | } 456 | } 457 | 458 | /// Trait for converting from a mutable slice of a fundamental, built-in numeric type to a mutable 459 | /// byte slice. 460 | /// 461 | /// # Example 462 | /// ```no_run 463 | /// # extern crate byte_slice_cast; 464 | /// # fn main() { 465 | /// use byte_slice_cast::*; 466 | /// 467 | /// let mut slice: [u16; 3] = [0x0102, 0x0304, 0x0506]; 468 | /// let converted_slice = slice.as_mut_byte_slice(); 469 | /// 470 | /// if cfg!(target_endian = "big") { 471 | /// assert_eq!(converted_slice, &mut [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]); 472 | /// } else { 473 | /// assert_eq!(converted_slice, &mut [2u8, 1u8, 4u8, 3u8, 6u8, 5u8]); 474 | /// } 475 | /// # } 476 | /// ``` 477 | pub trait AsMutByteSlice { 478 | fn as_mut_byte_slice(&mut self) -> &mut [u8]; 479 | } 480 | 481 | impl + ?Sized> AsMutByteSlice for U { 482 | #[inline] 483 | fn as_mut_byte_slice(&mut self) -> &mut [u8] { 484 | ToMutByteSlice::to_mut_byte_slice(self) 485 | } 486 | } 487 | 488 | impl_trait!(u8); 489 | impl_trait!(u16); 490 | impl_trait!(u32); 491 | impl_trait!(u64); 492 | impl_trait!(u128); 493 | impl_trait!(i8); 494 | impl_trait!(i16); 495 | impl_trait!(i32); 496 | impl_trait!(i64); 497 | impl_trait!(i128); 498 | impl_trait!(f32); 499 | impl_trait!(f64); 500 | impl_trait!(usize); 501 | impl_trait!(isize); 502 | 503 | impl_trait_array!(u8); 504 | impl_trait_array!(u16); 505 | impl_trait_array!(u32); 506 | impl_trait_array!(u64); 507 | impl_trait_array!(u128); 508 | impl_trait_array!(i8); 509 | impl_trait_array!(i16); 510 | impl_trait_array!(i32); 511 | impl_trait_array!(i64); 512 | impl_trait_array!(i128); 513 | impl_trait_array!(f32); 514 | impl_trait_array!(f64); 515 | impl_trait_array!(usize); 516 | impl_trait_array!(isize); 517 | 518 | impl TypeName for () { 519 | const TYPE_NAME: &'static str = "()"; 520 | } 521 | 522 | unsafe impl ToByteSlice for () { 523 | #[inline] 524 | fn to_byte_slice + ?Sized>(_: &T) -> &[u8] { 525 | &[] 526 | } 527 | } 528 | 529 | unsafe impl ToMutByteSlice for () { 530 | #[inline] 531 | fn to_mut_byte_slice + ?Sized>(_: &mut T) -> &mut [u8] { 532 | &mut [] 533 | } 534 | } 535 | 536 | #[cfg(test)] 537 | mod tests { 538 | use super::*; 539 | 540 | #[test] 541 | fn u8() { 542 | let input: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; 543 | 544 | let output: &[u8] = input.as_slice_of::().unwrap(); 545 | assert_eq!(&input, output); 546 | 547 | let output2: &[u8] = input.as_byte_slice(); 548 | assert_eq!(&input, output2); 549 | } 550 | 551 | #[test] 552 | fn u16() { 553 | let slice: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; 554 | let bytes = slice.as_byte_slice(); 555 | 556 | if cfg!(target_endian = "big") { 557 | assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]); 558 | } else { 559 | assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]); 560 | } 561 | 562 | assert_eq!( 563 | (bytes[1..]).as_slice_of::(), 564 | Err(Error::AlignmentMismatch { 565 | dst_type: "u16", 566 | dst_minimum_alignment: mem::align_of::() 567 | }) 568 | ); 569 | assert_eq!( 570 | (bytes[0..15]).as_slice_of::(), 571 | Err(Error::LengthMismatch { 572 | dst_type: "u16", 573 | src_slice_size: 15, 574 | dst_type_size: 2 575 | }) 576 | ); 577 | assert_eq!(bytes.as_slice_of::(), Ok(slice.as_ref())); 578 | } 579 | 580 | #[cfg(feature = "std")] 581 | #[test] 582 | fn u16_error_string() { 583 | let slice: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; 584 | let bytes = slice.as_byte_slice(); 585 | 586 | let error = (bytes[1..]).as_slice_of::().unwrap_err().to_string(); 587 | assert_eq!( 588 | error, 589 | "cannot cast a &[u8] into a &[u16]: the slice's address is not divisible by the minimum alignment (2) of u16", 590 | ); 591 | let error = (bytes[0..15]).as_slice_of::().unwrap_err().to_string(); 592 | assert_eq!( 593 | error, 594 | "cannot cast a &[u8] into a &[u16]: the size (15) of the slice is not divisible by the size (2) of u16" 595 | ); 596 | } 597 | 598 | #[test] 599 | fn u32() { 600 | let slice: [u32; 4] = [0, 1, 2, 3]; 601 | let bytes = slice.as_byte_slice(); 602 | 603 | if cfg!(target_endian = "big") { 604 | assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]); 605 | } else { 606 | assert_eq!(bytes, &[0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]); 607 | } 608 | 609 | assert_eq!( 610 | (bytes[1..]).as_slice_of::(), 611 | Err(Error::AlignmentMismatch { 612 | dst_type: "u32", 613 | dst_minimum_alignment: mem::align_of::() 614 | }) 615 | ); 616 | assert_eq!( 617 | (bytes[0..15]).as_slice_of::(), 618 | Err(Error::LengthMismatch { 619 | dst_type: "u32", 620 | src_slice_size: 15, 621 | dst_type_size: 4 622 | }) 623 | ); 624 | assert_eq!(bytes.as_slice_of::(), Ok(slice.as_ref())); 625 | } 626 | 627 | #[test] 628 | fn u64() { 629 | let slice: [u64; 2] = [0, 1]; 630 | let bytes = slice.as_byte_slice(); 631 | 632 | if cfg!(target_endian = "big") { 633 | assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); 634 | } else { 635 | assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]); 636 | } 637 | 638 | assert_eq!( 639 | (bytes[1..]).as_slice_of::(), 640 | Err(Error::AlignmentMismatch { 641 | dst_type: "u64", 642 | dst_minimum_alignment: mem::align_of::() 643 | }) 644 | ); 645 | assert_eq!( 646 | (bytes[0..15]).as_slice_of::(), 647 | Err(Error::LengthMismatch { 648 | dst_type: "u64", 649 | src_slice_size: 15, 650 | dst_type_size: 8 651 | }) 652 | ); 653 | assert_eq!(bytes.as_slice_of::(), Ok(slice.as_ref())); 654 | } 655 | 656 | #[test] 657 | #[allow(clippy::collapsible_if)] 658 | #[allow(clippy::collapsible_else_if)] 659 | fn usize() { 660 | let slice: [usize; 2] = [0, 1]; 661 | let bytes = slice.as_byte_slice(); 662 | 663 | if cfg!(target_endian = "big") { 664 | if cfg!(target_pointer_width = "16") { 665 | assert_eq!(bytes, &[0, 0, 0, 1]); 666 | } else if cfg!(target_pointer_width = "32") { 667 | assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 1]); 668 | } else if cfg!(target_pointer_width = "64") { 669 | assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); 670 | } else { 671 | panic!("Unhandled target_endian/target_pointer_width configuration"); 672 | } 673 | } else { 674 | if cfg!(target_pointer_width = "16") { 675 | assert_eq!(bytes, &[0, 0, 1, 0]); 676 | } else if cfg!(target_pointer_width = "32") { 677 | assert_eq!(bytes, &[0, 0, 0, 0, 1, 0, 0, 0]); 678 | } else if cfg!(target_pointer_width = "64") { 679 | assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]); 680 | } else { 681 | panic!("Unhandled target_endian/target_pointer_width configuration"); 682 | } 683 | } 684 | 685 | assert_eq!( 686 | (bytes[1..]).as_slice_of::(), 687 | Err(Error::AlignmentMismatch { 688 | dst_type: "usize", 689 | dst_minimum_alignment: mem::align_of::() 690 | }) 691 | ); 692 | assert_eq!( 693 | (bytes[0..3]).as_slice_of::(), 694 | Err(Error::LengthMismatch { 695 | dst_type: "usize", 696 | src_slice_size: 3, 697 | dst_type_size: mem::size_of::() 698 | }) 699 | ); 700 | assert_eq!(bytes.as_slice_of::(), Ok(slice.as_ref())); 701 | } 702 | 703 | #[test] 704 | fn f32() { 705 | let slice: [f32; 4] = [2.0, 1.0, 0.5, 0.25]; 706 | let bytes = slice.as_byte_slice(); 707 | 708 | if cfg!(target_endian = "big") { 709 | assert_eq!( 710 | bytes, 711 | [ 712 | 0x40, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 713 | 0x80, 0x00, 0x00 714 | ] 715 | ); 716 | } else { 717 | assert_eq!( 718 | bytes, 719 | [ 720 | 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 721 | 0x00, 0x80, 0x3e 722 | ] 723 | ); 724 | }; 725 | 726 | assert_eq!( 727 | (bytes[1..]).as_slice_of::(), 728 | Err(Error::AlignmentMismatch { 729 | dst_type: "f32", 730 | dst_minimum_alignment: mem::align_of::() 731 | }) 732 | ); 733 | assert_eq!( 734 | (bytes[0..15]).as_slice_of::(), 735 | Err(Error::LengthMismatch { 736 | dst_type: "f32", 737 | src_slice_size: 15, 738 | dst_type_size: 4 739 | }) 740 | ); 741 | assert_eq!(bytes.as_slice_of::(), Ok(slice.as_ref())); 742 | } 743 | 744 | #[test] 745 | fn f64() { 746 | let slice: [f64; 2] = [2.0, 0.5]; 747 | let bytes = slice.as_byte_slice(); 748 | 749 | if cfg!(target_endian = "big") { 750 | assert_eq!( 751 | bytes, 752 | [ 753 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 0x00, 754 | 0x00, 0x00, 0x00 755 | ] 756 | ); 757 | } else { 758 | assert_eq!( 759 | bytes, 760 | [ 761 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 762 | 0x00, 0xe0, 0x3f 763 | ] 764 | ); 765 | }; 766 | 767 | assert_eq!( 768 | (bytes[1..]).as_slice_of::(), 769 | Err(Error::AlignmentMismatch { 770 | dst_type: "f64", 771 | dst_minimum_alignment: mem::align_of::() 772 | }) 773 | ); 774 | assert_eq!( 775 | (bytes[0..15]).as_slice_of::(), 776 | Err(Error::LengthMismatch { 777 | dst_type: "f64", 778 | src_slice_size: 15, 779 | dst_type_size: mem::size_of::() 780 | }) 781 | ); 782 | assert_eq!(bytes.as_slice_of::(), Ok(slice.as_ref())); 783 | } 784 | 785 | #[test] 786 | fn u16_mut() { 787 | let mut slice: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; 788 | let mut slice_2: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; 789 | let bytes = slice_2.as_mut_byte_slice(); 790 | 791 | if cfg!(target_endian = "big") { 792 | assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]); 793 | } else { 794 | assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]); 795 | } 796 | 797 | assert_eq!( 798 | (bytes[1..]).as_mut_slice_of::(), 799 | Err(Error::AlignmentMismatch { 800 | dst_type: "u16", 801 | dst_minimum_alignment: mem::align_of::() 802 | }) 803 | ); 804 | assert_eq!( 805 | (bytes[0..15]).as_mut_slice_of::(), 806 | Err(Error::LengthMismatch { 807 | dst_type: "u16", 808 | src_slice_size: 15, 809 | dst_type_size: 2 810 | }) 811 | ); 812 | assert_eq!(bytes.as_mut_slice_of::(), Ok(slice.as_mut())); 813 | } 814 | 815 | #[cfg(feature = "std")] 816 | #[test] 817 | fn u16_vec() { 818 | let vec: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; 819 | let bytes = vec.as_byte_slice(); 820 | 821 | if cfg!(target_endian = "big") { 822 | assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]); 823 | } else { 824 | assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]); 825 | } 826 | 827 | assert_eq!( 828 | (bytes[1..]).as_slice_of::(), 829 | Err(Error::AlignmentMismatch { 830 | dst_type: "u16", 831 | dst_minimum_alignment: mem::align_of::() 832 | }) 833 | ); 834 | assert_eq!( 835 | (bytes[0..15]).as_slice_of::(), 836 | Err(Error::LengthMismatch { 837 | dst_type: "u16", 838 | src_slice_size: 15, 839 | dst_type_size: 2 840 | }) 841 | ); 842 | assert_eq!(bytes.as_slice_of::(), Ok(vec.as_ref())); 843 | } 844 | 845 | #[cfg(feature = "std")] 846 | #[test] 847 | fn u16_mut_vec() { 848 | let mut vec: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; 849 | let mut vec_clone = vec.clone(); 850 | let bytes = vec_clone.as_mut_byte_slice(); 851 | 852 | if cfg!(target_endian = "big") { 853 | assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]); 854 | } else { 855 | assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]); 856 | } 857 | 858 | assert_eq!( 859 | (bytes[1..]).as_mut_slice_of::(), 860 | Err(Error::AlignmentMismatch { 861 | dst_type: "u16", 862 | dst_minimum_alignment: mem::align_of::() 863 | }) 864 | ); 865 | assert_eq!( 866 | (bytes[0..15]).as_mut_slice_of::(), 867 | Err(Error::LengthMismatch { 868 | dst_type: "u16", 869 | src_slice_size: 15, 870 | dst_type_size: 2 871 | }) 872 | ); 873 | assert_eq!(bytes.as_mut_slice_of::(), Ok(vec.as_mut())); 874 | } 875 | 876 | #[cfg(feature = "std")] 877 | #[test] 878 | fn u16_box_slice() { 879 | let vec: Box<[u16]> = vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(); 880 | let bytes = vec.as_byte_slice(); 881 | 882 | if cfg!(target_endian = "big") { 883 | assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]); 884 | } else { 885 | assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]); 886 | } 887 | 888 | assert_eq!( 889 | (bytes[1..]).as_slice_of::(), 890 | Err(Error::AlignmentMismatch { 891 | dst_type: "u16", 892 | dst_minimum_alignment: mem::align_of::() 893 | }) 894 | ); 895 | assert_eq!( 896 | (bytes[0..15]).as_slice_of::(), 897 | Err(Error::LengthMismatch { 898 | dst_type: "u16", 899 | src_slice_size: 15, 900 | dst_type_size: 2 901 | }) 902 | ); 903 | assert_eq!(bytes.as_slice_of::(), Ok(vec.as_ref())); 904 | } 905 | 906 | #[cfg(feature = "std")] 907 | #[test] 908 | fn u16_mut_box_slice() { 909 | let mut vec: Box<[u16]> = vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(); 910 | let mut vec_clone: Box<[u16]> = vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(); 911 | let bytes = vec_clone.as_mut_byte_slice(); 912 | 913 | if cfg!(target_endian = "big") { 914 | assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]); 915 | } else { 916 | assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]); 917 | } 918 | 919 | assert_eq!( 920 | (bytes[1..]).as_mut_slice_of::(), 921 | Err(Error::AlignmentMismatch { 922 | dst_type: "u16", 923 | dst_minimum_alignment: mem::align_of::() 924 | }) 925 | ); 926 | assert_eq!( 927 | (bytes[0..15]).as_mut_slice_of::(), 928 | Err(Error::LengthMismatch { 929 | dst_type: "u16", 930 | src_slice_size: 15, 931 | dst_type_size: 2 932 | }) 933 | ); 934 | assert_eq!(bytes.as_mut_slice_of::(), Ok(vec.as_mut())); 935 | } 936 | 937 | #[test] 938 | fn u16_empty_to_byte_slice() { 939 | let slice: [u16; 0] = []; 940 | let bytes = slice.as_byte_slice(); 941 | 942 | assert_eq!(bytes, &[]); 943 | } 944 | 945 | #[test] 946 | fn u16_empty_from_byte_slice() { 947 | let bytes: [u8; 0] = []; 948 | let slice = bytes.as_slice_of::().unwrap(); 949 | assert_eq!(slice, &[]); 950 | } 951 | 952 | #[test] 953 | fn unit() { 954 | let slice: [(); 4] = [(), (), (), ()]; 955 | let bytes = slice.as_byte_slice(); 956 | 957 | assert_eq!(bytes, &[]); 958 | } 959 | 960 | #[test] 961 | fn u8_array() { 962 | let input: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14]][..]; 963 | 964 | let bytes: &[u8] = input.as_byte_slice(); 965 | assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]); 966 | 967 | let output = bytes.as_slice_of::<[u8; 3]>().unwrap(); 968 | 969 | assert_eq!(output, input); 970 | } 971 | 972 | #[test] 973 | fn u16_array() { 974 | let input: &[[u16; 3]] = &[[0, 1, 2], [3, 4, 5]][..]; 975 | 976 | let bytes: &[u8] = input.as_byte_slice(); 977 | if cfg!(target_endian = "big") { 978 | assert_eq!(bytes, [0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5]); 979 | } else { 980 | assert_eq!(bytes, [0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0]); 981 | }; 982 | 983 | assert_eq!( 984 | (bytes[1..]).as_slice_of::<[u16; 3]>(), 985 | Err(Error::AlignmentMismatch { 986 | dst_type: "[u16; N]", 987 | dst_minimum_alignment: mem::align_of::<[u16; 3]>() 988 | }) 989 | ); 990 | assert_eq!( 991 | (bytes[0..4]).as_slice_of::<[u16; 3]>(), 992 | Err(Error::LengthMismatch { 993 | dst_type: "[u16; N]", 994 | src_slice_size: 4, 995 | dst_type_size: 6 996 | }) 997 | ); 998 | 999 | let output = bytes.as_slice_of::<[u16; 3]>().unwrap(); 1000 | assert_eq!(output, input); 1001 | } 1002 | } 1003 | --------------------------------------------------------------------------------