csskit_derives 0.0.22

Derive macros for CSS parsing, visiting, and AST operations.
Documentation
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Error, Fields, Result, parse_quote};
use synstructure::{AddBounds, BindStyle, Structure};

use crate::WhereCollector;

pub fn derive(input: DeriveInput) -> Result<TokenStream> {
	if let Data::Struct(ref s) = input.data
		&& matches!(s.fields, Fields::Unit)
	{
		return Err(Error::new(input.ident.span(), "Cannot derive ToCursors on this struct"));
	}
	if matches!(input.data, Data::Union(_)) {
		return Err(Error::new(input.ident.span(), "Cannot derive ToCursors on a Union"));
	}

	let mut s = Structure::try_new(&input)?;
	s.add_bounds(AddBounds::None);
	s.bind_with(|_| BindStyle::Ref);

	let body = s.each(|bi| {
		quote! { ::css_parse::ToCursors::to_cursors(#bi, s); }
	});

	let mut wc = WhereCollector::new();
	for variant in s.variants() {
		for binding in variant.bindings() {
			wc.add(&binding.ast().ty);
		}
	}
	let where_clause = wc.extend_where_clause(&input.generics, parse_quote! { ::css_parse::ToCursors });

	let ident = &input.ident;
	let generics = &input.generics;
	let (impl_generics, type_generics, _) = generics.split_for_impl();

	Ok(quote! {
		#[automatically_derived]
		impl #impl_generics ::css_parse::ToCursors for #ident #type_generics #where_clause {
			fn to_cursors(&self, s: &mut impl ::css_parse::CursorSink) {
				match *self { #body }
			}
		}
	})
}