Skip to content

Commit

Permalink
feat: Improve proc-macro zenoh_macros::unstable (#1016)
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzzypixelz authored May 7, 2024
1 parent 7e5d5e8 commit b8dd01d
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 23 deletions.
122 changes: 108 additions & 14 deletions commons/zenoh-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
//!
//! [Click here for Zenoh's documentation](../zenoh/index.html)
use proc_macro::TokenStream;
use quote::quote;
use syn::LitStr;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, parse_quote, Attribute, Error, Item, LitStr, TraitItem};
use zenoh_keyexpr::{
format::{
macro_support::{self, SegmentBuilder},
Expand Down Expand Up @@ -59,19 +59,113 @@ pub fn rustc_version_release(_tokens: TokenStream) -> TokenStream {
(quote! {(#release, #commit)}).into()
}

/// An enumeration of items supported by the [`unstable`] attribute.
enum UnstableItem {
/// Wrapper around [`syn::Item`].
Item(Item),
/// Wrapper around [`syn::TraitItem`].
TraitItem(TraitItem),
}

macro_rules! parse_unstable_item {
($tokens:ident) => {{
let item: Item = parse_macro_input!($tokens as Item);

if matches!(item, Item::Verbatim(_)) {
let tokens = TokenStream::from(item.to_token_stream());
let trait_item: TraitItem = parse_macro_input!(tokens as TraitItem);

if matches!(trait_item, TraitItem::Verbatim(_)) {
Err(Error::new_spanned(
trait_item,
"the `unstable` proc-macro attribute only supports items and trait items",
))
} else {
Ok(UnstableItem::TraitItem(trait_item))
}
} else {
Ok(UnstableItem::Item(item))
}
}};
}

impl UnstableItem {
/// Mutably borrows the attribute list of this item.
fn attributes_mut(&mut self) -> Result<&mut Vec<Attribute>, Error> {
match self {
UnstableItem::Item(item) => match item {
Item::Const(item) => Ok(&mut item.attrs),
Item::Enum(item) => Ok(&mut item.attrs),
Item::ExternCrate(item) => Ok(&mut item.attrs),
Item::Fn(item) => Ok(&mut item.attrs),
Item::ForeignMod(item) => Ok(&mut item.attrs),
Item::Impl(item) => Ok(&mut item.attrs),
Item::Macro(item) => Ok(&mut item.attrs),
Item::Mod(item) => Ok(&mut item.attrs),
Item::Static(item) => Ok(&mut item.attrs),
Item::Struct(item) => Ok(&mut item.attrs),
Item::Trait(item) => Ok(&mut item.attrs),
Item::TraitAlias(item) => Ok(&mut item.attrs),
Item::Type(item) => Ok(&mut item.attrs),
Item::Union(item) => Ok(&mut item.attrs),
Item::Use(item) => Ok(&mut item.attrs),
other => Err(Error::new_spanned(
other,
"item is not supported by the `unstable` proc-macro attribute",
)),
},
UnstableItem::TraitItem(trait_item) => match trait_item {
TraitItem::Const(trait_item) => Ok(&mut trait_item.attrs),
TraitItem::Fn(trait_item) => Ok(&mut trait_item.attrs),
TraitItem::Type(trait_item) => Ok(&mut trait_item.attrs),
TraitItem::Macro(trait_item) => Ok(&mut trait_item.attrs),
other => Err(Error::new_spanned(
other,
"item is not supported by the `unstable` proc-macro attribute",
)),
},
}
}

/// Converts this item to a `proc_macro2::TokenStream`.
fn to_token_stream(&self) -> proc_macro2::TokenStream {
match self {
UnstableItem::Item(item) => item.to_token_stream(),
UnstableItem::TraitItem(trait_item) => trait_item.to_token_stream(),
}
}
}

#[proc_macro_attribute]
pub fn unstable(_attr: TokenStream, item: TokenStream) -> TokenStream {
let item = proc_macro2::TokenStream::from(item);
TokenStream::from(quote! {
#[cfg(feature = "unstable")]
/// <div class="stab unstable">
/// <span class="emoji">🔬</span>
/// This API has been marked as unstable: it works as advertised, but we may change it in a future release.
/// To use it, you must enable zenoh's <code>unstable</code> feature flag.
/// </div>
///
#item
})
pub fn unstable(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
let mut item = match parse_unstable_item!(tokens) {
Ok(item) => item,
Err(err) => return err.into_compile_error().into(),
};

let attrs = match item.attributes_mut() {
Ok(attrs) => attrs,
Err(err) => return err.into_compile_error().into(),
};

if attrs.iter().any(is_doc_attribute) {
// See: https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#adding-a-warning-block
let message = "<div class=\"warning\">This API has been marked as <strong>unstable</strong>: it works as advertised, but it may be changed in a future release.</div>";
let note: Attribute = parse_quote!(#[doc = #message]);
attrs.push(note);
}

let feature_gate: Attribute = parse_quote!(#[cfg(feature = "unstable")]);
attrs.push(feature_gate);

TokenStream::from(item.to_token_stream())
}

/// Returns `true` if the attribute is a `#[doc = "..."]` attribute.
fn is_doc_attribute(attr: &Attribute) -> bool {
attr.path()
.get_ident()
.is_some_and(|ident| &ident.to_string() == "doc")
}

fn keformat_support(source: &str) -> proc_macro2::TokenStream {
Expand Down
3 changes: 2 additions & 1 deletion zenoh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ form_urlencoded = { workspace = true }
futures = { workspace = true }
git-version = { workspace = true }
lazy_static = { workspace = true }
tracing = {workspace = true}
tracing = { workspace = true }
ordered-float = { workspace = true }
paste = { workspace = true }
petgraph = { workspace = true }
Expand Down Expand Up @@ -119,6 +119,7 @@ name = "zenoh"
# NOTE: if you change this, also change it in .github/workflows/release.yml in "doc" job.
[package.metadata.docs.rs]
features = ["unstable"]
rustdoc-args = ["--cfg", "doc_auto_cfg"]

[package.metadata.deb]
name = "zenoh"
Expand Down
2 changes: 2 additions & 0 deletions zenoh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// ZettaScale Zenoh Team, <[email protected]>
//

#![cfg_attr(doc_auto_cfg, feature(doc_auto_cfg))]

//! [Zenoh](https://zenoh.io) /zeno/ is a stack that unifies data in motion, data at
//! rest and computations. It elegantly blends traditional pub/sub with geo distributed
//! storage, queries and computations, while retaining a level of time and space efficiency
Expand Down
10 changes: 2 additions & 8 deletions zenoh/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,19 +355,13 @@ pub(crate) const _REPLY_KEY_EXPR_ANY_SEL_PARAM: &str = "_anyke";
pub const REPLY_KEY_EXPR_ANY_SEL_PARAM: &str = _REPLY_KEY_EXPR_ANY_SEL_PARAM;

#[zenoh_macros::unstable]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum ReplyKeyExpr {
Any,
#[default]
MatchingQuery,
}

#[zenoh_macros::unstable]
impl Default for ReplyKeyExpr {
fn default() -> Self {
ReplyKeyExpr::MatchingQuery
}
}

impl<Handler> Resolvable for GetBuilder<'_, '_, Handler>
where
Handler: IntoCallbackReceiverPair<'static, Reply> + Send,
Expand Down

0 comments on commit b8dd01d

Please sign in to comment.