-
Notifications
You must be signed in to change notification settings - Fork 1k
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(build): use prettyplease to format output (#890) #904
Conversation
Make it a hard dependency and drop the optional rustfmt feature. Fixes: hyperium#890
Hot take: Why does tonic have to format the generated code at all? Can't users do that, if necessary? |
Certainly possible but I see myself freaked out, first time I jump into unformatted, computer-generated code. And I definitely do sometimes browse the code. Edit: but @LucioFranco can probably outline the motivation for introducing rustfmt in the first place. |
You mean after opening it from within the target directory? I normally format the code in the rust playground if I'm just interested in peeking at it. Otherwise I browse the generated docs. |
Kind of. nvim/lsp + rust-analyzer let's me jump to any piece of code no matter if the current crate, some dependency or generated code like tonic's. |
Ah I see. That doesn't work for me for some reason and it just jumps to the place where I include the generated code 🤷♂️ I think formatting the code is still worth it especially given how easy with prettyplease. I was just wondering about your use case. |
@davidpdrsn originally when I was developing tonic I ran into compiler errors and what the compiler does is selects the line to print. When all the code is not formatted it fits onto one line and you can probably guess what the errors looked like xD |
@matze could you post a copy of what the formatted code looks like? |
This is the output for the helloworld.proto: prettyplease/// The request message containing the user's name.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloRequest {
#[prost(string, tag="1")]
pub name: ::prost::alloc::string::String,
}
/// The response message containing the greetings
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloReply {
#[prost(string, tag="1")]
pub message: ::prost::alloc::string::String,
}
/// Generated client implementations.
pub mod greeter_client {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value, )]
use tonic::codegen::*;
/// The greeting service definition.
#[derive(Debug, Clone)]
pub struct GreeterClient<T> {
inner: tonic::client::Grpc<T>,
}
impl GreeterClient<tonic::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>
where
D: std::convert::TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> GreeterClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::ResponseBody: Body + Send + 'static,
T::Error: Into<StdError>,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> GreeterClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<
tonic::body::BoxBody,
>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + Send + Sync,
{
GreeterClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with `gzip`.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_gzip(mut self) -> Self {
self.inner = self.inner.send_gzip();
self
}
/// Enable decompressing responses with `gzip`.
#[must_use]
pub fn accept_gzip(mut self) -> Self {
self.inner = self.inner.accept_gzip();
self
}
/// Sends a greeting
pub async fn say_hello(
&mut self,
request: impl tonic::IntoRequest<super::HelloRequest>,
) -> Result<tonic::Response<super::HelloReply>, tonic::Status> {
self
.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/helloworld.Greeter/SayHello",
);
self.inner.unary(request.into_request(), path, codec).await
}
}
}
/// Generated server implementations.
pub mod greeter_server {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value, )]
use tonic::codegen::*;
///Generated trait containing gRPC methods that should be implemented for use with GreeterServer.
#[async_trait]
pub trait Greeter: Send + Sync + 'static {
/// Sends a greeting
async fn say_hello(
&self,
request: tonic::Request<super::HelloRequest>,
) -> Result<tonic::Response<super::HelloReply>, tonic::Status>;
}
/// The greeting service definition.
#[derive(Debug)]
pub struct GreeterServer<T: Greeter> {
inner: _Inner<T>,
accept_compression_encodings: (),
send_compression_encodings: (),
}
struct _Inner<T>(Arc<T>);
impl<T: Greeter> GreeterServer<T> {
pub fn new(inner: T) -> Self {
Self::from_arc(Arc::new(inner))
}
pub fn from_arc(inner: Arc<T>) -> Self {
let inner = _Inner(inner);
Self {
inner,
accept_compression_encodings: Default::default(),
send_compression_encodings: Default::default(),
}
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> InterceptedService<Self, F>
where
F: tonic::service::Interceptor,
{
InterceptedService::new(Self::new(inner), interceptor)
}
}
impl<T, B> tonic::codegen::Service<http::Request<B>> for GreeterServer<T>
where
T: Greeter,
B: Body + Send + 'static,
B::Error: Into<StdError> + Send + 'static,
{
type Response = http::Response<tonic::body::BoxBody>;
type Error = Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(
&mut self,
_cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
let inner = self.inner.clone();
match req.uri().path() {
"/helloworld.Greeter/SayHello" => {
#[allow(non_camel_case_types)]
struct SayHelloSvc<T: Greeter>(pub Arc<T>);
impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest>
for SayHelloSvc<T> {
type Response = super::HelloReply;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::HelloRequest>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move { (*inner).say_hello(request).await };
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = SayHelloSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
_ => {
Box::pin(
async move {
Ok(
http::Response::builder()
.status(200)
.header("grpc-status", "12")
.header("content-type", "application/grpc")
.body(empty_body())
.unwrap(),
)
},
)
}
}
}
}
impl<T: Greeter> Clone for GreeterServer<T> {
fn clone(&self) -> Self {
let inner = self.inner.clone();
Self {
inner,
accept_compression_encodings: self.accept_compression_encodings,
send_compression_encodings: self.send_compression_encodings,
}
}
}
impl<T: Greeter> Clone for _Inner<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl<T: Greeter> tonic::transport::NamedService for GreeterServer<T> {
const NAME: &'static str = "helloworld.Greeter";
}
} reformatted with rustfmt/// The request message containing the user's name.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloRequest {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
}
/// The response message containing the greetings
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelloReply {
#[prost(string, tag = "1")]
pub message: ::prost::alloc::string::String,
}
/// Generated client implementations.
pub mod greeter_client {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
use tonic::codegen::*;
/// The greeting service definition.
#[derive(Debug, Clone)]
pub struct GreeterClient<T> {
inner: tonic::client::Grpc<T>,
}
impl GreeterClient<tonic::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>
where
D: std::convert::TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> GreeterClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::ResponseBody: Body + Send + 'static,
T::Error: Into<StdError>,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> GreeterClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<http::Request<tonic::body::BoxBody>>>::Error:
Into<StdError> + Send + Sync,
{
GreeterClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with `gzip`.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_gzip(mut self) -> Self {
self.inner = self.inner.send_gzip();
self
}
/// Enable decompressing responses with `gzip`.
#[must_use]
pub fn accept_gzip(mut self) -> Self {
self.inner = self.inner.accept_gzip();
self
}
/// Sends a greeting
pub async fn say_hello(
&mut self,
request: impl tonic::IntoRequest<super::HelloRequest>,
) -> Result<tonic::Response<super::HelloReply>, tonic::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static("/helloworld.Greeter/SayHello");
self.inner.unary(request.into_request(), path, codec).await
}
}
}
/// Generated server implementations.
pub mod greeter_server {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
use tonic::codegen::*;
///Generated trait containing gRPC methods that should be implemented for use with GreeterServer.
#[async_trait]
pub trait Greeter: Send + Sync + 'static {
/// Sends a greeting
async fn say_hello(
&self,
request: tonic::Request<super::HelloRequest>,
) -> Result<tonic::Response<super::HelloReply>, tonic::Status>;
}
/// The greeting service definition.
#[derive(Debug)]
pub struct GreeterServer<T: Greeter> {
inner: _Inner<T>,
accept_compression_encodings: (),
send_compression_encodings: (),
}
struct _Inner<T>(Arc<T>);
impl<T: Greeter> GreeterServer<T> {
pub fn new(inner: T) -> Self {
Self::from_arc(Arc::new(inner))
}
pub fn from_arc(inner: Arc<T>) -> Self {
let inner = _Inner(inner);
Self {
inner,
accept_compression_encodings: Default::default(),
send_compression_encodings: Default::default(),
}
}
pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
where
F: tonic::service::Interceptor,
{
InterceptedService::new(Self::new(inner), interceptor)
}
}
impl<T, B> tonic::codegen::Service<http::Request<B>> for GreeterServer<T>
where
T: Greeter,
B: Body + Send + 'static,
B::Error: Into<StdError> + Send + 'static,
{
type Response = http::Response<tonic::body::BoxBody>;
type Error = Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
let inner = self.inner.clone();
match req.uri().path() {
"/helloworld.Greeter/SayHello" => {
#[allow(non_camel_case_types)]
struct SayHelloSvc<T: Greeter>(pub Arc<T>);
impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest> for SayHelloSvc<T> {
type Response = super::HelloReply;
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
fn call(
&mut self,
request: tonic::Request<super::HelloRequest>,
) -> Self::Future {
let inner = self.0.clone();
let fut = async move { (*inner).say_hello(request).await };
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = SayHelloSvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec).apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
_ => Box::pin(async move {
Ok(http::Response::builder()
.status(200)
.header("grpc-status", "12")
.header("content-type", "application/grpc")
.body(empty_body())
.unwrap())
}),
}
}
}
impl<T: Greeter> Clone for GreeterServer<T> {
fn clone(&self) -> Self {
let inner = self.inner.clone();
Self {
inner,
accept_compression_encodings: self.accept_compression_encodings,
send_compression_encodings: self.send_compression_encodings,
}
}
}
impl<T: Greeter> Clone for _Inner<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl<T: Greeter> tonic::transport::NamedService for GreeterServer<T> {
const NAME: &'static str = "helloworld.Greeter";
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this!
Method `format` was removed in hyperium#904, but this doc was not updated because has an attribute `ignore`
Method `format` was removed in #904, but this doc was not updated because has an attribute `ignore`
Use prettyplease to format the output unconditionally and drop the optional rustfmt feature.
Motivation
Having to ask people to install
rustfmt
to avoid spurious build errors was annoying. prettyplease can be installed as a regular dependency and format the code without having to shell out. Moreover this feature was asked for in #890.Solution
Add prettyplease 0.1.x and use it to format the token stream unconditionally. The few protos I tested were indistinguishable from having them formatted with rustfmt.