From 3853a36ff6b00f7500c89410f0027baec415dee7 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 20 Oct 2020 02:20:29 +0200 Subject: [PATCH] Support more unusual reference types in Outgoing derive --- ruma-common-macros/src/outgoing.rs | 64 ++++++++++++++++-------------- ruma-common/tests/outgoing.rs | 3 ++ 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/ruma-common-macros/src/outgoing.rs b/ruma-common-macros/src/outgoing.rs index ff72b955..b44cdc4b 100644 --- a/ruma-common-macros/src/outgoing.rs +++ b/ruma-common-macros/src/outgoing.rs @@ -240,37 +240,43 @@ fn strip_lifetimes(field_type: &mut Type) -> bool { has_lifetimes || is_lifetime_generic } - Type::Reference(TypeReference { elem, .. }) => match &mut **elem { - Type::Path(ty_path) => { - let TypePath { path, .. } = ty_path; - let segs = path - .segments - .clone() - .into_iter() - .map(|seg| seg.ident.to_string()) - .collect::>(); + Type::Reference(TypeReference { elem, .. }) => { + let special_replacement = match &mut **elem { + Type::Path(ty) => { + let path = &ty.path; + let last_seg = path.segments.last().unwrap(); - if path.is_ident("str") { - // &str -> String - *field_type = parse_quote! { ::std::string::String }; - } else if segs.contains(&"DeviceId".into()) || segs.contains(&"ServerName".into()) { - // The identifiers that need to be boxed `Box` since they are DST's. - *field_type = parse_quote! { ::std::boxed::Box<#path> }; - } else { - // &T -> T - *field_type = Type::Path(ty_path.clone()); + if last_seg.ident == "str" { + // &str -> String + Some(parse_quote! { ::std::string::String }) + } else if last_seg.ident == "DeviceId" || last_seg.ident == "ServerName" { + // The identifiers that need to be boxed `Box` since they are DST's. + Some(parse_quote! { ::std::boxed::Box<#path> }) + } else { + None + } } - true - } - // &[T] -> Vec - Type::Slice(TypeSlice { elem, .. }) => { - // Recursively strip the lifetimes of the slice's elements. - strip_lifetimes(&mut *elem); - *field_type = parse_quote! { Vec<#elem> }; - true - } - _ => false, - }, + // &[T] -> Vec + Type::Slice(TypeSlice { elem, .. }) => { + // Recursively strip the lifetimes of the slice's elements. + strip_lifetimes(&mut *elem); + Some(parse_quote! { Vec<#elem> }) + } + _ => None, + }; + + *field_type = match special_replacement { + Some(ty) => ty, + None => { + // Strip lifetimes of `elem`. + strip_lifetimes(elem); + // Replace reference with `elem`. + (**elem).clone() + } + }; + + true + } Type::Tuple(syn::TypeTuple { elems, .. }) => { let mut has_lifetime = false; for elem in elems { diff --git a/ruma-common/tests/outgoing.rs b/ruma-common/tests/outgoing.rs index 6bcc54d9..8fdc736d 100644 --- a/ruma-common/tests/outgoing.rs +++ b/ruma-common/tests/outgoing.rs @@ -32,6 +32,9 @@ pub struct FakeRequest<'a, T> { pub option: Option<&'a [u8]>, pub depth: Option<&'a [(&'a str, &'a str)]>, pub arc_type: std::sync::Arc<&'a ::ruma_identifiers::ServerName>, + pub thing_ref: &'a Thing<'a, T>, + pub double_ref: &'a &'a u8, + pub triple_ref: &'a &'a &'a str, } #[derive(Outgoing)]