oxidd_derive/
lib.rs

1//! Various derive macros for oxidd
2//!
3//! Note that the code generated by the macros depends on definitions in
4//! `oxidd_core`, not their re-exports in `oxidd`. So in case you want to use
5//! these macros as an "external" user, you may need to add `oxidd_core` to your
6//! `Cargo.toml`.
7#![warn(missing_docs)]
8
9mod countable;
10mod function;
11mod manager_event_subscriber;
12pub(crate) mod util;
13
14// The actual proc macros must reside at the root of the crate:
15
16/// Derive the `Countable` trait from `oxidd_core`
17///
18/// The `Countable` trait can be derived for:
19/// - Fieldless `enum`s with primitive representation (currently `repr(u8)`
20///   only). Explicit discriminants are not yet supported.
21/// - `struct`s with zero fields.
22#[proc_macro_error::proc_macro_error]
23#[proc_macro_derive(Countable)]
24pub fn derive_countable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
25    let input = syn::parse_macro_input!(input as syn::DeriveInput);
26    let expanded = countable::derive_countable(input);
27    proc_macro::TokenStream::from(expanded)
28}
29
30/// Derive the `ManagerEventSubscriber` trait from `oxidd_core::util`
31///
32/// # Example
33///
34/// ```
35/// # use std::marker::PhantomData;
36/// # use oxidd_core::{Manager, ManagerEventSubscriber};
37/// # use oxidd_derive::ManagerEventSubscriber;
38/// # struct ApplyCache<M>(PhantomData<M>);
39/// # impl<M: Manager> ManagerEventSubscriber<M> for ApplyCache<M> {}
40/// # struct ZBDDCache<M>(PhantomData<M>);
41/// # impl<M: Manager> ManagerEventSubscriber<M> for ZBDDCache<M> {}
42/// #[derive(ManagerEventSubscriber)]
43/// #[subscribe(manager = M)]
44/// struct ManagerData<M> {
45///     apply_cache: ApplyCache<M>,
46///     zbdd_cache: ZBDDCache<M>,
47///     #[subscribe(skip)]
48///     field_to_skip: bool,
49/// }
50/// ```
51///
52/// Specifying the manager type via `#[subscribe(manager = M)]` is mandatory (it
53/// does not need to be a generic parameter, though). The generated
54/// implementation will look like this:
55///
56/// ```
57/// # use std::marker::PhantomData;
58/// # use oxidd_core::{Manager, ManagerEventSubscriber};
59/// # struct ApplyCache<M>(PhantomData<M>);
60/// # impl<M: Manager> ManagerEventSubscriber<M> for ApplyCache<M> {}
61/// # struct ZBDDCache<M>(PhantomData<M>);
62/// # impl<M: Manager> ManagerEventSubscriber<M> for ZBDDCache<M> {}
63/// # struct ManagerData<M> {
64/// #     apply_cache: ApplyCache<M>,
65/// #     zbdd_cache: ZBDDCache<M>,
66/// #     field_to_skip: bool,
67/// # }
68/// impl<M> ManagerEventSubscriber<M> for ManagerData<M>
69/// where
70///     M: Manager,
71///     ApplyCache<M>: ManagerEventSubscriber<M>,
72///     ZBDDCache<M>: ManagerEventSubscriber<M>,
73/// {
74///     fn pre_gc(&self, manager: &M) {
75///         self.apply_cache.pre_gc(manager);
76///         self.zbdd_cache.pre_gc(manager);
77///     }
78///     unsafe fn post_gc(&self, manager: &M) {
79///         // SAFETY: since the caller ensures to call this method (only!) once
80///         // after a GC, we call `post_gc` (only) once  for each substructure.
81///         unsafe {
82///             self.apply_cache.post_gc(manager);
83///             self.zbdd_cache.post_gc(manager);
84///         }
85///     }
86///     // similar implementations for `pre_reorder` and `post_reorder` ...
87///     fn pre_reorder_mut(manager: &mut M) {
88///         ApplyCache::<M>::pre_reorder_mut(manager);
89///         ZBDDCache::<M>::pre_reorder_mut(manager);
90///     }
91///     // similar implementation for `post_reorder_mut` ...
92/// }
93/// ```
94///
95/// Note that if you have two fields of the same type (and you do not use
96/// `#[subscribe(skip)]` on either of these fields), the `pre_reorder_mut` and
97/// `post_reorder_mut` implementation will call the method for that type twice
98/// (with the same `manager` argument).
99///
100/// In some cases the trait bounds `M: Manager`,
101/// `ApplyCache<M>: ManagerEventSubscriber<M>`, etc. can lead to undesired
102/// self-references and cause the [compiler error
103/// E0275](https://doc.rust-lang.org/stable/error_codes/E0275.html). To disable
104/// the generation of those trait bounds, specify `no_trait_bounds` via a
105/// struct-level `subscribe` attribute. (This will not affect trait bounds from
106/// the struct declaration itself.)
107#[proc_macro_error::proc_macro_error]
108#[proc_macro_derive(ManagerEventSubscriber, attributes(subscribe))]
109pub fn derive_manager_event_subscriber(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
110    let input = syn::parse_macro_input!(input as syn::DeriveInput);
111    let expanded = manager_event_subscriber::derive_manager_event_subscriber(input);
112    proc_macro::TokenStream::from(expanded)
113}
114
115/// Derive the `Function` trait from `oxidd_core::function`
116///
117/// This trait can be derived for `struct`s that wrap another `Function`
118/// implementation. Currently, this macro is restricted to `struct`s with a
119/// single field.
120///
121/// You may specify the associated `ManagerRef` type using an attribute
122/// `#[use_manager_ref(YourManagerRefType)]`.
123///
124/// To influence the representation identifier, use the attribute
125/// `#[repr_id = "MY_BDD"]`.
126#[proc_macro_error::proc_macro_error]
127#[proc_macro_derive(Function, attributes(use_manager_ref, repr_id))]
128pub fn derive_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
129    let input = syn::parse_macro_input!(input as syn::DeriveInput);
130    let expanded = function::derive_function(input);
131    proc_macro::TokenStream::from(expanded)
132}
133
134/// Derive the `FunctionSubst` trait from `oxidd_core::function`
135///
136/// This trait can be derived for `struct`s that wrap another `FunctionSubst`
137/// implementation. The same restrictions apply as for deriving [`Function`].
138#[proc_macro_error::proc_macro_error]
139#[proc_macro_derive(FunctionSubst)]
140pub fn derive_function_subst(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
141    let input = syn::parse_macro_input!(input as syn::DeriveInput);
142    let expanded = function::derive_function_subst(input);
143    proc_macro::TokenStream::from(expanded)
144}
145
146/// Derive the `BooleanFunction` trait from `oxidd_core::function`
147///
148/// This trait can be derived for `struct`s that wrap another `BooleanFunction`
149/// implementation. The same restrictions apply as for deriving [`Function`].
150#[proc_macro_error::proc_macro_error]
151#[proc_macro_derive(BooleanFunction)]
152pub fn derive_boolean_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
153    let input = syn::parse_macro_input!(input as syn::DeriveInput);
154    let expanded = function::derive_boolean_function(input);
155    proc_macro::TokenStream::from(expanded)
156}
157
158/// Derive the `BooleanFunctionQuant` trait from `oxidd_core::function`
159///
160/// This trait can be derived for `struct`s that wrap another
161/// `BooleanFunctionQuant` implementation. The same restrictions apply as for
162/// deriving [`Function`].
163#[proc_macro_error::proc_macro_error]
164#[proc_macro_derive(BooleanFunctionQuant)]
165pub fn derive_boolean_function_quant(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
166    let input = syn::parse_macro_input!(input as syn::DeriveInput);
167    let expanded = function::derive_boolean_function_quant(input);
168    proc_macro::TokenStream::from(expanded)
169}
170
171/// Derive the `BooleanVecSet` trait from `oxidd_core::function`
172///
173/// This trait can be derived for `struct`s that wrap another `BooleanVecSet`
174/// implementation. The same restrictions apply as for deriving [`Function`].
175#[proc_macro_error::proc_macro_error]
176#[proc_macro_derive(BooleanVecSet)]
177pub fn derive_boolean_vec_set(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
178    let input = syn::parse_macro_input!(input as syn::DeriveInput);
179    let expanded = function::derive_boolean_vec_set(input);
180    proc_macro::TokenStream::from(expanded)
181}
182
183/// Derive the `PseudoBooleanFunction` trait from `oxidd_core::function`
184///
185/// This trait can be derived for `struct`s that wrap another
186/// `PseudoBooleanFunction` implementation. The same restrictions apply as for
187/// deriving [`Function`].
188#[proc_macro_error::proc_macro_error]
189#[proc_macro_derive(PseudoBooleanFunction)]
190pub fn derive_pseudo_boolean_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
191    let input = syn::parse_macro_input!(input as syn::DeriveInput);
192    let expanded = function::derive_pseudo_boolean_function(input);
193    proc_macro::TokenStream::from(expanded)
194}
195
196/// Derive the `TVLFunction` trait from `oxidd_core::function`
197///
198/// This trait can be derived for `struct`s that wrap another `TVLFunction`
199/// implementation. The same restrictions apply as for deriving [`Function`].
200#[proc_macro_error::proc_macro_error]
201#[proc_macro_derive(TVLFunction)]
202pub fn derive_tvl_function(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
203    let input = syn::parse_macro_input!(input as syn::DeriveInput);
204    let expanded = function::derive_tvl_function(input);
205    proc_macro::TokenStream::from(expanded)
206}