1use std::collections::HashMap;
7
8pub struct Features;
10
11impl Features {
12 pub const fn has_std() -> bool {
14 cfg!(feature = "std")
15 }
16
17 pub const fn has_no_std() -> bool {
19 cfg!(feature = "no_std")
20 }
21
22 pub const fn has_serde() -> bool {
24 cfg!(feature = "serde")
25 }
26
27 pub const fn has_binary() -> bool {
29 cfg!(feature = "binary")
30 }
31
32 pub const fn has_polars() -> bool {
34 cfg!(feature = "polars")
35 }
36
37 pub const fn has_arrow() -> bool {
39 cfg!(feature = "arrow")
40 }
41
42 pub const fn has_simd() -> bool {
44 cfg!(feature = "simd")
45 }
46
47 pub const fn has_parallel() -> bool {
49 cfg!(feature = "parallel")
50 }
51
52 pub const fn has_mmap() -> bool {
54 cfg!(feature = "mmap")
55 }
56
57 pub const fn has_async() -> bool {
59 cfg!(feature = "async_support")
60 }
61
62 pub const fn has_streaming() -> bool {
64 cfg!(feature = "streaming")
65 }
66
67 pub const fn has_gpu() -> bool {
69 cfg!(feature = "gpu_support")
70 }
71
72 pub const fn has_distributed() -> bool {
74 cfg!(feature = "distributed")
75 }
76
77 pub const fn has_linear_models() -> bool {
79 cfg!(feature = "linear_models")
80 }
81
82 pub const fn has_tree_models() -> bool {
83 cfg!(feature = "tree_models")
84 }
85
86 pub const fn has_neural_networks() -> bool {
87 cfg!(feature = "neural_networks")
88 }
89
90 pub const fn has_clustering() -> bool {
91 cfg!(feature = "clustering")
92 }
93
94 pub const fn has_dimensionality_reduction() -> bool {
95 cfg!(feature = "dimensionality_reduction")
96 }
97
98 pub const fn has_ensemble_methods() -> bool {
99 cfg!(feature = "ensemble_methods")
100 }
101
102 pub const fn has_validation() -> bool {
104 cfg!(feature = "validation")
105 }
106
107 pub const fn has_metrics() -> bool {
108 cfg!(feature = "metrics")
109 }
110
111 pub const fn has_preprocessing() -> bool {
112 cfg!(feature = "preprocessing")
113 }
114
115 pub const fn has_model_selection() -> bool {
116 cfg!(feature = "model_selection")
117 }
118
119 pub const fn has_debug_assertions() -> bool {
121 cfg!(feature = "debug_assertions")
122 }
123
124 pub const fn has_profiling() -> bool {
125 cfg!(feature = "profiling")
126 }
127
128 pub const fn has_benchmarking() -> bool {
129 false
131 }
132
133 pub fn enabled_features() -> HashMap<&'static str, bool> {
135 let mut features = HashMap::new();
136
137 features.insert("std", Self::has_std());
139 features.insert("no_std", Self::has_no_std());
140
141 features.insert("serde", Self::has_serde());
143 features.insert("binary", Self::has_binary());
144
145 features.insert("polars", Self::has_polars());
147 features.insert("arrow", Self::has_arrow());
148
149 features.insert("simd", Self::has_simd());
151 features.insert("parallel", Self::has_parallel());
152 features.insert("mmap", Self::has_mmap());
153
154 features.insert("linear_models", Self::has_linear_models());
156 features.insert("tree_models", Self::has_tree_models());
157 features.insert("neural_networks", Self::has_neural_networks());
158 features.insert("clustering", Self::has_clustering());
159 features.insert(
160 "dimensionality_reduction",
161 Self::has_dimensionality_reduction(),
162 );
163 features.insert("ensemble_methods", Self::has_ensemble_methods());
164
165 features.insert("async_support", Self::has_async());
167 features.insert("streaming", Self::has_streaming());
168 features.insert("gpu_support", Self::has_gpu());
169 features.insert("distributed", Self::has_distributed());
170
171 features.insert("validation", Self::has_validation());
173 features.insert("metrics", Self::has_metrics());
174 features.insert("preprocessing", Self::has_preprocessing());
175 features.insert("model_selection", Self::has_model_selection());
176
177 features.insert("debug_assertions", Self::has_debug_assertions());
179 features.insert("profiling", Self::has_profiling());
180 features.insert("benchmarking", Self::has_benchmarking());
181
182 features
183 }
184
185 pub fn print_enabled_features() {
187 println!("Enabled features:");
188 for (feature, enabled) in Self::enabled_features() {
189 if enabled {
190 println!(" - {feature}");
191 }
192 }
193 }
194
195 pub fn feature_summary() -> FeatureSummary {
197 FeatureSummary {
198 core: CoreFeatures {
199 std: Self::has_std(),
200 no_std: Self::has_no_std(),
201 },
202 serialization: SerializationFeatures {
203 serde: Self::has_serde(),
204 binary: Self::has_binary(),
205 },
206 data_formats: DataFormatFeatures {
207 polars: Self::has_polars(),
208 arrow: Self::has_arrow(),
209 },
210 performance: PerformanceFeatures {
211 simd: Self::has_simd(),
212 parallel: Self::has_parallel(),
213 mmap: Self::has_mmap(),
214 },
215 algorithms: AlgorithmFeatures {
216 linear_models: Self::has_linear_models(),
217 tree_models: Self::has_tree_models(),
218 neural_networks: Self::has_neural_networks(),
219 clustering: Self::has_clustering(),
220 dimensionality_reduction: Self::has_dimensionality_reduction(),
221 ensemble_methods: Self::has_ensemble_methods(),
222 },
223 advanced: AdvancedFeatures {
224 async_support: Self::has_async(),
225 streaming: Self::has_streaming(),
226 gpu_support: Self::has_gpu(),
227 distributed: Self::has_distributed(),
228 },
229 utilities: UtilityFeatures {
230 validation: Self::has_validation(),
231 metrics: Self::has_metrics(),
232 preprocessing: Self::has_preprocessing(),
233 model_selection: Self::has_model_selection(),
234 },
235 development: DevelopmentFeatures {
236 debug_assertions: Self::has_debug_assertions(),
237 profiling: Self::has_profiling(),
238 benchmarking: Self::has_benchmarking(),
239 },
240 }
241 }
242}
243
244#[derive(Debug, Clone)]
246pub struct FeatureSummary {
247 pub core: CoreFeatures,
248 pub serialization: SerializationFeatures,
249 pub data_formats: DataFormatFeatures,
250 pub performance: PerformanceFeatures,
251 pub algorithms: AlgorithmFeatures,
252 pub advanced: AdvancedFeatures,
253 pub utilities: UtilityFeatures,
254 pub development: DevelopmentFeatures,
255}
256
257#[derive(Debug, Clone)]
259pub struct CoreFeatures {
260 pub std: bool,
261 pub no_std: bool,
262}
263
264#[derive(Debug, Clone)]
266pub struct SerializationFeatures {
267 pub serde: bool,
268 pub binary: bool,
269}
270
271#[derive(Debug, Clone)]
273pub struct DataFormatFeatures {
274 pub polars: bool,
275 pub arrow: bool,
276}
277
278#[derive(Debug, Clone)]
280pub struct PerformanceFeatures {
281 pub simd: bool,
282 pub parallel: bool,
283 pub mmap: bool,
284}
285
286#[derive(Debug, Clone)]
288pub struct AlgorithmFeatures {
289 pub linear_models: bool,
290 pub tree_models: bool,
291 pub neural_networks: bool,
292 pub clustering: bool,
293 pub dimensionality_reduction: bool,
294 pub ensemble_methods: bool,
295}
296
297impl AlgorithmFeatures {
298 pub fn any_enabled(&self) -> bool {
300 self.linear_models
301 || self.tree_models
302 || self.neural_networks
303 || self.clustering
304 || self.dimensionality_reduction
305 || self.ensemble_methods
306 }
307
308 pub fn count_enabled(&self) -> usize {
310 [
311 self.linear_models,
312 self.tree_models,
313 self.neural_networks,
314 self.clustering,
315 self.dimensionality_reduction,
316 self.ensemble_methods,
317 ]
318 .iter()
319 .filter(|&&enabled| enabled)
320 .count()
321 }
322
323 pub fn enabled_categories(&self) -> Vec<&'static str> {
325 let mut categories = Vec::new();
326 if self.linear_models {
327 categories.push("linear_models");
328 }
329 if self.tree_models {
330 categories.push("tree_models");
331 }
332 if self.neural_networks {
333 categories.push("neural_networks");
334 }
335 if self.clustering {
336 categories.push("clustering");
337 }
338 if self.dimensionality_reduction {
339 categories.push("dimensionality_reduction");
340 }
341 if self.ensemble_methods {
342 categories.push("ensemble_methods");
343 }
344 categories
345 }
346}
347
348#[derive(Debug, Clone)]
350pub struct AdvancedFeatures {
351 pub async_support: bool,
352 pub streaming: bool,
353 pub gpu_support: bool,
354 pub distributed: bool,
355}
356
357#[derive(Debug, Clone)]
359pub struct UtilityFeatures {
360 pub validation: bool,
361 pub metrics: bool,
362 pub preprocessing: bool,
363 pub model_selection: bool,
364}
365
366#[derive(Debug, Clone)]
368pub struct DevelopmentFeatures {
369 pub debug_assertions: bool,
370 pub profiling: bool,
371 pub benchmarking: bool,
372}
373
374pub mod validation {
376 use super::Features;
377
378 pub const fn validate_features() -> Result<(), &'static str> {
380 if Features::has_std() && Features::has_no_std() {
384 }
387
388 if Features::has_binary() && !Features::has_serde() {
391 return Err("'binary' feature requires 'serde' feature");
392 }
393
394 if Features::has_streaming() && !Features::has_async() {
397 return Err("'streaming' feature requires 'async_support' feature");
398 }
399
400 if Features::has_distributed() && !Features::has_async() {
401 return Err("'distributed' feature requires 'async_support' feature");
402 }
403
404 if !Features::has_std() && !Features::has_no_std() {
406 }
409
410 Ok(())
411 }
412
413 pub const fn assert_valid_features() {
415 match validate_features() {
416 Ok(()) => {}
417 Err(_) => panic!("Invalid feature combination detected"),
418 }
419 }
420}
421
422pub struct FeatureConfig {
424 enabled_features: HashMap<String, bool>,
425}
426
427impl FeatureConfig {
428 pub fn from_compile_time() -> Self {
430 let enabled = Features::enabled_features()
431 .into_iter()
432 .map(|(k, v)| (k.to_string(), v))
433 .collect();
434
435 Self {
436 enabled_features: enabled,
437 }
438 }
439
440 pub fn is_enabled(&self, feature: &str) -> bool {
442 self.enabled_features.get(feature).copied().unwrap_or(false)
443 }
444
445 pub fn enabled_features(&self) -> Vec<&str> {
447 self.enabled_features
448 .iter()
449 .filter_map(|(k, &v)| if v { Some(k.as_str()) } else { None })
450 .collect()
451 }
452
453 #[cfg(feature = "serde")]
455 pub fn to_json(&self) -> Result<String, serde_json::Error> {
456 serde_json::to_string_pretty(&self.enabled_features)
457 }
458
459 #[cfg(feature = "serde")]
461 pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
462 let enabled_features = serde_json::from_str(json)?;
463 Ok(Self { enabled_features })
464 }
465}
466
467#[macro_export]
469macro_rules! cfg_feature {
470 ($feature:literal, $code:block) => {
471 #[cfg(feature = $feature)]
472 $code
473 };
474 ($feature:literal, $code:block, else $else_code:block) => {
475 #[cfg(feature = $feature)]
476 $code
477 #[cfg(not(feature = $feature))]
478 $else_code
479 };
480}
481
482#[macro_export]
484macro_rules! cfg_type {
485 ($feature:literal, $type_def:item) => {
486 #[cfg(feature = $feature)]
487 $type_def
488 };
489}
490
491#[macro_export]
493macro_rules! cfg_impl {
494 ($feature:literal, impl $trait_name:ident for $type:ty { $($item:item)* }) => {
495 #[cfg(feature = $feature)]
496 impl $trait_name for $type {
497 $($item)*
498 }
499 };
500}
501
502#[allow(non_snake_case)]
503#[cfg(test)]
504mod tests {
505 use super::*;
506
507 #[test]
508 fn test_feature_detection() {
509 let summary = Features::feature_summary();
511
512 assert!(summary.core.std || summary.core.no_std);
514
515 Features::print_enabled_features();
517 }
518
519 #[test]
520 fn test_feature_config() {
521 let config = FeatureConfig::from_compile_time();
522
523 assert!(!config.enabled_features().is_empty());
525
526 let has_std = config.is_enabled("std");
528 assert_eq!(has_std, Features::has_std());
529 }
530
531 #[test]
532 fn test_algorithm_features() {
533 let algo_features = Features::feature_summary().algorithms;
534
535 let count = algo_features.count_enabled();
537 let categories = algo_features.enabled_categories();
538
539 assert_eq!(count, categories.len());
540 }
541
542 #[test]
543 fn test_feature_validation() {
544 validation::assert_valid_features();
546
547 assert!(validation::validate_features().is_ok());
549 }
550
551 #[cfg(feature = "serde")]
552 #[test]
553 fn test_feature_serialization() {
554 let config = FeatureConfig::from_compile_time();
555
556 let json = config.to_json().unwrap();
558 assert!(!json.is_empty());
559
560 let config2 = FeatureConfig::from_json(&json).unwrap();
562 assert_eq!(
563 config.enabled_features().len(),
564 config2.enabled_features().len()
565 );
566 }
567
568 #[test]
569 fn test_feature_macros() {
570 cfg_feature!("std", {
572 println!("std feature is enabled");
573 });
574
575 cfg_feature!("gpu_support", {
577 println!("gpu_support feature is enabled");
578 }, else {
579 println!("gpu_support is not enabled (expected in most builds)");
580 });
581 }
582}