proc_macro_assertions/generatable/
type.rs1use std::iter;
2
3use better_any::{Tid, TidAble};
4use proc_macro2::{Span, TokenStream};
5use quote::quote;
6use syn::Ident;
7
8use crate::{
9 context::Context,
10 maybe_borrowed::MaybeBorrowed,
11 passed_data::{PassedData, WithData},
12 token_cmp_wrapper::TokenCmpWrapper,
13};
14
15use super::{Generatable, StaticTid};
16#[derive(Tid, PartialEq, Eq, PartialOrd, Ord)]
18pub struct Type<'a> {
19 #[doc = r"The type to check the asserted type equals"]
20 pub r#type: MaybeBorrowed<'a, TokenCmpWrapper<syn::Type>>,
21 pub generics_count: usize,
23}
24
25impl<'a> Type<'a> {
26 pub fn new<T>(r#type: T, generics_count: usize) -> Self
30 where
31 T: Into<MaybeBorrowed<'a, TokenCmpWrapper<syn::Type>>>,
32 {
33 Self {
34 r#type: r#type.into(),
35 generics_count,
36 }
37 }
38
39 #[must_use]
40 pub fn from_owned(r#type: syn::Type, generics_count: usize) -> Self {
41 Self::new(r#type, generics_count)
42 }
43
44 #[must_use]
45 pub fn from_borrowed(r#type: &'a syn::Type, generics_count: usize) -> Self {
46 Self::new(r#type, generics_count)
47 }
48}
49
50impl<'a> Generatable<'a, TokenCmpWrapper<syn::Type>> for Type<'a> {
51 type GeneratableData = Ident;
52 type TemplateData = ();
53
54 const EMITS_NON_CONSTANT_CODE: bool = false;
55
56 fn generatable(
57 Context {
58 ident_generator, ..
59 }: &mut Context,
60 ) -> PassedData<Self::GeneratableData> {
61 let ident = ident_generator.prefixed("assert_type_eq");
62 let type_eq_ident = ident_generator.prefixed("TypeEq");
63
64 quote! {
65 trait #type_eq_ident {
66 type This: ?Sized;
67 }
68 impl<T: ?Sized> #type_eq_ident for T {
69 type This = Self;
70 }
71
72 fn #ident<T, U>()
73 where
74 T: ?Sized + TypeEq<This = U>,
75 U: ?Sized,
76 {
77 }
78 }
79 .with_data(ident)
80 }
81
82 fn assert(
83 &self,
84 _context: &mut Context,
85 (assert_type_eq, _): (&Self::GeneratableData, &Self::TemplateData),
86 to_assert: &TokenCmpWrapper<syn::Type>,
87 ) -> Option<TokenStream> {
88 let type_bound = &*self.r#type;
89
90 let generics = (self.generics_count > 0).then(|| {
91 let generic_ident = Ident::new("_", Span::call_site());
92 let generic_ident_iter = iter::repeat(generic_ident).take(self.generics_count);
93
94 quote! {
95 <#(#generic_ident_iter),*>
96 }
97 });
98
99 Some(quote! {
100 #assert_type_eq::<#to_assert,#type_bound #generics>();
101 })
102 }
103
104 fn template(
105 &self,
106 _context: &mut Context,
107 _passed: &Self::GeneratableData,
108 ) -> PassedData<Self::TemplateData>
109 where
110 Self::TemplateData: Default,
111 {
112 PassedData::default()
113 }
114}
115
116impl<'a> Generatable<'a, TokenCmpWrapper<StaticTid<syn::Ident>>> for Type<'a> {
117 type GeneratableData = Ident;
118 type TemplateData = ();
119
120 const EMITS_NON_CONSTANT_CODE: bool = true;
121
122 fn generatable(
123 Context {
124 ident_generator, ..
125 }: &mut Context,
126 ) -> PassedData<Self::GeneratableData> {
127 let ident = ident_generator.prefixed("assert_type_eq");
128 let type_eq_ident = ident_generator.prefixed("TypeEq");
129
130 quote! {
131 trait #type_eq_ident {
132 type This: ?Sized;
133 }
134 impl<T: ?Sized> #type_eq_ident for T {
135 type This = Self;
136 }
137
138 fn #ident<T, U>(_v: U)
139 where
140 U: ?Sized + TypeEq<This = U>,
141 T: ?Sized,
142 {
143 }
144 }
145 .with_data(ident)
146 }
147
148 fn assert(
149 &self,
150 _context: &mut Context,
151 (assert_type_eq, _): (&Self::GeneratableData, &Self::TemplateData),
152 to_assert: &TokenCmpWrapper<StaticTid<syn::Ident>>,
153 ) -> Option<TokenStream> {
154 let type_bound = &*self.r#type;
155
156 let generics = (self.generics_count > 0).then(|| {
157 let generic_ident = Ident::new("_", Span::call_site());
158 let generic_ident_iter = iter::repeat(generic_ident).take(self.generics_count);
159
160 quote! {
161 <#(#generic_ident_iter),*>
162 }
163 });
164
165 Some(quote! {
166 #assert_type_eq::<#type_bound #generics,_>(#to_assert);
167 })
168 }
169
170 fn template(
171 &self,
172 _context: &mut Context,
173 _passed: &Self::GeneratableData,
174 ) -> PassedData<Self::TemplateData>
175 where
176 Self::TemplateData: Default,
177 {
178 PassedData::default()
179 }
180}
181
182#[cfg(test)]
183mod test {
184 use crate::ident_generator::MockIdentGenerator;
185 use quote::quote;
186 use syn::parse_quote;
187
188 use super::*;
189
190 #[test]
191 fn generate_generatable() {
192 let mut mock_ident_gen = MockIdentGenerator::new();
193
194 mock_ident_gen.push_ident("mock_1");
195
196 let mut context = Context::new(&mut mock_ident_gen);
197
198 assert_eq!(
199 <Type as Generatable<TokenCmpWrapper<syn::Type>>>::generatable(&mut context),
200 quote! {
201 trait TypeEq {
202 type This: ?Sized;
203 }
204 impl<T: ?Sized> TypeEq for T {
205 type This = Self;
206 }
207
208 fn assert_type_eq_mock_1<T, U>()
209 where
210 T: ?Sized + TypeEq<This = U>,
211 U: ?Sized,
212 {
213 }
214 }
215 .with_data(parse_quote!(assert_type_eq_mock_1)),
216 );
217
218 assert!(mock_ident_gen.has_no_idents_remaining());
219 }
220
221 #[test]
222 fn generate_template() {
223 let mut mock_ident_gen = MockIdentGenerator::new();
224 let mut context = Context::new(&mut mock_ident_gen);
225
226 assert_eq!(
227 <Type as Generatable<TokenCmpWrapper<syn::Type>>>::template(
228 &Type {
229 r#type: (&syn::Type::Path(syn::parse_quote!(Type))).into(),
230 generics_count: 2,
231 },
232 &mut context,
233 &parse_quote!(assert_type_eq_mock_1)
234 ),
235 PassedData::<()>::default(),
236 );
237 assert!(mock_ident_gen.was_not_called());
238 }
239
240 #[test]
241 fn generate_assert() {
242 let mut mock_ident_gen = MockIdentGenerator::new();
243 let mut context = Context::new(&mut mock_ident_gen);
244
245 assert_eq!(
246 <Type as Generatable<TokenCmpWrapper<syn::Type>>>::assert(
247 &Type {
248 r#type: (&syn::Type::Path(syn::parse_quote!(Type))).into(),
249 generics_count: 2,
250 },
251 &mut context,
252 (&parse_quote!(assert_type_eq_mock_1), &()),
253 &syn::Type::Verbatim("Test".parse().unwrap()).into()
254 )
255 .map(|x| x.to_string()),
256 Some(quote! {
257 assert_type_eq_mock_1::<Test,Type<_,_>>();
258 })
259 .map(|x| x.to_string())
260 );
261 assert!(mock_ident_gen.was_not_called());
262 }
263}