Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 858c6968d4 | |||
| 7fbea70860 | |||
| a4fa72c819 | |||
| 22c4e17e9f | |||
| 87b111faf5 | |||
| d9be36726f | |||
| 74d975788b | |||
| 20e4fb909b | |||
| a2a5c12235 | |||
| b73cbb3dbc | |||
| 38367227ed |
@@ -0,0 +1,19 @@
|
|||||||
|
## Ask for clarification
|
||||||
|
|
||||||
|
Unless the request is extremely clear, assemble a list of questions up front. After you begin work,
|
||||||
|
you should be able to work without user assistance.
|
||||||
|
|
||||||
|
## Coding
|
||||||
|
|
||||||
|
If you are writing code, write tests first. The tests must pass for your work to be complete.
|
||||||
|
|
||||||
|
## Special instructions
|
||||||
|
|
||||||
|
### Fork
|
||||||
|
|
||||||
|
If the users asks you to fork off and work on something, this means that you should:
|
||||||
|
|
||||||
|
1. Create a temporary directory using `mktemp -d`
|
||||||
|
2. Create a new branch to work on
|
||||||
|
3. Use git worktree to extract that branch to the temporary directory (i.e., `git worktree add $TMP_DIR -- $BRANCH)
|
||||||
|
4. Work from that directory (i.e., `cd $TMP_DIR`)
|
||||||
+16
-4
@@ -1,5 +1,7 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use roto::proto_gen::google::protobuf::descriptor::FileDescriptorSet;
|
use roto::google::protobuf::descriptor::{
|
||||||
|
FileDescriptorSet
|
||||||
|
};
|
||||||
use roto::generator::generate_rust_code;
|
use roto::generator::generate_rust_code;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -11,9 +13,13 @@ struct Args {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
input: PathBuf,
|
input: PathBuf,
|
||||||
|
|
||||||
/// Path to the output Rust file (.rs)
|
/// Path to the output directory
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
output: PathBuf,
|
output: PathBuf,
|
||||||
|
|
||||||
|
/// Files to generate. If omitted, all files are generated.
|
||||||
|
#[arg(short, long, value_delimiter = ',')]
|
||||||
|
files: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -21,8 +27,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let data = fs::read(&args.input)?;
|
let data = fs::read(&args.input)?;
|
||||||
let set = FileDescriptorSet::new(&data).expect("Failed to parse FileDescriptorSet");
|
let set = FileDescriptorSet::new(&data).expect("Failed to parse FileDescriptorSet");
|
||||||
|
|
||||||
let output = generate_rust_code(&set);
|
let files = generate_rust_code(&set, args.files.as_deref(), true);
|
||||||
|
|
||||||
fs::write(&args.output, output)?;
|
for (filename, content) in files {
|
||||||
|
let path = args.output.join(filename);
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
fs::write(path, content)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-25
@@ -1,10 +1,13 @@
|
|||||||
use env_logger::init;
|
use env_logger::init;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use roto::generator::generate_rust_code;
|
use roto::generator::generate_rust_code;
|
||||||
use roto::proto_gen::google::protobuf::descriptor::{
|
use roto::google::protobuf::descriptor::{
|
||||||
CodeGeneratorRequest, CodeGeneratorResponse, FileDescriptorSet, ResponseFile,
|
FileDescriptorSet
|
||||||
};
|
};
|
||||||
use roto::ProtoBuilder;
|
use roto::google::protobuf::compiler::plugin::{
|
||||||
|
CodeGeneratorRequest, CodeGeneratorResponseBuilder, code_generator_response::FileBuilder,
|
||||||
|
};
|
||||||
|
// use roto::ProtoBuilder;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -67,36 +70,35 @@ fn handle_request(request: &CodeGeneratorRequest) -> std::result::Result<Vec<u8>
|
|||||||
|
|
||||||
let set = FileDescriptorSet::new(&set_buf)?;
|
let set = FileDescriptorSet::new(&set_buf)?;
|
||||||
|
|
||||||
|
let files_to_generate: Vec<String> = request.file_to_generate()
|
||||||
|
.filter_map(|res| {
|
||||||
|
let (bytes, _) = res.ok()?;
|
||||||
|
std::str::from_utf8(bytes).ok().map(|s| s.to_string())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Generate the Rust code
|
// Generate the Rust code
|
||||||
info!("Generating Rust code from descriptor set...");
|
info!("Generating Rust code from descriptor set...");
|
||||||
let generated_code = generate_rust_code(&set);
|
let generated_files = generate_rust_code(&set, Some(&files_to_generate), false);
|
||||||
|
|
||||||
// Determine the output filename
|
|
||||||
let mut output_filename = "roto_generated.rs".to_string();
|
|
||||||
if let Some(first_file) = request.file_to_generate().next() {
|
|
||||||
if let Ok((name_bytes, _)) = first_file {
|
|
||||||
if let Ok(name) = std::str::from_utf8(name_bytes) {
|
|
||||||
output_filename = format!("{}.rs", name.replace(".proto", ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the response
|
// Construct the response
|
||||||
let mut response_buf = vec![0u8; 1024 * 1024 * 2]; // Allocate 2MB for response
|
let mut response_buf = vec![0u8; 1024 * 1024 * 2]; // Allocate 2MB for response
|
||||||
let mut resp_builder = CodeGeneratorResponse::builder(&mut response_buf);
|
let mut resp_builder = CodeGeneratorResponseBuilder::builder(&mut response_buf);
|
||||||
|
|
||||||
let mut file_buf = vec![0u8; 1024 * 1024 * 2];
|
for (filename, content) in generated_files {
|
||||||
let final_file = ResponseFile::builder(&mut file_buf)
|
let mut file_buf = vec![0u8; 1024 * 1024 * 2];
|
||||||
.name(&output_filename)?
|
let final_file = FileBuilder::builder(&mut file_buf)
|
||||||
.content(&generated_code)?
|
.name(&filename)?
|
||||||
.finish()
|
.content(&content)?
|
||||||
.map_err(|e| {
|
.finish()
|
||||||
error!("Failed to build ResponseFile: {:?}", e);
|
.map_err(|e| {
|
||||||
e
|
error!("Failed to build ResponseFile {}: {:?}", filename, e);
|
||||||
})?;
|
e
|
||||||
|
})?;
|
||||||
|
resp_builder = resp_builder.file(final_file)?;
|
||||||
|
}
|
||||||
|
|
||||||
let final_response_slice = resp_builder
|
let final_response_slice = resp_builder
|
||||||
.add_file(final_file)?
|
|
||||||
.finish()
|
.finish()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("Failed to finish CodeGeneratorResponse: {:?}", e);
|
error!("Failed to finish CodeGeneratorResponse: {:?}", e);
|
||||||
|
|||||||
+300
-132
@@ -1,8 +1,9 @@
|
|||||||
use crate::proto_gen::google::protobuf::descriptor::{
|
use crate::google::protobuf::descriptor::{
|
||||||
DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, FileDescriptorProto, FileDescriptorSet,
|
DescriptorProto, EnumDescriptorProto, FileDescriptorProto, FieldDescriptorProto, FileDescriptorSet
|
||||||
};
|
};
|
||||||
use crate::{ProtoAccessor, Result, RotoError};
|
use crate::ProtoAccessor;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub fn to_pascal_case(s: &str) -> String {
|
pub fn to_pascal_case(s: &str) -> String {
|
||||||
s.split('_')
|
s.split('_')
|
||||||
@@ -16,53 +17,267 @@ pub fn to_pascal_case(s: &str) -> String {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_snake_case(s: &str) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
for (i, c) in s.chars().enumerate() {
|
||||||
|
if c.is_uppercase() {
|
||||||
|
if i > 0 {
|
||||||
|
result.push('_');
|
||||||
|
}
|
||||||
|
result.push(c.to_ascii_lowercase());
|
||||||
|
} else {
|
||||||
|
result.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn map_type_to_rust_accessor(field_type: i32, label: i32) -> (String, String) {
|
fn map_type_to_rust_accessor(field_type: i32, label: i32) -> (String, String) {
|
||||||
if label == 3 {
|
if label == 3 {
|
||||||
// LABEL_REPEATED
|
// LABEL_REPEATED
|
||||||
return (
|
return (
|
||||||
"crate::RepeatedFieldIterator<'a>".to_string(),
|
"crate::RepeatedFieldIterator<'a>".to_string(),
|
||||||
"self.0.iter_repeated(%d)".to_string(),
|
"".to_string(), // Not used for repeated fields in the same way
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match field_type {
|
match field_type {
|
||||||
9 => (
|
9 => (
|
||||||
"&'a str".to_string(),
|
"&'a str".to_string(),
|
||||||
"str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)".to_string(),
|
"str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)".to_string(),
|
||||||
), // TYPE_STRING
|
), // TYPE_STRING
|
||||||
1 => (
|
1 => (
|
||||||
"f64".to_string(),
|
"f64".to_string(),
|
||||||
"Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| RotoError::WireFormatViolation)?))".to_string(),
|
"Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| crate::RotoError::WireFormatViolation)?))".to_string(),
|
||||||
), // TYPE_DOUBLE
|
), // TYPE_DOUBLE
|
||||||
2 => (
|
2 => (
|
||||||
"f32".to_string(),
|
"f32".to_string(),
|
||||||
"f32::from_le_bytes(bytes.try_into().map_err(|_| RotoError::WireFormatViolation)?)".to_string(),
|
"f32::from_le_bytes(bytes.try_into().map_err(|_| crate::RotoError::WireFormatViolation)?)".to_string(),
|
||||||
), // TYPE_FLOAT
|
), // TYPE_FLOAT
|
||||||
3 | 5 | 15 | 17 => (
|
3 | 5 | 15 | 17 => (
|
||||||
"i32".to_string(),
|
"i32".to_string(),
|
||||||
"crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| RotoError::WireFormatViolation)".to_string(),
|
"crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)".to_string(),
|
||||||
), // INT/SINT/SFIXED 32
|
), // INT/SINT/SFIXED 32
|
||||||
4 | 6 | 13 => (
|
4 | 6 | 13 => (
|
||||||
"u32".to_string(),
|
"u32".to_string(),
|
||||||
"crate::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| RotoError::WireFormatViolation)".to_string(),
|
"crate::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| crate::RotoError::WireFormatViolation)".to_string(),
|
||||||
), // UINT/FIXED 32
|
), // UINT/FIXED 32
|
||||||
16 | 18 => (
|
16 | 18 => (
|
||||||
"i64".to_string(),
|
"i64".to_string(),
|
||||||
"crate::read_varint(bytes).map(|(v, _)| v as i64).map_err(|_| RotoError::WireFormatViolation)".to_string(),
|
"crate::read_varint(bytes).map(|(v, _)| v as i64).map_err(|_| crate::RotoError::WireFormatViolation)".to_string(),
|
||||||
), // SINT/SFIXED 64
|
), // SINT/SFIXED 64
|
||||||
7 | 14 => (
|
7 | 14 => (
|
||||||
"u64".to_string(),
|
"u64".to_string(),
|
||||||
"crate::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| RotoError::WireFormatViolation)".to_string(),
|
"crate::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| crate::RotoError::WireFormatViolation)".to_string(),
|
||||||
), // UINT/FIXED 64
|
), // UINT/FIXED 64
|
||||||
8 => (
|
8 => (
|
||||||
"bool".to_string(),
|
"bool".to_string(),
|
||||||
"crate::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| RotoError::WireFormatViolation)".to_string(),
|
"crate::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| crate::RotoError::WireFormatViolation)".to_string(),
|
||||||
), // TYPE_BOOL
|
), // TYPE_BOOL
|
||||||
11 | 12 => ("&'a [u8]".to_string(), "Ok(bytes)".to_string()), // MESSAGE/BYTES
|
11 | 12 => ("&'a [u8]".to_string(), "Ok(bytes)".to_string()), // MESSAGE/BYTES
|
||||||
_ => ("&'a [u8]".to_string(), "Ok(bytes)".to_string()),
|
_ => ("&'a [u8]".to_string(), "Ok(bytes)".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_enum(enum_proto: &EnumDescriptorProto, output: &mut String) {
|
||||||
|
let enum_name = to_pascal_case(enum_proto.name().unwrap());
|
||||||
|
|
||||||
|
output.push_str(&format!(
|
||||||
|
"#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[repr(i32)]\npub enum {} {{\n",
|
||||||
|
enum_name
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut values = enum_proto.value();
|
||||||
|
let mut zero_variant_name = None;
|
||||||
|
while let Some(val_res) = values.next() {
|
||||||
|
let (val_data, _) = val_res.expect("Failed to iterate enum");
|
||||||
|
let accessor = ProtoAccessor::new(val_data).expect("Failed to parse EnumValueDescriptorProto");
|
||||||
|
let (name_bytes, _) = accessor.get_value(1).expect("Enum value name missing");
|
||||||
|
let name = str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
|
||||||
|
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
|
||||||
|
let (num, _) = crate::read_varint(num_bytes).expect("Enum value number invalid varint");
|
||||||
|
|
||||||
|
let pascal_name = to_pascal_case(name);
|
||||||
|
if num == 0 {
|
||||||
|
zero_variant_name = Some(pascal_name.clone());
|
||||||
|
}
|
||||||
|
output.push_str(&format!(" {} = {},\n", pascal_name, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
if zero_variant_name.is_none() {
|
||||||
|
output.push_str(" Unknown = 0,\n");
|
||||||
|
zero_variant_name = Some("Unknown".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str("}\n\n");
|
||||||
|
|
||||||
|
output.push_str(&format!(
|
||||||
|
"impl {} {{\n pub fn from_i32(value: i32) -> Self {{\n match value {{\n",
|
||||||
|
enum_name
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut values = enum_proto.value();
|
||||||
|
while let Some(val_res) = values.next() {
|
||||||
|
let (val_data, _) = val_res.expect("Failed to read enum value");
|
||||||
|
let accessor = ProtoAccessor::new(val_data).expect("Failed to parse EnumValueDescriptorProto");
|
||||||
|
let (name_bytes, _) = accessor.get_value(1).expect("Enum value name missing");
|
||||||
|
let name = str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
|
||||||
|
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
|
||||||
|
let (num, _) = crate::read_varint(num_bytes).expect("Enum value number invalid varint");
|
||||||
|
|
||||||
|
output.push_str(&format!(" {} => {}::{},\n", num, enum_name, to_pascal_case(name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str(&format!(" _ => {}::{},\n", enum_name, zero_variant_name.as_ref().unwrap()));
|
||||||
|
output.push_str(" }\n }\n}\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
|
||||||
|
let msg_name = to_pascal_case(msg_proto.name().unwrap());
|
||||||
|
|
||||||
|
let mut fields_info = 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 tag = field_proto.number().unwrap();
|
||||||
|
let f_type = field_proto.r#type().unwrap() as i32;
|
||||||
|
let f_label = field_proto.label().unwrap() as i32;
|
||||||
|
|
||||||
|
fields_info.push((field_name.to_string(), tag, f_type, f_label));
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str(&format!(
|
||||||
|
"pub struct {}<'a> {{\n",
|
||||||
|
msg_name
|
||||||
|
));
|
||||||
|
if !fields_info.is_empty() {
|
||||||
|
output.push_str(" accessor: crate::ProtoAccessor<'a>,\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (field_name, _tag, _f_type, f_label) in &fields_info {
|
||||||
|
if *f_label == 3 {
|
||||||
|
output.push_str(&format!(" {}_start: Option<usize>,\n", field_name));
|
||||||
|
output.push_str(&format!(" {}_end: Option<usize>,\n", field_name));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!(" {}_offset: Option<usize>,\n", field_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.push_str("}\n\n");
|
||||||
|
|
||||||
|
output.push_str(&format!("impl<'a> {}<'a> {{\n", msg_name));
|
||||||
|
output.push_str(" pub fn new(data: &'a [u8]) -> crate::Result<Self> {\n");
|
||||||
|
if !fields_info.is_empty() {
|
||||||
|
output.push_str(" let accessor = crate::ProtoAccessor::new(data)?;\n");
|
||||||
|
|
||||||
|
for (name, _, _, label) in &fields_info {
|
||||||
|
if *label == 3 {
|
||||||
|
output.push_str(&format!(" let mut {}_start = None;\n", name));
|
||||||
|
output.push_str(&format!(" let mut {}_end = None;\n", name));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!(" let mut {}_offset = None;\n", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str(" for item in accessor.fields() {\n");
|
||||||
|
output.push_str(" let (offset, tag, _) = item?;\n");
|
||||||
|
|
||||||
|
for (name, tag, _, label) in &fields_info {
|
||||||
|
if *label == 3 {
|
||||||
|
output.push_str(&format!(" if tag.field_number == {} {{\n", tag));
|
||||||
|
output.push_str(&format!(" if {}_start.is_none() {{ {}_start = Some(offset); }}\n", name, name));
|
||||||
|
output.push_str(&format!(" {}_end = Some(offset);\n", name));
|
||||||
|
output.push_str(" }\n");
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!(" if tag.field_number == {} {{ {}_offset = Some(offset); }}\n", tag, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.push_str(" }\n\n");
|
||||||
|
} else {
|
||||||
|
output.push_str(" let _ = crate::ProtoAccessor::new(data)?;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str(" Ok(Self {\n");
|
||||||
|
if !fields_info.is_empty() {
|
||||||
|
output.push_str(" accessor,\n");
|
||||||
|
}
|
||||||
|
for (name, _, _, label) in &fields_info {
|
||||||
|
if *label == 3 {
|
||||||
|
output.push_str(&format!("{}_start, {}_end,\n", name, name));
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("{}_offset,\n", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.push_str(" })\n }\n\n");
|
||||||
|
|
||||||
|
for (field_name, tag, f_type, f_label) in fields_info {
|
||||||
|
let (rust_type, logic) = map_type_to_rust_accessor(f_type, f_label);
|
||||||
|
let safe_name = if field_name == "type" { format!("r#{}", field_name) } else { field_name.clone() };
|
||||||
|
|
||||||
|
if f_label == 3 {
|
||||||
|
output.push_str(&format!(" pub fn {}(&self) -> {} {{\n", safe_name, rust_type));
|
||||||
|
output.push_str(&format!(" match (self.{}_start, self.{}_end) {{\n", field_name, field_name));
|
||||||
|
output.push_str(&format!(" (Some(start), Some(end)) => self.accessor.iter_repeated_range({}, start, end),\n", tag));
|
||||||
|
output.push_str(&format!(" _ => self.accessor.iter_repeated({}),\n", tag));
|
||||||
|
output.push_str(" }\n }\n\n");
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!(" pub fn {}(&self) -> crate::Result<{}> {{\n", safe_name, rust_type));
|
||||||
|
output.push_str(&format!(" let offset = self.{}_offset.ok_or(crate::RotoError::FieldNotFound)?;\n", field_name));
|
||||||
|
output.push_str(" let (bytes, _) = self.accessor.get_value_at(offset)?;\n");
|
||||||
|
output.push_str(&format!(" {}\n", logic));
|
||||||
|
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
|
||||||
|
));
|
||||||
|
|
||||||
|
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 safe_name = if field_name == "type" { format!("r#{}", field_name) } else { field_name.to_string() };
|
||||||
|
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);
|
||||||
|
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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
for e_res in msg_proto.enum_type() {
|
||||||
|
if let Ok((e, _)) = e_res { nested_enums.push(e); }
|
||||||
|
}
|
||||||
|
let mut nested_msgs = Vec::new();
|
||||||
|
for m_res in msg_proto.nested_type() {
|
||||||
|
if let Ok((m, _)) = m_res { nested_msgs.push(m); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if !nested_enums.is_empty() || !nested_msgs.is_empty() {
|
||||||
|
let mod_name = to_snake_case(msg_proto.name().unwrap());
|
||||||
|
output.push_str(&format!("pub mod {} {{\n", mod_name));
|
||||||
|
for e_data in nested_enums {
|
||||||
|
write_enum(&EnumDescriptorProto::new(e_data).expect("Failed to parse nested EnumDescriptorProto"), output);
|
||||||
|
}
|
||||||
|
for m_data in nested_msgs {
|
||||||
|
write_message(&DescriptorProto::new(m_data).expect("Failed to parse nested DescriptorProto"), output);
|
||||||
|
}
|
||||||
|
output.push_str("}\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn map_type_to_rust_builder(field_type: i32) -> (String, String) {
|
fn map_type_to_rust_builder(field_type: i32) -> (String, String) {
|
||||||
match field_type {
|
match field_type {
|
||||||
9 => ("&str".to_string(), "write_string".to_string()),
|
9 => ("&str".to_string(), "write_string".to_string()),
|
||||||
@@ -75,144 +290,97 @@ fn map_type_to_rust_builder(field_type: i32) -> (String, String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_rust_code(set: &FileDescriptorSet) -> String {
|
pub fn generate_rust_code(
|
||||||
let mut output = String::new();
|
set: &FileDescriptorSet,
|
||||||
output.push_str("use crate::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator};\n");
|
files_to_generate: Option<&[String]>,
|
||||||
output.push_str("use std::str;\n\n");
|
generate_mod_files: bool,
|
||||||
|
) -> Vec<(String, String)> {
|
||||||
|
let mut generated_files = Vec::new();
|
||||||
|
|
||||||
for file_res in set.file() {
|
for file_res in set.file() {
|
||||||
let (file_data, _) = file_res.expect("Failed to iterate file");
|
let (file_data, _) = file_res.expect("Failed to iterate file");
|
||||||
let file_proto = FileDescriptorProto::new(file_data).expect("Failed to parse FileDescriptorProto");
|
let file_proto = FileDescriptorProto::new(file_data).expect("Failed to parse FileDescriptorProto");
|
||||||
|
let proto_name = file_proto.name().expect("File proto name missing");
|
||||||
|
|
||||||
|
if let Some(filter) = files_to_generate {
|
||||||
|
if !filter.contains(&proto_name.to_string()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rust_file_name = format!("{}.rs", proto_name.replace(".proto", ""));
|
||||||
|
|
||||||
|
let mut output = String::new();
|
||||||
|
output.push_str("use crate::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator};\n");
|
||||||
|
output.push_str("use std::str;\n\n");
|
||||||
|
|
||||||
|
for dep_res in file_proto.dependency() {
|
||||||
|
let (dep_data, _) = dep_res.expect("Failed to iterate dependency");
|
||||||
|
let dep_name = str::from_utf8(dep_data).expect("Dependency name invalid utf8");
|
||||||
|
let dep_mod_path = dep_name.replace(".proto", "").replace('/', "::");
|
||||||
|
output.push_str(&format!("use crate::{};\n", dep_mod_path));
|
||||||
|
}
|
||||||
|
output.push_str("\n");
|
||||||
|
|
||||||
// Enums
|
// Enums
|
||||||
for enum_res in file_proto.enum_type() {
|
for enum_res in file_proto.enum_type() {
|
||||||
let (enum_data, _) = enum_res.expect("Failed to iterate enum");
|
let (enum_data, _) = enum_res.expect("Failed to iterate enum");
|
||||||
let enum_proto = EnumDescriptorProto::new(enum_data).expect("Failed to parse EnumDescriptorProto");
|
write_enum(&EnumDescriptorProto::new(enum_data).expect("Failed to parse EnumDescriptorProto"), &mut output);
|
||||||
let enum_name = to_pascal_case(enum_proto.name().unwrap());
|
|
||||||
|
|
||||||
output.push_str(&format!(
|
|
||||||
"#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[repr(i32)]\npub enum {} {{\n",
|
|
||||||
enum_name
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut values = enum_proto.enum_value();
|
|
||||||
let mut variant_count = 0;
|
|
||||||
let mut zero_variant_name = None;
|
|
||||||
while let Some(val_res) = values.next() {
|
|
||||||
let (val_data, _) = val_res.expect("Failed to iterate enum");
|
|
||||||
let accessor = ProtoAccessor::new(val_data).expect("Failed to parse EnumValueDescriptorProto");
|
|
||||||
let (name_bytes, _) = accessor.get_value(1).expect("Enum value name missing");
|
|
||||||
let name = str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
|
|
||||||
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
|
|
||||||
let (num, _) = crate::read_varint(num_bytes).expect("Enum value number invalid varint");
|
|
||||||
|
|
||||||
let pascal_name = to_pascal_case(name);
|
|
||||||
if num == 0 {
|
|
||||||
zero_variant_name = Some(pascal_name.clone());
|
|
||||||
}
|
|
||||||
output.push_str(&format!(" {} = {},\n", pascal_name, num));
|
|
||||||
variant_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if zero_variant_name.is_none() {
|
|
||||||
output.push_str(" Unknown = 0,\n");
|
|
||||||
zero_variant_name = Some("Unknown".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push_str("}\n\n");
|
|
||||||
|
|
||||||
output.push_str(&format!(
|
|
||||||
"impl {} {{\n pub fn from_i32(value: i32) -> Self {{\n match value {{\n",
|
|
||||||
enum_name
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut values = enum_proto.enum_value();
|
|
||||||
while let Some(val_res) = values.next() {
|
|
||||||
let (val_data, _) = val_res.expect("Failed to read enum value");
|
|
||||||
let accessor = ProtoAccessor::new(val_data).expect("Failed to parse EnumValueDescriptorProto");
|
|
||||||
let (name_bytes, _) = accessor.get_value(1).expect("Enum value name missing");
|
|
||||||
let name = str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
|
|
||||||
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
|
|
||||||
let (num, _) = crate::read_varint(num_bytes).expect("Enum value number invalid varint");
|
|
||||||
|
|
||||||
output.push_str(&format!(" {} => {}::{},\n", num, enum_name, to_pascal_case(name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push_str(&format!(" _ => {}::{},\n", enum_name, zero_variant_name.as_ref().unwrap()));
|
|
||||||
output.push_str(" }\n }\n}\n\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
for msg_res in file_proto.message_type() {
|
for msg_res in file_proto.message_type() {
|
||||||
let (msg_data, _) = msg_res.expect("Failed to iterate message");
|
let (msg_data, _) = msg_res.expect("Failed to iterate message");
|
||||||
let msg_proto = DescriptorProto::new(msg_data).expect("Failed to parse DescriptorProto");
|
write_message(&DescriptorProto::new(msg_data).expect("Failed to parse DescriptorProto"), &mut output);
|
||||||
let msg_name = to_pascal_case(msg_proto.name().unwrap());
|
}
|
||||||
|
generated_files.push((rust_file_name, output));
|
||||||
|
}
|
||||||
|
|
||||||
// Accessor
|
if !generate_mod_files {
|
||||||
output.push_str(&format!(
|
return generated_files;
|
||||||
"pub struct {}<'a>(ProtoAccessor<'a>);\n\nimpl<'a> {}<'a> {{\n",
|
}
|
||||||
msg_name, msg_name
|
|
||||||
));
|
|
||||||
output.push_str(&format!(
|
|
||||||
" pub fn new(data: &'a [u8]) -> Result<Self> {{\n Ok(Self(ProtoAccessor::new(data)?))\n }}\n\n"
|
|
||||||
));
|
|
||||||
|
|
||||||
for field_res in msg_proto.field() {
|
let mut all_paths: Vec<String> = generated_files.iter().map(|(p, _)| p.clone()).collect();
|
||||||
let (field_data, _) = field_res.expect("Failed to iterate field");
|
all_paths.sort();
|
||||||
let field_proto = FieldDescriptorProto::new(field_data).expect("Failed to parse FieldDescriptorProto");
|
|
||||||
let field_name = field_proto.name().unwrap();
|
|
||||||
let safe_name = if field_name == "type" { format!("r#{}", field_name) } else { field_name.to_string() };
|
|
||||||
let tag = field_proto.number().unwrap();
|
|
||||||
let f_type = field_proto.field_type().unwrap() as i32;
|
|
||||||
let f_label = field_proto.label().unwrap() as i32;
|
|
||||||
|
|
||||||
let (rust_type, logic) = map_type_to_rust_accessor(f_type, f_label);
|
let mut mod_files: HashMap<String, HashSet<String>> = HashMap::new();
|
||||||
|
for path in &all_paths {
|
||||||
if f_label == 3 {
|
let parts: Vec<&str> = path.split('/').collect();
|
||||||
output.push_str(&format!(
|
let mut current_dir = String::new();
|
||||||
" pub fn {}(&self) -> {} {{\n {}\n }}\n\n",
|
for i in 0..parts.len() - 1 {
|
||||||
safe_name, rust_type, logic.replace("%d", &tag.to_string())
|
if !current_dir.is_empty() {
|
||||||
));
|
current_dir.push('/');
|
||||||
} else {
|
|
||||||
output.push_str(&format!(
|
|
||||||
" pub fn {}(&self) -> Result<{}> {{\n let (bytes, _) = self.0.get_value({})?;\n {}\n }}\n\n",
|
|
||||||
safe_name, rust_type, tag, logic
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
output.push_str("}\n\n");
|
current_dir.push_str(parts[i]);
|
||||||
|
let mod_path = format!("{}/mod.rs", current_dir);
|
||||||
// Builder
|
let sub_mod = parts[i + 1].replace(".rs", "");
|
||||||
output.push_str(&format!(
|
mod_files.entry(mod_path).or_default().insert(sub_mod);
|
||||||
"pub struct {}Builder<'b> {{\n builder: 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: ProtoBuilder::new(buf),\n }}\n }}\n\n",
|
|
||||||
msg_name, msg_name
|
|
||||||
));
|
|
||||||
|
|
||||||
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 safe_name = if field_name == "type" { format!("r#{}", field_name) } else { field_name.to_string() };
|
|
||||||
let tag = field_proto.number().unwrap();
|
|
||||||
let f_type = field_proto.field_type().unwrap() as i32;
|
|
||||||
|
|
||||||
let (rust_type, method) = map_type_to_rust_builder(f_type);
|
|
||||||
|
|
||||||
output.push_str(&format!(
|
|
||||||
" pub fn {}(mut self, value: {}) -> Result<Self> {{\n self.builder.{}({}, value)?;\n Ok(self)\n }}\n\n",
|
|
||||||
safe_name, rust_type, method, tag
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push_str(&format!(
|
|
||||||
" pub fn finish(self) -> Result<&'b mut [u8]> {{\n self.builder.finish()\n }}\n}}\n\n"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
let mut root_mods = HashSet::new();
|
||||||
|
for path in &all_paths {
|
||||||
|
let parts: Vec<&str> = path.split('/').collect();
|
||||||
|
root_mods.insert(parts[0].replace(".rs", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut root_mod_content = String::new();
|
||||||
|
let mut sorted_root_mods: Vec<_> = root_mods.into_iter().collect();
|
||||||
|
sorted_root_mods.sort();
|
||||||
|
for m in sorted_root_mods {
|
||||||
|
root_mod_content.push_str(&format!("pub mod {};\n", m));
|
||||||
|
}
|
||||||
|
generated_files.push(("mod.rs".to_string(), root_mod_content));
|
||||||
|
|
||||||
|
for (mod_path, sub_mods) in mod_files {
|
||||||
|
let mut content = String::new();
|
||||||
|
let mut sorted_subs: Vec<_> = sub_mods.into_iter().collect();
|
||||||
|
sorted_subs.sort();
|
||||||
|
for sub in sorted_subs {
|
||||||
|
content.push_str(&format!("pub mod {};\n", sub));
|
||||||
|
}
|
||||||
|
generated_files.push((mod_path, content));
|
||||||
|
}
|
||||||
|
|
||||||
|
generated_files
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod protobuf;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod plugin;
|
||||||
@@ -0,0 +1,455 @@
|
|||||||
|
use std::str;
|
||||||
|
|
||||||
|
// use crate::google::protobuf::descriptor;
|
||||||
|
|
||||||
|
pub struct Version<'a> {
|
||||||
|
accessor: crate::ProtoAccessor<'a>,
|
||||||
|
major_offset: Option<usize>,
|
||||||
|
minor_offset: Option<usize>,
|
||||||
|
patch_offset: Option<usize>,
|
||||||
|
suffix_offset: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Version<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> crate::Result<Self> {
|
||||||
|
let accessor = crate::ProtoAccessor::new(data)?;
|
||||||
|
let mut major_offset = None;
|
||||||
|
let mut minor_offset = None;
|
||||||
|
let mut patch_offset = None;
|
||||||
|
let mut suffix_offset = None;
|
||||||
|
for item in accessor.fields() {
|
||||||
|
let (offset, tag, _) = item?;
|
||||||
|
if tag.field_number == 1 { major_offset = Some(offset); }
|
||||||
|
if tag.field_number == 2 { minor_offset = Some(offset); }
|
||||||
|
if tag.field_number == 3 { patch_offset = Some(offset); }
|
||||||
|
if tag.field_number == 4 { suffix_offset = Some(offset); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
accessor,
|
||||||
|
major_offset,
|
||||||
|
minor_offset,
|
||||||
|
patch_offset,
|
||||||
|
suffix_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn major(&self) -> crate::Result<i32> {
|
||||||
|
let offset = self.major_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minor(&self) -> crate::Result<i32> {
|
||||||
|
let offset = self.minor_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn patch(&self) -> crate::Result<i32> {
|
||||||
|
let offset = self.patch_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn suffix(&self) -> crate::Result<&'a str> {
|
||||||
|
let offset = self.suffix_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VersionBuilder<'b> {
|
||||||
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> VersionBuilder<'b> {
|
||||||
|
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
|
||||||
|
VersionBuilder {
|
||||||
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn major(mut self, value: i32) -> crate::Result<Self> {
|
||||||
|
self.builder.write_int32(1, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minor(mut self, value: i32) -> crate::Result<Self> {
|
||||||
|
self.builder.write_int32(2, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn patch(mut self, value: i32) -> crate::Result<Self> {
|
||||||
|
self.builder.write_int32(3, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn suffix(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(4, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> crate::Result<&'b mut [u8]> {
|
||||||
|
self.builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeGeneratorRequest<'a> {
|
||||||
|
accessor: crate::ProtoAccessor<'a>,
|
||||||
|
file_to_generate_start: Option<usize>,
|
||||||
|
file_to_generate_end: Option<usize>,
|
||||||
|
parameter_offset: Option<usize>,
|
||||||
|
proto_file_start: Option<usize>,
|
||||||
|
proto_file_end: Option<usize>,
|
||||||
|
source_file_descriptors_start: Option<usize>,
|
||||||
|
source_file_descriptors_end: Option<usize>,
|
||||||
|
compiler_version_offset: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CodeGeneratorRequest<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> crate::Result<Self> {
|
||||||
|
let accessor = crate::ProtoAccessor::new(data)?;
|
||||||
|
let mut file_to_generate_start = None;
|
||||||
|
let mut file_to_generate_end = None;
|
||||||
|
let mut parameter_offset = None;
|
||||||
|
let mut proto_file_start = None;
|
||||||
|
let mut proto_file_end = None;
|
||||||
|
let mut source_file_descriptors_start = None;
|
||||||
|
let mut source_file_descriptors_end = None;
|
||||||
|
let mut compiler_version_offset = None;
|
||||||
|
for item in accessor.fields() {
|
||||||
|
let (offset, tag, _) = item?;
|
||||||
|
if tag.field_number == 1 {
|
||||||
|
if file_to_generate_start.is_none() { file_to_generate_start = Some(offset); }
|
||||||
|
file_to_generate_end = Some(offset);
|
||||||
|
}
|
||||||
|
if tag.field_number == 2 { parameter_offset = Some(offset); }
|
||||||
|
if tag.field_number == 15 {
|
||||||
|
if proto_file_start.is_none() { proto_file_start = Some(offset); }
|
||||||
|
proto_file_end = Some(offset);
|
||||||
|
}
|
||||||
|
if tag.field_number == 17 {
|
||||||
|
if source_file_descriptors_start.is_none() { source_file_descriptors_start = Some(offset); }
|
||||||
|
source_file_descriptors_end = Some(offset);
|
||||||
|
}
|
||||||
|
if tag.field_number == 3 { compiler_version_offset = Some(offset); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
accessor,
|
||||||
|
file_to_generate_start, file_to_generate_end,
|
||||||
|
parameter_offset,
|
||||||
|
proto_file_start, proto_file_end,
|
||||||
|
source_file_descriptors_start, source_file_descriptors_end,
|
||||||
|
compiler_version_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_to_generate(&self) -> crate::RepeatedFieldIterator<'a> {
|
||||||
|
match (self.file_to_generate_start, self.file_to_generate_end) {
|
||||||
|
(Some(start), Some(end)) => self.accessor.iter_repeated_range(1, start, end),
|
||||||
|
_ => self.accessor.iter_repeated(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parameter(&self) -> crate::Result<&'a str> {
|
||||||
|
let offset = self.parameter_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proto_file(&self) -> crate::RepeatedFieldIterator<'a> {
|
||||||
|
match (self.proto_file_start, self.proto_file_end) {
|
||||||
|
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
|
||||||
|
_ => self.accessor.iter_repeated(15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_file_descriptors(&self) -> crate::RepeatedFieldIterator<'a> {
|
||||||
|
match (self.source_file_descriptors_start, self.source_file_descriptors_end) {
|
||||||
|
(Some(start), Some(end)) => self.accessor.iter_repeated_range(17, start, end),
|
||||||
|
_ => self.accessor.iter_repeated(17),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compiler_version(&self) -> crate::Result<&'a [u8]> {
|
||||||
|
let offset = self.compiler_version_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
Ok(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeGeneratorRequestBuilder<'b> {
|
||||||
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> CodeGeneratorRequestBuilder<'b> {
|
||||||
|
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
|
||||||
|
CodeGeneratorRequestBuilder {
|
||||||
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_to_generate(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(1, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parameter(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(2, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proto_file(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
|
self.builder.write_bytes(15, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_file_descriptors(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
|
self.builder.write_bytes(17, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compiler_version(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
|
self.builder.write_bytes(3, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> crate::Result<&'b mut [u8]> {
|
||||||
|
self.builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeGeneratorResponse<'a> {
|
||||||
|
accessor: crate::ProtoAccessor<'a>,
|
||||||
|
error_offset: Option<usize>,
|
||||||
|
supported_features_offset: Option<usize>,
|
||||||
|
minimum_edition_offset: Option<usize>,
|
||||||
|
maximum_edition_offset: Option<usize>,
|
||||||
|
file_start: Option<usize>,
|
||||||
|
file_end: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CodeGeneratorResponse<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> crate::Result<Self> {
|
||||||
|
let accessor = crate::ProtoAccessor::new(data)?;
|
||||||
|
let mut error_offset = None;
|
||||||
|
let mut supported_features_offset = None;
|
||||||
|
let mut minimum_edition_offset = None;
|
||||||
|
let mut maximum_edition_offset = None;
|
||||||
|
let mut file_start = None;
|
||||||
|
let mut file_end = None;
|
||||||
|
for item in accessor.fields() {
|
||||||
|
let (offset, tag, _) = item?;
|
||||||
|
if tag.field_number == 1 { error_offset = Some(offset); }
|
||||||
|
if tag.field_number == 2 { supported_features_offset = Some(offset); }
|
||||||
|
if tag.field_number == 3 { minimum_edition_offset = Some(offset); }
|
||||||
|
if tag.field_number == 4 { maximum_edition_offset = Some(offset); }
|
||||||
|
if tag.field_number == 15 {
|
||||||
|
if file_start.is_none() { file_start = Some(offset); }
|
||||||
|
file_end = Some(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
accessor,
|
||||||
|
error_offset,
|
||||||
|
supported_features_offset,
|
||||||
|
minimum_edition_offset,
|
||||||
|
maximum_edition_offset,
|
||||||
|
file_start, file_end,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(&self) -> crate::Result<&'a str> {
|
||||||
|
let offset = self.error_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supported_features(&self) -> crate::Result<u32> {
|
||||||
|
let offset = self.supported_features_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
crate::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minimum_edition(&self) -> crate::Result<i32> {
|
||||||
|
let offset = self.minimum_edition_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maximum_edition(&self) -> crate::Result<i32> {
|
||||||
|
let offset = self.maximum_edition_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file(&self) -> crate::RepeatedFieldIterator<'a> {
|
||||||
|
match (self.file_start, self.file_end) {
|
||||||
|
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
|
||||||
|
_ => self.accessor.iter_repeated(15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeGeneratorResponseBuilder<'b> {
|
||||||
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> CodeGeneratorResponseBuilder<'b> {
|
||||||
|
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
|
||||||
|
CodeGeneratorResponseBuilder {
|
||||||
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(1, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supported_features(mut self, value: u64) -> crate::Result<Self> {
|
||||||
|
self.builder.write_varint(2, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minimum_edition(mut self, value: i32) -> crate::Result<Self> {
|
||||||
|
self.builder.write_int32(3, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maximum_edition(mut self, value: i32) -> crate::Result<Self> {
|
||||||
|
self.builder.write_int32(4, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
|
self.builder.write_bytes(15, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> crate::Result<&'b mut [u8]> {
|
||||||
|
self.builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod code_generator_response {
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum Feature {
|
||||||
|
FEATURENONE = 0,
|
||||||
|
FEATUREPROTO3OPTIONAL = 1,
|
||||||
|
FEATURESUPPORTSEDITIONS = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Feature {
|
||||||
|
pub fn from_i32(value: i32) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Feature::FEATURENONE,
|
||||||
|
1 => Feature::FEATUREPROTO3OPTIONAL,
|
||||||
|
2 => Feature::FEATURESUPPORTSEDITIONS,
|
||||||
|
_ => Feature::FEATURENONE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct File<'a> {
|
||||||
|
accessor: crate::ProtoAccessor<'a>,
|
||||||
|
name_offset: Option<usize>,
|
||||||
|
insertion_point_offset: Option<usize>,
|
||||||
|
content_offset: Option<usize>,
|
||||||
|
generated_code_info_offset: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> File<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> crate::Result<Self> {
|
||||||
|
let accessor = crate::ProtoAccessor::new(data)?;
|
||||||
|
let mut name_offset = None;
|
||||||
|
let mut insertion_point_offset = None;
|
||||||
|
let mut content_offset = None;
|
||||||
|
let mut generated_code_info_offset = None;
|
||||||
|
for item in accessor.fields() {
|
||||||
|
let (offset, tag, _) = item?;
|
||||||
|
if tag.field_number == 1 { name_offset = Some(offset); }
|
||||||
|
if tag.field_number == 2 { insertion_point_offset = Some(offset); }
|
||||||
|
if tag.field_number == 15 { content_offset = Some(offset); }
|
||||||
|
if tag.field_number == 16 { generated_code_info_offset = Some(offset); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
accessor,
|
||||||
|
name_offset,
|
||||||
|
insertion_point_offset,
|
||||||
|
content_offset,
|
||||||
|
generated_code_info_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> crate::Result<&'a str> {
|
||||||
|
let offset = self.name_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insertion_point(&self) -> crate::Result<&'a str> {
|
||||||
|
let offset = self.insertion_point_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content(&self) -> crate::Result<&'a str> {
|
||||||
|
let offset = self.content_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generated_code_info(&self) -> crate::Result<&'a [u8]> {
|
||||||
|
let offset = self.generated_code_info_offset.ok_or(crate::RotoError::FieldNotFound)?;
|
||||||
|
let (bytes, _) = self.accessor.get_value_at(offset)?;
|
||||||
|
Ok(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FileBuilder<'b> {
|
||||||
|
builder: crate::ProtoBuilder<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> FileBuilder<'b> {
|
||||||
|
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
|
||||||
|
FileBuilder {
|
||||||
|
builder: crate::ProtoBuilder::new(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(1, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insertion_point(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(2, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content(mut self, value: &str) -> crate::Result<Self> {
|
||||||
|
self.builder.write_string(15, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generated_code_info(mut self, value: &[u8]) -> crate::Result<Self> {
|
||||||
|
self.builder.write_bytes(16, value)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> crate::Result<&'b mut [u8]> {
|
||||||
|
self.builder.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod compiler;
|
||||||
|
pub mod descriptor;
|
||||||
+51
-7
@@ -1,5 +1,5 @@
|
|||||||
pub mod proto_gen;
|
|
||||||
pub mod generator;
|
pub mod generator;
|
||||||
|
pub mod google;
|
||||||
// Uncomment this to check if the code compiles
|
// Uncomment this to check if the code compiles
|
||||||
// #[path = "../proto/google/protobuf/descriptor.rs"]
|
// #[path = "../proto/google/protobuf/descriptor.rs"]
|
||||||
// pub mod descriptor;
|
// pub mod descriptor;
|
||||||
@@ -189,7 +189,7 @@ impl<'a> ProtoAccessor<'a> {
|
|||||||
pub fn get_value(&self, field_number: u32) -> Result<(&'a [u8], WireType)> {
|
pub fn get_value(&self, field_number: u32) -> Result<(&'a [u8], WireType)> {
|
||||||
let mut last_value = None;
|
let mut last_value = None;
|
||||||
for item in self.fields() {
|
for item in self.fields() {
|
||||||
let (tag, value) = item?;
|
let (_offset, tag, value) = item?;
|
||||||
if tag.field_number == field_number {
|
if tag.field_number == field_number {
|
||||||
last_value = Some((value, tag.wire_type));
|
last_value = Some((value, tag.wire_type));
|
||||||
}
|
}
|
||||||
@@ -201,6 +201,32 @@ impl<'a> ProtoAccessor<'a> {
|
|||||||
pub fn iter_repeated(&self, field_number: u32) -> RepeatedFieldIterator<'a> {
|
pub fn iter_repeated(&self, field_number: u32) -> RepeatedFieldIterator<'a> {
|
||||||
RepeatedFieldIterator::new(self.data, field_number)
|
RepeatedFieldIterator::new(self.data, field_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the value and wire type of a field at a specific offset.
|
||||||
|
pub fn get_value_at(&self, offset: usize) -> Result<(&'a [u8], WireType)> {
|
||||||
|
if offset >= self.data.len() {
|
||||||
|
return Err(RotoError::UnexpectedEndOfBuffer);
|
||||||
|
}
|
||||||
|
let (tag, tag_len) = Tag::decode(&self.data[offset..])?;
|
||||||
|
let cursor_after_tag = offset + tag_len;
|
||||||
|
if cursor_after_tag > self.data.len() {
|
||||||
|
return Err(RotoError::UnexpectedEndOfBuffer);
|
||||||
|
}
|
||||||
|
let value_len = skip_value(tag.wire_type, &self.data[cursor_after_tag..])?;
|
||||||
|
let (value_offset, actual_value_len) = match tag.wire_type {
|
||||||
|
WireType::LengthDelimited => {
|
||||||
|
let (_, varint_len) = read_varint(&self.data[cursor_after_tag..])?;
|
||||||
|
(cursor_after_tag + varint_len, value_len - varint_len)
|
||||||
|
}
|
||||||
|
_ => (cursor_after_tag, value_len),
|
||||||
|
};
|
||||||
|
Ok((&self.data[value_offset..value_offset + actual_value_len], tag.wire_type))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator that scans a specific range of the buffer for all occurrences of the specified field.
|
||||||
|
pub fn iter_repeated_range(&self, field_number: u32, start: usize, end: usize) -> RepeatedFieldIterator<'a> {
|
||||||
|
RepeatedFieldIterator::new_range(self.data, field_number, start, end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FieldIterator<'a> {
|
pub struct FieldIterator<'a> {
|
||||||
@@ -209,7 +235,7 @@ pub struct FieldIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for FieldIterator<'a> {
|
impl<'a> Iterator for FieldIterator<'a> {
|
||||||
type Item = Result<(Tag, &'a [u8])>;
|
type Item = Result<(usize, Tag, &'a [u8])>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.cursor >= self.data.len() {
|
if self.cursor >= self.data.len() {
|
||||||
@@ -254,23 +280,36 @@ impl<'a> Iterator for FieldIterator<'a> {
|
|||||||
|
|
||||||
self.cursor = cursor_after_tag + value_len;
|
self.cursor = cursor_after_tag + value_len;
|
||||||
|
|
||||||
Some(Ok((tag, &self.data[value_offset..value_offset + actual_value_len])))
|
Some(Ok((self.cursor - tag_len - value_len, tag, &self.data[value_offset..value_offset + actual_value_len])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RepeatedFieldIterator<'a> {
|
pub struct RepeatedFieldIterator<'a> {
|
||||||
iterator: FieldIterator<'a>,
|
iterator: FieldIterator<'a>,
|
||||||
field_number: u32,
|
field_number: u32,
|
||||||
|
end_offset: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RepeatedFieldIterator<'a> {
|
impl<'a> RepeatedFieldIterator<'a> {
|
||||||
fn new(data: &'a [u8], field_number: u32) -> Self {
|
pub fn new(data: &'a [u8], field_number: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
iterator: FieldIterator {
|
iterator: FieldIterator {
|
||||||
data,
|
data,
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
},
|
},
|
||||||
field_number,
|
field_number,
|
||||||
|
end_offset: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_range(data: &'a [u8], field_number: u32, start: usize, end: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
iterator: FieldIterator {
|
||||||
|
data,
|
||||||
|
cursor: start,
|
||||||
|
},
|
||||||
|
field_number,
|
||||||
|
end_offset: Some(end),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +320,12 @@ impl<'a> Iterator for RepeatedFieldIterator<'a> {
|
|||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(item) = self.iterator.next() {
|
while let Some(item) = self.iterator.next() {
|
||||||
match item {
|
match item {
|
||||||
Ok((tag, value)) if tag.field_number == self.field_number => {
|
Ok((offset, tag, value)) if tag.field_number == self.field_number => {
|
||||||
|
if let Some(end) = self.end_offset {
|
||||||
|
if offset > end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
return Some(Ok((value, tag.wire_type)));
|
return Some(Ok((value, tag.wire_type)));
|
||||||
}
|
}
|
||||||
Ok(_) => continue,
|
Ok(_) => continue,
|
||||||
@@ -476,7 +520,7 @@ mod tests {
|
|||||||
|
|
||||||
// Validate that fields appear in the expected relative order
|
// Validate that fields appear in the expected relative order
|
||||||
let field_numbers: Vec<u32> = acc.fields()
|
let field_numbers: Vec<u32> = acc.fields()
|
||||||
.map(|r| r.expect("Failed to decode field").0.field_number)
|
.map(|r| r.expect("Failed to decode field").1.field_number)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let essential_fields = [1, 2, 3, 14, 16, 20];
|
let essential_fields = [1, 2, 3, 14, 16, 20];
|
||||||
|
|||||||
@@ -1,281 +0,0 @@
|
|||||||
use crate::{ProtoAccessor, ProtoBuilder, Result, RotoError};
|
|
||||||
use crate::proto_gen::google::protobuf::descriptor::{FileDescriptorProto, GeneratedCodeInfo};
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
pub struct Version<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> Version<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn major(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minor(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn patch(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn suffix(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(4)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
|
|
||||||
VersionBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VersionBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> VersionBuilder<'b> {
|
|
||||||
pub fn major(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minor(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn patch(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn suffix(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(4, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorRequest<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> CodeGeneratorRequest<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_to_generate(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parameter(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compiler_version(&self) -> Result<Version<'a>> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
Version::new(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proto_file(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(15)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_file_descriptors(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(17)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
|
|
||||||
CodeGeneratorRequestBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorRequestBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> CodeGeneratorRequestBuilder<'b> {
|
|
||||||
pub fn add_file_to_generate(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parameter(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compiler_version(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(3, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_proto_file(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(15, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_source_file_descriptor(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(17, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorResponse<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> CodeGeneratorResponse<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn supported_features(&self) -> Result<u64> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minimum_edition(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maximum_edition(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(4)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(15)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
|
|
||||||
CodeGeneratorResponseBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorResponseBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> CodeGeneratorResponseBuilder<'b> {
|
|
||||||
pub fn error(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn supported_features(mut self, value: u64) -> Result<Self> {
|
|
||||||
self.builder.write_varint(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minimum_edition(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maximum_edition(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(4, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_file(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(15, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorResponseFile<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> CodeGeneratorResponseFile<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insertion_point(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn content(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(15)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generated_code_info(&self) -> Result<GeneratedCodeInfo<'a>> {
|
|
||||||
let (bytes, _) = self.0.get_value(16)?;
|
|
||||||
GeneratedCodeInfo::new(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseFileBuilder<'_> {
|
|
||||||
CodeGeneratorResponseFileBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorResponseFileBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> CodeGeneratorResponseFileBuilder<'b> {
|
|
||||||
pub fn name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insertion_point(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn content(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(15, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generated_code_info(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(16, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,905 +0,0 @@
|
|||||||
use crate::{ProtoAccessor, ProtoBuilder, Result, RotoError};
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
/// The edition of the proto file.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
#[repr(i32)]
|
|
||||||
pub enum Edition {
|
|
||||||
EditionLegacy = 0,
|
|
||||||
EditionProto2 = 1,
|
|
||||||
EditionProto3 = 2,
|
|
||||||
Edition2023 = 3,
|
|
||||||
Edition2024 = 4,
|
|
||||||
Edition2026 = 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Edition {
|
|
||||||
pub fn from_i32(value: i32) -> Self {
|
|
||||||
match value {
|
|
||||||
1 => Edition::EditionProto2,
|
|
||||||
2 => Edition::EditionProto3,
|
|
||||||
3 => Edition::Edition2023,
|
|
||||||
4 => Edition::Edition2024,
|
|
||||||
5 => Edition::Edition2026,
|
|
||||||
_ => Edition::EditionLegacy,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FileDescriptorSet<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> FileDescriptorSet<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FileDescriptorProto<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> FileDescriptorProto<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn package(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dependency(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public_dependency(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(10)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn weak_dependency(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(11)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn option_dependency(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(15)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message_type(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enum_type(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(5)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn service(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(6)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extension(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(7)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn syntax(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(12)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn edition(&self) -> Result<Edition> {
|
|
||||||
let (bytes, _) = self.0.get_value(14)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(Edition::from_i32(val as i32))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> FileDescriptorProtoBuilder<'_> {
|
|
||||||
FileDescriptorProtoBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FileDescriptorProtoBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> FileDescriptorProtoBuilder<'b> {
|
|
||||||
pub fn name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn package(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_dependency(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_public_dependency(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(10, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_weak_dependency(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(11, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_option_dependency(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(15, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_message_type(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(4, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_enum_type(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(5, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_service(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(6, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_extension(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(7, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn syntax(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(12, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn edition(mut self, value: Edition) -> Result<Self> {
|
|
||||||
self.builder.write_varint(14, value as u64)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DescriptorProto<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> DescriptorProto<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extension(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(6)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nested_type(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enum_type(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reserved_name(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(10)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> DescriptorProtoBuilder<'_> {
|
|
||||||
DescriptorProtoBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DescriptorProtoBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> DescriptorProtoBuilder<'b> {
|
|
||||||
pub fn name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_field(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(2, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_extension(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(6, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_nested_type(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(3, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_enum_type(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(4, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_reserved_name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(10, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EnumDescriptorProto<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> EnumDescriptorProto<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enum_value(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reserved_value(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn options(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> EnumDescriptorProtoBuilder<'_> {
|
|
||||||
EnumDescriptorProtoBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EnumDescriptorProtoBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> EnumDescriptorProtoBuilder<'b> {
|
|
||||||
pub fn name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_enum_value(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(2, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_reserved_value(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_options(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(4, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum FieldType {
|
|
||||||
Double = 1,
|
|
||||||
Float = 2,
|
|
||||||
Int64 = 3,
|
|
||||||
Uint64 = 4,
|
|
||||||
Int32 = 5,
|
|
||||||
Fixed64 = 6,
|
|
||||||
Fixed32 = 7,
|
|
||||||
Bool = 8,
|
|
||||||
String = 9,
|
|
||||||
Group = 10,
|
|
||||||
Message = 11,
|
|
||||||
Bytes = 12,
|
|
||||||
Uint32 = 13,
|
|
||||||
Enum = 14,
|
|
||||||
Sfixed32 = 15,
|
|
||||||
Sfixed64 = 16,
|
|
||||||
Sint32 = 17,
|
|
||||||
Sint64 = 18,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FieldType {
|
|
||||||
pub fn from_i32(value: i32) -> Self {
|
|
||||||
match value {
|
|
||||||
1 => FieldType::Double,
|
|
||||||
2 => FieldType::Float,
|
|
||||||
3 => FieldType::Int64,
|
|
||||||
4 => FieldType::Uint64,
|
|
||||||
5 => FieldType::Int32,
|
|
||||||
6 => FieldType::Fixed64,
|
|
||||||
7 => FieldType::Fixed32,
|
|
||||||
8 => FieldType::Bool,
|
|
||||||
9 => FieldType::String,
|
|
||||||
10 => FieldType::Group,
|
|
||||||
11 => FieldType::Message,
|
|
||||||
12 => FieldType::Bytes,
|
|
||||||
13 => FieldType::Uint32,
|
|
||||||
14 => FieldType::Enum,
|
|
||||||
15 => FieldType::Sfixed32,
|
|
||||||
16 => FieldType::Sfixed64,
|
|
||||||
17 => FieldType::Sint32,
|
|
||||||
18 => FieldType::Sint64,
|
|
||||||
_ => FieldType::Int32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum FieldLabel {
|
|
||||||
Optional = 1,
|
|
||||||
Required = 2,
|
|
||||||
Repeated = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FieldLabel {
|
|
||||||
pub fn from_i32(value: i32) -> Self {
|
|
||||||
match value {
|
|
||||||
1 => FieldLabel::Optional,
|
|
||||||
2 => FieldLabel::Required,
|
|
||||||
3 => FieldLabel::Repeated,
|
|
||||||
_ => FieldLabel::Optional,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FieldDescriptorProto<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> FieldDescriptorProto<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn number(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn label(&self) -> Result<FieldLabel> {
|
|
||||||
let (bytes, _) = self.0.get_value(4)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(FieldLabel::from_i32(val as i32))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field_type(&self) -> Result<FieldType> {
|
|
||||||
let (bytes, _) = self.0.get_value(5)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(FieldType::from_i32(val as i32))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(6)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_value(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(7)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn oneof_index(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(9)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn json_name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(10)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proto3_optional(&self) -> Result<bool> {
|
|
||||||
let (bytes, _) = self.0.get_value(17)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val != 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> FieldDescriptorProtoBuilder<'_> {
|
|
||||||
FieldDescriptorProtoBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FieldDescriptorProtoBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> FieldDescriptorProtoBuilder<'b> {
|
|
||||||
pub fn name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn number(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn label(mut self, value: FieldLabel) -> Result<Self> {
|
|
||||||
self.builder.write_varint(4, value as u64)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field_type(mut self, value: FieldType) -> Result<Self> {
|
|
||||||
self.builder.write_varint(5, value as u64)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(6, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_value(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(7, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn oneof_index(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(9, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn json_name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(10, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proto3_optional(mut self, value: bool) -> Result<Self> {
|
|
||||||
self.builder.write_varint(17, if value { 1 } else { 0 })?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GeneratedCodeInfo<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> GeneratedCodeInfo<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn annotation(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> GeneratedCodeInfoBuilder<'_> {
|
|
||||||
GeneratedCodeInfoBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GeneratedCodeInfoBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> GeneratedCodeInfoBuilder<'b> {
|
|
||||||
pub fn add_annotation(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(1, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Version<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> Version<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn major(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minor(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn patch(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn suffix(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(4)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
|
|
||||||
VersionBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VersionBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> VersionBuilder<'b> {
|
|
||||||
pub fn major(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minor(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn patch(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn suffix(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(4, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorRequest<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> CodeGeneratorRequest<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_to_generate(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parameter(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compiler_version(&self) -> Result<&'a [u8]> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
Ok(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proto_file(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(15)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_file_descriptors(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(17)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
|
|
||||||
CodeGeneratorRequestBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorRequestBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> CodeGeneratorRequestBuilder<'b> {
|
|
||||||
pub fn add_file_to_generate(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parameter(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compiler_version(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(3, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_proto_file(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(15, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_source_file_descriptor(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(17, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorResponse<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> CodeGeneratorResponse<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn supported_features(&self) -> Result<u64> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minimum_edition(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maximum_edition(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(4)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(15)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
|
|
||||||
CodeGeneratorResponseBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGeneratorResponseBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> CodeGeneratorResponseBuilder<'b> {
|
|
||||||
pub fn error(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn supported_features(mut self, value: u64) -> Result<Self> {
|
|
||||||
self.builder.write_varint(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minimum_edition(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maximum_edition(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(4, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_file(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(15, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ResponseFile<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> ResponseFile<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(1)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insertion_point(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn content(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(15)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generated_code_info(&self) -> Result<&'a [u8]> {
|
|
||||||
let (bytes, _) = self.0.get_value(16)?;
|
|
||||||
Ok(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> ResponseFileBuilder<'_> {
|
|
||||||
ResponseFileBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ResponseFileBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> ResponseFileBuilder<'b> {
|
|
||||||
pub fn name(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insertion_point(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn content(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(15, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generated_code_info(mut self, data: &[u8]) -> Result<Self> {
|
|
||||||
self.builder.write_bytes(16, data)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_read_descriptor_set() {
|
|
||||||
let data = include_bytes!("../../../../data/test_types.desc");
|
|
||||||
let set = FileDescriptorSet::new(data).expect("Failed to parse FileDescriptorSet");
|
|
||||||
let mut files = set.file();
|
|
||||||
let (file_data, _) = files.next().expect("No file descriptors found").expect("Failed to read file descriptor");
|
|
||||||
let file_proto = FileDescriptorProto::new(file_data).expect("Failed to parse FileDescriptorProto");
|
|
||||||
assert_eq!(file_proto.name().unwrap(), "data/test_types.proto");
|
|
||||||
assert_eq!(file_proto.package().unwrap(), "roto.test");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Annotation<'a>(ProtoAccessor<'a>);
|
|
||||||
|
|
||||||
impl<'a> Annotation<'a> {
|
|
||||||
pub fn new(data: &'a [u8]) -> Result<Self> {
|
|
||||||
Ok(Self(ProtoAccessor::new(data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> crate::RepeatedFieldIterator<'a> {
|
|
||||||
self.0.iter_repeated(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_file(&self) -> Result<&'a str> {
|
|
||||||
let (bytes, _) = self.0.get_value(2)?;
|
|
||||||
str::from_utf8(bytes).map_err(|_| RotoError::WireFormatViolation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn begin(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(3)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn end(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(4)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn semantic(&self) -> Result<i32> {
|
|
||||||
let (bytes, _) = self.0.get_value(5)?;
|
|
||||||
let (val, _) = crate::read_varint(bytes)?;
|
|
||||||
Ok(val as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder(buf: &mut [u8]) -> AnnotationBuilder<'_> {
|
|
||||||
AnnotationBuilder {
|
|
||||||
builder: ProtoBuilder::new(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AnnotationBuilder<'b> {
|
|
||||||
builder: ProtoBuilder<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b> AnnotationBuilder<'b> {
|
|
||||||
pub fn add_path(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(1, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_file(mut self, value: &str) -> Result<Self> {
|
|
||||||
self.builder.write_string(2, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn begin(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(3, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn end(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_int32(4, value)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn semantic(mut self, value: i32) -> Result<Self> {
|
|
||||||
self.builder.write_varint(5, value as u64)?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Result<&'b mut [u8]> {
|
|
||||||
self.builder.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
|||||||
pub mod google {
|
|
||||||
pub mod protobuf {
|
|
||||||
pub mod descriptor;
|
|
||||||
pub mod compiler {
|
|
||||||
pub mod plugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::path::PathBuf;
|
use roto::google::protobuf::descriptor::{
|
||||||
|
FileDescriptorSet
|
||||||
|
};
|
||||||
|
use roto::google::protobuf::compiler::plugin::{
|
||||||
|
CodeGeneratorRequest,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_generated_code_builds() {
|
fn test_generated_code_builds() {
|
||||||
// 1. Generate Rust code from data/request.bin
|
// 1. Generate Rust code from data/request.bin
|
||||||
let request_path = "data/request.bin";
|
let request_path = "data/request.bin";
|
||||||
let data = fs::read(request_path).expect("Failed to read request.bin");
|
let data = fs::read(request_path).expect("Failed to read request.bin");
|
||||||
let request = roto::proto_gen::google::protobuf::descriptor::CodeGeneratorRequest::new(&data)
|
let request = CodeGeneratorRequest::new(&data)
|
||||||
.expect("Failed to parse CodeGeneratorRequest");
|
.expect("Failed to parse CodeGeneratorRequest");
|
||||||
|
|
||||||
// Mimic the logic from protoc-gen-roto to build a FileDescriptorSet
|
// Mimic the logic from protoc-gen-roto to build a FileDescriptorSet
|
||||||
@@ -27,11 +32,11 @@ fn test_generated_code_builds() {
|
|||||||
// Write data
|
// Write data
|
||||||
set_buf.extend_from_slice(file_data);
|
set_buf.extend_from_slice(file_data);
|
||||||
}
|
}
|
||||||
let set = roto::proto_gen::google::protobuf::descriptor::FileDescriptorSet::new(&set_buf)
|
let set = FileDescriptorSet::new(&set_buf)
|
||||||
.expect("Failed to create FileDescriptorSet");
|
.expect("Failed to create FileDescriptorSet");
|
||||||
|
|
||||||
let generated_code = roto::generator::generate_rust_code(&set);
|
let generated_files = roto::generator::generate_rust_code(&set, None, false);
|
||||||
assert!(!generated_code.is_empty(), "Generated code should not be empty");
|
assert!(!generated_files.is_empty(), "Generated code should not be empty");
|
||||||
|
|
||||||
// 2. Setup a temporary Cargo project to verify the code builds
|
// 2. Setup a temporary Cargo project to verify the code builds
|
||||||
let root = std::env::current_dir().expect("Failed to get current directory");
|
let root = std::env::current_dir().expect("Failed to get current directory");
|
||||||
@@ -62,7 +67,12 @@ fn test_generated_code_builds() {
|
|||||||
// 4. Write the generated code to src/lib.rs
|
// 4. Write the generated code to src/lib.rs
|
||||||
// The generated code uses `use crate::{...}`, but it's now in a separate crate.
|
// The generated code uses `use crate::{...}`, but it's now in a separate crate.
|
||||||
// Replace `crate` with `roto` to reference the types in the dependency.
|
// Replace `crate` with `roto` to reference the types in the dependency.
|
||||||
let final_code = generated_code.replace("use crate::", "use roto::");
|
let mut all_code = String::new();
|
||||||
|
for (_, content) in generated_files {
|
||||||
|
all_code.push_str(&content);
|
||||||
|
all_code.push_str("\n");
|
||||||
|
}
|
||||||
|
let final_code = all_code.replace("use crate::", "use roto::");
|
||||||
let lib_path = temp_project_dir.join("src/lib.rs");
|
let lib_path = temp_project_dir.join("src/lib.rs");
|
||||||
fs::write(lib_path, final_code).expect("Failed to write generated code to src/lib.rs");
|
fs::write(lib_path, final_code).expect("Failed to write generated code to src/lib.rs");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use roto::generator::generate_rust_code;
|
||||||
|
use roto::google::protobuf::descriptor::{
|
||||||
|
FileDescriptorSet
|
||||||
|
};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_proto_generation_contains_modules() {
|
||||||
|
let request_path = "data/request.bin";
|
||||||
|
if !std::path::Path::new(request_path).exists() {
|
||||||
|
panic!("data/request.bin not found. This test requires the sample request binary.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = fs::read(request_path).expect("Failed to read request.bin");
|
||||||
|
|
||||||
|
// The existing test logic to build a FileDescriptorSet from CodeGeneratorRequest
|
||||||
|
// We can simplify this by just wrapping the data if it's already a FileDescriptorSet,
|
||||||
|
// but request.bin is usually a CodeGeneratorRequest.
|
||||||
|
|
||||||
|
// Let's use the same logic as build_generated_code.rs to get a FileDescriptorSet
|
||||||
|
let request = roto::google::protobuf::compiler::plugin::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(10);
|
||||||
|
let len = file_data.len() as u64;
|
||||||
|
let mut len_buf = [0u8; 10];
|
||||||
|
let len_size = roto::write_varint(len, &mut len_buf).expect("Failed to write varint length");
|
||||||
|
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");
|
||||||
|
|
||||||
|
let generated_files = generate_rust_code(&set, None, false);
|
||||||
|
|
||||||
|
let all_code: String = generated_files.into_iter().map(|(_, content)| content).collect();
|
||||||
|
println!("Generated Code:\n{}", all_code);
|
||||||
|
|
||||||
|
// We want to see if any message has a nested module.
|
||||||
|
// Since we don't know exactly what's in request.bin, we'll look for ANY 'pub mod' inside the generated code
|
||||||
|
// that isn't at the top level (though the generator puts them inside the message definition).
|
||||||
|
assert!(all_code.contains("pub mod "), "Generated code should contain at least one nested module for nested types");
|
||||||
|
assert!(all_code.contains("pub struct "), "Generated code should contain structs");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user