From bccfe12102ec3f1d6f2b68fbcfaf62d092ba6416 Mon Sep 17 00:00:00 2001 From: Jian Yang Date: Fri, 4 Jul 2025 15:03:36 +0800 Subject: [PATCH] feat: Add Builder::emit_struct_field_null to output null --- pbjson-build/src/generator/message.rs | 21 +++++++++++++++++++++ pbjson-build/src/lib.rs | 8 ++++++++ 2 files changed, 29 insertions(+) diff --git a/pbjson-build/src/generator/message.rs b/pbjson-build/src/generator/message.rs index 2822f56..f5a90c7 100644 --- a/pbjson-build/src/generator/message.rs +++ b/pbjson-build/src/generator/message.rs @@ -42,6 +42,7 @@ pub fn generate_message( btree_map_paths: &[String], emit_fields: bool, preserve_proto_field_names: bool, + emit_struct_fields_null: bool, ) -> Result<()> { let rust_type = resolver.rust_type(&message.path); @@ -54,6 +55,7 @@ pub fn generate_message( writer, emit_fields, preserve_proto_field_names, + emit_struct_fields_null, )?; write_serialize_end(0, writer)?; @@ -116,6 +118,7 @@ fn write_message_serialize( writer: &mut W, emit_fields: bool, preserve_proto_field_names: bool, + emit_struct_fields_null: bool, ) -> Result<()> { write_struct_serialize_start(indent, message, writer, emit_fields)?; @@ -127,6 +130,7 @@ fn write_message_serialize( writer, emit_fields, preserve_proto_field_names, + emit_struct_fields_null, )?; } @@ -404,6 +408,7 @@ fn write_serialize_field( writer: &mut W, emit_fields: bool, preserve_proto_field_names: bool, + emit_struct_fields_null: bool, ) -> Result<()> { let as_ref = format!("&self.{}", field.rust_field_name()); let variable = Variable { @@ -443,6 +448,22 @@ fn write_serialize_field( writer, preserve_proto_field_names, )?; + if emit_struct_fields_null { + writeln!(writer, "{}}} else {{", Indent(indent))?; + + let json_name = field.json_name(); + let field_name = if preserve_proto_field_names { + field.name.as_str() + } else { + json_name.as_str() + }; + writeln!( + writer, + "{}struct_ser.serialize_field(\"{}\", &None::>)?;", + Indent(indent + 1), + field_name, + )?; + } writeln!(writer, "{}}}", Indent(indent))?; } FieldModifier::Repeated | FieldModifier::UseDefault => { diff --git a/pbjson-build/src/lib.rs b/pbjson-build/src/lib.rs index 912bbee..4fcc901 100644 --- a/pbjson-build/src/lib.rs +++ b/pbjson-build/src/lib.rs @@ -108,6 +108,7 @@ pub struct Builder { emit_fields: bool, use_integers_for_enums: bool, preserve_proto_field_names: bool, + emit_struct_field_null: bool, } impl Builder { @@ -200,6 +201,12 @@ impl Builder { self } + /// Output optional struct fields with None value as "null", instead of omitted. + pub fn emit_struct_field_null(&mut self) -> &mut Self { + self.emit_struct_field_null = true; + self + } + /// Generates code for all registered types where `prefixes` contains a prefix of /// the fully-qualified path of the type pub fn build>(&mut self, prefixes: &[S]) -> Result<()> { @@ -289,6 +296,7 @@ impl Builder { &self.btree_map_paths, self.emit_fields, self.preserve_proto_field_names, + self.emit_struct_field_null, )? } }