Skip to content

Commit

Permalink
BinWrite derive doesn't work on structs with generic arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
widberg committed Sep 29, 2023
1 parent ee4c30f commit 161a73b
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 227 deletions.
2 changes: 1 addition & 1 deletion bff/src/bigfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn blocks_parser(
fn pool_parser(objects: &mut HashMap<Name, Object>) -> BinResult<ManifestPool> {
let mut pool = Pool::read_options(reader, endian, ())?;

let object_entry_indices = pool.header.object_descriptions_indices.into();
let object_entry_indices = pool.header.object_descriptions_indices.data;
let object_entries = pool
.header
.object_descriptions
Expand Down
75 changes: 11 additions & 64 deletions bff/src/dynarray.rs
Original file line number Diff line number Diff line change
@@ -1,85 +1,32 @@
use std::fmt::Debug;
use std::marker::PhantomData;

use binrw::{binread, BinRead, BinWrite};
use binrw::{binrw, BinRead, BinWrite};
use derive_more::Deref;
use serde::{Deserialize, Serialize};

#[binread]
#[binrw]
#[derive(Debug, Serialize, Deref, Deserialize)]
#[serde(transparent)]
#[br(import_raw(inner: <InnerType as BinRead>::Args<'_>))]
pub struct DynArray<InnerType: BinRead + 'static, SizeType: BinRead = u32>
pub struct DynArray<InnerType: BinRead + BinWrite + 'static, SizeType: BinRead + BinWrite = u32>
where
for<'a> <InnerType as BinRead>::Args<'a>: Clone + Default,
for<'a> <SizeType as BinRead>::Args<'a>: Default,
SizeType: TryInto<usize>,
<SizeType as TryInto<usize>>::Error: Debug,

for<'a> InnerType: BinWrite<Args<'a> = ()>,
for<'a> SizeType: BinWrite<Args<'a> = ()>,
usize: TryInto<SizeType>,
<usize as TryInto<SizeType>>::Error: Debug,
{
#[br(temp)]
#[bw(ignore)]
#[bw(calc = data.len().try_into().unwrap())]
count: SizeType,
#[deref]
#[br(args { count: count.try_into().unwrap(), inner: inner.clone() })]
data: Vec<InnerType>,
#[br(args { count: count.try_into().unwrap(), inner })]
pub data: Vec<InnerType>,
#[serde(skip)]
_phantom: PhantomData<SizeType>,
}

impl<InnerType: BinWrite + BinRead + 'static, SizeType: BinWrite + BinRead> BinWrite
for DynArray<InnerType, SizeType>
where
for<'a> <InnerType as BinRead>::Args<'a>: Clone + Default,
for<'a> <SizeType as BinRead>::Args<'a>: Default,
SizeType: TryInto<usize>,
<SizeType as TryInto<usize>>::Error: Debug,
for<'a> <InnerType as BinWrite>::Args<'a>: Clone + Default,
for<'a> <SizeType as BinWrite>::Args<'a>: Default,
usize: TryInto<SizeType>,
<usize as TryInto<SizeType>>::Error: Debug,
{
type Args<'a> = <InnerType as BinWrite>::Args<'a>;

fn write_options<R: binrw::io::Write + binrw::io::Seek>(
&self,
reader: &mut R,
endian: binrw::Endian,
_args: Self::Args<'_>,
) -> binrw::BinResult<()> {
SizeType::write_options(
&self.data.len().try_into().unwrap(),
reader,
endian,
<_>::default(),
)?;
Vec::write_options(&self.data, reader, endian, <_>::default())?;
Ok(())
}
}

impl<InnerType: BinRead, SizeType: BinRead> From<DynArray<InnerType, SizeType>> for Vec<InnerType>
where
for<'a> <InnerType as BinRead>::Args<'a>: Clone + Default,
for<'a> <SizeType as BinRead>::Args<'a>: Default,
SizeType: TryInto<usize>,
<SizeType as TryInto<usize>>::Error: Debug,
{
fn from(dynarray: DynArray<InnerType, SizeType>) -> Self {
dynarray.data
}
}

impl<InnerType: BinRead, SizeType: BinRead> From<Vec<InnerType>> for DynArray<InnerType, SizeType>
where
for<'a> <InnerType as BinRead>::Args<'a>: Clone + Default,
for<'a> <SizeType as BinRead>::Args<'a>: Default,
SizeType: TryInto<usize>,
<SizeType as TryInto<usize>>::Error: Debug,
{
fn from(vec: Vec<InnerType>) -> Self {
Self {
data: vec,
_phantom: PhantomData,
}
}
}
8 changes: 4 additions & 4 deletions bff/src/keyframer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub struct KeyframerTpl<TKey>
where
for<'a> TKey: BinRead + BinWrite + Serialize + 'a,
for<'a> <TKey as BinRead>::Args<'a>: Clone + Default,
for<'a> <TKey as BinWrite>::Args<'a>: Clone + Default,
for<'a> TKey: BinWrite<Args<'a> = ()>,
{
interpolation_type: KeyframerInterpolationType,
keyframes: DynArray<TKey>,
Expand All @@ -132,7 +132,7 @@ impl<TKey> BinWrite for KeyframerTpl<TKey>
where
for<'a> TKey: BinRead + BinWrite + Serialize + 'a,
for<'a> <TKey as BinRead>::Args<'a>: Clone + Default,
for<'a> <TKey as BinWrite>::Args<'a>: Clone + Default,
for<'a> TKey: BinWrite<Args<'a> = ()>,
{
type Args<'a> = ();

Expand All @@ -155,7 +155,7 @@ pub struct KeyframerNoFlagsTpl<TKey>
where
for<'a> TKey: BinRead + BinWrite + Serialize + 'a,
for<'a> <TKey as BinRead>::Args<'a>: Clone + Default,
for<'a> <TKey as BinWrite>::Args<'a>: Clone + Default,
for<'a> TKey: BinWrite<Args<'a> = ()>,
{
keyframes: DynArray<TKey>,
}
Expand All @@ -164,7 +164,7 @@ impl<TKey> BinWrite for KeyframerNoFlagsTpl<TKey>
where
for<'a> TKey: BinRead + BinWrite + Serialize + 'a,
for<'a> <TKey as BinRead>::Args<'a>: Clone + Default,
for<'a> <TKey as BinWrite>::Args<'a>: Clone + Default,
for<'a> TKey: BinWrite<Args<'a> = ()>,
{
type Args<'a> = ();

Expand Down
91 changes: 12 additions & 79 deletions bff/src/math.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::io::{Read, Seek, Write};
use std::io::{Read, Seek};
use std::marker::PhantomData;
use std::ops::{Add, Div, Mul, Range, RangeInclusive, Sub};

use binrw::{BinRead, BinResult, BinWrite, Endian};
use binrw::{BinRead, BinWrite, Endian};
use derive_more::{Deref, DerefMut};
use num_traits::{cast, MulAdd, NumCast, PrimInt, Signed, Unsigned};
use serde::{Deserialize, Serialize};
Expand All @@ -28,87 +28,41 @@ pub type Mat3f = Mat<3>;
pub type Mat4f = Mat<4>;

// A fixed precision float with a variable numerator and constant denominator.
#[derive(BinRead, Deref, DerefMut, Debug, Serialize, Deserialize)]
#[derive(BinRead, BinWrite, Deref, DerefMut, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct NumeratorFloat<
T: NumCast + BinRead + BinWrite,
const DENOMINATOR: usize,
F: NumCast + Div<Output = F> + Mul<Output = F> = f32,
F: NumCast + Div<Output = F> + Mul<Output = F> + Copy = f32,
>(
#[deref_mut]
#[deref]
#[br(map = |x: T| cast::<T, F>(x).unwrap() / cast::<usize, F>(DENOMINATOR).unwrap())]
#[bw(map = |x: &F| cast::<F, T>(*x * cast::<usize, F>(DENOMINATOR).unwrap()).unwrap())]
F,
#[serde(skip)] PhantomData<T>,
)
where
for<'a> <T as BinRead>::Args<'a>: Default,
for<'a> <T as BinWrite>::Args<'a>: Clone + Default;

impl<
T: NumCast + BinRead + BinWrite,
const DENOMINATOR: usize,
F: NumCast + Div<Output = F> + Mul<Output = F> + Clone,
> BinWrite for NumeratorFloat<T, DENOMINATOR, F>
where
for<'a> <T as BinRead>::Args<'a>: Default,
for<'a> <T as BinWrite>::Args<'a>: Clone + Default,
{
type Args<'a> = ();

fn write_options<W: Write + Seek>(
&self,
writer: &mut W,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<()> {
cast::<F, T>(self.0.clone() * cast::<usize, F>(DENOMINATOR).unwrap())
.unwrap()
.write_options(writer, endian, <_>::default())
}
}
for<'a> T: BinWrite<Args<'a> = ()>;

// A fixed precision normal float between -1 and 1. (x / x.max_value()) * 2 + -1.
#[derive(BinRead, Deref, DerefMut, Debug, Serialize, Deserialize)]
#[derive(BinRead, BinWrite, Deref, DerefMut, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SignedNormalFloat<
T: NumCast + Div<F, Output = F> + Unsigned + PrimInt + BinRead + BinWrite,
F: NumCast + MulAdd<f32, f32, Output = F> + Signed = f32,
F: NumCast + MulAdd<f32, f32, Output = F> + Signed + Copy = f32,
>(
#[deref_mut]
#[deref]
#[br(map = |x: T| (x / cast::<T, F>(T::max_value()).unwrap()).mul_add(2., -1.))]
#[bw(map = |x: &F| cast::<F, T>((*x + cast::<f32, F>(1.).unwrap()) / cast::<f32, F>(2.).unwrap() * cast::<T, F>(T::max_value()).unwrap()).unwrap())]
F,
#[serde(skip)] PhantomData<T>,
)
where
for<'a> <T as BinRead>::Args<'a>: Default,
for<'a> <T as BinWrite>::Args<'a>: Clone + Default;

impl<
T: NumCast + Div<F, Output = F> + Unsigned + PrimInt + BinRead + BinWrite,
F: NumCast + MulAdd<f32, f32, Output = F> + Signed + Clone,
> BinWrite for SignedNormalFloat<T, F>
where
for<'a> <T as BinRead>::Args<'a>: Default,
for<'a> <T as BinWrite>::Args<'a>: Clone + Default,
{
type Args<'a> = ();

fn write_options<W: Write + Seek>(
&self,
writer: &mut W,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<()> {
cast::<F, T>(
(self.0.clone() + cast::<f32, F>(1.).unwrap()) / cast::<f32, F>(2.).unwrap()
* cast::<T, F>(T::max_value()).unwrap(),
)
.unwrap()
.write_options(writer, endian, <_>::default())
}
}
for<'a> T: BinWrite<Args<'a> = ()>;

// Range whose first element is first and last element is last. [first, last].
// We intentionally use the names first and last instead of begin and end to avoid confusion with
Expand Down Expand Up @@ -212,33 +166,12 @@ pub struct DynBox {
pub name: Name,
}

#[derive(BinRead, Debug, Serialize, Deserialize)]
#[derive(BinRead, BinWrite, Debug, Serialize, Deserialize)]
pub struct Rect<T: BinRead + BinWrite + 'static = i32>
where
for<'a> <T as BinRead>::Args<'a>: Default + Clone,
for<'a> <T as BinWrite>::Args<'a>: Default + Clone,
for<'a> T: BinWrite<Args<'a> = ()>,
{
pub top_left: Vec2<T>,
pub bottom_right: Vec2<T>,
}

impl<T: BinRead + BinWrite + 'static> BinWrite for Rect<T>
where
for<'a> <T as BinRead>::Args<'a>: Default + Clone,
for<'a> <T as BinWrite>::Args<'a>: Default + Clone,
{
type Args<'a> = ();

fn write_options<W: Write + Seek>(
&self,
writer: &mut W,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<()> {
self.top_left
.write_options(writer, endian, <_>::default())?;
self.bottom_right
.write_options(writer, endian, <_>::default())?;
Ok(())
}
}
95 changes: 16 additions & 79 deletions bff/src/option.rs
Original file line number Diff line number Diff line change
@@ -1,93 +1,30 @@
use std::fmt::Debug;
use std::marker::PhantomData;

use binrw::{BinRead, BinResult, BinWrite};
use binrw::{binrw, BinRead, BinWrite};
use derive_more::Deref;
use num_traits::{One, Zero};
use serde::{Deserialize, Serialize};

use crate::Endian;

#[binrw]
#[derive(Serialize, Deref, Debug, Deserialize)]
pub struct BffOption<InnerType, ConditionType = u8> {
pub struct BffOption<
InnerType: BinRead + BinWrite,
ConditionType: BinRead + BinWrite + One + Zero + Eq = u8,
> where
for<'a> <InnerType as BinRead>::Args<'a>: Clone + Default,
for<'a> <ConditionType as BinRead>::Args<'a>: Default,

for<'a> InnerType: BinWrite<Args<'a> = ()>,
for<'a> ConditionType: BinWrite<Args<'a> = ()>,
{
#[br(temp)]
#[bw(calc = if inner.is_some() { ConditionType::one() } else { ConditionType::zero() })]
condition: ConditionType,
#[deref]
#[serde(skip_serializing_if = "Option::is_none")]
#[br(if(condition != ConditionType::zero()))]
inner: Option<InnerType>,
#[serde(skip)]
_phantom: PhantomData<ConditionType>,
}

impl<InnerType: BinRead, ConditionType: BinRead + Zero + Eq> BinRead
for BffOption<InnerType, ConditionType>
where
for<'a> <InnerType as BinRead>::Args<'a>: Default,
for<'a> <ConditionType as BinRead>::Args<'a>: Default,
{
type Args<'a> = ();

fn read_options<R: binrw::io::Read + binrw::io::Seek>(
reader: &mut R,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<Self> {
let condition = ConditionType::read_options(reader, endian, <_>::default())?;
let inner = if condition != ConditionType::zero() {
Some(InnerType::read_options(reader, endian, <_>::default())?)
} else {
None
};
Ok(Self {
inner,
_phantom: PhantomData,
})
}
}

impl<InnerType: BinWrite, ConditionType: BinWrite + Zero + One> BinWrite
for BffOption<InnerType, ConditionType>
where
for<'a> <InnerType as BinWrite>::Args<'a>: Default,
for<'a> <ConditionType as BinWrite>::Args<'a>: Default,
{
type Args<'a> = ();

fn write_options<R: binrw::io::Write + binrw::io::Seek>(
&self,
reader: &mut R,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<()> {
ConditionType::write_options(
&if self.inner.is_some() {
ConditionType::one()
} else {
ConditionType::zero()
},
reader,
endian,
<_>::default(),
)?;
if let Some(data) = &self.inner {
InnerType::write_options(data, reader, endian, <_>::default())?;
}
Ok(())
}
}

impl<InnerType, ConditionType> From<Option<InnerType>> for BffOption<InnerType, ConditionType>
where
for<'a> InnerType: BinRead + BinWrite + Serialize + 'a,
for<'a> <InnerType as BinRead>::Args<'a>: Clone + Default,
for<'a> <InnerType as BinWrite>::Args<'a>: Default,

ConditionType: BinRead + BinWrite + Debug + Copy + PartialEq + One + Zero,
for<'a> <ConditionType as BinRead>::Args<'a>: Default,
for<'a> <ConditionType as BinWrite>::Args<'a>: Default,
{
fn from(inner: Option<InnerType>) -> Self {
Self {
inner,
_phantom: PhantomData,
}
}
}

0 comments on commit 161a73b

Please sign in to comment.