1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
///
/// Defines types whose values can be `encast`ed and `decast`ed.
///
/// Note: In this crate, the term `encast` means decoding a number of
/// bytes to one or more values, the term `decast` means encoding one
/// or more variables to a number of bytes, and the term `endian-flip`
/// means flipping the endianness of value(s).
///
/// # Description
///
/// A type is `Cast` if
/// - it is a numeric type, i.e.,
/// * i8, i16, i32, i64, i128, isize,
/// * u8, u16, u32, u64, u128, usize,
/// * f32, or f64,
/// - it is an array type whose element is `Cast`, or
/// - it is a struct type or a union type whose all members are `Cast`
/// and implements `Cast` by declaring `#[derive(Cast)]`.
/// (Note: `#[repr(C)]` must also be declared)
///
/// As you may have noticed, all types implementing trait `Cast` can
/// be duplicated simply by copying bits. But trait `Cast` is not a
/// subtrait of trait `Copy`. The reasons why trait `Cast` is defined
/// independently from trait `Copy` are (1) to exclude pointers, (2)
/// to avoid unexpected copying, and (3) to enjoy the benefits of
/// Rust's ownership system. Therefore, if a struct type or a union
/// type need to be `Copy`, `#[derive(Clone, Copy)]` should also be
/// declared.
///
/// Trait `Cast` has no method. It is purely defined as a trait
/// bound.
///
/// # Example
///
/// In the example below, `#[derive(Cast)]` makes the values of
/// `ElfIdHdr` `encast`able / `decast`able so that methods `encast`
/// and method `decast` can work. Note that `#[repr(C)]` must also be
/// declared.
///
/// ```
/// # fn main() { test(); }
/// # fn test() -> Option<()> {
/// use castflip::{Cast, EncastMem, DecastMem};
///
/// #[repr(C)]
/// #[derive(Cast)]
/// struct ElfIdHdr {
/// magic: [u8; 4], //00-03: Magic Number 0x7F "ELF"
/// class: u8, //04 : File Class
/// encoding: u8, //05 : Data Encoding
/// version: u8, //06 : Version (should be 1)
/// os_abi: u8, //07 : OS and ABI
/// abi_ver: u8, //08 : ABI Version
/// pad: [u8; 7], //09-0F: Padding (should be 0)
/// }
///
/// // Input data: ELF Identification (16 bytes)
/// let bytes1: [u8; 16] = [0x7F, 0x45, 0x4C, 0x46, 0x02, 0x01, 0x01, 0x00,
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
///
/// // Decode bytes `bytes1` to variable `id_hdr2`.
/// let id_hdr2: ElfIdHdr = bytes1.encast()?;
///
/// // Encode the resulting `id_hdr2` to bytes `bytes3`.
/// let mut bytes3 = [0_u8; 16];
/// let size3 = bytes3.decast(&id_hdr2)?;
///
/// // Check the results (id_hdr2)
/// assert_eq!(id_hdr2.magic, *b"\x7FELF"); // Magic Number: 7F 45 4C 46
/// assert_eq!(id_hdr2.class, 2); // File Class: 64-bit
/// assert_eq!(id_hdr2.encoding, 1); // Encoding: Little-Endian
/// assert_eq!(id_hdr2.version, 1); // Version 1
/// assert_eq!(id_hdr2.os_abi, 0); // OS/ABI: unspecified
/// assert_eq!(id_hdr2.abi_ver, 0); // ABI Ver: unspecified
/// assert_eq!(id_hdr2.pad, [0_u8; 7]); // Padding
///
/// // Check the results (bytes3)
/// assert_eq!(size3, 16);
/// assert_eq!(bytes3, bytes1);
/// # Some(())
/// # }
/// ```
///
/// In the example above, method `encast` decodes bytes in `bytes1` to
/// variable `id_hdr` of type `ElfIdHdr`, and method `decast` encodes
/// the resulting value in `id_hdr` to bytes and stores them in
/// `bytes3`. Their endiannesses are not flipped.
///
/// Note: [ELF] is a common standard file format for executable files.
/// ELF Identification is the first 16 bytes of the ELF header.
///
/// [ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
///
pub trait Cast: Sized {}
impl Cast for i8 {}
impl Cast for i16 {}
impl Cast for i32 {}
impl Cast for i64 {}
impl Cast for i128 {}
impl Cast for isize {}
impl Cast for u8 {}
impl Cast for u16 {}
impl Cast for u32 {}
impl Cast for u64 {}
impl Cast for u128 {}
impl Cast for usize {}
impl Cast for f32 {}
impl Cast for f64 {}
impl<T: Cast, const N: usize> Cast for [T; N] {}