use pyo3::prelude::*;
#[macro_export]
macro_rules! add_classes {
($module:expr, $($class:ty),+ $(,)?) => {
$(
$module.add_class::<$class>()?;
)+
};
}
#[macro_export]
macro_rules! add_functions {
($module:expr, $($func:ident),+ $(,)?) => {
$(
$module.add_function(wrap_pyfunction!($func, $module)?)?;
)+
};
}
#[macro_export]
macro_rules! submodule {
(@resolve $parent:expr, $path:literal) => {{
let py = $parent.py();
let parts: Vec<&str> = $path.split('.')
.filter(|s| !s.is_empty())
.collect();
let mut current: Bound<'_, PyModule> = $parent.clone();
let sys_modules = py.import("sys")?.getattr("modules")?;
let root_name: String = {
let raw: String = current.name()?.to_string();
let segments: Vec<&str> = raw.split('.').collect();
if segments.len() >= 2 && segments[segments.len()-1] == segments[segments.len()-2] {
segments[..segments.len()-1].join(".")
} else {
raw
}
};
for &part in &parts {
let full_name = format!("{}.{}", root_name, part);
current = if let Ok(existing) = current.getattr(part) {
existing.cast_into::<PyModule>()?
} else {
let new_mod = PyModule::new(py, part)?;
new_mod.setattr("__name__", &full_name)?;
new_mod.setattr("__package__", &root_name)?;
current.add_submodule(&new_mod)?;
sys_modules.set_item(&full_name, &new_mod)?;
new_mod
};}
current
}};
($parent:expr, $path:literal, add_classes!($($class:ty),+ $(,)?)) => {{
let leaf = submodule!(@resolve $parent, $path);
add_classes!(leaf, $($class),+);
}};
($parent:expr, $path:literal, add_functions!($($func:ident),+ $(,)?)) => {{
let leaf = submodule!(@resolve $parent, $path);
add_functions!(leaf, $($func),+);
}};
($parent:expr, $path:literal,
add_classes!($($class:ty),+ $(,)?) && add_functions!($($func:ident),+ $(,)?)) => {{
let leaf = submodule!(@resolve $parent, $path);
add_classes!(leaf, $($class),+);
add_functions!(leaf, $($func),+);
}};
($parent:expr, $path:literal,
add_functions!($($func:ident),+ $(,)?) && add_classes!($($class:ty),+ $(,)?)) => {{
let leaf = submodule!(@resolve $parent, $path);
add_functions!(leaf, $($func),+);
add_classes!(leaf, $($class),+);
}};
}