133d722a9Sopenharmony_ciuse crate::syntax::{derive, Enum, Struct, Trait}; 233d722a9Sopenharmony_ciuse proc_macro2::{Ident, Span, TokenStream}; 333d722a9Sopenharmony_ciuse quote::{quote, quote_spanned, ToTokens}; 433d722a9Sopenharmony_ci 533d722a9Sopenharmony_cipub use crate::syntax::derive::*; 633d722a9Sopenharmony_ci 733d722a9Sopenharmony_cipub fn expand_struct(strct: &Struct, actual_derives: &mut Option<TokenStream>) -> TokenStream { 833d722a9Sopenharmony_ci let mut expanded = TokenStream::new(); 933d722a9Sopenharmony_ci let mut traits = Vec::new(); 1033d722a9Sopenharmony_ci 1133d722a9Sopenharmony_ci for derive in &strct.derives { 1233d722a9Sopenharmony_ci let span = derive.span; 1333d722a9Sopenharmony_ci match derive.what { 1433d722a9Sopenharmony_ci Trait::Copy => expanded.extend(struct_copy(strct, span)), 1533d722a9Sopenharmony_ci Trait::Clone => expanded.extend(struct_clone(strct, span)), 1633d722a9Sopenharmony_ci Trait::Debug => expanded.extend(struct_debug(strct, span)), 1733d722a9Sopenharmony_ci Trait::Default => expanded.extend(struct_default(strct, span)), 1833d722a9Sopenharmony_ci Trait::Eq => traits.push(quote_spanned!(span=> ::cxx::core::cmp::Eq)), 1933d722a9Sopenharmony_ci Trait::ExternType => unreachable!(), 2033d722a9Sopenharmony_ci Trait::Hash => traits.push(quote_spanned!(span=> ::cxx::core::hash::Hash)), 2133d722a9Sopenharmony_ci Trait::Ord => expanded.extend(struct_ord(strct, span)), 2233d722a9Sopenharmony_ci Trait::PartialEq => traits.push(quote_spanned!(span=> ::cxx::core::cmp::PartialEq)), 2333d722a9Sopenharmony_ci Trait::PartialOrd => expanded.extend(struct_partial_ord(strct, span)), 2433d722a9Sopenharmony_ci Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)), 2533d722a9Sopenharmony_ci Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)), 2633d722a9Sopenharmony_ci } 2733d722a9Sopenharmony_ci } 2833d722a9Sopenharmony_ci 2933d722a9Sopenharmony_ci if traits.is_empty() { 3033d722a9Sopenharmony_ci *actual_derives = None; 3133d722a9Sopenharmony_ci } else { 3233d722a9Sopenharmony_ci *actual_derives = Some(quote!(#[derive(#(#traits),*)])); 3333d722a9Sopenharmony_ci } 3433d722a9Sopenharmony_ci 3533d722a9Sopenharmony_ci expanded 3633d722a9Sopenharmony_ci} 3733d722a9Sopenharmony_ci 3833d722a9Sopenharmony_cipub fn expand_enum(enm: &Enum, actual_derives: &mut Option<TokenStream>) -> TokenStream { 3933d722a9Sopenharmony_ci let mut expanded = TokenStream::new(); 4033d722a9Sopenharmony_ci let mut traits = Vec::new(); 4133d722a9Sopenharmony_ci let mut has_copy = false; 4233d722a9Sopenharmony_ci let mut has_clone = false; 4333d722a9Sopenharmony_ci let mut has_eq = false; 4433d722a9Sopenharmony_ci let mut has_partial_eq = false; 4533d722a9Sopenharmony_ci 4633d722a9Sopenharmony_ci for derive in &enm.derives { 4733d722a9Sopenharmony_ci let span = derive.span; 4833d722a9Sopenharmony_ci match derive.what { 4933d722a9Sopenharmony_ci Trait::Copy => { 5033d722a9Sopenharmony_ci expanded.extend(enum_copy(enm, span)); 5133d722a9Sopenharmony_ci has_copy = true; 5233d722a9Sopenharmony_ci } 5333d722a9Sopenharmony_ci Trait::Clone => { 5433d722a9Sopenharmony_ci expanded.extend(enum_clone(enm, span)); 5533d722a9Sopenharmony_ci has_clone = true; 5633d722a9Sopenharmony_ci } 5733d722a9Sopenharmony_ci Trait::Debug => expanded.extend(enum_debug(enm, span)), 5833d722a9Sopenharmony_ci Trait::Default => unreachable!(), 5933d722a9Sopenharmony_ci Trait::Eq => { 6033d722a9Sopenharmony_ci traits.push(quote_spanned!(span=> ::cxx::core::cmp::Eq)); 6133d722a9Sopenharmony_ci has_eq = true; 6233d722a9Sopenharmony_ci } 6333d722a9Sopenharmony_ci Trait::ExternType => unreachable!(), 6433d722a9Sopenharmony_ci Trait::Hash => traits.push(quote_spanned!(span=> ::cxx::core::hash::Hash)), 6533d722a9Sopenharmony_ci Trait::Ord => expanded.extend(enum_ord(enm, span)), 6633d722a9Sopenharmony_ci Trait::PartialEq => { 6733d722a9Sopenharmony_ci traits.push(quote_spanned!(span=> ::cxx::core::cmp::PartialEq)); 6833d722a9Sopenharmony_ci has_partial_eq = true; 6933d722a9Sopenharmony_ci } 7033d722a9Sopenharmony_ci Trait::PartialOrd => expanded.extend(enum_partial_ord(enm, span)), 7133d722a9Sopenharmony_ci Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)), 7233d722a9Sopenharmony_ci Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)), 7333d722a9Sopenharmony_ci } 7433d722a9Sopenharmony_ci } 7533d722a9Sopenharmony_ci 7633d722a9Sopenharmony_ci let span = enm.name.rust.span(); 7733d722a9Sopenharmony_ci if !has_copy { 7833d722a9Sopenharmony_ci expanded.extend(enum_copy(enm, span)); 7933d722a9Sopenharmony_ci } 8033d722a9Sopenharmony_ci if !has_clone { 8133d722a9Sopenharmony_ci expanded.extend(enum_clone(enm, span)); 8233d722a9Sopenharmony_ci } 8333d722a9Sopenharmony_ci if !has_eq { 8433d722a9Sopenharmony_ci // Required to be derived in order for the enum's "variants" to be 8533d722a9Sopenharmony_ci // usable in patterns. 8633d722a9Sopenharmony_ci traits.push(quote!(::cxx::core::cmp::Eq)); 8733d722a9Sopenharmony_ci } 8833d722a9Sopenharmony_ci if !has_partial_eq { 8933d722a9Sopenharmony_ci traits.push(quote!(::cxx::core::cmp::PartialEq)); 9033d722a9Sopenharmony_ci } 9133d722a9Sopenharmony_ci 9233d722a9Sopenharmony_ci *actual_derives = Some(quote!(#[derive(#(#traits),*)])); 9333d722a9Sopenharmony_ci 9433d722a9Sopenharmony_ci expanded 9533d722a9Sopenharmony_ci} 9633d722a9Sopenharmony_ci 9733d722a9Sopenharmony_cifn struct_copy(strct: &Struct, span: Span) -> TokenStream { 9833d722a9Sopenharmony_ci let ident = &strct.name.rust; 9933d722a9Sopenharmony_ci let generics = &strct.generics; 10033d722a9Sopenharmony_ci 10133d722a9Sopenharmony_ci quote_spanned! {span=> 10233d722a9Sopenharmony_ci impl #generics ::cxx::core::marker::Copy for #ident #generics {} 10333d722a9Sopenharmony_ci } 10433d722a9Sopenharmony_ci} 10533d722a9Sopenharmony_ci 10633d722a9Sopenharmony_cifn struct_clone(strct: &Struct, span: Span) -> TokenStream { 10733d722a9Sopenharmony_ci let ident = &strct.name.rust; 10833d722a9Sopenharmony_ci let generics = &strct.generics; 10933d722a9Sopenharmony_ci 11033d722a9Sopenharmony_ci let body = if derive::contains(&strct.derives, Trait::Copy) { 11133d722a9Sopenharmony_ci quote!(*self) 11233d722a9Sopenharmony_ci } else { 11333d722a9Sopenharmony_ci let fields = strct.fields.iter().map(|field| &field.name.rust); 11433d722a9Sopenharmony_ci let values = strct.fields.iter().map(|field| { 11533d722a9Sopenharmony_ci let ident = &field.name.rust; 11633d722a9Sopenharmony_ci let ty = field.ty.to_token_stream(); 11733d722a9Sopenharmony_ci let span = ty.into_iter().last().unwrap().span(); 11833d722a9Sopenharmony_ci quote_spanned!(span=> &self.#ident) 11933d722a9Sopenharmony_ci }); 12033d722a9Sopenharmony_ci quote_spanned!(span=> #ident { 12133d722a9Sopenharmony_ci #(#fields: ::cxx::core::clone::Clone::clone(#values),)* 12233d722a9Sopenharmony_ci }) 12333d722a9Sopenharmony_ci }; 12433d722a9Sopenharmony_ci 12533d722a9Sopenharmony_ci quote_spanned! {span=> 12633d722a9Sopenharmony_ci #[allow(clippy::expl_impl_clone_on_copy)] 12733d722a9Sopenharmony_ci impl #generics ::cxx::core::clone::Clone for #ident #generics { 12833d722a9Sopenharmony_ci fn clone(&self) -> Self { 12933d722a9Sopenharmony_ci #body 13033d722a9Sopenharmony_ci } 13133d722a9Sopenharmony_ci } 13233d722a9Sopenharmony_ci } 13333d722a9Sopenharmony_ci} 13433d722a9Sopenharmony_ci 13533d722a9Sopenharmony_cifn struct_debug(strct: &Struct, span: Span) -> TokenStream { 13633d722a9Sopenharmony_ci let ident = &strct.name.rust; 13733d722a9Sopenharmony_ci let generics = &strct.generics; 13833d722a9Sopenharmony_ci let struct_name = ident.to_string(); 13933d722a9Sopenharmony_ci let fields = strct.fields.iter().map(|field| &field.name.rust); 14033d722a9Sopenharmony_ci let field_names = fields.clone().map(Ident::to_string); 14133d722a9Sopenharmony_ci 14233d722a9Sopenharmony_ci quote_spanned! {span=> 14333d722a9Sopenharmony_ci impl #generics ::cxx::core::fmt::Debug for #ident #generics { 14433d722a9Sopenharmony_ci fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { 14533d722a9Sopenharmony_ci formatter.debug_struct(#struct_name) 14633d722a9Sopenharmony_ci #(.field(#field_names, &self.#fields))* 14733d722a9Sopenharmony_ci .finish() 14833d722a9Sopenharmony_ci } 14933d722a9Sopenharmony_ci } 15033d722a9Sopenharmony_ci } 15133d722a9Sopenharmony_ci} 15233d722a9Sopenharmony_ci 15333d722a9Sopenharmony_cifn struct_default(strct: &Struct, span: Span) -> TokenStream { 15433d722a9Sopenharmony_ci let ident = &strct.name.rust; 15533d722a9Sopenharmony_ci let generics = &strct.generics; 15633d722a9Sopenharmony_ci let fields = strct.fields.iter().map(|field| &field.name.rust); 15733d722a9Sopenharmony_ci 15833d722a9Sopenharmony_ci quote_spanned! {span=> 15933d722a9Sopenharmony_ci #[allow(clippy::derivable_impls)] // different spans than the derived impl 16033d722a9Sopenharmony_ci impl #generics ::cxx::core::default::Default for #ident #generics { 16133d722a9Sopenharmony_ci fn default() -> Self { 16233d722a9Sopenharmony_ci #ident { 16333d722a9Sopenharmony_ci #( 16433d722a9Sopenharmony_ci #fields: ::cxx::core::default::Default::default(), 16533d722a9Sopenharmony_ci )* 16633d722a9Sopenharmony_ci } 16733d722a9Sopenharmony_ci } 16833d722a9Sopenharmony_ci } 16933d722a9Sopenharmony_ci } 17033d722a9Sopenharmony_ci} 17133d722a9Sopenharmony_ci 17233d722a9Sopenharmony_cifn struct_ord(strct: &Struct, span: Span) -> TokenStream { 17333d722a9Sopenharmony_ci let ident = &strct.name.rust; 17433d722a9Sopenharmony_ci let generics = &strct.generics; 17533d722a9Sopenharmony_ci let fields = strct.fields.iter().map(|field| &field.name.rust); 17633d722a9Sopenharmony_ci 17733d722a9Sopenharmony_ci quote_spanned! {span=> 17833d722a9Sopenharmony_ci impl #generics ::cxx::core::cmp::Ord for #ident #generics { 17933d722a9Sopenharmony_ci fn cmp(&self, other: &Self) -> ::cxx::core::cmp::Ordering { 18033d722a9Sopenharmony_ci #( 18133d722a9Sopenharmony_ci match ::cxx::core::cmp::Ord::cmp(&self.#fields, &other.#fields) { 18233d722a9Sopenharmony_ci ::cxx::core::cmp::Ordering::Equal => {} 18333d722a9Sopenharmony_ci ordering => return ordering, 18433d722a9Sopenharmony_ci } 18533d722a9Sopenharmony_ci )* 18633d722a9Sopenharmony_ci ::cxx::core::cmp::Ordering::Equal 18733d722a9Sopenharmony_ci } 18833d722a9Sopenharmony_ci } 18933d722a9Sopenharmony_ci } 19033d722a9Sopenharmony_ci} 19133d722a9Sopenharmony_ci 19233d722a9Sopenharmony_cifn struct_partial_ord(strct: &Struct, span: Span) -> TokenStream { 19333d722a9Sopenharmony_ci let ident = &strct.name.rust; 19433d722a9Sopenharmony_ci let generics = &strct.generics; 19533d722a9Sopenharmony_ci 19633d722a9Sopenharmony_ci let body = if derive::contains(&strct.derives, Trait::Ord) { 19733d722a9Sopenharmony_ci quote! { 19833d722a9Sopenharmony_ci ::cxx::core::option::Option::Some(::cxx::core::cmp::Ord::cmp(self, other)) 19933d722a9Sopenharmony_ci } 20033d722a9Sopenharmony_ci } else { 20133d722a9Sopenharmony_ci let fields = strct.fields.iter().map(|field| &field.name.rust); 20233d722a9Sopenharmony_ci quote! { 20333d722a9Sopenharmony_ci #( 20433d722a9Sopenharmony_ci match ::cxx::core::cmp::PartialOrd::partial_cmp(&self.#fields, &other.#fields) { 20533d722a9Sopenharmony_ci ::cxx::core::option::Option::Some(::cxx::core::cmp::Ordering::Equal) => {} 20633d722a9Sopenharmony_ci ordering => return ordering, 20733d722a9Sopenharmony_ci } 20833d722a9Sopenharmony_ci )* 20933d722a9Sopenharmony_ci ::cxx::core::option::Option::Some(::cxx::core::cmp::Ordering::Equal) 21033d722a9Sopenharmony_ci } 21133d722a9Sopenharmony_ci }; 21233d722a9Sopenharmony_ci 21333d722a9Sopenharmony_ci quote_spanned! {span=> 21433d722a9Sopenharmony_ci impl #generics ::cxx::core::cmp::PartialOrd for #ident #generics { 21533d722a9Sopenharmony_ci fn partial_cmp(&self, other: &Self) -> ::cxx::core::option::Option<::cxx::core::cmp::Ordering> { 21633d722a9Sopenharmony_ci #body 21733d722a9Sopenharmony_ci } 21833d722a9Sopenharmony_ci } 21933d722a9Sopenharmony_ci } 22033d722a9Sopenharmony_ci} 22133d722a9Sopenharmony_ci 22233d722a9Sopenharmony_cifn enum_copy(enm: &Enum, span: Span) -> TokenStream { 22333d722a9Sopenharmony_ci let ident = &enm.name.rust; 22433d722a9Sopenharmony_ci 22533d722a9Sopenharmony_ci quote_spanned! {span=> 22633d722a9Sopenharmony_ci impl ::cxx::core::marker::Copy for #ident {} 22733d722a9Sopenharmony_ci } 22833d722a9Sopenharmony_ci} 22933d722a9Sopenharmony_ci 23033d722a9Sopenharmony_cifn enum_clone(enm: &Enum, span: Span) -> TokenStream { 23133d722a9Sopenharmony_ci let ident = &enm.name.rust; 23233d722a9Sopenharmony_ci 23333d722a9Sopenharmony_ci quote_spanned! {span=> 23433d722a9Sopenharmony_ci #[allow(clippy::expl_impl_clone_on_copy)] 23533d722a9Sopenharmony_ci impl ::cxx::core::clone::Clone for #ident { 23633d722a9Sopenharmony_ci fn clone(&self) -> Self { 23733d722a9Sopenharmony_ci *self 23833d722a9Sopenharmony_ci } 23933d722a9Sopenharmony_ci } 24033d722a9Sopenharmony_ci } 24133d722a9Sopenharmony_ci} 24233d722a9Sopenharmony_ci 24333d722a9Sopenharmony_cifn enum_debug(enm: &Enum, span: Span) -> TokenStream { 24433d722a9Sopenharmony_ci let ident = &enm.name.rust; 24533d722a9Sopenharmony_ci let variants = enm.variants.iter().map(|variant| { 24633d722a9Sopenharmony_ci let variant = &variant.name.rust; 24733d722a9Sopenharmony_ci let name = variant.to_string(); 24833d722a9Sopenharmony_ci quote_spanned! {span=> 24933d722a9Sopenharmony_ci #ident::#variant => formatter.write_str(#name), 25033d722a9Sopenharmony_ci } 25133d722a9Sopenharmony_ci }); 25233d722a9Sopenharmony_ci let fallback = format!("{}({{}})", ident); 25333d722a9Sopenharmony_ci 25433d722a9Sopenharmony_ci quote_spanned! {span=> 25533d722a9Sopenharmony_ci impl ::cxx::core::fmt::Debug for #ident { 25633d722a9Sopenharmony_ci fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { 25733d722a9Sopenharmony_ci match *self { 25833d722a9Sopenharmony_ci #(#variants)* 25933d722a9Sopenharmony_ci _ => ::cxx::core::write!(formatter, #fallback, self.repr), 26033d722a9Sopenharmony_ci } 26133d722a9Sopenharmony_ci } 26233d722a9Sopenharmony_ci } 26333d722a9Sopenharmony_ci } 26433d722a9Sopenharmony_ci} 26533d722a9Sopenharmony_ci 26633d722a9Sopenharmony_cifn enum_ord(enm: &Enum, span: Span) -> TokenStream { 26733d722a9Sopenharmony_ci let ident = &enm.name.rust; 26833d722a9Sopenharmony_ci 26933d722a9Sopenharmony_ci quote_spanned! {span=> 27033d722a9Sopenharmony_ci impl ::cxx::core::cmp::Ord for #ident { 27133d722a9Sopenharmony_ci fn cmp(&self, other: &Self) -> ::cxx::core::cmp::Ordering { 27233d722a9Sopenharmony_ci ::cxx::core::cmp::Ord::cmp(&self.repr, &other.repr) 27333d722a9Sopenharmony_ci } 27433d722a9Sopenharmony_ci } 27533d722a9Sopenharmony_ci } 27633d722a9Sopenharmony_ci} 27733d722a9Sopenharmony_ci 27833d722a9Sopenharmony_cifn enum_partial_ord(enm: &Enum, span: Span) -> TokenStream { 27933d722a9Sopenharmony_ci let ident = &enm.name.rust; 28033d722a9Sopenharmony_ci 28133d722a9Sopenharmony_ci quote_spanned! {span=> 28233d722a9Sopenharmony_ci impl ::cxx::core::cmp::PartialOrd for #ident { 28333d722a9Sopenharmony_ci fn partial_cmp(&self, other: &Self) -> ::cxx::core::option::Option<::cxx::core::cmp::Ordering> { 28433d722a9Sopenharmony_ci ::cxx::core::cmp::PartialOrd::partial_cmp(&self.repr, &other.repr) 28533d722a9Sopenharmony_ci } 28633d722a9Sopenharmony_ci } 28733d722a9Sopenharmony_ci } 28833d722a9Sopenharmony_ci} 289