hobo_derive 0.1.4

hobo is a Rust frontend framework
Documentation
use derive_utils::quick_derive as enum_derive;
// use proc_macro2::TokenStream;
use proc_quote::quote;
use quote::ToTokens;
use proc_macro_error::proc_macro_error;

#[proc_macro_error]
#[proc_macro_attribute]
pub fn trick(_: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
	let syn::ImplItemMethod { attrs, vis, defaultness, mut sig, block } = syn::parse_macro_input!(item as syn::ImplItemMethod);
	sig.output = syn::parse_quote!(-> ::std::rc::Rc<::std::cell::RefCell<Self>>);
	(quote! {
		#(#attrs)* #vis #defaultness #sig {
			let mut this: ::std::rc::Rc<::std::mem::MaybeUninit<::std::cell::RefCell<Self>>> = ::std::rc::Rc::new(::std::mem::MaybeUninit::uninit());
			let new_this = #block;
			unsafe {
				let raw_uninit = ::std::rc::Rc::into_raw(this) as *mut ::std::mem::MaybeUninit<_>;
				let raw_init = (&mut *raw_uninit).as_mut_ptr();
				std::ptr::write(raw_init, ::std::cell::RefCell::new(new_this));
				::std::rc::Rc::from_raw(raw_init)
			}
		}
	}).into()
}

#[proc_macro_derive(Element)]
pub fn derive_element(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
	let input = syn::parse_macro_input!(input as syn::DeriveInput);

	match &input.data {
		syn::Data::Enum(_) => enum_derive! {
			input.to_token_stream(),
			::hobo::Element,
			trait Element {
				fn element(&self) -> ::std::borrow::Cow<'_, ::hobo::web_sys::Element>;
			}
		},
		_ => {
			let name = input.ident;
			let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
			(quote! {
				impl #impl_generics ::hobo::Element for #name #ty_generics #where_clause {
					fn element(&self) -> ::std::borrow::Cow<'_, ::hobo::web_sys::Element> { self.element.element() }
				}
			}).into()
		},
	}
}

#[proc_macro_derive(EventTarget)]
pub fn derive_event_target(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
	let input = syn::parse_macro_input!(input as syn::DeriveInput);

	match &input.data {
		syn::Data::Enum(_) => enum_derive! {
			input.to_token_stream(),
			::hobo::EventTarget,
			trait EventTarget {
				fn event_handlers(&self) -> ::std::cell::RefMut<::std::vec::Vec<::hobo::EventHandler>>;
			}
		},
		_ => {
			let name = input.ident;
			let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
			(quote! {
				impl #impl_generics ::hobo::EventTarget for #name #ty_generics #where_clause {
					fn event_handlers(&self) -> ::std::cell::RefMut<::std::vec::Vec<::hobo::EventHandler>> { self.element.event_handlers() }
				}
			}).into()
		},
	}
}

#[proc_macro_derive(Container)]
pub fn derive_container(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
	let input = syn::parse_macro_input!(input as syn::DeriveInput);

	match &input.data {
		syn::Data::Enum(_) => enum_derive! {
			input.to_token_stream(),
			::hobo::Container,
			trait Container {
				fn children(&self) -> &::std::vec::Vec<Box<dyn ::hobo::Element>>;
				fn children_mut(&mut self) -> &mut ::std::vec::Vec<Box<dyn ::hobo::Element>>;
			}
		},
		_ => {
			let name = input.ident;
			let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
			(quote! {
				impl #impl_generics ::hobo::Container for #name #ty_generics #where_clause {
					fn children(&self) -> &::std::vec::Vec<Box<dyn ::hobo::Element>> { self.element.children() }
					fn children_mut(&mut self) -> &mut ::std::vec::Vec<Box<dyn ::hobo::Element>> { self.element.children_mut() }
				}
			}).into()
		},
	}
}

#[proc_macro_derive(Replaceable)]
pub fn derive_replaceable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
	let input = syn::parse_macro_input!(input as syn::DeriveInput);

	match &input.data {
		syn::Data::Enum(_) => enum_derive! {
			input.to_token_stream(),
			::hobo::Replaceable,
			trait Replaceable<T> {
				fn replace_element(&self, element: T);
			}
		},
		_ => {
			let name = input.ident;
			let (_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
			(quote! {
				impl<T: ::hobo::Element + 'static> ::hobo::Replaceable<T> for #name #ty_generics #where_clause {
					fn replace_element(&self, element: T) { self.element.replace_element(element) }
				}
			}).into()
		},
	}
}

#[proc_macro_derive(RawElement)]
pub fn derive_raw_element(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
	let input = syn::parse_macro_input!(input as syn::DeriveInput);
	let name = input.ident;
	let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

	let element_type = match &input.data {
		syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(syn::FieldsNamed { named, .. }), .. }) => {
			let mut res = None;
			for field in named.iter() {
				if let Some(ident) = &field.ident {
					if ident == "element" {
						res = Some(&field.ty);
						break;
					}
				}
			}
			if let Some(x) = res { x } else { panic!("element not found") }
		},
		_ => unimplemented!(),
	};

	(quote! {
		impl #impl_generics ::hobo::RawElement for #name #ty_generics #where_clause {
			type RawElementType = <#element_type as ::hobo::RawElement>::RawElementType;
			fn raw_element(&self) -> &<#element_type as ::hobo::RawElement>::RawElementType { self.element.raw_element() }
		}
	}).into()
}