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}