csskit_derives 0.0.24

Derive macros for CSS parsing, visiting, and AST operations.
Documentation
use darling::FromAttributes;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{DeriveInput, Ident, Result};

use crate::darling_ext::{InheritsArg, PipeList};

#[derive(Debug, Default, FromAttributes)]
#[darling(attributes(declaration_metadata))]
struct MetadataArg {
	#[darling(default)]
	pub initial: Option<String>,
	#[darling(default)]
	pub inherits: Option<InheritsArg>,
	#[darling(default)]
	pub applies_to: Option<PipeList<Ident>>,
	#[darling(default)]
	pub animation_type: Option<Ident>,
	#[darling(default)]
	pub percentages: Option<Ident>,
	#[darling(default)]
	pub shorthand_group: Option<Ident>,
	#[darling(default)]
	pub longhands: Option<PipeList<Ident>>,
	#[darling(default)]
	pub property_group: Option<Ident>,
	#[darling(default)]
	pub computed_value_type: Option<Ident>,
	#[darling(default)]
	pub canonical_order: Option<String>,
	#[darling(default)]
	pub logical_property_group: Option<Ident>,
	#[darling(default)]
	pub box_side: Option<PipeList<Ident>>,
	#[darling(default)]
	pub box_portion: Option<PipeList<Ident>>,
	#[darling(default)]
	pub unitless_zero_resolves: Option<Ident>,
}

pub fn derive(input: DeriveInput) -> Result<TokenStream> {
	let attrs = MetadataArg::from_attributes(&input.attrs)?;
	let ident = &input.ident;
	let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
	let initial = attrs.initial.map(|initial| {
		quote! {
			fn initial() -> &'static str { #initial }
		}
	});
	let inherits = attrs.inherits.map(|InheritsArg(inherits)| {
		quote! {
			fn inherits() -> Inherits { Inherits::#inherits }
		}
	});
	let applies_to = attrs.applies_to.map(|PipeList(applies_to)| {
		quote! { fn applies_to() -> AppliesTo { #(AppliesTo::#applies_to)|* } }
	});
	let animation_type = attrs.animation_type.map(|animation_type| {
		quote! {
			fn animation_type() -> AnimationType { AnimationType::#animation_type }
		}
	});
	let percentages = attrs.percentages.map(|percentages| {
		quote! {
			fn percentages() -> Percentages { Percentages::#percentages }
		}
	});
	let shorthand_group = attrs.shorthand_group.map(|shorthand_group| {
		quote! {
			fn shorthand_group() -> CssAtomSet { CssAtomSet::#shorthand_group }
		}
	});
	let property_group = attrs.property_group.map(|property_group| {
		quote! {
			fn property_group() -> PropertyGroup { PropertyGroup::#property_group }
		}
	});
	let computed_value_type = attrs.computed_value_type.map(|computed_value_type| {
		quote! {
			fn computed_value_type() -> ComputedValueType { ComputedValueType::#computed_value_type }
		}
	});
	let canonical_order = attrs.canonical_order.map(|canonical_order| {
		quote! {
			fn canonical_order() -> Option<&'static str> { Some(#canonical_order) }
		}
	});
	let logical_property_group = attrs.logical_property_group.map(|logical_property_group| {
		quote! {
			fn logical_property_group() -> Option<CssAtomSet> { Some(CssAtomSet::#logical_property_group) }
		}
	});
	let box_side = attrs.box_side.map(|PipeList(box_side)| {
		quote! { fn box_side() -> BoxSide { #(BoxSide::#box_side)|* } }
	});
	let box_portion = attrs.box_portion.map(|PipeList(box_portion)| {
		quote! { fn box_portion() -> BoxPortion { #(BoxPortion::#box_portion)|* } }
	});
	let longhands = attrs.longhands.map(|PipeList(longhands)| {
		quote! {
			fn longhands() -> Option<&'static [CssAtomSet]> {
				Some(&[#(CssAtomSet::#longhands),*])
			}
			fn is_shorthand() -> bool { true }
		}
	});
	let unitless_zero_resolves = attrs.unitless_zero_resolves.map(|unitless_zero_resolves| {
		quote! {
			fn unitless_zero_resolves() -> crate::UnitlessZeroResolves { crate::UnitlessZeroResolves::#unitless_zero_resolves }
		}
	});
	Ok(quote! {
	  #[automatically_derived]
	  impl #impl_generics crate::DeclarationMetadata for #ident #type_generics #where_clause {
			#initial
			#inherits
			#applies_to
			#animation_type
			#percentages
			#shorthand_group
			#longhands
			#property_group
			#computed_value_type
			#canonical_order
			#logical_property_group
			#box_side
			#box_portion
			#unitless_zero_resolves
	  }
	})
}