use futures::stream::{Stream, StreamExt};
use prost::Message;
use crate::client::{CallOptions, Client, UnaryResponse};
use crate::metadata::Metadata;
use crate::status::{Code, Status};
#[derive(Debug, Clone)]
pub struct TypedResponse<M> {
pub message: M,
pub headers: Metadata,
pub trailers: Metadata,
}
impl<M> TypedResponse<M> {
pub fn into_inner(self) -> M {
self.message
}
}
pub trait TypedClient {
fn unary_typed<Req, Res>(
&self,
path: &str,
request: Req,
options: CallOptions,
) -> impl std::future::Future<Output = Result<TypedResponse<Res>, Status>>
where
Req: Message,
Res: Message + Default;
fn client_streaming_typed<Req, Res, S>(
&self,
path: &str,
requests: S,
options: CallOptions,
) -> impl std::future::Future<Output = Result<TypedResponse<Res>, Status>>
where
Req: Message + 'static,
Res: Message + Default,
S: Stream<Item = Req> + 'static;
}
impl TypedClient for Client {
async fn unary_typed<Req, Res>(
&self,
path: &str,
request: Req,
options: CallOptions,
) -> Result<TypedResponse<Res>, Status>
where
Req: Message,
Res: Message + Default,
{
let response = self.unary(path, request.encode_to_vec(), options).await?;
decode(response)
}
async fn client_streaming_typed<Req, Res, S>(
&self,
path: &str,
requests: S,
options: CallOptions,
) -> Result<TypedResponse<Res>, Status>
where
Req: Message + 'static,
Res: Message + Default,
S: Stream<Item = Req> + 'static,
{
let response = self
.client_streaming(path, requests.map(|m| m.encode_to_vec()), options)
.await?;
decode(response)
}
}
fn decode<Res: Message + Default>(response: UnaryResponse) -> Result<TypedResponse<Res>, Status> {
let message = Res::decode(response.message.as_slice()).map_err(|e| {
Status::new(Code::Internal, format!("failed to decode response message: {e}"))
})?;
Ok(TypedResponse { message, headers: response.headers, trailers: response.trailers })
}