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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
//! Traits that expose information about the way types are parsed or serialised.
//!
//! The traits in this module *describe* how a [`BinRead`] or [`BinWrite`]
//! implementation works; they do not *control* the implementation. They are
//! automatically implemented for derived `BinRead` or `BinWrite`
//! implementations, but can also be manually implemented if needed for types
//! that manually implement `BinRead` and `BinWrite`.
//!
//! [`BinRead`]: crate::BinRead
//! [`BinWrite`]: crate::BinWrite
use crate::Endian;
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
use core::marker::PhantomData;
/// Types that require a magic number when parsed.
///
/// This trait is automatically defined on derived types with a
/// [magic directive](crate::docs::attribute#magic).
pub trait ReadMagic {
/// The type of the magic number.
type MagicType;
/// The magic number.
const MAGIC: Self::MagicType;
}
/// Types that write a magic number when serialised.
///
/// This trait is automatically defined on derived types with a
/// [magic directive](crate::docs::attribute#magic).
pub trait WriteMagic {
/// The type of the magic number.
type MagicType;
/// The magic number.
const MAGIC: Self::MagicType;
}
/// Types with explicit read endianness.
///
/// This trait is automatically defined on derived types with a
/// [byte order directive](crate::docs::attribute#byte-order).
pub trait ReadEndian {
/// The endianness of the type.
const ENDIAN: EndianKind;
}
/// Types with explicit write endianness.
///
/// This trait is automatically defined on derived types with a
/// [byte order directive](crate::docs::attribute#byte-order).
pub trait WriteEndian {
/// The endianness of the type.
const ENDIAN: EndianKind;
}
/// The kind of endianness used by a type.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EndianKind {
/// The type has no endianness at all.
None,
/// The type uses a fixed endianness.
Endian(Endian),
/// The type uses an endianness that is dynamically determined at runtime
/// from an expression.
Runtime,
/// The type uses a heterogenous mix of endianness.
Mixed,
}
impl EndianKind {
/// Returns the fixed endianness of the type, if one exists.
#[must_use]
pub fn endian(self) -> Option<Endian> {
match self {
EndianKind::None | EndianKind::Runtime | EndianKind::Mixed => None,
EndianKind::Endian(endian) => Some(endian),
}
}
}
macro_rules! endian_impl {
($($($Ty:ty)+ => $kind:expr),+ $(,)?) => {$($(
impl ReadEndian for $Ty {
const ENDIAN: EndianKind = $kind;
}
impl WriteEndian for $Ty {
const ENDIAN: EndianKind = $kind;
}
)+)+}
}
endian_impl!(() i8 u8 core::num::NonZeroU8 core::num::NonZeroI8 crate::strings::NullString => EndianKind::None);
impl<T: ReadEndian + ?Sized> ReadEndian for Box<T> {
const ENDIAN: EndianKind = <T as ReadEndian>::ENDIAN;
}
impl<T: WriteEndian + ?Sized> WriteEndian for Box<T> {
const ENDIAN: EndianKind = <T as WriteEndian>::ENDIAN;
}
impl<T: ReadEndian> ReadEndian for [T] {
const ENDIAN: EndianKind = <T as ReadEndian>::ENDIAN;
}
impl<T: WriteEndian> WriteEndian for [T] {
const ENDIAN: EndianKind = <T as WriteEndian>::ENDIAN;
}
impl<T: ReadEndian, const N: usize> ReadEndian for [T; N] {
const ENDIAN: EndianKind = <T as ReadEndian>::ENDIAN;
}
impl<T: WriteEndian, const N: usize> WriteEndian for [T; N] {
const ENDIAN: EndianKind = <T as WriteEndian>::ENDIAN;
}
macro_rules! endian_generic_impl {
($($Ty:ident)+) => {$(
impl<T: ReadEndian> ReadEndian for $Ty<T> {
const ENDIAN: EndianKind = <T as ReadEndian>::ENDIAN;
}
impl<T: WriteEndian> WriteEndian for $Ty<T> {
const ENDIAN: EndianKind = <T as WriteEndian>::ENDIAN;
}
)+}
}
endian_generic_impl!(Option Vec PhantomData);
macro_rules! endian_tuple_impl {
($type1:ident $(, $types:ident)*) => {
#[allow(non_camel_case_types)]
impl<$type1: ReadEndian, $($types: ReadEndian),*> ReadEndian for ($type1, $($types),*) {
const ENDIAN: EndianKind = EndianKind::Mixed;
}
#[allow(non_camel_case_types)]
impl<$type1: WriteEndian, $($types: WriteEndian),*> WriteEndian for ($type1, $($types),*) {
const ENDIAN: EndianKind = EndianKind::Mixed;
}
endian_tuple_impl!($($types),*);
};
() => {};
}
endian_tuple_impl!(
b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21,
b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32
);