diff --git a/src/expand.rs b/src/expand.rs index 4d59e14..c82737f 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -1,3 +1,4 @@ +use crate::utils::type_lifetimes_to_static; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use syn::{parse_quote, ItemStruct}; @@ -23,7 +24,10 @@ pub(crate) fn expand_struct(mut item: ItemStruct) -> proc_macro::TokenStream { } else { let fn_name_lit = format!("__serde_inline_default_{}_{}", item.ident, i); let fn_name_ident = Ident::new(&fn_name_lit, Span::call_site()); - let return_type = &field.ty; + let mut return_type = field.ty.clone(); + + // replaces most lifetimes with 'static + type_lifetimes_to_static(&mut return_type); let inline_fn = quote! { #[doc(hidden)] diff --git a/src/lib.rs b/src/lib.rs index c570c62..2701159 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use proc_macro::TokenStream; use syn::{parse_macro_input, Item}; mod expand; +mod utils; /// The main macro of this crate. /// Use it to define default values of fields in structs you [`Serialize`] or [`Deserialize`]. diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..8c854a7 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,41 @@ +use syn::{parse_quote, GenericArgument, PathArguments, Type}; + +pub(crate) fn type_lifetimes_to_static(ty: &mut Type) { + match ty { + Type::Array(array) => type_lifetimes_to_static(array.elem.as_mut()), + Type::Group(group) => type_lifetimes_to_static(&mut group.elem), + Type::ImplTrait(_) => {} + Type::Path(path) => { + for segment in &mut path.path.segments { + match &mut segment.arguments { + PathArguments::None => (), + PathArguments::AngleBracketed(angle_bracketed) => { + for arg in &mut angle_bracketed.args { + match arg { + GenericArgument::Lifetime(lifetime) => { + *lifetime = parse_quote!('static); + } + GenericArgument::Type(ty) => type_lifetimes_to_static(ty), + _ => (), + } + } + } + PathArguments::Parenthesized(parenthesized) => { + for input in &mut parenthesized.inputs { + type_lifetimes_to_static(input) + } + } + } + } + } + Type::Ptr(ptr) => type_lifetimes_to_static(&mut ptr.elem), + Type::Reference(reference) => reference.lifetime = Some(parse_quote!('static)), + Type::Slice(slice) => type_lifetimes_to_static(&mut slice.elem), + Type::Tuple(tuple) => { + for elem in &mut tuple.elems { + type_lifetimes_to_static(elem) + } + } + _ => (), + } +} diff --git a/tests/test_serde_inline_default.rs b/tests/test_serde_inline_default.rs index ffe42a5..cc07fc2 100644 --- a/tests/test_serde_inline_default.rs +++ b/tests/test_serde_inline_default.rs @@ -1,6 +1,7 @@ use serde::Deserialize; use serde_inline_default::serde_inline_default; use serde_json::json; +use std::borrow::Cow; #[test] fn test_serde_inline_default() { @@ -28,3 +29,17 @@ fn test_serde_inline_default() { assert_eq!(test.inline_negative, -1337); assert_eq!(test.string, "string".to_string()); } + +#[test] +fn test_lifetime() { + #[serde_inline_default] + #[derive(Deserialize)] + struct LifetimeTest<'a> { + #[serde_inline_default("test".into())] + test_str: Cow<'a, str>, + } + + let lifetime_test: LifetimeTest = serde_json::from_value(json!({})).unwrap(); + + assert_eq!(lifetime_test.test_str, "test"); +}