devela/build/
features.rs

1// devela build::features
2//
3//! Features debugging and compile flags enabling for reflexion.
4//
5
6#[cfg(feature = "__dbg")]
7use crate::utils::println;
8use std::{collections::HashSet, env, sync::OnceLock};
9
10/// The set of enabled features.
11pub(crate) static ENABLED_FEATURES: OnceLock<HashSet<String>> = OnceLock::new();
12
13pub(crate) fn main() -> Result<(), std::io::Error> {
14    #[cfg(feature = "__dbg")]
15    super::utils::println_heading("Features & Flags:");
16
17    ENABLED_FEATURES.get_or_init(|| {
18        env::vars()
19            .filter_map(|(key, _)| key.strip_prefix("CARGO_FEATURE_").map(|f| f.to_lowercase()))
20            .collect::<HashSet<_>>()
21    });
22
23    #[cfg(feature = "__dbg")]
24    if let Some(f) = ENABLED_FEATURES.get() {
25        println(&format!("Enabled features ({}): {:?}", f.len(), f));
26        println("");
27    };
28
29    let _enabled_flags = reflection::set_flags();
30
31    #[cfg(feature = "__dbg")]
32    {
33        println(&format!("Enabled flags ({}): {:?}", _enabled_flags.len(), _enabled_flags));
34    }
35
36    Ok(())
37}
38
39/// Sets configuration options for reflection, based on enabled features.
40//
41// https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options
42#[rustfmt::skip]
43mod reflection {
44    use super::ENABLED_FEATURES;
45
46    /// A type that associates a list of flags with a list of features.
47    pub struct FlagsFeatures<'a> {
48        /// The list of flags to be enabled if any of the features are enabled.
49        flags: &'a [&'a str],
50        /// The list of features that enables the associated flags.
51        features: &'a [&'a str],
52    }
53
54    /* # miscellaneous */
55
56    pub const DEVELOPMENT: FlagsFeatures = FlagsFeatures {
57        flags: &[],
58        features: &[
59            "__dbg",
60            "__no_test",
61            "__force_miri_dst",
62            // "default",
63            // "_default",
64            "_docsrs", "_docsrs_min",
65            "_docsrs_stable", "_docsrs_stable_min",
66            "_docs_max", "_docs_min",
67        ]
68    };
69
70    pub const ENVIRONMENT: FlagsFeatures = FlagsFeatures {
71        flags: &[],
72        features: &["std", "alloc", "no_std"]
73    };
74
75    // In sync with ./Cargo.toml::[un][safe][st] & ./src/lib.rs::safety
76    pub const SAFE: FlagsFeatures = FlagsFeatures {
77        flags: &["safe··"],
78        features: &[
79            "safe",
80            "safe_code",
81            "safe_data",
82            "safe_lang",
83            "safe_media",
84                "safe_audio", "safe_color", "safe_draw", "safe_font", "safe_image",
85            "safe_num",
86            "safe_phys",
87                "safe_time",
88            "safe_sys",
89                "safe_io", "safe_mem",
90            "safe_text",
91            "safe_ui", "safe_layout",
92            "safe_work",
93        ]
94    };
95    pub const SAFEST: FlagsFeatures = FlagsFeatures {
96        flags: &[],
97        features: &["safest"],
98    };
99    pub const UNSAFE: FlagsFeatures = FlagsFeatures {
100        flags: &["unsafe··"],
101        features: &[
102            "unsafe", // [11]
103            "unsafe_array", "unsafe_ffi", "unsafe_hint", "unsafe_layout",
104            "unsafe_niche", "unsafe_ptr", "unsafe_slice", "unsafe_str",
105            "unsafe_sync", "unsafe_syscall", "unsafe_thread",
106        ]
107    };
108
109    // In sync with ./Cargo.toml::nightly & ./src/lib.rs
110    pub const NIGHTLY: FlagsFeatures = FlagsFeatures {
111        flags: &["nightly··"],
112        features: &[
113            "nightly_allocator",
114            "nightly_autodiff",
115            "nightly_bigint",
116            "nightly_coro",
117            "nightly_doc",
118            "nightly_float",
119            "nightly_simd",
120            "nightly_stable",
121        ]
122    };
123
124    pub const DEPENDENCY: FlagsFeatures = FlagsFeatures {
125        flags: &["dep··"],
126        features: &include!{"../config/dep_all.rs"},
127    };
128
129    /* # modules */
130
131    pub const CODE: FlagsFeatures = FlagsFeatures {
132        flags: &["code··"],
133        features: &["code", "error"]
134    };
135    pub const DATA: FlagsFeatures = FlagsFeatures {
136        flags: &["data··"],
137        features: &["data", "hash"]
138    };
139    pub const LANG: FlagsFeatures = FlagsFeatures {
140        flags: &["lang··"],
141        features: &["lang", "glsl", "js"]
142    };
143    pub const MEDIA: FlagsFeatures = FlagsFeatures {
144        flags: &["media··"],
145        features: &["media", "audio", "color", "draw", "font", "image"]
146    };
147    pub const NUM: FlagsFeatures = FlagsFeatures {
148        flags: &["num··"],
149        features: &["num", "alg", "geom", "prim", "rand", "unit"]
150    };
151        pub const PRIM: FlagsFeatures = FlagsFeatures {
152            flags: &["prim··"],
153            features: &["prim", "cast", "join", "split"]
154        };
155    pub const PHYS: FlagsFeatures = FlagsFeatures {
156        flags: &["phys··"],
157        features: &["phys", "time", "wave"]
158    };
159    pub const SYS: FlagsFeatures = FlagsFeatures {
160        flags: &["sys··"],
161        features: &["sys", "io", "mem",
162            /* os: */ "linux", "windows"]
163    };
164        // RETHINK:
165        pub const MEM: FlagsFeatures = FlagsFeatures {
166            flags: &["mem··"],
167            features: &["mem", "bit"]
168        };
169    pub const TEXT: FlagsFeatures = FlagsFeatures {
170        flags: &["text··"],
171        features: &["text", "ascii", "fmt", "str"]
172    };
173    pub const UI: FlagsFeatures = FlagsFeatures {
174        flags: &["ui··"],
175        features: &[
176            "ui", "layout",
177            "dep_crossterm", "dep_fltk", "dep_girls", "dep_miniquad", "dep_sdl2", "dep_sdl3",
178        ]
179    };
180    pub const WORK: FlagsFeatures = FlagsFeatures {
181        flags: &["work··"],
182        features: &["work", "process", "sync", "thread"]
183    };
184
185    /* # capabilities */
186
187    /* ## code */
188
189    pub const UNROLL: FlagsFeatures = FlagsFeatures {
190        flags: &[],
191        features: &[
192            "_unroll", "_unroll_128", "_unroll_256", "_unroll_512", "_unroll_1024", "_unroll_2048",
193        ]
194    };
195
196    /* ## data */
197
198    pub const BIT: FlagsFeatures = FlagsFeatures {
199        flags: &["_bit··"],
200        features: &[
201            "_bit_i8", "_bit_i16", "_bit_i32", "_bit_i64", "_bit_i128", "_bit_isize",
202            "_bit_u8", "_bit_u16", "_bit_u32", "_bit_u64", "_bit_u128", "_bit_usize",
203        ]
204    };
205    pub const TUPLE: FlagsFeatures = FlagsFeatures {
206        flags: &[],
207        features: &["_tuple", "_tuple_24", "_tuple_36", "_tuple_48", "_tuple_72"]
208    };
209
210    // ### collections
211    pub const DESTAQUE: FlagsFeatures = FlagsFeatures {
212        flags: &["_destaque··"],
213        features: &["_destaque_u8", "_destaque_u16", "_destaque_u32", "_destaque_usize"]
214    };
215    pub const GRAPH: FlagsFeatures = FlagsFeatures {
216        flags: &["_graph··"],
217        features: &["_graph_u8", "_graph_u16", "_graph_u32", "_graph_usize"]
218    };
219    pub const NODE: FlagsFeatures = FlagsFeatures {
220        flags: &["_node··"],
221        features: &["_node_u8", "_node_u16", "_node_u32", "_node_usize"]
222    };
223    pub const STACK: FlagsFeatures = FlagsFeatures {
224        flags: &["_stack··"],
225        features: &["_stack_u8", "_stack_u16", "_stack_u32", "_stack_usize"] };
226
227    pub const SORT_INT: FlagsFeatures = FlagsFeatures {
228        flags: &["_sort··", "_sort_int··"],
229        features: &[
230            "_sort_i8", "_sort_i16", "_sort_i32", "_sort_i64", "_sort_i128", "_sort_isize",
231            "_sort_u8", "_sort_u16", "_sort_u32", "_sort_u64", "_sort_u128", "_sort_usize",
232        ]
233    };
234    pub const SORT_FLOAT: FlagsFeatures = FlagsFeatures {
235        flags: &["_sort··", "_sort_float··"],
236        features: &["_sort_f32", "_sort_f64"]
237    };
238
239    /* ## num */
240
241    pub const CMP: FlagsFeatures = FlagsFeatures {
242        flags: &["_cmp··"],
243        features: &[
244            "_cmp_i8", "_cmp_i16", "_cmp_i32", "_cmp_i64", "_cmp_i128", "_cmp_isize",
245            "_cmp_u8", "_cmp_u16", "_cmp_u32", "_cmp_u64", "_cmp_u128",
246            "_cmp_f32", "_cmp_f64",
247        ]
248    };
249
250    // ### numbers
251    pub const FLOAT: FlagsFeatures = FlagsFeatures {
252        flags: &["_float··", "_nums··"],
253        features: &["_float_f32", "_float_f64"] };
254    pub const INT: FlagsFeatures = FlagsFeatures {
255        flags: &["_int_i··", "_int··", "_nums··"],
256        features: &["_int_i8", "_int_i16", "_int_i32", "_int_i64", "_int_i128", "_int_isize"] };
257    pub const UINT: FlagsFeatures = FlagsFeatures {
258        flags: &["_int_u··", "_int··", "_nums··"],
259        features: &["_int_u8", "_int_u16", "_int_u32", "_int_u64", "_int_u128", "_int_usize"] };
260
261    /* ## text */
262
263    pub const STRING_U: FlagsFeatures = FlagsFeatures {
264        flags: &["_str··", "_str_u··"],
265        features: &["_str_u8", "_str_u16", "_str_u32", "_str_usize"] };
266    pub const STRING: FlagsFeatures = FlagsFeatures {
267        flags: &["_str··"],
268        features: &["_str_nonul"] };
269    pub const CHAR: FlagsFeatures = FlagsFeatures {
270        flags: &["_char··"],
271        features: &["_char7", "_char8", "_char16", "_char24", "_char32"] };
272
273
274    // function helpers
275    // -------------------------------------------------------------------------
276
277    /// Set the flags for all the corresponding enabled features from the list.
278    ///
279    /// This is the list of the constants defined above.
280    pub(super) fn set_flags() -> Vec<String> {
281        let mut enabled_flags = Vec::new();
282
283        for ff in [
284            /* development */
285
286            DEVELOPMENT,
287            ENVIRONMENT,
288            SAFE, SAFEST, UNSAFE,
289            NIGHTLY,
290            DEPENDENCY,
291
292            /* modules */
293
294            CODE,
295            DATA,
296            LANG,
297            MEDIA,
298            NUM, PRIM,
299            PHYS,
300            SYS, MEM,
301            TEXT,
302            UI,
303            WORK,
304
305            /* capabilities */
306
307            // code
308            UNROLL,
309            // data
310            BIT, TUPLE,
311            DESTAQUE, GRAPH, NODE, STACK, // collections
312            SORT_INT, SORT_FLOAT,
313            // text
314            CHAR, STRING, STRING_U,
315            // num
316            CMP,
317            FLOAT, INT, UINT, // numbers
318
319        ] { set_flags_dbg_features(ff.flags, ff.features, &mut enabled_flags); }
320
321        enabled_flags
322    }
323
324    /// Sets configuration flags for reflection if some features are enabled.
325    ///
326    /// - flag_names: The name of the cfg flag to set if any feature is enabled.
327    /// - features:   The feature names to check.
328    fn set_flags_dbg_features(flags: &[&str], features: &[&str], enabled: &mut Vec<String>) {
329        let is_enabled = features.iter().any(|&f| ENABLED_FEATURES.get().unwrap().contains(f));
330        if is_enabled {
331            for flag in flags {
332                println!("cargo:rustc-cfg={}", flag);
333                enabled.push(flag.to_string());
334            }
335        }
336    }
337}