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}