proc_macro_assertions/
store.rs1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3
4use crate::{raw_assert::r#trait, token_store::TokenStore};
5
6use super::{
7 context::Context,
8 generatable_set::GeneratableSet,
9 ident_generator::{self, CountingIdentGenerator},
10};
11
12pub struct Store<'a, IdentGenerator = CountingIdentGenerator>
31where
32 IdentGenerator: ident_generator::IdentGenerator,
33{
34 pub(crate) extra_items: TokenStream,
35 pub(crate) generatables: GeneratableSet<'a>,
36 pub(crate) ident_gen: IdentGenerator,
37}
38
39impl<'a, IdentGenerator> Store<'a, IdentGenerator>
40where
41 IdentGenerator: ident_generator::IdentGenerator,
42{
43 pub fn add_extra_items(&mut self, item: impl ToTokens) {
44 item.to_tokens(&mut self.extra_items);
45 }
46}
47
48#[allow(clippy::module_name_repetitions)]
49pub type DefaultStore<'a> = Store<'a, CountingIdentGenerator>;
50
51impl<'a, IdentGenerator> Store<'a, IdentGenerator>
52where
53 IdentGenerator: ident_generator::IdentGenerator,
54{
55 pub fn assert(&mut self, assert: impl r#trait::RawAssertable<'a>) {
56 assert.do_raw_assert(self);
57 }
58
59 #[must_use]
60 pub fn new() -> Self
61 where
62 IdentGenerator: Default,
63 {
64 Self::default()
65 }
66}
67
68impl<'a, IdentGenerator> Default for Store<'a, IdentGenerator>
69where
70 IdentGenerator: ident_generator::IdentGenerator + Default,
71{
72 fn default() -> Self {
73 Self {
74 extra_items: TokenStream::new(),
75 generatables: GeneratableSet::new(),
76 ident_gen: IdentGenerator::default(),
77 }
78 }
79}
80
81impl<'a, IdentGenerator> ToTokens for Store<'a, IdentGenerator>
82where
83 IdentGenerator: ident_generator::IdentGenerator + Clone,
84{
85 fn to_tokens(&self, tokens: &mut TokenStream) {
86 let mut ident_gen = self.ident_gen.clone();
87 let mut context = Context::new(&mut ident_gen);
88
89 let mut token_store = TokenStore::new();
90
91 for generatable in self.generatables.iter() {
92 generatable.generate_into(&mut context, &mut token_store);
93 }
94 let asserted_tokens = token_store.into_tokens(&mut context);
95 let extra_items = &self.extra_items;
96
97 let closure_contents = quote! {
98 #extra_items
99 #asserted_tokens
100 };
101
102 let closure = if context.requires_nonconstant_code() {
103 quote! {
104 let _ = || {
105 #closure_contents
106 };
107 }
108 } else {
109 quote! {
110 const _: fn() = || {
111 #closure_contents
112 };
113 }
114 };
115
116 tokens.extend(quote! {
117 #[doc(hidden)]
121 #[allow(warnings)]
122 #closure
123 });
124 }
125}
126
127#[cfg(test)]
128mod test {
129 use quote::ToTokens;
130 use syn::parse_quote;
131
132 use crate::assert_into;
133
134 use super::DefaultStore;
135
136 #[test]
137 fn test() {
138 let generics = syn::Generics::default();
139 let test_ident: syn::Type = parse_quote!(Test1);
140 let test_type: syn::Type = syn::Type::Path(parse_quote!(Test2));
141 let mut store = DefaultStore::new();
142 assert_into!(store | &test_type with &generics == Test);
143 assert_into!(store | &test_ident with &generics impl Debug);
144 println!("{}", store.to_token_stream());
145 }
146}