From 8eb36fc032d390eceb3df0971484f979cf3b7f4a Mon Sep 17 00:00:00 2001 From: rooooooooob Date: Mon, 31 Jul 2023 22:23:08 -0700 Subject: [PATCH] Optional array fields with preserve-encodings=true --- src/generation.rs | 63 ++++++++++++++++++------- tests/preserve-encodings/input.cddl | 14 +++++- tests/preserve-encodings/tests.rs | 71 +++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 18 deletions(-) diff --git a/src/generation.rs b/src/generation.rs index 0deaccc..9c91949 100644 --- a/src/generation.rs +++ b/src/generation.rs @@ -4408,9 +4408,8 @@ fn generate_array_struct_deserialization( gen_scope.dont_generate_deserialize( name, format!( - "Array struct with potentially-ambiguous optional field {}: {}", - field.name, - field.rust_type.for_rust_member(types, false, cli) + "Array struct with potentially-ambiguous optional field {}: {:?}", + field.name, field.rust_type, ), ); } @@ -4463,6 +4462,39 @@ fn generate_array_struct_deserialization( let type_check_block = Block::new(format!("{before}{type_check_cond}")); let mut type_check_else = Block::new("else"); if cli.annotate_fields { + let enc_fields = if cli.preserve_encodings { + let resolved_rust_type = field.rust_type.clone().resolve_aliases(); + assert!( + !resolved_rust_type.is_fixed_value(), + "https://github.com/dcSpark/cddl-codegen/issues/205" + ); + encoding_fields(types, &field.name, &resolved_rust_type, false, cli) + } else { + vec![] + }; + let (some_map, defaults) = if !enc_fields.is_empty() { + let enc_names_str = enc_fields + .iter() + .map(|enc| enc.field_name.clone()) + .collect::>() + .join(", "); + ( + Cow::from(format!( + "|({}, {})| (Some({}), {})", + field.name, enc_names_str, field.name, enc_names_str + )), + Cow::from(format!( + "(None, {})", + enc_fields + .iter() + .map(|enc| enc.default_expr.to_owned()) + .collect::>() + .join(", ") + )), + ) + } else { + (Cow::from("Some"), Cow::from("None")) + }; gen_scope .generate_deserialize( types, @@ -4473,10 +4505,10 @@ fn generate_array_struct_deserialization( .optional_field(true), cli, ) - .annotate(&field.name, "", ".map(Some)") + .annotate(&field.name, "", &format!(".map({some_map})")) .wrap_in_block(type_check_block) .add_to_code(&mut deser_code); - type_check_else.line("Ok(None)"); + type_check_else.line(format!("Ok({defaults})")); } else { gen_scope .generate_deserialize( @@ -4535,18 +4567,15 @@ fn generate_array_struct_deserialization( encoding_vars_output.push(("tag_encoding".to_owned(), "Some(tag_encoding)".to_owned())); } for field in record.fields.iter() { - // we don't support deserialization for optional fields so don't even bother - if !field.optional { - for field_enc in encoding_fields( - types, - &field.name, - &field.rust_type.clone().resolve_aliases(), - true, - cli, - ) { - encoding_vars_output - .push((field_enc.field_name.clone(), field_enc.field_name.clone())); - } + for field_enc in encoding_fields( + types, + &field.name, + &field.rust_type.clone().resolve_aliases(), + true, + cli, + ) { + encoding_vars_output + .push((field_enc.field_name.clone(), field_enc.field_name.clone())); } } } diff --git a/tests/preserve-encodings/input.cddl b/tests/preserve-encodings/input.cddl index b4cbb20..354b125 100644 --- a/tests/preserve-encodings/input.cddl +++ b/tests/preserve-encodings/input.cddl @@ -76,4 +76,16 @@ default_uint = uint .default 1337 map_with_defaults = { ? 1 : default_uint ? 2 : text .default "two" -} \ No newline at end of file +} + +; TODO: preserve-encodings remembering optional fixed values. Issue: https://github.com/dcSpark/cddl-codegen/issues/205 +array_opt_fields = [ +; ? x: null, + ? a: uint, + ? b: text, + c: nint, + ? d: text, + y: #6.10(1), + ? e: non_overlapping_type_choice_some +; ? z: null, +] \ No newline at end of file diff --git a/tests/preserve-encodings/tests.rs b/tests/preserve-encodings/tests.rs index 7f5016d..056db1b 100644 --- a/tests/preserve-encodings/tests.rs +++ b/tests/preserve-encodings/tests.rs @@ -644,4 +644,75 @@ mod tests { } } } + + #[test] + fn array_opt_fields() { + let def_encodings = vec![Sz::Inline, Sz::One, Sz::Two, Sz::Four, Sz::Eight]; + let str_12_encodings = vec![ + StringLenSz::Len(Sz::One), + StringLenSz::Len(Sz::Inline), + StringLenSz::Indefinite(vec![(5, Sz::Two), (7, Sz::One)]), + StringLenSz::Indefinite(vec![(3, Sz::Inline), (0, Sz::Inline), (9, Sz::Four)]), + ]; + for str_enc in &str_12_encodings { + for def_enc in &def_encodings { + let e_values = [ + None, + Some(NonOverlappingTypeChoiceSome::U64 { + uint: 5, + uint_encoding: Some(*def_enc), + }), + Some(NonOverlappingTypeChoiceSome::N64 { + n64: 4, + n64_encoding: Some(*def_enc), + }), + Some(NonOverlappingTypeChoiceSome::Text { + text: "twelve chars".to_owned(), + text_encoding: str_enc.clone().into(), + }), + ]; + for e in &e_values { + for a in [false, true] { + for b in [false, true] { + for d in [false, true] { + // TODO: preserve-encodings remembering optional fixed values. Issue: https://github.com/dcSpark/cddl-codegen/issues/205 + // for x in [false, true] { + // for z in [false, true] { + let mut components: Vec> = vec![vec![ARR_INDEF]]; + // if x { + // components.push(vec![0xf5]); + // } + if a { + components.push(cbor_int(0, *def_enc)); + } + if b { + components.push(cbor_str_sz("hello, world", str_enc.clone())); + } + // c + components.push(cbor_int(-10, *def_enc)); + if d { + components.push(cbor_str_sz("cddl-codegen", str_enc.clone())); + } + // y + components.push(cbor_tag_sz(10, *def_enc)); + components.push(cbor_int(1, *def_enc)); + if let Some(e) = &e { + components.push(e.to_cbor_bytes()); + } + // if z { + // //components.push(vec![NULL]); + // } + components.push(vec![BREAK]); + let irregular_bytes = components.into_iter().flatten().clone().collect::>(); + let irregular = ArrayOptFields::from_cbor_bytes(&irregular_bytes).unwrap(); + assert_eq!(irregular_bytes, irregular.to_cbor_bytes()); + // } + // } + } + } + } + } + } + } + } }