From 62b411f1de77d2b297e163e3831e6a34569f59cc Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Sun, 26 Nov 2023 01:00:38 -0600 Subject: [PATCH] Only map `parse_with` result type if field is not also mapped Fixes jam1garner/binrw#239. (cherry picked from commit 5ee621a5eea5058d2b97e7d5c445dc9ae6aa8ac5) --- binrw/tests/derive/struct_map.rs | 30 +++++++++++++++++++ .../src/binrw/codegen/read_options/struct.rs | 16 ++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/binrw/tests/derive/struct_map.rs b/binrw/tests/derive/struct_map.rs index 3e586622..b15070ab 100644 --- a/binrw/tests/derive/struct_map.rs +++ b/binrw/tests/derive/struct_map.rs @@ -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| 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)] @@ -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::().unwrap(); +} + #[test] fn try_map_struct() { #[derive(BinRead, Debug)] diff --git a/binrw_derive/src/binrw/codegen/read_options/struct.rs b/binrw_derive/src/binrw/codegen/read_options/struct.rs index 7358d177..a1abe71f 100644 --- a/binrw_derive/src/binrw/codegen/read_options/struct.rs +++ b/binrw_derive/src/binrw/codegen/read_options/struct.rs @@ -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! {