From 4c01fee5c5018b41689a163166c8a8f1500420e8 Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Tue, 28 Jul 2020 17:12:32 -0400 Subject: [PATCH] Move new type body init field (last field initialized) --- ruma-api-macros/src/api/request.rs | 17 +++++++++++++++-- ruma-api-macros/src/api/response.rs | 20 ++++++++++++++------ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/ruma-api-macros/src/api/request.rs b/ruma-api-macros/src/api/request.rs index 95e3ef0c..0918849d 100644 --- a/ruma-api-macros/src/api/request.rs +++ b/ruma-api-macros/src/api/request.rs @@ -163,7 +163,7 @@ impl Request { request_field_kind: RequestFieldKind, src: TokenStream, ) -> TokenStream { - let fields = self.fields.iter().filter_map(|f| { + let process_field = |f: &RequestField| { f.field_of_kind(request_field_kind).map(|field| { let field_name = field.ident.as_ref().expect("expected field to have an identifier"); @@ -176,7 +176,20 @@ impl Request { #field_name: #src.#field_name } }) - }); + }; + + let mut fields = vec![]; + let mut new_type_body = None; + for field in &self.fields { + if let RequestField::NewtypeRawBody(_) = field { + new_type_body = process_field(field); + } else { + fields.extend(process_field(field)); + } + } + + // Move field that consumes `request` to the end of the init list. + fields.extend(new_type_body); quote! { #(#fields,)* } } diff --git a/ruma-api-macros/src/api/response.rs b/ruma-api-macros/src/api/response.rs index 0d8d8283..3ff77f61 100644 --- a/ruma-api-macros/src/api/response.rs +++ b/ruma-api-macros/src/api/response.rs @@ -38,14 +38,16 @@ impl Response { /// Produces code for a response struct initializer. pub fn init_fields(&self) -> TokenStream { - let fields = self.fields.iter().map(|response_field| { + let mut fields = vec![]; + let mut new_type_raw_body = None; + for response_field in &self.fields { let field = response_field.field(); let field_name = field.ident.as_ref().expect("expected field to have an identifier"); let span = field.span(); let cfg_attrs = field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::>(); - match response_field { + fields.push(match response_field { ResponseField::Body(_) => { quote_spanned! {span=> #( #cfg_attrs )* @@ -66,13 +68,19 @@ impl Response { #field_name: response_body.0 } } + // This field must be instantiated last to avoid `use of move value` error. + // We are guaranteed only one new body field because of a check in `try_from`. ResponseField::NewtypeRawBody(_) => { - quote_spanned! {span=> + new_type_raw_body = Some(quote_spanned! {span=> #field_name: response.into_body() - } + }); + // skip adding to the vec + continue; } - } - }); + }); + } + + fields.extend(new_type_raw_body); quote! { #(#fields,)*