Skip to content

Commit

Permalink
Implement BinRead for all array lengths using const generics.
Browse files Browse the repository at this point in the history
This increases the minimum supported Rust version to 1.51.0.
I sadly had to introduce another unsafe statement, because:
* `Default` is only implemented for array lengths up to 32
  (rust-lang/rust#61415)
* arr_macro doesn't support const generics
  (JoshMcguigan/arr_macro#2)
* Direct initialization via [T; N] adds a trait bound
  `BinRead: Copy`
  • Loading branch information
ColinFinck authored and jam1garner committed Mar 28, 2021
1 parent 18398c3 commit 76ed76c
Showing 1 changed file with 38 additions and 43 deletions.
81 changes: 38 additions & 43 deletions binread/src/binread_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,55 +117,50 @@ impl<C: Copy + 'static, B: BinRead<Args = C>> BinRead for Vec<B> {
}
}

macro_rules! binread_array_impl {
($($size:literal),*$(,)?) => {
$(
impl<C: Copy + 'static, B: BinRead<Args = C> + Default> BinRead for [B; $size] {
type Args = B::Args;
impl<C: Copy + 'static, B: BinRead<Args = C>, const N: usize> BinRead for [B; N] {
type Args = B::Args;

fn read_options<R: Read + Seek>(reader: &mut R, options: &ReadOptions, args: Self::Args) -> BinResult<Self> {
#[cfg(feature = "debug_template")]
{
let pos = reader.seek(SeekFrom::Current(0))?;
let type_name = core::any::type_name::<B>().rsplitn(1, "::").nth(0).unwrap();

if let Some(name) = options.variable_name {
binary_template::write_vec_named(
options.endian, pos, type_name, $size, name
);
} else {
binary_template::write_vec(options.endian, pos, type_name, $size);
}
}
fn read_options<R: Read + Seek>(
reader: &mut R,
options: &ReadOptions,
args: Self::Args,
) -> BinResult<Self> {
#[cfg(feature = "debug_template")]
{
let pos = reader.seek(SeekFrom::Current(0))?;
let type_name = core::any::type_name::<B>().rsplitn(1, "::").nth(0).unwrap();

#[cfg(feature = "debug_template")]
let options = &ReadOptions {
dont_output_to_template: true,
..*options
};

let mut arr: [B; $size] = Default::default();
for elem in arr.iter_mut() {
*elem = BinRead::read_options(reader, options, args)?;
}
Ok(arr)
}
if let Some(name) = options.variable_name {
binary_template::write_vec_named(options.endian, pos, type_name, N, name);
} else {
binary_template::write_vec(options.endian, pos, type_name, N);
}
}

fn after_parse<R>(&mut self, reader: &mut R, ro: &ReadOptions, args: B::Args)-> BinResult<()>
where R: Read + Seek,
{
for val in self.iter_mut() {
val.after_parse(reader, ro, args)?;
}
#[cfg(feature = "debug_template")]
let options = &ReadOptions {
dont_output_to_template: true,
..*options
};

Ok(())
}
}
)*
let mut arr: [B; N] = unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for elem in arr.iter_mut() {
*elem = BinRead::read_options(reader, options, args)?;
}
Ok(arr)
}
}

binread_array_impl!(0, 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);
fn after_parse<R>(&mut self, reader: &mut R, ro: &ReadOptions, args: B::Args) -> BinResult<()>
where
R: Read + Seek,
{
for val in self.iter_mut() {
val.after_parse(reader, ro, args)?;
}

Ok(())
}
}

/// Internal macro to recursively implement BinRead for every size tuple given
/// in the invocation
Expand Down

0 comments on commit 76ed76c

Please sign in to comment.