Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add IntoRequest and IntoStreamingRequest traits #66

Merged
merged 32 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d6dd4ed
small tweaks, typos
alce Sep 25, 2019
dc7daca
Merge branch 'master' of github.com:LucioFranco/tonic
alce Sep 25, 2019
96c9519
Merge branch 'master' of github.com:alce/tonic
alce Sep 30, 2019
d11d7b6
pin all alpha dependencies
alce Oct 1, 2019
cb84a13
Merge branch 'master' of github.com:LucioFranco/tonic
alce Oct 1, 2019
481c3a9
Merge branch 'master' of github.com:hyperium/tonic
alce Oct 2, 2019
0ad4de1
Merge branch 'master' of github.com:hyperium/tonic
alce Oct 2, 2019
30142bd
Merge branch 'master' of github.com:hyperium/tonic
alce Oct 2, 2019
8313341
Merge branch 'master' of github.com:hyperium/tonic
alce Oct 8, 2019
78e58bf
Merge branch 'master' of github.com:alce/tonic
alce Oct 9, 2019
0bbd595
Merge branch 'master' of https://github.com/hyperium/tonic
alce Oct 10, 2019
2d86038
add IntoRequest and IntoStreamingRequest traits
alce Oct 10, 2019
8a5096b
Merge branch 'master' of github.com:hyperium/tonic
alce Oct 10, 2019
58d4238
RequestMessage marker trait. generate more compact code
alce Oct 10, 2019
bfa3e9b
improve naming
alce Oct 12, 2019
d23ec04
fmt
alce Oct 12, 2019
405b5e3
fix interop crate
alce Oct 15, 2019
d40ac7e
hide RequestMessage trait from docs
alce Oct 15, 2019
1acf426
use impl Trait instead of type parameter
alce Oct 18, 2019
0e9fe70
remove RequestMessage trait
alce Oct 18, 2019
3f6ff67
Merge branch 'master' of github.com:hyperium/tonic
alce Oct 19, 2019
0e52d8e
Merge branch 'master' into intorequest
alce Oct 19, 2019
03d7a16
conflicts
alce Oct 19, 2019
4439002
Merge branch 'intorequest' of github.com:alce/tonic into intorequest
alce Oct 19, 2019
878120c
document IntoRequest
alce Oct 19, 2019
2f93f33
document IntoStreamingRequest
alce Oct 22, 2019
0528352
Merge branch 'master' into intorequest
alce Oct 23, 2019
adbbe8c
remove IntoRequest in favor of From impl
alce Oct 24, 2019
b32b4e9
Merge branch 'intorequest' of github.com:alce/tonic into intorequest
alce Oct 24, 2019
9a9ee93
seal IntoStreamingRequest
alce Oct 24, 2019
8802192
remove From<T> for Request, implement IntoRequest instead
alce Oct 29, 2019
7017f97
improve docs
alce Oct 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 deletions tonic-build/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,14 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream {
let (request, response) = crate::replace_wellknown(proto, &method);

quote! {
pub async fn #ident(&mut self, request: tonic::Request<#request>)
-> Result<tonic::Response<#response>, tonic::Status> {
pub async fn #ident(
&mut self,
request: impl tonic::IntoRequest<#request>,
) -> Result<tonic::Response<#response>, tonic::Status> {
self.ready().await?;
let codec = tonic::codec::ProstCodec::new();
let path = http::uri::PathAndQuery::from_static(#path);
self.inner.unary(request, path, codec).await
self.inner.unary(request.into_request(), path, codec).await
}
}
}
Expand All @@ -115,12 +117,14 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke
let (request, response) = crate::replace_wellknown(proto, &method);

quote! {
pub async fn #ident(&mut self, request: tonic::Request<#request>)
-> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
pub async fn #ident(
&mut self,
request: impl tonic::IntoRequest<#request>,
) -> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
self.ready().await?;
let codec = tonic::codec::ProstCodec::new();
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
}
}
}
Expand All @@ -131,14 +135,14 @@ fn generate_client_streaming(method: &Method, proto: &str, path: String) -> Toke
let (request, response) = crate::replace_wellknown(proto, &method);

quote! {
pub async fn #ident<S>(&mut self, request: tonic::Request<S>)
-> Result<tonic::Response<#response>, tonic::Status>
where S: Stream<Item = #request> + Send + 'static,
{
pub async fn #ident(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = #request>
) -> Result<tonic::Response<#response>, tonic::Status> {
self.ready().await?;
let codec = tonic::codec::ProstCodec::new();
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
}
}
}
Expand All @@ -149,14 +153,14 @@ fn generate_streaming(method: &Method, proto: &str, path: String) -> TokenStream
let (request, response) = crate::replace_wellknown(proto, &method);

quote! {
pub async fn #ident<S>(&mut self, request: tonic::Request<S>)
-> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status>
where S: Stream<Item = #request> + Send + 'static,
{
pub async fn #ident(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = #request>
) -> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
self.ready().await?;
let codec = tonic::codec::ProstCodec::new();
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
}
}
}
2 changes: 1 addition & 1 deletion tonic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down
121 changes: 121 additions & 0 deletions tonic/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::metadata::MetadataMap;
use futures_core::Stream;

/// A gRPC request and metadata from an RPC call.
#[derive(Debug)]
Expand All @@ -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 {}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

/// ```
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.
///
Expand Down Expand Up @@ -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 {}
}