derive_builder_core_fork_arti/
deprecation_notes.rs

1use proc_macro2::{Span, TokenStream};
2use quote::{ToTokens, TokenStreamExt};
3use syn;
4
5/// Deprecation notes we want to emit to the user, implementing
6/// `quote::ToTokens`.
7///
8/// Can be expanded at every place that accepts statements and item definitions
9/// (e.g. function bodys).
10///
11/// # Examples
12///
13/// Will expand to something like the following (depending on settings):
14///
15/// ```rust,ignore
16/// # #[macro_use]
17/// # extern crate quote;
18/// # extern crate derive_builder_core;
19/// # use derive_builder_core::DeprecationNotes;
20/// # fn main() {
21/// #    let mut note = DeprecationNotes::default();
22/// #    note.push("Some Warning".to_string());
23/// #    assert_eq!(quote!(#note).to_string(), quote!(
24///         {
25///             #[deprecated(note = "Some Warning")]
26///             fn derive_builder_core_deprecation_note() { }
27///             derive_builder_core_deprecation_note();
28///         }
29/// #    ).to_string());
30/// # }
31/// ```
32///
33/// This will emit a deprecation warning in the downstream crate. Cool stuff. ^^
34///
35/// Proof of concept:
36/// - <https://play.rust-lang.org/?gist=8394141c07d1f6d75d314818389eb4d8>
37#[derive(Debug, Default, Clone)]
38pub struct DeprecationNotes(Vec<String>);
39
40impl ToTokens for DeprecationNotes {
41    fn to_tokens(&self, tokens: &mut TokenStream) {
42        for note in &self.0 {
43            let fn_ident =
44                syn::Ident::new("derive_builder_core_deprecation_note", Span::call_site());
45            tokens.append_all(quote!(
46                {
47                    #[deprecated(note=#note)]
48                    fn #fn_ident() { }
49                    #fn_ident();
50                }
51            ));
52        }
53    }
54}
55
56impl DeprecationNotes {
57    /// Appends a note to the collection.
58    #[cfg(test)]
59    pub fn push(&mut self, note: String) {
60        self.0.push(note)
61    }
62
63    /// Create a view of these deprecation notes that can annotate a struct.
64    pub const fn as_item(&self) -> DeprecationNotesAsItem {
65        DeprecationNotesAsItem(self)
66    }
67}
68
69/// A view of `DeprecationNotes` that can be used in any context that accept
70/// items.
71///
72/// Expands to a function `__deprecation_notes` which emits the notes.
73#[derive(Debug)]
74pub struct DeprecationNotesAsItem<'a>(&'a DeprecationNotes);
75
76impl<'a> ToTokens for DeprecationNotesAsItem<'a> {
77    fn to_tokens(&self, tokens: &mut TokenStream) {
78        let deprecation_notes = self.0;
79
80        if !deprecation_notes.0.is_empty() {
81            tokens.append_all(quote!(
82                #[doc(hidden)]
83                fn derive_builder_core_deprecation_note() {
84                    #deprecation_notes
85                }
86            ))
87        }
88    }
89}
90
91#[test]
92fn deprecation_note() {
93    let mut note = DeprecationNotes::default();
94    note.push("Some Warning".to_string());
95    assert_eq!(
96        quote!(#note).to_string(),
97        quote!({
98            #[deprecated(note = "Some Warning")]
99            fn derive_builder_core_deprecation_note() {}
100            derive_builder_core_deprecation_note();
101        })
102        .to_string()
103    );
104}