sharksforarms / deku

Declarative binary reading and writing: bit-level, symmetric, serialization/deserialization
Apache License 2.0
1.14k stars 55 forks source link

write_map or similar to map the value before writing (opposite of map attribute) #231

Open passcod opened 3 years ago

passcod commented 3 years ago

This is the way I write it at the moment:

use deku::prelude::*;
use std::ffi::CString;

#[derive(Clone, Debug, DekuRead, DekuWrite)]
struct Foo {
        #[deku(
            map = "from_nul_terminated",
            writer = "CString::new(handle.to_vec()).unwrap().write(deku::output, ())"
        )]
        handle: Vec<u8>,
}

fn from_nul_terminated(raw: CString) -> Result<Vec<u8>, DekuError> {
    Ok(raw.into_bytes())
}

That works, but requires me to take care to write the correct writer every time (the field mention changes, in particular), and also I can't return an error?

I'd like to do e.g.

use deku::prelude::*;
use std::ffi::CString;

#[derive(Clone, Debug, DekuRead, DekuWrite)]
struct Foo {
        #[deku(
            map = "from_nul_terminated",
            map_write = "to_nul_terminated"
        )]
        handle: Vec<u8>,
}

fn from_nul_terminated(raw: CString) -> Result<Vec<u8>, DekuError> {
    Ok(raw.into_bytes())
}

fn to_nul_terminated(cooked: Vec<u8>) -> Result<CString, DekuError> {
    CString::new(cooked.to_vec()).map_err(...)
}

This is something that pops up for more than nul-terminated things, too, hence the general map_write instead of special-support for nul-termination (though that could be nice); this example is just what I've been struggling through tonight.

sharksforarms commented 3 years ago

I agree, there's some attributes which only make sense for read. I wonder if there's a better way to describe this.