feat: Add IntoRequest and IntoStreamingRequest traits (#66)

This commit is contained in:
Juan Alvarez
2019-10-29 16:09:08 -04:00
committed by Lucio Franco
parent af5754bd43
commit 4bb087b5ff
3 changed files with 142 additions and 17 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ pub use async_trait::async_trait;
#[doc(inline)]
pub use codec::Streaming;
pub use request::Request;
pub use request::{IntoRequest, IntoStreamingRequest, Request};
pub use response::Response;
pub use status::{Code, Status};
+121
View File
@@ -1,4 +1,5 @@
use crate::metadata::MetadataMap;
use futures_core::Stream;
/// A gRPC request and metadata from an RPC call.
#[derive(Debug)]
@@ -7,6 +8,84 @@ pub struct Request<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> {
/// 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 {}
}