Compare commits

...

4 Commits

Author SHA1 Message Date
charles 52df4b6908 Resolve type paths and add typed iterators
Build a type registry across all files to correctly handle nested
and cross-referenced proto messages. Qualify generated Rust paths
based on module depth. Introduce dedicated iterator structs for
repeated message fields to replace raw byte accessors.
2026-06-25 01:57:08 -07:00
charles 229727340d Add RevBuilder for reverse message encoding
Generate RevBuilder structs in codegen alongside ProtoBuilder.
RevBuilder writes fields into a buffer starting from the end,
allowing fields to be set in reverse declaration order. This
avoids reallocation and produces valid protobuf data matching
the forward layout.

Update generated interop files and add comprehensive tests for
wire format, nesting, map entries, overflow handling, and buffer
marking utilities.
2026-06-19 19:39:21 -07:00
charles 3640af6e57 Format generated interop.rs 2026-06-18 22:38:37 -07:00
charles 3d0eab01cf Update codegen to suppress more compiler warnings 2026-06-18 22:36:11 -07:00
9 changed files with 5194 additions and 3063 deletions
+256 -13
View File
@@ -7,11 +7,11 @@ use crate::runtime::ProtoAccessor;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::str; use std::str;
const DATA_IMPORTS: &str = "#[allow(unused)]\n\ const DATA_IMPORTS: &str = "#[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]\n\
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};\n\ use roto_runtime::{ProtoAccessor, ProtoBuilder, RevBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};\n\
use core::str;\n\ use core::str;\n\
use bytes::{Bytes, BytesMut, Buf, BufMut};\n"; use bytes::{Bytes, BytesMut, Buf, BufMut};\n";
const SERVICE_IMPORTS: &str = "#[allow(unused)]\n\ const SERVICE_IMPORTS: &str = "#[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]\n\
use tonic::{Request, Response, Status};\n\ use tonic::{Request, Response, Status};\n\
use tokio_stream::Stream;\n\ use tokio_stream::Stream;\n\
use std::pin::Pin;\n\ use std::pin::Pin;\n\
@@ -191,7 +191,52 @@ fn write_enum(enum_proto: &EnumDescriptorProto, output: &mut String) {
output.push_str(" }\n }\n}\n\n"); output.push_str(" }\n }\n}\n\n");
} }
fn write_message(msg_proto: &DescriptorProto, output: &mut String) { /// Recursively build a mapping from proto type short name to generated Rust path.
/// Handles nested messages like DescriptorProto.ExtensionRange -> descriptor_proto::ExtensionRange
fn collect_type_paths(
msg_proto: &DescriptorProto,
parent_mod: &str,
registry: &mut HashMap<String, String>,
) {
let msg_name = to_pascal_case(msg_proto.name().unwrap());
let mod_name = to_snake_case(msg_proto.name().unwrap());
let rust_path = if parent_mod.is_empty() {
msg_name.clone()
} else {
format!("{}::{}", parent_mod, msg_name)
};
// Register this message under its short name
registry.insert(msg_name.clone(), rust_path);
let child_mod = if parent_mod.is_empty() {
mod_name.clone()
} else {
format!("{}::{}", parent_mod, mod_name)
};
for m_res in msg_proto.nested_type() {
let (m_data, _) = m_res.expect("Failed to iterate nested message");
let nested = DescriptorProto::new(m_data).expect("Failed to parse nested message");
collect_type_paths(&nested, &child_mod, registry);
}
}
pub fn write_message(
msg_proto: &DescriptorProto,
output: &mut String,
type_registry: &HashMap<String, String>,
module_depth: usize,
) {
fn qualify_type(type_path: &str, depth: usize) -> String {
if depth == 0 {
type_path.to_string()
} else {
let prefix = (0..depth).map(|_| "super::").collect::<String>();
format!("{}{}", prefix, type_path)
}
}
let msg_name = to_pascal_case(msg_proto.name().unwrap()); let msg_name = to_pascal_case(msg_proto.name().unwrap());
let mod_name = to_snake_case(msg_proto.name().unwrap()); let mod_name = to_snake_case(msg_proto.name().unwrap());
@@ -216,6 +261,22 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
}) })
.unwrap_or(false); .unwrap_or(false);
let type_name = if f_type == 11 {
field_proto.type_name().ok().and_then(|s| {
// Extract the short type name (last component)
let short = s
.split('.')
.filter(|p| !p.is_empty())
.last()
.unwrap_or("")
.to_string();
// Look up the full Rust path in the registry
type_registry.get(&short).cloned()
})
} else {
None
};
fields_info.push(( fields_info.push((
field_name.to_string(), field_name.to_string(),
tag, tag,
@@ -223,6 +284,7 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
f_label, f_label,
oneof_index, oneof_index,
is_map, is_map,
type_name,
)); ));
} }
@@ -235,7 +297,7 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
output.push_str(&format!("pub struct {}<'a> {{\n", msg_name)); output.push_str(&format!("pub struct {}<'a> {{\n", msg_name));
output.push_str(" accessor: roto_runtime::ProtoAccessor<'a>,\n"); output.push_str(" accessor: roto_runtime::ProtoAccessor<'a>,\n");
for (field_name, _tag, _f_type, f_label, _oneof_index, _is_map) in &fields_info { for (field_name, _tag, _f_type, f_label, _oneof_index, _is_map, _type_name) in &fields_info {
if *f_label == 3 { if *f_label == 3 {
output.push_str(&format!(" {}_start: Option<usize>,\n", field_name)); output.push_str(&format!(" {}_start: Option<usize>,\n", field_name));
output.push_str(&format!(" {}_end: Option<usize>,\n", field_name)); output.push_str(&format!(" {}_end: Option<usize>,\n", field_name));
@@ -248,7 +310,7 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
output.push_str(&format!("impl<'a> {}<'a> {{\n", msg_name)); output.push_str(&format!("impl<'a> {}<'a> {{\n", msg_name));
output.push_str(" pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {\n"); output.push_str(" pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {\n");
output.push_str(" let accessor = roto_runtime::ProtoAccessor::new(data)?;\n"); output.push_str(" let accessor = roto_runtime::ProtoAccessor::new(data)?;\n");
for (name, _, _, label, _oneof_index, _is_map) in &fields_info { for (name, _, _, label, _oneof_index, _is_map, _type_name) in &fields_info {
if *label == 3 { if *label == 3 {
output.push_str(&format!(" let mut {}_start = None;\n", name)); output.push_str(&format!(" let mut {}_start = None;\n", name));
output.push_str(&format!(" let mut {}_end = None;\n", name)); output.push_str(&format!(" let mut {}_end = None;\n", name));
@@ -259,7 +321,7 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
output.push_str(" for item in accessor.fields() {\n"); output.push_str(" for item in accessor.fields() {\n");
output.push_str(" let (offset, tag, _) = item?;\n"); output.push_str(" let (offset, tag, _) = item?;\n");
for (name, tag, _, label, _oneof_index, _is_map) in &fields_info { for (name, tag, _, label, _oneof_index, _is_map, _type_name) in &fields_info {
if *label == 3 { if *label == 3 {
output.push_str(&format!(" if tag.field_number == {} {{\n", tag)); output.push_str(&format!(" if tag.field_number == {} {{\n", tag));
output.push_str(&format!( output.push_str(&format!(
@@ -279,7 +341,7 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
output.push_str(" Ok(Self {\n"); output.push_str(" Ok(Self {\n");
output.push_str(" accessor,\n"); output.push_str(" accessor,\n");
for (name, _, _, label, _oneof_index, _is_map) in &fields_info { for (name, _, _, label, _oneof_index, _is_map, _type_name) in &fields_info {
if *label == 3 { if *label == 3 {
output.push_str(&format!("{}_start, {}_end,\n", name, name)); output.push_str(&format!("{}_start, {}_end,\n", name, name));
} else { } else {
@@ -288,8 +350,10 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
} }
output.push_str(" })\n }\n\n"); output.push_str(" })\n }\n\n");
for (field_name, tag, f_type, f_label, _oneof_index, is_map) in &fields_info { // Collect typed iterator info for repeated message fields (generated after the impl block)
let (rust_type, logic, default_val) = map_type_to_rust_accessor(*f_type, *f_label, *is_map); let mut typed_iters: Vec<(String, String, String)> = Vec::new();
for (field_name, tag, f_type, f_label, _oneof_index, is_map, type_name) in &fields_info {
let safe_name = if field_name == "type" { let safe_name = if field_name == "type" {
format!("r#{}", field_name) format!("r#{}", field_name)
} else { } else {
@@ -297,6 +361,8 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
}; };
if *f_label == 3 { if *f_label == 3 {
// Repeated field — use the original accessor for the raw iterator
let (rust_type, _, _) = map_type_to_rust_accessor(*f_type, *f_label, *is_map);
output.push_str(&format!( output.push_str(&format!(
" pub fn {}(&self) -> {} {{\n", " pub fn {}(&self) -> {} {{\n",
safe_name, rust_type safe_name, rust_type
@@ -319,7 +385,71 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
)); ));
} }
output.push_str(" }\n }\n\n"); output.push_str(" }\n }\n\n");
// Generate typed iterator for repeated message fields
if *f_type == 11 {
if let Some(inner_type) = type_name {
let qualified = qualify_type(inner_type, module_depth);
// Use {ParentMsg}{Field}Iter to guarantee uniqueness
let pascal_field = to_pascal_case(field_name);
let iter_name = format!("{}{}Iter", msg_name, pascal_field);
// Schedule iterator struct for generation after impl block
typed_iters.push((iter_name, qualified, safe_name.clone()));
}
}
} else if *f_type == 11 {
// Typed singular message field
if let Some(inner_type) = type_name {
let qualified = qualify_type(inner_type, module_depth);
output.push_str(&format!(
" pub fn {}(&self) -> roto_runtime::Result<{}<'a>> {{\n",
safe_name, qualified
));
output.push_str(&format!(
" let offset = self.{}_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;\n",
field_name
));
output.push_str(" let (bytes, _) = self.accessor.get_value_at(offset)?;\n");
output.push_str(&format!(" {}::new(bytes)\n", qualified));
output.push_str(" }\n\n");
output.push_str(&format!(
" pub fn has_{}(&self) -> bool {{ self.{}_offset.is_some() }}\n\n",
field_name, field_name
));
} else { } else {
// Fallback — no type name, treat as raw bytes
let (rust_type, logic, default_val) =
map_type_to_rust_accessor(*f_type, *f_label, *is_map);
output.push_str(&format!(
" pub fn {}(&self) -> roto_runtime::Result<{}> {{\n",
safe_name, rust_type
));
output.push_str(&format!(
" let offset = self.{}_offset.ok_or(roto_runtime::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(&format!(
" pub fn {}_or_default(&self) -> roto_runtime::Result<{}> {{\n",
safe_name, rust_type
));
output.push_str(&format!(
" self.{}().or(Ok({}))\n",
safe_name, default_val
));
output.push_str(" }\n\n");
output.push_str(&format!(
" pub fn has_{}(&self) -> bool {{ self.{}_offset.is_some() }}\n\n",
field_name, field_name
));
}
} else {
// Non-message singular field — use the original accessor
let (rust_type, logic, default_val) =
map_type_to_rust_accessor(*f_type, *f_label, *is_map);
output.push_str(&format!( output.push_str(&format!(
" pub fn {}(&self) -> roto_runtime::Result<{}> {{\n", " pub fn {}(&self) -> roto_runtime::Result<{}> {{\n",
safe_name, rust_type safe_name, rust_type
@@ -362,7 +492,9 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
snake_oneof_name, return_type snake_oneof_name, return_type
); );
output.push_str(&signature); output.push_str(&signature);
for (field_name, _tag, _f_type, _f_label, f_oneof_index, _is_map) in &fields_info { for (field_name, _tag, _f_type, _f_label, f_oneof_index, _is_map, _type_name) in
&fields_info
{
if *f_oneof_index == Some(oneof_index as i32) { if *f_oneof_index == Some(oneof_index as i32) {
let safe_field_name = if field_name == "type" { let safe_field_name = if field_name == "type" {
format!("r#{}", field_name) format!("r#{}", field_name)
@@ -383,12 +515,47 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
output.push_str(" Ok(None)\n }\n\n"); output.push_str(" Ok(None)\n }\n\n");
} }
// Typed iterator accessors (for repeated message fields)
for (iter_name, _inner_type, safe_field) in &typed_iters {
output.push_str(&format!(
" pub fn {}_iter(&self) -> {}<'a> {{\n",
safe_field, iter_name
));
output.push_str(&format!(
" {}::new(self.{}())\n",
iter_name, safe_field
));
output.push_str(" }\n\n");
}
// raw_fields() convenience on the message struct (before closing the impl) // raw_fields() convenience on the message struct (before closing the impl)
output.push_str(" pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {\n"); output.push_str(" pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {\n");
output.push_str(" self.accessor.raw_fields()\n"); output.push_str(" self.accessor.raw_fields()\n");
output.push_str(" }\n\n"); output.push_str(" }\n\n");
output.push_str("}\n\n"); output.push_str("}\n\n");
// Generate typed iterator structs (outside the impl block)
for (iter_name, inner_type, _safe_field) in &typed_iters {
output.push_str(&format!("pub struct {}<'a> {{\n", iter_name));
output.push_str(" inner: roto_runtime::RepeatedFieldIterator<'a>,\n");
output.push_str("}\n\n");
output.push_str(&format!("impl<'a> {}<'a> {{\n", iter_name));
output.push_str(&format!(
" pub fn new(iter: roto_runtime::RepeatedFieldIterator<'a>) -> Self {{\n Self {{ inner: iter }}\n }}\n\n"
));
output.push_str("}\n\n");
output.push_str(&format!("impl<'a> Iterator for {}<'a> {{\n", iter_name));
output.push_str(&format!(
" type Item = roto_runtime::Result<{}<'a>>;\n",
inner_type
));
output.push_str(" fn next(&mut self) -> Option<Self::Item> {\n");
output.push_str(" self.inner.next().map(|item| {\n");
output.push_str(" let (bytes, _) = item?;\n");
output.push_str(&format!(" {}::new(bytes)\n", inner_type));
output.push_str(" })\n }\n}\n\n");
}
// Collect builder field info so we can use it multiple times below. // Collect builder field info so we can use it multiple times below.
// Tuple: (field_name, safe_name, tag, rust_type, write_method) // Tuple: (field_name, safe_name, tag, rust_type, write_method)
let mut builder_fields: Vec<(String, String, u32, String, String)> = Vec::new(); let mut builder_fields: Vec<(String, String, u32, String, String)> = Vec::new();
@@ -460,6 +627,59 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
output.push_str(&format!(" pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {{\n self.builder.finish()\n }}\n}}\n\n")); output.push_str(&format!(" pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {{\n self.builder.finish()\n }}\n}}\n\n"));
// RevBuilder struct — reverse encoding, one `_written: bool` flag per field
output.push_str(&format!("pub struct {}RevBuilder<'b> {{\n", msg_name));
output.push_str(" builder: roto_runtime::RevBuilder<'b>,\n");
for (field_name, _, _, _, _) in &builder_fields {
output.push_str(&format!(" {}_written: bool,\n", field_name));
}
output.push_str(&format!("}}\n\nimpl<'b> {}RevBuilder<'b> {{\n", msg_name));
// Constructor
output.push_str(&format!(
" pub fn builder(buf: &mut [u8]) -> {}RevBuilder<'_> {{\n {}RevBuilder {{\n",
msg_name, msg_name
));
output.push_str(" builder: roto_runtime::RevBuilder::new(buf),\n");
for (field_name, _, _, _, _) in &builder_fields {
output.push_str(&format!(" {}_written: false,\n", field_name));
}
output.push_str(" }\n }\n\n");
// Per-field setters — same as ProtoBuilder but using RevBuilder methods
for (field_name, safe_name, tag, rust_type, method) in &builder_fields {
output.push_str(&format!(
" pub fn {}(mut self, value: {}) -> roto_runtime::Result<Self> {{\n self.builder.{}({}, value)?;\n self.{}_written = true;\n Ok(self)\n }}\n\n",
safe_name, rust_type, method, tag, field_name
));
}
// with() — copies unseen fields from an existing message (iterate in reverse for RevBuilder)
output.push_str(&format!(
" pub fn with(mut self, msg: &{}<'_>) -> roto_runtime::Result<Self> {{\n",
msg_name
));
output.push_str(" let fields: Vec<_> = msg.accessor.raw_fields().collect();\n");
output.push_str(" for item in fields.into_iter().rev() {\n");
output.push_str(" let (field_number, raw_bytes) = item?;\n");
output.push_str(" let is_written = match field_number {\n");
for (field_name, _, tag, _, _) in &builder_fields {
output.push_str(&format!(
" {} => self.{}_written,\n",
tag, field_name
));
}
output.push_str(" _ => false,\n");
output.push_str(" };\n");
output.push_str(" if !is_written {\n");
output.push_str(" self.builder.write_raw(raw_bytes)?;\n");
output.push_str(" }\n");
output.push_str(" }\n");
output.push_str(" Ok(self)\n");
output.push_str(" }\n\n");
output.push_str(&format!(" pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {{\n self.builder.finish()\n }}\n}}\n\n"));
output.push_str(&format!("pub struct Owned{} {{\n", msg_name)); output.push_str(&format!("pub struct Owned{} {{\n", msg_name));
output.push_str(" pub data: bytes::Bytes,\n"); output.push_str(" pub data: bytes::Bytes,\n");
output.push_str("}\n\n"); output.push_str("}\n\n");
@@ -516,6 +736,8 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
write_message( write_message(
&DescriptorProto::new(m_data).expect("Failed to parse nested DescriptorProto"), &DescriptorProto::new(m_data).expect("Failed to parse nested DescriptorProto"),
output, output,
type_registry,
module_depth + 1,
); );
} }
@@ -525,7 +747,9 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
let oneof_name = oneof_desc.name().unwrap(); let oneof_name = oneof_desc.name().unwrap();
let pascal_oneof_name = to_pascal_case(oneof_name); let pascal_oneof_name = to_pascal_case(oneof_name);
output.push_str(&format!("pub enum {}<'a> {{\n", pascal_oneof_name)); output.push_str(&format!("pub enum {}<'a> {{\n", pascal_oneof_name));
for (field_name, _tag, f_type, f_label, f_oneof_index, _is_map) in &fields_info { for (field_name, _tag, f_type, f_label, f_oneof_index, _is_map, _type_name) in
&fields_info
{
if *f_oneof_index == Some(oneof_index as i32) { if *f_oneof_index == Some(oneof_index as i32) {
let (rust_type, _, _) = map_type_to_rust_accessor(*f_type, *f_label, *_is_map); let (rust_type, _, _) = map_type_to_rust_accessor(*f_type, *f_label, *_is_map);
let safe_field_name = if field_name == "type" { let safe_field_name = if field_name == "type" {
@@ -591,7 +815,6 @@ where
let mut output = String::new(); let mut output = String::new();
output.push_str("// @generated by protoc-gen-roto — do not edit\n"); output.push_str("// @generated by protoc-gen-roto — do not edit\n");
output.push_str("#[allow(unused_imports)]\n");
output.push_str(imports); output.push_str(imports);
for dep_res in file_proto.dependency() { for dep_res in file_proto.dependency() {
@@ -676,6 +899,21 @@ pub fn generate_protobuf_code(
generate_mod_files, generate_mod_files,
DATA_IMPORTS, DATA_IMPORTS,
|file_proto, output| { |file_proto, output| {
// Build a global type registry from ALL files in the descriptor set,
// so cross-file type references (e.g., FeatureSet defined in one file,
// used in another) resolve correctly.
let mut type_registry: HashMap<String, String> = HashMap::new();
for file_res in set.file() {
let (file_data, _) = file_res.expect("Failed to iterate file");
let fp = FileDescriptorProto::new(file_data).expect("Failed to parse file");
for msg_res in fp.message_type() {
let (msg_data, _) = msg_res.expect("Failed to iterate message");
let msg_proto =
DescriptorProto::new(msg_data).expect("Failed to parse message");
collect_type_paths(&msg_proto, "", &mut type_registry);
}
}
// 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");
@@ -692,6 +930,8 @@ pub fn generate_protobuf_code(
write_message( write_message(
&DescriptorProto::new(msg_data).expect("Failed to parse DescriptorProto"), &DescriptorProto::new(msg_data).expect("Failed to parse DescriptorProto"),
output, output,
&type_registry,
0,
); );
} }
}, },
@@ -773,6 +1013,9 @@ fn strip_boilerplate(content: &str) -> String {
"#[allow(unused_imports)]\n", "#[allow(unused_imports)]\n",
"#![allow(unused_imports)]\n\n", "#![allow(unused_imports)]\n\n",
"#![allow(unused_imports)]\n", "#![allow(unused_imports)]\n",
"#[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]\n",
"#![allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]\n",
"#![allow(unused, unused_imports, unused_assignments, unused_variables)]\n",
]; ];
for pattern in patterns { for pattern in patterns {
+1 -1
View File
@@ -1,4 +1,4 @@
pub const DATA_IMPORTS: &str = "use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};\nuse core::str;\nuse bytes::{Bytes, BytesMut, Buf, BufMut};\n"; pub const DATA_IMPORTS: &str = "use roto_runtime::{ProtoAccessor, ProtoBuilder, RevBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};\nuse core::str;\nuse bytes::{Bytes, BytesMut, Buf, BufMut};\n";
pub fn to_pascal_case(s: &str) -> String { pub fn to_pascal_case(s: &str) -> String {
s.split('_') s.split('_')
+221 -108
View File
@@ -1,21 +1,29 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#[allow(unused)] #![allow(
unused,
unused_imports,
unused_assignments,
unused_variables,
non_camel_case_types
)]
use crate::runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator}; use crate::runtime::{
use std::str; ProtoAccessor, ProtoBuilder, RepeatedFieldIterator, Result, RotoError, read_varint,
use bytes::{Bytes, BytesMut, Buf, BufMut}; };
use tonic::{Request, Response, Status}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use tokio_stream::Stream; use futures_util::StreamExt;
use http_body::Body;
use http_body_util::BodyExt;
use roto_tonic::{BufferPool, StatusBody};
use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::str;
use std::sync::Arc; use std::sync::Arc;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::future::Future; use tokio_stream::Stream;
use tonic::body::BoxBody; use tonic::body::BoxBody;
use tonic::{Request, Response, Status};
use tower::Service; use tower::Service;
use futures_util::StreamExt;
use http_body_util::BodyExt;
use http_body::Body;
use roto_tonic::{BufferPool, StatusBody};
use crate::google::protobuf::descriptor; use crate::google::protobuf::descriptor;
@@ -36,59 +44,87 @@ impl<'a> Version<'a> {
let mut suffix_offset = None; let mut suffix_offset = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { major_offset = Some(offset); } if tag.field_number == 1 {
if tag.field_number == 2 { minor_offset = Some(offset); } major_offset = Some(offset);
if tag.field_number == 3 { patch_offset = Some(offset); } }
if tag.field_number == 4 { suffix_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 { Ok(Self {
accessor, accessor,
major_offset, major_offset,
minor_offset, minor_offset,
patch_offset, patch_offset,
suffix_offset, suffix_offset,
}) })
} }
pub fn major(&self) -> crate::runtime::Result<i32> { pub fn major(&self) -> crate::runtime::Result<i32> {
let offset = self.major_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.major_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::runtime::RotoError::WireFormatViolation) crate::runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn major_or_default(&self) -> crate::runtime::Result<i32> { pub fn major_or_default(&self) -> crate::runtime::Result<i32> {
self.major().or(Ok(0)) self.major().or(Ok(0))
} }
pub fn has_major(&self) -> bool { self.major_offset.is_some() } pub fn has_major(&self) -> bool {
self.major_offset.is_some()
}
pub fn minor(&self) -> crate::runtime::Result<i32> { pub fn minor(&self) -> crate::runtime::Result<i32> {
let offset = self.minor_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.minor_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::runtime::RotoError::WireFormatViolation) crate::runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn minor_or_default(&self) -> crate::runtime::Result<i32> { pub fn minor_or_default(&self) -> crate::runtime::Result<i32> {
self.minor().or(Ok(0)) self.minor().or(Ok(0))
} }
pub fn has_minor(&self) -> bool { self.minor_offset.is_some() } pub fn has_minor(&self) -> bool {
self.minor_offset.is_some()
}
pub fn patch(&self) -> crate::runtime::Result<i32> { pub fn patch(&self) -> crate::runtime::Result<i32> {
let offset = self.patch_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.patch_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::runtime::RotoError::WireFormatViolation) crate::runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn patch_or_default(&self) -> crate::runtime::Result<i32> { pub fn patch_or_default(&self) -> crate::runtime::Result<i32> {
self.patch().or(Ok(0)) self.patch().or(Ok(0))
} }
pub fn has_patch(&self) -> bool { self.patch_offset.is_some() } pub fn has_patch(&self) -> bool {
self.patch_offset.is_some()
}
pub fn suffix(&self) -> crate::runtime::Result<&'a str> { pub fn suffix(&self) -> crate::runtime::Result<&'a str> {
let offset = self.suffix_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.suffix_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
@@ -97,12 +133,13 @@ suffix_offset,
self.suffix().or(Ok("")) self.suffix().or(Ok(""))
} }
pub fn has_suffix(&self) -> bool { self.suffix_offset.is_some() } pub fn has_suffix(&self) -> bool {
self.suffix_offset.is_some()
}
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct VersionBuilder<'b> { pub struct VersionBuilder<'b> {
@@ -217,28 +254,41 @@ impl<'a> CodeGeneratorRequest<'a> {
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { if tag.field_number == 1 {
if file_to_generate_start.is_none() { file_to_generate_start = Some(offset); } if file_to_generate_start.is_none() {
file_to_generate_start = Some(offset);
}
file_to_generate_end = Some(offset); file_to_generate_end = Some(offset);
} }
if tag.field_number == 2 { parameter_offset = Some(offset); } if tag.field_number == 2 {
parameter_offset = Some(offset);
}
if tag.field_number == 15 { if tag.field_number == 15 {
if proto_file_start.is_none() { proto_file_start = Some(offset); } if proto_file_start.is_none() {
proto_file_start = Some(offset);
}
proto_file_end = Some(offset); proto_file_end = Some(offset);
} }
if tag.field_number == 17 { if tag.field_number == 17 {
if source_file_descriptors_start.is_none() { source_file_descriptors_start = Some(offset); } if source_file_descriptors_start.is_none() {
source_file_descriptors_start = Some(offset);
}
source_file_descriptors_end = Some(offset); source_file_descriptors_end = Some(offset);
} }
if tag.field_number == 3 { compiler_version_offset = Some(offset); } if tag.field_number == 3 {
compiler_version_offset = Some(offset);
}
} }
Ok(Self { Ok(Self {
accessor, accessor,
file_to_generate_start, file_to_generate_end, file_to_generate_start,
parameter_offset, file_to_generate_end,
proto_file_start, proto_file_end, parameter_offset,
source_file_descriptors_start, source_file_descriptors_end, proto_file_start,
compiler_version_offset, proto_file_end,
source_file_descriptors_start,
source_file_descriptors_end,
compiler_version_offset,
}) })
} }
@@ -250,7 +300,9 @@ compiler_version_offset,
} }
pub fn parameter(&self) -> crate::runtime::Result<&'a str> { pub fn parameter(&self) -> crate::runtime::Result<&'a str> {
let offset = self.parameter_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.parameter_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
@@ -259,7 +311,9 @@ compiler_version_offset,
self.parameter().or(Ok("")) self.parameter().or(Ok(""))
} }
pub fn has_parameter(&self) -> bool { self.parameter_offset.is_some() } pub fn has_parameter(&self) -> bool {
self.parameter_offset.is_some()
}
pub fn proto_file(&self) -> crate::runtime::RepeatedFieldIterator<'a> { pub fn proto_file(&self) -> crate::runtime::RepeatedFieldIterator<'a> {
match (self.proto_file_start, self.proto_file_end) { match (self.proto_file_start, self.proto_file_end) {
@@ -269,14 +323,19 @@ compiler_version_offset,
} }
pub fn source_file_descriptors(&self) -> crate::runtime::RepeatedFieldIterator<'a> { pub fn source_file_descriptors(&self) -> crate::runtime::RepeatedFieldIterator<'a> {
match (self.source_file_descriptors_start, self.source_file_descriptors_end) { match (
self.source_file_descriptors_start,
self.source_file_descriptors_end,
) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(17, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(17, start, end),
_ => self.accessor.iter_repeated(17), _ => self.accessor.iter_repeated(17),
} }
} }
pub fn compiler_version(&self) -> crate::runtime::Result<&'a [u8]> { pub fn compiler_version(&self) -> crate::runtime::Result<&'a [u8]> {
let offset = self.compiler_version_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.compiler_version_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes) Ok(bytes)
} }
@@ -285,12 +344,13 @@ compiler_version_offset,
self.compiler_version().or(Ok(&[])) self.compiler_version().or(Ok(&[]))
} }
pub fn has_compiler_version(&self) -> bool { self.compiler_version_offset.is_some() } pub fn has_compiler_version(&self) -> bool {
self.compiler_version_offset.is_some()
}
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct CodeGeneratorRequestBuilder<'b> { pub struct CodeGeneratorRequestBuilder<'b> {
@@ -409,28 +469,41 @@ impl<'a> CodeGeneratorResponse<'a> {
let mut file_end = None; let mut file_end = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { error_offset = Some(offset); } if tag.field_number == 1 {
if tag.field_number == 2 { supported_features_offset = Some(offset); } error_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 == 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 tag.field_number == 15 {
if file_start.is_none() { file_start = Some(offset); } if file_start.is_none() {
file_start = Some(offset);
}
file_end = Some(offset); file_end = Some(offset);
} }
} }
Ok(Self { Ok(Self {
accessor, accessor,
error_offset, error_offset,
supported_features_offset, supported_features_offset,
minimum_edition_offset, minimum_edition_offset,
maximum_edition_offset, maximum_edition_offset,
file_start, file_end, file_start,
file_end,
}) })
} }
pub fn error(&self) -> crate::runtime::Result<&'a str> { pub fn error(&self) -> crate::runtime::Result<&'a str> {
let offset = self.error_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.error_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
@@ -439,43 +512,63 @@ file_start, file_end,
self.error().or(Ok("")) self.error().or(Ok(""))
} }
pub fn has_error(&self) -> bool { self.error_offset.is_some() } pub fn has_error(&self) -> bool {
self.error_offset.is_some()
}
pub fn supported_features(&self) -> crate::runtime::Result<u32> { pub fn supported_features(&self) -> crate::runtime::Result<u32> {
let offset = self.supported_features_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.supported_features_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::runtime::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| crate::runtime::RotoError::WireFormatViolation) crate::runtime::read_varint(bytes)
.map(|(v, _)| v as u32)
.map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn supported_features_or_default(&self) -> crate::runtime::Result<u32> { pub fn supported_features_or_default(&self) -> crate::runtime::Result<u32> {
self.supported_features().or(Ok(0)) self.supported_features().or(Ok(0))
} }
pub fn has_supported_features(&self) -> bool { self.supported_features_offset.is_some() } pub fn has_supported_features(&self) -> bool {
self.supported_features_offset.is_some()
}
pub fn minimum_edition(&self) -> crate::runtime::Result<i32> { pub fn minimum_edition(&self) -> crate::runtime::Result<i32> {
let offset = self.minimum_edition_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.minimum_edition_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::runtime::RotoError::WireFormatViolation) crate::runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn minimum_edition_or_default(&self) -> crate::runtime::Result<i32> { pub fn minimum_edition_or_default(&self) -> crate::runtime::Result<i32> {
self.minimum_edition().or(Ok(0)) self.minimum_edition().or(Ok(0))
} }
pub fn has_minimum_edition(&self) -> bool { self.minimum_edition_offset.is_some() } pub fn has_minimum_edition(&self) -> bool {
self.minimum_edition_offset.is_some()
}
pub fn maximum_edition(&self) -> crate::runtime::Result<i32> { pub fn maximum_edition(&self) -> crate::runtime::Result<i32> {
let offset = self.maximum_edition_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.maximum_edition_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::runtime::RotoError::WireFormatViolation) crate::runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn maximum_edition_or_default(&self) -> crate::runtime::Result<i32> { pub fn maximum_edition_or_default(&self) -> crate::runtime::Result<i32> {
self.maximum_edition().or(Ok(0)) self.maximum_edition().or(Ok(0))
} }
pub fn has_maximum_edition(&self) -> bool { self.maximum_edition_offset.is_some() } pub fn has_maximum_edition(&self) -> bool {
self.maximum_edition_offset.is_some()
}
pub fn file(&self) -> crate::runtime::RepeatedFieldIterator<'a> { pub fn file(&self) -> crate::runtime::RepeatedFieldIterator<'a> {
match (self.file_start, self.file_end) { match (self.file_start, self.file_end) {
@@ -487,7 +580,6 @@ file_start, file_end,
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct CodeGeneratorResponseBuilder<'b> { pub struct CodeGeneratorResponseBuilder<'b> {
@@ -586,15 +678,15 @@ impl crate::runtime::RotoMessage for OwnedCodeGeneratorResponse {
} }
pub mod code_generator_response { pub mod code_generator_response {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)] #[repr(i32)]
pub enum Feature { pub enum Feature {
FEATURENONE = 0, FEATURENONE = 0,
FEATUREPROTO3OPTIONAL = 1, FEATUREPROTO3OPTIONAL = 1,
FEATURESUPPORTSEDITIONS = 2, FEATURESUPPORTSEDITIONS = 2,
} }
impl Feature { impl Feature {
pub fn from_i32(value: i32) -> Self { pub fn from_i32(value: i32) -> Self {
match value { match value {
0 => Feature::FEATURENONE, 0 => Feature::FEATURENONE,
@@ -603,17 +695,17 @@ impl Feature {
_ => Feature::FEATURENONE, _ => Feature::FEATURENONE,
} }
} }
} }
pub struct File<'a> { pub struct File<'a> {
accessor: crate::runtime::ProtoAccessor<'a>, accessor: crate::runtime::ProtoAccessor<'a>,
name_offset: Option<usize>, name_offset: Option<usize>,
insertion_point_offset: Option<usize>, insertion_point_offset: Option<usize>,
content_offset: Option<usize>, content_offset: Option<usize>,
generated_code_info_offset: Option<usize>, generated_code_info_offset: Option<usize>,
} }
impl<'a> File<'a> { impl<'a> File<'a> {
pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> { pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = crate::runtime::ProtoAccessor::new(data)?; let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut name_offset = None; let mut name_offset = None;
@@ -622,23 +714,33 @@ impl<'a> File<'a> {
let mut generated_code_info_offset = None; let mut generated_code_info_offset = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { name_offset = Some(offset); } if tag.field_number == 1 {
if tag.field_number == 2 { insertion_point_offset = Some(offset); } name_offset = Some(offset);
if tag.field_number == 15 { content_offset = Some(offset); } }
if tag.field_number == 16 { generated_code_info_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 { Ok(Self {
accessor, accessor,
name_offset, name_offset,
insertion_point_offset, insertion_point_offset,
content_offset, content_offset,
generated_code_info_offset, generated_code_info_offset,
}) })
} }
pub fn name(&self) -> crate::runtime::Result<&'a str> { pub fn name(&self) -> crate::runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.name_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
@@ -647,10 +749,14 @@ generated_code_info_offset,
self.name().or(Ok("")) self.name().or(Ok(""))
} }
pub fn has_name(&self) -> bool { self.name_offset.is_some() } pub fn has_name(&self) -> bool {
self.name_offset.is_some()
}
pub fn insertion_point(&self) -> crate::runtime::Result<&'a str> { pub fn insertion_point(&self) -> crate::runtime::Result<&'a str> {
let offset = self.insertion_point_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.insertion_point_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
@@ -659,10 +765,14 @@ generated_code_info_offset,
self.insertion_point().or(Ok("")) self.insertion_point().or(Ok(""))
} }
pub fn has_insertion_point(&self) -> bool { self.insertion_point_offset.is_some() } pub fn has_insertion_point(&self) -> bool {
self.insertion_point_offset.is_some()
}
pub fn content(&self) -> crate::runtime::Result<&'a str> { pub fn content(&self) -> crate::runtime::Result<&'a str> {
let offset = self.content_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.content_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
@@ -671,10 +781,14 @@ generated_code_info_offset,
self.content().or(Ok("")) self.content().or(Ok(""))
} }
pub fn has_content(&self) -> bool { self.content_offset.is_some() } pub fn has_content(&self) -> bool {
self.content_offset.is_some()
}
pub fn generated_code_info(&self) -> crate::runtime::Result<&'a [u8]> { pub fn generated_code_info(&self) -> crate::runtime::Result<&'a [u8]> {
let offset = self.generated_code_info_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?; let offset = self
.generated_code_info_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes) Ok(bytes)
} }
@@ -683,23 +797,24 @@ generated_code_info_offset,
self.generated_code_info().or(Ok(&[])) self.generated_code_info().or(Ok(&[]))
} }
pub fn has_generated_code_info(&self) -> bool { self.generated_code_info_offset.is_some() } pub fn has_generated_code_info(&self) -> bool {
self.generated_code_info_offset.is_some()
}
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
}
} pub struct FileBuilder<'b> {
pub struct FileBuilder<'b> {
builder: crate::runtime::ProtoBuilder<'b>, builder: crate::runtime::ProtoBuilder<'b>,
name_written: bool, name_written: bool,
insertion_point_written: bool, insertion_point_written: bool,
content_written: bool, content_written: bool,
generated_code_info_written: bool, generated_code_info_written: bool,
} }
impl<'b> FileBuilder<'b> { impl<'b> FileBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> { pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
FileBuilder { FileBuilder {
builder: crate::runtime::ProtoBuilder::new(buf), builder: crate::runtime::ProtoBuilder::new(buf),
@@ -754,20 +869,20 @@ impl<'b> FileBuilder<'b> {
pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> { pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
pub struct OwnedFile { pub struct OwnedFile {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
impl crate::runtime::RotoOwned for OwnedFile { impl crate::runtime::RotoOwned for OwnedFile {
type Reader<'a> = File<'a>; type Reader<'a> = File<'a>;
fn reader(&self) -> File<'_> { fn reader(&self) -> File<'_> {
File::new(&self.data).expect("failed to create reader") File::new(&self.data).expect("failed to create reader")
} }
} }
impl crate::runtime::RotoMessage for OwnedFile { impl crate::runtime::RotoMessage for OwnedFile {
fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedFile { data: buf }) Ok(OwnedFile { data: buf })
} }
@@ -775,7 +890,5 @@ impl crate::runtime::RotoMessage for OwnedFile {
fn bytes(&self) -> bytes::Bytes { fn bytes(&self) -> bytes::Bytes {
self.data.clone() self.data.clone()
} }
}
} }
}
File diff suppressed because it is too large Load Diff
+18 -6
View File
@@ -1,12 +1,19 @@
use tonic::Request; use hello::{OwnedHelloRequest, OwnedHelloResponse};
use roto_tonic::RotoCodec;
use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse};
use roto_runtime::RotoOwned; use roto_runtime::RotoOwned;
use roto_tonic::RotoCodec;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use tonic::Request;
use tower::Service; use tower::Service;
pub use roto_tonic::{BufferPool, StatusBody}; pub use roto_tonic::{BufferPool, StatusBody};
#[allow(
unused,
unused_imports,
unused_assignments,
unused_variables,
non_camel_case_types
)]
pub mod hello { pub mod hello {
include!(concat!(env!("OUT_DIR"), "/hello.rs")); include!(concat!(env!("OUT_DIR"), "/hello.rs"));
} }
@@ -45,8 +52,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// We need to specify the method path. For HelloWorldService/HelloWorld, it is "/hello.HelloWorldService/HelloWorld" // We need to specify the method path. For HelloWorldService/HelloWorld, it is "/hello.HelloWorldService/HelloWorld"
let mut buf = vec![0u8; 1024]; let mut buf = vec![0u8; 1024];
let slice = hello::HelloRequestBuilder::builder(&mut buf) let slice = hello::HelloRequestBuilder::builder(&mut buf)
.name("Roto").unwrap() .name("Roto")
.finish().unwrap(); .unwrap()
.finish()
.unwrap();
let request = OwnedHelloRequest { let request = OwnedHelloRequest {
data: bytes::Bytes::copy_from_slice(slice), data: bytes::Bytes::copy_from_slice(slice),
@@ -63,7 +72,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response_msg: OwnedHelloResponse = response.into_inner(); let response_msg: OwnedHelloResponse = response.into_inner();
let reader = response_msg.reader(); let reader = response_msg.reader();
println!("Server responded: {}", reader.message().unwrap_or("No message")); println!(
"Server responded: {}",
reader.message().unwrap_or("No message")
);
Ok(()) Ok(())
} }
+44 -20
View File
@@ -1,20 +1,24 @@
use std::pin::Pin; use bytes::{BufMut, Bytes};
use std::future::Future;
use std::task::{Context, Poll};
use std::sync::{Arc, Mutex};
use tonic::{transport::Server, Request, Response, Status};
use roto_tonic::RotoCodec;
use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse}; use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse};
use tower::Service;
use bytes::{Bytes, BytesMut, Buf, BufMut};
use tonic::body::BoxBody;
use futures_util::StreamExt;
use roto_runtime::{RotoOwned, RotoMessage};
use http_body_util::BodyExt; use http_body_util::BodyExt;
use http_body::Body; use roto_runtime::{RotoMessage, RotoOwned};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use tonic::body::BoxBody;
use tonic::{Request, Response, Status, transport::Server};
use tower::Service;
pub use roto_tonic::{BufferPool, StatusBody}; pub use roto_tonic::{BufferPool, StatusBody};
#[allow(
unused,
unused_imports,
unused_assignments,
unused_variables,
non_camel_case_types
)]
pub mod hello { pub mod hello {
include!(concat!(env!("OUT_DIR"), "/hello.rs")); include!(concat!(env!("OUT_DIR"), "/hello.rs"));
} }
@@ -43,8 +47,10 @@ impl HelloWorldService for MyHelloWorld {
let mut buf = self.pool.get(); let mut buf = self.pool.get();
buf.resize(1024, 0); buf.resize(1024, 0);
let slice = hello::HelloResponseBuilder::builder(&mut buf[..]) let slice = hello::HelloResponseBuilder::builder(&mut buf[..])
.message(&format!("Hello {}!", name)).unwrap() .message(&format!("Hello {}!", name))
.finish().unwrap(); .unwrap()
.finish()
.unwrap();
let res_len = slice.len(); let res_len = slice.len();
let response_bytes = buf.split_to(res_len).freeze(); let response_bytes = buf.split_to(res_len).freeze();
@@ -68,7 +74,10 @@ pub struct HelloWorldServer {
impl HelloWorldServer { impl HelloWorldServer {
pub fn new(inner: MyHelloWorld, pool: Arc<BufferPool>) -> Self { pub fn new(inner: MyHelloWorld, pool: Arc<BufferPool>) -> Self {
Self { inner: Arc::new(inner), pool } Self {
inner: Arc::new(inner),
pool,
}
} }
} }
@@ -111,7 +120,10 @@ impl Service<http::Request<BoxBody>> for HelloWorldServer {
if bytes_vec.len() < 5 { if bytes_vec.len() < 5 {
println!("Body too short: {} bytes", bytes_vec.len()); println!("Body too short: {} bytes", bytes_vec.len());
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder() return Ok(http::Response::builder()
.status(200) .status(200)
.body(res_body) .body(res_body)
@@ -123,8 +135,14 @@ impl Service<http::Request<BoxBody>> for HelloWorldServer {
Ok(msg) => msg, Ok(msg) => msg,
Err(e) => { Err(e) => {
println!("Decode error: {}", e); println!("Decode error: {}", e);
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
} }
}; };
@@ -133,8 +151,14 @@ impl Service<http::Request<BoxBody>> for HelloWorldServer {
Ok(res) => res, Ok(res) => res,
Err(e) => { Err(e) => {
println!("Service error: {}", e); println!("Service error: {}", e);
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
} }
}; };
+239 -114
View File
@@ -1,22 +1,29 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#[allow(unused)] #![allow(
unused,
unused_imports,
unused_assignments,
unused_variables,
non_camel_case_types
)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage}; use crate::{BufferPool, StatusBody};
use std::str; use bytes::{Buf, BufMut, Bytes, BytesMut};
use bytes::{Bytes, BytesMut, Buf, BufMut}; use futures_util::StreamExt;
use tonic::{Request, Response, Status}; use http_body::Body;
use tokio_stream::Stream; use http_body_util::BodyExt;
use roto_runtime::{
ProtoAccessor, ProtoBuilder, RepeatedFieldIterator, Result, RotoError, RotoMessage, read_varint,
};
use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::str;
use std::sync::Arc; use std::sync::Arc;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::future::Future; use tokio_stream::Stream;
use tonic::body::BoxBody; use tonic::body::BoxBody;
use tonic::{Request, Response, Status};
use tower::Service; use tower::Service;
use futures_util::StreamExt;
use http_body_util::BodyExt;
use http_body::Body;
use crate::{BufferPool, StatusBody};
pub struct Hello<'a> { pub struct Hello<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
@@ -47,36 +54,57 @@ impl<'a> Hello<'a> {
let mut pets_end = None; let mut pets_end = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { name_offset = Some(offset); } if tag.field_number == 1 {
if tag.field_number == 2 { d_offset = Some(offset); } name_offset = Some(offset);
if tag.field_number == 3 { f_offset = Some(offset); } }
if tag.field_number == 4 { b_offset = Some(offset); } if tag.field_number == 2 {
if tag.field_number == 5 { n_offset = Some(offset); } d_offset = Some(offset);
if tag.field_number == 6 { l_offset = Some(offset); } }
if tag.field_number == 7 { c1_offset = Some(offset); } if tag.field_number == 3 {
if tag.field_number == 8 { c2_offset = Some(offset); } f_offset = Some(offset);
}
if tag.field_number == 4 {
b_offset = Some(offset);
}
if tag.field_number == 5 {
n_offset = Some(offset);
}
if tag.field_number == 6 {
l_offset = Some(offset);
}
if tag.field_number == 7 {
c1_offset = Some(offset);
}
if tag.field_number == 8 {
c2_offset = Some(offset);
}
if tag.field_number == 9 { if tag.field_number == 9 {
if pets_start.is_none() { pets_start = Some(offset); } if pets_start.is_none() {
pets_start = Some(offset);
}
pets_end = Some(offset); pets_end = Some(offset);
} }
} }
Ok(Self { Ok(Self {
accessor, accessor,
name_offset, name_offset,
d_offset, d_offset,
f_offset, f_offset,
b_offset, b_offset,
n_offset, n_offset,
l_offset, l_offset,
c1_offset, c1_offset,
c2_offset, c2_offset,
pets_start, pets_end, pets_start,
pets_end,
}) })
} }
pub fn name(&self) -> roto_runtime::Result<&'a str> { pub fn name(&self) -> roto_runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.name_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
@@ -85,70 +113,104 @@ pets_start, pets_end,
self.name().or(Ok("")) self.name().or(Ok(""))
} }
pub fn has_name(&self) -> bool { self.name_offset.is_some() } pub fn has_name(&self) -> bool {
self.name_offset.is_some()
}
pub fn d(&self) -> roto_runtime::Result<f64> { pub fn d(&self) -> roto_runtime::Result<f64> {
let offset = self.d_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.d_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?)) Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| {
roto_runtime::RotoError::WireFormatViolation
})?))
} }
pub fn d_or_default(&self) -> roto_runtime::Result<f64> { pub fn d_or_default(&self) -> roto_runtime::Result<f64> {
self.d().or(Ok(0.0)) self.d().or(Ok(0.0))
} }
pub fn has_d(&self) -> bool { self.d_offset.is_some() } pub fn has_d(&self) -> bool {
self.d_offset.is_some()
}
pub fn f(&self) -> roto_runtime::Result<f32> { pub fn f(&self) -> roto_runtime::Result<f32> {
let offset = self.f_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.f_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(f32::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?)) Ok(f32::from_le_bytes(bytes.try_into().map_err(|_| {
roto_runtime::RotoError::WireFormatViolation
})?))
} }
pub fn f_or_default(&self) -> roto_runtime::Result<f32> { pub fn f_or_default(&self) -> roto_runtime::Result<f32> {
self.f().or(Ok(0.0)) self.f().or(Ok(0.0))
} }
pub fn has_f(&self) -> bool { self.f_offset.is_some() } pub fn has_f(&self) -> bool {
self.f_offset.is_some()
}
pub fn b(&self) -> roto_runtime::Result<bool> { pub fn b(&self) -> roto_runtime::Result<bool> {
let offset = self.b_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.b_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes)
.map(|(v, _)| v != 0)
.map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn b_or_default(&self) -> roto_runtime::Result<bool> { pub fn b_or_default(&self) -> roto_runtime::Result<bool> {
self.b().or(Ok(false)) self.b().or(Ok(false))
} }
pub fn has_b(&self) -> bool { self.b_offset.is_some() } pub fn has_b(&self) -> bool {
self.b_offset.is_some()
}
pub fn n(&self) -> roto_runtime::Result<i32> { pub fn n(&self) -> roto_runtime::Result<i32> {
let offset = self.n_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.n_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn n_or_default(&self) -> roto_runtime::Result<i32> { pub fn n_or_default(&self) -> roto_runtime::Result<i32> {
self.n().or(Ok(0)) self.n().or(Ok(0))
} }
pub fn has_n(&self) -> bool { self.n_offset.is_some() } pub fn has_n(&self) -> bool {
self.n_offset.is_some()
}
pub fn l(&self) -> roto_runtime::Result<i32> { pub fn l(&self) -> roto_runtime::Result<i32> {
let offset = self.l_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.l_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes)
.map(|(v, _)| v as i32)
.map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn l_or_default(&self) -> roto_runtime::Result<i32> { pub fn l_or_default(&self) -> roto_runtime::Result<i32> {
self.l().or(Ok(0)) self.l().or(Ok(0))
} }
pub fn has_l(&self) -> bool { self.l_offset.is_some() } pub fn has_l(&self) -> bool {
self.l_offset.is_some()
}
pub fn c1(&self) -> roto_runtime::Result<&'a str> { pub fn c1(&self) -> roto_runtime::Result<&'a str> {
let offset = self.c1_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.c1_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
@@ -157,19 +219,27 @@ pets_start, pets_end,
self.c1().or(Ok("")) self.c1().or(Ok(""))
} }
pub fn has_c1(&self) -> bool { self.c1_offset.is_some() } pub fn has_c1(&self) -> bool {
self.c1_offset.is_some()
}
pub fn c2(&self) -> roto_runtime::Result<bool> { pub fn c2(&self) -> roto_runtime::Result<bool> {
let offset = self.c2_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.c2_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes)
.map(|(v, _)| v != 0)
.map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn c2_or_default(&self) -> roto_runtime::Result<bool> { pub fn c2_or_default(&self) -> roto_runtime::Result<bool> {
self.c2().or(Ok(false)) self.c2().or(Ok(false))
} }
pub fn has_c2(&self) -> bool { self.c2_offset.is_some() } pub fn has_c2(&self) -> bool {
self.c2_offset.is_some()
}
pub fn pets(&self) -> roto_runtime::RepeatedFieldIterator<'a> { pub fn pets(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.pets_start, self.pets_end) { match (self.pets_start, self.pets_end) {
@@ -178,12 +248,12 @@ pets_start, pets_end,
} }
} }
pub fn which_choice(&self) -> roto_runtime::Result<Option<hello::Choice<'a>> > { pub fn which_choice(&self) -> roto_runtime::Result<Option<hello::Choice<'a>>> {
if self.c1_offset.is_some() { if self.c1_offset.is_some() {
return Ok(Some(hello::Choice::c1 (self.c1()?))); return Ok(Some(hello::Choice::c1(self.c1()?)));
} }
if self.c2_offset.is_some() { if self.c2_offset.is_some() {
return Ok(Some(hello::Choice::c2 (self.c2()?))); return Ok(Some(hello::Choice::c2(self.c2()?)));
} }
Ok(None) Ok(None)
} }
@@ -191,7 +261,6 @@ pets_start, pets_end,
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct HelloBuilder<'b> { pub struct HelloBuilder<'b> {
@@ -326,32 +395,38 @@ impl roto_runtime::RotoMessage for OwnedHello {
} }
pub mod hello { pub mod hello {
pub struct Pet<'a> { pub struct Pet<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
name_offset: Option<usize>, name_offset: Option<usize>,
color_offset: Option<usize>, color_offset: Option<usize>,
} }
impl<'a> Pet<'a> { impl<'a> Pet<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> { pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?; let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut name_offset = None; let mut name_offset = None;
let mut color_offset = None; let mut color_offset = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { name_offset = Some(offset); } if tag.field_number == 1 {
if tag.field_number == 2 { color_offset = Some(offset); } name_offset = Some(offset);
}
if tag.field_number == 2 {
color_offset = Some(offset);
}
} }
Ok(Self { Ok(Self {
accessor, accessor,
name_offset, name_offset,
color_offset, color_offset,
}) })
} }
pub fn name(&self) -> roto_runtime::Result<&'a str> { pub fn name(&self) -> roto_runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.name_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
@@ -360,33 +435,40 @@ color_offset,
self.name().or(Ok("")) self.name().or(Ok(""))
} }
pub fn has_name(&self) -> bool { self.name_offset.is_some() } pub fn has_name(&self) -> bool {
self.name_offset.is_some()
}
pub fn color(&self) -> roto_runtime::Result<u64> { pub fn color(&self) -> roto_runtime::Result<u64> {
let offset = self.color_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.color_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| roto_runtime::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes)
.map(|(v, _)| v as u64)
.map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn color_or_default(&self) -> roto_runtime::Result<u64> { pub fn color_or_default(&self) -> roto_runtime::Result<u64> {
self.color().or(Ok(0)) self.color().or(Ok(0))
} }
pub fn has_color(&self) -> bool { self.color_offset.is_some() } pub fn has_color(&self) -> bool {
self.color_offset.is_some()
}
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
}
} pub struct PetBuilder<'b> {
pub struct PetBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>, builder: roto_runtime::ProtoBuilder<'b>,
name_written: bool, name_written: bool,
color_written: bool, color_written: bool,
} }
impl<'b> PetBuilder<'b> { impl<'b> PetBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> PetBuilder<'_> { pub fn builder(buf: &mut [u8]) -> PetBuilder<'_> {
PetBuilder { PetBuilder {
builder: roto_runtime::ProtoBuilder::new(buf), builder: roto_runtime::ProtoBuilder::new(buf),
@@ -425,20 +507,20 @@ impl<'b> PetBuilder<'b> {
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
pub struct OwnedPet { pub struct OwnedPet {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
impl roto_runtime::RotoOwned for OwnedPet { impl roto_runtime::RotoOwned for OwnedPet {
type Reader<'a> = Pet<'a>; type Reader<'a> = Pet<'a>;
fn reader(&self) -> Pet<'_> { fn reader(&self) -> Pet<'_> {
Pet::new(&self.data).expect("failed to create reader") Pet::new(&self.data).expect("failed to create reader")
} }
} }
impl roto_runtime::RotoMessage for OwnedPet { impl roto_runtime::RotoMessage for OwnedPet {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedPet { data: buf }) Ok(OwnedPet { data: buf })
} }
@@ -446,21 +528,21 @@ impl roto_runtime::RotoMessage for OwnedPet {
fn bytes(&self) -> bytes::Bytes { fn bytes(&self) -> bytes::Bytes {
self.data.clone() self.data.clone()
} }
} }
pub mod pet { pub mod pet {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)] #[repr(i32)]
pub enum Color { pub enum Color {
BLACK = 0, BLACK = 0,
WHITE = 1, WHITE = 1,
BLUE = 2, BLUE = 2,
RED = 3, RED = 3,
YELLOW = 4, YELLOW = 4,
GREEN = 5, GREEN = 5,
} }
impl Color { impl Color {
pub fn from_i32(value: i32) -> Self { pub fn from_i32(value: i32) -> Self {
match value { match value {
0 => Color::BLACK, 0 => Color::BLACK,
@@ -472,15 +554,13 @@ impl Color {
_ => Color::BLACK, _ => Color::BLACK,
} }
} }
} }
}
} pub enum Choice<'a> {
pub enum Choice<'a> {
c1(&'a str), c1(&'a str),
c2(bool), c2(bool),
} }
} }
pub struct HelloRequest<'a> { pub struct HelloRequest<'a> {
@@ -494,17 +574,21 @@ impl<'a> HelloRequest<'a> {
let mut request_offset = None; let mut request_offset = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { request_offset = Some(offset); } if tag.field_number == 1 {
request_offset = Some(offset);
}
} }
Ok(Self { Ok(Self {
accessor, accessor,
request_offset, request_offset,
}) })
} }
pub fn request(&self) -> roto_runtime::Result<&'a [u8]> { pub fn request(&self) -> roto_runtime::Result<&'a [u8]> {
let offset = self.request_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.request_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes) Ok(bytes)
} }
@@ -513,12 +597,13 @@ request_offset,
self.request().or(Ok(&[])) self.request().or(Ok(&[]))
} }
pub fn has_request(&self) -> bool { self.request_offset.is_some() } pub fn has_request(&self) -> bool {
self.request_offset.is_some()
}
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct HelloRequestBuilder<'b> { pub struct HelloRequestBuilder<'b> {
@@ -591,17 +676,21 @@ impl<'a> HelloReply<'a> {
let mut response_offset = None; let mut response_offset = None;
for item in accessor.fields() { for item in accessor.fields() {
let (offset, tag, _) = item?; let (offset, tag, _) = item?;
if tag.field_number == 1 { response_offset = Some(offset); } if tag.field_number == 1 {
response_offset = Some(offset);
}
} }
Ok(Self { Ok(Self {
accessor, accessor,
response_offset, response_offset,
}) })
} }
pub fn response(&self) -> roto_runtime::Result<&'a [u8]> { pub fn response(&self) -> roto_runtime::Result<&'a [u8]> {
let offset = self.response_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self
.response_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes) Ok(bytes)
} }
@@ -610,12 +699,13 @@ response_offset,
self.response().or(Ok(&[])) self.response().or(Ok(&[]))
} }
pub fn has_response(&self) -> bool { self.response_offset.is_some() } pub fn has_response(&self) -> bool {
self.response_offset.is_some()
}
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct HelloReplyBuilder<'b> { pub struct HelloReplyBuilder<'b> {
@@ -679,7 +769,10 @@ impl roto_runtime::RotoMessage for OwnedHelloReply {
#[tonic::async_trait] #[tonic::async_trait]
pub trait Greeter: Send + Sync + 'static { pub trait Greeter: Send + Sync + 'static {
async fn say_hello(&self, request: Request<OwnedHelloRequest>) -> std::result::Result<Response<OwnedHelloReply>, Status>; async fn say_hello(
&self,
request: Request<OwnedHelloRequest>,
) -> std::result::Result<Response<OwnedHelloReply>, Status>;
} }
#[derive(Clone)] #[derive(Clone)]
@@ -701,7 +794,8 @@ impl tonic::server::NamedService for GreeterServer {
impl Service<http::Request<BoxBody>> for GreeterServer { impl Service<http::Request<BoxBody>> for GreeterServer {
type Response = http::Response<BoxBody>; type Response = http::Response<BoxBody>;
type Error = std::convert::Infallible; type Error = std::convert::Infallible;
type Future = Pin<Box<dyn Future<Output = std::result::Result<Self::Response, Self::Error>> + Send>>; type Future =
Pin<Box<dyn Future<Output = std::result::Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
@@ -726,8 +820,14 @@ impl Service<http::Request<BoxBody>> for GreeterServer {
let bytes_vec = buf.split_to(total_len).freeze(); let bytes_vec = buf.split_to(total_len).freeze();
pool.put(buf); pool.put(buf);
if bytes_vec.len() < 5 { if bytes_vec.len() < 5 {
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
} }
let payload = bytes_vec.slice(5..); let payload = bytes_vec.slice(5..);
@@ -737,16 +837,28 @@ impl Service<http::Request<BoxBody>> for GreeterServer {
let request_msg = match OwnedHelloRequest::decode(payload) { let request_msg = match OwnedHelloRequest::decode(payload) {
Ok(msg) => msg, Ok(msg) => msg,
Err(e) => { Err(e) => {
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
} }
}; };
let response = match inner.say_hello(Request::new(request_msg)).await { let response = match inner.say_hello(Request::new(request_msg)).await {
Ok(res) => res, Ok(res) => res,
Err(e) => { Err(e) => {
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
} }
}; };
@@ -762,13 +874,26 @@ impl Service<http::Request<BoxBody>> for GreeterServer {
pool.put(res_buf); pool.put(res_buf);
let res_body = BoxBody::new(StatusBody::new(Some(frame), 0)); let res_body = BoxBody::new(StatusBody::new(Some(frame), 0));
routed = true; routed = true;
return Ok(http::Response::builder().status(200).header("content-type", "application/grpc").body(res_body).unwrap()); return Ok(http::Response::builder()
.status(200)
.header("content-type", "application/grpc")
.body(res_body)
.unwrap());
} }
if !routed { if !routed {
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); Some(Bytes::from_static(&[0, 0, 0, 0, 0])),
0,
));
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
} }
Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody::new(None, 0))).unwrap()) Ok(http::Response::builder()
.status(200)
.body(BoxBody::new(StatusBody::new(None, 0)))
.unwrap())
}) })
} }
} }
+162 -5
View File
@@ -1,6 +1,6 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#![allow(unused)] #[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage}; use roto_runtime::{ProtoAccessor, ProtoBuilder, RevBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use core::str; use core::str;
use bytes::{Bytes, BytesMut, Buf, BufMut}; use bytes::{Bytes, BytesMut, Buf, BufMut};
@@ -80,6 +80,45 @@ impl<'b> UnaryRequestBuilder<'b> {
} }
} }
pub struct UnaryRequestRevBuilder<'b> {
builder: roto_runtime::RevBuilder<'b>,
message_written: bool,
}
impl<'b> UnaryRequestRevBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> UnaryRequestRevBuilder<'_> {
UnaryRequestRevBuilder {
builder: roto_runtime::RevBuilder::new(buf),
message_written: false,
}
}
pub fn message(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.message_written = true;
Ok(self)
}
pub fn with(mut self, msg: &UnaryRequest<'_>) -> roto_runtime::Result<Self> {
let fields: Vec<_> = msg.accessor.raw_fields().collect();
for item in fields.into_iter().rev() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.message_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub struct OwnedUnaryRequest { pub struct OwnedUnaryRequest {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
@@ -177,6 +216,45 @@ impl<'b> UnaryResponseBuilder<'b> {
} }
} }
pub struct UnaryResponseRevBuilder<'b> {
builder: roto_runtime::RevBuilder<'b>,
reply_written: bool,
}
impl<'b> UnaryResponseRevBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> UnaryResponseRevBuilder<'_> {
UnaryResponseRevBuilder {
builder: roto_runtime::RevBuilder::new(buf),
reply_written: false,
}
}
pub fn reply(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.reply_written = true;
Ok(self)
}
pub fn with(mut self, msg: &UnaryResponse<'_>) -> roto_runtime::Result<Self> {
let fields: Vec<_> = msg.accessor.raw_fields().collect();
for item in fields.into_iter().rev() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.reply_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub struct OwnedUnaryResponse { pub struct OwnedUnaryResponse {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
@@ -274,6 +352,45 @@ impl<'b> StreamingRequestBuilder<'b> {
} }
} }
pub struct StreamingRequestRevBuilder<'b> {
builder: roto_runtime::RevBuilder<'b>,
query_written: bool,
}
impl<'b> StreamingRequestRevBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> StreamingRequestRevBuilder<'_> {
StreamingRequestRevBuilder {
builder: roto_runtime::RevBuilder::new(buf),
query_written: false,
}
}
pub fn query(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.query_written = true;
Ok(self)
}
pub fn with(mut self, msg: &StreamingRequest<'_>) -> roto_runtime::Result<Self> {
let fields: Vec<_> = msg.accessor.raw_fields().collect();
for item in fields.into_iter().rev() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.query_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub struct OwnedStreamingRequest { pub struct OwnedStreamingRequest {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
@@ -371,6 +488,45 @@ impl<'b> StreamingResponseBuilder<'b> {
} }
} }
pub struct StreamingResponseRevBuilder<'b> {
builder: roto_runtime::RevBuilder<'b>,
item_written: bool,
}
impl<'b> StreamingResponseRevBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> StreamingResponseRevBuilder<'_> {
StreamingResponseRevBuilder {
builder: roto_runtime::RevBuilder::new(buf),
item_written: false,
}
}
pub fn item(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.item_written = true;
Ok(self)
}
pub fn with(mut self, msg: &StreamingResponse<'_>) -> roto_runtime::Result<Self> {
let fields: Vec<_> = msg.accessor.raw_fields().collect();
for item in fields.into_iter().rev() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.item_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub struct OwnedStreamingResponse { pub struct OwnedStreamingResponse {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
@@ -394,6 +550,7 @@ impl roto_runtime::RotoMessage for OwnedStreamingResponse {
#[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]
use tonic::{Request, Response, Status}; use tonic::{Request, Response, Status};
use tokio_stream::Stream; use tokio_stream::Stream;
use std::pin::Pin; use std::pin::Pin;
@@ -462,12 +619,12 @@ impl Service<http::Request<BoxBody>> for InteropServiceServer {
} }
let payload = bytes_vec.slice(5..); let payload = bytes_vec.slice(5..);
#[allow(unused_assignments)]
let mut routed = false; let mut routed = false;
if path == "/interop.InteropService/UnaryCall" { if path == "/interop.InteropService/UnaryCall" {
let request_msg = match OwnedUnaryRequest::decode(payload) { let request_msg = match OwnedUnaryRequest::decode(payload) {
Ok(msg) => msg, Ok(msg) => msg,
Err(e) => { Err(_e) => {
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); return Ok(http::Response::builder().status(200).body(res_body).unwrap());
} }
@@ -475,7 +632,7 @@ impl Service<http::Request<BoxBody>> for InteropServiceServer {
let response = match inner.unary_call(Request::new(request_msg)).await { let response = match inner.unary_call(Request::new(request_msg)).await {
Ok(res) => res, Ok(res) => res,
Err(e) => { Err(_e) => {
let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));
return Ok(http::Response::builder().status(200).body(res_body).unwrap()); return Ok(http::Response::builder().status(200).body(res_body).unwrap());
} }
+385 -3
View File
@@ -6,8 +6,8 @@ extern crate alloc;
#[cfg(feature = "std")] #[cfg(feature = "std")]
extern crate std; extern crate std;
use core::fmt;
use bytes::BufMut; use bytes::BufMut;
use core::fmt;
pub struct MapFieldIterator<'a> { pub struct MapFieldIterator<'a> {
inner: RepeatedFieldIterator<'a>, inner: RepeatedFieldIterator<'a>,
@@ -65,7 +65,9 @@ impl std::error::Error for RotoError {}
pub type Result<T> = core::result::Result<T, RotoError>; pub type Result<T> = core::result::Result<T, RotoError>;
pub trait RotoOwned { pub trait RotoOwned {
type Reader<'a> where Self: 'a; type Reader<'a>
where
Self: 'a;
fn reader(&self) -> Self::Reader<'_>; fn reader(&self) -> Self::Reader<'_>;
} }
@@ -442,7 +444,7 @@ impl<'a> Iterator for RawFieldIterator<'a> {
mod tests { mod tests {
use super::*; use super::*;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use alloc::{vec, vec::{Vec}}; use alloc::{vec, vec::Vec};
#[test] #[test]
fn test_varint_read_write() { fn test_varint_read_write() {
@@ -745,6 +747,199 @@ mod tests {
} }
assert_eq!(found_count, essential_fields.len()); assert_eq!(found_count, essential_fields.len());
} }
#[test]
fn test_revbuilder_string_wire_format() {
let mut buf = [0u8; 256];
let mut builder = RevBuilder::new(&mut buf);
builder.write_string(1, "hello").unwrap();
let data = builder.finish().unwrap();
assert_eq!(data, &[0x0A, 0x05, b'h', b'e', b'l', b'l', b'o']);
let acc = ProtoAccessor::new(data).unwrap();
let (val, wt) = acc.get_value(1).unwrap();
assert_eq!(wt, WireType::LengthDelimited);
assert_eq!(val, b"hello");
}
#[test]
fn test_revbuilder_multiple_fields_reverse_order() {
let mut buf = [0u8; 256];
let mut builder = RevBuilder::new(&mut buf);
builder.write_varint(3, 300).unwrap();
builder.write_string(2, "hi").unwrap();
builder.write_varint(1, 42).unwrap();
let data = builder.finish().unwrap();
let acc = ProtoAccessor::new(data).unwrap();
let (val1, _) = acc.get_value(1).unwrap();
let (v1, _) = read_varint(val1).unwrap();
assert_eq!(v1, 42);
let (val2, _) = acc.get_value(2).unwrap();
assert_eq!(val2, b"hi");
let (val3, _) = acc.get_value(3).unwrap();
let (v3, _) = read_varint(val3).unwrap();
assert_eq!(v3, 300);
}
#[test]
fn test_revbuilder_nested_message() {
let mut buf = [0u8; 256];
let mut builder = RevBuilder::new(&mut buf);
// Mark before writing inner fields
let inner_start = builder.mark();
// Write inner field
builder.write_varint(1, 100).unwrap();
// Write length prefix and tag for outer field
builder.write_length_since(inner_start).unwrap();
builder.put_tag(1, WireType::LengthDelimited).unwrap();
let data = builder.finish().unwrap();
let acc = ProtoAccessor::new(data).unwrap();
let (nested_bytes, wt) = acc.get_value(1).unwrap();
assert_eq!(wt, WireType::LengthDelimited);
let nested_acc = ProtoAccessor::new(nested_bytes).unwrap();
let (inner_val, _) = nested_acc.get_value(1).unwrap();
let (inner_v, _) = read_varint(inner_val).unwrap();
assert_eq!(inner_v, 100);
}
#[test]
fn test_revbuilder_readable_by_accessor() {
let mut buf = [0u8; 256];
let mut builder = RevBuilder::new(&mut buf);
builder.write_fixed64(6, 0xDEADBEEFCAFEBABE).unwrap();
builder.write_fixed32(5, 0xDEADBEEFu32).unwrap();
builder.write_bytes(4, &[1, 2, 3, 255, 0]).unwrap();
builder.write_string(3, "protobuf").unwrap();
builder.write_int32(2, -42).unwrap();
builder.write_varint(1, 0x1234ABCD).unwrap();
let data = builder.finish().unwrap();
let acc = ProtoAccessor::new(data).unwrap();
let (v1, _) = acc.get_value(1).unwrap();
let (val1, _) = read_varint(v1).unwrap();
assert_eq!(val1, 0x1234ABCD);
let (v2, _) = acc.get_value(2).unwrap();
let (val2, _) = read_varint(v2).unwrap();
assert_eq!(val2, -42i32 as u64);
assert_eq!(acc.get_value(3).unwrap().0, b"protobuf");
assert_eq!(acc.get_value(4).unwrap().0, &[1, 2, 3, 255, 0]);
assert_eq!(acc.get_value(5).unwrap().0, &(0xDEADBEEFu32).to_le_bytes());
assert_eq!(
acc.get_value(6).unwrap().0,
&(0xDEADBEEFCAFEBABEu64).to_le_bytes()
);
}
#[test]
fn test_revbuilder_buffer_overflow() {
let mut buf = [0u8; 4];
let mut builder = RevBuilder::new(&mut buf);
let result = builder.write_string(1, "hello");
assert_eq!(result, Err(RotoError::BufferOverflow));
let mut buf2 = [0u8; 1];
let mut builder2 = RevBuilder::new(&mut buf2);
let result2 = builder2.write_varint(1000, 1);
assert_eq!(result2, Err(RotoError::BufferOverflow));
}
#[test]
fn test_revbuilder_matches_proto_builder() {
let mut fwd_buf = [0u8; 256];
let mut fwd_builder = ProtoBuilder::new(&mut fwd_buf);
fwd_builder.write_string(1, "hello").unwrap();
fwd_builder.write_int32(2, 42).unwrap();
fwd_builder.write_bytes(3, &[1, 2, 3]).unwrap();
let fwd_data = fwd_builder.finish().unwrap();
let mut rev_buf = [0u8; 256];
let mut rev_builder = RevBuilder::new(&mut rev_buf);
rev_builder.write_bytes(3, &[1, 2, 3]).unwrap();
rev_builder.write_int32(2, 42).unwrap();
rev_builder.write_string(1, "hello").unwrap();
let rev_data = rev_builder.finish().unwrap();
let fwd_acc = ProtoAccessor::new(fwd_data).unwrap();
let rev_acc = ProtoAccessor::new(rev_data).unwrap();
let (f1, _) = fwd_acc.get_value(1).unwrap();
let (r1, _) = rev_acc.get_value(1).unwrap();
assert_eq!(f1, r1);
assert_eq!(f1, b"hello");
let (f2, _) = fwd_acc.get_value(2).unwrap();
let (r2, _) = rev_acc.get_value(2).unwrap();
assert_eq!(f2, r2);
assert_eq!(f2, &[42]);
let (f3, _) = fwd_acc.get_value(3).unwrap();
let (r3, _) = rev_acc.get_value(3).unwrap();
assert_eq!(f3, r3);
assert_eq!(f3, &[1, 2, 3]);
}
#[test]
fn test_revbuilder_empty_finish() {
let mut buf = [1u8; 64];
let builder = RevBuilder::new(&mut buf);
let data = builder.finish().unwrap();
assert!(data.is_empty());
}
#[test]
fn test_revbuilder_map_entry() {
let mut buf = [0u8; 256];
let mut builder = RevBuilder::new(&mut buf);
let mut key_buf = [0u8; 16];
let key_tag_len = Tag::encode(1, WireType::Varint, &mut key_buf).unwrap();
key_buf[key_tag_len] = 7;
let key_bytes = &key_buf[..key_tag_len + 1];
let mut val_buf = [0u8; 16];
let val_tag_len = Tag::encode(2, WireType::LengthDelimited, &mut val_buf).unwrap();
val_buf[val_tag_len] = 1;
val_buf[val_tag_len + 1] = b'x';
let val_bytes = &val_buf[..val_tag_len + 2];
builder.write_map_entry(10, key_bytes, val_bytes).unwrap();
let data = builder.finish().unwrap();
let acc = ProtoAccessor::new(data).unwrap();
let (entry_bytes, _) = acc.get_value(10).unwrap();
let entry_acc = ProtoAccessor::new(entry_bytes).unwrap();
let (key_v, _) = entry_acc.get_value(1).unwrap();
let (key_val, _) = read_varint(key_v).unwrap();
assert_eq!(key_val, 7);
let (val_v, _) = entry_acc.get_value(2).unwrap();
assert_eq!(val_v, b"x");
}
#[test]
fn test_revbuilder_written_since() {
let mut buf = [0u8; 256];
let mut builder = RevBuilder::new(&mut buf);
let m1 = builder.mark();
builder.write_string(1, "test").unwrap();
assert!(builder.written_since(m1) > 0);
let m2 = builder.mark();
builder.write_varint(2, 999).unwrap();
assert!(builder.written_since(m2) > 0);
let total = builder.written_since(m1);
let just_field2 = builder.written_since(m2);
assert!(total > just_field2);
}
#[test]
fn test_revbuilder_write_raw() {
let mut src_buf = [0u8; 128];
let mut src_builder = ProtoBuilder::new(&mut src_buf);
src_builder.write_string(1, "original").unwrap();
src_builder.write_int32(2, 99).unwrap();
let src_data = src_builder.finish().unwrap();
let src_acc = ProtoAccessor::new(src_data).unwrap();
let mut dst_buf = [0u8; 128];
let mut dst_builder = RevBuilder::new(&mut dst_buf);
let fields: Vec<_> = src_acc.raw_fields().collect();
for item in fields.into_iter().rev() {
let (_, raw_bytes) = item.unwrap();
dst_builder.write_raw(raw_bytes).unwrap();
}
let dst_data = dst_builder.finish().unwrap();
let dst_acc = ProtoAccessor::new(dst_data).unwrap();
let (d1, _) = dst_acc.get_value(1).unwrap();
assert_eq!(d1, b"original");
let (d2, _) = dst_acc.get_value(2).unwrap();
assert_eq!(d2, &[99]);
}
} }
pub struct ProtoBuilder<'a> { pub struct ProtoBuilder<'a> {
@@ -922,3 +1117,190 @@ impl<'a, B: BufMut> BufMutBuilder<'a, B> {
Ok(()) Ok(())
} }
} }
/// A reverse-direction protobuf builder that writes fields BACKWARDS through
/// a buffer, from the end toward the beginning. This enables zero-copy
/// single-pass encoding for length-delimited payloads: write the payload
/// first, compute its size, then write the length varint and tag going backwards.
///
/// After encoding, the valid data is in `buf[pos..buf.len()]` — no memmove is
/// needed because the first byte we wrote (now at `pos`) IS the first byte of
/// the wire-format message.
///
/// # Invariant
///
/// `pos` always points to the **start** of valid data. Data lives in
/// `buf[pos..buf.len()]`. `pos` starts at `buf.len()` (empty) and
/// decreases as we write.
pub struct RevBuilder<'a> {
buf: &'a mut [u8],
pos: usize,
}
impl<'a> RevBuilder<'a> {
/// Create a new `RevBuilder` that writes backwards into `buf`.
///
/// The buffer is initially empty; valid data grows from the end
/// toward the beginning.
pub fn new(buf: &'a mut [u8]) -> Self {
let pos = buf.len();
Self { buf, pos }
}
// ------------------------------------------------------------------
// Low-level primitives (write at current pos, moving pos left)
// ------------------------------------------------------------------
/// Encode `value` as a varint and place it at the current position,
/// moving `pos` left by the encoded length.
pub fn put_varint(&mut self, value: u64) -> Result<()> {
let mut temp = [0u8; 10];
let len = write_varint(value, &mut temp)?;
if self.pos < len {
return Err(RotoError::BufferOverflow);
}
self.pos -= len;
self.buf[self.pos..self.pos + len].copy_from_slice(&temp[..len]);
Ok(())
}
/// Copy `bytes` into the buffer at the current position, moving `pos`
/// left by `bytes.len()`.
pub fn put_slice(&mut self, bytes: &[u8]) -> Result<()> {
let len = bytes.len();
if self.pos < len {
return Err(RotoError::BufferOverflow);
}
self.pos -= len;
self.buf[self.pos..self.pos + len].copy_from_slice(bytes);
Ok(())
}
/// Encode a tag varint at the current position.
pub fn put_tag(&mut self, field_number: u32, wire_type: WireType) -> Result<()> {
let mut temp = [0u8; 10];
let len = Tag::encode(field_number, wire_type, &mut temp)?;
if self.pos < len {
return Err(RotoError::BufferOverflow);
}
self.pos -= len;
self.buf[self.pos..self.pos + len].copy_from_slice(&temp[..len]);
Ok(())
}
// ------------------------------------------------------------------
// High-level field writers
// ------------------------------------------------------------------
/// Encode a length-delimited string field.
///
/// Write order: payload → length varint → tag (all going backwards),
/// which produces the correct wire order: `[tag][len][payload]`.
pub fn write_string(&mut self, field_number: u32, value: &str) -> Result<()> {
let bytes = value.as_bytes();
// payload first (moves pos left)
self.put_slice(bytes)?;
// length
self.put_varint(bytes.len() as u64)?;
// tag
self.put_tag(field_number, WireType::LengthDelimited)?;
Ok(())
}
/// Encode a length-delimited bytes field.
pub fn write_bytes(&mut self, field_number: u32, value: &[u8]) -> Result<()> {
self.put_slice(value)?;
self.put_varint(value.len() as u64)?;
self.put_tag(field_number, WireType::LengthDelimited)?;
Ok(())
}
/// Encode a varint field (tag + varint value).
pub fn write_varint(&mut self, field_number: u32, value: u64) -> Result<()> {
self.put_varint(value)?;
self.put_tag(field_number, WireType::Varint)?;
Ok(())
}
/// Encode an int32 field (same wire encoding as varint).
pub fn write_int32(&mut self, field_number: u32, value: i32) -> Result<()> {
self.write_varint(field_number, value as u64)
}
/// Encode a fixed32 field (tag + 4-byte LE value).
pub fn write_fixed32(&mut self, field_number: u32, value: u32) -> Result<()> {
self.put_slice(&value.to_le_bytes())?;
self.put_tag(field_number, WireType::Fixed32)?;
Ok(())
}
/// Encode a fixed64 field (tag + 8-byte LE value).
pub fn write_fixed64(&mut self, field_number: u32, value: u64) -> Result<()> {
self.put_slice(&value.to_le_bytes())?;
self.put_tag(field_number, WireType::Fixed64)?;
Ok(())
}
/// Write a pre-encoded field (tag + value) verbatim into the buffer.
///
/// Useful for the `with()` pattern: copy raw bytes from an existing
/// message without re-encoding.
pub fn write_raw(&mut self, raw_bytes: &[u8]) -> Result<()> {
self.put_slice(raw_bytes)?;
Ok(())
}
/// Encode a map entry as a length-delimited field containing
/// `key_encoded` followed by `value_encoded`.
pub fn write_map_entry(
&mut self,
field_number: u32,
key_encoded: &[u8],
value_encoded: &[u8],
) -> Result<()> {
// We want final bytes: [key...][value...] (in wire order)
// Written backwards: first write value at right, then key at left.
// So the last thing written (key) ends up at the start (left).
self.put_slice(value_encoded)?;
self.put_slice(key_encoded)?;
let entry_len = key_encoded.len() + value_encoded.len();
self.put_varint(entry_len as u64)?;
self.put_tag(field_number, WireType::LengthDelimited)?;
Ok(())
}
// ------------------------------------------------------------------
// Nested-message helpers
// ------------------------------------------------------------------
/// Return the current position (start of valid data).
///
/// Call this *before* writing nested fields, then pass the returned
/// value to [`write_length_since`](Self::write_length_since) to
/// encode the length prefix.
pub fn mark(&self) -> usize {
self.pos
}
/// Return the number of bytes written since `mark`.
pub fn written_since(&self, mark: usize) -> usize {
mark - self.pos
}
/// Write the length-prefix varint for the bytes that were written
/// between `mark` and now. Call this *after* encoding the nested
/// message fields.
pub fn write_length_since(&mut self, mark: usize) -> Result<()> {
let len = mark - self.pos;
self.put_varint(len as u64)?;
Ok(())
}
/// Finalize and return the encoded slice.
///
/// The valid data is `buf[pos..buf.len()]` — the bytes we wrote,
/// in correct wire-format order.
pub fn finish(self) -> Result<&'a mut [u8]> {
Ok(&mut self.buf[self.pos..])
}
}