ruma_macros/api/response/
outgoing.rs
1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::Ident;
4
5use super::{Response, ResponseField};
6
7impl Response {
8 pub fn expand_outgoing(&self, status_ident: &Ident, ruma_common: &TokenStream) -> TokenStream {
9 let bytes = quote! { #ruma_common::exports::bytes };
10 let http = quote! { #ruma_common::exports::http };
11
12 let serialize_response_headers = self.fields.iter().filter_map(|response_field| {
13 response_field.as_header_field().map(|(field, header_name)| {
14 let field_name =
15 field.ident.as_ref().expect("expected field to have an identifier");
16
17 match &field.ty {
18 syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. })
19 if segments.last().unwrap().ident == "Option" =>
20 {
21 quote! {
22 if let Some(header) = self.#field_name {
23 headers.insert(
24 #header_name,
25 header.to_string().parse()?,
26 );
27 }
28 }
29 }
30 _ => quote! {
31 headers.insert(
32 #header_name,
33 self.#field_name.to_string().parse()?,
34 );
35 },
36 }
37 })
38 });
39
40 let body = if let Some(field) =
41 self.fields.iter().find_map(ResponseField::as_raw_body_field)
42 {
43 let field_name = field.ident.as_ref().expect("expected field to have an identifier");
44 quote! { #ruma_common::serde::slice_to_buf(&self.#field_name) }
45 } else {
46 let fields = self.fields.iter().filter_map(|response_field| {
47 response_field.as_body_field().map(|field| {
48 let field_name =
49 field.ident.as_ref().expect("expected field to have an identifier");
50 let cfg_attrs = field.attrs.iter().filter(|a| a.path().is_ident("cfg"));
51
52 quote! {
53 #( #cfg_attrs )*
54 #field_name: self.#field_name,
55 }
56 })
57 });
58
59 quote! {
60 #ruma_common::serde::json_to_buf(&ResponseBody { #(#fields)* })?
61 }
62 };
63
64 quote! {
65 #[automatically_derived]
66 #[cfg(feature = "server")]
67 impl #ruma_common::api::OutgoingResponse for Response {
68 fn try_into_http_response<T: ::std::default::Default + #bytes::BufMut>(
69 self,
70 ) -> ::std::result::Result<#http::Response<T>, #ruma_common::api::error::IntoHttpError> {
71 let mut resp_builder = #http::Response::builder()
72 .status(#http::StatusCode::#status_ident)
73 .header(#http::header::CONTENT_TYPE, "application/json");
74
75 if let Some(mut headers) = resp_builder.headers_mut() {
76 #(#serialize_response_headers)*
77 }
78
79 ::std::result::Result::Ok(resp_builder.body(#body)?)
80 }
81 }
82 }
83 }
84}