byte_slice_cast/
lib.rs

1// Copyright (C) 2017,2018 Sebastian Dröge <sebastian@centricular.com>
2//
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
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<T>`
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::<u16>().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::<u16>().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
66use core::{fmt, mem, slice};
67
68#[cfg(feature = "std")]
69use std::error::Error as StdError;
70
71/// Possible errors during slice conversion.
72#[derive(Clone, Debug, PartialEq, Eq)]
73pub 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
90impl 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
125trait TypeName {
126    const TYPE_NAME: &'static str;
127}
128
129#[cfg(feature = "std")]
130impl 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
141fn check_alignment<T, U>(data: &T) -> Result<usize, Error>
142where
143    U: TypeName,
144    T: AsRef<[u8]> + ?Sized,
145{
146    let alignment = mem::align_of::<U>();
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
158fn check_length<T, U>(data: &T) -> Result<usize, Error>
159where
160    U: TypeName,
161    T: AsRef<[u8]> + ?Sized,
162{
163    let size_out = mem::size_of::<U>();
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
175fn check_constraints<U>(data: &[u8]) -> Result<usize, Error>
176where
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
189macro_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<T: AsRef<[u8]> + ?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<T: AsMut<[u8]> + ?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<T: AsRef<[$to]> + ?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<T: AsMut<[$to]> + ?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
255macro_rules! impl_trait_array (
256    ($to:ty) => {
257        impl<const N: usize> TypeName for [$to; N] {
258            const TYPE_NAME: &'static str = stringify!([$to; N]);
259        }
260
261        unsafe impl<const N: usize> FromByteSlice for [$to; N] {
262            #[inline]
263            fn from_byte_slice<T: AsRef<[u8]> + ?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<T: AsMut<[u8]> + ?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<const N: usize> ToByteSlice for [$to; N] {
298            #[inline]
299            fn to_byte_slice<T: AsRef<[[$to; N]]> + ?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<const N: usize> ToMutByteSlice for [$to; N] {
309            #[inline]
310            fn to_mut_byte_slice<T: AsMut<[[$to; N]]> + ?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
327pub unsafe trait FromByteSlice
328where
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<T: AsRef<[u8]> + ?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<T: AsMut<[u8]> + ?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
345pub unsafe trait ToByteSlice
346where
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<T: AsRef<[Self]> + ?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
360pub unsafe trait ToMutByteSlice
361where
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<T: AsMut<[Self]> + ?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::<u16>().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/// ```
387pub trait AsSliceOf {
388    fn as_slice_of<T: FromByteSlice>(&self) -> Result<&[T], Error>;
389}
390
391impl<U: AsRef<[u8]> + ?Sized> AsSliceOf for U {
392    #[inline]
393    fn as_slice_of<T: FromByteSlice>(&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::<u16>().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/// ```
417pub trait AsMutSliceOf {
418    fn as_mut_slice_of<T: FromByteSlice>(&mut self) -> Result<&mut [T], Error>;
419}
420
421impl<U: AsMut<[u8]> + ?Sized> AsMutSliceOf for U {
422    #[inline]
423    fn as_mut_slice_of<T: FromByteSlice>(&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/// ```
447pub trait AsByteSlice<T> {
448    fn as_byte_slice(&self) -> &[u8];
449}
450
451impl<T: ToByteSlice, U: AsRef<[T]> + ?Sized> AsByteSlice<T> 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/// ```
477pub trait AsMutByteSlice<T> {
478    fn as_mut_byte_slice(&mut self) -> &mut [u8];
479}
480
481impl<T: ToMutByteSlice, U: AsMut<[T]> + ?Sized> AsMutByteSlice<T> for U {
482    #[inline]
483    fn as_mut_byte_slice(&mut self) -> &mut [u8] {
484        ToMutByteSlice::to_mut_byte_slice(self)
485    }
486}
487
488impl_trait!(u8);
489impl_trait!(u16);
490impl_trait!(u32);
491impl_trait!(u64);
492impl_trait!(u128);
493impl_trait!(i8);
494impl_trait!(i16);
495impl_trait!(i32);
496impl_trait!(i64);
497impl_trait!(i128);
498impl_trait!(f32);
499impl_trait!(f64);
500impl_trait!(usize);
501impl_trait!(isize);
502
503impl_trait_array!(u8);
504impl_trait_array!(u16);
505impl_trait_array!(u32);
506impl_trait_array!(u64);
507impl_trait_array!(u128);
508impl_trait_array!(i8);
509impl_trait_array!(i16);
510impl_trait_array!(i32);
511impl_trait_array!(i64);
512impl_trait_array!(i128);
513impl_trait_array!(f32);
514impl_trait_array!(f64);
515impl_trait_array!(usize);
516impl_trait_array!(isize);
517
518impl TypeName for () {
519    const TYPE_NAME: &'static str = "()";
520}
521
522unsafe impl ToByteSlice for () {
523    #[inline]
524    fn to_byte_slice<T: AsRef<[()]> + ?Sized>(_: &T) -> &[u8] {
525        &[]
526    }
527}
528
529unsafe impl ToMutByteSlice for () {
530    #[inline]
531    fn to_mut_byte_slice<T: AsMut<[()]> + ?Sized>(_: &mut T) -> &mut [u8] {
532        &mut []
533    }
534}
535
536#[cfg(test)]
537mod 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::<u8>().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::<u16>(),
564            Err(Error::AlignmentMismatch {
565                dst_type: "u16",
566                dst_minimum_alignment: mem::align_of::<u16>()
567            })
568        );
569        assert_eq!(
570            (bytes[0..15]).as_slice_of::<u16>(),
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::<u16>(), 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::<u16>().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::<u16>().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::<u32>(),
611            Err(Error::AlignmentMismatch {
612                dst_type: "u32",
613                dst_minimum_alignment: mem::align_of::<u32>()
614            })
615        );
616        assert_eq!(
617            (bytes[0..15]).as_slice_of::<u32>(),
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::<u32>(), 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::<u64>(),
640            Err(Error::AlignmentMismatch {
641                dst_type: "u64",
642                dst_minimum_alignment: mem::align_of::<u64>()
643            })
644        );
645        assert_eq!(
646            (bytes[0..15]).as_slice_of::<u64>(),
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::<u64>(), 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::<usize>(),
687            Err(Error::AlignmentMismatch {
688                dst_type: "usize",
689                dst_minimum_alignment: mem::align_of::<usize>()
690            })
691        );
692        assert_eq!(
693            (bytes[0..3]).as_slice_of::<usize>(),
694            Err(Error::LengthMismatch {
695                dst_type: "usize",
696                src_slice_size: 3,
697                dst_type_size: mem::size_of::<usize>()
698            })
699        );
700        assert_eq!(bytes.as_slice_of::<usize>(), 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::<f32>(),
728            Err(Error::AlignmentMismatch {
729                dst_type: "f32",
730                dst_minimum_alignment: mem::align_of::<f32>()
731            })
732        );
733        assert_eq!(
734            (bytes[0..15]).as_slice_of::<f32>(),
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::<f32>(), 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::<f64>(),
769            Err(Error::AlignmentMismatch {
770                dst_type: "f64",
771                dst_minimum_alignment: mem::align_of::<f64>()
772            })
773        );
774        assert_eq!(
775            (bytes[0..15]).as_slice_of::<f64>(),
776            Err(Error::LengthMismatch {
777                dst_type: "f64",
778                src_slice_size: 15,
779                dst_type_size: mem::size_of::<f64>()
780            })
781        );
782        assert_eq!(bytes.as_slice_of::<f64>(), 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::<u16>(),
799            Err(Error::AlignmentMismatch {
800                dst_type: "u16",
801                dst_minimum_alignment: mem::align_of::<u16>()
802            })
803        );
804        assert_eq!(
805            (bytes[0..15]).as_mut_slice_of::<u16>(),
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::<u16>(), Ok(slice.as_mut()));
813    }
814
815    #[cfg(feature = "std")]
816    #[test]
817    fn u16_vec() {
818        let vec: Vec<u16> = 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::<u16>(),
829            Err(Error::AlignmentMismatch {
830                dst_type: "u16",
831                dst_minimum_alignment: mem::align_of::<u16>()
832            })
833        );
834        assert_eq!(
835            (bytes[0..15]).as_slice_of::<u16>(),
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::<u16>(), Ok(vec.as_ref()));
843    }
844
845    #[cfg(feature = "std")]
846    #[test]
847    fn u16_mut_vec() {
848        let mut vec: Vec<u16> = 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::<u16>(),
860            Err(Error::AlignmentMismatch {
861                dst_type: "u16",
862                dst_minimum_alignment: mem::align_of::<u16>()
863            })
864        );
865        assert_eq!(
866            (bytes[0..15]).as_mut_slice_of::<u16>(),
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::<u16>(), 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::<u16>(),
890            Err(Error::AlignmentMismatch {
891                dst_type: "u16",
892                dst_minimum_alignment: mem::align_of::<u16>()
893            })
894        );
895        assert_eq!(
896            (bytes[0..15]).as_slice_of::<u16>(),
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::<u16>(), 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::<u16>(),
921            Err(Error::AlignmentMismatch {
922                dst_type: "u16",
923                dst_minimum_alignment: mem::align_of::<u16>()
924            })
925        );
926        assert_eq!(
927            (bytes[0..15]).as_mut_slice_of::<u16>(),
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::<u16>(), 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::<u16>().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}