blob: 8bea55775d04c59e461324d41e3a54f7936162af [file] [log] [blame]
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, TokenStreamExt};
/// Deprecation notes we want to emit to the user, implementing
/// `quote::ToTokens`.
///
/// Can be expanded at every place that accepts statements and item definitions
/// (e.g. function bodys).
///
/// # Examples
///
/// Will expand to something like the following (depending on settings):
///
/// ```rust,ignore
/// # #[macro_use]
/// # extern crate quote;
/// # extern crate derive_builder_core;
/// # use derive_builder_core::DeprecationNotes;
/// # fn main() {
/// # let mut note = DeprecationNotes::default();
/// # note.push("Some Warning".to_string());
/// # assert_eq!(quote!(#note).to_string(), quote!(
/// {
/// #[deprecated(note = "Some Warning")]
/// fn derive_builder_core_deprecation_note() { }
/// derive_builder_core_deprecation_note();
/// }
/// # ).to_string());
/// # }
/// ```
///
/// This will emit a deprecation warning in the downstream crate. Cool stuff. ^^
///
/// Proof of concept:
/// - <https://play.rust-lang.org/?gist=8394141c07d1f6d75d314818389eb4d8>
#[derive(Debug, Default, Clone)]
pub struct DeprecationNotes(Vec<String>);
impl ToTokens for DeprecationNotes {
fn to_tokens(&self, tokens: &mut TokenStream) {
for note in &self.0 {
let fn_ident =
syn::Ident::new("derive_builder_core_deprecation_note", Span::call_site());
tokens.append_all(quote!(
{
#[deprecated(note=#note)]
fn #fn_ident() { }
#fn_ident();
}
));
}
}
}
impl DeprecationNotes {
/// Appends a note to the collection.
#[cfg(test)]
pub fn push(&mut self, note: String) {
self.0.push(note)
}
/// Create a view of these deprecation notes that can annotate a struct.
pub const fn as_item(&self) -> DeprecationNotesAsItem {
DeprecationNotesAsItem(self)
}
}
/// A view of `DeprecationNotes` that can be used in any context that accept
/// items.
///
/// Expands to a function `__deprecation_notes` which emits the notes.
#[derive(Debug)]
pub struct DeprecationNotesAsItem<'a>(&'a DeprecationNotes);
impl<'a> ToTokens for DeprecationNotesAsItem<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let deprecation_notes = self.0;
if !deprecation_notes.0.is_empty() {
tokens.append_all(quote!(
#[doc(hidden)]
fn derive_builder_core_deprecation_note() {
#deprecation_notes
}
))
}
}
}
#[test]
fn deprecation_note() {
let mut note = DeprecationNotes::default();
note.push("Some Warning".to_string());
assert_eq!(
quote!(#note).to_string(),
quote!({
#[deprecated(note = "Some Warning")]
fn derive_builder_core_deprecation_note() {}
derive_builder_core_deprecation_note();
})
.to_string()
);
}