summaryrefslogtreecommitdiffstats
path: root/vendor/derivative/src/clone.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:42 +0000
commitcec1877e180393eba0f6ddb0cf97bf3a791631c7 (patch)
tree47b4dac2a9dd9a40c30c251b4d4a72d7ccf77e9f /vendor/derivative/src/clone.rs
parentAdding debian version 1.74.1+dfsg1-1. (diff)
downloadrustc-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.rs196
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,
+ &copy_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)
+ }
+}