Compare commits

...

8 Commits

Author SHA1 Message Date
openhands 6ac13ff43e Make code generator self-contained by integrating runtime support 2026-05-26 05:11:41 +00:00
openhands 6376abd412 Implement the requested changes in the generator modules.
Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-26 04:15:02 +00:00
openhands de6af24565 Refactor codegen/src/generator.rs into a modular directory structure and fix compilation errors.
Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-25 04:11:57 +00:00
charles 6085ef3923 More generated files 2026-05-20 08:12:38 -07:00
charles f03e1afdbf Regenerate protobuf files 2026-05-20 08:09:11 -07:00
charles 7e43e09f66 Clean up generated code and implement strip_boilerplate
Remove redundant newlines and duplicate headers from generated files
and prevent the creation of empty sub-modules. Implement the
`strip_boilerplate` function to remove generated headers and
attributes, including a comprehensive test suite.
2026-05-19 23:08:05 -07:00
charles 117cbf812b Introduce alloc feature for optional allocation
Wrap heap-allocated types and service generation in the `alloc` feature
flag to support environments without a memory allocator.
2026-05-19 21:55:18 -07:00
charles 6910f11d69 Add no_std test example and update alloc gating
Update codegen to make `bytes` imports conditional on the `alloc`
feature and add a test example for the `thumbv7em-none-eabihf`
target.
2026-05-18 08:43:22 -07:00
31 changed files with 17607 additions and 2773 deletions
+2
View File
@@ -5,3 +5,5 @@ test_map_gen_project
test_grpc_project test_grpc_project
artifacts/ artifacts/
temp_test_project/ temp_test_project/
output_svc/
output_proto/
Generated
+4 -1
View File
@@ -546,6 +546,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
name = "hello-world" name = "hello-world"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http",
@@ -836,6 +837,8 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
name = "no_std_test" name = "no_std_test"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bytes",
"prost",
"roto-runtime", "roto-runtime",
] ]
@@ -1183,7 +1186,6 @@ dependencies = [
"http-body", "http-body",
"http-body-util", "http-body-util",
"log", "log",
"roto-runtime",
"roto-tonic", "roto-tonic",
"tokio-stream", "tokio-stream",
"tonic", "tonic",
@@ -1201,6 +1203,7 @@ dependencies = [
name = "roto-tonic" name = "roto-tonic"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http",
+291 -108
View File
@@ -1,13 +1,13 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#![allow(unused_imports)] #[allow(unused_imports)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use crate::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator}; use core::str;
use std::str; #[cfg(feature = "alloc")]
use bytes::{Bytes, BytesMut, Buf, BufMut};
use crate::google::protobuf::descriptor; use crate::google::protobuf::descriptor;
pub struct Version<'a> { pub struct Version<'a> {
accessor: crate::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
major_offset: Option<usize>, major_offset: Option<usize>,
minor_offset: Option<usize>, minor_offset: Option<usize>,
patch_offset: Option<usize>, patch_offset: Option<usize>,
@@ -15,8 +15,8 @@ pub struct Version<'a> {
} }
impl<'a> Version<'a> { impl<'a> Version<'a> {
pub fn new(data: &'a [u8]) -> crate::Result<Self> { pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = crate::ProtoAccessor::new(data)?; let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut major_offset = None; let mut major_offset = None;
let mut minor_offset = None; let mut minor_offset = None;
let mut patch_offset = None; let mut patch_offset = None;
@@ -38,38 +38,62 @@ suffix_offset,
}) })
} }
pub fn major(&self) -> crate::Result<i32> { pub fn major(&self) -> roto_runtime::Result<i32> {
let offset = self.major_offset.ok_or(crate::RotoError::FieldNotFound)?; let offset = self.major_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn minor(&self) -> crate::Result<i32> { pub fn major_or_default(&self) -> roto_runtime::Result<i32> {
let offset = self.minor_offset.ok_or(crate::RotoError::FieldNotFound)?; self.major().or(Ok(0))
let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
} }
pub fn patch(&self) -> crate::Result<i32> { pub fn has_major(&self) -> bool { self.major_offset.is_some() }
let offset = self.patch_offset.ok_or(crate::RotoError::FieldNotFound)?;
pub fn minor(&self) -> roto_runtime::Result<i32> {
let offset = self.minor_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn suffix(&self) -> crate::Result<&'a str> { pub fn minor_or_default(&self) -> roto_runtime::Result<i32> {
let offset = self.suffix_offset.ok_or(crate::RotoError::FieldNotFound)?; self.minor().or(Ok(0))
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
} }
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> { pub fn has_minor(&self) -> bool { self.minor_offset.is_some() }
pub fn patch(&self) -> roto_runtime::Result<i32> {
let offset = self.patch_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)
}
pub fn patch_or_default(&self) -> roto_runtime::Result<i32> {
self.patch().or(Ok(0))
}
pub fn has_patch(&self) -> bool { self.patch_offset.is_some() }
pub fn suffix(&self) -> roto_runtime::Result<&'a str> {
let offset = self.suffix_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn suffix_or_default(&self) -> roto_runtime::Result<&'a str> {
self.suffix().or(Ok(""))
}
pub fn has_suffix(&self) -> bool { self.suffix_offset.is_some() }
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct VersionBuilder<'b> { pub struct VersionBuilder<'b> {
builder: crate::ProtoBuilder<'b>, builder: roto_runtime::ProtoBuilder<'b>,
major_written: bool, major_written: bool,
minor_written: bool, minor_written: bool,
patch_written: bool, patch_written: bool,
@@ -79,7 +103,7 @@ pub struct VersionBuilder<'b> {
impl<'b> VersionBuilder<'b> { impl<'b> VersionBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> { pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
VersionBuilder { VersionBuilder {
builder: crate::ProtoBuilder::new(buf), builder: roto_runtime::ProtoBuilder::new(buf),
major_written: false, major_written: false,
minor_written: false, minor_written: false,
patch_written: false, patch_written: false,
@@ -87,32 +111,32 @@ impl<'b> VersionBuilder<'b> {
} }
} }
pub fn major(mut self, value: i32) -> crate::Result<Self> { pub fn major(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(1, value)?; self.builder.write_int32(1, value)?;
self.major_written = true; self.major_written = true;
Ok(self) Ok(self)
} }
pub fn minor(mut self, value: i32) -> crate::Result<Self> { pub fn minor(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(2, value)?; self.builder.write_int32(2, value)?;
self.minor_written = true; self.minor_written = true;
Ok(self) Ok(self)
} }
pub fn patch(mut self, value: i32) -> crate::Result<Self> { pub fn patch(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(3, value)?; self.builder.write_int32(3, value)?;
self.patch_written = true; self.patch_written = true;
Ok(self) Ok(self)
} }
pub fn suffix(mut self, value: &str) -> crate::Result<Self> { pub fn suffix(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(4, value)?; self.builder.write_string(4, value)?;
self.suffix_written = true; self.suffix_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &Version<'_>) -> crate::Result<Self> { pub fn with(mut self, msg: &Version<'_>) -> roto_runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
1 => self.major_written, 1 => self.major_written,
@@ -128,13 +152,37 @@ impl<'b> VersionBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> crate::Result<&'b mut [u8]> { pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedVersion {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedVersion {
type Reader<'a> = Version<'a>;
fn reader(&self) -> Version<'_> {
Version::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedVersion {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedVersion { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub struct CodeGeneratorRequest<'a> { pub struct CodeGeneratorRequest<'a> {
accessor: crate::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
file_to_generate_start: Option<usize>, file_to_generate_start: Option<usize>,
file_to_generate_end: Option<usize>, file_to_generate_end: Option<usize>,
parameter_offset: Option<usize>, parameter_offset: Option<usize>,
@@ -146,8 +194,8 @@ pub struct CodeGeneratorRequest<'a> {
} }
impl<'a> CodeGeneratorRequest<'a> { impl<'a> CodeGeneratorRequest<'a> {
pub fn new(data: &'a [u8]) -> crate::Result<Self> { pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = crate::ProtoAccessor::new(data)?; let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut file_to_generate_start = None; let mut file_to_generate_start = None;
let mut file_to_generate_end = None; let mut file_to_generate_end = None;
let mut parameter_offset = None; let mut parameter_offset = None;
@@ -184,47 +232,59 @@ compiler_version_offset,
}) })
} }
pub fn file_to_generate(&self) -> crate::RepeatedFieldIterator<'a> { pub fn file_to_generate(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.file_to_generate_start, self.file_to_generate_end) { match (self.file_to_generate_start, self.file_to_generate_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(1, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(1, start, end),
_ => self.accessor.iter_repeated(1), _ => self.accessor.iter_repeated(1),
} }
} }
pub fn parameter(&self) -> crate::Result<&'a str> { pub fn parameter(&self) -> roto_runtime::Result<&'a str> {
let offset = self.parameter_offset.ok_or(crate::RotoError::FieldNotFound)?; let offset = self.parameter_offset.ok_or(roto_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::RotoError::WireFormatViolation) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn proto_file(&self) -> crate::RepeatedFieldIterator<'a> { pub fn parameter_or_default(&self) -> roto_runtime::Result<&'a str> {
self.parameter().or(Ok(""))
}
pub fn has_parameter(&self) -> bool { self.parameter_offset.is_some() }
pub fn proto_file(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.proto_file_start, self.proto_file_end) { match (self.proto_file_start, self.proto_file_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
_ => self.accessor.iter_repeated(15), _ => self.accessor.iter_repeated(15),
} }
} }
pub fn source_file_descriptors(&self) -> crate::RepeatedFieldIterator<'a> { pub fn source_file_descriptors(&self) -> roto_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::Result<&'a [u8]> { pub fn compiler_version(&self) -> roto_runtime::Result<&'a [u8]> {
let offset = self.compiler_version_offset.ok_or(crate::RotoError::FieldNotFound)?; let offset = self.compiler_version_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)
} }
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> { pub fn compiler_version_or_default(&self) -> roto_runtime::Result<&'a [u8]> {
self.compiler_version().or(Ok(&[]))
}
pub fn has_compiler_version(&self) -> bool { self.compiler_version_offset.is_some() }
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct CodeGeneratorRequestBuilder<'b> { pub struct CodeGeneratorRequestBuilder<'b> {
builder: crate::ProtoBuilder<'b>, builder: roto_runtime::ProtoBuilder<'b>,
file_to_generate_written: bool, file_to_generate_written: bool,
parameter_written: bool, parameter_written: bool,
proto_file_written: bool, proto_file_written: bool,
@@ -235,7 +295,7 @@ pub struct CodeGeneratorRequestBuilder<'b> {
impl<'b> CodeGeneratorRequestBuilder<'b> { impl<'b> CodeGeneratorRequestBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> { pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
CodeGeneratorRequestBuilder { CodeGeneratorRequestBuilder {
builder: crate::ProtoBuilder::new(buf), builder: roto_runtime::ProtoBuilder::new(buf),
file_to_generate_written: false, file_to_generate_written: false,
parameter_written: false, parameter_written: false,
proto_file_written: false, proto_file_written: false,
@@ -244,38 +304,38 @@ impl<'b> CodeGeneratorRequestBuilder<'b> {
} }
} }
pub fn file_to_generate(mut self, value: &str) -> crate::Result<Self> { pub fn file_to_generate(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?; self.builder.write_string(1, value)?;
self.file_to_generate_written = true; self.file_to_generate_written = true;
Ok(self) Ok(self)
} }
pub fn parameter(mut self, value: &str) -> crate::Result<Self> { pub fn parameter(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(2, value)?; self.builder.write_string(2, value)?;
self.parameter_written = true; self.parameter_written = true;
Ok(self) Ok(self)
} }
pub fn proto_file(mut self, value: &[u8]) -> crate::Result<Self> { pub fn proto_file(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(15, value)?; self.builder.write_bytes(15, value)?;
self.proto_file_written = true; self.proto_file_written = true;
Ok(self) Ok(self)
} }
pub fn source_file_descriptors(mut self, value: &[u8]) -> crate::Result<Self> { pub fn source_file_descriptors(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(17, value)?; self.builder.write_bytes(17, value)?;
self.source_file_descriptors_written = true; self.source_file_descriptors_written = true;
Ok(self) Ok(self)
} }
pub fn compiler_version(mut self, value: &[u8]) -> crate::Result<Self> { pub fn compiler_version(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(3, value)?; self.builder.write_bytes(3, value)?;
self.compiler_version_written = true; self.compiler_version_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &CodeGeneratorRequest<'_>) -> crate::Result<Self> { pub fn with(mut self, msg: &CodeGeneratorRequest<'_>) -> roto_runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
1 => self.file_to_generate_written, 1 => self.file_to_generate_written,
@@ -292,13 +352,37 @@ impl<'b> CodeGeneratorRequestBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> crate::Result<&'b mut [u8]> { pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedCodeGeneratorRequest {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedCodeGeneratorRequest {
type Reader<'a> = CodeGeneratorRequest<'a>;
fn reader(&self) -> CodeGeneratorRequest<'_> {
CodeGeneratorRequest::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedCodeGeneratorRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedCodeGeneratorRequest { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub struct CodeGeneratorResponse<'a> { pub struct CodeGeneratorResponse<'a> {
accessor: crate::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
error_offset: Option<usize>, error_offset: Option<usize>,
supported_features_offset: Option<usize>, supported_features_offset: Option<usize>,
minimum_edition_offset: Option<usize>, minimum_edition_offset: Option<usize>,
@@ -308,8 +392,8 @@ pub struct CodeGeneratorResponse<'a> {
} }
impl<'a> CodeGeneratorResponse<'a> { impl<'a> CodeGeneratorResponse<'a> {
pub fn new(data: &'a [u8]) -> crate::Result<Self> { pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = crate::ProtoAccessor::new(data)?; let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut error_offset = None; let mut error_offset = None;
let mut supported_features_offset = None; let mut supported_features_offset = None;
let mut minimum_edition_offset = None; let mut minimum_edition_offset = None;
@@ -338,45 +422,69 @@ file_start, file_end,
}) })
} }
pub fn error(&self) -> crate::Result<&'a str> { pub fn error(&self) -> roto_runtime::Result<&'a str> {
let offset = self.error_offset.ok_or(crate::RotoError::FieldNotFound)?; let offset = self.error_offset.ok_or(roto_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::RotoError::WireFormatViolation) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn supported_features(&self) -> crate::Result<u32> { pub fn error_or_default(&self) -> roto_runtime::Result<&'a str> {
let offset = self.supported_features_offset.ok_or(crate::RotoError::FieldNotFound)?; self.error().or(Ok(""))
let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| crate::RotoError::WireFormatViolation)
} }
pub fn minimum_edition(&self) -> crate::Result<i32> { pub fn has_error(&self) -> bool { self.error_offset.is_some() }
let offset = self.minimum_edition_offset.ok_or(crate::RotoError::FieldNotFound)?;
pub fn supported_features(&self) -> roto_runtime::Result<u32> {
let offset = self.supported_features_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?; let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation) roto_runtime::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn maximum_edition(&self) -> crate::Result<i32> { pub fn supported_features_or_default(&self) -> roto_runtime::Result<u32> {
let offset = self.maximum_edition_offset.ok_or(crate::RotoError::FieldNotFound)?; self.supported_features().or(Ok(0))
let (bytes, _) = self.accessor.get_value_at(offset)?;
crate::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| crate::RotoError::WireFormatViolation)
} }
pub fn file(&self) -> crate::RepeatedFieldIterator<'a> { pub fn has_supported_features(&self) -> bool { self.supported_features_offset.is_some() }
pub fn minimum_edition(&self) -> roto_runtime::Result<i32> {
let offset = self.minimum_edition_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)
}
pub fn minimum_edition_or_default(&self) -> roto_runtime::Result<i32> {
self.minimum_edition().or(Ok(0))
}
pub fn has_minimum_edition(&self) -> bool { self.minimum_edition_offset.is_some() }
pub fn maximum_edition(&self) -> roto_runtime::Result<i32> {
let offset = self.maximum_edition_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)
}
pub fn maximum_edition_or_default(&self) -> roto_runtime::Result<i32> {
self.maximum_edition().or(Ok(0))
}
pub fn has_maximum_edition(&self) -> bool { self.maximum_edition_offset.is_some() }
pub fn file(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.file_start, self.file_end) { match (self.file_start, self.file_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
_ => self.accessor.iter_repeated(15), _ => self.accessor.iter_repeated(15),
} }
} }
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> { pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct CodeGeneratorResponseBuilder<'b> { pub struct CodeGeneratorResponseBuilder<'b> {
builder: crate::ProtoBuilder<'b>, builder: roto_runtime::ProtoBuilder<'b>,
error_written: bool, error_written: bool,
supported_features_written: bool, supported_features_written: bool,
minimum_edition_written: bool, minimum_edition_written: bool,
@@ -387,7 +495,7 @@ pub struct CodeGeneratorResponseBuilder<'b> {
impl<'b> CodeGeneratorResponseBuilder<'b> { impl<'b> CodeGeneratorResponseBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> { pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
CodeGeneratorResponseBuilder { CodeGeneratorResponseBuilder {
builder: crate::ProtoBuilder::new(buf), builder: roto_runtime::ProtoBuilder::new(buf),
error_written: false, error_written: false,
supported_features_written: false, supported_features_written: false,
minimum_edition_written: false, minimum_edition_written: false,
@@ -396,38 +504,38 @@ impl<'b> CodeGeneratorResponseBuilder<'b> {
} }
} }
pub fn error(mut self, value: &str) -> crate::Result<Self> { pub fn error(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?; self.builder.write_string(1, value)?;
self.error_written = true; self.error_written = true;
Ok(self) Ok(self)
} }
pub fn supported_features(mut self, value: u64) -> crate::Result<Self> { pub fn supported_features(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(2, value)?; self.builder.write_varint(2, value)?;
self.supported_features_written = true; self.supported_features_written = true;
Ok(self) Ok(self)
} }
pub fn minimum_edition(mut self, value: i32) -> crate::Result<Self> { pub fn minimum_edition(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(3, value)?; self.builder.write_int32(3, value)?;
self.minimum_edition_written = true; self.minimum_edition_written = true;
Ok(self) Ok(self)
} }
pub fn maximum_edition(mut self, value: i32) -> crate::Result<Self> { pub fn maximum_edition(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(4, value)?; self.builder.write_int32(4, value)?;
self.maximum_edition_written = true; self.maximum_edition_written = true;
Ok(self) Ok(self)
} }
pub fn file(mut self, value: &[u8]) -> crate::Result<Self> { pub fn file(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(15, value)?; self.builder.write_bytes(15, value)?;
self.file_written = true; self.file_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &CodeGeneratorResponse<'_>) -> crate::Result<Self> { pub fn with(mut self, msg: &CodeGeneratorResponse<'_>) -> roto_runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
1 => self.error_written, 1 => self.error_written,
@@ -444,11 +552,35 @@ impl<'b> CodeGeneratorResponseBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> crate::Result<&'b mut [u8]> { pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedCodeGeneratorResponse {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedCodeGeneratorResponse {
type Reader<'a> = CodeGeneratorResponse<'a>;
fn reader(&self) -> CodeGeneratorResponse<'_> {
CodeGeneratorResponse::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedCodeGeneratorResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedCodeGeneratorResponse { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
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)]
@@ -470,7 +602,7 @@ impl Feature {
} }
pub struct File<'a> { pub struct File<'a> {
accessor: crate::ProtoAccessor<'a>, accessor: roto_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>,
@@ -478,8 +610,8 @@ pub struct File<'a> {
} }
impl<'a> File<'a> { impl<'a> File<'a> {
pub fn new(data: &'a [u8]) -> crate::Result<Self> { pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = crate::ProtoAccessor::new(data)?; let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut name_offset = None; let mut name_offset = None;
let mut insertion_point_offset = None; let mut insertion_point_offset = None;
let mut content_offset = None; let mut content_offset = None;
@@ -501,38 +633,62 @@ generated_code_info_offset,
}) })
} }
pub fn name(&self) -> crate::Result<&'a str> { pub fn name(&self) -> roto_runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(crate::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)?;
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn insertion_point(&self) -> crate::Result<&'a str> { pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> {
let offset = self.insertion_point_offset.ok_or(crate::RotoError::FieldNotFound)?; self.name().or(Ok(""))
let (bytes, _) = self.accessor.get_value_at(offset)?;
str::from_utf8(bytes).map_err(|_| crate::RotoError::WireFormatViolation)
} }
pub fn content(&self) -> crate::Result<&'a str> { pub fn has_name(&self) -> bool { self.name_offset.is_some() }
let offset = self.content_offset.ok_or(crate::RotoError::FieldNotFound)?;
pub fn insertion_point(&self) -> roto_runtime::Result<&'a str> {
let offset = self.insertion_point_offset.ok_or(roto_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::RotoError::WireFormatViolation) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn generated_code_info(&self) -> crate::Result<&'a [u8]> { pub fn insertion_point_or_default(&self) -> roto_runtime::Result<&'a str> {
let offset = self.generated_code_info_offset.ok_or(crate::RotoError::FieldNotFound)?; self.insertion_point().or(Ok(""))
}
pub fn has_insertion_point(&self) -> bool { self.insertion_point_offset.is_some() }
pub fn content(&self) -> roto_runtime::Result<&'a str> {
let offset = self.content_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn content_or_default(&self) -> roto_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) -> roto_runtime::Result<&'a [u8]> {
let offset = self.generated_code_info_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)
} }
pub fn raw_fields(&self) -> crate::RawFieldIterator<'a> { pub fn generated_code_info_or_default(&self) -> roto_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) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields() self.accessor.raw_fields()
} }
} }
pub struct FileBuilder<'b> { pub struct FileBuilder<'b> {
builder: crate::ProtoBuilder<'b>, builder: roto_runtime::ProtoBuilder<'b>,
name_written: bool, name_written: bool,
insertion_point_written: bool, insertion_point_written: bool,
content_written: bool, content_written: bool,
@@ -542,7 +698,7 @@ pub struct FileBuilder<'b> {
impl<'b> FileBuilder<'b> { impl<'b> FileBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> { pub fn builder(buf: &mut [u8]) -> FileBuilder<'_> {
FileBuilder { FileBuilder {
builder: crate::ProtoBuilder::new(buf), builder: roto_runtime::ProtoBuilder::new(buf),
name_written: false, name_written: false,
insertion_point_written: false, insertion_point_written: false,
content_written: false, content_written: false,
@@ -550,32 +706,32 @@ impl<'b> FileBuilder<'b> {
} }
} }
pub fn name(mut self, value: &str) -> crate::Result<Self> { pub fn name(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?; self.builder.write_string(1, value)?;
self.name_written = true; self.name_written = true;
Ok(self) Ok(self)
} }
pub fn insertion_point(mut self, value: &str) -> crate::Result<Self> { pub fn insertion_point(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(2, value)?; self.builder.write_string(2, value)?;
self.insertion_point_written = true; self.insertion_point_written = true;
Ok(self) Ok(self)
} }
pub fn content(mut self, value: &str) -> crate::Result<Self> { pub fn content(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(15, value)?; self.builder.write_string(15, value)?;
self.content_written = true; self.content_written = true;
Ok(self) Ok(self)
} }
pub fn generated_code_info(mut self, value: &[u8]) -> crate::Result<Self> { pub fn generated_code_info(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(16, value)?; self.builder.write_bytes(16, value)?;
self.generated_code_info_written = true; self.generated_code_info_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &File<'_>) -> crate::Result<Self> { pub fn with(mut self, msg: &File<'_>) -> roto_runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
1 => self.name_written, 1 => self.name_written,
@@ -591,10 +747,37 @@ impl<'b> FileBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> crate::Result<&'b mut [u8]> { pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedFile {
pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedFile {
type Reader<'a> = File<'a>;
fn reader(&self) -> File<'_> {
File::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedFile {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedFile { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
}
use crate::google::protobuf::descriptor;
File diff suppressed because it is too large Load Diff
+456 -294
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
roto-runtime = { path = "../runtime" }
roto-tonic = { path = "../roto-tonic" } roto-tonic = { path = "../roto-tonic" }
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
log = "0.4" log = "0.4"
+2 -2
View File
@@ -5,7 +5,7 @@ use roto_codegen::google::protobuf::compiler::plugin::{
CodeGeneratorRequest, CodeGeneratorResponseBuilder, code_generator_response::FileBuilder, CodeGeneratorRequest, CodeGeneratorResponseBuilder, code_generator_response::FileBuilder,
}; };
use roto_codegen::google::protobuf::descriptor::FileDescriptorSet; use roto_codegen::google::protobuf::descriptor::FileDescriptorSet;
// use roto_runtime::ProtoBuilder; // use roto_codegen::runtime::ProtoBuilder;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
fn main() { fn main() {
@@ -58,7 +58,7 @@ fn handle_request(
// Write length as varint // Write length as varint
let len = file_data.len() as u64; let len = file_data.len() as u64;
let mut len_buf = [0u8; 10]; let mut len_buf = [0u8; 10];
let len_size = roto_runtime::write_varint(len, &mut len_buf).map_err(|e| { let len_size = roto_codegen::runtime::write_varint(len, &mut len_buf).map_err(|e| {
error!("Failed to write varint length: {:?}", e); error!("Failed to write varint length: {:?}", e);
e e
})?; })?;
+467
View File
@@ -0,0 +1,467 @@
use crate::google::protobuf::descriptor::{DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, MessageOptions, OneofDescriptorProto};
use crate::google::protobuf::descriptor::FileDescriptorSet;
use crate::generator::types::map_type_to_rust_builder;
use crate::runtime::ProtoAccessor;
use crate::generator::utils::{to_pascal_case, to_snake_case};
use crate::generator::types::map_type_to_rust_accessor;
pub fn write_enum(enum_proto: &EnumDescriptorProto, output: &mut String) {
let enum_name = to_pascal_case(enum_proto.name().unwrap());
output.push_str(&format!(
"#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[repr(i32)]\npub enum {} {{\n",
enum_name
));
let mut values = enum_proto.value();
let mut zero_variant_name = None;
while let Some(val_res) = values.next() {
let (val_data, _) = val_res.expect("Failed to iterate enum");
let accessor =
ProtoAccessor::new(val_data).expect("Failed to parse EnumValueDescriptorProto");
let (name_bytes, _) = accessor.get_value(1).expect("Enum value name missing");
let name = std::str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
let (num, _) =
crate::runtime::read_varint(num_bytes).expect("Enum value number invalid varint");
let pascal_name = to_pascal_case(name);
if num == 0 {
zero_variant_name = Some(pascal_name.clone());
}
output.push_str(&format!(" {} = {},\n", pascal_name, num));
}
if zero_variant_name.is_none() {
output.push_str(" Unknown = 0,\n");
zero_variant_name = Some("Unknown".to_string());
}
output.push_str("}\n\n");
output.push_str(&format!(
"impl {} {{\n pub fn from_i32(value: i32) -> Self {{\n match value {{\n",
enum_name
));
let mut values = enum_proto.value();
while let Some(val_res) = values.next() {
let (val_data, _) = val_res.expect("Failed to read enum value");
let accessor =
ProtoAccessor::new(val_data).expect("Failed to parse EnumValueDescriptorProto");
let (name_bytes, _) = accessor.get_value(1).expect("Enum value name missing");
let name = std::str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
let (num, _) =
crate::runtime::read_varint(num_bytes).expect("Enum value number invalid varint");
output.push_str(&format!(
" {} => {}::{},\n",
num,
enum_name,
to_pascal_case(name)
));
}
output.push_str(&format!(
" _ => {}::{},\n",
enum_name,
zero_variant_name.as_ref().unwrap()
));
output.push_str(" }\n }\n}\n\n");
}
pub fn write_message(msg_proto: &DescriptorProto, output: &mut String) {
let msg_name = to_pascal_case(msg_proto.name().unwrap());
let mod_name = to_snake_case(msg_proto.name().unwrap());
let mut fields_info = Vec::new();
for field_res in msg_proto.field() {
let (field_data, _) = field_res.expect("Failed to iterate field");
let field_proto =
FieldDescriptorProto::new(field_data).expect("Failed to parse FieldDescriptorProto");
let field_name = field_proto.name().unwrap();
let tag = field_proto.number().unwrap();
let f_type = field_proto.rype().unwrap() as i32;
let f_label = field_proto.label().unwrap() as i32;
let oneof_index = field_proto.oneof_index().ok();
let is_map = field_proto
.options()
.map(|opt| {
MessageOptions::new(opt)
.unwrap()
.map_entry()
.unwrap_or(false)
})
.unwrap_or(false);
fields_info.push((
field_name.to_string(),
tag,
f_type,
f_label,
oneof_index,
is_map,
));
}
let mut oneofs = Vec::new();
for o_res in msg_proto.oneof_decl() {
let (o, _) = o_res.expect("Failed to iterate oneof");
oneofs.push(o);
}
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 {
if *f_label == 3 {
output.push_str(&format!(" {}_start: Option<usize>,\n", field_name));
output.push_str(&format!(" {}_end: Option<usize>,\n", field_name));
} else {
output.push_str(&format!(" {}_offset: Option<usize>,\n", field_name));
}
}
output.push_str("}\n\n");
output.push_str(&format!("impl<'a> {}<'a> {{\n", msg_name));
output.push_str(" pub fn new(data: &'a [u8]) -> 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 {
if *label == 3 {
output.push_str(&format!(" let mut {}_start = None;\n", name));
output.push_str(&format!(" let mut {}_end = None;\n", name));
} else {
output.push_str(&format!(" let mut {}_offset = None;\n", name));
}
}
output.push_str(" for item in accessor.fields() {\n");
output.push_str(" let (offset, tag, _) = item?;\n");
for (name, tag, _, label, _oneof_index, _is_map) in &fields_info {
if *label == 3 {
output.push_str(&format!(" if tag.field_number == {} {{\n", tag));
output.push_str(&format!(
" if {}_start.is_none() {{ {}_start = Some(offset); }}\n",
name, name
));
output.push_str(&format!(" {}_end = Some(offset);\n", name));
output.push_str(" }\n");
} else {
output.push_str(&format!(
" if tag.field_number == {} {{ {}_offset = Some(offset); }}\n",
tag, name
));
}
}
output.push_str(" }\n\n");
output.push_str(" Ok(Self {\n");
output.push_str(" accessor,\n");
for (name, _, _, label, _oneof_index, _is_map) in &fields_info {
if *label == 3 {
output.push_str(&format!("{}_start, {}_end,\n", name, name));
} else {
output.push_str(&format!("{}_offset,\n", name));
}
}
output.push_str(" })\n }\n\n");
for (field_name, tag, f_type, f_label, _oneof_index, is_map) in &fields_info {
let (rust_type, logic, default_val) = map_type_to_rust_accessor(*f_type, *f_label, *is_map);
let safe_name = if field_name == "type" {
format!("r#{}", field_name)
} else {
field_name.clone()
};
if *f_label == 3 {
output.push_str(&format!(
" pub fn {}(&self) -> {} {{\n",
safe_name, rust_type
));
output.push_str(&format!(
" match (self.{}_start, self.{}_end) {{\n",
field_name, field_name
));
if *is_map {
output.push_str(&format!(" (Some(start), Some(end)) => roto_runtime::MapFieldIterator::new(self.accessor.iter_repeated_range({}, start, end)),\n", tag));
output.push_str(&format!(
" _ => roto_runtime::MapFieldIterator::new(self.accessor.iter_repeated({})),\n",
tag
));
} else {
output.push_str(&format!(" (Some(start), Some(end)) => self.accessor.iter_repeated_range({}, start, end),\n", tag));
output.push_str(&format!(
" _ => self.accessor.iter_repeated({}),\n",
tag
));
}
output.push_str(" }\n }\n\n");
} else {
output.push_str(&format!(
" pub fn {}(&self) -> 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
));
}
}
for (oneof_index, oneof_proto) in oneofs.iter().enumerate() {
let oneof_desc =
OneofDescriptorProto::new(*oneof_proto).expect("Failed to parse OneofDescriptorProto");
let oneof_name = oneof_desc.name().unwrap();
let pascal_oneof_name = to_pascal_case(oneof_name);
let snake_oneof_name = to_snake_case(oneof_name);
let return_type = format!("{}::{}<'a>", mod_name, pascal_oneof_name);
let signature = format!(
" pub fn which_{}(&self) -> roto_runtime::Result<Option<{}> > {{\n",
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 {
if *f_oneof_index == Some(oneof_index as i32) {
let safe_field_name = if field_name == "type" {
format!("r#{}", field_name)
} else {
field_name.clone()
};
output.push_str(&format!(
" if self.{}_offset.is_some() {{\n",
field_name
));
output.push_str(&format!(
" return Ok(Some({}::{}::{} (self.{}()?)));\n",
mod_name, pascal_oneof_name, safe_field_name, safe_field_name
));
output.push_str(" }\n");
}
}
output.push_str(" Ok(None)\n }\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");
// Collect builder field info so we can use it multiple times below.
// Tuple: (field_name, safe_name, tag, rust_type, write_method)
let mut builder_fields: Vec<(String, String, u32, String, String)> = Vec::new();
for field_res in msg_proto.field() {
let (field_data, _) = field_res.expect("Failed to iterate field");
let field_proto =
FieldDescriptorProto::new(field_data).expect("Failed to parse FieldDescriptorProto");
let field_name = field_proto.name().unwrap().to_string();
let safe_name = if field_name == "type" {
format!("r#{}", field_name)
} else {
field_name.clone()
};
let tag = field_proto.number().unwrap();
let f_type = field_proto.rype().unwrap() as i32;
let (rust_type, method) = map_type_to_rust_builder(f_type);
builder_fields.push((field_name, safe_name, tag as u32, rust_type, method));
}
// Builder struct — one `_written: bool` flag per field
output.push_str(&format!("pub struct {}Builder<'b> {{\n", msg_name));
output.push_str(" builder: roto_runtime::ProtoBuilder<'b>,\n");
for (field_name, _, _, _, _) in &builder_fields {
output.push_str(&format!(" {}_written: bool,\n", field_name));
}
output.push_str(&format!("}}\n\nimpl<'b> {}Builder<'b> {{\n", msg_name));
// Constructor — initialise every flag to false
output.push_str(&format!(
" pub fn builder(buf: &mut [u8]) -> {}Builder<'_> {{\n {}Builder {{\n",
msg_name, msg_name
));
output.push_str(" builder: roto_runtime::ProtoBuilder::new(buf),\n");
for (field_name, _, _, _, _) in &builder_fields {
output.push_str(&format!(" {}_written: false,\n", field_name));
}
output.push_str(" }\n }\n\n");
// Per-field setters — mark field as written
for (field_name, safe_name, tag, rust_type, method) in &builder_fields {
output.push_str(&format!(
" pub fn {}(mut self, value: {}) -> 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
output.push_str(&format!(
" pub fn with(mut self, msg: &{}<'_>) -> roto_runtime::Result<Self> {{\n",
msg_name
));
output.push_str(" for item in msg.accessor.raw_fields() {\n");
output.push_str(" let (field_number, raw_bytes) = item?;\n");
output.push_str(" let is_written = match field_number {\n");
for (field_name, _, tag, _, _) in &builder_fields {
output.push_str(&format!(
" {} => self.{}_written,\n",
tag, field_name
));
}
output.push_str(" _ => false,\n");
output.push_str(" };\n");
output.push_str(" if !is_written {\n");
output.push_str(" self.builder.write_raw(raw_bytes)?;\n");
output.push_str(" }\n");
output.push_str(" }\n");
output.push_str(" Ok(self)\n");
output.push_str(" }\n\n");
output.push_str(&format!(" pub fn finish(self) -> 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");
output.push_str(&format!(
impl roto_runtime::RotoOwned for Owned{} {{\n",
msg_name
));
output.push_str(&format!(" type Reader<'a> = {}<'a>;\n", msg_name));
output.push_str(&format!(" fn reader(&self) -> {}<'_> {{\n", msg_name));
output.push_str(&format!(
" {}::new(&self.data).expect(\"failed to create reader\")\n",
msg_name
));
output.push_str(" }\n");
output.push_str("}\n\n");
output.push_str(&format!(
impl roto_runtime::RotoMessage for Owned{} {{\n",
msg_name
));
output.push_str(" fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {\n");
output.push_str(&format!(" Ok(Owned{} {{ data: buf }})\n", msg_name));
output.push_str(" }\n\n");
output.push_str(" fn bytes(&self) -> bytes::Bytes {\n");
output.push_str(" self.data.clone()\n");
output.push_str(" }\n");
output.push_str("}\n\n");
let mut nested_enums = Vec::new();
for e_res in msg_proto.enum_type() {
if let Ok((e, _)) = e_res {
nested_enums.push(e);
}
}
let mut nested_msgs = Vec::new();
for m_res in msg_proto.nested_type() {
if let Ok((m, _)) = m_res {
nested_msgs.push(m);
}
}
if !nested_enums.is_empty() || !nested_msgs.is_empty() || !oneofs.is_empty() {
let mod_name = to_snake_case(msg_proto.name().unwrap());
output.push_str(&format!("pub mod {} {{\n", mod_name));
for e_data in &nested_enums {
write_enum(
&EnumDescriptorProto::new(e_data)
.expect("Failed to parse nested EnumDescriptorProto"),
output,
);
}
for m_data in &nested_msgs {
write_message(
&DescriptorProto::new(m_data).expect("Failed to parse nested DescriptorProto"),
output,
);
}
for (oneof_index, oneof_proto) in oneofs.iter().enumerate() {
let oneof_desc = OneofDescriptorProto::new(*oneof_proto)
.expect("Failed to parse OneofDescriptorProto");
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 {
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" {
format!("r#{}", field_name)
} else {
field_name.clone()
};
output.push_str(&format!(" {}({}),\n", safe_field_name, rust_type));
}
}
output.push_str("}\n\n");
}
}
if !nested_enums.is_empty() || !nested_msgs.is_empty() || !oneofs.is_empty() {
output.push_str("}\n\n");
}
}
pub fn generate_protobuf_code(
set: &FileDescriptorSet,
files_to_generate: Option<&[String]>,
generate_mod_files: bool,
) -> Vec<(String, String)> {
generate_files_common(
set,
files_to_generate,
generate_mod_files,
DATA_IMPORTS,
|file_proto, output| {
// Enums
for enum_res in file_proto.enum_type() {
let (enum_data, _) = enum_res.expect("Failed to iterate enum");
write_enum(
&EnumDescriptorProto::new(enum_data)
.expect("Failed to parse EnumDescriptorProto"),
output,
);
}
// Messages
for msg_res in file_proto.message_type() {
let (msg_data, _) = msg_res.expect("Failed to iterate message");
write_message(
&DescriptorProto::new(msg_data).expect("Failed to parse DescriptorProto"),
output,
);
}
},
)
}
@@ -1,13 +1,25 @@
use crate::google::protobuf::descriptor::{ use crate::google::protobuf::descriptor::{
DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, FileDescriptorProto, DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, FileDescriptorProto,
FileDescriptorSet, MessageOptions, MethodDescriptorProto, OneofDescriptorProto, ServiceDescriptorProto, FileDescriptorSet, MessageOptions, MethodDescriptorProto, OneofDescriptorProto,
ServiceDescriptorProto,
}; };
use roto_runtime::ProtoAccessor; use crate::runtime::ProtoAccessor;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::str; use std::str;
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"; 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";
const SERVICE_IMPORTS: &str = "use tonic::{Request, Response, Status};\nuse tokio_stream::Stream;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse std::future::Future;\nuse tonic::body::BoxBody;\nuse tower::Service;\nuse futures_util::StreamExt;\nuse http_body_util::BodyExt;\nuse http_body::Body;\nuse crate::{BufferPool, StatusBody};\n"; const SERVICE_IMPORTS: &str = "use tonic::{Request, Response, Status};\n\
use tokio_stream::Stream;\n\
use std::pin::Pin;\n\
use std::sync::Arc;\n\
use std::task::{Context, Poll};\n\
use std::future::Future;\n\
use tonic::body::BoxBody;\n\
use tower::Service;\n\
use futures_util::StreamExt;\n\
use http_body_util::BodyExt;\n\
use http_body::Body;\n\
use crate::{BufferPool, StatusBody};\n";
pub fn to_pascal_case(s: &str) -> String { pub fn to_pascal_case(s: &str) -> String {
s.split('_') s.split('_')
@@ -36,7 +48,11 @@ pub fn to_snake_case(s: &str) -> String {
result result
} }
fn map_type_to_rust_accessor(field_type: i32, label: i32, is_map: bool) -> (String, String, String) { fn map_type_to_rust_accessor(
field_type: i32,
label: i32,
is_map: bool,
) -> (String, String, String) {
if label == 3 { if label == 3 {
// LABEL_REPEATED // LABEL_REPEATED
let iterator_type = if is_map { let iterator_type = if is_map {
@@ -54,7 +70,7 @@ fn map_type_to_rust_accessor(field_type: i32, label: i32, is_map: bool) -> (Stri
match field_type { match field_type {
9 => ( 9 => (
"&'a str".to_string(), "&'a str".to_string(),
"std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(), "core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"\"\"".to_string(), "\"\"".to_string(),
), // TYPE_STRING ), // TYPE_STRING
1 => ( 1 => (
@@ -123,7 +139,7 @@ fn write_enum(enum_proto: &EnumDescriptorProto, output: &mut String) {
let name = std::str::from_utf8(name_bytes).expect("Enum value name invalid utf8"); let name = std::str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing"); let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
let (num, _) = let (num, _) =
roto_runtime::read_varint(num_bytes).expect("Enum value number invalid varint"); crate::runtime::read_varint(num_bytes).expect("Enum value number invalid varint");
let pascal_name = to_pascal_case(name); let pascal_name = to_pascal_case(name);
if num == 0 { if num == 0 {
@@ -153,7 +169,7 @@ fn write_enum(enum_proto: &EnumDescriptorProto, output: &mut String) {
let name = std::str::from_utf8(name_bytes).expect("Enum value name invalid utf8"); let name = std::str::from_utf8(name_bytes).expect("Enum value name invalid utf8");
let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing"); let (num_bytes, _) = accessor.get_value(2).expect("Enum value number missing");
let (num, _) = let (num, _) =
roto_runtime::read_varint(num_bytes).expect("Enum value number invalid varint"); crate::runtime::read_varint(num_bytes).expect("Enum value number invalid varint");
output.push_str(&format!( output.push_str(&format!(
" {} => {}::{},\n", " {} => {}::{},\n",
@@ -440,18 +456,30 @@ 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"));
output.push_str(&format!("#[cfg(feature = \"alloc\")]\npub 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");
output.push_str(&format!("#[cfg(feature = \"alloc\")]\nimpl roto_runtime::RotoOwned for Owned{} {{\n", msg_name)); output.push_str(&format!(
"impl roto_runtime::RotoOwned for Owned{} {{\n",
msg_name
));
output.push_str(&format!(" type Reader<'a> = {}<'a>;\n", msg_name)); output.push_str(&format!(" type Reader<'a> = {}<'a>;\n", msg_name));
output.push_str(&format!(" fn reader(&self) -> {}<'_> {{\n", msg_name)); output.push_str(&format!(" fn reader(&self) -> {}<'_> {{\n", msg_name));
output.push_str(&format!(" {}::new(&self.data).expect(\"failed to create reader\")\n", msg_name)); output.push_str(&format!(
" {}::new(&self.data).expect(\"failed to create reader\")\n",
msg_name
));
output.push_str(" }\n"); output.push_str(" }\n");
output.push_str("}\n\n"); output.push_str("}\n\n");
output.push_str(&format!("#[cfg(feature = \"alloc\")]\nimpl roto_runtime::RotoMessage for Owned{} {{\n", msg_name)); output.push_str(&format!(
"impl roto_runtime::RotoMessage for Owned{} {{\n",
msg_name
));
output.push_str(" fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {\n"); output.push_str(" fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {\n");
output.push_str(&format!(" Ok(Owned{} {{ data: buf }})\n", msg_name)); output.push_str(&format!(" Ok(Owned{} {{ data: buf }})\n", msg_name));
output.push_str(" }\n\n"); output.push_str(" }\n\n");
@@ -551,11 +579,18 @@ where
} }
} }
let rust_file_name = format!("{}.rs", std::path::Path::new(proto_name).file_stem().unwrap().to_str().unwrap()); let rust_file_name = format!(
"{}.rs",
std::path::Path::new(proto_name)
.file_stem()
.unwrap()
.to_str()
.unwrap()
);
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\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() {
@@ -600,10 +635,12 @@ where
} }
let mut root_mod_content = String::new(); let mut root_mod_content = String::new();
root_mod_content.push_str("// @generated by protoc-gen-roto — do not edit\n");
root_mod_content.push_str("#![allow(unused_imports)]\n\n");
let mut sorted_root_mods: Vec<_> = root_mods.into_iter().collect(); let mut sorted_root_mods: Vec<_> = root_mods.into_iter().collect();
sorted_root_mods.sort(); sorted_root_mods.sort();
if sorted_root_mods.is_empty() {
root_mod_content.push_str("// @generated by protoc-gen-roto — do not edit\n");
root_mod_content.push_str("#![allow(unused_imports)]\n\n");
}
for m in sorted_root_mods { for m in sorted_root_mods {
root_mod_content.push_str(&format!("pub mod {};\n", m)); root_mod_content.push_str(&format!("pub mod {};\n", m));
} }
@@ -611,6 +648,9 @@ where
for (mod_path, sub_mods) in mod_files { for (mod_path, sub_mods) in mod_files {
let mut content = String::new(); let mut content = String::new();
if sub_mods.is_empty() {
continue;
}
content.push_str("// @generated by protoc-gen-roto — do not edit\n"); content.push_str("// @generated by protoc-gen-roto — do not edit\n");
content.push_str("#![allow(unused_imports)]\n\n"); content.push_str("#![allow(unused_imports)]\n\n");
let mut sorted_subs: Vec<_> = sub_mods.into_iter().collect(); let mut sorted_subs: Vec<_> = sub_mods.into_iter().collect();
@@ -639,7 +679,8 @@ pub fn generate_protobuf_code(
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");
write_enum( write_enum(
&EnumDescriptorProto::new(enum_data).expect("Failed to parse EnumDescriptorProto"), &EnumDescriptorProto::new(enum_data)
.expect("Failed to parse EnumDescriptorProto"),
output, output,
); );
} }
@@ -665,14 +706,15 @@ pub fn generate_service_code(
set, set,
files_to_generate, files_to_generate,
generate_mod_files, generate_mod_files,
SERVICE_IMPORTS, "",
|file_proto, output| { |file_proto, output| {
let package = file_proto.package().unwrap_or("").to_string(); let package = file_proto.package().unwrap_or("").to_string();
// Services // Services
for svc_res in file_proto.service() { for svc_res in file_proto.service() {
let (svc_data, _) = svc_res.expect("Failed to iterate service"); let (svc_data, _) = svc_res.expect("Failed to iterate service");
write_service( write_service(
&ServiceDescriptorProto::new(svc_data).expect("Failed to parse ServiceDescriptorProto"), &ServiceDescriptorProto::new(svc_data)
.expect("Failed to parse ServiceDescriptorProto"),
&package, &package,
output, output,
); );
@@ -709,13 +751,7 @@ pub fn generate_rust_code(
result.sort_by(|a, b| a.0.cmp(&b.0)); result.sort_by(|a, b| a.0.cmp(&b.0));
if generate_mod_files { if generate_mod_files {
let mods = generate_files_common( let mods = generate_files_common(set, files_to_generate, true, "", |_, _| {});
set,
files_to_generate,
true,
"",
|_, _| {},
);
for (filename, content) in mods { for (filename, content) in mods {
if filename == "mod.rs" || filename.contains("/mod.rs") { if filename == "mod.rs" || filename.contains("/mod.rs") {
result.push((filename, content)); result.push((filename, content));
@@ -727,25 +763,81 @@ pub fn generate_rust_code(
} }
fn strip_boilerplate(content: &str) -> String { fn strip_boilerplate(content: &str) -> String {
// Find the first occurrence of a service definition or a trait let mut stripped = content;
// In our case, the services start after the dependency imports and a newline. let header = "// @generated by protoc-gen-roto — do not edit\n";
if let Some(idx) = content.find("pub trait ") { if stripped.starts_with(header) {
return content[idx..].to_string(); stripped = &stripped[header.len()..];
let patterns = [
"#[allow(unused_imports)]\n",
"#![allow(unused_imports)]\n\n",
"#![allow(unused_imports)]\n",
];
for pattern in patterns {
if stripped.starts_with(pattern) {
stripped = &stripped[pattern.len()..];
break;
} }
if let Some(idx) = content.find("pub struct ") {
// This might be a message, but generate_service_code only generates services (and their server structs)
return content[idx..].to_string();
} }
content.to_string() }
stripped.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strip_boilerplate_standard() {
let content = "// @generated by protoc-gen-roto — do not edit\n#[allow(unused_imports)]\nuse std::str;\n";
let stripped = strip_boilerplate(content);
assert_eq!(stripped, "use std::str;\n");
}
#[test]
fn test_strip_boilerplate_crate_level() {
let content = "// @generated by protoc-gen-roto — do not edit\n#![allow(unused_imports)]\n\nuse std::str;\n";
let stripped = strip_boilerplate(content);
assert_eq!(stripped, "use std::str;\n");
}
#[test]
fn test_strip_boilerplate_crate_level_single_newline() {
let content = "// @generated by protoc-gen-roto — do not edit\n#![allow(unused_imports)]\nuse std::str;\n";
let stripped = strip_boilerplate(content);
assert_eq!(stripped, "use std::str;\n");
}
#[test]
fn test_strip_boilerplate_no_boilerplate() {
let content = "use std::str;\n";
let stripped = strip_boilerplate(content);
assert_eq!(stripped, "use std::str;\n");
}
#[test]
fn test_strip_boilerplate_only_header() {
let content = "// @generated by protoc-gen-roto — do not edit\n";
let stripped = strip_boilerplate(content);
assert_eq!(stripped, "");
}
} }
fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut String) { fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut String) {
output.push_str(SERVICE_IMPORTS);
output.push_str("\n");
let svc_name = to_pascal_case(svc_proto.name().unwrap()); let svc_name = to_pascal_case(svc_proto.name().unwrap());
output.push_str(&format!("#[tonic::async_trait]\npub trait {}: Send + Sync + 'static {{\n", svc_name));
output.push_str(&format!(
"#[async_trait::async_trait]\npub trait {}: Send + Sync + 'static {{\n",
svc_name
));
for method_res in svc_proto.method() { for method_res in svc_proto.method() {
let (method_data, _) = method_res.expect("Failed to iterate method"); let (method_data, _) = method_res.expect("Failed to iterate method");
let method_proto = MethodDescriptorProto::new(method_data).expect("Failed to parse MethodDescriptorProto"); let method_proto =
MethodDescriptorProto::new(method_data).expect("Failed to parse MethodDescriptorProto");
let method_name = to_snake_case(method_proto.name().unwrap()); let method_name = to_snake_case(method_proto.name().unwrap());
let input_full_name = method_proto.input_type().unwrap(); let input_full_name = method_proto.input_type().unwrap();
@@ -767,7 +859,10 @@ fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut
}; };
let resp_type = if server_streaming { let resp_type = if server_streaming {
format!("Response<Pin<Box<dyn Stream<Item = std::result::Result<{}, Status>> + Send>>>", output_owned) format!(
"Response<Pin<Box<dyn Stream<Item = std::result::Result<{}, Status>> + Send>>>",
output_owned
)
} else { } else {
format!("Response<{}>", output_owned) format!("Response<{}>", output_owned)
}; };
@@ -780,27 +875,46 @@ fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut
output.push_str("}\n\n"); output.push_str("}\n\n");
let server_name = format!("{}Server", svc_name); let server_name = format!("{}Server", svc_name);
output.push_str(&format!("#[derive(Clone)]\npub struct {} {{\n", server_name));
output.push_str(&format!(
"#[derive(Clone)]\npub struct {} {{\n",
server_name
));
output.push_str(&format!(" inner: Arc<dyn {}>,\n", svc_name)); output.push_str(&format!(" inner: Arc<dyn {}>,\n", svc_name));
output.push_str(" pool: Arc<BufferPool>,\n"); output.push_str(" pool: Arc<BufferPool>,\n");
output.push_str("}\n\n"); output.push_str("}\n\n");
output.push_str(&format!("impl {} {{\n", server_name)); output.push_str(&format!("impl {} {{\n", server_name));
output.push_str(&format!(" pub fn new(inner: Arc<dyn {}>, pool: Arc<BufferPool>) -> Self {{\n", svc_name)); output.push_str(&format!(
" pub fn new(inner: Arc<dyn {}>, pool: Arc<BufferPool>) -> Self {{\n",
svc_name
));
output.push_str(" Self { inner, pool }\n"); output.push_str(" Self { inner, pool }\n");
output.push_str(" }\n"); output.push_str(" }\n");
output.push_str("}\n\n"); output.push_str("}\n\n");
output.push_str(&format!("impl tonic::server::NamedService for {} {{\n", server_name));
output.push_str(&format!(
"impl tonic::server::NamedService for {} {{\n",
server_name
));
let full_svc_name = if package.is_empty() { let full_svc_name = if package.is_empty() {
svc_proto.name().unwrap().to_string() svc_proto.name().unwrap().to_string()
} else { } else {
format!("{}.{}", package, svc_proto.name().unwrap()) format!("{}.{}", package, svc_proto.name().unwrap())
}; };
output.push_str(&format!(" const NAME: &'static str = \"{}\";\n", full_svc_name)); output.push_str(&format!(
" const NAME: &'static str = \"{}\";\n",
full_svc_name
));
output.push_str("}\n\n"); output.push_str("}\n\n");
output.push_str(&format!("impl Service<http::Request<BoxBody>> for {} {{\n", server_name));
output.push_str(&format!(
"impl Service<http::Request<BoxBody>> for {} {{\n",
server_name
));
output.push_str(" type Response = http::Response<BoxBody>;\n"); output.push_str(" type Response = http::Response<BoxBody>;\n");
output.push_str(" type Error = std::convert::Infallible;\n"); output.push_str(" type Error = std::convert::Infallible;\n");
output.push_str(" type Future = Pin<Box<dyn Future<Output = std::result::Result<Self::Response, Self::Error>> + Send>>;\n\n"); output.push_str(" type Future = Pin<Box<dyn Future<Output = std::result::Result<Self::Response, Self::Error>> + Send>>;\n\n");
@@ -837,14 +951,20 @@ fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut
let mut methods = Vec::new(); let mut methods = Vec::new();
for method_res in svc_proto.method() { for method_res in svc_proto.method() {
let (method_data, _) = method_res.expect("Failed to iterate method"); let (method_data, _) = method_res.expect("Failed to iterate method");
let method_proto = MethodDescriptorProto::new(method_data).expect("Failed to parse MethodDescriptorProto"); let method_proto =
MethodDescriptorProto::new(method_data).expect("Failed to parse MethodDescriptorProto");
let original_method_name = method_proto.name().unwrap().to_string(); let original_method_name = method_proto.name().unwrap().to_string();
let method_name = to_snake_case(&original_method_name); let method_name = to_snake_case(&original_method_name);
let input_full_name = method_proto.input_type().unwrap(); let input_full_name = method_proto.input_type().unwrap();
let input_type = input_full_name.split('.').last().unwrap(); let input_type = input_full_name.split('.').last().unwrap();
let input_owned = format!("Owned{}", input_type); let input_owned = format!("Owned{}", input_type);
let server_streaming = method_proto.server_streaming().unwrap_or(false); let server_streaming = method_proto.server_streaming().unwrap_or(false);
methods.push((original_method_name, method_name, input_owned, server_streaming)); methods.push((
original_method_name,
method_name,
input_owned,
server_streaming,
));
} }
for (original_method_name, method_name, input_owned, server_streaming) in methods { for (original_method_name, method_name, input_owned, server_streaming) in methods {
@@ -854,7 +974,12 @@ fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut
let full_path = if package.is_empty() { let full_path = if package.is_empty() {
format!("/{}/{}", svc_proto.name().unwrap(), original_method_name) format!("/{}/{}", svc_proto.name().unwrap(), original_method_name)
} else { } else {
format!("/{}.{}/{}", package, svc_proto.name().unwrap(), original_method_name) format!(
"/{}.{}/{}",
package,
svc_proto.name().unwrap(),
original_method_name
)
}; };
output.push_str(&format!(" if path == \"{}\" {{\n", full_path)); output.push_str(&format!(" if path == \"{}\" {{\n", full_path));
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n"); output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
@@ -865,17 +990,28 @@ fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut
let full_path = if package.is_empty() { let full_path = if package.is_empty() {
format!("/{}/{}", svc_proto.name().unwrap(), original_method_name) format!("/{}/{}", svc_proto.name().unwrap(), original_method_name)
} else { } else {
format!("/{}.{}/{}", package, svc_proto.name().unwrap(), original_method_name) format!(
"/{}.{}/{}",
package,
svc_proto.name().unwrap(),
original_method_name
)
}; };
output.push_str(&format!(" if path == \"{}\" {{\n", full_path)); output.push_str(&format!(" if path == \"{}\" {{\n", full_path));
output.push_str(&format!(" let request_msg = match {}::decode(payload) {{\n", input_owned)); output.push_str(&format!(
" let request_msg = match {}::decode(payload) {{\n",
input_owned
));
output.push_str(" Ok(msg) => msg,\n"); output.push_str(" Ok(msg) => msg,\n");
output.push_str(" Err(e) => {\n"); output.push_str(" Err(e) => {\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n"); output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n"); output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n");
output.push_str(" }\n"); output.push_str(" }\n");
output.push_str(" };\n\n"); output.push_str(" };\n\n");
output.push_str(&format!(" let response = match inner.{}(Request::new(request_msg)).await {{\n", method_name)); output.push_str(&format!(
" let response = match inner.{}(Request::new(request_msg)).await {{\n",
method_name
));
output.push_str(" Ok(res) => res,\n"); output.push_str(" Ok(res) => res,\n");
output.push_str(" Err(e) => {\n"); output.push_str(" Err(e) => {\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n"); output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
@@ -892,7 +1028,9 @@ fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut
output.push_str(" let frame_len = res_buf.len();\n"); output.push_str(" let frame_len = res_buf.len();\n");
output.push_str(" let frame = res_buf.split_to(frame_len).freeze();\n"); output.push_str(" let frame = res_buf.split_to(frame_len).freeze();\n");
output.push_str(" pool.put(res_buf);\n"); output.push_str(" pool.put(res_buf);\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(frame), 0));\n"); output.push_str(
" let res_body = BoxBody::new(StatusBody::new(Some(frame), 0));\n",
);
output.push_str(" routed = true;\n"); output.push_str(" routed = true;\n");
output.push_str(" return Ok(http::Response::builder().status(200).header(\"content-type\", \"application/grpc\").body(res_body).unwrap());\n"); output.push_str(" return Ok(http::Response::builder().status(200).header(\"content-type\", \"application/grpc\").body(res_body).unwrap());\n");
output.push_str(" }\n"); output.push_str(" }\n");
+258
View File
@@ -0,0 +1,258 @@
use crate::google::protobuf::descriptor::{ServiceDescriptorProto, MethodDescriptorProto};
use crate::google::protobuf::descriptor::FileDescriptorSet;
use crate::generator::generate_files_common;
use crate::generator::SERVICE_IMPORTS;
use crate::generator::utils::{to_pascal_case, to_snake_case};
pub fn generate_service_code(
set: &FileDescriptorSet,
files_to_generate: Option<&[String]>,
generate_mod_files: bool,
) -> Vec<(String, String)> {
generate_files_common(
set,
files_to_generate,
generate_mod_files,
"",
|file_proto, output| {
let package = file_proto.package().unwrap_or("").to_string();
// Services
for svc_res in file_proto.service() {
let (svc_data, _) = svc_res.expect("Failed to iterate service");
write_service(
&ServiceDescriptorProto::new(svc_data)
.expect("Failed to parse ServiceDescriptorProto"),
&package,
output,
);
}
},
)
}
pub fn write_service(svc_proto: &ServiceDescriptorProto, package: &str, output: &mut String) {
output.push_str(SERVICE_IMPORTS);
output.push_str("\n");
let svc_name = to_pascal_case(svc_proto.name().unwrap());
output.push_str(&format!(
"#[async_trait::async_trait]\npub trait {}: Send + Sync + 'static {{\n",
svc_name
));
for method_res in svc_proto.method() {
let (method_data, _) = method_res.expect("Failed to iterate method");
let method_proto =
MethodDescriptorProto::new(method_data).expect("Failed to parse MethodDescriptorProto");
let method_name = to_snake_case(method_proto.name().unwrap());
let input_full_name = method_proto.input_type().unwrap();
let output_full_name = method_proto.output_type().unwrap();
let input_type = input_full_name.split('.').last().unwrap();
let output_type = output_full_name.split('.').last().unwrap();
let input_owned = format!("Owned{}", input_type);
let output_owned = format!("Owned{}", output_type);
let client_streaming = method_proto.client_streaming().unwrap_or(false);
let server_streaming = method_proto.server_streaming().unwrap_or(false);
let req_type = if client_streaming {
format!("Request<tonic::Streaming<{}>>", input_owned)
} else {
format!("Request<{}>", input_owned)
};
let resp_type = if server_streaming {
format!(
"Response<Pin<Box<dyn Stream<Item = std::result::Result<{}, Status>> + Send>>>",
output_owned
)
} else {
format!("Response<{}>", output_owned)
};
output.push_str(&format!(
" async fn {}(&self, request: {}) -> std::result::Result<{}, Status>;\n",
method_name, req_type, resp_type
));
}
output.push_str("}\n\n");
let server_name = format!("{}Server", svc_name);
output.push_str(&format!(
"#[derive(Clone)]\npub struct {} {{\n",
server_name
));
output.push_str(&format!(" inner: Arc<dyn {}>,\n", svc_name));
output.push_str(" pool: Arc<BufferPool>,\n");
output.push_str("}\n\n");
output.push_str(&format!("impl {} {{\n", server_name));
output.push_str(&format!(
" pub fn new(inner: Arc<dyn {}>, pool: Arc<BufferPool>) -> Self {{\n",
svc_name
));
output.push_str(" Self { inner, pool }\n");
output.push_str(" }\n");
output.push_str("}\n\n");
output.push_str(&format!(
"impl tonic::server::NamedService for {} {{\n",
server_name
));
let full_svc_name = if package.is_empty() {
svc_proto.name().unwrap().to_string()
} else {
format!("{}.{}", package, svc_proto.name().unwrap())
};
output.push_str(&format!(
" const NAME: &'static str = \"{}\";\n",
full_svc_name
));
output.push_str("}\n\n");
output.push_str(&format!(
"impl Service<http::Request<BoxBody>> for {} {{\n",
server_name
));
output.push_str(" type Response = http::Response<BoxBody>;\n");
output.push_str(" type Error = std::convert::Infallible;\n");
output.push_str(" type Future = Pin<Box<dyn Future<Output = std::result::Result<Self::Response, Self::Error>> + Send>>;\n\n");
output.push_str(" fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {\n");
output.push_str(" Poll::Ready(Ok(()))\n");
output.push_str(" }\n\n");
output.push_str(" fn call(&mut self, req: http::Request<BoxBody>) -> Self::Future {\n");
output.push_str(" let inner = self.inner.clone();\n");
output.push_str(" let pool = self.pool.clone();\n");
output.push_str(" Box::pin(async move {\n");
output.push_str(" let path = req.uri().path().to_string();\n");
output.push_str(" let body = req.into_body();\n");
output.push_str(" let mut buf = pool.get();\n");
output.push_str(" let mut stream = body;\n");
output.push_str(" while let Some(frame_result) = stream.frame().await {\n");
output.push_str(" let frame = frame_result.expect(\"Body frame error\");\n");
output.push_str(" if let Some(data) = frame.data_ref() {\n");
output.push_str(" buf.put(data.clone());\n");
output.push_str(" }\n");
output.push_str(" }\n\n");
output.push_str(" let total_len = buf.len();\n");
output.push_str(" let bytes_vec = buf.split_to(total_len).freeze();\n");
output.push_str(" pool.put(buf);\n");
output.push_str(" if bytes_vec.len() < 5 {\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n");
output.push_str(" }\n\n");
output.push_str(" let payload = bytes_vec.slice(5..);\n");
output.push_str(" let mut routed = false;\n\n");
let mut methods = Vec::new();
for method_res in svc_proto.method() {
let (method_data, _) = method_res.expect("Failed to iterate method");
let method_proto =
MethodDescriptorProto::new(method_data).expect("Failed to parse MethodDescriptorProto");
let original_method_name = method_proto.name().unwrap().to_string();
let method_name = to_snake_case(&original_method_name);
let input_full_name = method_proto.input_type().unwrap();
let input_type = input_full_name.split('.').last().unwrap();
let input_owned = format!("Owned{}", input_type);
let server_streaming = method_proto.server_streaming().unwrap_or(false);
methods.push((
original_method_name,
method_name,
input_owned,
server_streaming,
));
}
for (original_method_name, method_name, input_owned, server_streaming) in methods {
if server_streaming {
// For streaming RPCs, we don't implement the server logic yet.
// We just make it compile by returning a "not implemented" response.
let full_path = if package.is_empty() {
format!("/{}/{}", svc_proto.name().unwrap(), original_method_name)
} else {
format!(
"/{}.{}/{}",
package,
svc_proto.name().unwrap(),
original_method_name
)
};
output.push_str(&format!(" if path == \"{}\" {{\n", full_path));
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n");
output.push_str(" }\n");
continue;
}
let full_path = if package.is_empty() {
format!("/{}/{}", svc_proto.name().unwrap(), original_method_name)
} else {
format!(
"/{}.{}/{}",
package,
svc_proto.name().unwrap(),
original_method_name
)
};
output.push_str(&format!(" if path == \"{}\" {{\n", full_path));
output.push_str(&format!(
" let request_msg = match {}::decode(payload) {{\n",
input_owned
));
output.push_str(" Ok(msg) => msg,\n");
output.push_str(" Err(e) => {\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n");
output.push_str(" }\n");
output.push_str(" };\n\n");
output.push_str(&format!(
" let response = match inner.{}(Request::new(request_msg)).await {{\n",
method_name
));
output.push_str(" Ok(res) => res,\n");
output.push_str(" Err(e) => {\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n");
output.push_str(" }\n");
output.push_str(" };\n\n");
output.push_str(" let response_msg = response.into_inner();\n");
output.push_str(" let response_bytes = response_msg.bytes();\n");
output.push_str(" let mut res_buf = pool.get();\n");
output.push_str(" res_buf.put_u8(0);\n");
output.push_str(" let len = response_bytes.len() as u32;\n");
output.push_str(" res_buf.put_slice(&len.to_be_bytes());\n");
output.push_str(" res_buf.put_slice(&response_bytes);\n");
output.push_str(" let frame_len = res_buf.len();\n");
output.push_str(" let frame = res_buf.split_to(frame_len).freeze();\n");
output.push_str(" pool.put(res_buf);\n");
output.push_str(
" let res_body = BoxBody::new(StatusBody::new(Some(frame), 0));\n",
);
output.push_str(" routed = true;\n");
output.push_str(" return Ok(http::Response::builder().status(200).header(\"content-type\", \"application/grpc\").body(res_body).unwrap());\n");
output.push_str(" }\n");
}
output.push_str(" if !routed {\n");
output.push_str(" let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0));\n");
output.push_str(" return Ok(http::Response::builder().status(200).body(res_body).unwrap());\n");
output.push_str(" }\n");
output.push_str(" Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody::new(None, 0))).unwrap())\n");
output.push_str(" })\n");
output.push_str(" }\n");
output.push_str("}\n");
}
+151
View File
@@ -0,0 +1,151 @@
use crate::google::protobuf::descriptor::FieldDescriptorProto;
use crate::google::protobuf::descriptor::DescriptorProto;
pub fn map_type_to_rust_accessor(
field_type: i32,
label: i32,
is_map: bool,
) -> (String, String, String) {
if label == 3 {
// LABEL_REPEATED
let iterator_type = if is_map {
"roto_runtime::MapFieldIterator<'a>"
} else {
"roto_runtime::RepeatedFieldIterator<'a>"
};
return (
iterator_type.to_string(),
"".to_string(), // Not used for repeated fields in the same way
"".to_string(), // Not used for repeated fields
);
}
match field_type {
9 => (
"&'a str".to_string(),
"core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"\"\"".to_string(),
), // TYPE_STRING
1 => (
"f64".to_string(),
"Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?))".to_string(),
"0.0".to_string(),
), // TYPE_DOUBLE
2 => (
"f32".to_string(),
"Ok(f32::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?))".to_string(),
"0.0".to_string(),
), // TYPE_FLOAT
3 | 5 | 15 | 17 => (
"i32".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // INT/SINT/SFIXED 32
4 | 6 | 13 => (
"u32".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // UINT/FIXED 32
16 | 18 => (
"i64".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as i64).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // SINT/SFIXED 64
7 | 14 => (
"u64".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // UINT/FIXED 64
8 => (
"bool".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"false".to_string(),
), // TYPE_BOOL
11 | 12 => (
"&'a [u8]".to_string(),
"Ok(bytes)".to_string(),
"&[]".to_string(),
), // MESSAGE/BYTES
_ => (
"&'a [u8]".to_string(),
"Ok(bytes)".to_string(),
"&[]".to_string(),
),
}
}
EOF > /opt/workspace/codegen/src/generator/types.rs
use crate::google::protobuf::descriptor::FieldDescriptorProto;
use crate::google::protobuf::descriptor::DescriptorProto;
pub fn map_type_to_rust_accessor(
field_type: i32,
label: i32,
is_map: bool,
) -> (String, String, String) {
if label == 3 {
// LABEL_REPEATED
let iterator_type = if is_map {
"roto_runtime::MapFieldIterator<'a>"
} else {
"roto_runtime::RepeatedFieldIterator<'a>"
};
return (
iterator_type.to_string(),
"".to_string(), // Not used for repeated fields in the same way
"".to_string(), // Not used for repeated fields
);
}
match field_type {
9 => (
"&'a str".to_string(),
"core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"\"\"".to_string(),
), // TYPE_STRING
1 => (
"f64".to_string(),
"Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?))".to_string(),
"0.0".to_string(),
), // TYPE_DOUBLE
2 => (
"f32".to_string(),
"Ok(f32::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?))".to_string(),
"0.0".to_string(),
), // TYPE_FLOAT
3 | 5 | 15 | 17 => (
"i32".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // INT/SINT/SFIXED 32
4 | 6 | 13 => (
"u32".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // UINT/FIXED 32
16 | 18 => (
"i64".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as i64).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // SINT/SFIXED 64
7 | 14 => (
"u64".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"0".to_string(),
), // UINT/FIXED 64
8 => (
"bool".to_string(),
"roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation)".to_string(),
"false".to_string(),
), // TYPE_BOOL
11 | 12 => (
"&'a [u8]".to_string(),
"Ok(bytes)".to_string(),
"&[]".to_string(),
), // MESSAGE/BYTES
_ => (
"&'a [u8]".to_string(),
"Ok(bytes)".to_string(),
"&[]".to_string(),
),
}
}
+32
View File
@@ -0,0 +1,32 @@
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 fn to_pascal_case(s: &str) -> String {
s.split('_')
.map(|word| {
let mut chars = word.chars();
match chars.next() {
None => String::new(),
Some(f) => {
let first = f.to_uppercase().collect::<String>();
let rest = chars.as_str().to_lowercase();
first + &rest
}
}
})
.collect()
}
pub fn to_snake_case(s: &str) -> String {
let mut result = String::new();
for (i, c) in s.chars().enumerate() {
if c.is_uppercase() {
if i > 0 {
result.push('_');
}
result.push(c.to_ascii_lowercase());
} else {
result.push(c);
}
}
result
}
+121 -121
View File
@@ -1,7 +1,7 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#[allow(unused_imports)] #[allow(unused_imports)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator}; use crate::runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator};
use std::str; use std::str;
use bytes::{Bytes, BytesMut, Buf, BufMut}; use bytes::{Bytes, BytesMut, Buf, BufMut};
use tonic::{Request, Response, Status}; use tonic::{Request, Response, Status};
@@ -20,7 +20,7 @@ use roto_tonic::{BufferPool, StatusBody};
use crate::google::protobuf::descriptor; use crate::google::protobuf::descriptor;
pub struct Version<'a> { pub struct Version<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: crate::runtime::ProtoAccessor<'a>,
major_offset: Option<usize>, major_offset: Option<usize>,
minor_offset: Option<usize>, minor_offset: Option<usize>,
patch_offset: Option<usize>, patch_offset: Option<usize>,
@@ -28,8 +28,8 @@ pub struct Version<'a> {
} }
impl<'a> Version<'a> { impl<'a> Version<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> { pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?; let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut major_offset = None; let mut major_offset = None;
let mut minor_offset = None; let mut minor_offset = None;
let mut patch_offset = None; let mut patch_offset = None;
@@ -51,62 +51,62 @@ suffix_offset,
}) })
} }
pub fn major(&self) -> roto_runtime::Result<i32> { pub fn major(&self) -> crate::runtime::Result<i32> {
let offset = self.major_offset.ok_or(roto_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)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_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) -> roto_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) -> roto_runtime::Result<i32> { pub fn minor(&self) -> crate::runtime::Result<i32> {
let offset = self.minor_offset.ok_or(roto_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)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_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) -> roto_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) -> roto_runtime::Result<i32> { pub fn patch(&self) -> crate::runtime::Result<i32> {
let offset = self.patch_offset.ok_or(roto_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)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_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) -> roto_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) -> roto_runtime::Result<&'a str> { pub fn suffix(&self) -> crate::runtime::Result<&'a str> {
let offset = self.suffix_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn suffix_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn suffix_or_default(&self) -> crate::runtime::Result<&'a str> {
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) -> roto_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> {
builder: roto_runtime::ProtoBuilder<'b>, builder: crate::runtime::ProtoBuilder<'b>,
major_written: bool, major_written: bool,
minor_written: bool, minor_written: bool,
patch_written: bool, patch_written: bool,
@@ -116,7 +116,7 @@ pub struct VersionBuilder<'b> {
impl<'b> VersionBuilder<'b> { impl<'b> VersionBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> { pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
VersionBuilder { VersionBuilder {
builder: roto_runtime::ProtoBuilder::new(buf), builder: crate::runtime::ProtoBuilder::new(buf),
major_written: false, major_written: false,
minor_written: false, minor_written: false,
patch_written: false, patch_written: false,
@@ -124,31 +124,31 @@ impl<'b> VersionBuilder<'b> {
} }
} }
pub fn major(mut self, value: i32) -> roto_runtime::Result<Self> { pub fn major(mut self, value: i32) -> crate::runtime::Result<Self> {
self.builder.write_int32(1, value)?; self.builder.write_int32(1, value)?;
self.major_written = true; self.major_written = true;
Ok(self) Ok(self)
} }
pub fn minor(mut self, value: i32) -> roto_runtime::Result<Self> { pub fn minor(mut self, value: i32) -> crate::runtime::Result<Self> {
self.builder.write_int32(2, value)?; self.builder.write_int32(2, value)?;
self.minor_written = true; self.minor_written = true;
Ok(self) Ok(self)
} }
pub fn patch(mut self, value: i32) -> roto_runtime::Result<Self> { pub fn patch(mut self, value: i32) -> crate::runtime::Result<Self> {
self.builder.write_int32(3, value)?; self.builder.write_int32(3, value)?;
self.patch_written = true; self.patch_written = true;
Ok(self) Ok(self)
} }
pub fn suffix(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn suffix(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(4, value)?; self.builder.write_string(4, value)?;
self.suffix_written = true; self.suffix_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &Version<'_>) -> roto_runtime::Result<Self> { pub fn with(mut self, msg: &Version<'_>) -> crate::runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
@@ -165,7 +165,7 @@ impl<'b> VersionBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
@@ -174,15 +174,15 @@ pub struct OwnedVersion {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
impl roto_runtime::RotoOwned for OwnedVersion { impl crate::runtime::RotoOwned for OwnedVersion {
type Reader<'a> = Version<'a>; type Reader<'a> = Version<'a>;
fn reader(&self) -> Version<'_> { fn reader(&self) -> Version<'_> {
Version::new(&self.data).expect("failed to create reader") Version::new(&self.data).expect("failed to create reader")
} }
} }
impl roto_runtime::RotoMessage for OwnedVersion { impl crate::runtime::RotoMessage for OwnedVersion {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedVersion { data: buf }) Ok(OwnedVersion { data: buf })
} }
@@ -192,7 +192,7 @@ impl roto_runtime::RotoMessage for OwnedVersion {
} }
pub struct CodeGeneratorRequest<'a> { pub struct CodeGeneratorRequest<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: crate::runtime::ProtoAccessor<'a>,
file_to_generate_start: Option<usize>, file_to_generate_start: Option<usize>,
file_to_generate_end: Option<usize>, file_to_generate_end: Option<usize>,
parameter_offset: Option<usize>, parameter_offset: Option<usize>,
@@ -204,8 +204,8 @@ pub struct CodeGeneratorRequest<'a> {
} }
impl<'a> CodeGeneratorRequest<'a> { impl<'a> CodeGeneratorRequest<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> { pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?; let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut file_to_generate_start = None; let mut file_to_generate_start = None;
let mut file_to_generate_end = None; let mut file_to_generate_end = None;
let mut parameter_offset = None; let mut parameter_offset = None;
@@ -242,59 +242,59 @@ compiler_version_offset,
}) })
} }
pub fn file_to_generate(&self) -> roto_runtime::RepeatedFieldIterator<'a> { pub fn file_to_generate(&self) -> crate::runtime::RepeatedFieldIterator<'a> {
match (self.file_to_generate_start, self.file_to_generate_end) { match (self.file_to_generate_start, self.file_to_generate_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(1, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(1, start, end),
_ => self.accessor.iter_repeated(1), _ => self.accessor.iter_repeated(1),
} }
} }
pub fn parameter(&self) -> roto_runtime::Result<&'a str> { pub fn parameter(&self) -> crate::runtime::Result<&'a str> {
let offset = self.parameter_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn parameter_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn parameter_or_default(&self) -> crate::runtime::Result<&'a str> {
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) -> roto_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) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
_ => self.accessor.iter_repeated(15), _ => self.accessor.iter_repeated(15),
} }
} }
pub fn source_file_descriptors(&self) -> roto_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) -> roto_runtime::Result<&'a [u8]> { pub fn compiler_version(&self) -> crate::runtime::Result<&'a [u8]> {
let offset = self.compiler_version_offset.ok_or(roto_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)
} }
pub fn compiler_version_or_default(&self) -> roto_runtime::Result<&'a [u8]> { pub fn compiler_version_or_default(&self) -> crate::runtime::Result<&'a [u8]> {
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) -> roto_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> {
builder: roto_runtime::ProtoBuilder<'b>, builder: crate::runtime::ProtoBuilder<'b>,
file_to_generate_written: bool, file_to_generate_written: bool,
parameter_written: bool, parameter_written: bool,
proto_file_written: bool, proto_file_written: bool,
@@ -305,7 +305,7 @@ pub struct CodeGeneratorRequestBuilder<'b> {
impl<'b> CodeGeneratorRequestBuilder<'b> { impl<'b> CodeGeneratorRequestBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> { pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
CodeGeneratorRequestBuilder { CodeGeneratorRequestBuilder {
builder: roto_runtime::ProtoBuilder::new(buf), builder: crate::runtime::ProtoBuilder::new(buf),
file_to_generate_written: false, file_to_generate_written: false,
parameter_written: false, parameter_written: false,
proto_file_written: false, proto_file_written: false,
@@ -314,37 +314,37 @@ impl<'b> CodeGeneratorRequestBuilder<'b> {
} }
} }
pub fn file_to_generate(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn file_to_generate(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(1, value)?; self.builder.write_string(1, value)?;
self.file_to_generate_written = true; self.file_to_generate_written = true;
Ok(self) Ok(self)
} }
pub fn parameter(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn parameter(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(2, value)?; self.builder.write_string(2, value)?;
self.parameter_written = true; self.parameter_written = true;
Ok(self) Ok(self)
} }
pub fn proto_file(mut self, value: &[u8]) -> roto_runtime::Result<Self> { pub fn proto_file(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(15, value)?; self.builder.write_bytes(15, value)?;
self.proto_file_written = true; self.proto_file_written = true;
Ok(self) Ok(self)
} }
pub fn source_file_descriptors(mut self, value: &[u8]) -> roto_runtime::Result<Self> { pub fn source_file_descriptors(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(17, value)?; self.builder.write_bytes(17, value)?;
self.source_file_descriptors_written = true; self.source_file_descriptors_written = true;
Ok(self) Ok(self)
} }
pub fn compiler_version(mut self, value: &[u8]) -> roto_runtime::Result<Self> { pub fn compiler_version(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(3, value)?; self.builder.write_bytes(3, value)?;
self.compiler_version_written = true; self.compiler_version_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &CodeGeneratorRequest<'_>) -> roto_runtime::Result<Self> { pub fn with(mut self, msg: &CodeGeneratorRequest<'_>) -> crate::runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
@@ -362,7 +362,7 @@ impl<'b> CodeGeneratorRequestBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
@@ -371,15 +371,15 @@ pub struct OwnedCodeGeneratorRequest {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
impl roto_runtime::RotoOwned for OwnedCodeGeneratorRequest { impl crate::runtime::RotoOwned for OwnedCodeGeneratorRequest {
type Reader<'a> = CodeGeneratorRequest<'a>; type Reader<'a> = CodeGeneratorRequest<'a>;
fn reader(&self) -> CodeGeneratorRequest<'_> { fn reader(&self) -> CodeGeneratorRequest<'_> {
CodeGeneratorRequest::new(&self.data).expect("failed to create reader") CodeGeneratorRequest::new(&self.data).expect("failed to create reader")
} }
} }
impl roto_runtime::RotoMessage for OwnedCodeGeneratorRequest { impl crate::runtime::RotoMessage for OwnedCodeGeneratorRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedCodeGeneratorRequest { data: buf }) Ok(OwnedCodeGeneratorRequest { data: buf })
} }
@@ -389,7 +389,7 @@ impl roto_runtime::RotoMessage for OwnedCodeGeneratorRequest {
} }
pub struct CodeGeneratorResponse<'a> { pub struct CodeGeneratorResponse<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: crate::runtime::ProtoAccessor<'a>,
error_offset: Option<usize>, error_offset: Option<usize>,
supported_features_offset: Option<usize>, supported_features_offset: Option<usize>,
minimum_edition_offset: Option<usize>, minimum_edition_offset: Option<usize>,
@@ -399,8 +399,8 @@ pub struct CodeGeneratorResponse<'a> {
} }
impl<'a> CodeGeneratorResponse<'a> { impl<'a> CodeGeneratorResponse<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> { pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?; let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut error_offset = None; let mut error_offset = None;
let mut supported_features_offset = None; let mut supported_features_offset = None;
let mut minimum_edition_offset = None; let mut minimum_edition_offset = None;
@@ -429,69 +429,69 @@ file_start, file_end,
}) })
} }
pub fn error(&self) -> roto_runtime::Result<&'a str> { pub fn error(&self) -> crate::runtime::Result<&'a str> {
let offset = self.error_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn error_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn error_or_default(&self) -> crate::runtime::Result<&'a str> {
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) -> roto_runtime::Result<u32> { pub fn supported_features(&self) -> crate::runtime::Result<u32> {
let offset = self.supported_features_offset.ok_or(roto_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)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| roto_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) -> roto_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) -> roto_runtime::Result<i32> { pub fn minimum_edition(&self) -> crate::runtime::Result<i32> {
let offset = self.minimum_edition_offset.ok_or(roto_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)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_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) -> roto_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) -> roto_runtime::Result<i32> { pub fn maximum_edition(&self) -> crate::runtime::Result<i32> {
let offset = self.maximum_edition_offset.ok_or(roto_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)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_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) -> roto_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) -> roto_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) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end), (Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
_ => self.accessor.iter_repeated(15), _ => self.accessor.iter_repeated(15),
} }
} }
pub fn raw_fields(&self) -> roto_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> {
builder: roto_runtime::ProtoBuilder<'b>, builder: crate::runtime::ProtoBuilder<'b>,
error_written: bool, error_written: bool,
supported_features_written: bool, supported_features_written: bool,
minimum_edition_written: bool, minimum_edition_written: bool,
@@ -502,7 +502,7 @@ pub struct CodeGeneratorResponseBuilder<'b> {
impl<'b> CodeGeneratorResponseBuilder<'b> { impl<'b> CodeGeneratorResponseBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> { pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
CodeGeneratorResponseBuilder { CodeGeneratorResponseBuilder {
builder: roto_runtime::ProtoBuilder::new(buf), builder: crate::runtime::ProtoBuilder::new(buf),
error_written: false, error_written: false,
supported_features_written: false, supported_features_written: false,
minimum_edition_written: false, minimum_edition_written: false,
@@ -511,37 +511,37 @@ impl<'b> CodeGeneratorResponseBuilder<'b> {
} }
} }
pub fn error(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn error(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(1, value)?; self.builder.write_string(1, value)?;
self.error_written = true; self.error_written = true;
Ok(self) Ok(self)
} }
pub fn supported_features(mut self, value: u64) -> roto_runtime::Result<Self> { pub fn supported_features(mut self, value: u64) -> crate::runtime::Result<Self> {
self.builder.write_varint(2, value)?; self.builder.write_varint(2, value)?;
self.supported_features_written = true; self.supported_features_written = true;
Ok(self) Ok(self)
} }
pub fn minimum_edition(mut self, value: i32) -> roto_runtime::Result<Self> { pub fn minimum_edition(mut self, value: i32) -> crate::runtime::Result<Self> {
self.builder.write_int32(3, value)?; self.builder.write_int32(3, value)?;
self.minimum_edition_written = true; self.minimum_edition_written = true;
Ok(self) Ok(self)
} }
pub fn maximum_edition(mut self, value: i32) -> roto_runtime::Result<Self> { pub fn maximum_edition(mut self, value: i32) -> crate::runtime::Result<Self> {
self.builder.write_int32(4, value)?; self.builder.write_int32(4, value)?;
self.maximum_edition_written = true; self.maximum_edition_written = true;
Ok(self) Ok(self)
} }
pub fn file(mut self, value: &[u8]) -> roto_runtime::Result<Self> { pub fn file(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(15, value)?; self.builder.write_bytes(15, value)?;
self.file_written = true; self.file_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &CodeGeneratorResponse<'_>) -> roto_runtime::Result<Self> { pub fn with(mut self, msg: &CodeGeneratorResponse<'_>) -> crate::runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
@@ -559,7 +559,7 @@ impl<'b> CodeGeneratorResponseBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
@@ -568,15 +568,15 @@ pub struct OwnedCodeGeneratorResponse {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
impl roto_runtime::RotoOwned for OwnedCodeGeneratorResponse { impl crate::runtime::RotoOwned for OwnedCodeGeneratorResponse {
type Reader<'a> = CodeGeneratorResponse<'a>; type Reader<'a> = CodeGeneratorResponse<'a>;
fn reader(&self) -> CodeGeneratorResponse<'_> { fn reader(&self) -> CodeGeneratorResponse<'_> {
CodeGeneratorResponse::new(&self.data).expect("failed to create reader") CodeGeneratorResponse::new(&self.data).expect("failed to create reader")
} }
} }
impl roto_runtime::RotoMessage for OwnedCodeGeneratorResponse { impl crate::runtime::RotoMessage for OwnedCodeGeneratorResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedCodeGeneratorResponse { data: buf }) Ok(OwnedCodeGeneratorResponse { data: buf })
} }
@@ -606,7 +606,7 @@ impl Feature {
} }
pub struct File<'a> { pub struct File<'a> {
accessor: roto_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>,
@@ -614,8 +614,8 @@ pub struct File<'a> {
} }
impl<'a> File<'a> { impl<'a> File<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> { pub fn new(data: &'a [u8]) -> crate::runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?; let accessor = crate::runtime::ProtoAccessor::new(data)?;
let mut name_offset = None; let mut name_offset = None;
let mut insertion_point_offset = None; let mut insertion_point_offset = None;
let mut content_offset = None; let mut content_offset = None;
@@ -637,62 +637,62 @@ generated_code_info_offset,
}) })
} }
pub fn name(&self) -> roto_runtime::Result<&'a str> { pub fn name(&self) -> crate::runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn name_or_default(&self) -> crate::runtime::Result<&'a str> {
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) -> roto_runtime::Result<&'a str> { pub fn insertion_point(&self) -> crate::runtime::Result<&'a str> {
let offset = self.insertion_point_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn insertion_point_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn insertion_point_or_default(&self) -> crate::runtime::Result<&'a str> {
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) -> roto_runtime::Result<&'a str> { pub fn content(&self) -> crate::runtime::Result<&'a str> {
let offset = self.content_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) str::from_utf8(bytes).map_err(|_| crate::runtime::RotoError::WireFormatViolation)
} }
pub fn content_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn content_or_default(&self) -> crate::runtime::Result<&'a str> {
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) -> roto_runtime::Result<&'a [u8]> { pub fn generated_code_info(&self) -> crate::runtime::Result<&'a [u8]> {
let offset = self.generated_code_info_offset.ok_or(roto_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)
} }
pub fn generated_code_info_or_default(&self) -> roto_runtime::Result<&'a [u8]> { pub fn generated_code_info_or_default(&self) -> crate::runtime::Result<&'a [u8]> {
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) -> roto_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: roto_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,
@@ -702,7 +702,7 @@ pub struct FileBuilder<'b> {
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: roto_runtime::ProtoBuilder::new(buf), builder: crate::runtime::ProtoBuilder::new(buf),
name_written: false, name_written: false,
insertion_point_written: false, insertion_point_written: false,
content_written: false, content_written: false,
@@ -710,31 +710,31 @@ impl<'b> FileBuilder<'b> {
} }
} }
pub fn name(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn name(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(1, value)?; self.builder.write_string(1, value)?;
self.name_written = true; self.name_written = true;
Ok(self) Ok(self)
} }
pub fn insertion_point(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn insertion_point(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(2, value)?; self.builder.write_string(2, value)?;
self.insertion_point_written = true; self.insertion_point_written = true;
Ok(self) Ok(self)
} }
pub fn content(mut self, value: &str) -> roto_runtime::Result<Self> { pub fn content(mut self, value: &str) -> crate::runtime::Result<Self> {
self.builder.write_string(15, value)?; self.builder.write_string(15, value)?;
self.content_written = true; self.content_written = true;
Ok(self) Ok(self)
} }
pub fn generated_code_info(mut self, value: &[u8]) -> roto_runtime::Result<Self> { pub fn generated_code_info(mut self, value: &[u8]) -> crate::runtime::Result<Self> {
self.builder.write_bytes(16, value)?; self.builder.write_bytes(16, value)?;
self.generated_code_info_written = true; self.generated_code_info_written = true;
Ok(self) Ok(self)
} }
pub fn with(mut self, msg: &File<'_>) -> roto_runtime::Result<Self> { pub fn with(mut self, msg: &File<'_>) -> crate::runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
@@ -751,7 +751,7 @@ impl<'b> FileBuilder<'b> {
Ok(self) Ok(self)
} }
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { pub fn finish(self) -> crate::runtime::Result<&'b mut [u8]> {
self.builder.finish() self.builder.finish()
} }
} }
@@ -760,15 +760,15 @@ pub struct OwnedFile {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
impl roto_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 roto_runtime::RotoMessage for OwnedFile { impl crate::runtime::RotoMessage for OwnedFile {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> crate::runtime::Result<Self> {
Ok(OwnedFile { data: buf }) Ok(OwnedFile { data: buf })
} }
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1,2 +1,4 @@
pub mod generator; pub mod generator;
pub mod google; pub mod google;
pub mod runtime;
+921
View File
@@ -0,0 +1,921 @@
use core::fmt;
use bytes::BufMut;
pub struct MapFieldIterator<'a> {
inner: RepeatedFieldIterator<'a>,
}
impl<'a> MapFieldIterator<'a> {
pub fn new(inner: RepeatedFieldIterator<'a>) -> Self {
Self { inner }
}
}
impl<'a> Iterator for MapFieldIterator<'a> {
type Item = Result<(&'a [u8], &'a [u8])>;
fn next(&mut self) -> Option<Self::Item> {
match self.inner.next() {
Some(Ok((value, _wire_type))) => {
let accessor = ProtoAccessor::new(value).ok()?;
let (key_bytes, _) = accessor.get_value(1).ok()?;
let (val_bytes, _) = accessor.get_value(2).ok()?;
Some(Ok((key_bytes, val_bytes)))
}
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
}
#[derive(Debug, PartialEq)]
pub enum RotoError {
UnexpectedEndOfBuffer,
InvalidVarint,
InvalidWireType(u8),
BufferOverflow,
FieldNotFound,
WireFormatViolation,
}
impl fmt::Display for RotoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RotoError::UnexpectedEndOfBuffer => write!(f, "Unexpected end of buffer"),
RotoError::InvalidVarint => write!(f, "Invalid varint encoding"),
RotoError::InvalidWireType(t) => write!(f, "Invalid wire type: {t}"),
RotoError::BufferOverflow => write!(f, "Buffer overflow during write"),
RotoError::FieldNotFound => write!(f, "Requested field not found in message"),
RotoError::WireFormatViolation => write!(f, "Wire format violation"),
}
}
}
impl std::error::Error for RotoError {}
pub type Result<T> = core::result::Result<T, RotoError>;
pub trait RotoOwned {
type Reader<'a> where Self: 'a;
fn reader(&self) -> Self::Reader<'_>;
}
pub trait RotoMessage: Sized {
fn decode(buf: bytes::Bytes) -> Result<Self>;
fn bytes(&self) -> bytes::Bytes;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WireType {
Varint = 0,
Fixed64 = 1,
LengthDelimited = 2,
StartGroup = 3, // Deprecated
EndGroup = 4, // Deprecated
Fixed32 = 5,
}
impl WireType {
pub fn from_u8(value: u8) -> Result<Self> {
match value {
0 => Ok(WireType::Varint),
1 => Ok(WireType::Fixed64),
2 => Ok(WireType::LengthDelimited),
3 => Ok(WireType::StartGroup),
4 => Ok(WireType::EndGroup),
5 => Ok(WireType::Fixed32),
_ => Err(RotoError::InvalidWireType(value)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Tag {
pub field_number: u32,
pub wire_type: WireType,
}
impl Tag {
/// Decodes a tag from the buffer, returning the tag and the number of bytes read.
pub fn decode(data: &[u8]) -> Result<(Self, usize)> {
let (val, len) = read_varint(data)?;
let wire_type_raw = (val & 0x7) as u8;
let field_number = (val >> 3) as u32;
Ok((
Tag {
field_number,
wire_type: WireType::from_u8(wire_type_raw)?,
},
len,
))
}
/// Encodes a tag into the provided buffer.
pub fn encode(field_number: u32, wire_type: WireType, buf: &mut [u8]) -> Result<usize> {
let val = ((field_number as u64) << 3) | (wire_type as u64);
write_varint(val, buf)
}
}
/// Reads a varint from the start of the buffer.
pub fn read_varint(data: &[u8]) -> Result<(u64, usize)> {
let mut result = 0u64;
let mut shift = 0;
let mut bytes_read = 0;
for &byte in data {
bytes_read += 1;
if bytes_read > 10 {
return Err(RotoError::InvalidVarint);
}
let value = (byte & 0x7F) as u64;
if shift >= 64 {
return Err(RotoError::InvalidVarint);
}
result |= value << shift;
shift += 7;
if (byte & 0x80) == 0 {
return Ok((result, bytes_read));
}
}
Err(RotoError::UnexpectedEndOfBuffer)
}
/// Writes a varint into the buffer.
pub fn write_varint(mut value: u64, buf: &mut [u8]) -> Result<usize> {
let mut bytes_written = 0;
while value >= 0x80 {
if bytes_written >= buf.len() {
return Err(RotoError::BufferOverflow);
}
buf[bytes_written] = (value as u8 & 0x7F) | 0x80;
value >>= 7;
bytes_written += 1;
}
if bytes_written >= buf.len() {
return Err(RotoError::BufferOverflow);
}
buf[bytes_written] = value as u8;
bytes_written += 1;
Ok(bytes_written)
}
/// Returns the number of bytes that should be skipped for a given wire type and the current data slice.
pub fn skip_value(wire_type: WireType, data: &[u8]) -> Result<usize> {
match wire_type {
WireType::Varint => {
let (_, len) = read_varint(data)?;
Ok(len)
}
WireType::Fixed64 => {
if data.len() < 8 {
return Err(RotoError::UnexpectedEndOfBuffer);
}
Ok(8)
}
WireType::LengthDelimited => {
let (len, varint_len) = read_varint(data)?;
let total_len = varint_len + len as usize;
if data.len() < total_len {
return Err(RotoError::UnexpectedEndOfBuffer);
}
Ok(total_len)
}
WireType::Fixed32 => {
if data.len() < 4 {
return Err(RotoError::UnexpectedEndOfBuffer);
}
Ok(4)
}
WireType::StartGroup | WireType::EndGroup => {
// These are deprecated and not fully supported in this runtime.
Err(RotoError::WireFormatViolation)
}
}
}
pub struct ProtoAccessor<'a> {
data: &'a [u8],
}
impl<'a> ProtoAccessor<'a> {
pub fn new(data: &'a [u8]) -> Result<Self> {
Ok(Self { data })
}
/// Returns an iterator over all fields in the message.
pub fn fields(&self) -> FieldIterator<'a> {
FieldIterator {
data: self.data,
cursor: 0,
}
}
/// Returns the value and wire type of the last occurrence of the specified field.
pub fn get_value(&self, field_number: u32) -> Result<(&'a [u8], WireType)> {
let mut last_value = None;
for item in self.fields() {
let (_offset, tag, value) = item?;
if tag.field_number == field_number {
last_value = Some((value, tag.wire_type));
}
}
last_value.ok_or(RotoError::FieldNotFound)
}
/// Returns an iterator that scans the entire buffer for all occurrences of the specified field.
pub fn iter_repeated(&self, field_number: u32) -> RepeatedFieldIterator<'a> {
RepeatedFieldIterator::new(self.data, field_number)
}
/// Returns the value and wire type of a field at a specific offset.
pub fn get_value_at(&self, offset: usize) -> Result<(&'a [u8], WireType)> {
if offset >= self.data.len() {
return Err(RotoError::UnexpectedEndOfBuffer);
}
let (tag, tag_len) = Tag::decode(&self.data[offset..])?;
let cursor_after_tag = offset + tag_len;
if cursor_after_tag > self.data.len() {
return Err(RotoError::UnexpectedEndOfBuffer);
}
let value_len = skip_value(tag.wire_type, &self.data[cursor_after_tag..])?;
let (value_offset, actual_value_len) = match tag.wire_type {
WireType::LengthDelimited => {
let (_, varint_len) = read_varint(&self.data[cursor_after_tag..])?;
(cursor_after_tag + varint_len, value_len - varint_len)
}
_ => (cursor_after_tag, value_len),
};
Ok((
&self.data[value_offset..value_offset + actual_value_len],
tag.wire_type,
))
}
/// Returns an iterator that scans a specific range of the buffer for all occurrences of the specified field.
pub fn iter_repeated_range(
&self,
field_number: u32,
start: usize,
end: usize,
) -> RepeatedFieldIterator<'a> {
RepeatedFieldIterator::new_range(self.data, field_number, start, end)
}
/// Returns an iterator that yields `(field_number, raw_bytes)` for every
/// field in the message. `raw_bytes` is the complete on-wire encoding
/// (tag + value, including any length prefix), suitable for passing
/// directly to `ProtoBuilder::write_raw`.
pub fn raw_fields(&self) -> RawFieldIterator<'a> {
RawFieldIterator {
data: self.data,
cursor: 0,
}
}
}
pub struct FieldIterator<'a> {
data: &'a [u8],
cursor: usize,
}
impl<'a> Iterator for FieldIterator<'a> {
type Item = Result<(usize, Tag, &'a [u8])>;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.data.len() {
return None;
}
let (tag, tag_len) = match Tag::decode(&self.data[self.cursor..]) {
Ok(t) => t,
Err(e) => {
self.cursor = self.data.len();
return Some(Err(e));
}
};
let cursor_after_tag = self.cursor + tag_len;
if cursor_after_tag > self.data.len() {
self.cursor = self.data.len();
return Some(Err(RotoError::UnexpectedEndOfBuffer));
}
let value_len = match skip_value(tag.wire_type, &self.data[cursor_after_tag..]) {
Ok(l) => l,
Err(e) => {
self.cursor = self.data.len();
return Some(Err(e));
}
};
let (value_offset, actual_value_len) = match tag.wire_type {
WireType::LengthDelimited => {
let (_, varint_len) = match read_varint(&self.data[cursor_after_tag..]) {
Ok(v) => v,
Err(e) => {
self.cursor = self.data.len();
return Some(Err(e));
}
};
(cursor_after_tag + varint_len, value_len - varint_len)
}
_ => (cursor_after_tag, value_len),
};
self.cursor = cursor_after_tag + value_len;
Some(Ok((
self.cursor - tag_len - value_len,
tag,
&self.data[value_offset..value_offset + actual_value_len],
)))
}
}
pub struct RepeatedFieldIterator<'a> {
iterator: FieldIterator<'a>,
field_number: u32,
end_offset: Option<usize>,
}
impl<'a> RepeatedFieldIterator<'a> {
pub fn new(data: &'a [u8], field_number: u32) -> Self {
Self {
iterator: FieldIterator { data, cursor: 0 },
field_number,
end_offset: None,
}
}
pub fn new_range(data: &'a [u8], field_number: u32, start: usize, end: usize) -> Self {
Self {
iterator: FieldIterator {
data,
cursor: start,
},
field_number,
end_offset: Some(end),
}
}
}
impl<'a> Iterator for RepeatedFieldIterator<'a> {
type Item = Result<(&'a [u8], WireType)>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(item) = self.iterator.next() {
match item {
Ok((offset, tag, value)) if tag.field_number == self.field_number => {
if let Some(end) = self.end_offset {
if offset > end {
return None;
}
}
return Some(Ok((value, tag.wire_type)));
}
Ok(_) => continue,
Err(e) => return Some(Err(e)),
}
}
None
}
}
/// An iterator that yields `(field_number, raw_bytes)` for every field in a
/// protobuf message, where `raw_bytes` is the complete on-wire encoding of the
/// field: tag varint + value bytes (including the length prefix for
/// length-delimited fields). This is the slice needed by
/// `ProtoBuilder::write_raw` to copy a field verbatim.
pub struct RawFieldIterator<'a> {
data: &'a [u8],
cursor: usize,
}
impl<'a> Iterator for RawFieldIterator<'a> {
type Item = Result<(u32, &'a [u8])>;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.data.len() {
return None;
}
let field_start = self.cursor;
let (tag, tag_len) = match Tag::decode(&self.data[self.cursor..]) {
Ok(t) => t,
Err(e) => {
self.cursor = self.data.len();
return Some(Err(e));
}
};
let cursor_after_tag = self.cursor + tag_len;
if cursor_after_tag > self.data.len() {
self.cursor = self.data.len();
return Some(Err(RotoError::UnexpectedEndOfBuffer));
}
let value_len = match skip_value(tag.wire_type, &self.data[cursor_after_tag..]) {
Ok(l) => l,
Err(e) => {
self.cursor = self.data.len();
return Some(Err(e));
}
};
self.cursor = cursor_after_tag + value_len;
Some(Ok((tag.field_number, &self.data[field_start..self.cursor])))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "alloc")]
use alloc::{vec, vec::{Vec}};
#[test]
fn test_varint_read_write() {
let mut buf = [0u8; 10];
let val = 300u64;
let len = write_varint(val, &mut buf).unwrap();
assert_eq!(len, 2);
assert_eq!(&buf[..2], &[0xAC, 0x02]);
let (read_val, read_len) = read_varint(&buf[..2]).unwrap();
assert_eq!(read_val, val);
assert_eq!(read_len, 2);
}
#[test]
fn test_tag_decode() {
// Field 1, WireType Varint: (1 << 3) | 0 = 8
let data = [8u8];
let (tag, len) = Tag::decode(&data).unwrap();
assert_eq!(tag.field_number, 1);
assert_eq!(tag.wire_type, WireType::Varint);
assert_eq!(len, 1);
// Field 15, WireType LengthDelimited: (15 << 3) | 2 = 120 | 2 = 122
let data2 = [122u8];
let (tag2, len2) = Tag::decode(&data2).unwrap();
assert_eq!(tag2.field_number, 15);
assert_eq!(tag2.wire_type, WireType::LengthDelimited);
assert_eq!(len2, 1);
}
#[test]
fn test_skip_value() {
// Varint: 300 (2 bytes)
let data_varint = [0xAC, 0x02];
assert_eq!(skip_value(WireType::Varint, &data_varint).unwrap(), 2);
// Fixed32: 4 bytes
let data_fixed32 = [0u8; 4];
assert_eq!(skip_value(WireType::Fixed32, &data_fixed32).unwrap(), 4);
// Length delimited: len=3, data=[1,2,3] (1 byte varint for length + 3 bytes)
let data_len = [3, 1, 2, 3];
assert_eq!(skip_value(WireType::LengthDelimited, &data_len).unwrap(), 4);
}
#[test]
fn test_accessor_basic() {
// Field 1 (Varint): 150
// Tag: (1 << 3) | 0 = 8. Value: 150 = [150, 1]
// Field 2 (LengthDelimited): "hi"
// Tag: (2 << 3) | 2 = 18. Length: 2. Value: [104, 105]
let data = [8, 150, 1, 18, 2, 104, 105];
let acc = ProtoAccessor::new(&data).unwrap();
let (val1, type1) = acc.get_value(1).unwrap();
assert_eq!(type1, WireType::Varint);
assert_eq!(val1, &[150, 1]);
let (val2, type2) = acc.get_value(2).unwrap();
assert_eq!(type2, WireType::LengthDelimited);
assert_eq!(val2, &[104, 105]);
}
#[test]
fn test_accessor_repeated() {
// Field 1: 10, Field 1: 20, Field 1: 30
// Tags: 8, 8, 8. Values: 10, 20, 30
let data = [8, 10, 8, 20, 8, 30];
let acc = ProtoAccessor::new(&data).unwrap();
// Last value should be 30
let (val, _) = acc.get_value(1).unwrap();
assert_eq!(val, &[30]);
// Iteration should find all three
let results: Vec<_> = acc.iter_repeated(1).collect();
assert_eq!(results.len(), 3);
assert_eq!(results[0].as_ref().unwrap().0, &[10]);
assert_eq!(results[1].as_ref().unwrap().0, &[20]);
assert_eq!(results[2].as_ref().unwrap().0, &[30]);
}
#[test]
fn test_builder_basic() {
let mut buf = [0u8; 1024];
let mut builder = ProtoBuilder::new(&mut buf);
builder.write_string(1, "hello").unwrap();
builder.write_int32(2, 42).unwrap();
let data = builder.finish().unwrap();
let acc = ProtoAccessor::new(data).unwrap();
let (val1, _) = acc.get_value(1).unwrap();
assert_eq!(val1, "hello".as_bytes());
let (val2, _) = acc.get_value(2).unwrap();
assert_eq!(val2, &[42]);
}
#[test]
fn test_builder_overflow() {
let mut buf = [0u8; 2];
let mut builder = ProtoBuilder::new(&mut buf);
let result = builder.write_string(1, "too long");
assert_eq!(result, Err(RotoError::BufferOverflow));
}
#[test]
fn test_raw_field_iterator_yields_correct_bytes() {
// Build: field 1 = string "hi", field 2 = int32 42
let mut buf = [0u8; 64];
let mut builder = ProtoBuilder::new(&mut buf);
builder.write_string(1, "hi").unwrap();
builder.write_int32(2, 42).unwrap();
let data = builder.finish().unwrap().to_vec();
let acc = ProtoAccessor::new(&data).unwrap();
let raw: Vec<_> = acc.raw_fields().collect();
assert_eq!(raw.len(), 2);
// Field 1: tag = (1 << 3) | 2 = 0x0A, len varint = 0x02, "hi" = [0x68, 0x69]
let (fn1, bytes1) = raw[0].as_ref().unwrap();
assert_eq!(*fn1, 1);
assert_eq!(*bytes1, [0x0A, 0x02, b'h', b'i']);
// Field 2: tag = (2 << 3) | 0 = 0x10, varint 42 = 0x2A
let (fn2, bytes2) = raw[1].as_ref().unwrap();
assert_eq!(*fn2, 2);
assert_eq!(*bytes2, [0x10, 0x2A]);
}
#[test]
fn test_write_raw_copies_field_verbatim() {
// Build source: field 1 = string "hello", field 2 = int32 99
let mut src_buf = [0u8; 64];
let mut src_builder = ProtoBuilder::new(&mut src_buf);
src_builder.write_string(1, "hello").unwrap();
src_builder.write_int32(2, 99).unwrap();
let src_data = src_builder.finish().unwrap().to_vec();
// Copy every raw field verbatim into a new buffer
let src_acc = ProtoAccessor::new(&src_data).unwrap();
let mut dst_buf = [0u8; 64];
let mut dst_builder = ProtoBuilder::new(&mut dst_buf);
for item in src_acc.raw_fields() {
let (_, raw_bytes) = item.unwrap();
dst_builder.write_raw(raw_bytes).unwrap();
}
let dst_data = dst_builder.finish().unwrap();
// The copy must be byte-identical to the source
assert_eq!(dst_data, src_data.as_slice());
}
#[test]
fn test_with_pattern_copies_unseen_fields() {
// Build an existing source message with 3 fields
let mut src_buf = [0u8; 128];
let mut src_builder = ProtoBuilder::new(&mut src_buf);
src_builder.write_string(1, "original").unwrap();
src_builder.write_int32(2, 99).unwrap();
src_builder.write_varint(3, 1u64).unwrap(); // bool
let src_data = src_builder.finish().unwrap().to_vec();
let src_acc = ProtoAccessor::new(&src_data).unwrap();
// Simulate what a generated `with` method does:
// field 1 was explicitly written; fields 2 and 3 come from source.
let field1_written = true;
let field2_written = false;
let field3_written = false;
let mut dst_buf = [0u8; 128];
let mut dst_builder = ProtoBuilder::new(&mut dst_buf);
dst_builder.write_string(1, "updated").unwrap();
for item in src_acc.raw_fields() {
let (field_number, raw_bytes) = item.unwrap();
let is_written = match field_number {
1 => field1_written,
2 => field2_written,
3 => field3_written,
_ => false,
};
if !is_written {
dst_builder.write_raw(raw_bytes).unwrap();
}
}
let dst_data = dst_builder.finish().unwrap();
let dst_acc = ProtoAccessor::new(dst_data).unwrap();
// Field 1: overridden value
let (val1, _) = dst_acc.get_value(1).unwrap();
assert_eq!(val1, b"updated");
// Field 2: copied from source
let (val2, _) = dst_acc.get_value(2).unwrap();
let (v2, _) = read_varint(val2).unwrap();
assert_eq!(v2 as i32, 99);
// Field 3: copied from source
let (val3, _) = dst_acc.get_value(3).unwrap();
let (v3, _) = read_varint(val3).unwrap();
assert_eq!(v3, 1u64);
}
#[test]
fn test_protoc_binary_compatibility() {
let data = include_bytes!("../data/test_data.pb");
let acc = ProtoAccessor::new(data).unwrap();
// 1. Varints (Integers, Booleans, Enums)
let (val_i32, type_i32) = acc.get_value(3).expect("i32_val not found");
assert_eq!(type_i32, WireType::Varint);
let (v, _) = read_varint(val_i32).unwrap();
assert_eq!(v, 42);
let (val_b, type_b) = acc.get_value(13).expect("b_val not found");
assert_eq!(type_b, WireType::Varint);
let (v_b, _) = read_varint(val_b).unwrap();
assert_eq!(v_b, 1); // true
let (val_status, type_status) = acc.get_value(16).expect("status not found");
assert_eq!(type_status, WireType::Varint);
let (v_s, _) = read_varint(val_status).unwrap();
assert_eq!(v_s, 1); // ACTIVE
// 2. Length Delimited (Strings, Bytes)
let (val_s, type_s) = acc.get_value(14).expect("s_val not found");
assert_eq!(type_s, WireType::LengthDelimited);
assert_eq!(val_s, "Hello Roto!".as_bytes());
// 3. Fixed Width (Floats)
let (val_f, type_f) = acc.get_value(2).expect("f_val not found");
assert_eq!(type_f, WireType::Fixed32);
let f_val = f32::from_le_bytes(val_f.try_into().expect("Expected 4 bytes for f32"));
assert!((f_val - 2.71828).abs() < 1e-5);
// 4. Repeated Fields
// Note: primitive repeated fields are packed in proto3, so we iterate over the blob
let mut i32_vals = Vec::new();
for item in acc.iter_repeated(17) {
let (blob, _) = item.expect("Failed to decode repeated i32");
let mut cursor = 0;
while cursor < blob.len() {
let (v, len) = read_varint(&blob[cursor..]).unwrap();
i32_vals.push(v);
cursor += len;
}
}
assert_eq!(i32_vals, vec![1, 2, 3, 4, 5]);
let repeated_strings: Vec<_> = acc
.iter_repeated(18)
.map(|r| {
let (val, _) = r.expect("Failed to decode repeated string");
core::str::from_utf8(val).expect("Invalid utf8")
})
.collect();
assert_eq!(repeated_strings, vec!["one", "two", "three"]);
let repeated_nested: Vec<_> = acc
.iter_repeated(19)
.map(|r| {
let (val, _) = r.expect("Failed to decode repeated nested");
let nested_acc = ProtoAccessor::new(val).unwrap();
let (id_val, _) = nested_acc.get_value(1).expect("Nested id not found");
let (id, _) = read_varint(id_val).unwrap();
id
})
.collect();
assert_eq!(repeated_nested, vec![101, 102]);
// 5. Single Nested Message
let (val_nested, type_nested) = acc.get_value(20).expect("single_nested not found");
assert_eq!(type_nested, WireType::LengthDelimited);
let nested_acc = ProtoAccessor::new(val_nested).unwrap();
let (val_id, _) = nested_acc.get_value(1).expect("Nested id not found");
let (id, _) = read_varint(val_id).unwrap();
assert_eq!(id, 200);
// Validate that fields appear in the expected relative order
let field_numbers: Vec<u32> = acc
.fields()
.map(|r| r.expect("Failed to decode field").1.field_number)
.collect();
let essential_fields = [1, 2, 3, 14, 16, 20];
let mut last_field = 0;
let mut found_count = 0;
for &f in &field_numbers {
if essential_fields.contains(&f) {
assert!(
f >= last_field,
"Fields appeared out of order: {} came after {}",
f,
last_field
);
last_field = f;
found_count += 1;
}
}
assert_eq!(found_count, essential_fields.len());
}
}
pub struct ProtoBuilder<'a> {
buf: &'a mut [u8],
pos: usize,
}
impl<'a> ProtoBuilder<'a> {
pub fn new(buf: &'a mut [u8]) -> Self {
Self { buf, pos: 0 }
}
fn write_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)?;
self.append_bytes(&temp[..len])
}
fn append_bytes(&mut self, bytes: &[u8]) -> Result<()> {
if self.pos + bytes.len() > self.buf.len() {
return Err(RotoError::BufferOverflow);
}
self.buf[self.pos..self.pos + bytes.len()].copy_from_slice(bytes);
self.pos += bytes.len();
Ok(())
}
pub fn write_varint(&mut self, field_number: u32, value: u64) -> Result<()> {
self.write_tag(field_number, WireType::Varint)?;
let mut temp = [0u8; 10];
let len = write_varint(value, &mut temp)?;
self.append_bytes(&temp[..len])
}
pub fn write_int32(&mut self, field_number: u32, value: i32) -> Result<()> {
self.write_varint(field_number, value as u64)
}
pub fn write_string(&mut self, field_number: u32, value: &str) -> Result<()> {
self.write_tag(field_number, WireType::LengthDelimited)?;
let bytes = value.as_bytes();
let mut len_buf = [0u8; 10];
let len_len = write_varint(bytes.len() as u64, &mut len_buf)?;
self.append_bytes(&len_buf[..len_len])?;
self.append_bytes(bytes)
}
pub fn write_fixed32(&mut self, field_number: u32, value: u32) -> Result<()> {
self.write_tag(field_number, WireType::Fixed32)?;
self.append_bytes(&value.to_le_bytes())
}
pub fn write_fixed64(&mut self, field_number: u32, value: u64) -> Result<()> {
self.write_tag(field_number, WireType::Fixed64)?;
self.append_bytes(&value.to_le_bytes())
}
pub fn write_bytes(&mut self, field_number: u32, value: &[u8]) -> Result<()> {
self.write_tag(field_number, WireType::LengthDelimited)?;
let mut len_buf = [0u8; 10];
let len_len = write_varint(value.len() as u64, &mut len_buf)?;
self.append_bytes(&len_buf[..len_len])?;
self.append_bytes(value)
}
/// Appends a pre-encoded field (tag + value bytes) verbatim into the
/// buffer. Use this together with `ProtoAccessor::raw_fields` to copy
/// fields from an existing message into a builder without re-encoding them.
pub fn write_raw(&mut self, raw_bytes: &[u8]) -> Result<()> {
self.append_bytes(raw_bytes)
}
pub fn write_map_entry(
&mut self,
field_number: u32,
key_encoded: &[u8],
value_encoded: &[u8],
) -> Result<()> {
let entry_len = key_encoded.len() + value_encoded.len();
self.write_tag(field_number, WireType::LengthDelimited)?;
let mut len_buf = [0u8; 10];
let len_len = write_varint(entry_len as u64, &mut len_buf)?;
self.append_bytes(&len_buf[..len_len])?;
self.append_bytes(key_encoded)?;
self.append_bytes(value_encoded)?;
Ok(())
}
pub fn finish(self) -> Result<&'a mut [u8]> {
Ok(&mut self.buf[..self.pos])
}
}
pub struct BufMutBuilder<'a, B: BufMut> {
buf: &'a mut B,
}
impl<'a, B: BufMut> BufMutBuilder<'a, B> {
pub fn new(buf: &'a mut B) -> Self {
Self { buf }
}
fn write_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)?;
self.buf.put_slice(&temp[..len]);
Ok(())
}
pub fn write_varint(&mut self, field_number: u32, value: u64) -> Result<()> {
self.write_tag(field_number, WireType::Varint)?;
let mut temp = [0u8; 10];
let len = write_varint(value, &mut temp)?;
self.buf.put_slice(&temp[..len]);
Ok(())
}
pub fn write_int32(&mut self, field_number: u32, value: i32) -> Result<()> {
self.write_varint(field_number, value as u64)
}
pub fn write_string(&mut self, field_number: u32, value: &str) -> Result<()> {
self.write_tag(field_number, WireType::LengthDelimited)?;
let bytes = value.as_bytes();
let mut len_buf = [0u8; 10];
let len_len = write_varint(bytes.len() as u64, &mut len_buf)?;
self.buf.put_slice(&len_buf[..len_len]);
self.buf.put_slice(bytes);
Ok(())
}
pub fn write_fixed32(&mut self, field_number: u32, value: u32) -> Result<()> {
self.write_tag(field_number, WireType::Fixed32)?;
self.buf.put_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_fixed64(&mut self, field_number: u32, value: u64) -> Result<()> {
self.write_tag(field_number, WireType::Fixed64)?;
self.buf.put_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_bytes(&mut self, field_number: u32, value: &[u8]) -> Result<()> {
self.write_tag(field_number, WireType::LengthDelimited)?;
let mut len_buf = [0u8; 10];
let len_len = write_varint(value.len() as u64, &mut len_buf)?;
self.buf.put_slice(&len_buf[..len_len]);
self.buf.put_slice(value);
Ok(())
}
pub fn write_raw(&mut self, raw_bytes: &[u8]) -> Result<()> {
self.buf.put_slice(raw_bytes);
Ok(())
}
pub fn write_map_entry(
&mut self,
field_number: u32,
key_encoded: &[u8],
value_encoded: &[u8],
) -> Result<()> {
let entry_len = key_encoded.len() + value_encoded.len();
self.write_tag(field_number, WireType::LengthDelimited)?;
let mut len_buf = [0u8; 10];
let len_len = write_varint(entry_len as u64, &mut len_buf)?;
self.buf.put_slice(&len_buf[..len_len]);
self.buf.put_slice(key_encoded);
self.buf.put_slice(value_encoded);
Ok(())
}
}
+5
View File
@@ -24,7 +24,12 @@ futures-util = "0.3"
http-body-util = "0.1" http-body-util = "0.1"
http = "1.1" http = "1.1"
http-body = "1.0" http-body = "1.0"
async-trait = "0.1"
[build-dependencies] [build-dependencies]
tonic-build = "0.12" tonic-build = "0.12"
roto-codegen = { path = "../../codegen" } roto-codegen = { path = "../../codegen" }
[features]
default = ["alloc"]
alloc = []
+61 -37
View File
@@ -1,22 +1,9 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#[allow(unused_imports)] #[allow(unused_imports)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator}; use core::str;
use std::str; #[cfg(feature = "alloc")]
use bytes::{Bytes, BytesMut, Buf, BufMut}; use bytes::{Bytes, BytesMut, Buf, BufMut};
use tonic::{Request, Response, Status};
use tokio_stream::Stream;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::future::Future;
use tonic::body::BoxBody;
use tower::Service;
use futures_util::StreamExt;
use http_body_util::BodyExt;
use http_body::Body;
use roto_tonic::{BufferPool, StatusBody};
pub struct HelloRequest<'a> { pub struct HelloRequest<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
@@ -41,7 +28,7 @@ name_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)?;
str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -76,7 +63,7 @@ impl<'b> HelloRequestBuilder<'b> {
} }
pub fn with(mut self, msg: &HelloRequest<'_>) -> roto_runtime::Result<Self> { pub fn with(mut self, msg: &HelloRequest<'_>) -> roto_runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
1 => self.name_written, 1 => self.name_written,
@@ -94,10 +81,12 @@ impl<'b> HelloRequestBuilder<'b> {
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedHelloRequest { pub struct OwnedHelloRequest {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedHelloRequest { impl roto_runtime::RotoOwned for OwnedHelloRequest {
type Reader<'a> = HelloRequest<'a>; type Reader<'a> = HelloRequest<'a>;
fn reader(&self) -> HelloRequest<'_> { fn reader(&self) -> HelloRequest<'_> {
@@ -105,6 +94,7 @@ impl roto_runtime::RotoOwned for OwnedHelloRequest {
} }
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedHelloRequest { impl roto_runtime::RotoMessage for OwnedHelloRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedHelloRequest { data: buf }) Ok(OwnedHelloRequest { data: buf })
@@ -138,7 +128,7 @@ message_offset,
pub fn message(&self) -> roto_runtime::Result<&'a str> { pub fn message(&self) -> roto_runtime::Result<&'a str> {
let offset = self.message_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self.message_offset.ok_or(roto_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(|_| roto_runtime::RotoError::WireFormatViolation) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn message_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn message_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -173,7 +163,7 @@ impl<'b> HelloResponseBuilder<'b> {
} }
pub fn with(mut self, msg: &HelloResponse<'_>) -> roto_runtime::Result<Self> { pub fn with(mut self, msg: &HelloResponse<'_>) -> roto_runtime::Result<Self> {
for item in msg.raw_fields() { for item in msg.accessor.raw_fields() {
let (field_number, raw_bytes) = item?; let (field_number, raw_bytes) = item?;
let is_written = match field_number { let is_written = match field_number {
1 => self.message_written, 1 => self.message_written,
@@ -191,10 +181,12 @@ impl<'b> HelloResponseBuilder<'b> {
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedHelloResponse { pub struct OwnedHelloResponse {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedHelloResponse { impl roto_runtime::RotoOwned for OwnedHelloResponse {
type Reader<'a> = HelloResponse<'a>; type Reader<'a> = HelloResponse<'a>;
fn reader(&self) -> HelloResponse<'_> { fn reader(&self) -> HelloResponse<'_> {
@@ -202,6 +194,7 @@ impl roto_runtime::RotoOwned for OwnedHelloResponse {
} }
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedHelloResponse { impl roto_runtime::RotoMessage for OwnedHelloResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedHelloResponse { data: buf }) Ok(OwnedHelloResponse { data: buf })
@@ -212,32 +205,65 @@ impl roto_runtime::RotoMessage for OwnedHelloResponse {
} }
} }
#[tonic::async_trait]
#[cfg(feature = "alloc")]
use tonic::{Request, Response, Status};
#[cfg(feature = "alloc")]
use tokio_stream::Stream;
#[cfg(feature = "alloc")]
use std::pin::Pin;
#[cfg(feature = "alloc")]
use std::sync::Arc;
#[cfg(feature = "alloc")]
use std::task::{Context, Poll};
#[cfg(feature = "alloc")]
use std::future::Future;
#[cfg(feature = "alloc")]
use tonic::body::BoxBody;
#[cfg(feature = "alloc")]
use tower::Service;
#[cfg(feature = "alloc")]
use futures_util::StreamExt;
#[cfg(feature = "alloc")]
use http_body_util::BodyExt;
#[cfg(feature = "alloc")]
use http_body::Body;
#[cfg(feature = "alloc")]
use crate::{BufferPool, StatusBody};
#[cfg(feature = "alloc")]
#[async_trait::async_trait]
pub trait HelloWorldService: Send + Sync + 'static { pub trait HelloWorldService: Send + Sync + 'static {
async fn hello_world(&self, request: Request<OwnedHelloRequest>) -> std::result::Result<Response<OwnedHelloResponse>, Status>; async fn hello_world(&self, request: Request<OwnedHelloRequest>) -> std::result::Result<Response<OwnedHelloResponse>, Status>;
} }
#[cfg(feature = "alloc")]
#[derive(Clone)]
pub struct HelloWorldServiceServer { pub struct HelloWorldServiceServer {
inner: Arc<dyn HelloWorldService>, inner: Arc<dyn HelloWorldService>,
pool: Arc<BufferPool>, pool: Arc<BufferPool>,
} }
#[cfg(feature = "alloc")]
impl HelloWorldServiceServer { impl HelloWorldServiceServer {
pub fn new(inner: Arc<dyn HelloWorldService>, pool: Arc<BufferPool>) -> Self { pub fn new(inner: Arc<dyn HelloWorldService>, pool: Arc<BufferPool>) -> Self {
Self { inner, pool } Self { inner, pool }
} }
} }
#[cfg(feature = "alloc")]
impl tonic::server::NamedService for HelloWorldServiceServer { impl tonic::server::NamedService for HelloWorldServiceServer {
const NAME: &'static str = "HelloWorldService"; const NAME: &'static str = "hello.HelloWorldService";
} }
#[cfg(feature = "alloc")]
impl Service<http::Request<BoxBody>> for HelloWorldServiceServer { impl Service<http::Request<BoxBody>> for HelloWorldServiceServer {
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 = 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<Result<(), Self::Error>> { fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
@@ -245,13 +271,12 @@ impl Service<http::Request<BoxBody>> for HelloWorldServiceServer {
let inner = self.inner.clone(); let inner = self.inner.clone();
let pool = self.pool.clone(); let pool = self.pool.clone();
Box::pin(async move { Box::pin(async move {
let path = req.uri().path().to_string();
let body = req.into_body(); let body = req.into_body();
let mut buf = pool.get(); let mut buf = pool.get();
let mut stream = body; let mut stream = body;
while let Some(frame_result) = stream.frame().await { while let Some(frame_result) = stream.frame().await {
let frame = frame_result.map_err(|e| { let frame = frame_result.expect("Body frame error");
panic!("Body frame error: {}", e);
})?;
if let Some(data) = frame.data_ref() { if let Some(data) = frame.data_ref() {
buf.put(data.clone()); buf.put(data.clone());
} }
@@ -261,30 +286,29 @@ impl Service<http::Request<BoxBody>> for HelloWorldServiceServer {
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(Some(Bytes::from_static(&[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());
} }
let payload = bytes_vec.slice(5..); let payload = bytes_vec.slice(5..);
let path = req.uri().path();
let mut routed = false; let mut routed = false;
if path == "/HelloWorldService/hello_world" { if path == "/hello.HelloWorldService/HelloWorld" {
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(Some(Bytes::from_static(&[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());
} }
}}; };
let response = match inner.hello_world(Request::new(request_msg)).await { let response = match inner.hello_world(Request::new(request_msg)).await {
Ok(res) => res, Ok(res) => res,
Err(e) => { Err(e) => {
let res_body = BoxBody::new(StatusBody(Some(Bytes::from_static(&[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());
} }
}}; };
let response_msg = response.into_inner(); let response_msg = response.into_inner();
let response_bytes = response_msg.bytes(); let response_bytes = response_msg.bytes();
@@ -296,15 +320,15 @@ impl Service<http::Request<BoxBody>> for HelloWorldServiceServer {
let frame_len = res_buf.len(); let frame_len = res_buf.len();
let frame = res_buf.split_to(frame_len).freeze(); let frame = res_buf.split_to(frame_len).freeze();
pool.put(res_buf); pool.put(res_buf);
let res_body = BoxBody::new(StatusBody(Some(frame))); 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(Some(Bytes::from_static(&[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());
} }
Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody(None))).unwrap()) Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody::new(None, 0))).unwrap())
}) })
} }
} }
+2
View File
@@ -0,0 +1,2 @@
[build]
target = "thumbv7em-none-eabihf"
+3 -7
View File
@@ -1,13 +1,9 @@
[package] [package]
name = "no_std_test" name = "no_std_test"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2021"
[dependencies] [dependencies]
roto-runtime = { path = "../../runtime", default-features = false } roto-runtime = { path = "../../runtime", default-features = false }
prost = "0.13"
[profile.dev] bytes = "1.8"
panic = "abort"
[profile.release]
panic = "abort"
+805
View File
@@ -0,0 +1,805 @@
// @generated by protoc-gen-roto — do not edit
#[allow(unused_imports)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use core::str;
#[cfg(feature = "alloc")]
use bytes::{Bytes, BytesMut, Buf, BufMut};
pub struct Hello<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
name_offset: Option<usize>,
d_offset: Option<usize>,
f_offset: Option<usize>,
b_offset: Option<usize>,
n_offset: Option<usize>,
l_offset: Option<usize>,
c1_offset: Option<usize>,
c2_offset: Option<usize>,
pets_start: Option<usize>,
pets_end: Option<usize>,
}
impl<'a> Hello<'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 d_offset = None;
let mut f_offset = None;
let mut b_offset = None;
let mut n_offset = None;
let mut l_offset = None;
let mut c1_offset = None;
let mut c2_offset = None;
let mut pets_start = None;
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 == 9 {
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,
})
}
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)?;
core::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 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 (bytes, _) = self.accessor.get_value_at(offset)?;
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 f(&self) -> roto_runtime::Result<f32> {
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)?))
}
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 b(&self) -> roto_runtime::Result<bool> {
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)
}
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 n(&self) -> roto_runtime::Result<i32> {
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)
}
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 l(&self) -> roto_runtime::Result<i32> {
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)
}
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 c1(&self) -> roto_runtime::Result<&'a str> {
let offset = self.c1_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn c1_or_default(&self) -> roto_runtime::Result<&'a str> {
self.c1().or(Ok(""))
}
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 (bytes, _) = self.accessor.get_value_at(offset)?;
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 pets(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.pets_start, self.pets_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(9, start, end),
_ => self.accessor.iter_repeated(9),
}
}
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()?)));
}
if self.c2_offset.is_some() {
return Ok(Some(hello::Choice::c2 (self.c2()?)));
}
Ok(None)
}
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct HelloBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>,
name_written: bool,
d_written: bool,
f_written: bool,
b_written: bool,
n_written: bool,
l_written: bool,
c1_written: bool,
c2_written: bool,
pets_written: bool,
}
impl<'b> HelloBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> HelloBuilder<'_> {
HelloBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
name_written: false,
d_written: false,
f_written: false,
b_written: false,
n_written: false,
l_written: false,
c1_written: false,
c2_written: false,
pets_written: false,
}
}
pub fn name(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
}
pub fn d(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(2, value)?;
self.d_written = true;
Ok(self)
}
pub fn f(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(3, value)?;
self.f_written = true;
Ok(self)
}
pub fn b(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(4, value)?;
self.b_written = true;
Ok(self)
}
pub fn n(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(5, value)?;
self.n_written = true;
Ok(self)
}
pub fn l(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(6, value)?;
self.l_written = true;
Ok(self)
}
pub fn c1(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(7, value)?;
self.c1_written = true;
Ok(self)
}
pub fn c2(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(8, value)?;
self.c2_written = true;
Ok(self)
}
pub fn pets(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(9, value)?;
self.pets_written = true;
Ok(self)
}
pub fn with(mut self, msg: &Hello<'_>) -> 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.d_written,
3 => self.f_written,
4 => self.b_written,
5 => self.n_written,
6 => self.l_written,
7 => self.c1_written,
8 => self.c2_written,
9 => self.pets_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()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedHello {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedHello {
type Reader<'a> = Hello<'a>;
fn reader(&self) -> Hello<'_> {
Hello::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedHello {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedHello { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub mod hello {
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); }
}
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)?;
core::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 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_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 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 name(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
}
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)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedPet {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedPet {
type Reader<'a> = Pet<'a>;
fn reader(&self) -> Pet<'_> {
Pet::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
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> {
accessor: roto_runtime::ProtoAccessor<'a>,
request_offset: Option<usize>,
}
impl<'a> HelloRequest<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut request_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { request_offset = Some(offset); }
}
Ok(Self {
accessor,
request_offset,
})
}
pub fn request(&self) -> roto_runtime::Result<&'a [u8]> {
let offset = self.request_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes)
}
pub fn request_or_default(&self) -> roto_runtime::Result<&'a [u8]> {
self.request().or(Ok(&[]))
}
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> {
builder: roto_runtime::ProtoBuilder<'b>,
request_written: bool,
}
impl<'b> HelloRequestBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> HelloRequestBuilder<'_> {
HelloRequestBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
request_written: false,
}
}
pub fn request(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(1, value)?;
self.request_written = true;
Ok(self)
}
pub fn with(mut self, msg: &HelloRequest<'_>) -> 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.request_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()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedHelloRequest {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedHelloRequest {
type Reader<'a> = HelloRequest<'a>;
fn reader(&self) -> HelloRequest<'_> {
HelloRequest::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedHelloRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedHelloRequest { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub struct HelloReply<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
response_offset: Option<usize>,
}
impl<'a> HelloReply<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut response_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { response_offset = Some(offset); }
}
Ok(Self {
accessor,
response_offset,
})
}
pub fn response(&self) -> roto_runtime::Result<&'a [u8]> {
let offset = self.response_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes)
}
pub fn response_or_default(&self) -> roto_runtime::Result<&'a [u8]> {
self.response().or(Ok(&[]))
}
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> {
builder: roto_runtime::ProtoBuilder<'b>,
response_written: bool,
}
impl<'b> HelloReplyBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> HelloReplyBuilder<'_> {
HelloReplyBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
response_written: false,
}
}
pub fn response(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(1, value)?;
self.response_written = true;
Ok(self)
}
pub fn with(mut self, msg: &HelloReply<'_>) -> 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.response_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()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedHelloReply {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedHelloReply {
type Reader<'a> = HelloReply<'a>;
fn reader(&self) -> HelloReply<'_> {
HelloReply::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedHelloReply {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedHelloReply { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
#[cfg(feature = "alloc")]
use tonic::{Request, Response, Status};
#[cfg(feature = "alloc")]
use tokio_stream::Stream;
#[cfg(feature = "alloc")]
use std::pin::Pin;
#[cfg(feature = "alloc")]
use std::sync::Arc;
#[cfg(feature = "alloc")]
use std::task::{Context, Poll};
#[cfg(feature = "alloc")]
use std::future::Future;
#[cfg(feature = "alloc")]
use tonic::body::BoxBody;
#[cfg(feature = "alloc")]
use tower::Service;
#[cfg(feature = "alloc")]
use futures_util::StreamExt;
#[cfg(feature = "alloc")]
use http_body_util::BodyExt;
#[cfg(feature = "alloc")]
use http_body::Body;
#[cfg(feature = "alloc")]
use crate::{BufferPool, StatusBody};
#[cfg(feature = "alloc")]
#[async_trait::async_trait]
pub trait Greeter: Send + Sync + 'static {
async fn say_hello(&self, request: Request<OwnedHelloRequest>) -> std::result::Result<Response<OwnedHelloReply>, Status>;
}
#[cfg(feature = "alloc")]
#[derive(Clone)]
pub struct GreeterServer {
inner: Arc<dyn Greeter>,
pool: Arc<BufferPool>,
}
#[cfg(feature = "alloc")]
impl GreeterServer {
pub fn new(inner: Arc<dyn Greeter>, pool: Arc<BufferPool>) -> Self {
Self { inner, pool }
}
}
#[cfg(feature = "alloc")]
impl tonic::server::NamedService for GreeterServer {
const NAME: &'static str = "helloworld.Greeter";
}
#[cfg(feature = "alloc")]
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>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<BoxBody>) -> Self::Future {
let inner = self.inner.clone();
let pool = self.pool.clone();
Box::pin(async move {
let path = req.uri().path().to_string();
let body = req.into_body();
let mut buf = pool.get();
let mut stream = body;
while let Some(frame_result) = stream.frame().await {
let frame = frame_result.expect("Body frame error");
if let Some(data) = frame.data_ref() {
buf.put(data.clone());
}
}
let total_len = buf.len();
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 payload = bytes_vec.slice(5..);
let mut routed = false;
if path == "/helloworld.Greeter/SayHello" {
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 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 response_msg = response.into_inner();
let response_bytes = response_msg.bytes();
let mut res_buf = pool.get();
res_buf.put_u8(0);
let len = response_bytes.len() as u32;
res_buf.put_slice(&len.to_be_bytes());
res_buf.put_slice(&response_bytes);
let frame_len = res_buf.len();
let frame = res_buf.split_to(frame_len).freeze();
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());
}
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());
}
Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody::new(None, 0))).unwrap())
})
}
}
+3 -5
View File
@@ -1,16 +1,14 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use roto_runtime::ProtoAccessor; use core::panic::PanicInfo;
#[panic_handler] #[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { fn panic(_info: &PanicInfo) -> ! {
loop {} loop {}
} }
#[unsafe(no_mangle)] #[no_mangle]
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
let _data = [0u8; 0];
let _ = ProtoAccessor::new(&_data);
loop {} loop {}
} }
+1 -1
View File
@@ -2,7 +2,7 @@ You are the Researcher. Your role is to conduct a comprehensive initial analysis
Your workflow: Your workflow:
1. Analyze the problem statement to identify key technical requirements and unknown areas. 1. Analyze the problem statement to identify key technical requirements and unknown areas.
2. Use available tools (such as SearXNG and web search) to research existing libraries, frameworks, APIs, and best practices relevant to the problem. 2. Use available tools (such as SearXNG and fetch) to research existing libraries, frameworks, APIs, and best practices relevant to the problem.
3. Explore the current codebase to understand how the new functionality fits in or what existing patterns should be followed. 3. Explore the current codebase to understand how the new functionality fits in or what existing patterns should be followed.
4. Compile a detailed report including: 4. Compile a detailed report including:
- Recommended tools and libraries. - Recommended tools and libraries.
+5
View File
@@ -12,9 +12,14 @@ http-body = "1.0"
http-body-util = "0.1" http-body-util = "0.1"
tower = "0.4" tower = "0.4"
futures-util = "0.3" futures-util = "0.3"
async-trait = "0.1"
tokio-stream = { version = "0.1", features = ["net"] } tokio-stream = { version = "0.1", features = ["net"] }
tokio = { version = "1.38", features = ["full"] } tokio = { version = "1.38", features = ["full"] }
http = "1.1" http = "1.1"
[build-dependencies] [build-dependencies]
tonic-build = "0.12" tonic-build = "0.12"
[features]
default = ["alloc"]
alloc = []
+51 -20
View File
@@ -1,22 +1,9 @@
// @generated by protoc-gen-roto — do not edit // @generated by protoc-gen-roto — do not edit
#[allow(unused_imports)] #[allow(unused_imports)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage}; use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use std::str; use core::str;
#[cfg(feature = "alloc")]
use bytes::{Bytes, BytesMut, Buf, BufMut}; use bytes::{Bytes, BytesMut, Buf, BufMut};
use tonic::{Request, Response, Status};
use tokio_stream::Stream;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::future::Future;
use tonic::body::BoxBody;
use tower::Service;
use futures_util::StreamExt;
use http_body_util::BodyExt;
use http_body::Body;
use crate::{BufferPool, StatusBody};
pub struct UnaryRequest<'a> { pub struct UnaryRequest<'a> {
accessor: roto_runtime::ProtoAccessor<'a>, accessor: roto_runtime::ProtoAccessor<'a>,
@@ -41,7 +28,7 @@ message_offset,
pub fn message(&self) -> roto_runtime::Result<&'a str> { pub fn message(&self) -> roto_runtime::Result<&'a str> {
let offset = self.message_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self.message_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) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn message_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn message_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -94,10 +81,12 @@ impl<'b> UnaryRequestBuilder<'b> {
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedUnaryRequest { pub struct OwnedUnaryRequest {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedUnaryRequest { impl roto_runtime::RotoOwned for OwnedUnaryRequest {
type Reader<'a> = UnaryRequest<'a>; type Reader<'a> = UnaryRequest<'a>;
fn reader(&self) -> UnaryRequest<'_> { fn reader(&self) -> UnaryRequest<'_> {
@@ -105,6 +94,7 @@ impl roto_runtime::RotoOwned for OwnedUnaryRequest {
} }
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedUnaryRequest { impl roto_runtime::RotoMessage for OwnedUnaryRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedUnaryRequest { data: buf }) Ok(OwnedUnaryRequest { data: buf })
@@ -138,7 +128,7 @@ reply_offset,
pub fn reply(&self) -> roto_runtime::Result<&'a str> { pub fn reply(&self) -> roto_runtime::Result<&'a str> {
let offset = self.reply_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self.reply_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) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn reply_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn reply_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -191,10 +181,12 @@ impl<'b> UnaryResponseBuilder<'b> {
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedUnaryResponse { pub struct OwnedUnaryResponse {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedUnaryResponse { impl roto_runtime::RotoOwned for OwnedUnaryResponse {
type Reader<'a> = UnaryResponse<'a>; type Reader<'a> = UnaryResponse<'a>;
fn reader(&self) -> UnaryResponse<'_> { fn reader(&self) -> UnaryResponse<'_> {
@@ -202,6 +194,7 @@ impl roto_runtime::RotoOwned for OwnedUnaryResponse {
} }
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedUnaryResponse { impl roto_runtime::RotoMessage for OwnedUnaryResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedUnaryResponse { data: buf }) Ok(OwnedUnaryResponse { data: buf })
@@ -235,7 +228,7 @@ query_offset,
pub fn query(&self) -> roto_runtime::Result<&'a str> { pub fn query(&self) -> roto_runtime::Result<&'a str> {
let offset = self.query_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self.query_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) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn query_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn query_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -288,10 +281,12 @@ impl<'b> StreamingRequestBuilder<'b> {
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedStreamingRequest { pub struct OwnedStreamingRequest {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedStreamingRequest { impl roto_runtime::RotoOwned for OwnedStreamingRequest {
type Reader<'a> = StreamingRequest<'a>; type Reader<'a> = StreamingRequest<'a>;
fn reader(&self) -> StreamingRequest<'_> { fn reader(&self) -> StreamingRequest<'_> {
@@ -299,6 +294,7 @@ impl roto_runtime::RotoOwned for OwnedStreamingRequest {
} }
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedStreamingRequest { impl roto_runtime::RotoMessage for OwnedStreamingRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedStreamingRequest { data: buf }) Ok(OwnedStreamingRequest { data: buf })
@@ -332,7 +328,7 @@ item_offset,
pub fn item(&self) -> roto_runtime::Result<&'a str> { pub fn item(&self) -> roto_runtime::Result<&'a str> {
let offset = self.item_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; let offset = self.item_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) core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
} }
pub fn item_or_default(&self) -> roto_runtime::Result<&'a str> { pub fn item_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -385,10 +381,12 @@ impl<'b> StreamingResponseBuilder<'b> {
} }
} }
#[cfg(feature = "alloc")]
pub struct OwnedStreamingResponse { pub struct OwnedStreamingResponse {
pub data: bytes::Bytes, pub data: bytes::Bytes,
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedStreamingResponse { impl roto_runtime::RotoOwned for OwnedStreamingResponse {
type Reader<'a> = StreamingResponse<'a>; type Reader<'a> = StreamingResponse<'a>;
fn reader(&self) -> StreamingResponse<'_> { fn reader(&self) -> StreamingResponse<'_> {
@@ -396,6 +394,7 @@ impl roto_runtime::RotoOwned for OwnedStreamingResponse {
} }
} }
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedStreamingResponse { impl roto_runtime::RotoMessage for OwnedStreamingResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> { fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedStreamingResponse { data: buf }) Ok(OwnedStreamingResponse { data: buf })
@@ -406,28 +405,60 @@ impl roto_runtime::RotoMessage for OwnedStreamingResponse {
} }
} }
#[tonic::async_trait]
#[cfg(feature = "alloc")]
use tonic::{Request, Response, Status};
#[cfg(feature = "alloc")]
use tokio_stream::Stream;
#[cfg(feature = "alloc")]
use std::pin::Pin;
#[cfg(feature = "alloc")]
use std::sync::Arc;
#[cfg(feature = "alloc")]
use std::task::{Context, Poll};
#[cfg(feature = "alloc")]
use std::future::Future;
#[cfg(feature = "alloc")]
use tonic::body::BoxBody;
#[cfg(feature = "alloc")]
use tower::Service;
#[cfg(feature = "alloc")]
use futures_util::StreamExt;
#[cfg(feature = "alloc")]
use http_body_util::BodyExt;
#[cfg(feature = "alloc")]
use http_body::Body;
#[cfg(feature = "alloc")]
use crate::{BufferPool, StatusBody};
#[cfg(feature = "alloc")]
#[async_trait::async_trait]
pub trait InteropService: Send + Sync + 'static { pub trait InteropService: Send + Sync + 'static {
async fn unary_call(&self, request: Request<OwnedUnaryRequest>) -> std::result::Result<Response<OwnedUnaryResponse>, Status>; async fn unary_call(&self, request: Request<OwnedUnaryRequest>) -> std::result::Result<Response<OwnedUnaryResponse>, Status>;
async fn streaming_call(&self, request: Request<OwnedStreamingRequest>) -> std::result::Result<Response<Pin<Box<dyn Stream<Item = std::result::Result<OwnedStreamingResponse, Status>> + Send>>>, Status>; async fn streaming_call(&self, request: Request<OwnedStreamingRequest>) -> std::result::Result<Response<Pin<Box<dyn Stream<Item = std::result::Result<OwnedStreamingResponse, Status>> + Send>>>, Status>;
} }
#[cfg(feature = "alloc")]
#[derive(Clone)] #[derive(Clone)]
pub struct InteropServiceServer { pub struct InteropServiceServer {
inner: Arc<dyn InteropService>, inner: Arc<dyn InteropService>,
pool: Arc<BufferPool>, pool: Arc<BufferPool>,
} }
#[cfg(feature = "alloc")]
impl InteropServiceServer { impl InteropServiceServer {
pub fn new(inner: Arc<dyn InteropService>, pool: Arc<BufferPool>) -> Self { pub fn new(inner: Arc<dyn InteropService>, pool: Arc<BufferPool>) -> Self {
Self { inner, pool } Self { inner, pool }
} }
} }
#[cfg(feature = "alloc")]
impl tonic::server::NamedService for InteropServiceServer { impl tonic::server::NamedService for InteropServiceServer {
const NAME: &'static str = "interop.InteropService"; const NAME: &'static str = "interop.InteropService";
} }
#[cfg(feature = "alloc")]
impl Service<http::Request<BoxBody>> for InteropServiceServer { impl Service<http::Request<BoxBody>> for InteropServiceServer {
type Response = http::Response<BoxBody>; type Response = http::Response<BoxBody>;
type Error = std::convert::Infallible; type Error = std::convert::Infallible;
+4
View File
@@ -0,0 +1,4 @@
// @generated by protoc-gen-roto — do not edit
#![allow(unused_imports)]
pub mod helloworld;
@@ -0,0 +1,783 @@
// @generated by protoc-gen-roto — do not edit
#[allow(unused_imports)]
use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage};
use core::str;
#[cfg(feature = "alloc")]
use bytes::{Bytes, BytesMut, Buf, BufMut};
use crate::google::protobuf::descriptor;
pub struct Version<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
major_offset: Option<usize>,
minor_offset: Option<usize>,
patch_offset: Option<usize>,
suffix_offset: Option<usize>,
}
impl<'a> Version<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut major_offset = None;
let mut minor_offset = None;
let mut patch_offset = None;
let mut suffix_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { major_offset = Some(offset); }
if tag.field_number == 2 { minor_offset = Some(offset); }
if tag.field_number == 3 { patch_offset = Some(offset); }
if tag.field_number == 4 { suffix_offset = Some(offset); }
}
Ok(Self {
accessor,
major_offset,
minor_offset,
patch_offset,
suffix_offset,
})
}
pub fn major(&self) -> roto_runtime::Result<i32> {
let offset = self.major_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)
}
pub fn major_or_default(&self) -> roto_runtime::Result<i32> {
self.major().or(Ok(0))
}
pub fn has_major(&self) -> bool { self.major_offset.is_some() }
pub fn minor(&self) -> roto_runtime::Result<i32> {
let offset = self.minor_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)
}
pub fn minor_or_default(&self) -> roto_runtime::Result<i32> {
self.minor().or(Ok(0))
}
pub fn has_minor(&self) -> bool { self.minor_offset.is_some() }
pub fn patch(&self) -> roto_runtime::Result<i32> {
let offset = self.patch_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)
}
pub fn patch_or_default(&self) -> roto_runtime::Result<i32> {
self.patch().or(Ok(0))
}
pub fn has_patch(&self) -> bool { self.patch_offset.is_some() }
pub fn suffix(&self) -> roto_runtime::Result<&'a str> {
let offset = self.suffix_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn suffix_or_default(&self) -> roto_runtime::Result<&'a str> {
self.suffix().or(Ok(""))
}
pub fn has_suffix(&self) -> bool { self.suffix_offset.is_some() }
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct VersionBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>,
major_written: bool,
minor_written: bool,
patch_written: bool,
suffix_written: bool,
}
impl<'b> VersionBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> VersionBuilder<'_> {
VersionBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
major_written: false,
minor_written: false,
patch_written: false,
suffix_written: false,
}
}
pub fn major(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(1, value)?;
self.major_written = true;
Ok(self)
}
pub fn minor(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(2, value)?;
self.minor_written = true;
Ok(self)
}
pub fn patch(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(3, value)?;
self.patch_written = true;
Ok(self)
}
pub fn suffix(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(4, value)?;
self.suffix_written = true;
Ok(self)
}
pub fn with(mut self, msg: &Version<'_>) -> 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.major_written,
2 => self.minor_written,
3 => self.patch_written,
4 => self.suffix_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedVersion {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedVersion {
type Reader<'a> = Version<'a>;
fn reader(&self) -> Version<'_> {
Version::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedVersion {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedVersion { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub struct CodeGeneratorRequest<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
file_to_generate_start: Option<usize>,
file_to_generate_end: Option<usize>,
parameter_offset: Option<usize>,
proto_file_start: Option<usize>,
proto_file_end: Option<usize>,
source_file_descriptors_start: Option<usize>,
source_file_descriptors_end: Option<usize>,
compiler_version_offset: Option<usize>,
}
impl<'a> CodeGeneratorRequest<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut file_to_generate_start = None;
let mut file_to_generate_end = None;
let mut parameter_offset = None;
let mut proto_file_start = None;
let mut proto_file_end = None;
let mut source_file_descriptors_start = None;
let mut source_file_descriptors_end = None;
let mut compiler_version_offset = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 {
if file_to_generate_start.is_none() { file_to_generate_start = Some(offset); }
file_to_generate_end = Some(offset);
}
if tag.field_number == 2 { parameter_offset = Some(offset); }
if tag.field_number == 15 {
if proto_file_start.is_none() { proto_file_start = Some(offset); }
proto_file_end = Some(offset);
}
if tag.field_number == 17 {
if source_file_descriptors_start.is_none() { source_file_descriptors_start = Some(offset); }
source_file_descriptors_end = Some(offset);
}
if tag.field_number == 3 { compiler_version_offset = Some(offset); }
}
Ok(Self {
accessor,
file_to_generate_start, file_to_generate_end,
parameter_offset,
proto_file_start, proto_file_end,
source_file_descriptors_start, source_file_descriptors_end,
compiler_version_offset,
})
}
pub fn file_to_generate(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.file_to_generate_start, self.file_to_generate_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(1, start, end),
_ => self.accessor.iter_repeated(1),
}
}
pub fn parameter(&self) -> roto_runtime::Result<&'a str> {
let offset = self.parameter_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn parameter_or_default(&self) -> roto_runtime::Result<&'a str> {
self.parameter().or(Ok(""))
}
pub fn has_parameter(&self) -> bool { self.parameter_offset.is_some() }
pub fn proto_file(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.proto_file_start, self.proto_file_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
_ => self.accessor.iter_repeated(15),
}
}
pub fn source_file_descriptors(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.source_file_descriptors_start, self.source_file_descriptors_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(17, start, end),
_ => self.accessor.iter_repeated(17),
}
}
pub fn compiler_version(&self) -> roto_runtime::Result<&'a [u8]> {
let offset = self.compiler_version_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes)
}
pub fn compiler_version_or_default(&self) -> roto_runtime::Result<&'a [u8]> {
self.compiler_version().or(Ok(&[]))
}
pub fn has_compiler_version(&self) -> bool { self.compiler_version_offset.is_some() }
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct CodeGeneratorRequestBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>,
file_to_generate_written: bool,
parameter_written: bool,
proto_file_written: bool,
source_file_descriptors_written: bool,
compiler_version_written: bool,
}
impl<'b> CodeGeneratorRequestBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> CodeGeneratorRequestBuilder<'_> {
CodeGeneratorRequestBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
file_to_generate_written: false,
parameter_written: false,
proto_file_written: false,
source_file_descriptors_written: false,
compiler_version_written: false,
}
}
pub fn file_to_generate(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.file_to_generate_written = true;
Ok(self)
}
pub fn parameter(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(2, value)?;
self.parameter_written = true;
Ok(self)
}
pub fn proto_file(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(15, value)?;
self.proto_file_written = true;
Ok(self)
}
pub fn source_file_descriptors(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(17, value)?;
self.source_file_descriptors_written = true;
Ok(self)
}
pub fn compiler_version(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(3, value)?;
self.compiler_version_written = true;
Ok(self)
}
pub fn with(mut self, msg: &CodeGeneratorRequest<'_>) -> 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.file_to_generate_written,
2 => self.parameter_written,
15 => self.proto_file_written,
17 => self.source_file_descriptors_written,
3 => self.compiler_version_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedCodeGeneratorRequest {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedCodeGeneratorRequest {
type Reader<'a> = CodeGeneratorRequest<'a>;
fn reader(&self) -> CodeGeneratorRequest<'_> {
CodeGeneratorRequest::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedCodeGeneratorRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedCodeGeneratorRequest { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
pub struct CodeGeneratorResponse<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
error_offset: Option<usize>,
supported_features_offset: Option<usize>,
minimum_edition_offset: Option<usize>,
maximum_edition_offset: Option<usize>,
file_start: Option<usize>,
file_end: Option<usize>,
}
impl<'a> CodeGeneratorResponse<'a> {
pub fn new(data: &'a [u8]) -> roto_runtime::Result<Self> {
let accessor = roto_runtime::ProtoAccessor::new(data)?;
let mut error_offset = None;
let mut supported_features_offset = None;
let mut minimum_edition_offset = None;
let mut maximum_edition_offset = None;
let mut file_start = None;
let mut file_end = None;
for item in accessor.fields() {
let (offset, tag, _) = item?;
if tag.field_number == 1 { error_offset = Some(offset); }
if tag.field_number == 2 { supported_features_offset = Some(offset); }
if tag.field_number == 3 { minimum_edition_offset = Some(offset); }
if tag.field_number == 4 { maximum_edition_offset = Some(offset); }
if tag.field_number == 15 {
if file_start.is_none() { file_start = Some(offset); }
file_end = Some(offset);
}
}
Ok(Self {
accessor,
error_offset,
supported_features_offset,
minimum_edition_offset,
maximum_edition_offset,
file_start, file_end,
})
}
pub fn error(&self) -> roto_runtime::Result<&'a str> {
let offset = self.error_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn error_or_default(&self) -> roto_runtime::Result<&'a str> {
self.error().or(Ok(""))
}
pub fn has_error(&self) -> bool { self.error_offset.is_some() }
pub fn supported_features(&self) -> roto_runtime::Result<u32> {
let offset = self.supported_features_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
roto_runtime::read_varint(bytes).map(|(v, _)| v as u32).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn supported_features_or_default(&self) -> roto_runtime::Result<u32> {
self.supported_features().or(Ok(0))
}
pub fn has_supported_features(&self) -> bool { self.supported_features_offset.is_some() }
pub fn minimum_edition(&self) -> roto_runtime::Result<i32> {
let offset = self.minimum_edition_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)
}
pub fn minimum_edition_or_default(&self) -> roto_runtime::Result<i32> {
self.minimum_edition().or(Ok(0))
}
pub fn has_minimum_edition(&self) -> bool { self.minimum_edition_offset.is_some() }
pub fn maximum_edition(&self) -> roto_runtime::Result<i32> {
let offset = self.maximum_edition_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)
}
pub fn maximum_edition_or_default(&self) -> roto_runtime::Result<i32> {
self.maximum_edition().or(Ok(0))
}
pub fn has_maximum_edition(&self) -> bool { self.maximum_edition_offset.is_some() }
pub fn file(&self) -> roto_runtime::RepeatedFieldIterator<'a> {
match (self.file_start, self.file_end) {
(Some(start), Some(end)) => self.accessor.iter_repeated_range(15, start, end),
_ => self.accessor.iter_repeated(15),
}
}
pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct CodeGeneratorResponseBuilder<'b> {
builder: roto_runtime::ProtoBuilder<'b>,
error_written: bool,
supported_features_written: bool,
minimum_edition_written: bool,
maximum_edition_written: bool,
file_written: bool,
}
impl<'b> CodeGeneratorResponseBuilder<'b> {
pub fn builder(buf: &mut [u8]) -> CodeGeneratorResponseBuilder<'_> {
CodeGeneratorResponseBuilder {
builder: roto_runtime::ProtoBuilder::new(buf),
error_written: false,
supported_features_written: false,
minimum_edition_written: false,
maximum_edition_written: false,
file_written: false,
}
}
pub fn error(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.error_written = true;
Ok(self)
}
pub fn supported_features(mut self, value: u64) -> roto_runtime::Result<Self> {
self.builder.write_varint(2, value)?;
self.supported_features_written = true;
Ok(self)
}
pub fn minimum_edition(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(3, value)?;
self.minimum_edition_written = true;
Ok(self)
}
pub fn maximum_edition(mut self, value: i32) -> roto_runtime::Result<Self> {
self.builder.write_int32(4, value)?;
self.maximum_edition_written = true;
Ok(self)
}
pub fn file(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(15, value)?;
self.file_written = true;
Ok(self)
}
pub fn with(mut self, msg: &CodeGeneratorResponse<'_>) -> 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.error_written,
2 => self.supported_features_written,
3 => self.minimum_edition_written,
4 => self.maximum_edition_written,
15 => self.file_written,
_ => false,
};
if !is_written {
self.builder.write_raw(raw_bytes)?;
}
}
Ok(self)
}
pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedCodeGeneratorResponse {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedCodeGeneratorResponse {
type Reader<'a> = CodeGeneratorResponse<'a>;
fn reader(&self) -> CodeGeneratorResponse<'_> {
CodeGeneratorResponse::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedCodeGeneratorResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedCodeGeneratorResponse { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
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: roto_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]) -> roto_runtime::Result<Self> {
let accessor = roto_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) -> roto_runtime::Result<&'a str> {
let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::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 has_name(&self) -> bool { self.name_offset.is_some() }
pub fn insertion_point(&self) -> roto_runtime::Result<&'a str> {
let offset = self.insertion_point_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn insertion_point_or_default(&self) -> roto_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) -> roto_runtime::Result<&'a str> {
let offset = self.content_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn content_or_default(&self) -> roto_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) -> roto_runtime::Result<&'a [u8]> {
let offset = self.generated_code_info_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
Ok(bytes)
}
pub fn generated_code_info_or_default(&self) -> roto_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) -> roto_runtime::RawFieldIterator<'a> {
self.accessor.raw_fields()
}
}
pub struct FileBuilder<'b> {
builder: roto_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: roto_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) -> roto_runtime::Result<Self> {
self.builder.write_string(1, value)?;
self.name_written = true;
Ok(self)
}
pub fn insertion_point(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(2, value)?;
self.insertion_point_written = true;
Ok(self)
}
pub fn content(mut self, value: &str) -> roto_runtime::Result<Self> {
self.builder.write_string(15, value)?;
self.content_written = true;
Ok(self)
}
pub fn generated_code_info(mut self, value: &[u8]) -> roto_runtime::Result<Self> {
self.builder.write_bytes(16, value)?;
self.generated_code_info_written = true;
Ok(self)
}
pub fn with(mut self, msg: &File<'_>) -> 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.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) -> roto_runtime::Result<&'b mut [u8]> {
self.builder.finish()
}
}
#[cfg(feature = "alloc")]
pub struct OwnedFile {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedFile {
type Reader<'a> = File<'a>;
fn reader(&self) -> File<'_> {
File::new(&self.data).expect("failed to create reader")
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedFile {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedFile { data: buf })
}
fn bytes(&self) -> bytes::Bytes {
self.data.clone()
}
}
}
use crate::google::protobuf::descriptor;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5
View File
@@ -1,5 +1,8 @@
#![no_std] #![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")] #[cfg(feature = "std")]
extern crate std; extern crate std;
@@ -438,6 +441,8 @@ impl<'a> Iterator for RawFieldIterator<'a> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[cfg(feature = "alloc")]
use alloc::{vec, vec::{Vec}};
#[test] #[test]
fn test_varint_read_write() { fn test_varint_read_write() {
+229
View File
@@ -0,0 +1,229 @@
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2024 which implies `resolver = "3"`
|
= note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
= note: to use the edition 2024 resolver, specify `workspace.resolver = "3"` in the workspace root's manifest
= note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:5:7
|
5 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:184:7
|
184 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:189:7
|
189 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:197:7
|
197 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:384:7
|
384 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:389:7
|
389 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:397:7
|
397 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:684:7
|
684 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:689:7
|
689 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:697:7
|
697 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:909:7
|
909 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:914:7
|
914 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:922:7
|
922 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:1209:7
|
1209 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:1214:7
|
1214 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:1222:7
|
1222 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:1359:7
|
1359 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:1364:7
|
1364 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `alloc`
--> benches/src/hackers.rs:1372:7
|
1372 | #[cfg(feature = "alloc")]
| ^^^^^^^^^^^^^^^^^ help: remove the condition
|
= note: no expected values for `feature`
= help: consider adding `alloc` as a feature in `Cargo.toml`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
Compiling no_std_test v0.1.0 (/opt/workspace/examples/no_std_test)
warning: `roto-benches` (lib) generated 19 warnings
Compiling roto-tonic v0.1.0 (/opt/workspace/roto-tonic)
warning: `roto-benches` (lib test) generated 19 warnings (19 duplicates)
Compiling tonic v0.12.3
error: failed to run custom build command for `roto-tonic v0.1.0 (/opt/workspace/roto-tonic)`
Caused by:
process didn't exit successfully: `/opt/workspace/target/debug/build/roto-tonic-3195fff626ab2304/build-script-build` (exit status: 101)
--- stdout
cargo:rerun-if-changed=proto/interop.proto
cargo:rerun-if-changed=proto
--- stderr
thread 'main' (391) panicked at roto-tonic/build.rs:9:45:
Failed to compile protos with tonic-build: Custom { kind: NotFound, error: "Could not find `protoc`. If `protoc` is installed, try setting the `PROTOC` environment variable to the path of the `protoc` binary. To install it on Debian, run `apt-get install protobuf-compiler`. It is also available at https://github.com/protocolbuffers/protobuf/releases For more information: https://docs.rs/prost-build/#sourcing-protoc" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error[E0152]: found duplicate lang item `panic_impl`
--> examples/no_std_test/src/main.rs:7:1
|
7 | / fn panic(_info: &PanicInfo) -> ! {
8 | | loop {}
9 | | }
| |_^
|
= note: the lang item is first defined in crate `std` (which `test` depends on)
= note: first definition in `std` loaded from /root/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib/libstd-30b8a9ba02153abd.so, /root/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib/libstd-30b8a9ba02153abd.rlib, /root/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib/libstd-30b8a9ba02153abd.rmeta
= note: second definition in the local crate (`no_std_test`)
For more information about this error, try `rustc --explain E0152`.
error: could not compile `no_std_test` (bin "no_std_test" test) due to 1 previous error