1use pyo3::prelude::*;
3
4#[macro_export]
6macro_rules! add_classes {
7 ($module:expr, $($class:ty),+ $(,)?) => {
8 $(
9 $module.add_class::<$class>()?;
10 )+
11 };
12}
13
14#[macro_export]
16macro_rules! add_functions {
17 ($module:expr, $($func:ident),+ $(,)?) => {
18 $(
19 $module.add_function(wrap_pyfunction!($func, $module)?)?;
20 )+
21 };
22}
23
24#[macro_export]
39macro_rules! submodule {
40 (@resolve $parent:expr, $path:literal) => {{
41 let py = $parent.py();
42 let parts: Vec<&str> = $path.split('.')
43 .filter(|s| !s.is_empty())
44 .collect();
45 let mut current: Bound<'_, PyModule> = $parent.clone();
46 let sys_modules = py.import("sys")?.getattr("modules")?;
47
48 let root_name: String = {
49 let raw: String = current.name()?.to_string();
50 let segments: Vec<&str> = raw.split('.').collect();
51 if segments.len() >= 2 && segments[segments.len()-1] == segments[segments.len()-2] {
52 segments[..segments.len()-1].join(".")
53 } else {
54 raw
55 }
56 };
57
58 for &part in &parts {
59 let full_name = format!("{}.{}", root_name, part);
60 current = if let Ok(existing) = current.getattr(part) {
61 existing.cast_into::<PyModule>()?
62 } else {
63 let new_mod = PyModule::new(py, part)?;
64 new_mod.setattr("__name__", &full_name)?;
65 new_mod.setattr("__package__", &root_name)?;
66 current.add_submodule(&new_mod)?;
67 sys_modules.set_item(&full_name, &new_mod)?;
68 new_mod
69 };}
70 current
71 }};
72
73 ($parent:expr, $path:literal, add_classes!($($class:ty),+ $(,)?)) => {{
75 let leaf = submodule!(@resolve $parent, $path);
76 add_classes!(leaf, $($class),+);
77 }};
78
79 ($parent:expr, $path:literal, add_functions!($($func:ident),+ $(,)?)) => {{
81 let leaf = submodule!(@resolve $parent, $path);
82 add_functions!(leaf, $($func),+);
83 }};
84
85 ($parent:expr, $path:literal,
87 add_classes!($($class:ty),+ $(,)?) && add_functions!($($func:ident),+ $(,)?)) => {{
88 let leaf = submodule!(@resolve $parent, $path);
89 add_classes!(leaf, $($class),+);
90 add_functions!(leaf, $($func),+);
91 }};
92
93 ($parent:expr, $path:literal,
95 add_functions!($($func:ident),+ $(,)?) && add_classes!($($class:ty),+ $(,)?)) => {{
96 let leaf = submodule!(@resolve $parent, $path);
97 add_functions!(leaf, $($func),+);
98 add_classes!(leaf, $($class),+);
99 }};
100}