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