//! Various derive macros for oxidd
//!
//! Note that the code generated by the macros depends on definitions in
//! `oxidd_core`, not their re-exports in `oxidd`. So in case you want to use
//! these macros as an "external" user, you may need to add `oxidd_core` to your
//! `Cargo.toml`.

mod countable;
mod function;
pub(crate) mod util;

// The actual proc macros must reside at the root of the crate:

/// Derive the `Countable` trait from `oxidd_core`
///
/// The `Countable` trait can be derived for:
/// - Fieldless `enum`s with primitive representation (currently `repr(u8)`
///   only). Explicit discriminants are not yet supported.
/// - `struct`s with zero fields.
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(Countable)]
pub fn derive_countable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = countable::derive_countable(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `Function` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another `Function`
/// implementation. Currently, this macro is restricted to `struct`s with a
/// single field.
///
/// You may specify the associated `ManagerRef` type using an attribute
/// `#[use_manager_ref(YourManagerRefType)]`.
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(Function, attributes(use_manager_ref))]
pub fn derive_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_function(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `FunctionSubst` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another `FunctionSubst`
/// implementation. The same restrictions apply as for deriving [`Function`].
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(FunctionSubst)]
pub fn derive_function_subst(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_function_subst(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `BooleanFunction` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another `BooleanFunction`
/// implementation. The same restrictions apply as for deriving [`Function`].
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(BooleanFunction)]
pub fn derive_boolean_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_boolean_function(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `BooleanFunctionQuant` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another
/// `BooleanFunctionQuant` implementation. The same restrictions apply as for
/// deriving [`Function`].
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(BooleanFunctionQuant)]
pub fn derive_boolean_function_quant(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_boolean_function_quant(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `BooleanVecSet` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another `BooleanVecSet`
/// implementation. The same restrictions apply as for deriving [`Function`].
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(BooleanVecSet)]
pub fn derive_boolean_vec_set(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_boolean_vec_set(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `PseudoBooleanFunction` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another
/// `PseudoBooleanFunction` implementation. The same restrictions apply as for
/// deriving [`Function`].
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(PseudoBooleanFunction)]
pub fn derive_pseudo_boolean_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_pseudo_boolean_function(input);
    proc_macro::TokenStream::from(expanded)
}

/// Derive the `TVLFunction` trait from `oxidd_core::function`
///
/// This trait can be derived for `struct`s that wrap another `TVLFunction`
/// implementation. The same restrictions apply as for deriving [`Function`].
#[proc_macro_error::proc_macro_error]
#[proc_macro_derive(TVLFunction)]
pub fn derive_tvl_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    let expanded = function::derive_tvl_function(input);
    proc_macro::TokenStream::from(expanded)
}
