Skip to content

Commit

Permalink
Only map parse_with result type if field is not also mapped
Browse files Browse the repository at this point in the history
Fixes #239.

(cherry picked from commit 5ee621a)
  • Loading branch information
csnover committed Nov 26, 2023
1 parent 7b52b46 commit 62b411f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 5 deletions.
30 changes: 30 additions & 0 deletions binrw/tests/derive/struct_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ fn map_expr() {
assert_eq!(result.a, 2);
}

#[test]
fn map_field_parse_with() {
#[derive(BinRead, Debug)]
#[br(big)]
pub struct Test {
#[br(parse_with = binrw::helpers::until_eof, map = |v: Vec<u8>| String::from_utf8_lossy(&v).to_string())]
a: String,
}

let result = Test::read(&mut Cursor::new(b"debug\xe2\x98\xba")).unwrap();
assert_eq!(result.a, "debug☺");
let result = Test::read(&mut Cursor::new(b"bad \xfe utf8 \xfe")).unwrap();
assert_eq!(result.a, "bad \u{FFFD} utf8 \u{FFFD}");
}

#[test]
fn map_repr_enum() {
#[derive(BinRead, Debug, PartialEq)]
Expand Down Expand Up @@ -171,6 +186,21 @@ fn try_map_field() {
.expect("wrong error type");
}

#[test]
fn try_map_field_parse_with() {
#[derive(BinRead, Debug)]
#[br(big)]
pub struct Test {
#[br(parse_with = binrw::helpers::until_eof, try_map = String::from_utf8)]
a: String,
}

let result = Test::read(&mut Cursor::new(b"debug\xe2\x98\xba")).unwrap();
assert_eq!(result.a, "debug☺");
let error = Test::read(&mut Cursor::new(b"bad \xfe utf8 \xfe")).expect_err("accepted bad data");
error.custom_err::<std::string::FromUtf8Error>().unwrap();
}

#[test]
fn try_map_struct() {
#[derive(BinRead, Debug)]
Expand Down
16 changes: 11 additions & 5 deletions binrw_derive/src/binrw/codegen/read_options/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,20 @@ impl<'field> FieldGenerator<'field> {

if let FieldMode::Function(f) = read_mode {
let ty = &self.field.ty;
// Mapping the value with an explicit type ensures the
// incompatible type is warned here as a mismatched type
// instead of later as a try-conversion error
let map = self.field.map.is_none().then(|| {
quote_spanned! { f.span()=>
.map(|v| -> #ty { v })
}
});

// Adding a closure suppresses mentions of the generated
// READ_FUNCTION variable in errors; mapping the value with
// an explicit type ensures the incompatible type is warned
// here as a mismatched type instead of later as a
// try-conversion error
// READ_FUNCTION variable in errors
quote_spanned_any! { f.span()=>
(|| #READ_FUNCTION)()(#reader_var, #endian_var, #args_arg)
.map(|v| -> #ty { v })
#map
}
} else {
quote! {
Expand Down

0 comments on commit 62b411f

Please sign in to comment.