From d6dd4ed53fe574864f9b2452e0ed04c96ad855c1 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Tue, 24 Sep 2019 22:46:17 -0500 Subject: [PATCH 01/16] small tweaks, typos --- tonic/src/client/grpc.rs | 4 ++-- tonic/src/codec/decode.rs | 4 ++-- tonic/src/metadata/map.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tonic/src/client/grpc.rs b/tonic/src/client/grpc.rs index f4987964a..0df98a218 100644 --- a/tonic/src/client/grpc.rs +++ b/tonic/src/client/grpc.rs @@ -22,8 +22,8 @@ use std::fmt; /// Each request method takes a [`Request`], a [`PathAndQuery`], and a /// [`Codec`]. The request contains the message to send via the /// [`Codec::encoder`]. The path determines the fully qualified path -/// that will be appened to the outgoing uri. The path must follow -/// the convetions explained in the [gRPC protocol definition] under `Path →`. An +/// that will be append to the outgoing uri. The path must follow +/// the conventions explained in the [gRPC protocol definition] under `Path →`. An /// example of this path could look like `/greeter.Greeter/SayHello`. /// /// [gRPC protocol definition]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests diff --git a/tonic/src/codec/decode.rs b/tonic/src/codec/decode.rs index 8169ac4b7..117ed64b3 100644 --- a/tonic/src/codec/decode.rs +++ b/tonic/src/codec/decode.rs @@ -101,7 +101,7 @@ impl Streaming { /// Fetch the trailing metadata. /// - /// This will drain the stream of all its messages to recieve the trailing + /// This will drain the stream of all its messages to receive the trailing /// metadata. If [`Streaming::message`] returns `None` then this function /// will not need to poll for trailers since the body was totally consumed. pub async fn trailers(&mut self) -> Result, Status> { @@ -192,7 +192,7 @@ impl Stream for Streaming { fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { loop { // TODO: implement the ability to poll trailers when we _know_ that - // the comnsumer of this stream will only poll for the first message. + // the consumer of this stream will only poll for the first message. // This means we skip the poll_trailers step. match self.decode_chunk()? { Some(item) => return Poll::Ready(Some(Ok(item))), diff --git a/tonic/src/metadata/map.rs b/tonic/src/metadata/map.rs index b14baa96e..36483da39 100644 --- a/tonic/src/metadata/map.rs +++ b/tonic/src/metadata/map.rs @@ -217,7 +217,7 @@ impl MetadataMap { /// Convert an HTTP HeaderMap to a MetadataMap pub fn from_headers(headers: http::HeaderMap) -> Self { - MetadataMap { headers: headers } + MetadataMap { headers } } /// Convert a MetadataMap into a HTTP HeaderMap From d11d7b62db28aec748022a873f2f56b686de4138 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Tue, 1 Oct 2019 14:33:18 -0500 Subject: [PATCH 02/16] pin all alpha dependencies --- tonic-examples/Cargo.toml | 2 +- tonic-interop/Cargo.toml | 4 ++-- tonic/Cargo.toml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tonic-examples/Cargo.toml b/tonic-examples/Cargo.toml index 24f08ae04..78c34c306 100644 --- a/tonic-examples/Cargo.toml +++ b/tonic-examples/Cargo.toml @@ -54,7 +54,7 @@ tokio = "=0.2.0-alpha.6" futures-preview = { version = "=0.3.0-alpha.19", default-features = false, features = ["alloc"]} async-stream = "0.1.2" http = "0.1" -tower = "0.3.0-alpha.2" +tower = "=0.3.0-alpha.2" # Required for routeguide serde = { version = "1.0", features = ["derive"] } diff --git a/tonic-interop/Cargo.toml b/tonic-interop/Cargo.toml index 410f3685e..5ede3a343 100644 --- a/tonic-interop/Cargo.toml +++ b/tonic-interop/Cargo.toml @@ -22,8 +22,8 @@ http = "0.1" futures-core-preview = "=0.3.0-alpha.19" futures-util-preview = "=0.3.0-alpha.19" async-stream = "0.1.2" -tower = "0.3.0-alpha.2" -http-body = "0.2.0-alpha.2" +tower = "=0.3.0-alpha.2" +http-body = "=0.2.0-alpha.2" console = "0.7" structopt = "0.2" diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index 117b53ec6..299ec4257 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -49,7 +49,7 @@ percent-encoding = "1.0.1" tower-service = "=0.3.0-alpha.2" tokio-codec = "=0.2.0-alpha.6" async-stream = "0.1.2" -http-body = "0.2.0-alpha.3" +http-body = "=0.2.0-alpha.2" pin-project = "^0.4" # prost @@ -60,7 +60,7 @@ prost-derive = { version = "0.5", optional = true } async-trait = { version = "0.1.13", optional = true } # transport -hyper = { version = "0.13.0-alpha.3", features = ["unstable-stream"], optional = true } +hyper = { version = "=0.13.0-alpha.3", features = ["unstable-stream"], optional = true } tokio = { version = "=0.2.0-alpha.6", default-features = false, features = ["tcp"], optional = true } tower = { version = "=0.3.0-alpha.2", optional = true} tower-make = "=0.3.0-alpha.2a" @@ -73,4 +73,4 @@ tokio-openssl = { version = "=0.4.0-alpha.6", optional = true } openssl1 = { package = "openssl", version = "0.10", optional = true } # rustls -tokio-rustls = { version = "0.12.0-alpha.4", optional = true } +tokio-rustls = { version = "=0.12.0-alpha.4", optional = true } From 2d86038dfb567dbb26435c9b684dd44e1d3a789c Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Thu, 10 Oct 2019 13:02:28 -0500 Subject: [PATCH 03/16] add IntoRequest and IntoStreamingRequest traits --- Cargo.toml | 2 +- tonic-build/src/client.rs | 36 +++++++++++---------- tonic-build/src/lib.rs | 32 +++++++++++++++++++ tonic-examples/src/helloworld/client.rs | 4 +-- tonic-examples/src/routeguide/client.rs | 9 ++---- tonic/src/lib.rs | 2 +- tonic/src/request.rs | 42 +++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bbcce3dc2..862b38ba8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,5 @@ members = [ "tonic", "tonic-build", "tonic-examples", - "tonic-interop", +# "tonic-interop", ] diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index a5dec9d1f..89bcc34b1 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -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::Status> { + pub async fn #ident> ( + &mut self, + request: R, + ) -> Result, 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 } } } @@ -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::Status> { + pub async fn #ident>( + &mut self, + request: R + ) -> Result>, 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 } } } @@ -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(&mut self, request: tonic::Request) - -> Result, tonic::Status> - where S: Stream + Send + 'static, - { + pub async fn #ident>( + &mut self, + request: S + ) -> Result, 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 } } } @@ -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(&mut self, request: tonic::Request) - -> Result>, tonic::Status> - where S: Stream + Send + 'static, - { + pub async fn #ident>( + &mut self, + request: S + ) -> Result>, 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 } } } diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index a42ebbdcc..34f4bda1c 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -219,6 +219,7 @@ struct ServiceGenerator { builder: Builder, clients: TokenStream, servers: TokenStream, + into_request_impls: TokenStream, } impl ServiceGenerator { @@ -227,6 +228,7 @@ impl ServiceGenerator { builder, clients: TokenStream::default(), servers: TokenStream::default(), + into_request_impls: TokenStream::default(), } } } @@ -243,14 +245,19 @@ impl prost_build::ServiceGenerator for ServiceGenerator { if self.builder.build_client { let client = client::generate(&service, path); self.clients.extend(client); + + let tokens = generate_into_request_implementations(&service); + self.into_request_impls.extend(tokens); } } fn finalize(&mut self, buf: &mut String) { if self.builder.build_client && !self.clients.is_empty() { let clients = &self.clients; + let into_request_impls = &self.into_request_impls; let client_service = quote::quote! { + #into_request_impls /// Generated client implementations. pub mod client { #![allow(unused_variables, dead_code, missing_docs)] @@ -329,3 +336,28 @@ fn replace_wellknown(proto_path: &str, method: &Method) -> (TokenStream, TokenSt (request, response) } + +fn generate_into_request_implementations(service: &prost_build::Service) -> TokenStream { + use std::collections::HashSet; + + service + .methods + .iter() + .fold(HashSet::new(), |mut set, method| { + set.insert(method.input_type.clone()); + set + }) + .iter() + .fold(TokenStream::new(), |mut stream, input| { + let request: syn::Type = syn::parse_str(&input).unwrap(); + stream.extend(quote::quote! { + impl tonic::IntoRequest for #request { + type Message = Self; + fn into_request(self) -> tonic::Request { + tonic::Request::new(self) + } + } + }); + stream + }) +} diff --git a/tonic-examples/src/helloworld/client.rs b/tonic-examples/src/helloworld/client.rs index 4676e9519..cb8a68614 100644 --- a/tonic-examples/src/helloworld/client.rs +++ b/tonic-examples/src/helloworld/client.rs @@ -8,9 +8,9 @@ use hello_world::{client::GreeterClient, HelloRequest}; async fn main() -> Result<(), Box> { let mut client = GreeterClient::connect("http://[::1]:50051")?; - let request = tonic::Request::new(HelloRequest { + let request = HelloRequest { name: "hello".into(), - }); + }; let response = client.say_hello(request).await?; diff --git a/tonic-examples/src/routeguide/client.rs b/tonic-examples/src/routeguide/client.rs index 942c39fb1..54c607b68 100644 --- a/tonic-examples/src/routeguide/client.rs +++ b/tonic-examples/src/routeguide/client.rs @@ -2,7 +2,6 @@ use futures::TryStreamExt; use route_guide::{Point, RouteNote}; use std::time::{Duration, Instant}; use tokio::timer::Interval; -use tonic::Request; pub mod route_guide { tonic::include_proto!("routeguide"); @@ -17,10 +16,10 @@ async fn main() -> Result<(), Box> { let start = Instant::now(); let response = client - .get_feature(Request::new(Point { + .get_feature(Point { latitude: 409146138, longitude: -746188906, - })) + }) .await?; println!("FEATURE = {:?}", response); @@ -42,9 +41,7 @@ async fn main() -> Result<(), Box> { } }; - let request = Request::new(outbound); - - let response = client.route_chat(request).await?; + let response = client.route_chat(outbound).await?; let mut inbound = response.into_inner(); diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index cca925cd2..881ccbb3e 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -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}; diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 2a46f1004..b4ee6156d 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -1,4 +1,46 @@ use crate::metadata::MetadataMap; +use futures_core::Stream; + +#[doc(hidden)] +pub trait IntoRequest { + type Message; + + fn into_request(self) -> Request; +} + +#[doc(hidden)] +pub trait IntoStreamingRequest { + type Stream: Stream + Send + 'static; + type Message; + + fn into_streaming_request(self) -> Request; +} + +impl IntoRequest for Request { + type Message = T; + + fn into_request(self) -> Request { + self + } +} + +impl IntoStreamingRequest for Request { + type Stream = T; + type Message = T::Item; + + fn into_streaming_request(self) -> Self { + self + } +} + +impl IntoStreamingRequest for T { + type Stream = T; + type Message = T::Item; + + fn into_streaming_request(self) -> Request { + Request::new(self) + } +} /// A gRPC request and metadata from an RPC call. #[derive(Debug)] From 58d4238fb7591b80ee75bc2386ab533570c8fcef Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Thu, 10 Oct 2019 15:49:28 -0500 Subject: [PATCH 04/16] RequestMessage marker trait. generate more compact code --- tonic-build/src/lib.rs | 9 +---- tonic/src/lib.rs | 2 +- tonic/src/request.rs | 75 ++++++++++++++++++++++++++---------------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index 34f4bda1c..f56dbab31 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -350,14 +350,7 @@ fn generate_into_request_implementations(service: &prost_build::Service) -> Toke .iter() .fold(TokenStream::new(), |mut stream, input| { let request: syn::Type = syn::parse_str(&input).unwrap(); - stream.extend(quote::quote! { - impl tonic::IntoRequest for #request { - type Message = Self; - fn into_request(self) -> tonic::Request { - tonic::Request::new(self) - } - } - }); + stream.extend(quote::quote!(impl tonic::RequestMessage for #request {})); stream }) } diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 881ccbb3e..e8c9a0f39 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -98,7 +98,7 @@ pub use async_trait::async_trait; #[doc(inline)] pub use codec::Streaming; -pub use request::{IntoRequest, IntoStreamingRequest, Request}; +pub use request::{IntoRequest, IntoStreamingRequest, Request, RequestMessage}; pub use response::Response; pub use status::{Code, Status}; diff --git a/tonic/src/request.rs b/tonic/src/request.rs index b4ee6156d..1f64bf50b 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -1,9 +1,12 @@ use crate::metadata::MetadataMap; use futures_core::Stream; +/// A marker trait that should be implemented for all input messages. +pub trait RequestMessage {} + #[doc(hidden)] pub trait IntoRequest { - type Message; + type Message: RequestMessage; fn into_request(self) -> Request; } @@ -11,37 +14,11 @@ pub trait IntoRequest { #[doc(hidden)] pub trait IntoStreamingRequest { type Stream: Stream + Send + 'static; - type Message; + type Message: RequestMessage; fn into_streaming_request(self) -> Request; } -impl IntoRequest for Request { - type Message = T; - - fn into_request(self) -> Request { - self - } -} - -impl IntoStreamingRequest for Request { - type Stream = T; - type Message = T::Item; - - fn into_streaming_request(self) -> Self { - self - } -} - -impl IntoStreamingRequest for T { - type Stream = T; - type Message = T::Item; - - fn into_streaming_request(self) -> Request { - Request::new(self) - } -} - /// A gRPC request and metadata from an RPC call. #[derive(Debug)] pub struct Request { @@ -130,3 +107,45 @@ impl Request { } } } + +impl IntoRequest for T { + type Message = Self; + + fn into_request(self) -> Request { + Request::new(self) + } +} + +impl IntoRequest for Request { + type Message = T; + + fn into_request(self) -> Request { + self + } +} + +impl IntoStreamingRequest for Request +where + T: Stream + Send + 'static, + T::Item: RequestMessage, +{ + type Stream = T; + type Message = T::Item; + + fn into_streaming_request(self) -> Self { + self + } +} + +impl IntoStreamingRequest for T +where + T: Stream + Send + 'static, + T::Item: RequestMessage, +{ + type Stream = T; + type Message = T::Item; + + fn into_streaming_request(self) -> Request { + Request::new(self) + } +} From bfa3e9bc7f6f4af92807f495a3c554fec1a2d098 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Sat, 12 Oct 2019 10:18:14 -0500 Subject: [PATCH 05/16] improve naming --- tonic-build/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index f56dbab31..2d17d0db9 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -219,7 +219,7 @@ struct ServiceGenerator { builder: Builder, clients: TokenStream, servers: TokenStream, - into_request_impls: TokenStream, + request_message_impls: TokenStream, } impl ServiceGenerator { @@ -228,7 +228,7 @@ impl ServiceGenerator { builder, clients: TokenStream::default(), servers: TokenStream::default(), - into_request_impls: TokenStream::default(), + request_message_impls: TokenStream::default(), } } } @@ -246,18 +246,18 @@ impl prost_build::ServiceGenerator for ServiceGenerator { let client = client::generate(&service, path); self.clients.extend(client); - let tokens = generate_into_request_implementations(&service); - self.into_request_impls.extend(tokens); + let tokens = generate_request_message_implementations(&service); + self.request_message_impls.extend(tokens); } } fn finalize(&mut self, buf: &mut String) { if self.builder.build_client && !self.clients.is_empty() { let clients = &self.clients; - let into_request_impls = &self.into_request_impls; + let trait_impls = &self.request_message_impls; let client_service = quote::quote! { - #into_request_impls + #trait_impls /// Generated client implementations. pub mod client { #![allow(unused_variables, dead_code, missing_docs)] @@ -337,7 +337,7 @@ fn replace_wellknown(proto_path: &str, method: &Method) -> (TokenStream, TokenSt (request, response) } -fn generate_into_request_implementations(service: &prost_build::Service) -> TokenStream { +fn generate_request_message_implementations(service: &prost_build::Service) -> TokenStream { use std::collections::HashSet; service From d23ec041ce78b086d9b22dde9e44d85286e6a907 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Sat, 12 Oct 2019 10:19:48 -0500 Subject: [PATCH 06/16] fmt --- tonic-build/src/client.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index 89bcc34b1..4bb1c9836 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -102,7 +102,7 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream { pub async fn #ident> ( &mut self, request: R, - ) -> Result, tonic::Status> { + ) -> Result, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); @@ -120,7 +120,7 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke pub async fn #ident>( &mut self, request: R - ) -> Result>, tonic::Status> { + ) -> Result>, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); @@ -138,7 +138,7 @@ fn generate_client_streaming(method: &Method, proto: &str, path: String) -> Toke pub async fn #ident>( &mut self, request: S - ) -> Result, tonic::Status> { + ) -> Result, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); From 405b5e3a33de4ad785db7713f83f6953eb56e46c Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Mon, 14 Oct 2019 20:07:57 -0500 Subject: [PATCH 07/16] fix interop crate --- Cargo.toml | 2 +- tonic-build/src/lib.rs | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 862b38ba8..bbcce3dc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,5 @@ members = [ "tonic", "tonic-build", "tonic-examples", -# "tonic-interop", + "tonic-interop", ] diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index 2d17d0db9..91928af41 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -64,6 +64,7 @@ use quote::{ToTokens, TokenStreamExt}; #[cfg(feature = "rustfmt")] use std::process::Command; use std::{ + collections::HashSet, io, path::{Path, PathBuf}, }; @@ -219,6 +220,7 @@ struct ServiceGenerator { builder: Builder, clients: TokenStream, servers: TokenStream, + seen_input_types: HashSet, request_message_impls: TokenStream, } @@ -228,6 +230,7 @@ impl ServiceGenerator { builder, clients: TokenStream::default(), servers: TokenStream::default(), + seen_input_types: HashSet::new(), request_message_impls: TokenStream::default(), } } @@ -246,7 +249,7 @@ impl prost_build::ServiceGenerator for ServiceGenerator { let client = client::generate(&service, path); self.clients.extend(client); - let tokens = generate_request_message_implementations(&service); + let tokens = generate_request_message_impls(&service, &mut self.seen_input_types); self.request_message_impls.extend(tokens); } } @@ -337,20 +340,30 @@ fn replace_wellknown(proto_path: &str, method: &Method) -> (TokenStream, TokenSt (request, response) } -fn generate_request_message_implementations(service: &prost_build::Service) -> TokenStream { - use std::collections::HashSet; - - service +fn generate_request_message_impls( + service: &prost_build::Service, + seen_input_types: &mut HashSet, +) -> TokenStream { + let service_input_types = service .methods .iter() .fold(HashSet::new(), |mut set, method| { set.insert(method.input_type.clone()); set - }) - .iter() - .fold(TokenStream::new(), |mut stream, input| { + }); + + let tokens = service_input_types.difference(seen_input_types).fold( + TokenStream::new(), + |mut stream, input| { let request: syn::Type = syn::parse_str(&input).unwrap(); stream.extend(quote::quote!(impl tonic::RequestMessage for #request {})); stream - }) + }, + ); + + for input in service_input_types { + seen_input_types.insert(input.to_owned()); + } + + tokens } From d40ac7e48f61b1e53397cf8ea99b5b3a5b3d1654 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Mon, 14 Oct 2019 20:18:25 -0500 Subject: [PATCH 08/16] hide RequestMessage trait from docs --- tonic/src/request.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 1f64bf50b..02f272a9f 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -1,7 +1,14 @@ use crate::metadata::MetadataMap; use futures_core::Stream; -/// A marker trait that should be implemented for all input messages. +/// A gRPC request and metadata from an RPC call. +#[derive(Debug)] +pub struct Request { + metadata: MetadataMap, + message: T, +} + +#[doc(hidden)] pub trait RequestMessage {} #[doc(hidden)] @@ -19,13 +26,6 @@ pub trait IntoStreamingRequest { fn into_streaming_request(self) -> Request; } -/// A gRPC request and metadata from an RPC call. -#[derive(Debug)] -pub struct Request { - metadata: MetadataMap, - message: T, -} - impl Request { /// Create a new gRPC request. /// From 1acf426cde7d0f2c7f53f7410014dbfdc850ee06 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Fri, 18 Oct 2019 18:03:34 -0500 Subject: [PATCH 09/16] use impl Trait instead of type parameter --- tonic-build/src/client.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index 4bb1c9836..cc2d199b5 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -99,9 +99,9 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream { let (request, response) = crate::replace_wellknown(proto, &method); quote! { - pub async fn #ident> ( + pub async fn #ident( &mut self, - request: R, + request: impl tonic::IntoRequest, ) -> Result, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); @@ -117,9 +117,9 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke let (request, response) = crate::replace_wellknown(proto, &method); quote! { - pub async fn #ident>( + pub async fn #ident( &mut self, - request: R + request: impl tonic::IntoRequest, ) -> Result>, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); @@ -135,9 +135,9 @@ fn generate_client_streaming(method: &Method, proto: &str, path: String) -> Toke let (request, response) = crate::replace_wellknown(proto, &method); quote! { - pub async fn #ident>( + pub async fn #ident( &mut self, - request: S + request: impl tonic::IntoStreamingRequest ) -> Result, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); @@ -153,9 +153,9 @@ fn generate_streaming(method: &Method, proto: &str, path: String) -> TokenStream let (request, response) = crate::replace_wellknown(proto, &method); quote! { - pub async fn #ident>( + pub async fn #ident( &mut self, - request: S + request: impl tonic::IntoStreamingRequest ) -> Result>, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); From 0e9fe70afdeaadc2dc7f5cc59df2fe2d8d207f32 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Fri, 18 Oct 2019 18:29:51 -0500 Subject: [PATCH 10/16] remove RequestMessage trait --- tonic-build/src/lib.rs | 29 ++++++++++++++++++++--------- tonic/src/lib.rs | 2 +- tonic/src/request.rs | 21 ++++----------------- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index 91928af41..30440c736 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -221,7 +221,7 @@ struct ServiceGenerator { clients: TokenStream, servers: TokenStream, seen_input_types: HashSet, - request_message_impls: TokenStream, + into_request_impls: TokenStream, } impl ServiceGenerator { @@ -231,7 +231,7 @@ impl ServiceGenerator { clients: TokenStream::default(), servers: TokenStream::default(), seen_input_types: HashSet::new(), - request_message_impls: TokenStream::default(), + into_request_impls: TokenStream::default(), } } } @@ -249,15 +249,15 @@ impl prost_build::ServiceGenerator for ServiceGenerator { let client = client::generate(&service, path); self.clients.extend(client); - let tokens = generate_request_message_impls(&service, &mut self.seen_input_types); - self.request_message_impls.extend(tokens); + let tokens = generate_into_request_impls(&service, &mut self.seen_input_types); + self.into_request_impls.extend(tokens); } } fn finalize(&mut self, buf: &mut String) { if self.builder.build_client && !self.clients.is_empty() { let clients = &self.clients; - let trait_impls = &self.request_message_impls; + let trait_impls = &self.into_request_impls; let client_service = quote::quote! { #trait_impls @@ -340,7 +340,7 @@ fn replace_wellknown(proto_path: &str, method: &Method) -> (TokenStream, TokenSt (request, response) } -fn generate_request_message_impls( +fn generate_into_request_impls( service: &prost_build::Service, seen_input_types: &mut HashSet, ) -> TokenStream { @@ -352,11 +352,22 @@ fn generate_request_message_impls( set }); - let tokens = service_input_types.difference(seen_input_types).fold( + let token_stream = service_input_types.difference(seen_input_types).fold( TokenStream::new(), |mut stream, input| { let request: syn::Type = syn::parse_str(&input).unwrap(); - stream.extend(quote::quote!(impl tonic::RequestMessage for #request {})); + + let trait_impl = quote::quote! { + impl tonic::IntoRequest for #request { + type Message = Self; + + fn into_request(self) -> tonic::Request { + tonic::Request::new(self) + } + } + }; + + stream.extend(trait_impl); stream }, ); @@ -365,5 +376,5 @@ fn generate_request_message_impls( seen_input_types.insert(input.to_owned()); } - tokens + token_stream } diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index e8c9a0f39..881ccbb3e 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -98,7 +98,7 @@ pub use async_trait::async_trait; #[doc(inline)] pub use codec::Streaming; -pub use request::{IntoRequest, IntoStreamingRequest, Request, RequestMessage}; +pub use request::{IntoRequest, IntoStreamingRequest, Request}; pub use response::Response; pub use status::{Code, Status}; diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 02f272a9f..e0049d189 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -8,12 +8,9 @@ pub struct Request { message: T, } -#[doc(hidden)] -pub trait RequestMessage {} - -#[doc(hidden)] +/// A trait that is implemented for all RPC request request types. pub trait IntoRequest { - type Message: RequestMessage; + type Message; fn into_request(self) -> Request; } @@ -21,7 +18,7 @@ pub trait IntoRequest { #[doc(hidden)] pub trait IntoStreamingRequest { type Stream: Stream + Send + 'static; - type Message: RequestMessage; + type Message; fn into_streaming_request(self) -> Request; } @@ -108,15 +105,7 @@ impl Request { } } -impl IntoRequest for T { - type Message = Self; - - fn into_request(self) -> Request { - Request::new(self) - } -} - -impl IntoRequest for Request { +impl IntoRequest for Request { type Message = T; fn into_request(self) -> Request { @@ -127,7 +116,6 @@ impl IntoRequest for Request { impl IntoStreamingRequest for Request where T: Stream + Send + 'static, - T::Item: RequestMessage, { type Stream = T; type Message = T::Item; @@ -140,7 +128,6 @@ where impl IntoStreamingRequest for T where T: Stream + Send + 'static, - T::Item: RequestMessage, { type Stream = T; type Message = T::Item; From 878120c72f1dd945d87dcfcf76f001b274e6f841 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Fri, 18 Oct 2019 21:38:48 -0500 Subject: [PATCH 11/16] document IntoRequest --- tonic/src/request.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tonic/src/request.rs b/tonic/src/request.rs index e0049d189..2038219eb 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -10,8 +10,10 @@ pub struct Request { /// A trait that is implemented for all RPC request request types. pub trait IntoRequest { + /// The RPC request type type Message; + /// Wrap `Message` in a `tonic::Request` fn into_request(self) -> Request; } From 2f93f3328a3df1e4ef19bf644b2304afe1b65a67 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Tue, 22 Oct 2019 16:56:53 -0500 Subject: [PATCH 12/16] document IntoStreamingRequest --- tonic/src/request.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 2038219eb..9f9a8c3d9 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -17,11 +17,15 @@ pub trait IntoRequest { fn into_request(self) -> Request; } -#[doc(hidden)] +/// A trait that is implemented for all streaming RPC request types. pub trait IntoStreamingRequest { + /// The RPC request stream type type Stream: Stream + Send + 'static; + + /// The RPC request type type Message; + /// Wrap the stream of messages in a `tonic::Request` fn into_streaming_request(self) -> Request; } From adbbe8cb5e9d5be109fb928ff49a376a359fdb92 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Thu, 24 Oct 2019 14:39:37 -0500 Subject: [PATCH 13/16] remove IntoRequest in favor of From impl --- tonic-build/src/client.rs | 8 +++---- tonic-build/src/lib.rs | 49 --------------------------------------- tonic/src/lib.rs | 2 +- tonic/src/request.rs | 17 +++----------- 4 files changed, 8 insertions(+), 68 deletions(-) diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index cc2d199b5..fbe7ea89c 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -101,12 +101,12 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream { quote! { pub async fn #ident( &mut self, - request: impl tonic::IntoRequest, + request: impl Into>, ) -> Result, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); - self.inner.unary(request.into_request(), path, codec).await + self.inner.unary(request.into(), path, codec).await } } } @@ -119,12 +119,12 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke quote! { pub async fn #ident( &mut self, - request: impl tonic::IntoRequest, + request: impl Into>, ) -> Result>, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); - self.inner.server_streaming(request.into_request(), path, codec).await + self.inner.server_streaming(request.into(), path, codec).await } } } diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index 30440c736..a42ebbdcc 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -64,7 +64,6 @@ use quote::{ToTokens, TokenStreamExt}; #[cfg(feature = "rustfmt")] use std::process::Command; use std::{ - collections::HashSet, io, path::{Path, PathBuf}, }; @@ -220,8 +219,6 @@ struct ServiceGenerator { builder: Builder, clients: TokenStream, servers: TokenStream, - seen_input_types: HashSet, - into_request_impls: TokenStream, } impl ServiceGenerator { @@ -230,8 +227,6 @@ impl ServiceGenerator { builder, clients: TokenStream::default(), servers: TokenStream::default(), - seen_input_types: HashSet::new(), - into_request_impls: TokenStream::default(), } } } @@ -248,19 +243,14 @@ impl prost_build::ServiceGenerator for ServiceGenerator { if self.builder.build_client { let client = client::generate(&service, path); self.clients.extend(client); - - let tokens = generate_into_request_impls(&service, &mut self.seen_input_types); - self.into_request_impls.extend(tokens); } } fn finalize(&mut self, buf: &mut String) { if self.builder.build_client && !self.clients.is_empty() { let clients = &self.clients; - let trait_impls = &self.into_request_impls; let client_service = quote::quote! { - #trait_impls /// Generated client implementations. pub mod client { #![allow(unused_variables, dead_code, missing_docs)] @@ -339,42 +329,3 @@ fn replace_wellknown(proto_path: &str, method: &Method) -> (TokenStream, TokenSt (request, response) } - -fn generate_into_request_impls( - service: &prost_build::Service, - seen_input_types: &mut HashSet, -) -> TokenStream { - let service_input_types = service - .methods - .iter() - .fold(HashSet::new(), |mut set, method| { - set.insert(method.input_type.clone()); - set - }); - - let token_stream = service_input_types.difference(seen_input_types).fold( - TokenStream::new(), - |mut stream, input| { - let request: syn::Type = syn::parse_str(&input).unwrap(); - - let trait_impl = quote::quote! { - impl tonic::IntoRequest for #request { - type Message = Self; - - fn into_request(self) -> tonic::Request { - tonic::Request::new(self) - } - } - }; - - stream.extend(trait_impl); - stream - }, - ); - - for input in service_input_types { - seen_input_types.insert(input.to_owned()); - } - - token_stream -} diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 881ccbb3e..862783ca9 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -98,7 +98,7 @@ pub use async_trait::async_trait; #[doc(inline)] pub use codec::Streaming; -pub use request::{IntoRequest, IntoStreamingRequest, Request}; +pub use request::{IntoStreamingRequest, Request}; pub use response::Response; pub use status::{Code, Status}; diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 9f9a8c3d9..291fc2c3b 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -8,15 +8,6 @@ pub struct Request { message: T, } -/// A trait that is implemented for all RPC request request types. -pub trait IntoRequest { - /// The RPC request type - type Message; - - /// Wrap `Message` in a `tonic::Request` - fn into_request(self) -> Request; -} - /// A trait that is implemented for all streaming RPC request types. pub trait IntoStreamingRequest { /// The RPC request stream type @@ -111,11 +102,9 @@ impl Request { } } -impl IntoRequest for Request { - type Message = T; - - fn into_request(self) -> Request { - self +impl From for Request { + fn from(t: T) -> Self { + Request::new(t) } } From 9a9ee931d58cc08ce162895e98d7c25f6ed098bf Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Thu, 24 Oct 2019 17:50:21 -0500 Subject: [PATCH 14/16] seal IntoStreamingRequest --- tonic/src/request.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 291fc2c3b..55c1c3508 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -8,8 +8,11 @@ pub struct Request { message: T, } -/// A trait that is implemented for all streaming RPC request types. -pub trait IntoStreamingRequest { +/// Conversion into a streaming `Request`. +/// +/// Types implementing this trait may be used as an argument to +/// generated client-streaming RPC methods. +pub trait IntoStreamingRequest: sealed::Sealed { /// The RPC request stream type type Stream: Stream + Send + 'static; @@ -131,3 +134,11 @@ where Request::new(self) } } + +impl sealed::Sealed for T where T: Stream + Send + 'static {} + +impl sealed::Sealed for Request where T: Stream + Send + 'static {} + +mod sealed { + pub trait Sealed {} +} From 8802192dc453b7014beb8566cc39c89d160211bc Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Mon, 28 Oct 2019 20:48:22 -0600 Subject: [PATCH 15/16] remove From for Request, implement IntoRequest instead --- tonic-build/src/client.rs | 8 ++++---- tonic/src/lib.rs | 2 +- tonic/src/request.rs | 25 +++++++++++++++++++------ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index fbe7ea89c..4e081205e 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -101,12 +101,12 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream { quote! { pub async fn #ident( &mut self, - request: impl Into>, + request: impl tonic::IntoRequest<#request>, ) -> Result, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); - self.inner.unary(request.into(), path, codec).await + self.inner.unary(request.into_request(), path, codec).await } } } @@ -119,12 +119,12 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke quote! { pub async fn #ident( &mut self, - request: impl Into>, + request: impl tonic::IntoRequest<#request>, ) -> Result>, tonic::Status> { self.ready().await?; let codec = tonic::codec::ProstCodec::new(); let path = http::uri::PathAndQuery::from_static(#path); - self.inner.server_streaming(request.into(), path, codec).await + self.inner.server_streaming(request.into_request(), path, codec).await } } } diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 862783ca9..881ccbb3e 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -98,7 +98,7 @@ pub use async_trait::async_trait; #[doc(inline)] pub use codec::Streaming; -pub use request::{IntoStreamingRequest, Request}; +pub use request::{IntoRequest, IntoStreamingRequest, Request}; pub use response::Response; pub use status::{Code, Status}; diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 55c1c3508..13a0bff34 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -23,6 +23,15 @@ pub trait IntoStreamingRequest: sealed::Sealed { fn into_streaming_request(self) -> Request; } +/// Conversion into a unary `Request`. +/// +/// Types implementing this trait may be used as an argument to +/// generated unary RPC methods. +pub trait IntoRequest: sealed::Sealed { + /// Wrap the input message `T` in a `tonic::Request` + fn into_request(self) -> Request; +} + impl Request { /// Create a new gRPC request. /// @@ -105,9 +114,15 @@ impl Request { } } -impl From for Request { - fn from(t: T) -> Self { - Request::new(t) +impl IntoRequest for Request { + fn into_request(self) -> Request { + self + } +} + +impl IntoRequest for T { + fn into_request(self) -> Request { + Request::new(self) } } @@ -135,9 +150,7 @@ where } } -impl sealed::Sealed for T where T: Stream + Send + 'static {} - -impl sealed::Sealed for Request where T: Stream + Send + 'static {} +impl sealed::Sealed for T {} mod sealed { pub trait Sealed {} From 7017f971633589ff861ba8f255900e85b96bd808 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Tue, 29 Oct 2019 13:54:57 -0600 Subject: [PATCH 16/16] improve docs --- tonic/src/request.rs | 102 +++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 24 deletions(-) diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 13a0bff34..2042e135f 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -8,10 +8,73 @@ pub struct Request { message: T, } -/// Conversion into a streaming `Request`. +/// Trait implemented by RPC request types. /// -/// Types implementing this trait may be used as an argument to -/// generated client-streaming RPC methods. +/// 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) {} +/// # } +/// # let client = Client {}; +/// use tonic::Request; +/// +/// client.get_feature(Point {}); +/// client.get_feature(Request::new(Point {})); +/// ``` +pub trait IntoRequest: sealed::Sealed { + /// Wrap the input message `T` in a `tonic::Request` + fn into_request(self) -> Request; +} + +/// 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) {} +/// # } +/// # 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 + Send + 'static; @@ -23,15 +86,6 @@ pub trait IntoStreamingRequest: sealed::Sealed { fn into_streaming_request(self) -> Request; } -/// Conversion into a unary `Request`. -/// -/// Types implementing this trait may be used as an argument to -/// generated unary RPC methods. -pub trait IntoRequest: sealed::Sealed { - /// Wrap the input message `T` in a `tonic::Request` - fn into_request(self) -> Request; -} - impl Request { /// Create a new gRPC request. /// @@ -114,39 +168,39 @@ impl Request { } } -impl IntoRequest for Request { - fn into_request(self) -> Request { - self - } -} - impl IntoRequest for T { fn into_request(self) -> Request { Request::new(self) } } -impl IntoStreamingRequest for Request +impl IntoRequest for Request { + fn into_request(self) -> Request { + self + } +} + +impl IntoStreamingRequest for T where T: Stream + Send + 'static, { type Stream = T; type Message = T::Item; - fn into_streaming_request(self) -> Self { - self + fn into_streaming_request(self) -> Request { + Request::new(self) } } -impl IntoStreamingRequest for T +impl IntoStreamingRequest for Request where T: Stream + Send + 'static, { type Stream = T; type Message = T::Item; - fn into_streaming_request(self) -> Request { - Request::new(self) + fn into_streaming_request(self) -> Self { + self } }