diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:42 +0000 |
commit | cec1877e180393eba0f6ddb0cf97bf3a791631c7 (patch) | |
tree | 47b4dac2a9dd9a40c30c251b4d4a72d7ccf77e9f /vendor/derivative/src/clone.rs | |
parent | Adding debian version 1.74.1+dfsg1-1. (diff) | |
download | rustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.tar.xz rustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/derivative/src/clone.rs')
-rw-r--r-- | vendor/derivative/src/clone.rs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/vendor/derivative/src/clone.rs b/vendor/derivative/src/clone.rs new file mode 100644 index 000000000..3594e9498 --- /dev/null +++ b/vendor/derivative/src/clone.rs @@ -0,0 +1,196 @@ +use proc_macro2; + +use ast; +use attr; +use matcher; +use syn; +use utils; + +/// Derive `Copy` for `input`. +pub fn derive_copy(input: &ast::Input) -> proc_macro2::TokenStream { + let name = &input.ident; + + let copy_trait_path = copy_trait_path(); + let generics = utils::build_impl_generics( + input, + ©_trait_path, + |attrs| attrs.copy_bound().is_none(), + |field| field.copy_bound(), + |input| input.copy_bound(), + ); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + quote! { + #[allow(unused_qualifications)] + impl #impl_generics #copy_trait_path for #name #ty_generics #where_clause {} + } +} + +/// Derive `Clone` for `input`. +pub fn derive_clone(input: &ast::Input) -> proc_macro2::TokenStream { + let name = &input.ident; + + let clone_trait_path = clone_trait_path(); + let generics = utils::build_impl_generics( + input, + &clone_trait_path, + needs_clone_bound, + |field| field.clone_bound(), + |input| input.clone_bound(), + ); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let is_copy = input.attrs.copy.is_some(); + if is_copy && input.generics.type_params().count() == 0 { + quote! { + #[allow(unused_qualifications)] + impl #impl_generics #clone_trait_path for #name #ty_generics #where_clause { + fn clone(&self) -> Self { + *self + } + } + } + } else { + let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed).build_arms( + input, + "__arg", + |arm_path, _, _, style, _, bis| { + let field_clones = bis.iter().map(|bi| { + let arg = &bi.expr; + + let clone = if let Some(clone_with) = bi.field.attrs.clone_with() { + quote!(#clone_with(&#arg)) + } else { + quote!(#arg.clone()) + }; + + if let Some(ref name) = bi.field.ident { + quote! { + #name: #clone + } + } else { + clone + } + }); + + match style { + ast::Style::Struct => { + quote! { + #arm_path { + #(#field_clones),* + } + } + } + ast::Style::Tuple => { + quote! { + #arm_path (#(#field_clones),*) + } + } + ast::Style::Unit => { + quote! { + #arm_path + } + } + } + }, + ); + + let clone_from = if input.attrs.clone_from() { + Some( + matcher::Matcher::new(matcher::BindingStyle::RefMut, input.attrs.is_packed).build_arms( + input, + "__arg", + |outer_arm_path, _, _, _, _, outer_bis| { + let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed).build_arms( + input, + "__other", + |inner_arm_path, _, _, _, _, inner_bis| { + if outer_arm_path == inner_arm_path { + let field_clones = outer_bis.iter().zip(inner_bis).map( + |(outer_bi, inner_bi)| { + let outer = &outer_bi.expr; + let inner = &inner_bi.expr; + + quote!(#outer.clone_from(&#inner);) + }, + ); + + quote! { + #(#field_clones)* + return; + } + } else { + quote!() + } + }, + ); + + quote! { + match *other { + #body + } + } + }, + ), + ) + } else { + None + }; + + let clone_from = clone_from.map(|body| { + // Enumerations are only cloned-from if both variants are the same. + // If they are different, fallback to normal cloning. + let fallback = if let ast::Body::Enum(_) = input.body { + Some(quote!(*self = other.clone();)) + } else { + None + }; + + quote! { + #[allow(clippy::needless_return)] + fn clone_from(&mut self, other: &Self) { + match *self { + #body + } + + #fallback + } + } + }); + + quote! { + #[allow(unused_qualifications)] + impl #impl_generics #clone_trait_path for #name #ty_generics #where_clause { + fn clone(&self) -> Self { + match *self { + #body + } + } + + #clone_from + } + } + } +} + +fn needs_clone_bound(attrs: &attr::Field) -> bool { + attrs.clone_bound().is_none() +} + +/// Return the path of the `Clone` trait, that is `::std::clone::Clone`. +fn clone_trait_path() -> syn::Path { + if cfg!(feature = "use_core") { + parse_quote!(::core::clone::Clone) + } else { + parse_quote!(::std::clone::Clone) + } +} + +/// Return the path of the `Copy` trait, that is `::std::marker::Copy`. +fn copy_trait_path() -> syn::Path { + if cfg!(feature = "use_core") { + parse_quote!(::core::marker::Copy) + } else { + parse_quote!(::std::marker::Copy) + } +} |