binary_layout/fields/primitive/copy_access/
read_write_ext.rs

1use crate::fields::{primitive::copy_access::FieldCopyAccess, Field};
2use crate::utils::infallible::{InfallibleResultExt, IsInfallible};
3
4/// This extension trait adds a [FieldReadExt::read] method to any type
5/// supporting [FieldCopyAccess::try_read] that has an implementation
6/// that cannot throw errors. This is a convenience function so that callers
7/// can just call [FieldReadExt::read] instead of having to call [FieldCopyAccess::try_read]
8/// and then calling [Result::unwrap] on the returned value.
9pub trait FieldReadExt: Field {
10    /// The data type that is returned from read calls and has to be
11    /// passed in to write calls. This can be different from the primitive
12    /// type used in the binary blob, since that primitive type can be
13    /// wrapped (see [WrappedField](crate::WrappedField) ) into a high level type before being returned from read
14    /// calls (or vice versa unwrapped when writing).
15    type HighLevelType;
16
17    /// Read the field from a given data region, assuming the defined layout, using the [Field] API.
18    ///
19    /// # Example:
20    /// ```
21    /// use binary_layout::prelude::*;
22    ///
23    /// binary_layout!(my_layout, LittleEndian, {
24    ///   //... other fields ...
25    ///   some_integer_field: u16,
26    ///   //... other fields ...
27    /// });
28    ///
29    /// fn func(storage_data: &[u8]) {
30    ///   let read: u16 = my_layout::some_integer_field::read(storage_data);
31    /// }
32    /// ```
33    fn read(storage: &[u8]) -> Self::HighLevelType;
34}
35
36/// This extension trait adds a [FieldWriteExt::write] method to any type
37/// supporting [FieldCopyAccess::try_write] that has an implementation
38/// that cannot throw errors. This is a convenience function so that callers
39/// can just call [FieldWriteExt::write] instead of having to call [FieldCopyAccess::try_write]
40/// and then calling [Result::unwrap] on the returned value.
41pub trait FieldWriteExt: Field {
42    /// The data type that is returned from read calls and has to be
43    /// passed in to write calls. This can be different from the primitive
44    /// type used in the binary blob, since that primitive type can be
45    /// wrapped (see [WrappedField](crate::WrappedField) ) into a high level type before being returned from read
46    /// calls (or vice versa unwrapped when writing).
47    type HighLevelType;
48
49    /// Write the field to a given data region, assuming the defined layout, using the [Field] API.
50    ///
51    /// # Example:
52    ///
53    /// ```
54    /// use binary_layout::prelude::*;
55    ///
56    /// binary_layout!(my_layout, LittleEndian, {
57    ///   //... other fields ...
58    ///   some_integer_field: u16,
59    ///   //... other fields ...
60    /// });
61    ///
62    /// fn func(storage_data: &mut [u8]) {
63    ///   my_layout::some_integer_field::write(storage_data, 10);
64    /// }
65    /// ```
66    fn write(storage: &mut [u8], v: Self::HighLevelType);
67}
68
69impl<F> FieldReadExt for F
70where
71    F: FieldCopyAccess,
72    F::ReadError: IsInfallible,
73{
74    type HighLevelType = F::HighLevelType;
75
76    /// This implements a convenience method for reading any data type whose [FieldCopyAccess::try_read]
77    /// does not throw errors.
78    /// See [FieldCopyAccess::try_read].
79    #[inline(always)]
80    fn read(storage: &[u8]) -> Self::HighLevelType {
81        F::try_read(storage).infallible_unwrap()
82    }
83}
84
85impl<F> FieldWriteExt for F
86where
87    F: FieldCopyAccess,
88    F::WriteError: IsInfallible,
89{
90    type HighLevelType = F::HighLevelType;
91
92    /// This implements a convenience method for writing any data type whose [FieldCopyAccess::try_write]
93    /// does not throw errors.
94    /// See [FieldCopyAccess::try_write].
95    #[inline(always)]
96    fn write(storage: &mut [u8], value: Self::HighLevelType) {
97        F::try_write(storage, value).infallible_unwrap()
98    }
99}