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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
use std::io::{Cursor, Read, Write}; #[cfg(feature = "verbose")] pub use log::debug; #[doc(hidden)] /// Allows for compile time assertions in the generated derive code pub use static_assertions as sa; #[cfg(test)] mod tests; mod error; pub use error::*; mod default_impls; pub use default_impls::*; mod helpers; pub use helpers::*; pub use simple_parse_derive::*; /// A context passed around [SpRead] and [SpWrite] functions pub struct SpCtx { /// How many bytes have been read/written so far pub cursor: usize, /// This value should only be checked inside custom validators (which get called for both Read & Write) /// Its contents are considered invalid otherwise pub is_reading: bool, /// If the abitrary input/output bytes should be treated as little endian pub is_little_endian: bool, /// If a dynamically sized Self uses an external count field, and what its contents are pub count: Option<usize>, } impl Default for SpCtx { fn default() -> Self { Self { cursor: 0, is_reading: true, is_little_endian: cfg!(target_endian = "little"), count: None, } } } #[doc(hidden)] /// This type is used for dynamically sized type's default implementations pub type DefaultCountType = u32; #[doc(hidden)] /// This is a safeguard against reading malicious/malformed dynamically sized types. /// For example, when reading a String that says it contains INT_MAX characters, chunks of /// MAX_ALLOC_SIZE will be read at a time instead of allocating INT_MAX bytes in one go. pub const MAX_ALLOC_SIZE: usize = 4096; /// Provides optimization hints used by [SpRead] traits. /// /// # Safety /// When not using defaults, implementors must be very careful not to return invalid values /// as it may lead to buffer over reads (e.g. setting `STATIC_SIZE` to 4 and reading 8 bytes in the `unchecked` readers) pub unsafe trait SpOptHints { /// Whether the type has a variable size const IS_VAR_SIZE: bool = true; /// How many bytes the `unchecked` parsing functions can assume are valid const STATIC_SIZE: usize = 0; /// Used to substract from STATIC_SIZE when a count is provided const COUNT_SIZE: usize = 0; } /// Parses `Self` from a source implementing [Read](std::io::Read) ([File](std::fs::File),[TcpStream](std::net::TcpStream), etc...) /// /// This trait is most usefull when the bytes are coming from some kind of IO stream. /// When possible, it is recommend to use [SpReadRaw] instead for better performance. pub trait SpRead { /// Converts bytes from a [Reader](std::io::Read) into `Self` /// /// This functions allows specifying endianness and count fields as opposed to using defaults with `from_reader` fn inner_from_reader<R: Read + ?Sized>( src: &mut R, ctx: &mut SpCtx, ) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints; /// Converts bytes from a `&mut Read` into `Self` with some assumptions on checked_bytes /// /// # Safety /// This function assumes that checked_bytes points to at least Self::STATIC_SIZE bytes. /// /// If this is implemented on a dynamic type, the implementors MUST check if count is provided. /// If it is provided, Self::COUNT_SIZE less bytes can be trusted from checked_bytes. unsafe fn inner_from_reader_unchecked<R: Read + ?Sized>( checked_bytes: *mut u8, src: &mut R, ctx: &mut SpCtx, ) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints; /// Converts bytes from a `&mut Read` into `Self` fn from_reader<R: Read + ?Sized>(src: &mut R) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints, { Self::inner_from_reader(src, &mut SpCtx::default()) } } /// Parses `Self` from a [Cursor<&\[u8\]>](std::io::Cursor) pub trait SpReadRaw<'b> { /// Converts bytes from a `Cursor<&[u8]>` into `Self` /// /// This functions allows specifying endianness and count fields as opposed to using defaults with `from_slice` fn inner_from_slice( src: &mut Cursor<&'b [u8]>, ctx: &mut SpCtx, ) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints; /// Converts bytes from a `Cursor<&[u8]>` into `Self` with some assumptions on checked_bytes /// /// # Safety /// This function assumes that checked_bytes points to at least Self::STATIC_SIZE bytes. /// /// If this is implemented on a dynamic type, the implementors MUST check if count is provided. /// If it is provided, Self::COUNT_SIZE less bytes can be trusted from checked_bytes. /// /// This function also allows returning references into the `Cursor<&[u8]>` when `Self` is a reference `&T`. /// This should not be done if `Self` itself contains non-primitive types, references, slices, etc... unsafe fn inner_from_slice_unchecked( checked_bytes: *const u8, src: &mut Cursor<&'b [u8]>, ctx: &mut SpCtx, ) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints; /// Converts bytes from a `Cursor<&[u8]>` into `Self` fn from_slice(src: &mut Cursor<&'b [u8]>) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints, { Self::inner_from_slice(src, &mut SpCtx::default()) } } /// Parses `Self` from a [Cursor<&mut \[u8\]>](std::io::Cursor) pub trait SpReadRawMut<'b> { /// Converts bytes from a `Cursor<&mut [u8]>` into `Self` /// /// This functions allows specifying endianness and count fields as opposed to using defaults with `from_slice` fn inner_from_mut_slice( src: &mut Cursor<&'b mut [u8]>, ctx: &mut SpCtx, ) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints; /// Converts bytes from a `Cursor<&mut [u8]>` into `Self` with some assumptions on checked_bytes /// /// # Safety /// This function assumes that checked_bytes points to at least Self::STATIC_SIZE bytes. /// /// If this is implemented on a dynamic type, the implementors MUST check if count is provided. /// If it is provided, Self::COUNT_SIZE less bytes can be trusted from checked_bytes. /// /// This function also allows returning references into the `Cursor<&[u8]>` when `Self` is a reference `&T` or `&mut T`. /// This should not be done if `Self` itself contains non-primitive types, references, slices, etc... unsafe fn inner_from_mut_slice_unchecked( checked_bytes: *mut u8, src: &mut Cursor<&'b mut [u8]>, ctx: &mut SpCtx, ) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints; /// Converts bytes from a `Cursor<&mut [u8]>` into `Self` fn from_mut_slice(src: &mut Cursor<&'b mut [u8]>) -> Result<Self, crate::SpError> where Self: Sized + SpOptHints, { Self::inner_from_mut_slice(src, &mut SpCtx::default()) } } /// Writes `T` into a [Writer](std::io::Write) ([File](std::fs::File),[TcpStream](std::net::TcpStream), etc...) pub trait SpWrite { /// Writes the byte representation for Self into a `&mut Write` with control over endianness fn inner_to_writer<W: Write + ?Sized>( &self, ctx: &mut SpCtx, dst: &mut W, ) -> Result<usize, crate::SpError>; /// Writes the byte representation for Self into a `&mut Write` fn to_writer<W: Write + ?Sized>(&self, dst: &mut W) -> Result<usize, crate::SpError> { self.inner_to_writer(&mut SpCtx::default(), dst) } }