jam1garner / binrw

A Rust crate for helping parse and rebuild binary data using ✨macro magic✨.
https://binrw.rs
MIT License
585 stars 35 forks source link

Add field-level `repr` for bi-directional conversion using `From`/`Into` #92

Closed jam1garner closed 2 years ago

jam1garner commented 2 years ago

For example, NullString <-> String conversion is quite common (as NullString isn't a very useful type in-memory).

Proposed syntax by actioninja:

#[brw(as(NullString))]
name: String,
octylFractal commented 2 years ago

Suggestion: re-use the repr attribute for this purpose. It already partially indicates this type of state.

jam1garner commented 2 years ago

Implementation Instructions:

  1. Since repr($ty) is ultimately desugaring to a mapping (using TryInto to do the mapping from representation-type to in-memory type, or vice-versa) we'll want to add a new way to convert to Map. Our parsing system has a built-in way to do this, just add Repr to the #[from(...)] line and implement From<Repr> for Map. Since we're using TryInto (fallible) we're going to want to have our From implementation convert into a Map::Try.
  2. For the implementation of From, we'll want to use quote!{} in order to generate a closure that looks something like:
    let ty = &field.ty;
    quote! {
    |repr_in| {
        <#ty as core::convert::TryInto>::try_into(repr_in)
            .map_err(|err| ::binrw::Error::ConvertFail { pos: #POS, err: Box::new(err) as Box<dyn CustomError> })
    }
    }
  3. Add the previously mentioned new ConvertFail variant to binrw::Error. I think the only fields it needs are pos (u64) and err (Box<dyn CustomError>), however you're free to think of how that could be changed, and more bikeshedding can be done at review time.
  4. Repeat step number 2 but for write::Repr instead of read::Repr. The closure body will need to be flipped (probably using TryFrom so you can still specify the type since we have that available to us)
dmgolembiowski commented 2 years ago

Does this introduce a naming conflict with binrw/src/io/no_std/error.rs or would these be one in the same?

jam1garner commented 2 years ago

@dmgolembiowski the enum you're referring to is a private implementation detail of that module and is unrelated