Skip to main content

osom_lib_cfg_ext/
lib.rs

1//! proc-macros that makes working with `#[cfg(...)]` easier.
2//!
3//! At the moment it provides [`cfg_match`] only.
4#![deny(warnings)]
5#![allow(unused_features)]
6#![warn(clippy::all, clippy::pedantic)]
7#![allow(clippy::redundant_field_names)]
8#![allow(clippy::inline_always)]
9
10use syn::parse_macro_input;
11
12mod cfg_matcher;
13mod generator;
14
15/// Matches against various cfg settings.
16///
17/// # Examples
18///
19/// ```rust
20/// use osom_lib_cfg_ext::cfg_match;
21///
22/// cfg_match!(
23///     (target_os = "windows") => {
24///         fn os_name() -> &'static str {
25///             "W"
26///         }
27///     },
28///     (target_os = "linux") => {
29///         fn os_name() -> &'static str {
30///             "L"
31///         }
32///     },
33///     _ => {
34///         fn os_name() -> &'static str {
35///             "U"
36///         }
37///     }
38/// );
39/// ```
40///
41/// The call above will generate only one `os_name` function, depending on the matched
42/// condition. The condition is translated to one of `#[cfg(...)]` attributes.
43///
44/// Conditions are evaluated one after another. In particular the order doesn't matter
45/// if they are independent. However it does matter in general. For example say we have
46/// this:
47///
48/// ```rust
49/// use osom_lib_cfg_ext::cfg_match;
50///
51/// cfg_match!(
52///     (A) => {
53///         const A: i32 = 1;
54///     },
55///     (B) => {
56///         const B: i32 = 2;
57///     }
58/// );
59/// ```
60///
61/// Then if `B` implies `A` (as a condition) then `B` arm will never be matched here.
62/// For it to be matched you need to reverse the order:
63///
64/// ```rust
65/// use osom_lib_cfg_ext::cfg_match;
66///
67/// cfg_match!(
68///     (B) => {
69///         const B: i32 = 2;
70///     },
71///     (A) => {
72///         const A: i32 = 1;
73///     }
74/// );
75/// ```
76#[proc_macro]
77pub fn cfg_match(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
78    let item = parse_macro_input!(tokens as cfg_matcher::CfgMatcher);
79    generator::generate_from_cfg_match(&item).into()
80}
81
82/// Helper when generating code from [`cfg_match`].
83#[doc(hidden)]
84#[proc_macro]
85pub fn identity(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
86    tokens
87}