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.
This commit is contained in:
2026-05-19 21:55:18 -07:00
parent 6910f11d69
commit 117cbf812b
7 changed files with 201 additions and 52 deletions
+4
View File
@@ -19,3 +19,7 @@ http = "1.1"
[build-dependencies]
tonic-build = "0.12"
[features]
default = ["alloc"]
alloc = []
+53 -17
View File
@@ -2,19 +2,9 @@
#[allow(unused_imports)]
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 tonic::{Request, Response, Status};
use std::sync::Arc;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::future::Future;
use tower::Service;
use tonic::body::BoxBody;
use tokio_stream::Stream;
use crate::{BufferPool, StatusBody};
use async_trait::async_trait;
use http_body_util::BodyExt;
pub struct UnaryRequest<'a> {
accessor: roto_runtime::ProtoAccessor<'a>,
@@ -39,7 +29,7 @@ message_offset,
pub fn message(&self) -> roto_runtime::Result<&'a str> {
let offset = self.message_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn message_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -92,10 +82,12 @@ impl<'b> UnaryRequestBuilder<'b> {
}
}
#[cfg(feature = "alloc")]
pub struct OwnedUnaryRequest {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedUnaryRequest {
type Reader<'a> = UnaryRequest<'a>;
fn reader(&self) -> UnaryRequest<'_> {
@@ -103,6 +95,7 @@ impl roto_runtime::RotoOwned for OwnedUnaryRequest {
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedUnaryRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedUnaryRequest { data: buf })
@@ -136,7 +129,7 @@ reply_offset,
pub fn reply(&self) -> roto_runtime::Result<&'a str> {
let offset = self.reply_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn reply_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -189,10 +182,12 @@ impl<'b> UnaryResponseBuilder<'b> {
}
}
#[cfg(feature = "alloc")]
pub struct OwnedUnaryResponse {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedUnaryResponse {
type Reader<'a> = UnaryResponse<'a>;
fn reader(&self) -> UnaryResponse<'_> {
@@ -200,6 +195,7 @@ impl roto_runtime::RotoOwned for OwnedUnaryResponse {
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedUnaryResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedUnaryResponse { data: buf })
@@ -233,7 +229,7 @@ query_offset,
pub fn query(&self) -> roto_runtime::Result<&'a str> {
let offset = self.query_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn query_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -286,10 +282,12 @@ impl<'b> StreamingRequestBuilder<'b> {
}
}
#[cfg(feature = "alloc")]
pub struct OwnedStreamingRequest {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedStreamingRequest {
type Reader<'a> = StreamingRequest<'a>;
fn reader(&self) -> StreamingRequest<'_> {
@@ -297,6 +295,7 @@ impl roto_runtime::RotoOwned for OwnedStreamingRequest {
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedStreamingRequest {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedStreamingRequest { data: buf })
@@ -330,7 +329,7 @@ item_offset,
pub fn item(&self) -> roto_runtime::Result<&'a str> {
let offset = self.item_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?;
let (bytes, _) = self.accessor.get_value_at(offset)?;
std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
core::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation)
}
pub fn item_or_default(&self) -> roto_runtime::Result<&'a str> {
@@ -383,10 +382,12 @@ impl<'b> StreamingResponseBuilder<'b> {
}
}
#[cfg(feature = "alloc")]
pub struct OwnedStreamingResponse {
pub data: bytes::Bytes,
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoOwned for OwnedStreamingResponse {
type Reader<'a> = StreamingResponse<'a>;
fn reader(&self) -> StreamingResponse<'_> {
@@ -394,6 +395,7 @@ impl roto_runtime::RotoOwned for OwnedStreamingResponse {
}
}
#[cfg(feature = "alloc")]
impl roto_runtime::RotoMessage for OwnedStreamingResponse {
fn decode(buf: bytes::Bytes) -> roto_runtime::Result<Self> {
Ok(OwnedStreamingResponse { data: buf })
@@ -405,28 +407,62 @@ impl roto_runtime::RotoMessage for OwnedStreamingResponse {
}
#[async_trait]
// @generated by protoc-gen-roto — do not edit
#[allow(unused_imports)]
#[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 {
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>;
}
#[cfg(feature = "alloc")]
#[derive(Clone)]
pub struct InteropServiceServer {
inner: Arc<dyn InteropService>,
pool: Arc<BufferPool>,
}
#[cfg(feature = "alloc")]
impl InteropServiceServer {
pub fn new(inner: Arc<dyn InteropService>, pool: Arc<BufferPool>) -> Self {
Self { inner, pool }
}
}
#[cfg(feature = "alloc")]
impl tonic::server::NamedService for InteropServiceServer {
const NAME: &'static str = "interop.InteropService";
}
#[cfg(feature = "alloc")]
impl Service<http::Request<BoxBody>> for InteropServiceServer {
type Response = http::Response<BoxBody>;
type Error = std::convert::Infallible;