mod model;
mod property;
mod selection;
#[cfg(feature = "wasm")]
mod tsify;
#[cfg(feature = "wasm")]
mod wasm_signal;
mod wrapper_macros;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Model, attributes(active_type, ephemeral, model))]
pub fn derive_model(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let desc = match model::description::ModelDescription::parse(&input) {
Ok(model) => model,
Err(e) => return e.to_compile_error().into(),
};
let hygiene_module = quote::format_ident!("__ankurah_derive_impl_{}", to_snake_case(&desc.name().to_string()));
let wasm_imports = if cfg!(feature = "wasm") {
quote! {
use ::ankurah::derive_deps::wasm_bindgen::prelude::*;
use ::ankurah::derive_deps::wasm_bindgen_futures;
}
} else {
quote! {}
};
let model_impl = model::model::model_impl(&desc);
let view_impl = model::view::view_impl(&desc);
let mutable_impl = model::mutable::mutable_impl(&desc);
#[cfg(feature = "wasm")]
let wasm_impl = model::wasm::wasm_impl(&input, &desc);
#[cfg(not(feature = "wasm"))]
let wasm_impl = quote! {};
#[cfg(all(feature = "uniffi", not(feature = "wasm")))]
let uniffi_impl = model::uniffi::uniffi_impl(&desc);
#[cfg(any(not(feature = "uniffi"), feature = "wasm"))]
let uniffi_impl = quote! {};
let expanded = quote! {
mod #hygiene_module {
use super::*;
#wasm_imports
#model_impl
#view_impl
#mutable_impl
#wasm_impl
#uniffi_impl
}
pub use #hygiene_module::*;
};
expanded.into()
}
fn to_snake_case(ident: &str) -> String {
ident
.chars()
.enumerate()
.flat_map(|(i, c)| {
if c.is_uppercase() && i > 0 {
vec!['_', c.to_lowercase().next().unwrap()]
} else {
vec![c.to_lowercase().next().unwrap()]
}
})
.collect()
}
#[cfg(feature = "wasm")]
#[proc_macro_derive(WasmSignal)]
pub fn derive_wasm_signal(input: TokenStream) -> TokenStream { wasm_signal::derive_wasm_signal_impl(input) }
#[proc_macro_derive(Property)]
pub fn derive_property(input: TokenStream) -> TokenStream { property::derive_property_impl(input) }
#[proc_macro]
pub fn selection(input: TokenStream) -> TokenStream { selection::selection_macro(input) }
#[proc_macro]
pub fn fetch(input: TokenStream) -> TokenStream { selection::fetch_macro(input) }
#[proc_macro]
pub fn livequery(input: TokenStream) -> TokenStream { selection::subscribe_macro(input) }
#[proc_macro]
pub fn impl_provided_wrapper_types(input: TokenStream) -> TokenStream {
let config_filename = parse_macro_input!(input as syn::LitStr);
let wasm_result = wrapper_macros::impl_provided_wrapper_types_impl(&config_filename.value());
let uniffi_result = wrapper_macros::impl_provided_wrapper_types_uniffi_impl(&config_filename.value());
match (wasm_result, uniffi_result) {
(Ok(wasm_tokens), Ok(uniffi_tokens)) => {
let combined = quote::quote! {
#wasm_tokens
#uniffi_tokens
};
combined.into()
}
(Err(err), _) | (_, Err(err)) => err.to_compile_error().into(),
}
}
#[proc_macro]
pub fn impl_wrapper_type(input: TokenStream) -> TokenStream {
let custom_type = parse_macro_input!(input as syn::Type);
let wasm_result = wrapper_macros::impl_wrapper_type_impl(&custom_type);
let uniffi_result = wrapper_macros::impl_wrapper_type_uniffi_impl(&custom_type);
match (wasm_result, uniffi_result) {
(Ok(wasm_tokens), Ok(uniffi_tokens)) => {
let combined = quote::quote! {
#wasm_tokens
#uniffi_tokens
};
combined.into()
}
(Err(err), _) | (_, Err(err)) => err.to_compile_error().into(),
}
}