Add raw field iterator and with builder method
- Implement RawFieldIterator and ProtoAccessor::raw_fields that yield (field_number, raw_bytes) pairs for each field - Extend Builder with per-field _written flags and add a with() method to copy unseen fields from a source message - Add ProtoBuilder::write_raw to copy pre-encoded field bytes - Add tests for raw-field iteration, verbatim copying, and with()
This commit is contained in:
+59
-14
@@ -257,36 +257,81 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
|
||||
output.push_str(" }\n\n");
|
||||
}
|
||||
}
|
||||
// raw_fields() convenience on the message struct (before closing the impl)
|
||||
output.push_str(" pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {\n");
|
||||
output.push_str(" self.accessor.raw_fields()\n");
|
||||
output.push_str(" }\n\n");
|
||||
output.push_str("}\n\n");
|
||||
|
||||
// Builder
|
||||
output.push_str(&format!(
|
||||
"pub struct {}Builder<'b> {{\n builder: crate::ProtoBuilder<'b>,\n}}\n\nimpl<'b> {}Builder<'b> {{\n",
|
||||
msg_name, msg_name
|
||||
));
|
||||
output.push_str(&format!(
|
||||
" pub fn builder(buf: &mut [u8]) -> {}Builder<'_> {{\n {}Builder {{\n builder: crate::ProtoBuilder::new(buf),\n }}\n }}\n\n",
|
||||
msg_name, msg_name
|
||||
));
|
||||
|
||||
// Collect builder field info so we can use it multiple times below.
|
||||
// Tuple: (field_name, safe_name, tag, rust_type, write_method)
|
||||
let mut builder_fields: Vec<(String, String, u32, String, String)> = Vec::new();
|
||||
for field_res in msg_proto.field() {
|
||||
let (field_data, _) = field_res.expect("Failed to iterate field");
|
||||
let field_proto =
|
||||
FieldDescriptorProto::new(field_data).expect("Failed to parse FieldDescriptorProto");
|
||||
let field_name = field_proto.name().unwrap();
|
||||
let field_name = field_proto.name().unwrap().to_string();
|
||||
let safe_name = if field_name == "type" {
|
||||
format!("r#{}", field_name)
|
||||
} else {
|
||||
field_name.to_string()
|
||||
field_name.clone()
|
||||
};
|
||||
let tag = field_proto.number().unwrap();
|
||||
let f_type = field_proto.r#type().unwrap() as i32;
|
||||
let (rust_type, method) = map_type_to_rust_builder(f_type);
|
||||
builder_fields.push((field_name, safe_name, tag, rust_type, method));
|
||||
}
|
||||
|
||||
// Builder struct — one `_written: bool` flag per field
|
||||
output.push_str(&format!("pub struct {}Builder<'b> {{\n", msg_name));
|
||||
output.push_str(" builder: crate::ProtoBuilder<'b>,\n");
|
||||
for (field_name, _, _, _, _) in &builder_fields {
|
||||
output.push_str(&format!(" {}_written: bool,\n", field_name));
|
||||
}
|
||||
output.push_str(&format!("}}\.\n\nimpl<'b> {}Builder<'b> {{\n", msg_name));
|
||||
|
||||
// Constructor — initialise every flag to false
|
||||
output.push_str(&format!(
|
||||
" pub fn builder(buf: &mut [u8]) -> {}Builder<'_> {{\n {}Builder {{\n",
|
||||
msg_name, msg_name
|
||||
));
|
||||
output.push_str(" builder: crate::ProtoBuilder::new(buf),\n");
|
||||
for (field_name, _, _, _, _) in &builder_fields {
|
||||
output.push_str(&format!(" {}_written: false,\n", field_name));
|
||||
}
|
||||
output.push_str(" }\n }\n\n");
|
||||
|
||||
// Per-field setters — mark field as written
|
||||
for (field_name, safe_name, tag, rust_type, method) in &builder_fields {
|
||||
output.push_str(&format!(
|
||||
" pub fn {}(mut self, value: {}) -> crate::Result<Self> {{\n self.builder.{}({}, value)?;\n Ok(self)\n }}\n\n",
|
||||
safe_name, rust_type, method, tag
|
||||
" pub fn {}(mut self, value: {}) -> crate::Result<Self> {{\n self.builder.{}({}, value)?;\n self.{}_written = true;\n Ok(self)\n }}\n\n",
|
||||
safe_name, rust_type, method, tag, field_name
|
||||
));
|
||||
}
|
||||
|
||||
// with() — copies unseen fields from an existing message
|
||||
output.push_str(&format!(
|
||||
" pub fn with(mut self, msg: &{}<'_>) -> crate::Result<Self> {{\n",
|
||||
msg_name
|
||||
));
|
||||
output.push_str(" for item in msg.raw_fields() {\n");
|
||||
output.push_str(" let (field_number, raw_bytes) = item?;\n");
|
||||
output.push_str(" let is_written = match field_number {\n");
|
||||
for (field_name, _, tag, _, _) in &builder_fields {
|
||||
output.push_str(&format!(
|
||||
" {} => self.{}_written,\n",
|
||||
tag, field_name
|
||||
));
|
||||
}
|
||||
output.push_str(" _ => false,\n");
|
||||
output.push_str(" };\n");
|
||||
output.push_str(" if !is_written {\n");
|
||||
output.push_str(" self.builder.write_raw(raw_bytes)?;\n");
|
||||
output.push_str(" }\n");
|
||||
output.push_str(" }\n");
|
||||
output.push_str(" Ok(self)\n");
|
||||
output.push_str(" }\n\n");
|
||||
|
||||
output.push_str(&format!(" pub fn finish(self) -> crate::Result<&'b mut [u8]> {{\n self.builder.finish()\n }}\n}}\n\n"));
|
||||
|
||||
let mut nested_enums = Vec::new();
|
||||
|
||||
Reference in New Issue
Block a user