diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-01-07 13:11:46 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-01-07 13:26:51 +0100 |
| commit | 0b624390906e911bde325b487b2710b67c8205c8 (patch) | |
| tree | 43fbfc28082add3dcb1398ae0b6f71202fe51efe /macros | |
| parent | af014cfe5eea4233d8034c79c1a5f898c972396c (diff) | |
Scoped styles
Diffstat (limited to 'macros')
| -rw-r--r-- | macros/src/lib.rs | 103 |
1 files changed, 49 insertions, 54 deletions
diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 55e597b1..16fb7885 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -17,37 +17,34 @@ pub fn properties(_: TokenStream, item: TokenStream) -> TokenStream { /// Expand a property impl block for a node. fn expand(mut impl_block: syn::ItemImpl) -> Result<TokenStream2> { // Split the node type into name and generic type arguments. - let (self_name, self_args) = parse_self(&*impl_block.self_ty)?; + let self_ty = &*impl_block.self_ty; + let (self_name, self_args) = parse_self(self_ty)?; // Rewrite the const items from values to keys. - let mut style_ids = vec![]; let mut modules = vec![]; for item in &mut impl_block.items { if let syn::ImplItem::Const(item) = item { - let (style_id, module) = process_const(item, &self_name, &self_args)?; - style_ids.push(style_id); + let module = process_const( + item, + &impl_block.generics, + self_ty, + &self_name, + &self_args, + )?; modules.push(module); } } - // Here, we use the collected `style_ids` to provide a function that checks - // whether a property belongs to the node. - impl_block.items.insert(0, parse_quote! { - /// Check whether the property with the given type id belongs to `Self`. - pub fn has_property(id: StyleId) -> bool { - [#(#style_ids),*].contains(&id) - } - }); - // Put everything into a module with a hopefully unique type to isolate // it from the outside. let module = quote::format_ident!("{}_types", self_name); Ok(quote! { #[allow(non_snake_case)] mod #module { + use std::any::TypeId; use std::marker::PhantomData; use once_cell::sync::Lazy; - use crate::eval::{Nonfolding, Property, StyleId}; + use crate::eval::{Nonfolding, Property}; use super::*; #impl_block @@ -85,19 +82,21 @@ fn parse_self(self_ty: &syn::Type) -> Result<(String, Vec<&syn::Type>)> { /// Process a single const item. fn process_const( item: &mut syn::ImplItemConst, + impl_generics: &syn::Generics, + self_ty: &syn::Type, self_name: &str, self_args: &[&syn::Type], -) -> Result<(syn::Expr, syn::ItemMod)> { +) -> Result<syn::ItemMod> { + // The module that will contain the `Key` type. + let module_name = &item.ident; + // The type of the property's value is what the user of our macro wrote // as type of the const ... let value_ty = &item.ty; - // ... but the real type of the const becomes Key<#key_param>. - let key_param = if self_args.is_empty() { - quote! { #value_ty } - } else { - quote! { (#value_ty, #(#self_args),*) } - }; + // ... but the real type of the const becomes Key<#key_args>. + let key_params = &impl_generics.params; + let key_args = quote! { #value_ty #(, #self_args)* }; // The display name, e.g. `TextNode::STRONG`. let name = format!("{}::{}", self_name, &item.ident); @@ -108,7 +107,7 @@ fn process_const( let mut folder = None; let mut nonfolding = Some(quote! { - impl<T: 'static> Nonfolding for Key<T> {} + impl<#key_params> Nonfolding for Key<#key_args> {} }); // Look for a folding function like `#[fold(u64::add)]`. @@ -127,54 +126,50 @@ fn process_const( } } - // The implementation of the `Property` trait. - let property_impl = quote! { - impl<T: 'static> Property for Key<T> { - type Value = #value_ty; - - const NAME: &'static str = #name; + // Generate the module code. + let module = parse_quote! { + #[allow(non_snake_case)] + mod #module_name { + use super::*; - fn default() -> Self::Value { - #default - } + pub struct Key<T, #key_params>(pub PhantomData<(T, #key_args)>); - fn default_ref() -> &'static Self::Value { - static LAZY: Lazy<#value_ty> = Lazy::new(|| #default); - &*LAZY + impl<#key_params> Copy for Key<#key_args> {} + impl<#key_params> Clone for Key<#key_args> { + fn clone(&self) -> Self { + *self + } } - #folder - } + impl<#key_params> Property for Key<#key_args> { + type Value = #value_ty; - #nonfolding - }; + const NAME: &'static str = #name; - // The module that will contain the `Key` type. - let module_name = &item.ident; + fn node_id() -> TypeId { + TypeId::of::<#self_ty>() + } - // Generate the style id and module code. - let style_id = parse_quote! { StyleId::of::<#module_name::Key<#key_param>>() }; - let module = parse_quote! { - #[allow(non_snake_case)] - mod #module_name { - use super::*; + fn default() -> Self::Value { + #default + } - pub struct Key<T>(pub PhantomData<T>); - impl<T> Copy for Key<T> {} - impl<T> Clone for Key<T> { - fn clone(&self) -> Self { - *self + fn default_ref() -> &'static Self::Value { + static LAZY: Lazy<#value_ty> = Lazy::new(|| #default); + &*LAZY } + + #folder } - #property_impl + #nonfolding } }; // Replace type and initializer expression with the `Key`. item.attrs.retain(|attr| !attr.path.is_ident("fold")); - item.ty = parse_quote! { #module_name::Key<#key_param> }; + item.ty = parse_quote! { #module_name::Key<#key_args> }; item.expr = parse_quote! { #module_name::Key(PhantomData) }; - Ok((style_id, module)) + Ok(module) } |
