instability/lib.rs
1//! This crate provides attribute macros for specifying API stability of public API items of a
2//! crate.
3//!
4//! The Rust standard library has a concept of [API stability] and custom attributes for managing
5//! that on a per-item basis, but most of these attributes are not available for normal crates to
6//! use, with the exception of the [`deprecated`] attribute. This crate seeks to provide similar
7//! attributes on stable Rust, though tuned more toward what the needs of normal crate authors.
8//!
9//! For complete examples of how to use this crate, check out the source code for the
10//! [`instability-example`] crate in the repository
11//!
12//! Currently, only the [`unstable`] attribute is available. Please see the documentation of that
13//! macro for an explanation on what it does and how to use it.
14//!
15//! [API stability]: https://rustc-dev-guide.rust-lang.org/stability.html
16//! [`deprecated`]:
17//! https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
18//! [`instability-example`]: https://github.com/ratatui-org/instability/tree/main/example
19//! [`unstable`]: macro@unstable
20
21use proc_macro::TokenStream;
22use stable::stable_macro;
23use unstable::unstable_macro;
24
25mod item_like;
26mod stable;
27mod unstable;
28
29/// Mark an API as unstable.
30///
31/// You can apply this attribute to an item in your public API that you would like to expose to
32/// users, but are not yet ready for general use. This is useful when you want to let users try out
33/// some new functionality for an API you haven't finished testing or designing, or for whatever
34/// reason do not want to commit any stability guarantees for.
35///
36/// This attribute does the following things to annotated items:
37///
38/// - Changes the visibility of the item from `pub` to `pub(crate)` unless a certain crate feature
39/// is enabled. This ensures that internal code within the crate can always use the item, but
40/// downstream consumers cannot access it unless they opt-in to the unstable API.
41/// - Annotated `impl` blocks will instead be removed.
42/// - Changes the Visibility of certain child items of the annotated item (such as struct fields) to
43/// match the item's visibility. Children that are not public will not be affected.
44/// - Appends an "Stability" section to the item's documentation that notes that the item is
45/// unstable and indicates the name of the crate feature to enable it.
46///
47/// Child items of annotated modules are unchanged, as it might be desirable to be able to re-export
48/// them even if the module visibility is restricted. You should apply the attribute to each item
49/// within the module with the same feature name if you want to restrict the module's contents
50/// itself and not just the module namespace.
51///
52/// Note that unlike the [`unstable`][std-unstable] attribute used in the standard library, this
53/// attribute does not apply itself recursively to child items.
54///
55/// [std-unstable]: https://rustc-dev-guide.rust-lang.org/stability.html
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 control its behavior.
62///
63/// - `feature`: the name of the unstable feature that should control this item's availability. This
64/// will have the string `unstable-` prepended to it. If not specified, the item will instead be
65/// guarded by a catch-all `unstable` feature.
66/// - `issue`: a link or reference to a tracking issue for the unstable feature. This will be
67/// included in the item's documentation.
68///
69/// # Examples
70///
71/// We can apply the attribute to a public function like so:
72///
73/// ```
74/// /// This function does something really risky!
75/// ///
76/// /// Don't use it yet!
77/// #[instability::unstable(feature = "risky-function")]
78/// pub fn risky_function() {
79/// unimplemented!()
80/// }
81/// ```
82///
83/// This will essentially be expanded to the following:
84///
85/// ```
86/// /// This function does something really risky!
87/// ///
88/// /// Don't use it yet!
89/// ///
90/// /// # Availability
91/// ///
92/// /// **This API is marked as unstable** and is only available when the `unstable-risky-function`
93/// /// crate feature is enabled. This comes with no stability guarantees, and could be changed or
94/// /// removed at any time.
95/// #[cfg(feature = "unstable-risky-function")]
96/// pub fn risky_function() {
97/// unimplemented!()
98/// }
99///
100/// /// This function does something really risky!
101/// ///
102/// /// Don't use it yet!
103/// #[cfg(not(feature = "unstable-risky-function"))]
104/// pub(crate) fn risky_function() {
105/// unimplemented!()
106/// }
107/// ```
108///
109/// We can also apply the attribute to an `impl` block like so:
110///
111/// ```
112/// /// This structure is responsible for bar.
113/// pub struct Foo;
114///
115/// #[instability::unstable(feature = "unstable-dependency")]
116/// impl Default for Foo {
117/// fn default() -> Self {
118/// unimplemented!()
119/// }
120/// }
121/// ```
122#[proc_macro_attribute]
123pub fn unstable(args: TokenStream, input: TokenStream) -> TokenStream {
124 unstable_macro(args.into(), input.into()).into()
125}
126
127/// Mark an API as stable.
128///
129/// You can apply this attribute to an item in your public API that you would like to expose to
130/// users, and are ready to make a stability guarantee for. This is useful when you have finished
131/// testing and designing an API and are ready to commit to its design and stability.
132///
133/// This attribute does the following things to annotated items:
134///
135/// - Appends a "Stability" section to the item's documentation that notes that the item is stable
136/// and indicates the version at which it was stabilized.
137///
138/// # Arguments
139///
140/// The `stable` attribute supports optional arguments that can be passed to control its behavior.
141///
142/// - `since`: the version at which the item was stabilized. This should be a string that follows
143/// the [Semantic Versioning](https://semver.org) convention. If not specified, the item will be
144/// marked as stable with no version information.
145/// - `issue`: a link or reference to a tracking issue for the stabilized feature. This will be
146/// included in the item's documentation.
147///
148/// # Examples
149///
150/// We can apply the attribute to a public function like so:
151///
152/// ```
153/// /// This function does something really risky!
154/// ///
155/// /// Don't use it yet!
156/// #[instability::stable(since = "v1.0.0")]
157/// pub fn stable_function() {
158/// unimplemented!()
159/// }
160/// ```
161///
162/// This will essentially be expanded to the following:
163///
164/// ```
165/// /// This function does something really risky!
166/// ///
167/// /// Don't use it yet!
168/// ///
169/// /// # Stability
170/// ///
171/// /// This API was stabilized in version 1.0.0.
172/// pub fn stable_function() {
173/// unimplemented!()
174/// }
175/// ```
176///
177/// Applying this attribute to non-`pub` items is pointless and does nothing.
178///
179/// # Panics
180///
181/// This macro will panic if applied to an unsupported item type.
182///
183/// # Limitations
184///
185/// This attribute does not change the visibility of the annotated item. You should ensure that the
186/// item's visibility is set to `pub` if you want it to be part of your crate's public API.
187///
188/// # See also
189///
190/// - The [`unstable`] attribute for marking an API as unstable.
191///
192/// [`unstable`]: macro@unstable
193#[proc_macro_attribute]
194pub fn stable(args: TokenStream, input: TokenStream) -> TokenStream {
195 stable_macro(args.into(), input.into()).into()
196}