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: &String in &self.0 {
43 let fn_ident: Ident =
44 syn::Ident::new(string:"derive_builder_core_deprecation_note", Span::call_site());
45 tokens.append_all(iter: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: &DeprecationNotes = self.0;
79
80 if !deprecation_notes.0.is_empty() {
81 tokens.append_all(iter: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 = 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}
105