stability/
lib.rs

1//! This crate provides attribute macros for specifying API stability of public
2//! API items of a crate.
3//!
4//! The Rust standard library has a concept of [API
5//! stability](https://rustc-dev-guide.rust-lang.org/stability.html) and custom
6//! attributes for managing that on a per-item basis, but most of these
7//! attributes are not available for normal crates to use, with the exception of
8//! the
9//! [`#[deprecated]`](https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute)
10//! attribute. This crate seeks to provide similar attributes on stable Rust,
11//! though tuned more toward what the needs of normal crate authors.
12//!
13//! For complete examples of how to use this crate, check out the source code
14//! for the [`stability-example`
15//! crate](https://github.com/sagebind/stability/tree/master/example) included
16//! in the stability repository.
17//!
18//! Currently, only the [`#[unstable]`][macro@unstable] attribute is available.
19//! Please see the documentation of that macro for an explanation on what it
20//! does and how to use it.
21
22use proc_macro::TokenStream;
23use syn::{parse_macro_input, Item};
24
25mod unstable;
26
27/// Mark an API as unstable.
28///
29/// You can apply this attribute to an item in your public API that you would
30/// like to expose to users, but are not yet ready for general use. This is
31/// useful when you want to let users try out some new functionality for an API
32/// you haven't finished testing or designing, or for whatever reason do not
33/// want to commit any stability guarantees for.
34///
35/// This attribute does the following things to annotated items:
36///
37/// - Changes the visibility of the item from `pub` to `pub(crate)`, unless a
38///   certain crate feature is enabled. This ensures that internal code within
39///   the crate can always use the item, but downstream consumers cannot access
40///   it unless they opt-in to the unstable API.
41///   - Visibility of certain child items of the annotated item will also be
42///     changed to match the new item visibility, such as struct fields. Children
43///     that are not public will not be affected.
44///   - Child items of annotated modules will *not* have their visibility changed,
45///     as it might be desirable to be able to re-export them even if the module
46///     visibility is restricted. You should apply the attribute to each item
47///     within the module with the same feature name if you want to restrict the
48///     module's contents itself and not just the module namespace.
49/// - Appends an "Availability" section to the item's documentation that notes
50///   that the item is unstable, and indicates the name of the crate feature to
51///   enable it.
52///
53/// Note that unlike the `#[unstable]` attribute used [in the standard
54/// library](https://rustc-dev-guide.rust-lang.org/stability.html), this
55/// attribute does not apply itself recursively to child items.
56///
57/// Applying this attribute to non-`pub` items is pointless and does nothing.
58///
59/// # Arguments
60///
61/// The `unstable` attribute supports optional arguments that can be passed to
62/// control its behavior.
63///
64/// - `feature`: Specify the name of the unstable feature that should control
65///   this item's availability. The crate feature will have the string
66///   `unstable-` prepended to it. If not specified, it will be guarded by a
67///   catch-all `unstable` feature.
68/// - `issue`: Provide a link or reference to a tracking issue for the unstable
69///   feature. This will be included in the item's documentation.
70///
71/// # Examples
72///
73/// We can apply the attribute to a public function like so:
74///
75/// ```
76/// /// This function does something really risky!
77/// ///
78/// /// Don't use it yet!
79/// #[stability::unstable(feature = "risky-function")]
80/// pub fn risky_function() {
81///     unimplemented!()
82/// }
83/// ```
84///
85/// This will essentially be expanded to the following:
86///
87/// ```
88/// /// This function does something really risky!
89/// ///
90/// /// Don't use it yet!
91/// ///
92/// /// # Availability
93/// ///
94/// /// **This API is marked as unstable** and is only available when the
95/// /// `unstable-risky-function` crate feature is enabled. This comes with no
96/// /// stability guarantees, and could be changed or removed at any time.
97/// #[cfg(feature = "unstable-risky-function")]
98/// pub fn risky_function() {
99///     unimplemented!()
100/// }
101///
102/// /// This function does something really risky!
103/// ///
104/// /// Don't use it yet!
105/// #[cfg(not(feature = "unstable-risky-function"))]
106/// pub(crate) fn risky_function() {
107///     unimplemented!()
108/// }
109/// ```
110#[proc_macro_attribute]
111pub fn unstable(args: TokenStream, input: TokenStream) -> TokenStream {
112    let mut attributes = unstable::UnstableAttribute::default();
113    let attributes_parser = syn::meta::parser(|meta| attributes.parse(meta));
114    parse_macro_input!(args with attributes_parser);
115
116    match parse_macro_input!(input as Item) {
117        Item::Type(item_type) => attributes.expand(item_type),
118        Item::Enum(item_enum) => attributes.expand(item_enum),
119        Item::Struct(item_struct) => attributes.expand(item_struct),
120        Item::Fn(item_fn) => attributes.expand(item_fn),
121        Item::Mod(item_mod) => attributes.expand(item_mod),
122        Item::Trait(item_trait) => attributes.expand(item_trait),
123        Item::Const(item_const) => attributes.expand(item_const),
124        Item::Static(item_static) => attributes.expand(item_static),
125        Item::Use(item_use) => attributes.expand(item_use),
126        _ => panic!("unsupported item type"),
127    }
128}