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::str;
const DATA_IMPORTS: &str = "#[allow(unused)]\n\
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};\n\
const DATA_IMPORTS: &str = "#[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]\n\
use roto_runtime::{ProtoAccessor, ProtoBuilder, RevBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};\n\
use core::str;\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 tokio_stream::Stream;\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");
}
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 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);
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((
field_name.to_string(),
tag,
@@ -223,6 +284,7 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
f_label,
oneof_index,
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(" 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 {
output.push_str(&format!(" {}_start: 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(" pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {\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 {
output.push_str(&format!(" let mut {}_start = 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(" 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 {
output.push_str(&format!(" if tag.field_number == {} {{\n", tag));
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(" 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 {
output.push_str(&format!("{}_start, {}_end,\n", name, name));
} else {
@@ -288,8 +350,10 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
}
output.push_str(" })\n }\n\n");
for (field_name, tag, f_type, f_label, _oneof_index, is_map) in &fields_info {
let (rust_type, logic, default_val) = map_type_to_rust_accessor(*f_type, *f_label, *is_map);
// Collect typed iterator info for repeated message fields (generated after the impl block)
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" {
format!("r#{}", field_name)
} else {
@@ -297,6 +361,8 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
};
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!(
" pub fn {}(&self) -> {} {{\n",
safe_name, rust_type
@@ -319,7 +385,71 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
));
}
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 {
// 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!(
" pub fn {}(&self) -> roto_runtime::Result<{}> {{\n",
safe_name, rust_type
@@ -362,7 +492,9 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
snake_oneof_name, return_type
);
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) {
let safe_field_name = if field_name == "type" {
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");
}
// 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)
output.push_str(" pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {\n");
output.push_str(" self.accessor.raw_fields()\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.
// Tuple: (field_name, safe_name, tag, rust_type, write_method)
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"));
// 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(" pub data: bytes::Bytes,\n");
output.push_str("}\n\n");
@@ -516,6 +736,8 @@ fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
write_message(
&DescriptorProto::new(m_data).expect("Failed to parse nested DescriptorProto"),
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 pascal_oneof_name = to_pascal_case(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) {
let (rust_type, _, _) = map_type_to_rust_accessor(*f_type, *f_label, *_is_map);
let safe_field_name = if field_name == "type" {
@@ -591,7 +815,6 @@ where
let mut output = String::new();
output.push_str("// @generated by protoc-gen-roto — do not edit\n");
output.push_str("#[allow(unused_imports)]\n");
output.push_str(imports);
for dep_res in file_proto.dependency() {
@@ -676,6 +899,21 @@ pub fn generate_protobuf_code(
generate_mod_files,
DATA_IMPORTS,
|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
for enum_res in file_proto.enum_type() {
let (enum_data, _) = enum_res.expect("Failed to iterate enum");
@@ -692,6 +930,8 @@ pub fn generate_protobuf_code(
write_message(
&DescriptorProto::new(msg_data).expect("Failed to parse DescriptorProto"),
output,
&type_registry,
0,
);
}
},
@@ -773,6 +1013,9 @@ fn strip_boilerplate(content: &str) -> String {
"#[allow(unused_imports)]\n",
"#![allow(unused_imports)]\n\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 {
+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 {
s.split('_')
+365 -252
View File
@@ -1,21 +1,29 @@
// @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 std::str;
use bytes::{Bytes, BytesMut, Buf, BufMut};
use tonic::{Request, Response, Status};
use tokio_stream::Stream;
use crate::runtime::{
ProtoAccessor, ProtoBuilder, RepeatedFieldIterator, Result, RotoError, read_varint,
};
use bytes::{Buf, BufMut, Bytes, BytesMut};
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::str;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::future::Future;
use tokio_stream::Stream;
use tonic::body::BoxBody;
use tonic::{Request, Response, Status};
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;
@@ -36,59 +44,87 @@ impl<'a> Version<'a> {
let mut suffix_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { major_offset = Some(offset); }
if tag.field_number == 2 { minor_offset = Some(offset); }
if tag.field_number == 3 { patch_offset = Some(offset); }
if tag.field_number == 4 { suffix_offset = Some(offset); }
if tag.field_number == 1 {
major_offset = Some(offset);
}
if tag.field_number == 2 {
minor_offset = Some(offset);
}
if tag.field_number == 3 {
patch_offset = Some(offset);
}
if tag.field_number == 4 {
suffix_offset = Some(offset);
}
}
Ok(Self {
accessor,
major_offset,
minor_offset,
patch_offset,
suffix_offset,
major_offset,
minor_offset,
patch_offset,
suffix_offset,
})
}
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
@@ -97,12 +133,13 @@ suffix_offset,
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> {
self.accessor.raw_fields()
}
}
pub struct VersionBuilder<'b> {
@@ -217,28 +254,41 @@ impl<'a> CodeGeneratorRequest<'a> {
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 {
if file_to_generate_start.is_none() { file_to_generate_start = Some(offset); }
if file_to_generate_start.is_none() {
file_to_generate_start = Some(offset);
}
file_to_generate_end = Some(offset);
}
if tag.field_number == 2 { parameter_offset = Some(offset); }
if tag.field_number == 2 {
parameter_offset = Some(offset);
}
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);
}
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);
}
if tag.field_number == 3 { compiler_version_offset = Some(offset); }
if tag.field_number == 3 {
compiler_version_offset = Some(offset);
}
}
Ok(Self {
accessor,
file_to_generate_start, file_to_generate_end,
parameter_offset,
proto_file_start, proto_file_end,
source_file_descriptors_start, source_file_descriptors_end,
compiler_version_offset,
file_to_generate_start,
file_to_generate_end,
parameter_offset,
proto_file_start,
proto_file_end,
source_file_descriptors_start,
source_file_descriptors_end,
compiler_version_offset,
})
}
@@ -250,7 +300,9 @@ compiler_version_offset,
}
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)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
@@ -259,7 +311,9 @@ compiler_version_offset,
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> {
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> {
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),
_ => self.accessor.iter_repeated(17),
}
}
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)?;
Ok(bytes)
}
@@ -285,12 +344,13 @@ compiler_version_offset,
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> {
self.accessor.raw_fields()
}
}
pub struct CodeGeneratorRequestBuilder<'b> {
@@ -409,28 +469,41 @@ impl<'a> CodeGeneratorResponse<'a> {
let mut file_end = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { error_offset = Some(offset); }
if tag.field_number == 2 { supported_features_offset = Some(offset); }
if tag.field_number == 3 { minimum_edition_offset = Some(offset); }
if tag.field_number == 4 { maximum_edition_offset = Some(offset); }
if tag.field_number == 1 {
error_offset = Some(offset);
}
if tag.field_number == 2 {
supported_features_offset = Some(offset);
}
if tag.field_number == 3 {
minimum_edition_offset = Some(offset);
}
if tag.field_number == 4 {
maximum_edition_offset = Some(offset);
}
if tag.field_number == 15 {
if file_start.is_none() { file_start = Some(offset); }
if file_start.is_none() {
file_start = Some(offset);
}
file_end = Some(offset);
}
}
Ok(Self {
accessor,
error_offset,
supported_features_offset,
minimum_edition_offset,
maximum_edition_offset,
file_start, file_end,
error_offset,
supported_features_offset,
minimum_edition_offset,
maximum_edition_offset,
file_start,
file_end,
})
}
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)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
@@ -439,43 +512,63 @@ file_start, file_end,
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
match (self.file_start, self.file_end) {
@@ -487,7 +580,6 @@ file_start, file_end,
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct CodeGeneratorResponseBuilder<'b> {
@@ -586,196 +678,217 @@ impl crate::runtime::RotoMessage for OwnedCodeGeneratorResponse {
}
pub mod code_generator_response {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum Feature {
FEATURENONE = 0,
FEATUREPROTO3OPTIONAL = 1,
FEATURESUPPORTSEDITIONS = 2,
}
impl Feature {
pub fn from_i32(value: i32) -> Self {
match value {
0 => Feature::FEATURENONE,
1 => Feature::FEATUREPROTO3OPTIONAL,
2 => Feature::FEATURESUPPORTSEDITIONS,
_ => Feature::FEATURENONE,
}
}
}
pub struct File<'a> {
accessor: crate::runtime::ProtoAccessor<'a>,
name_offset: Option<usize>,
insertion_point_offset: Option<usize>,
content_offset: Option<usize>,
generated_code_info_offset: Option<usize>,
}
impl<'a> File<'a> {
pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut name_offset = None;
let mut insertion_point_offset = None;
let mut content_offset = None;
let mut generated_code_info_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { name_offset = Some(offset); }
if tag.field_number == 2 { insertion_point_offset = Some(offset); }
if tag.field_number == 15 { content_offset = Some(offset); }
if tag.field_number == 16 { generated_code_info_offset = Some(offset); }
}
Ok(Self {
accessor,
name_offset,
insertion_point_offset,
content_offset,
generated_code_info_offset,
})
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum Feature {
FEATURENONE = 0,
FEATUREPROTO3OPTIONAL = 1,
FEATURESUPPORTSEDITIONS = 2,
}
pub fn name(&self) -> crate::runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
pub fn name_or_default(&self) -> crate::runtime::Result<&'a str> {
self.name().or(Ok(""))
}
pub fn has_name(&self) -> bool { self.name_offset.is_some() }
pub fn insertion_point(&self) -> crate::runtime::Result<&'a str> {
let offset = self.insertion_point_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
pub fn insertion_point_or_default(&self) -> crate::runtime::Result<&'a str> {
self.insertion_point().or(Ok(""))
}
pub fn has_insertion_point(&self) -> bool { self.insertion_point_offset.is_some() }
pub fn content(&self) -> crate::runtime::Result<&'a str> {
let offset = self.content_offset.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
pub fn content_or_default(&self) -> crate::runtime::Result<&'a str> {
self.content().or(Ok(""))
}
pub fn has_content(&self) -> bool { self.content_offset.is_some() }
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 (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes)
}
pub fn generated_code_info_or_default(&self) -> crate::runtime::Result<&'a [u8]> {
self.generated_code_info().or(Ok(&[]))
}
pub fn has_generated_code_info(&self) -> bool { self.generated_code_info_offset.is_some() }
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct FileBuilder<'b> {
builder: crate::runtime::ProtoBuilder<'b>,
name_written: bool,
insertion_point_written: bool,
content_written: bool,
generated_code_info_written: bool,
}
impl<'b> FileBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
FileBuilder {
builder: crate::runtime::ProtoBuilder::new(buf),
name_written: false,
insertion_point_written: false,
content_written: false,
generated_code_info_written: false,
}
}
pub fn name(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
}
pub fn insertion_point(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(2, value)?;
self.insertion_point_written = true;
Ok(self)
}
pub fn content(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(15, value)?;
self.content_written = true;
Ok(self)
}
pub fn generated_code_info(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(16, value)?;
self.generated_code_info_written = true;
Ok(self)
}
pub fn with(mut self, msg: &File<'_>) -> crate::runtime::Result<Self> {
for item in msg.raw_fields() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.name_written,
2 => self.insertion_point_written,
15 => self.content_written,
16 => self.generated_code_info_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
impl Feature {
pub fn from_i32(value: i32) -> Self {
match value {
0 => Feature::FEATURENONE,
1 => Feature::FEATUREPROTO3OPTIONAL,
2 => Feature::FEATURESUPPORTSEDITIONS,
_ => Feature::FEATURENONE,
}
}
Ok(self)
}
pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub struct OwnedFile {
pub data: bytes::Bytes,
}
impl crate::runtime::RotoOwned for OwnedFile {
type Reader<'a> = File<'a>;
fn reader(&self) -> File<'_> {
File::new(&self.data).expect("failed to create reader")
}
}
impl crate::runtime::RotoMessage for OwnedFile {
fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedFile { data: buf })
pub struct File<'a> {
accessor: crate::runtime::ProtoAccessor<'a>,
name_offset: Option<usize>,
insertion_point_offset: Option<usize>,
content_offset: Option<usize>,
generated_code_info_offset: Option<usize>,
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
impl<'a> File<'a> {
pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut name_offset = None;
let mut insertion_point_offset = None;
let mut content_offset = None;
let mut generated_code_info_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 {
name_offset = Some(offset);
}
if tag.field_number == 2 {
insertion_point_offset = Some(offset);
}
if tag.field_number == 15 {
content_offset = Some(offset);
}
if tag.field_number == 16 {
generated_code_info_offset = Some(offset);
}
}
Ok(Self {
accessor,
name_offset,
insertion_point_offset,
content_offset,
generated_code_info_offset,
})
}
pub fn name(&self) -> crate::runtime::Result<&'a str> {
let offset = self
.name_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
pub fn name_or_default(&self) -> crate::runtime::Result<&'a str> {
self.name().or(Ok(""))
}
pub fn has_name(&self) -> bool {
self.name_offset.is_some()
}
pub fn insertion_point(&self) -> crate::runtime::Result<&'a str> {
let offset = self
.insertion_point_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
pub fn insertion_point_or_default(&self) -> crate::runtime::Result<&'a str> {
self.insertion_point().or(Ok(""))
}
pub fn has_insertion_point(&self) -> bool {
self.insertion_point_offset.is_some()
}
pub fn content(&self) -> crate::runtime::Result<&'a str> {
let offset = self
.content_offset
.ok_or(crate::runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
}
pub fn content_or_default(&self) -> crate::runtime::Result<&'a str> {
self.content().or(Ok(""))
}
pub fn has_content(&self) -> bool {
self.content_offset.is_some()
}
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 (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes)
}
pub fn generated_code_info_or_default(&self) -> crate::runtime::Result<&'a [u8]> {
self.generated_code_info().or(Ok(&[]))
}
pub fn has_generated_code_info(&self) -> bool {
self.generated_code_info_offset.is_some()
}
pub fn raw_fields(&self) -> crate::runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct FileBuilder<'b> {
builder: crate::runtime::ProtoBuilder<'b>,
name_written: bool,
insertion_point_written: bool,
content_written: bool,
generated_code_info_written: bool,
}
impl<'b> FileBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
FileBuilder {
builder: crate::runtime::ProtoBuilder::new(buf),
name_written: false,
insertion_point_written: false,
content_written: false,
generated_code_info_written: false,
}
}
pub fn name(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
}
pub fn insertion_point(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(2, value)?;
self.insertion_point_written = true;
Ok(self)
}
pub fn content(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(15, value)?;
self.content_written = true;
Ok(self)
}
pub fn generated_code_info(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(16, value)?;
self.generated_code_info_written = true;
Ok(self)
}
pub fn with(mut self, msg: &File<'_>) -> crate::runtime::Result<Self> {
for item in msg.raw_fields() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.name_written,
2 => self.insertion_point_written,
15 => self.content_written,
16 => self.generated_code_info_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub struct OwnedFile {
pub data: bytes::Bytes,
}
impl crate::runtime::RotoOwned for OwnedFile {
type Reader<'a> = File<'a>;
fn reader(&self) -> File<'_> {
File::new(&self.data).expect("failed to create reader")
}
}
impl crate::runtime::RotoMessage for OwnedFile {
fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedFile { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
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 roto_tonic::RotoCodec;
use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse};
use hello::{OwnedHelloRequest, OwnedHelloResponse};
use roto_runtime::RotoOwned;
use roto_tonic::RotoCodec;
use std::task::{Context, Poll};
use tonic::Request;
use tower::Service;
pub use roto_tonic::{BufferPool, StatusBody};
#[allow(
unused,
unused_imports,
unused_assignments,
unused_variables,
non_camel_case_types
)]
pub mod hello {
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"
let mut buf = vec![0u8; 1024];
let slice = hello::HelloRequestBuilder::builder(&mut buf)
.name("Roto").unwrap()
.finish().unwrap();
.name("Roto")
.unwrap()
.finish()
.unwrap();
let request = OwnedHelloRequest {
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 reader = response_msg.reader();
println!("Server responded: {}", reader.message().unwrap_or("No message"));
println!(
"Server responded: {}",
reader.message().unwrap_or("No message")
);
Ok(())
}
+44 -20
View File
@@ -1,20 +1,24 @@
use std::pin::Pin;
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 bytes::{BufMut, Bytes};
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::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};
#[allow(
unused,
unused_imports,
unused_assignments,
unused_variables,
non_camel_case_types
)]
pub mod hello {
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
}
@@ -43,8 +47,10 @@ impl HelloWorldService for MyHelloWorld {
let mut buf = self.pool.get();
buf.resize(1024, 0);
let slice = hello::HelloResponseBuilder::builder(&mut buf[..])
.message(&format!("Hello {}!", name)).unwrap()
.finish().unwrap();
.message(&format!("Hello {}!", name))
.unwrap()
.finish()
.unwrap();
let res_len = slice.len();
let response_bytes = buf.split_to(res_len).freeze();
@@ -68,7 +74,10 @@ pub struct HelloWorldServer {
impl HelloWorldServer {
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 {
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()
.status(200)
.body(res_body)
@@ -123,8 +135,14 @@ impl Service<http::Request<BoxBody>> for HelloWorldServer {
Ok(msg) => msg,
Err(e) => {
println!("Decode error: {}", e);
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());
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());
}
};
@@ -133,8 +151,14 @@ impl Service<http::Request<BoxBody>> for HelloWorldServer {
Ok(res) => res,
Err(e) => {
println!("Service error: {}", e);
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());
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());
}
};
+333 -208
View File
@@ -1,22 +1,29 @@
// @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 std::str;
use bytes::{Bytes, BytesMut, Buf, BufMut};
use tonic::{Request, Response, Status};
use tokio_stream::Stream;
use crate::{BufferPool, StatusBody};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures_util::StreamExt;
use http_body::Body;
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::str;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::future::Future;
use tokio_stream::Stream;
use tonic::body::BoxBody;
use tonic::{Request, Response, Status};
use tower::Service;
use futures_util::StreamExt;
use http_body_util::BodyExt;
use http_body::Body;
use crate::{BufferPool, StatusBody};
pub struct Hello<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
@@ -47,36 +54,57 @@ impl<'a> Hello<'a> {
let mut pets_end = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { name_offset = Some(offset); }
if tag.field_number == 2 { d_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 == 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 == 1 {
name_offset = Some(offset);
}
if tag.field_number == 2 {
d_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 == 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 pets_start.is_none() { pets_start = Some(offset); }
if pets_start.is_none() {
pets_start = Some(offset);
}
pets_end = Some(offset);
}
}
Ok(Self {
accessor,
name_offset,
d_offset,
f_offset,
b_offset,
n_offset,
l_offset,
c1_offset,
c2_offset,
pets_start, pets_end,
name_offset,
d_offset,
f_offset,
b_offset,
n_offset,
l_offset,
c1_offset,
c2_offset,
pets_start,
pets_end,
})
}
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)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
@@ -85,70 +113,104 @@ pets_start, pets_end,
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
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> {
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> {
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)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
@@ -157,19 +219,27 @@ pets_start, pets_end,
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> {
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)?;
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> {
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> {
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() {
return Ok(Some(hello::Choice::c1 (self.c1()?)));
return Ok(Some(hello::Choice::c1(self.c1()?)));
}
if self.c2_offset.is_some() {
return Ok(Some(hello::Choice::c2 (self.c2()?)));
return Ok(Some(hello::Choice::c2(self.c2()?)));
}
Ok(None)
}
@@ -191,7 +261,6 @@ pets_start, pets_end,
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct HelloBuilder<'b> {
@@ -326,161 +395,172 @@ impl roto_runtime::RotoMessage for OwnedHello {
}
pub mod hello {
pub struct Pet<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
name_offset: Option<usize>,
color_offset: Option<usize>,
}
pub struct Pet<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
name_offset: Option<usize>,
color_offset: Option<usize>,
}
impl<'a> Pet<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut name_offset = None;
let mut color_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { name_offset = Some(offset); }
if tag.field_number == 2 { color_offset = Some(offset); }
impl<'a> Pet<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut name_offset = None;
let mut color_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 {
name_offset = Some(offset);
}
if tag.field_number == 2 {
color_offset = Some(offset);
}
}
Ok(Self {
accessor,
name_offset,
color_offset,
})
}
Ok(Self {
accessor,
name_offset,
color_offset,
})
}
pub fn name(&self) -> roto_runtime::Result<&'a str> {
let offset = self
.name_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn name(&self) -> roto_runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> {
self.name().or(Ok(""))
}
pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> {
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> {
let offset = self
.color_offset
.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes)
.map(|(v, _)| v as u64)
.map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn color(&self) -> roto_runtime::Result<u64> {
let offset = self.color_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
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> {
self.color().or(Ok(0))
}
pub fn color_or_default(&self) -> roto_runtime::Result<u64> {
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> {
self.accessor.raw_fields()
}
}
pub struct PetBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>,
name_written: bool,
color_written: bool,
}
impl<'b> PetBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> PetBuilder<'_> {
PetBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
name_written: false,
color_written: false,
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub fn name(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
pub struct PetBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>,
name_written: bool,
color_written: bool,
}
pub fn color(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(2, value)?;
self.color_written = true;
Ok(self)
}
pub fn with(mut self, msg: &Pet<'_>) -> roto_runtime::Result<Self> {
for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.name_written,
2 => self.color_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
impl<'b> PetBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> PetBuilder<'_> {
PetBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
name_written: false,
color_written: false,
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
pub fn name(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
}
pub struct OwnedPet {
pub data: bytes::Bytes,
}
pub fn color(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(2, value)?;
self.color_written = true;
Ok(self)
}
impl roto_runtime::RotoOwned for OwnedPet {
type Reader<'a> = Pet<'a>;
fn reader(&self) -> Pet<'_> {
Pet::new(&self.data).expect("failed to create reader")
}
}
pub fn with(mut self, msg: &Pet<'_>) -> roto_runtime::Result<Self> {
for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?;
let is_written = match field_number {
1 => self.name_written,
2 => self.color_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
impl roto_runtime::RotoMessage for OwnedPet {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedPet { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub mod pet {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum Color {
BLACK = 0,
WHITE = 1,
BLUE = 2,
RED = 3,
YELLOW = 4,
GREEN = 5,
}
impl Color {
pub fn from_i32(value: i32) -> Self {
match value {
0 => Color::BLACK,
1 => Color::WHITE,
2 => Color::BLUE,
3 => Color::RED,
4 => Color::YELLOW,
5 => Color::GREEN,
_ => Color::BLACK,
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
}
}
pub struct OwnedPet {
pub data: bytes::Bytes,
}
pub enum Choice<'a> {
c1(&'a str),
c2(bool),
}
impl roto_runtime::RotoOwned for OwnedPet {
type Reader<'a> = Pet<'a>;
fn reader(&self) -> Pet<'_> {
Pet::new(&self.data).expect("failed to create reader")
}
}
impl roto_runtime::RotoMessage for OwnedPet {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedPet { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub mod pet {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum Color {
BLACK = 0,
WHITE = 1,
BLUE = 2,
RED = 3,
YELLOW = 4,
GREEN = 5,
}
impl Color {
pub fn from_i32(value: i32) -> Self {
match value {
0 => Color::BLACK,
1 => Color::WHITE,
2 => Color::BLUE,
3 => Color::RED,
4 => Color::YELLOW,
5 => Color::GREEN,
_ => Color::BLACK,
}
}
}
}
pub enum Choice<'a> {
c1(&'a str),
c2(bool),
}
}
pub struct HelloRequest<'a> {
@@ -494,17 +574,21 @@ impl<'a> HelloRequest<'a> {
let mut request_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { request_offset = Some(offset); }
if tag.field_number == 1 {
request_offset = Some(offset);
}
}
Ok(Self {
accessor,
request_offset,
request_offset,
})
}
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)?;
Ok(bytes)
}
@@ -513,12 +597,13 @@ request_offset,
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> {
self.accessor.raw_fields()
}
}
pub struct HelloRequestBuilder<'b> {
@@ -591,17 +676,21 @@ impl<'a> HelloReply<'a> {
let mut response_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { response_offset = Some(offset); }
if tag.field_number == 1 {
response_offset = Some(offset);
}
}
Ok(Self {
accessor,
response_offset,
response_offset,
})
}
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)?;
Ok(bytes)
}
@@ -610,12 +699,13 @@ response_offset,
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> {
self.accessor.raw_fields()
}
}
pub struct HelloReplyBuilder<'b> {
@@ -679,7 +769,10 @@ impl roto_runtime::RotoMessage for OwnedHelloReply {
#[tonic::async_trait]
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)]
@@ -701,7 +794,8 @@ impl tonic::server::NamedService for GreeterServer {
impl Service<http::Request<BoxBody>> for GreeterServer {
type Response = http::Response<BoxBody>;
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>> {
Poll::Ready(Ok(()))
@@ -726,8 +820,14 @@ impl Service<http::Request<BoxBody>> for GreeterServer {
let bytes_vec = buf.split_to(total_len).freeze();
pool.put(buf);
if bytes_vec.len() < 5 {
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());
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());
}
let payload = bytes_vec.slice(5..);
@@ -737,16 +837,28 @@ impl Service<http::Request<BoxBody>> for GreeterServer {
let request_msg = match OwnedHelloRequest::decode(payload) {
Ok(msg) => msg,
Err(e) => {
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());
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());
}
};
let response = match inner.say_hello(Request::new(request_msg)).await {
Ok(res) => res,
Err(e) => {
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());
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());
}
};
@@ -762,13 +874,26 @@ impl Service<http::Request<BoxBody>> for GreeterServer {
pool.put(res_buf);
let res_body = BoxBody::new(StatusBody::new(Some(frame), 0));
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 {
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());
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());
}
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
#![allow(unused)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
#[allow(unused, unused_imports, unused_assignments, unused_variables, non_camel_case_types)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, RevBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use core::str;
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 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 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 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 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 tokio_stream::Stream;
use std::pin::Pin;
@@ -462,12 +619,12 @@ impl Service<http::Request<BoxBody>> for InteropServiceServer {
}
let payload = bytes_vec.slice(5..);
#[allow(unused_assignments)]
let mut routed = false;
if path == "/interop.InteropService/UnaryCall" {
let request_msg = match OwnedUnaryRequest::decode(payload) {
Ok(msg) => msg,
Err(e) => {
Err(_e) => {
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());
}
@@ -475,7 +632,7 @@ impl Service<http::Request<BoxBody>> for InteropServiceServer {
let response = match inner.unary_call(Request::new(request_msg)).await {
Ok(res) => res,
Err(e) => {
Err(_e) => {
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());
}
+385 -3
View File
@@ -6,8 +6,8 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
use core::fmt;
use bytes::BufMut;
use core::fmt;
pub struct MapFieldIterator<'a> {
inner: RepeatedFieldIterator<'a>,
@@ -65,7 +65,9 @@ impl std::error::Error for RotoError {}
pub type Result<T> = core::result::Result<T, RotoError>;
pub trait RotoOwned {
type Reader<'a> where Self: 'a;
type Reader<'a>
where
Self: 'a;
fn reader(&self) -> Self::Reader<'_>;
}
@@ -442,7 +444,7 @@ impl<'a> Iterator for RawFieldIterator<'a> {
mod tests {
use super::*;
#[cfg(feature = "alloc")]
use alloc::{vec, vec::{Vec}};
use alloc::{vec, vec::Vec};
#[test]
fn test_varint_read_write() {
@@ -745,6 +747,199 @@ mod tests {
}
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> {
@@ -922,3 +1117,190 @@ impl<'a, B: BufMut> BufMutBuilder<'a, B> {
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..])
}
}