Skip to main content

ruma_common/api/
body.rs

1use std::convert::Infallible;
2
3use bytes::BufMut;
4
5use crate::{api::error::IntoHttpError, serde::slice_to_buf};
6
7/// HTTP message body pre-serialization.
8pub trait OutgoingBody {
9    /// The type of error that can happen in `try_info_buf`.
10    type Error: Into<IntoHttpError>;
11
12    /// The value for the `Content-Type` HTTP header for this body, if there is one.
13    ///
14    /// This is the value set if the request or response type does not set one dynamically, for
15    /// example with the `#[ruma_api(header = CONTENT_TYPE)]` attribute.
16    ///
17    /// If this is `None`, no `Content-Type` HTTP header is added.
18    fn content_type(&self) -> Option<http::HeaderValue>;
19
20    /// Turn `self` into a byte buffer (copying a raw body or serializing a JSON one).
21    fn try_into_buf<T: Default + BufMut + AsRef<[u8]>>(self) -> Result<T, Self::Error>;
22}
23
24/// "Empty" body type, used mostly for GET requests.
25///
26/// If `TRULY_EMPTY` is `true`, serializes to an empty buffer.
27/// If `TRULY_EMPTY` is `false`, serializes to an empty JSON object.
28/// (that case is not encoded as a separate type due to macro requirements)
29#[expect(clippy::exhaustive_structs)]
30pub struct EmptyBody<const TRULY_EMPTY: bool = true>;
31
32impl<const TRULY_EMPTY: bool> OutgoingBody for EmptyBody<TRULY_EMPTY> {
33    type Error = Infallible;
34
35    fn content_type(&self) -> Option<http::HeaderValue> {
36        if TRULY_EMPTY { None } else { Some(crate::http_headers::APPLICATION_JSON) }
37    }
38
39    fn try_into_buf<T: Default + BufMut + AsRef<[u8]>>(self) -> Result<T, Infallible> {
40        if TRULY_EMPTY { Ok(Default::default()) } else { Ok(slice_to_buf(b"{}")) }
41    }
42}
43
44/// Raw-bytes body type, used for some media endpoints.
45#[expect(clippy::exhaustive_structs)]
46pub struct BytesBody(pub Vec<u8>);
47
48impl OutgoingBody for BytesBody {
49    type Error = Infallible;
50
51    fn content_type(&self) -> Option<http::HeaderValue> {
52        Some(crate::http_headers::APPLICATION_OCTET_STREAM)
53    }
54
55    fn try_into_buf<T: Default + BufMut + AsRef<[u8]>>(self) -> Result<T, Infallible> {
56        Ok(slice_to_buf(&self.0))
57    }
58}