diff options
| author | iximeow <me@iximeow.net> | 2021-07-03 21:10:30 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2021-07-03 21:10:30 -0700 | 
| commit | 1a71764b221f6a0f497ab8ce4b6e52ff3fd79d60 (patch) | |
| tree | 96f6d9a9ec6fda539269f697c9c9272843707776 /src | |
| parent | 041ef2605f5de35e268bd0f82d9a6240a9a58e61 (diff) | |
reader impls for various word sizes
Diffstat (limited to 'src')
| -rw-r--r-- | src/reader.rs | 344 | 
1 files changed, 174 insertions, 170 deletions
| diff --git a/src/reader.rs b/src/reader.rs index c5dacf6..b263f22 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -39,6 +39,16 @@ impl<'a> U8Reader<'a> {      }  } +/* a `std::io::Read`-friendly `Reader` would take some thought. this was an old impl, and now would + * require something like + * ``` + * pub struct IoReader<'io, T: std::io::Read> { + *   io: &io mut T, + *   count: u64, + *   start: u64, + * } + * ``` + */  /*  #[cfg(feature = "std")]  impl<T: std::io::Read> Reader<u8> for T { @@ -55,207 +65,201 @@ impl<T: std::io::Read> Reader<u8> for T {  }  */ -impl Reader<u64, u8> for U8Reader<'_> { -    #[inline] -    fn next(&mut self) -> Result<u8, ReadError> { -        if self.data == self.end { -            Err(ReadError::ExhaustedInput) -        } else { -            let word = unsafe { core::ptr::read(self.data) }; -            unsafe { -                self.data = self.data.offset(1); +macro_rules! word_wrapper { +    ($name:ident, $underlying:ident) => { +        #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] +        pub struct $name(pub $underlying); + +        impl core::fmt::Display for $name { +            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { +                write!(f, "{}", self.0)              } -            Ok(word)          }      } -    #[inline] -    fn next_n(&mut self, buf: &mut [u8]) -> Result<(), ReadError> { -        if let Some(data_size) = (self.end as usize).checked_sub(self.data as usize) { -            if buf.len() > data_size { -                return Err(ReadError::ExhaustedInput); +} + +word_wrapper!(U16le, u16); +word_wrapper!(U16be, u16); +word_wrapper!(U32le, u32); +word_wrapper!(U32be, u32); +word_wrapper!(U64le, u64); +word_wrapper!(U64be, u64); + +macro_rules! u8reader_reader_impl { +    ($addr_size:ident, $word:ident, $word_from_slice:expr, $words_from_slice:expr) => { +        impl Reader<$addr_size, $word> for U8Reader<'_> { +            #[inline] +            fn next(&mut self) -> Result<$word, ReadError> { +                let data_size = self.end as usize - self.data as usize; + +                if core::mem::size_of::<$word>() > data_size { +                    return Err(ReadError::ExhaustedInput); +                } + +                // `word_from_slice` knows that we have bounds-checked that `word`-many bytes are +                // available. +                let word = $word_from_slice(self.data); +                unsafe { +                    self.data = self.data.offset(core::mem::size_of::<$word>() as isize); +                } +                Ok(word)              } -            unsafe { -                core::ptr::copy_nonoverlapping(self.data, buf.as_mut_ptr(), buf.len()); +            #[inline] +            fn next_n(&mut self, buf: &mut [$word]) -> Result<(), ReadError> { +                let data_size = self.end as usize - self.data as usize; + +                let words_size_bytes = buf.len() * core::mem::size_of::<$word>(); +                if words_size_bytes > data_size { +                    return Err(ReadError::ExhaustedInput); +                } + +                // `word_from_slice` knows that we have bounds-checked that `word`-many bytes are +                // available. +                $words_from_slice(self.data, buf); +                unsafe { +                    self.data = self.data.offset(words_size_bytes as isize); +                } +                Ok(()) +            } +            #[inline] +            fn mark(&mut self) { +                self.mark = self.data;              } -            unsafe { -                self.data = self.data.offset(buf.len() as isize); +            #[inline] +            fn offset(&mut self) -> $addr_size { +                (self.data as usize - self.mark as usize) as $addr_size +            } +            #[inline] +            fn total_offset(&mut self) -> $addr_size { +                (self.data as usize - self.start as usize) as $addr_size              } -            Ok(()) -        } else { -            Err(ReadError::ExhaustedInput)          } -    } -    #[inline] -    fn mark(&mut self) { -        self.mark = self.data; -    } -    #[inline] -    fn offset(&mut self) -> u64 { -        self.data as u64 - self.mark as u64 -    } -    #[inline] -    fn total_offset(&mut self) -> u64 { -        self.data as u64 - self.start as u64 +      }  } -impl Reader<u32, u8> for U8Reader<'_> { -    fn next(&mut self) -> Result<u8, ReadError> { -        if self.data == self.end { -            Err(ReadError::ExhaustedInput) -        } else { -            let word = unsafe { core::ptr::read(self.data) }; -            unsafe { -                self.data = self.data.offset(1); -            } -            Ok(word) -        } +macro_rules! u8reader_each_addr_size { +    ($word:ident, $word_from_slice:expr, $words_from_slice:expr) => { +        u8reader_reader_impl!(u64, $word, $word_from_slice, $words_from_slice); +        u8reader_reader_impl!(u32, $word, $word_from_slice, $words_from_slice);      } -    #[inline] -    fn next_n(&mut self, buf: &mut [u8]) -> Result<(), ReadError> { -        if let Some(data_size) = (self.end as usize).checked_sub(self.data as usize) { -            if buf.len() > data_size { -                return Err(ReadError::ExhaustedInput); -            } -            unsafe { -                core::ptr::copy_nonoverlapping(self.data, buf.as_mut_ptr(), buf.len()); -            } -            self.data = unsafe { self.data.offset(buf.len() as isize) }; -            Ok(()) -        } else { -            Err(ReadError::ExhaustedInput) +} +u8reader_each_addr_size!(u8, +    |ptr: *const u8| { unsafe { core::ptr::read(ptr) } }, +    |ptr: *const u8, buf: &mut [u8]| { +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr(), buf.len())          }      } -    fn mark(&mut self) { -        self.mark = self.data; -    } -    fn offset(&mut self) -> u32 { -        self.data as u32 - self.mark as u32 -    } -    fn total_offset(&mut self) -> u32 { -        self.data as u32 - self.start as u32 -    } -} +); -/* -#[derive(Debug, PartialEq, Eq)] -pub struct U16le(pub u16); - -impl Reader<U16le> for &[u8] { -    fn next(&mut self) -> Result<U16le, ReadError> { -        if self.len() < 2 { -            Err(ReadError::ExhaustedInput) -        } else { -            let bytes = [self[0], self[1]]; -            *self = &self[2..]; -            Ok(U16le(u16::from_le_bytes(bytes))) +u8reader_each_addr_size!(U16le, +    |ptr: *const u8| { +        let mut word = [0u8; 2]; +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, word.as_mut_ptr(), word.len()); +        } +        U16le(u16::from_le_bytes(word)) +    }, +    |ptr: *const u8, buf: &mut [U16le]| { +        // `U16le` are layout-identical to u16, so we can just copy into buf +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr() as *mut u8, buf.len() * core::mem::size_of::<U16le>())          }      } -} +); -#[derive(Debug, PartialEq, Eq)] -pub struct U16be(pub u16); - -impl Reader<U16be> for &[u8] { -    fn next(&mut self) -> Result<U16be, ReadError> { -        if self.len() < 2 { -            Err(ReadError::ExhaustedInput) -        } else { -            let bytes = [self[0], self[1]]; -            *self = &self[2..]; -            Ok(U16be(u16::from_be_bytes(bytes))) +u8reader_each_addr_size!(U32le, +    |ptr: *const u8| { +        let mut word = [0u8; 4]; +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, word.as_mut_ptr(), word.len()); +        } +        U32le(u32::from_le_bytes(word)) +    }, +    |ptr: *const u8, buf: &mut [U32le]| { +        // `U32le` are layout-identical to u32, so we can just copy into buf +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr() as *mut u8, buf.len() * core::mem::size_of::<U32le>())          }      } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct U32le(pub u32); +); -impl Reader<U32le> for &[u8] { -    fn next(&mut self) -> Result<U32le, ReadError> { -        if self.len() < 4 { -            Err(ReadError::ExhaustedInput) -        } else { -            let bytes = [self[0], self[1], self[2], self[3]]; -            *self = &self[4..]; -            Ok(U32le(u32::from_le_bytes(bytes))) +u8reader_each_addr_size!(U64le, +    |ptr: *const u8| { +        let mut word = [0u8; 8]; +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, word.as_mut_ptr(), word.len()); +        } +        U64le(u64::from_le_bytes(word)) +    }, +    |ptr: *const u8, buf: &mut [U64le]| { +        // `U64le` are layout-identical to u64, so we can just copy into buf +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr() as *mut u8, buf.len() * core::mem::size_of::<U64le>())          }      } -} +); -#[derive(Debug, PartialEq, Eq)] -pub struct U32be(pub u32); +u8reader_each_addr_size!(U16be, +    |ptr: *const u8| { +        let mut word = [0u8; 2]; +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, word.as_mut_ptr(), word.len()); +        } +        U16be(u16::from_be_bytes(word)) +    }, +    |ptr: *const u8, buf: &mut [U16be]| { +        // `U16be` are layout-identical to u16, so we can just copy into buf +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr() as *mut u8, buf.len() * core::mem::size_of::<U16be>()) +        } -impl Reader<U32be> for &[u8] { -    fn next(&mut self) -> Result<U32be, ReadError> { -        if self.len() < 4 { -            Err(ReadError::ExhaustedInput) -        } else { -            let bytes = [self[0], self[1], self[2], self[3]]; -            *self = &self[4..]; -            Ok(U32be(u32::from_be_bytes(bytes))) +        // but now we have to bswap all the words +        for i in 0..buf.len() { +            buf[i] = U16be(buf[i].0.swap_bytes());          }      } -} +); -#[derive(Debug, PartialEq, Eq)] -pub struct U64le(pub u64); +u8reader_each_addr_size!(U32be, +    |ptr: *const u8| { +        let mut word = [0u8; 4]; +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, word.as_mut_ptr(), word.len()); +        } +        U32be(u32::from_be_bytes(word)) +    }, +    |ptr: *const u8, buf: &mut [U32be]| { +        // `U32be` are layout-identical to u32, so we can just copy into buf +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr() as *mut u8, buf.len() * core::mem::size_of::<U32be>()) +        } -impl Reader<U64le> for &[u8] { -    fn next(&mut self) -> Result<U64le, ReadError> { -        if self.len() < 8 { -            Err(ReadError::ExhaustedInput) -        } else { -            let bytes = [self[0], self[1], self[2], self[3], self[4], self[5], self[6], self[7]]; -            *self = &self[8..]; -            Ok(U64le(u64::from_le_bytes(bytes))) +        // but now we have to bswap all the words +        for i in 0..buf.len() { +            buf[i] = U32be(buf[i].0.swap_bytes());          }      } -} +); -#[derive(Debug, PartialEq, Eq)] -pub struct U64be(pub u64); - -impl Reader<U64be> for &[u8] { -    fn next(&mut self) -> Result<U64be, ReadError> { -        if self.len() < 8 { -            Err(ReadError::ExhaustedInput) -        } else { -            let bytes = [self[0], self[1], self[2], self[3], self[4], self[5], self[6], self[7]]; -            *self = &self[8..]; -            Ok(U64be(u64::from_be_bytes(bytes))) +u8reader_each_addr_size!(U64be, +    |ptr: *const u8| { +        let mut word = [0u8; 8]; +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, word.as_mut_ptr(), word.len()); +        } +        U64be(u64::from_be_bytes(word)) +    }, +    |ptr: *const u8, buf: &mut [U64be]| { +        // `U64be` are layout-identical to u64, so we can just copy into buf +        unsafe { +            core::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr() as *mut u8, buf.len() * core::mem::size_of::<U64be>())          } -    } -} -impl core::fmt::Display for U16le { -    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -        write!(f, "{}", self.0) -    } -} -impl core::fmt::Display for U16be { -    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -        write!(f, "{}", self.0) -    } -} -impl core::fmt::Display for U32le { -    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -        write!(f, "{}", self.0) -    } -} -impl core::fmt::Display for U32be { -    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -        write!(f, "{}", self.0) -    } -} -impl core::fmt::Display for U64le { -    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -        write!(f, "{}", self.0) -    } -} -impl core::fmt::Display for U64be { -    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -        write!(f, "{}", self.0) +        // but now we have to bswap all the words +        for i in 0..buf.len() { +            buf[i] = U64be(buf[i].0.swap_bytes()); +        }      } -} -*/ +); | 
