From a82242225bdfb376935d9ecdcac4cd112fd97a21 Mon Sep 17 00:00:00 2001 From: Renar Narubin Date: Mon, 3 Oct 2022 14:41:20 -0700 Subject: [PATCH] feat: Accept proto field name when deserializing For message fields, the proto3 json specification requires parsers to accept both lowerCamelCase names and the original proto field names. This change adapts the deserialization code-gen to accept the proto name. --- pbjson-build/src/generator/message.rs | 45 ++++++++++++++++++++------- pbjson-test/src/lib.rs | 10 ++++++ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/pbjson-build/src/generator/message.rs b/pbjson-build/src/generator/message.rs index 4fd13fd..f5fc404 100644 --- a/pbjson-build/src/generator/message.rs +++ b/pbjson-build/src/generator/message.rs @@ -610,14 +610,26 @@ fn write_deserialize_field_name( ) -> Result<()> { let fields: Vec<_> = message .all_fields() - .map(|field| (field.json_name(), field.rust_type_name())) + .map(|field| { + let json_name = field.json_name(); + // only carry the original proto name if it's different from the provided json name + let proto_name = + Some(field.name.as_str()).filter(|proto_name| proto_name != &json_name); + (json_name, field.rust_type_name(), proto_name) + }) .collect(); - write_fields_array(writer, indent, fields.iter().map(|(name, _)| name.as_str()))?; + write_fields_array( + writer, + indent, + fields.iter().flat_map(|(json_name, _, proto_name)| { + proto_name.iter().copied().chain([json_name.as_str()]) + }), + )?; write_fields_enum( writer, indent, - fields.iter().map(|(_, name)| name.as_str()), + fields.iter().map(|(_, type_name, _)| type_name.as_str()), ignore_unknown_fields, )?; @@ -647,14 +659,25 @@ fn write_deserialize_field_name( if !fields.is_empty() { writeln!(writer, "{}match value {{", Indent(indent + 4))?; - for (json_name, type_name) in &fields { - writeln!( - writer, - "{}\"{}\" => Ok(GeneratedField::{}),", - Indent(indent + 5), - json_name, - type_name - )?; + for (json_name, type_name, proto_name) in &fields { + if let Some(proto_name) = proto_name { + writeln!( + writer, + "{}\"{}\" | \"{}\" => Ok(GeneratedField::{}),", + Indent(indent + 5), + json_name, + proto_name, + type_name + )?; + } else { + writeln!( + writer, + "{}\"{}\" => Ok(GeneratedField::{}),", + Indent(indent + 5), + json_name, + type_name + )?; + } } if ignore_unknown_fields { writeln!( diff --git a/pbjson-test/src/lib.rs b/pbjson-test/src/lib.rs index f4a22a8..7954e1d 100644 --- a/pbjson-test/src/lib.rs +++ b/pbjson-test/src/lib.rs @@ -149,6 +149,7 @@ mod tests { // Can also decode from string verify_decode(&decoded, r#"{"optionalI32":"0"}"#); + verify_decode(&decoded, r#"{"optional_i32":"0"}"#); decoded.optional_i32 = None; verify_decode(&decoded, "{}"); @@ -168,6 +169,7 @@ mod tests { // Can also decode from non-string verify_decode(&decoded, r#"{"optionalI64":0}"#); + verify_decode(&decoded, r#"{"optional_i64":0}"#); decoded.optional_i64 = None; verify_decode(&decoded, "{}"); @@ -191,6 +193,7 @@ mod tests { verify(&decoded, r#"{"repeatedI32":[0,23,5,6,2,34]}"#); // Can also mix in some strings verify_decode(&decoded, r#"{"repeatedI32":[0,"23",5,6,"2",34]}"#); + verify_decode(&decoded, r#"{"repeated_i32":[0,"23",5,6,"2",34]}"#); decoded.repeated_i32 = vec![]; verify_decode(&decoded, "{}"); @@ -199,6 +202,7 @@ mod tests { verify(&decoded, r#"{"repeatedU64":["0","532","2"]}"#); // Can also mix in some non-strings verify_decode(&decoded, r#"{"repeatedU64":["0",532,"2"]}"#); + verify_decode(&decoded, r#"{"repeated_u64":["0",532,"2"]}"#); decoded.repeated_u64 = vec![]; verify_decode(&decoded, "{}"); @@ -218,6 +222,7 @@ mod tests { // Can also use variant number verify_decode(&decoded, r#"{"optionalValue":0}"#); + verify_decode(&decoded, r#"{"optional_value":0}"#); decoded.optional_value = None; verify_decode(&decoded, "{}"); @@ -238,6 +243,7 @@ mod tests { verify(&decoded, r#"{"int32Dict":{"343":"A"}}"#); // Enum dictionary values can be decoded from integers verify_decode(&decoded, r#"{"int32Dict":{"343":66}}"#); + verify_decode(&decoded, r#"{"int32_dict":{"343":66}}"#); decoded.int32_dict = Default::default(); verify_decode(&decoded, "{}"); @@ -247,6 +253,7 @@ mod tests { verify(&decoded, r#"{"integerDict":{"12":"13"}}"#); // 64-bit dictionary values can be decoded from numeric types verify_decode(&decoded, r#"{"integerDict":{"12":13}}"#); + verify_decode(&decoded, r#"{"integer_dict":{"12":13}}"#); decoded.integer_dict = Default::default(); verify_decode(&decoded, "{}"); @@ -255,6 +262,7 @@ mod tests { verify(&decoded, r#"{"oneOfI32":0}"#); // Can also specify string verify_decode(&decoded, r#"{"oneOfI32":"0"}"#); + verify_decode(&decoded, r#"{"one_of_i32":"0"}"#); decoded.one_of = Some(kitchen_sink::OneOf::OneOfI32(12)); verify(&decoded, r#"{"oneOfI32":12}"#); @@ -271,6 +279,7 @@ mod tests { verify(&decoded, r#"{"oneOfValue":"VALUE_B"}"#); // Can also specify enum variant verify_decode(&decoded, r#"{"oneOfValue":63}"#); + verify_decode(&decoded, r#"{"one_of_value":63}"#); decoded.one_of = None; verify_decode(&decoded, "{}"); @@ -285,6 +294,7 @@ mod tests { r#"{"repeatedValue":["VALUE_B","VALUE_B","VALUE_A"]}"#, ); verify_decode(&decoded, r#"{"repeatedValue":[63,"VALUE_B","VALUE_A"]}"#); + verify_decode(&decoded, r#"{"repeated_value":[63,"VALUE_B","VALUE_A"]}"#); decoded.repeated_value = Default::default(); verify_decode(&decoded, "{}");