binrw
binrw copied to clipboard
Add serde-style `brw(with)` attribute
General idea is providing a module containing both a custom parser and a custom writer function. This would also make it easier to make binrw compatibility crates by allowing you to two generic functions that are custom readers/writers for all types the crate supports to get around orphan rules:
In the compatibility crate (let's call it binrw_3d
, similar to bevy-style 3rd party compatibility crates, basically a binrw crate with common 3d type parsers):
use binrw::{prelude::*, io::*};
trait Supported {
type ReprType: Into<Self> + From<Self> + BinRead + BinWrite;
}
fn read_options<R: Read + Seek, T: Supported>(reader: &mut R, opts: &ReadOptions, args: <T::ReprType as BinRead>::Args) -> BinResult<T> {
<T::ReprType as BinRead>::read_options(reader, opts, args)
}
fn write_options<W: Write + Seek, T: Supported>(
val: &T,
writer: &mut W,
options: &WriteOptions,
args: <T::ReprType as BinWrite>::Args,
) -> BinResult<()> {
<T::ReprType as BinWrite>::write_options(&T::ReprType::from(val), writer, opts)
}
Then for each type that should be supported, make a new struct implement BinRead
/BinWrite
as normal, and implement conversion to and from the type itself. Then all that's needed is:
impl Supported for glam::Vec3 {
type Repr = MyVec3f; // MyVec3f implements BinRead/BinWrite/From<glam::Vec3>/Into<glam::Vec3>
}
And while that's a bit of boilerplate just to make a binrw implementation for a foreign type, all that your crate user needs to do is:
use glam::Vec3;
#[binrw]
struct Vertex {
#[brw(with = binrw_3d)]
position: Vec3,
#[brw(with = binrw_3d)]
position: Quaternion,
}
and the foreign types "just work"
Open Design Questions
Should binrw provide a macro or two to make all the boilerplate above just a single line? Is encouraging 3rd-party utility types worthwhile enough for that? Maybe something like:
use binrw::*;
binrw::conversion_crate!(Supported);
#[binrw(Supported for glam::Vec3)]
struct Vec3 {
x: f32,
y: f32,
z: f32,
}
// impl conversion traits here