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}