gazebo_derive/src/util.rs (117 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under both the MIT license found in the * LICENSE-MIT file in the root directory of this source tree and the Apache * License, Version 2.0 found in the LICENSE-APACHE file in the root directory * of this source tree. */ use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; use syn::{ spanned::Spanned, Data, DataEnum, DataStruct, Fields, GenericParam, Generics, Ident, Index, TypeParamBound, Variant, }; // Add a bound to every type parameter. pub fn add_trait_bounds(mut generics: Generics, bound: &TypeParamBound) -> Generics { for param in &mut generics.params { if let GenericParam::Type(ref mut type_param) = *param { type_param.bounds.push(bound.clone()); } } generics } fn duplicate_struct(data: &DataStruct, duplicate: &TokenStream) -> TokenStream { match data.fields { Fields::Named(ref fields) => { // Self {x: clone(self.x), y: clone(self.y)} let xs = fields.named.iter().map(|f| { let name = &f.ident; quote_spanned! {f.span() => #name: #duplicate(&self.#name) } }); quote! { Self { #(#xs, )* } } } Fields::Unnamed(ref fields) => { // Self(clone(self.0), clone(self.1)) let xs = fields.unnamed.iter().enumerate().map(|(i, f)| { let index = Index::from(i); quote_spanned! {f.span()=> #duplicate(&self.#index) } }); quote! { Self ( #(#xs, )* ) } } Fields::Unit => { // Self quote!(Self) } } } fn duplicate_variant(data: &Variant, duplicate: &TokenStream) -> TokenStream { let ctor = &data.ident; match data.fields { Fields::Named(ref fields) => { // Self::Ctor{x,y} => {x: clone(x), y: clone(y)} let (pats, es): (Vec<_>, Vec<_>) = fields .named .iter() .map(|f| { let name = &f.ident; ( quote_spanned! {f.span() => #name }, quote_spanned! {f.span() => #name: #duplicate(#name) }, ) }) .unzip(); quote! { Self::#ctor{ #(#pats, )* } => Self::#ctor{ #(#es, )* } } } Fields::Unnamed(ref fields) => { // Self::Ctor(v0,v1) => Self::Ctor(clone(v0), clone(v1)) let (pats, es): (Vec<_>, Vec<_>) = fields .unnamed .iter() .enumerate() .map(|(i, f)| { let var = Ident::new(&format!("v{}", i), f.span()); ( quote_spanned! {f.span() => #var}, quote_spanned! {f.span() => #duplicate(#var)}, ) }) .unzip(); quote! { Self::#ctor( #(#pats,)* ) => Self::#ctor( #(#es,)* ) } } Fields::Unit => { // Self::Ctor => Self::Ctor quote!(Self::#ctor => Self::#ctor) } } } fn duplicate_enum(data: &DataEnum, duplicate: &TokenStream) -> TokenStream { let xs = data .variants .iter() .map(|v| duplicate_variant(v, duplicate)); quote! { match self { #(#xs, )* } } } pub fn duplicate_impl(data: &Data, duplicate: &TokenStream) -> TokenStream { match data { Data::Struct(data) => duplicate_struct(data, duplicate), Data::Enum(data) => duplicate_enum(data, duplicate), Data::Union(x) => { syn::Error::new_spanned(x.union_token, "Can't derive duplication for unions") .into_compile_error() } } }