feat: Add IntoRequest and IntoStreamingRequest traits (#66)
This commit is contained in:
committed by
Lucio Franco
parent
af5754bd43
commit
4bb087b5ff
+20
-16
@@ -99,12 +99,14 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream {
|
|||||||
let (request, response) = crate::replace_wellknown(proto, &method);
|
let (request, response) = crate::replace_wellknown(proto, &method);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub async fn #ident(&mut self, request: tonic::Request<#request>)
|
pub async fn #ident(
|
||||||
-> Result<tonic::Response<#response>, tonic::Status> {
|
&mut self,
|
||||||
|
request: impl tonic::IntoRequest<#request>,
|
||||||
|
) -> Result<tonic::Response<#response>, tonic::Status> {
|
||||||
self.ready().await?;
|
self.ready().await?;
|
||||||
let codec = tonic::codec::ProstCodec::new();
|
let codec = tonic::codec::ProstCodec::new();
|
||||||
let path = http::uri::PathAndQuery::from_static(#path);
|
let path = http::uri::PathAndQuery::from_static(#path);
|
||||||
self.inner.unary(request, path, codec).await
|
self.inner.unary(request.into_request(), path, codec).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,12 +117,14 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke
|
|||||||
let (request, response) = crate::replace_wellknown(proto, &method);
|
let (request, response) = crate::replace_wellknown(proto, &method);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub async fn #ident(&mut self, request: tonic::Request<#request>)
|
pub async fn #ident(
|
||||||
-> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
|
&mut self,
|
||||||
|
request: impl tonic::IntoRequest<#request>,
|
||||||
|
) -> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
|
||||||
self.ready().await?;
|
self.ready().await?;
|
||||||
let codec = tonic::codec::ProstCodec::new();
|
let codec = tonic::codec::ProstCodec::new();
|
||||||
let path = http::uri::PathAndQuery::from_static(#path);
|
let path = http::uri::PathAndQuery::from_static(#path);
|
||||||
self.inner.server_streaming(request, path, codec).await
|
self.inner.server_streaming(request.into_request(), path, codec).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,14 +135,14 @@ fn generate_client_streaming(method: &Method, proto: &str, path: String) -> Toke
|
|||||||
let (request, response) = crate::replace_wellknown(proto, &method);
|
let (request, response) = crate::replace_wellknown(proto, &method);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub async fn #ident<S>(&mut self, request: tonic::Request<S>)
|
pub async fn #ident(
|
||||||
-> Result<tonic::Response<#response>, tonic::Status>
|
&mut self,
|
||||||
where S: Stream<Item = #request> + Send + 'static,
|
request: impl tonic::IntoStreamingRequest<Message = #request>
|
||||||
{
|
) -> Result<tonic::Response<#response>, tonic::Status> {
|
||||||
self.ready().await?;
|
self.ready().await?;
|
||||||
let codec = tonic::codec::ProstCodec::new();
|
let codec = tonic::codec::ProstCodec::new();
|
||||||
let path = http::uri::PathAndQuery::from_static(#path);
|
let path = http::uri::PathAndQuery::from_static(#path);
|
||||||
self.inner.client_streaming(request, path, codec).await
|
self.inner.client_streaming(request.into_streaming_request(), path, codec).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,14 +153,14 @@ fn generate_streaming(method: &Method, proto: &str, path: String) -> TokenStream
|
|||||||
let (request, response) = crate::replace_wellknown(proto, &method);
|
let (request, response) = crate::replace_wellknown(proto, &method);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub async fn #ident<S>(&mut self, request: tonic::Request<S>)
|
pub async fn #ident(
|
||||||
-> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status>
|
&mut self,
|
||||||
where S: Stream<Item = #request> + Send + 'static,
|
request: impl tonic::IntoStreamingRequest<Message = #request>
|
||||||
{
|
) -> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
|
||||||
self.ready().await?;
|
self.ready().await?;
|
||||||
let codec = tonic::codec::ProstCodec::new();
|
let codec = tonic::codec::ProstCodec::new();
|
||||||
let path = http::uri::PathAndQuery::from_static(#path);
|
let path = http::uri::PathAndQuery::from_static(#path);
|
||||||
self.inner.streaming(request, path, codec).await
|
self.inner.streaming(request.into_streaming_request(), path, codec).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -98,7 +98,7 @@ pub use async_trait::async_trait;
|
|||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use codec::Streaming;
|
pub use codec::Streaming;
|
||||||
pub use request::Request;
|
pub use request::{IntoRequest, IntoStreamingRequest, Request};
|
||||||
pub use response::Response;
|
pub use response::Response;
|
||||||
pub use status::{Code, Status};
|
pub use status::{Code, Status};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::metadata::MetadataMap;
|
use crate::metadata::MetadataMap;
|
||||||
|
use futures_core::Stream;
|
||||||
|
|
||||||
/// A gRPC request and metadata from an RPC call.
|
/// A gRPC request and metadata from an RPC call.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -7,6 +8,84 @@ pub struct Request<T> {
|
|||||||
message: T,
|
message: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait implemented by RPC request types.
|
||||||
|
///
|
||||||
|
/// Types implementing this trait can be used as arguments to client RPC
|
||||||
|
/// methods without explicitly wrapping them into `tonic::Request`s. The purpose
|
||||||
|
/// is to make client calls slightly more convenient to write.
|
||||||
|
///
|
||||||
|
/// Tonic's code generation and blanket implementations handle this for you,
|
||||||
|
/// so it is not necessary to implement this trait directly.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Given the following gRPC method definition:
|
||||||
|
/// ```proto
|
||||||
|
/// rpc GetFeature(Point) returns (Feature) {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// we can call `get_feature` in two equivalent ways:
|
||||||
|
/// ```rust
|
||||||
|
/// # pub struct Point {}
|
||||||
|
/// # pub struct Client {}
|
||||||
|
/// # impl Client {
|
||||||
|
/// # fn get_feature(&self, r: impl tonic::IntoRequest<Point>) {}
|
||||||
|
/// # }
|
||||||
|
/// # let client = Client {};
|
||||||
|
/// use tonic::Request;
|
||||||
|
///
|
||||||
|
/// client.get_feature(Point {});
|
||||||
|
/// client.get_feature(Request::new(Point {}));
|
||||||
|
/// ```
|
||||||
|
pub trait IntoRequest<T>: sealed::Sealed {
|
||||||
|
/// Wrap the input message `T` in a `tonic::Request`
|
||||||
|
fn into_request(self) -> Request<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait implemented by RPC streaming request types.
|
||||||
|
///
|
||||||
|
/// Types implementing this trait can be used as arguments to client streaming
|
||||||
|
/// RPC methods without explicitly wrapping them into `tonic::Request`s. The
|
||||||
|
/// purpose is to make client calls slightly more convenient to write.
|
||||||
|
///
|
||||||
|
/// Tonic's code generation and blanket implementations handle this for you,
|
||||||
|
/// so it is not necessary to implement this trait directly.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Given the following gRPC service method definition:
|
||||||
|
/// ```proto
|
||||||
|
/// rpc RecordRoute(stream Point) returns (RouteSummary) {}
|
||||||
|
/// ```
|
||||||
|
/// we can call `record_route` in two equivalent ways:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #[derive(Clone)]
|
||||||
|
/// # pub struct Point {};
|
||||||
|
/// # pub struct Client {};
|
||||||
|
/// # impl Client {
|
||||||
|
/// # fn record_route(&self, r: impl tonic::IntoStreamingRequest<Message = Point>) {}
|
||||||
|
/// # }
|
||||||
|
/// # let client = Client {};
|
||||||
|
/// use tonic::Request;
|
||||||
|
/// use futures_util::stream;
|
||||||
|
///
|
||||||
|
/// let messages = vec![Point {}, Point {}];
|
||||||
|
///
|
||||||
|
/// client.record_route(Request::new(stream::iter(messages.clone())));
|
||||||
|
/// client.record_route(stream::iter(messages));
|
||||||
|
/// ```
|
||||||
|
pub trait IntoStreamingRequest: sealed::Sealed {
|
||||||
|
/// The RPC request stream type
|
||||||
|
type Stream: Stream<Item = Self::Message> + Send + 'static;
|
||||||
|
|
||||||
|
/// The RPC request type
|
||||||
|
type Message;
|
||||||
|
|
||||||
|
/// Wrap the stream of messages in a `tonic::Request`
|
||||||
|
fn into_streaming_request(self) -> Request<Self::Stream>;
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Request<T> {
|
impl<T> Request<T> {
|
||||||
/// Create a new gRPC request.
|
/// Create a new gRPC request.
|
||||||
///
|
///
|
||||||
@@ -88,3 +167,45 @@ impl<T> Request<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> IntoRequest<T> for T {
|
||||||
|
fn into_request(self) -> Request<Self> {
|
||||||
|
Request::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoRequest<T> for Request<T> {
|
||||||
|
fn into_request(self) -> Request<T> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoStreamingRequest for T
|
||||||
|
where
|
||||||
|
T: Stream + Send + 'static,
|
||||||
|
{
|
||||||
|
type Stream = T;
|
||||||
|
type Message = T::Item;
|
||||||
|
|
||||||
|
fn into_streaming_request(self) -> Request<Self> {
|
||||||
|
Request::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoStreamingRequest for Request<T>
|
||||||
|
where
|
||||||
|
T: Stream + Send + 'static,
|
||||||
|
{
|
||||||
|
type Stream = T;
|
||||||
|
type Message = T::Item;
|
||||||
|
|
||||||
|
fn into_streaming_request(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> sealed::Sealed for T {}
|
||||||
|
|
||||||
|
mod sealed {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user