From bebd446c2cdb1645be7197fa738a66b73449bfc5 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 2 Oct 2022 15:53:05 +0200 Subject: feat: add feature_specific macro --- src/lib.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/lib.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..87d933c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,88 @@ +//! Utility macros for utilizing cargo features. + +#![deny(clippy::all)] +#![deny(clippy::pedantic)] +#![deny(missing_docs)] + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse2, Item, LitStr}; + +/// Specifies that a item is only available with a specific feature enabled. This will also +/// document that item is only available with the specified feature enabled by using +/// the [`doc_cfg`] feature. +/// +/// All this macro does is to add the following attributes: +/// ```text +/// #[cfg(feature = {FEATURE})] +/// #[cfg_attr(doc_cfg, doc(cfg(feature = {FEATURE})))] +/// ``` +/// +/// With `{FEATURE}` being replaced with the feature argument. +/// +/// # Arguments +/// - The feature. For example: `"parsing"` +/// +/// # Panics +/// If not attributed to a item or if arguments is missing. +/// +/// # Examples +/// ``` +/// # use feature_macros::feature_specific; +/// # +/// #[feature_specific("cool-things")] +/// pub fn do_some_cool_thing() { +/// // ... +/// } +/// ``` +/// +/// [`doc_cfg`]: https://doc.rust-lang.org/unstable-book/language-features/doc-cfg.html +#[proc_macro_attribute] +pub fn feature_specific(args_stream: TokenStream, item_stream: TokenStream) -> TokenStream { + create_feature_specific(args_stream.into(), item_stream.into()) + .unwrap() + .into() +} + +fn create_feature_specific( + args_stream: proc_macro2::TokenStream, + item_stream: proc_macro2::TokenStream, +) -> Result> { + let item = parse2::(item_stream)?; + + let feature = parse2::(args_stream).unwrap().value(); + + Ok(quote! { + #[cfg(feature = #feature)] + #[cfg_attr(doc_cfg, doc(cfg(feature = #feature)))] + #item + }) +} + +#[cfg(test)] +mod tests { + use std::error::Error; + + use super::*; + + #[test] + fn create_feature_specific_works() -> Result<(), Box> { + assert_eq!( + create_feature_specific( + quote! {"extra-stuff"}, + quote! { + pub mod extra; + }, + )? + .to_string(), + quote! { + #[cfg(feature = "extra-stuff")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-stuff")))] + pub mod extra; + } + .to_string() + ); + + Ok(()) + } +} -- cgit v1.2.3-18-g5258