mocktail/
ext.rs

1//! Extension traits
2use bytes::{BufMut, Bytes, BytesMut};
3use http::status::InvalidStatusCode;
4use prost::Message;
5
6pub trait CodeExt {
7    /// Creates a gRPC status code from an equivalent HTTP status code.
8    fn from_u16(code: u16) -> Result<tonic::Code, InvalidStatusCode>;
9    /// Creates a gRPC status code from an equivalent [`http::StatusCode`].
10    fn from_http(status_code: http::StatusCode) -> tonic::Code;
11}
12
13impl CodeExt for tonic::Code {
14    fn from_u16(code: u16) -> Result<tonic::Code, InvalidStatusCode> {
15        let status_code = http::StatusCode::from_u16(code)?;
16        Ok(tonic::Code::from_http(status_code))
17    }
18
19    fn from_http(status_code: http::StatusCode) -> tonic::Code {
20        match status_code {
21            http::StatusCode::INTERNAL_SERVER_ERROR => tonic::Code::Internal,
22            http::StatusCode::UNPROCESSABLE_ENTITY | http::StatusCode::BAD_REQUEST => {
23                tonic::Code::InvalidArgument
24            }
25            http::StatusCode::UNAUTHORIZED => tonic::Code::Unauthenticated,
26            http::StatusCode::FORBIDDEN => tonic::Code::PermissionDenied,
27            http::StatusCode::NOT_FOUND => tonic::Code::NotFound,
28            http::StatusCode::NOT_IMPLEMENTED => tonic::Code::Unimplemented,
29            http::StatusCode::TOO_MANY_REQUESTS
30            | http::StatusCode::BAD_GATEWAY
31            | http::StatusCode::SERVICE_UNAVAILABLE
32            | http::StatusCode::GATEWAY_TIMEOUT => tonic::Code::Unavailable,
33            http::StatusCode::OK => tonic::Code::Ok,
34            _ => tonic::Code::Unknown,
35        }
36    }
37}
38
39pub trait MessageExt {
40    /// Encodes the messages to bytes for a HTTP body.
41    fn to_bytes(&self) -> Bytes;
42}
43
44impl<T: Message> MessageExt for T {
45    fn to_bytes(&self) -> Bytes {
46        let mut buf = BytesMut::with_capacity(256);
47        buf.reserve(5);
48        unsafe {
49            buf.advance_mut(5);
50        }
51        self.encode(&mut buf).unwrap();
52        {
53            let len = buf.len() - 5;
54            let mut buf = &mut buf[..5];
55            buf.put_u8(0); // byte must be 0
56            buf.put_u32(len as u32);
57        }
58        buf.freeze()
59    }
60}