Skip to main content

xet_runtime/config/
macros.rs

1/// Single source of truth for all platform-independent config groups.
2/// Invokes the given callback macro with the list of group names.
3///
4/// The `system_monitor` group is excluded because it is `#[cfg(not(target_family = "wasm"))]`;
5/// each consumer appends it separately with the appropriate cfg gate.
6#[macro_export]
7macro_rules! all_config_groups {
8    ($mac:ident) => {
9        $mac!(data, shard, deduplication, chunk_cache, client, log, reconstruction, xorb, session);
10    };
11}
12
13/// Macro to create a configuration value group struct.
14///
15/// Usage:
16/// ```rust,no_run
17/// use xet_runtime::config_group;
18///
19/// mod basic_group {
20///     use xet_runtime::config_group;
21///
22///     config_group!({
23///         ref TEST_INT: usize = 42;
24///         ref TEST_STRING: String = "default".to_string();
25///     });
26/// }
27/// ```
28///
29/// This creates a `ConfigValueGroup` struct with the specified fields, default values,
30/// environment variable overrides, and string-based accessors.
31///
32/// Python bindings are provided at the `XetConfig` level, not per-group.
33#[macro_export]
34macro_rules! config_group {
35    ({
36        $(
37            $(#[$meta:meta])*
38            ref $name:ident : $type:ty = $value:expr;
39        )+
40    }) => {
41        #[allow(unused_imports)]
42        use $crate::config::ParsableConfigValue;
43
44        /// Name of this configuration struct, accessible for macro generation
45        pub const CONFIG_VALUES_NAME: &str = "ConfigValueGroup";
46
47        /// ConfigValueGroup struct containing all configurable values
48        #[derive(Debug, Clone)]
49        pub struct ConfigValueGroup {
50            $(
51                $(#[$meta])*
52                #[allow(non_snake_case)]
53                pub $name: $type,
54            )+
55        }
56
57        impl Default for ConfigValueGroup {
58            fn default() -> Self {
59                Self {
60                    $(
61                        $name: {
62                            let v: $type = $value;
63                            v
64                        },
65                    )+
66                }
67            }
68        }
69
70        impl AsRef<ConfigValueGroup> for ConfigValueGroup {
71            fn as_ref(&self) -> &ConfigValueGroup {
72                self
73            }
74        }
75
76        impl ConfigValueGroup {
77            /// Create a new instance with default values only (no environment variable overrides).
78            pub fn new() -> Self {
79                Self::default()
80            }
81
82            /// Apply environment variable overrides to this configuration group.
83            ///
84            /// The group name is derived from the module path. For example, in module `xet_config::groups::data`,
85            /// the env var for TEST_INT would be HF_XET_DATA_TEST_INT.
86            pub fn apply_env_overrides(&mut self) {
87                $(
88                    {
89                    const ENV_VAR_NAME: &str = const_str::concat!(
90                        "HF_XET_",
91                        const_str::convert_ascii_case!(upper, konst::string::rsplit_once(module_path!(), "::").unwrap().1),
92                        "_",
93                        const_str::convert_ascii_case!(upper, stringify!($name)));
94
95                    let mut maybe_env_value = std::env::var(ENV_VAR_NAME).ok();
96
97                    if maybe_env_value.is_none() {
98                            for &(primary_name, alias_name) in $crate::config::ENVIRONMENT_NAME_ALIASES {
99                                if primary_name == ENV_VAR_NAME {
100                                    let alt_env_value = std::env::var(alias_name).ok();
101                                    if alt_env_value.is_some() {
102                                        maybe_env_value = alt_env_value;
103                                        break;
104                                    }
105                                }
106                            }
107                    }
108
109                    let default_value: $type = $value;
110                    self.$name = <$type>::parse_config_value(stringify!($name), maybe_env_value, default_value);
111                }
112                )+
113            }
114
115            /// Returns the list of field names in this configuration group.
116            pub fn field_names() -> &'static [&'static str] {
117                &[$(stringify!($name)),+]
118            }
119
120            // Internal: used by XetConfig::with_config to apply field updates by name.
121            pub(crate) fn update_field(&mut self, name: &str, value: impl ToString) -> Result<(), $crate::config::ConfigError> {
122                let value_string = value.to_string();
123                match name {
124                    $(
125                        stringify!($name) => {
126                            if !self.$name.try_update_in_place(&value_string) {
127                                return Err($crate::config::ConfigError::ParseError {
128                                    field: name.to_owned(),
129                                    value: value_string,
130                                });
131                            }
132                            Ok(())
133                        }
134                    )+
135                    _ => Err($crate::config::ConfigError::UnknownField(name.to_owned())),
136                }
137            }
138
139            /// Get a configuration field's string representation by name.
140            pub fn get(&self, name: &str) -> Result<String, $crate::config::ConfigError> {
141                match name {
142                    $(
143                        stringify!($name) => Ok(self.$name.to_config_string()),
144                    )+
145                    _ => Err($crate::config::ConfigError::UnknownField(name.to_owned())),
146                }
147            }
148
149            // Internal: used by PyXetConfig::with_config to apply field updates from Python values.
150            #[cfg(feature = "python")]
151            pub(crate) fn update_field_from_python(
152                &mut self,
153                name: &str,
154                value: &pyo3::Bound<'_, pyo3::PyAny>,
155            ) -> pyo3::PyResult<()> {
156                match name {
157                    $(
158                        stringify!($name) => {
159                            <$type as $crate::config::python::PythonConfigValue>::update_from_python(&mut self.$name, value)?;
160                            Ok(())
161                        }
162                    )+
163                    _ => Err(pyo3::exceptions::PyValueError::new_err(format!("Unknown config field: '{name}'"))),
164                }
165            }
166
167            // Internal: used by PyXetConfig to return field values as native Python objects.
168            #[cfg(feature = "python")]
169            pub(crate) fn get_to_python(
170                &self,
171                name: &str,
172                py: pyo3::Python<'_>,
173            ) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
174                match name {
175                    $(
176                        stringify!($name) => {
177                            <$type as $crate::config::python::PythonConfigValue>::to_python(&self.$name, py)
178                        }
179                    )+
180                    _ => Err(pyo3::exceptions::PyValueError::new_err(format!("Unknown config field: '{name}'"))),
181                }
182            }
183
184            // Internal: used by PyXetConfig iteration to yield all (field, value) pairs.
185            #[cfg(feature = "python")]
186            pub(crate) fn items_to_python(
187                &self,
188                py: pyo3::Python<'_>,
189            ) -> pyo3::PyResult<Vec<(&'static str, pyo3::Py<pyo3::PyAny>)>> {
190                Ok(vec![
191                    $(
192                        (stringify!($name),
193                         <$type as $crate::config::python::PythonConfigValue>::to_python(&self.$name, py)?),
194                    )+
195                ])
196            }
197        }
198
199        /// Type alias for easier reference in config aggregation macros
200        pub(crate) type ConfigValues = ConfigValueGroup;
201    };
202}