Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ members = [
"tests/web",
"tests/default_stubs",
"tests/deprecated_methods",
"tests/tonic_path/wrapper",
"tests/tonic_path/my_application",
]
resolver = "2"

Expand Down
156 changes: 87 additions & 69 deletions grpc/src/generated/grpc_examples_echo.rs

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions tests/tonic_path/my_application/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "my_application_tonic_path"
edition = "2024"
license = "MIT"
publish = false

[dependencies]
prost = "0.14"
wrapper = { path = "../wrapper" }

[build-dependencies]
tonic-prost-build = { path = "../../../tonic-prost-build" }
7 changes: 7 additions & 0 deletions tests/tonic_path/my_application/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() -> Result<(), std::io::Error> {
tonic_prost_build::configure()
.tonic_path("wrapper::tonic")
.codec_path("wrapper::tonic_prost::ProstCodec")
.compile_protos(&["greeter/greeter.proto"], &["../proto"])?;
Ok(())
}
34 changes: 34 additions & 0 deletions tests/tonic_path/my_application/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
mod pb {
include!(concat!(env!("OUT_DIR"), "/greeter.rs"));
}

#[derive(Default)]
struct MyGreeter;

#[wrapper::tonic::async_trait]
impl pb::greeter_server::Greeter for MyGreeter {
async fn say_hello(
&self,
request: wrapper::tonic::Request<pb::HelloRequest>,
) -> Result<wrapper::tonic::Response<pb::HelloResponse>, wrapper::tonic::Status> {
let name = request.into_inner().name;
Ok(wrapper::tonic::Response::new(pb::HelloResponse {
message: format!("Hello, {name}!"),
}))
}
}

fn main() {
let _server = pb::greeter_server::GreeterServer::new(MyGreeter);
}

#[cfg(test)]
#[test]
fn test_generated_types_resolve_through_wrapper() {
// Constructing both the server and client types proves the generated
// code resolved `wrapper::tonic::*` and `wrapper::tonic_prost::ProstCodec`
// without any direct `tonic` dependency in this crate's manifest.
let _server = pb::greeter_server::GreeterServer::new(MyGreeter);
fn _assert_client_type<T>() {}
_assert_client_type::<pb::greeter_client::GreeterClient<wrapper::tonic::transport::Channel>>();
}
15 changes: 15 additions & 0 deletions tests/tonic_path/proto/greeter/greeter.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
syntax = "proto3";

package greeter;

message HelloRequest {
string name = 1;
}

message HelloResponse {
string message = 1;
}

service Greeter {
rpc SayHello(HelloRequest) returns (HelloResponse);
}
9 changes: 9 additions & 0 deletions tests/tonic_path/wrapper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "wrapper"
edition = "2024"
license = "MIT"
publish = false

[dependencies]
tonic = { path = "../../../tonic" }
tonic-prost = { path = "../../../tonic-prost" }
2 changes: 2 additions & 0 deletions tests/tonic_path/wrapper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub use ::tonic;
pub use ::tonic_prost;
80 changes: 50 additions & 30 deletions tonic-build/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

#[allow(clippy::too_many_arguments)]
pub(crate) fn generate_internal<T: Service>(
service: &T,
emit_package: bool,
Expand All @@ -16,6 +17,7 @@ pub(crate) fn generate_internal<T: Service>(
build_transport: bool,
attributes: &Attributes,
disable_comments: &HashSet<String>,
tonic_path: &syn::Path,
) -> TokenStream {
let service_ident = quote::format_ident!("{}Client", service.name());
let client_mod = quote::format_ident!("{}_client", naive_snake_case(service.name()));
Expand All @@ -25,9 +27,10 @@ pub(crate) fn generate_internal<T: Service>(
proto_path,
compile_well_known_types,
disable_comments,
tonic_path,
);

let connect = generate_connect(&service_ident, build_transport);
let connect = generate_connect(&service_ident, build_transport, tonic_path);

let package = if emit_package { service.package() } else { "" };
let service_name = format_service_name(service, emit_package);
Expand All @@ -53,44 +56,44 @@ pub(crate) fn generate_internal<T: Service>(
// will trigger if compression is disabled
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
use #tonic_path::codegen::*;
use #tonic_path::codegen::http::Uri;

#service_doc
#(#struct_attributes)*
#[derive(Debug, Clone)]
pub struct #service_ident<T> {
inner: tonic::client::Grpc<T>,
inner: #tonic_path::client::Grpc<T>,
}

#connect

impl<T> #service_ident<T>
where
T: tonic::client::GrpcService<tonic::body::Body>,
T: #tonic_path::client::GrpcService<#tonic_path::body::Body>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
let inner = #tonic_path::client::Grpc::new(inner);
Self { inner }
}

pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
let inner = #tonic_path::client::Grpc::with_origin(inner, origin);
Self { inner }
}

pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
F: #tonic_path::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::Body>,
Response = http::Response<<T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody>
T: #tonic_path::codegen::Service<
http::Request<#tonic_path::body::Body>,
Response = http::Response<<T as #tonic_path::client::GrpcService<#tonic_path::body::Body>>::ResponseBody>
>,
<T as tonic::codegen::Service<http::Request<tonic::body::Body>>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
<T as #tonic_path::codegen::Service<http::Request<#tonic_path::body::Body>>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
#service_ident::new(InterceptedService::new(inner, interceptor))
}
Expand Down Expand Up @@ -137,16 +140,20 @@ pub(crate) fn generate_internal<T: Service>(
}

#[cfg(feature = "transport")]
fn generate_connect(service_ident: &syn::Ident, enabled: bool) -> TokenStream {
fn generate_connect(
service_ident: &syn::Ident,
enabled: bool,
tonic_path: &syn::Path,
) -> TokenStream {
let connect_impl = quote! {
impl #service_ident<tonic::transport::Channel> {
impl #service_ident<#tonic_path::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
pub async fn connect<D>(dst: D) -> Result<Self, #tonic_path::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D: TryInto<#tonic_path::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
let conn = #tonic_path::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
Expand All @@ -160,7 +167,11 @@ fn generate_connect(service_ident: &syn::Ident, enabled: bool) -> TokenStream {
}

#[cfg(not(feature = "transport"))]
fn generate_connect(_service_ident: &syn::Ident, _enabled: bool) -> TokenStream {
fn generate_connect(
_service_ident: &syn::Ident,
_enabled: bool,
_tonic_path: &syn::Path,
) -> TokenStream {
TokenStream::new()
}

Expand All @@ -170,6 +181,7 @@ fn generate_methods<T: Service>(
proto_path: &str,
compile_well_known_types: bool,
disable_comments: &HashSet<String>,
tonic_path: &syn::Path,
) -> TokenStream {
let mut stream = TokenStream::new();

Expand All @@ -188,27 +200,31 @@ fn generate_methods<T: Service>(
emit_package,
proto_path,
compile_well_known_types,
tonic_path,
),
(false, true) => generate_server_streaming(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
tonic_path,
),
(true, false) => generate_client_streaming(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
tonic_path,
),
(true, true) => generate_streaming(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
tonic_path,
),
};

Expand All @@ -224,6 +240,7 @@ fn generate_unary<T: Service>(
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
tonic_path: &syn::Path,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());
Expand All @@ -235,10 +252,10 @@ fn generate_unary<T: Service>(
quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoRequest<#request>,
) -> std::result::Result<tonic::Response<#response>, tonic::Status> {
request: impl #tonic_path::IntoRequest<#request>,
) -> std::result::Result<#tonic_path::Response<#response>, #tonic_path::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::unknown(format!("Service was not ready: {}", e.into()))
#tonic_path::Status::unknown(format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
Expand All @@ -255,6 +272,7 @@ fn generate_server_streaming<T: Service>(
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
tonic_path: &syn::Path,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());
Expand All @@ -266,10 +284,10 @@ fn generate_server_streaming<T: Service>(
quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoRequest<#request>,
) -> std::result::Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
request: impl #tonic_path::IntoRequest<#request>,
) -> std::result::Result<#tonic_path::Response<#tonic_path::codec::Streaming<#response>>, #tonic_path::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::unknown(format!("Service was not ready: {}", e.into()))
#tonic_path::Status::unknown(format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
Expand All @@ -286,6 +304,7 @@ fn generate_client_streaming<T: Service>(
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
tonic_path: &syn::Path,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());
Expand All @@ -297,10 +316,10 @@ fn generate_client_streaming<T: Service>(
quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = #request>
) -> std::result::Result<tonic::Response<#response>, tonic::Status> {
request: impl #tonic_path::IntoStreamingRequest<Message = #request>
) -> std::result::Result<#tonic_path::Response<#response>, #tonic_path::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::unknown(format!("Service was not ready: {}", e.into()))
#tonic_path::Status::unknown(format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
Expand All @@ -317,6 +336,7 @@ fn generate_streaming<T: Service>(
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
tonic_path: &syn::Path,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());
Expand All @@ -328,10 +348,10 @@ fn generate_streaming<T: Service>(
quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = #request>
) -> std::result::Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
request: impl #tonic_path::IntoStreamingRequest<Message = #request>
) -> std::result::Result<#tonic_path::Response<#tonic_path::codec::Streaming<#response>>, #tonic_path::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::unknown(format!("Service was not ready: {}", e.into()))
#tonic_path::Status::unknown(format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
Expand Down
Loading
Loading