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
use super::super::Field;
use super::PrimitiveField;
/// This trait is implemented for fields with "try copy access",
/// i.e. fields that read/write data by copying it from/to the
/// binary blob, but where reading or writing can fail.
/// Examples of this are primitive types like NonZeroU8, NonZeroI32, ...
pub trait FieldCopyAccess: Field {
/// Error type that can be thrown from [FieldCopyAccess::try_read]. You can set this to [Infallible](core::convert::Infallible) if the function does not throw an error.
type ReadError;
/// Error type that can be thrown from [FieldCopyAccess::try_write]. You can set this to [Infallible](core::convert::Infallible) if the function does not throw an error.
type WriteError;
/// The data type that is returned from read calls and has to be
/// passed in to write calls. This can be different from the primitive
/// type used in the binary blob, since that primitive type can be
/// wrapped (see [WrappedField](crate::WrappedField) ) into a high level type before being returned from read
/// calls (or vice versa unwrapped when writing).
type HighLevelType;
/// Read the field from a given data region, assuming the defined layout, using the [Field] API.
///
/// # Example:
/// ```
/// use binary_layout::prelude::*;
/// use core::num::NonZeroU16;
///
/// binary_layout!(my_layout, LittleEndian, {
/// //... other fields ...
/// some_integer_field: core::num::NonZeroU16,
/// //... other fields ...
/// });
///
/// fn func(storage_data: &[u8]) -> Result<NonZeroU16, NonZeroIsZeroError> {
/// let read: NonZeroU16 = my_layout::some_integer_field::try_read(storage_data)?;
/// Ok(read)
/// }
/// ```
fn try_read(storage: &[u8]) -> Result<Self::HighLevelType, Self::ReadError>;
/// Write the field to a given data region, assuming the defined layout, using the [Field] API.
///
/// # Example:
///
/// ```
/// use binary_layout::prelude::*;
/// use core::num::NonZeroU16;
/// use core::convert::Infallible;
///
/// binary_layout!(my_layout, LittleEndian, {
/// //... other fields ...
/// some_integer_field: core::num::NonZeroU16,
/// //... other fields ...
/// });
///
/// fn func(storage_data: &mut [u8]) -> Result<(), Infallible> {
/// let value = NonZeroU16::new(10).unwrap();
/// my_layout::some_integer_field::try_write(storage_data, value)?;
/// Ok(())
/// }
/// ```
fn try_write(storage: &mut [u8], v: Self::HighLevelType) -> Result<(), Self::WriteError>;
}
macro_rules! impl_field_traits {
($type: ty) => {
impl<E: Endianness, const OFFSET_: usize> Field for PrimitiveField<$type, E, OFFSET_> {
/// See [Field::Endian]
type Endian = E;
/// See [Field::OFFSET]
const OFFSET: usize = OFFSET_;
/// See [Field::SIZE]
const SIZE: Option<usize> = Some(core::mem::size_of::<$type>());
}
impl<'a, E: Endianness, const OFFSET_: usize> StorageToFieldView<&'a [u8]>
for PrimitiveField<$type, E, OFFSET_>
{
type View = FieldView<&'a [u8], Self>;
#[inline(always)]
fn view(storage: &'a [u8]) -> Self::View {
Self::View::new(storage)
}
}
impl<'a, E: Endianness, const OFFSET_: usize> StorageToFieldView<&'a mut [u8]>
for PrimitiveField<$type, E, OFFSET_>
{
type View = FieldView<&'a mut [u8], Self>;
#[inline(always)]
fn view(storage: &'a mut [u8]) -> Self::View {
Self::View::new(storage)
}
}
impl<S: AsRef<[u8]>, E: Endianness, const OFFSET_: usize> StorageIntoFieldView<S>
for PrimitiveField<$type, E, OFFSET_>
{
type View = FieldView<S, Self>;
#[inline(always)]
fn into_view(storage: S) -> Self::View {
Self::View::new(storage)
}
}
};
}
mod primitive_float;
mod primitive_int;
mod primitive_nonzero_int;
mod primitive_unit;
mod read_write_ext;
pub use primitive_nonzero_int::NonZeroIsZeroError;
pub use read_write_ext::{FieldReadExt, FieldWriteExt};