95 lines
3.9 KiB
Rust
95 lines
3.9 KiB
Rust
use proc_macro2::TokenStream;
|
|
use quote::quote;
|
|
|
|
use super::{Response, ResponseField};
|
|
|
|
impl Response {
|
|
pub fn expand_outgoing(&self, ruma_api: &TokenStream) -> TokenStream {
|
|
let bytes = quote! { #ruma_api::exports::bytes };
|
|
let http = quote! { #ruma_api::exports::http };
|
|
let ruma_serde = quote! { #ruma_api::exports::ruma_serde };
|
|
|
|
let serialize_response_headers = self.fields.iter().map(|response_field| {
|
|
if let ResponseField::Header(field, header_name) = response_field {
|
|
let field_name =
|
|
field.ident.as_ref().expect("expected field to have an identifier");
|
|
|
|
match &field.ty {
|
|
syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. })
|
|
if segments.last().unwrap().ident == "Option" =>
|
|
{
|
|
quote! {
|
|
if let Some(header) = self.#field_name {
|
|
headers.insert(
|
|
#http::header::#header_name,
|
|
header.parse()?,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
_ => quote! {
|
|
headers.insert(
|
|
#http::header::#header_name,
|
|
self.#field_name.parse()?,
|
|
);
|
|
},
|
|
}
|
|
} else {
|
|
TokenStream::new()
|
|
}
|
|
});
|
|
|
|
let body = if let Some(field) = self.newtype_raw_body_field() {
|
|
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
|
quote! { #ruma_serde::slice_to_buf(&self.#field_name) }
|
|
} else if let Some(field) = self.newtype_body_field() {
|
|
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
|
quote! {
|
|
#ruma_serde::json_to_buf(&self.#field_name)?
|
|
}
|
|
} else {
|
|
let fields = self.fields.iter().map(|response_field| {
|
|
if let ResponseField::Body(field) = response_field {
|
|
let field_name =
|
|
field.ident.as_ref().expect("expected field to have an identifier");
|
|
let cfg_attrs = field.attrs.iter().filter(|a| a.path.is_ident("cfg"));
|
|
|
|
quote! {
|
|
#( #cfg_attrs )*
|
|
#field_name: self.#field_name,
|
|
}
|
|
} else {
|
|
TokenStream::new()
|
|
}
|
|
});
|
|
|
|
quote! {
|
|
#ruma_serde::json_to_buf(&ResponseBody { #(#fields)* })?
|
|
}
|
|
};
|
|
|
|
quote! {
|
|
#[automatically_derived]
|
|
#[cfg(feature = "server")]
|
|
#[allow(clippy::unknown_clippy_lints, clippy::inconsistent_struct_constructor)]
|
|
impl #ruma_api::OutgoingResponse for Response {
|
|
fn try_into_http_response<T: ::std::default::Default + #bytes::BufMut>(
|
|
self,
|
|
) -> ::std::result::Result<#http::Response<T>, #ruma_api::error::IntoHttpError> {
|
|
let mut resp_builder = #http::Response::builder()
|
|
.header(#http::header::CONTENT_TYPE, "application/json");
|
|
|
|
let mut headers = resp_builder
|
|
.headers_mut()
|
|
.expect("`http::ResponseBuilder` is in unusable state");
|
|
#(#serialize_response_headers)*
|
|
|
|
// This cannot fail because we parse each header value checking for errors as
|
|
// each value is inserted and we only allow keys from the `http::header` module.
|
|
::std::result::Result::Ok(resp_builder.body(#body).unwrap())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|