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