Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 04ef952a58 | |||
| 05e4c275bb |
@@ -95,6 +95,23 @@ fn build_proto(buf: &mut [u8]) -> roto::Result<&[u8]> {
|
|||||||
Builder methods consume `self` and return `Result<Self>`, enabling `?`-based chaining.
|
Builder methods consume `self` and return `Result<Self>`, enabling `?`-based chaining.
|
||||||
`finish()` returns `Result<&'b mut [u8]>` — a slice of the portion of the buffer that was written.
|
`finish()` returns `Result<&'b mut [u8]>` — a slice of the portion of the buffer that was written.
|
||||||
|
|
||||||
|
### Updating messages
|
||||||
|
|
||||||
|
You can read a message, modify specific fields, and use `.with()` to copy the remaining fields from the original binary.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn update_proto(data: &[u8], buf: &mut [u8]) -> roto::Result<&[u8]> {
|
||||||
|
let msg = Message::new(data)?;
|
||||||
|
|
||||||
|
let mut builder = MessageBuilder::builder(buf);
|
||||||
|
if msg.foo()? == "bar" {
|
||||||
|
builder = builder.foo("foosbar")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.with(&msg)?.finish()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Repeated fields
|
### Repeated fields
|
||||||
|
|
||||||
Repeated fields return a `RepeatedFieldIterator<'a>`. Each item yields `Result<(&[u8], WireType)>`.
|
Repeated fields return a `RepeatedFieldIterator<'a>`. Each item yields `Result<(&[u8], WireType)>`.
|
||||||
|
|||||||
+59
-14
@@ -257,36 +257,81 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
|
|||||||
output.push_str(" }\n\n");
|
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");
|
output.push_str("}\n\n");
|
||||||
|
|
||||||
// Builder
|
// Collect builder field info so we can use it multiple times below.
|
||||||
output.push_str(&format!(
|
// Tuple: (field_name, safe_name, tag, rust_type, write_method)
|
||||||
"pub struct {}Builder<'b> {{\n builder: crate::ProtoBuilder<'b>,\n}}\n\nimpl<'b> {}Builder<'b> {{\n",
|
let mut builder_fields: Vec<(String, String, u32, String, String)> = Vec::new();
|
||||||
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
|
|
||||||
));
|
|
||||||
|
|
||||||
for field_res in msg_proto.field() {
|
for field_res in msg_proto.field() {
|
||||||
let (field_data, _) = field_res.expect("Failed to iterate field");
|
let (field_data, _) = field_res.expect("Failed to iterate field");
|
||||||
let field_proto =
|
let field_proto =
|
||||||
FieldDescriptorProto::new(field_data).expect("Failed to parse FieldDescriptorProto");
|
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" {
|
let safe_name = if field_name == "type" {
|
||||||
format!("r#{}", field_name)
|
format!("r#{}", field_name)
|
||||||
} else {
|
} else {
|
||||||
field_name.to_string()
|
field_name.clone()
|
||||||
};
|
};
|
||||||
let tag = field_proto.number().unwrap();
|
let tag = field_proto.number().unwrap();
|
||||||
let f_type = field_proto.r#type().unwrap() as i32;
|
let f_type = field_proto.r#type().unwrap() as i32;
|
||||||
let (rust_type, method) = map_type_to_rust_builder(f_type);
|
let (rust_type, method) = map_type_to_rust_builder(f_type);
|
||||||
|
builder_fields.push((field_name, safe_name, tag as u32, 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!(
|
output.push_str(&format!(
|
||||||
" pub fn {}(mut self, value: {}) -> crate::Result<Self> {{\n self.builder.{}({}, value)?;\n Ok(self)\n }}\n\n",
|
" 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
|
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"));
|
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();
|
let mut nested_enums = Vec::new();
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
// @generated by protoc-gen-roto — do not edit
|
||||||
|
|
||||||
|
use crate::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
// use crate::google::protobuf::descriptor;
|
use crate::google::protobuf::descriptor;
|
||||||
|
|
||||||
pub struct Version<'a> {
|
pub struct Version<'a> {
|
||||||
accessor: crate::ProtoAccessor<'a>,
|
accessor: crate::ProtoAccessor<'a>,
|
||||||
@@ -58,36 +61,69 @@ suffix_offset,
|
|||||||
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VersionBuilder<'b> {
|
pub struct VersionBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
major_written: bool,
|
||||||
|
minor_written: bool,
|
||||||
|
patch_written: bool,
|
||||||
|
suffix_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> VersionBuilder<'b> {
|
impl<'b> VersionBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
|
||||||
VersionBuilder {
|
VersionBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
major_written: false,
|
||||||
|
minor_written: false,
|
||||||
|
patch_written: false,
|
||||||
|
suffix_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn major(mut self, value: i32) -> crate::Result<Self> {
|
pub fn major(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(1, value)?;
|
self.builder.write_int32(1, value)?;
|
||||||
|
self.major_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn minor(mut self, value: i32) -> crate::Result<Self> {
|
pub fn minor(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(2, value)?;
|
self.builder.write_int32(2, value)?;
|
||||||
|
self.minor_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn patch(mut self, value: i32) -> crate::Result<Self> {
|
pub fn patch(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(3, value)?;
|
self.builder.write_int32(3, value)?;
|
||||||
|
self.patch_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suffix(mut self, value: &str) -> crate::Result<Self> {
|
pub fn suffix(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(4, value)?;
|
self.builder.write_string(4, value)?;
|
||||||
|
self.suffix_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Version<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.major_written,
|
||||||
|
2 => self.minor_written,
|
||||||
|
3 => self.patch_written,
|
||||||
|
4 => self.suffix_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,41 +216,78 @@ compiler_version_offset,
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CodeGeneratorRequestBuilder<'b> {
|
pub struct CodeGeneratorRequestBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
file_to_generate_written: bool,
|
||||||
|
parameter_written: bool,
|
||||||
|
proto_file_written: bool,
|
||||||
|
source_file_descriptors_written: bool,
|
||||||
|
compiler_version_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> CodeGeneratorRequestBuilder<'b> {
|
impl<'b> CodeGeneratorRequestBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
|
||||||
CodeGeneratorRequestBuilder {
|
CodeGeneratorRequestBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
file_to_generate_written: false,
|
||||||
|
parameter_written: false,
|
||||||
|
proto_file_written: false,
|
||||||
|
source_file_descriptors_written: false,
|
||||||
|
compiler_version_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_to_generate(mut self, value: &str) -> crate::Result<Self> {
|
pub fn file_to_generate(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.file_to_generate_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameter(mut self, value: &str) -> crate::Result<Self> {
|
pub fn parameter(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(2, value)?;
|
self.builder.write_string(2, value)?;
|
||||||
|
self.parameter_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn proto_file(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn proto_file(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(15, value)?;
|
self.builder.write_bytes(15, value)?;
|
||||||
|
self.proto_file_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_file_descriptors(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn source_file_descriptors(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(17, value)?;
|
self.builder.write_bytes(17, value)?;
|
||||||
|
self.source_file_descriptors_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compiler_version(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn compiler_version(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(3, value)?;
|
self.builder.write_bytes(3, value)?;
|
||||||
|
self.compiler_version_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &CodeGeneratorRequest<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.file_to_generate_written,
|
||||||
|
2 => self.parameter_written,
|
||||||
|
15 => self.proto_file_written,
|
||||||
|
17 => self.source_file_descriptors_written,
|
||||||
|
3 => self.compiler_version_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,41 +368,78 @@ file_start, file_end,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CodeGeneratorResponseBuilder<'b> {
|
pub struct CodeGeneratorResponseBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
error_written: bool,
|
||||||
|
supported_features_written: bool,
|
||||||
|
minimum_edition_written: bool,
|
||||||
|
maximum_edition_written: bool,
|
||||||
|
file_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> CodeGeneratorResponseBuilder<'b> {
|
impl<'b> CodeGeneratorResponseBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
|
||||||
CodeGeneratorResponseBuilder {
|
CodeGeneratorResponseBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
error_written: false,
|
||||||
|
supported_features_written: false,
|
||||||
|
minimum_edition_written: false,
|
||||||
|
maximum_edition_written: false,
|
||||||
|
file_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(mut self, value: &str) -> crate::Result<Self> {
|
pub fn error(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.error_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn supported_features(mut self, value: u64) -> crate::Result<Self> {
|
pub fn supported_features(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(2, value)?;
|
self.builder.write_varint(2, value)?;
|
||||||
|
self.supported_features_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn minimum_edition(mut self, value: i32) -> crate::Result<Self> {
|
pub fn minimum_edition(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(3, value)?;
|
self.builder.write_int32(3, value)?;
|
||||||
|
self.minimum_edition_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maximum_edition(mut self, value: i32) -> crate::Result<Self> {
|
pub fn maximum_edition(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(4, value)?;
|
self.builder.write_int32(4, value)?;
|
||||||
|
self.maximum_edition_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn file(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(15, value)?;
|
self.builder.write_bytes(15, value)?;
|
||||||
|
self.file_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &CodeGeneratorResponse<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.error_written,
|
||||||
|
2 => self.supported_features_written,
|
||||||
|
3 => self.minimum_edition_written,
|
||||||
|
4 => self.maximum_edition_written,
|
||||||
|
15 => self.file_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,36 +524,69 @@ generated_code_info_offset,
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FileBuilder<'b> {
|
pub struct FileBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
name_written: bool,
|
||||||
|
insertion_point_written: bool,
|
||||||
|
content_written: bool,
|
||||||
|
generated_code_info_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> FileBuilder<'b> {
|
impl<'b> FileBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
|
||||||
FileBuilder {
|
FileBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
name_written: false,
|
||||||
|
insertion_point_written: false,
|
||||||
|
content_written: false,
|
||||||
|
generated_code_info_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.name_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insertion_point(mut self, value: &str) -> crate::Result<Self> {
|
pub fn insertion_point(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(2, value)?;
|
self.builder.write_string(2, value)?;
|
||||||
|
self.insertion_point_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content(mut self, value: &str) -> crate::Result<Self> {
|
pub fn content(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(15, value)?;
|
self.builder.write_string(15, value)?;
|
||||||
|
self.content_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generated_code_info(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn generated_code_info(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(16, value)?;
|
self.builder.write_bytes(16, value)?;
|
||||||
|
self.generated_code_info_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &File<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.name_written,
|
||||||
|
2 => self.insertion_point_written,
|
||||||
|
15 => self.content_written,
|
||||||
|
16 => self.generated_code_info_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,3 +596,4 @@ impl<'b> FileBuilder<'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1309
-10
File diff suppressed because it is too large
Load Diff
+250
@@ -70,41 +70,78 @@ exploit_count_offset,
|
|||||||
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ToolBuilder<'b> {
|
pub struct ToolBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
name_written: bool,
|
||||||
|
version_written: bool,
|
||||||
|
payload_written: bool,
|
||||||
|
is_active_written: bool,
|
||||||
|
exploit_count_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> ToolBuilder<'b> {
|
impl<'b> ToolBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> ToolBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> ToolBuilder<'_> {
|
||||||
ToolBuilder {
|
ToolBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
name_written: false,
|
||||||
|
version_written: false,
|
||||||
|
payload_written: false,
|
||||||
|
is_active_written: false,
|
||||||
|
exploit_count_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.name_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn version(mut self, value: &str) -> crate::Result<Self> {
|
pub fn version(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(2, value)?;
|
self.builder.write_string(2, value)?;
|
||||||
|
self.version_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn payload(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn payload(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(3, value)?;
|
self.builder.write_bytes(3, value)?;
|
||||||
|
self.payload_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_active(mut self, value: u64) -> crate::Result<Self> {
|
pub fn is_active(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(4, value)?;
|
self.builder.write_varint(4, value)?;
|
||||||
|
self.is_active_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exploit_count(mut self, value: i32) -> crate::Result<Self> {
|
pub fn exploit_count(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(5, value)?;
|
self.builder.write_int32(5, value)?;
|
||||||
|
self.exploit_count_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Tool<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.name_written,
|
||||||
|
2 => self.version_written,
|
||||||
|
3 => self.payload_written,
|
||||||
|
4 => self.is_active_written,
|
||||||
|
5 => self.exploit_count_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,41 +216,78 @@ session_key_offset,
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConnectionBuilder<'b> {
|
pub struct ConnectionBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
host_written: bool,
|
||||||
|
port_written: bool,
|
||||||
|
encrypted_written: bool,
|
||||||
|
bandwidth_bps_written: bool,
|
||||||
|
session_key_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> ConnectionBuilder<'b> {
|
impl<'b> ConnectionBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> ConnectionBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> ConnectionBuilder<'_> {
|
||||||
ConnectionBuilder {
|
ConnectionBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
host_written: false,
|
||||||
|
port_written: false,
|
||||||
|
encrypted_written: false,
|
||||||
|
bandwidth_bps_written: false,
|
||||||
|
session_key_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn host(mut self, value: &str) -> crate::Result<Self> {
|
pub fn host(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.host_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn port(mut self, value: i32) -> crate::Result<Self> {
|
pub fn port(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(2, value)?;
|
self.builder.write_int32(2, value)?;
|
||||||
|
self.port_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encrypted(mut self, value: u64) -> crate::Result<Self> {
|
pub fn encrypted(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(3, value)?;
|
self.builder.write_varint(3, value)?;
|
||||||
|
self.encrypted_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bandwidth_bps(mut self, value: u64) -> crate::Result<Self> {
|
pub fn bandwidth_bps(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(4, value)?;
|
self.builder.write_varint(4, value)?;
|
||||||
|
self.bandwidth_bps_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn session_key(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn session_key(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(5, value)?;
|
self.builder.write_bytes(5, value)?;
|
||||||
|
self.session_key_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Connection<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.host_written,
|
||||||
|
2 => self.port_written,
|
||||||
|
3 => self.encrypted_written,
|
||||||
|
4 => self.bandwidth_bps_written,
|
||||||
|
5 => self.session_key_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,61 +414,114 @@ active_connection_offset,
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HackerBuilder<'b> {
|
pub struct HackerBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
handle_written: bool,
|
||||||
|
real_name_written: bool,
|
||||||
|
age_written: bool,
|
||||||
|
skill_level_written: bool,
|
||||||
|
is_elite_written: bool,
|
||||||
|
crew_id_written: bool,
|
||||||
|
exploits_written: bool,
|
||||||
|
tools_written: bool,
|
||||||
|
active_connection_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> HackerBuilder<'b> {
|
impl<'b> HackerBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> HackerBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> HackerBuilder<'_> {
|
||||||
HackerBuilder {
|
HackerBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
handle_written: false,
|
||||||
|
real_name_written: false,
|
||||||
|
age_written: false,
|
||||||
|
skill_level_written: false,
|
||||||
|
is_elite_written: false,
|
||||||
|
crew_id_written: false,
|
||||||
|
exploits_written: false,
|
||||||
|
tools_written: false,
|
||||||
|
active_connection_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(mut self, value: &str) -> crate::Result<Self> {
|
pub fn handle(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.handle_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn real_name(mut self, value: &str) -> crate::Result<Self> {
|
pub fn real_name(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(2, value)?;
|
self.builder.write_string(2, value)?;
|
||||||
|
self.real_name_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn age(mut self, value: i32) -> crate::Result<Self> {
|
pub fn age(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(3, value)?;
|
self.builder.write_int32(3, value)?;
|
||||||
|
self.age_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skill_level(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn skill_level(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(4, value)?;
|
self.builder.write_bytes(4, value)?;
|
||||||
|
self.skill_level_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_elite(mut self, value: u64) -> crate::Result<Self> {
|
pub fn is_elite(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(5, value)?;
|
self.builder.write_varint(5, value)?;
|
||||||
|
self.is_elite_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn crew_id(mut self, value: u64) -> crate::Result<Self> {
|
pub fn crew_id(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(6, value)?;
|
self.builder.write_varint(6, value)?;
|
||||||
|
self.crew_id_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exploits(mut self, value: &str) -> crate::Result<Self> {
|
pub fn exploits(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(7, value)?;
|
self.builder.write_string(7, value)?;
|
||||||
|
self.exploits_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tools(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn tools(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(8, value)?;
|
self.builder.write_bytes(8, value)?;
|
||||||
|
self.tools_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_connection(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn active_connection(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(9, value)?;
|
self.builder.write_bytes(9, value)?;
|
||||||
|
self.active_connection_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Hacker<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.handle_written,
|
||||||
|
2 => self.real_name_written,
|
||||||
|
3 => self.age_written,
|
||||||
|
4 => self.skill_level_written,
|
||||||
|
5 => self.is_elite_written,
|
||||||
|
6 => self.crew_id_written,
|
||||||
|
7 => self.exploits_written,
|
||||||
|
8 => self.tools_written,
|
||||||
|
9 => self.active_connection_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,46 +612,87 @@ targets_start, targets_end,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WormBuilder<'b> {
|
pub struct WormBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
name_written: bool,
|
||||||
|
variant_written: bool,
|
||||||
|
size_bytes_written: bool,
|
||||||
|
payload_written: bool,
|
||||||
|
polymorphic_written: bool,
|
||||||
|
targets_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> WormBuilder<'b> {
|
impl<'b> WormBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> WormBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> WormBuilder<'_> {
|
||||||
WormBuilder {
|
WormBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
name_written: false,
|
||||||
|
variant_written: false,
|
||||||
|
size_bytes_written: false,
|
||||||
|
payload_written: false,
|
||||||
|
polymorphic_written: false,
|
||||||
|
targets_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.name_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variant(mut self, value: i32) -> crate::Result<Self> {
|
pub fn variant(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(2, value)?;
|
self.builder.write_int32(2, value)?;
|
||||||
|
self.variant_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size_bytes(mut self, value: u64) -> crate::Result<Self> {
|
pub fn size_bytes(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(3, value)?;
|
self.builder.write_varint(3, value)?;
|
||||||
|
self.size_bytes_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn payload(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn payload(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(4, value)?;
|
self.builder.write_bytes(4, value)?;
|
||||||
|
self.payload_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn polymorphic(mut self, value: u64) -> crate::Result<Self> {
|
pub fn polymorphic(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(5, value)?;
|
self.builder.write_varint(5, value)?;
|
||||||
|
self.polymorphic_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn targets(mut self, value: &str) -> crate::Result<Self> {
|
pub fn targets(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(6, value)?;
|
self.builder.write_string(6, value)?;
|
||||||
|
self.targets_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Worm<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.name_written,
|
||||||
|
2 => self.variant_written,
|
||||||
|
3 => self.size_bytes_written,
|
||||||
|
4 => self.payload_written,
|
||||||
|
5 => self.polymorphic_written,
|
||||||
|
6 => self.targets_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,61 +819,114 @@ severity_offset,
|
|||||||
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OperationBuilder<'b> {
|
pub struct OperationBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
codename_written: bool,
|
||||||
|
target_corp_written: bool,
|
||||||
|
timestamp_written: bool,
|
||||||
|
successful_written: bool,
|
||||||
|
stolen_data_written: bool,
|
||||||
|
crew_written: bool,
|
||||||
|
worm_written: bool,
|
||||||
|
log_entries_written: bool,
|
||||||
|
severity_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> OperationBuilder<'b> {
|
impl<'b> OperationBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> OperationBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> OperationBuilder<'_> {
|
||||||
OperationBuilder {
|
OperationBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
codename_written: false,
|
||||||
|
target_corp_written: false,
|
||||||
|
timestamp_written: false,
|
||||||
|
successful_written: false,
|
||||||
|
stolen_data_written: false,
|
||||||
|
crew_written: false,
|
||||||
|
worm_written: false,
|
||||||
|
log_entries_written: false,
|
||||||
|
severity_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn codename(mut self, value: &str) -> crate::Result<Self> {
|
pub fn codename(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.codename_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn target_corp(mut self, value: &str) -> crate::Result<Self> {
|
pub fn target_corp(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(2, value)?;
|
self.builder.write_string(2, value)?;
|
||||||
|
self.target_corp_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timestamp(mut self, value: u64) -> crate::Result<Self> {
|
pub fn timestamp(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(3, value)?;
|
self.builder.write_varint(3, value)?;
|
||||||
|
self.timestamp_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn successful(mut self, value: u64) -> crate::Result<Self> {
|
pub fn successful(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(4, value)?;
|
self.builder.write_varint(4, value)?;
|
||||||
|
self.successful_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stolen_data(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn stolen_data(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(5, value)?;
|
self.builder.write_bytes(5, value)?;
|
||||||
|
self.stolen_data_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn crew(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn crew(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(6, value)?;
|
self.builder.write_bytes(6, value)?;
|
||||||
|
self.crew_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn worm(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn worm(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(7, value)?;
|
self.builder.write_bytes(7, value)?;
|
||||||
|
self.worm_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_entries(mut self, value: &str) -> crate::Result<Self> {
|
pub fn log_entries(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(8, value)?;
|
self.builder.write_string(8, value)?;
|
||||||
|
self.log_entries_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn severity(mut self, value: i32) -> crate::Result<Self> {
|
pub fn severity(mut self, value: i32) -> crate::Result<Self> {
|
||||||
self.builder.write_int32(9, value)?;
|
self.builder.write_int32(9, value)?;
|
||||||
|
self.severity_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Operation<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.codename_written,
|
||||||
|
2 => self.target_corp_written,
|
||||||
|
3 => self.timestamp_written,
|
||||||
|
4 => self.successful_written,
|
||||||
|
5 => self.stolen_data_written,
|
||||||
|
6 => self.crew_written,
|
||||||
|
7 => self.worm_written,
|
||||||
|
8 => self.log_entries_written,
|
||||||
|
9 => self.severity_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,31 +987,60 @@ total_bytes_stolen_offset,
|
|||||||
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> {
|
||||||
|
self.accessor.raw_fields()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CampaignBuilder<'b> {
|
pub struct CampaignBuilder<'b> {
|
||||||
builder: crate::ProtoBuilder<'b>,
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
name_written: bool,
|
||||||
|
operations_written: bool,
|
||||||
|
total_bytes_stolen_written: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> CampaignBuilder<'b> {
|
impl<'b> CampaignBuilder<'b> {
|
||||||
pub fn builder(buf: &mut [u8]) -> CampaignBuilder<'_> {
|
pub fn builder(buf: &mut [u8]) -> CampaignBuilder<'_> {
|
||||||
CampaignBuilder {
|
CampaignBuilder {
|
||||||
builder: crate::ProtoBuilder::new(buf),
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
name_written: false,
|
||||||
|
operations_written: false,
|
||||||
|
total_bytes_stolen_written: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
||||||
self.builder.write_string(1, value)?;
|
self.builder.write_string(1, value)?;
|
||||||
|
self.name_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operations(mut self, value: &[u8]) -> crate::Result<Self> {
|
pub fn operations(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
self.builder.write_bytes(2, value)?;
|
self.builder.write_bytes(2, value)?;
|
||||||
|
self.operations_written = true;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_bytes_stolen(mut self, value: u64) -> crate::Result<Self> {
|
pub fn total_bytes_stolen(mut self, value: u64) -> crate::Result<Self> {
|
||||||
self.builder.write_varint(3, value)?;
|
self.builder.write_varint(3, value)?;
|
||||||
|
self.total_bytes_stolen_written = true;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(mut self, msg: &Campaign<'_>) -> crate::Result<Self> {
|
||||||
|
for item in msg.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item?;
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => self.name_written,
|
||||||
|
2 => self.operations_written,
|
||||||
|
3 => self.total_bytes_stolen_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
self.builder.write_raw(raw_bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+158
@@ -236,6 +236,17 @@ impl<'a> ProtoAccessor<'a> {
|
|||||||
) -> RepeatedFieldIterator<'a> {
|
) -> RepeatedFieldIterator<'a> {
|
||||||
RepeatedFieldIterator::new_range(self.data, field_number, start, end)
|
RepeatedFieldIterator::new_range(self.data, field_number, start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator that yields `(field_number, raw_bytes)` for every
|
||||||
|
/// field in the message. `raw_bytes` is the complete on-wire encoding
|
||||||
|
/// (tag + value, including any length prefix), suitable for passing
|
||||||
|
/// directly to `ProtoBuilder::write_raw`.
|
||||||
|
pub fn raw_fields(&self) -> RawFieldIterator<'a> {
|
||||||
|
RawFieldIterator {
|
||||||
|
data: self.data,
|
||||||
|
cursor: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FieldIterator<'a> {
|
pub struct FieldIterator<'a> {
|
||||||
@@ -346,6 +357,48 @@ impl<'a> Iterator for RepeatedFieldIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator that yields `(field_number, raw_bytes)` for every field in a
|
||||||
|
/// protobuf message, where `raw_bytes` is the complete on-wire encoding of the
|
||||||
|
/// field: tag varint + value bytes (including the length prefix for
|
||||||
|
/// length-delimited fields). This is the slice needed by
|
||||||
|
/// `ProtoBuilder::write_raw` to copy a field verbatim.
|
||||||
|
pub struct RawFieldIterator<'a> {
|
||||||
|
data: &'a [u8],
|
||||||
|
cursor: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for RawFieldIterator<'a> {
|
||||||
|
type Item = Result<(u32, &'a [u8])>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.cursor >= self.data.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let field_start = self.cursor;
|
||||||
|
let (tag, tag_len) = match Tag::decode(&self.data[self.cursor..]) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(e) => {
|
||||||
|
self.cursor = self.data.len();
|
||||||
|
return Some(Err(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let cursor_after_tag = self.cursor + tag_len;
|
||||||
|
if cursor_after_tag > self.data.len() {
|
||||||
|
self.cursor = self.data.len();
|
||||||
|
return Some(Err(RotoError::UnexpectedEndOfBuffer));
|
||||||
|
}
|
||||||
|
let value_len = match skip_value(tag.wire_type, &self.data[cursor_after_tag..]) {
|
||||||
|
Ok(l) => l,
|
||||||
|
Err(e) => {
|
||||||
|
self.cursor = self.data.len();
|
||||||
|
return Some(Err(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.cursor = cursor_after_tag + value_len;
|
||||||
|
Some(Ok((tag.field_number, &self.data[field_start..self.cursor])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -455,6 +508,104 @@ mod tests {
|
|||||||
assert_eq!(result, Err(RotoError::BufferOverflow));
|
assert_eq!(result, Err(RotoError::BufferOverflow));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_raw_field_iterator_yields_correct_bytes() {
|
||||||
|
// Build: field 1 = string "hi", field 2 = int32 42
|
||||||
|
let mut buf = [0u8; 64];
|
||||||
|
let mut builder = ProtoBuilder::new(&mut buf);
|
||||||
|
builder.write_string(1, "hi").unwrap();
|
||||||
|
builder.write_int32(2, 42).unwrap();
|
||||||
|
let data = builder.finish().unwrap().to_vec();
|
||||||
|
|
||||||
|
let acc = ProtoAccessor::new(&data).unwrap();
|
||||||
|
let raw: Vec<_> = acc.raw_fields().collect();
|
||||||
|
assert_eq!(raw.len(), 2);
|
||||||
|
|
||||||
|
// Field 1: tag = (1 << 3) | 2 = 0x0A, len varint = 0x02, "hi" = [0x68, 0x69]
|
||||||
|
let (fn1, bytes1) = raw[0].as_ref().unwrap();
|
||||||
|
assert_eq!(*fn1, 1);
|
||||||
|
assert_eq!(*bytes1, [0x0A, 0x02, b'h', b'i']);
|
||||||
|
|
||||||
|
// Field 2: tag = (2 << 3) | 0 = 0x10, varint 42 = 0x2A
|
||||||
|
let (fn2, bytes2) = raw[1].as_ref().unwrap();
|
||||||
|
assert_eq!(*fn2, 2);
|
||||||
|
assert_eq!(*bytes2, [0x10, 0x2A]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_raw_copies_field_verbatim() {
|
||||||
|
// Build source: field 1 = string "hello", field 2 = int32 99
|
||||||
|
let mut src_buf = [0u8; 64];
|
||||||
|
let mut src_builder = ProtoBuilder::new(&mut src_buf);
|
||||||
|
src_builder.write_string(1, "hello").unwrap();
|
||||||
|
src_builder.write_int32(2, 99).unwrap();
|
||||||
|
let src_data = src_builder.finish().unwrap().to_vec();
|
||||||
|
|
||||||
|
// Copy every raw field verbatim into a new buffer
|
||||||
|
let src_acc = ProtoAccessor::new(&src_data).unwrap();
|
||||||
|
let mut dst_buf = [0u8; 64];
|
||||||
|
let mut dst_builder = ProtoBuilder::new(&mut dst_buf);
|
||||||
|
for item in src_acc.raw_fields() {
|
||||||
|
let (_, raw_bytes) = item.unwrap();
|
||||||
|
dst_builder.write_raw(raw_bytes).unwrap();
|
||||||
|
}
|
||||||
|
let dst_data = dst_builder.finish().unwrap();
|
||||||
|
|
||||||
|
// The copy must be byte-identical to the source
|
||||||
|
assert_eq!(dst_data, src_data.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_with_pattern_copies_unseen_fields() {
|
||||||
|
// Build an existing source message with 3 fields
|
||||||
|
let mut src_buf = [0u8; 128];
|
||||||
|
let mut src_builder = ProtoBuilder::new(&mut src_buf);
|
||||||
|
src_builder.write_string(1, "original").unwrap();
|
||||||
|
src_builder.write_int32(2, 99).unwrap();
|
||||||
|
src_builder.write_varint(3, 1u64).unwrap(); // bool
|
||||||
|
let src_data = src_builder.finish().unwrap().to_vec();
|
||||||
|
let src_acc = ProtoAccessor::new(&src_data).unwrap();
|
||||||
|
|
||||||
|
// Simulate what a generated `with` method does:
|
||||||
|
// field 1 was explicitly written; fields 2 and 3 come from source.
|
||||||
|
let field1_written = true;
|
||||||
|
let field2_written = false;
|
||||||
|
let field3_written = false;
|
||||||
|
|
||||||
|
let mut dst_buf = [0u8; 128];
|
||||||
|
let mut dst_builder = ProtoBuilder::new(&mut dst_buf);
|
||||||
|
dst_builder.write_string(1, "updated").unwrap();
|
||||||
|
|
||||||
|
for item in src_acc.raw_fields() {
|
||||||
|
let (field_number, raw_bytes) = item.unwrap();
|
||||||
|
let is_written = match field_number {
|
||||||
|
1 => field1_written,
|
||||||
|
2 => field2_written,
|
||||||
|
3 => field3_written,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_written {
|
||||||
|
dst_builder.write_raw(raw_bytes).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dst_data = dst_builder.finish().unwrap();
|
||||||
|
let dst_acc = ProtoAccessor::new(dst_data).unwrap();
|
||||||
|
|
||||||
|
// Field 1: overridden value
|
||||||
|
let (val1, _) = dst_acc.get_value(1).unwrap();
|
||||||
|
assert_eq!(val1, b"updated");
|
||||||
|
|
||||||
|
// Field 2: copied from source
|
||||||
|
let (val2, _) = dst_acc.get_value(2).unwrap();
|
||||||
|
let (v2, _) = read_varint(val2).unwrap();
|
||||||
|
assert_eq!(v2 as i32, 99);
|
||||||
|
|
||||||
|
// Field 3: copied from source
|
||||||
|
let (val3, _) = dst_acc.get_value(3).unwrap();
|
||||||
|
let (v3, _) = read_varint(val3).unwrap();
|
||||||
|
assert_eq!(v3, 1u64);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_protoc_binary_compatibility() {
|
fn test_protoc_binary_compatibility() {
|
||||||
let data = include_bytes!("../data/test_data.pb");
|
let data = include_bytes!("../data/test_data.pb");
|
||||||
@@ -618,6 +769,13 @@ impl<'a> ProtoBuilder<'a> {
|
|||||||
self.append_bytes(value)
|
self.append_bytes(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a pre-encoded field (tag + value bytes) verbatim into the
|
||||||
|
/// buffer. Use this together with `ProtoAccessor::raw_fields` to copy
|
||||||
|
/// fields from an existing message into a builder without re-encoding them.
|
||||||
|
pub fn write_raw(&mut self, raw_bytes: &[u8]) -> Result<()> {
|
||||||
|
self.append_bytes(raw_bytes)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'a mut [u8]> {
|
pub fn finish(self) -> Result<&'a mut [u8]> {
|
||||||
Ok(&mut self.buf[..self.pos])
|
Ok(&mut self.buf[..self.pos])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
use roto::generator::generate_rust_code;
|
||||||
|
use roto::google::protobuf::compiler::plugin::CodeGeneratorRequest;
|
||||||
|
use roto::google::protobuf::descriptor::FileDescriptorSet;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
fn load_generated_code() -> String {
|
||||||
|
let data = fs::read("data/request.bin").expect("Failed to read data/request.bin");
|
||||||
|
let request = CodeGeneratorRequest::new(&data).expect("Failed to parse CodeGeneratorRequest");
|
||||||
|
|
||||||
|
let mut set_buf = Vec::new();
|
||||||
|
for file_res in request.proto_file() {
|
||||||
|
let (file_data, _) = file_res.expect("Failed to iterate proto_file");
|
||||||
|
set_buf.push(10u8);
|
||||||
|
let len = file_data.len() as u64;
|
||||||
|
let mut len_buf = [0u8; 10];
|
||||||
|
let len_size = roto::write_varint(len, &mut len_buf).unwrap();
|
||||||
|
set_buf.extend_from_slice(&len_buf[..len_size]);
|
||||||
|
set_buf.extend_from_slice(file_data);
|
||||||
|
}
|
||||||
|
let set = FileDescriptorSet::new(&set_buf).expect("Failed to create FileDescriptorSet");
|
||||||
|
|
||||||
|
generate_rust_code(&set, None, false)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, content)| content)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builder_structs_have_written_flags() {
|
||||||
|
let code = load_generated_code();
|
||||||
|
assert!(
|
||||||
|
code.contains("_written: bool"),
|
||||||
|
"Builder structs should contain `_written: bool` fields for each proto field"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builder_constructor_initialises_written_flags_to_false() {
|
||||||
|
let code = load_generated_code();
|
||||||
|
assert!(
|
||||||
|
code.contains("_written: false"),
|
||||||
|
"Builder constructors should initialise every `_written` flag to false"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builder_setters_mark_field_as_written() {
|
||||||
|
let code = load_generated_code();
|
||||||
|
assert!(
|
||||||
|
code.contains("_written = true"),
|
||||||
|
"Each builder setter should set its `_written` flag to true"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builder_has_with_method() {
|
||||||
|
let code = load_generated_code();
|
||||||
|
assert!(
|
||||||
|
code.contains("pub fn with("),
|
||||||
|
"Each builder impl should expose a `with` method"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_message_structs_have_raw_fields_method() {
|
||||||
|
let code = load_generated_code();
|
||||||
|
assert!(
|
||||||
|
code.contains("pub fn raw_fields("),
|
||||||
|
"Each message struct impl should expose a `raw_fields` method"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_with_method_uses_write_raw() {
|
||||||
|
let code = load_generated_code();
|
||||||
|
assert!(
|
||||||
|
code.contains("write_raw(raw_bytes)"),
|
||||||
|
"The `with` method should call `write_raw` to copy field bytes"
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user