abi_stable_derive/stable_abi/
shared_vars.rs
1use crate::{
2 arenas::Arenas,
3 composite_collections::SmallStartLen as StartLen,
4 lifetimes::{LifetimeIndex, LifetimeIndexPair, LifetimeRange},
5 literals_constructors::rslice_tokenizer,
6 utils::{join_spans, LinearResult, SynResultExt},
7};
8
9use super::{
10 attribute_parsing::LayoutConstructor, tl_multi_tl::TypeLayoutIndex, CommonTokens, ConstIdents,
11};
12
13use as_derive_utils::{syn_err, to_token_fn::ToTokenFnMut};
14
15use core_extensions::SelfOps;
16
17use proc_macro2::Span;
18
19use quote::{quote, ToTokens};
20
21use std::{collections::HashMap, fmt::Display};
22
23pub(crate) struct SharedVars<'a> {
24 const_idents: &'a ConstIdents,
25 arenas: &'a Arenas,
26 ctokens: &'a CommonTokens<'a>,
27 strings: String,
28 lifetime_indices: Vec<LifetimeIndex>,
29 type_layouts_map: HashMap<(LayoutConstructor, &'a syn::Type), u16>,
30 type_layouts: Vec<(LayoutConstructor, &'a syn::Type)>,
31 constants: Vec<&'a syn::Expr>,
32 overflowed_strings: LinearResult<()>,
33 overflowed_lifetime_indices: LinearResult<()>,
34 overflowed_type_layouts: LinearResult<()>,
35 overflowed_constants: LinearResult<()>,
36 extra_errs: LinearResult<()>,
37}
38
39impl<'a> SharedVars<'a> {
40 pub(crate) fn new(
41 arenas: &'a Arenas,
42 const_idents: &'a ConstIdents,
43 ctokens: &'a CommonTokens,
44 ) -> Self {
45 Self {
46 const_idents,
47 arenas,
48 ctokens,
49 strings: String::new(),
50 lifetime_indices: Vec::new(),
51 type_layouts: Vec::new(),
52 type_layouts_map: HashMap::new(),
53 constants: Vec::new(),
54 overflowed_strings: LinearResult::ok(()),
55 overflowed_lifetime_indices: LinearResult::ok(()),
56 overflowed_type_layouts: LinearResult::ok(()),
57 overflowed_constants: LinearResult::ok(()),
58 extra_errs: LinearResult::ok(()),
59 }
60 }
61
62 pub(crate) fn strings(&self) -> &str {
63 &self.strings
64 }
65
66 pub(crate) fn arenas(&self) -> &'a Arenas {
67 self.arenas
68 }
69
70 pub(crate) fn ctokens(&self) -> &'a CommonTokens<'a> {
71 self.ctokens
72 }
73
74 pub(crate) fn extract_errs(&mut self) -> Result<(), syn::Error> {
75 let mut errors = Ok::<(), syn::Error>(());
76 self.overflowed_strings.take().combine_into_err(&mut errors);
77 self.overflowed_lifetime_indices
78 .take()
79 .combine_into_err(&mut errors);
80 self.overflowed_type_layouts
81 .take()
82 .combine_into_err(&mut errors);
83 self.overflowed_constants
84 .take()
85 .combine_into_err(&mut errors);
86 self.extra_errs.take().combine_into_err(&mut errors);
87 errors
88 }
89
90 fn push_str_inner<F>(&mut self, f: F) -> StartLen
91 where
92 F: FnOnce(&mut Self) -> Option<Span>,
93 {
94 let start = self.strings.len();
95 let span = f(self);
96 let len = self.strings.len() - start;
97
98 if start >= (1 << 16) || len >= (1 << 16) {
99 self.string_overflow_err(span);
100 StartLen::DUMMY
101 } else {
102 StartLen::from_start_len(start, len)
103 }
104 }
105
106 pub(crate) fn combine_err(&mut self, r: Result<(), syn::Error>) {
107 self.extra_errs.combine_err(r);
108 }
109
110 pub(crate) fn push_ident(&mut self, ident: &syn::Ident) -> StartLen {
111 self.push_str_inner(|this| {
112 use std::fmt::Write;
113 let _ = write!(this.strings, "{}", ident);
114 Some(ident.span())
115 })
116 }
117
118 pub(crate) fn push_str(&mut self, s: &str, span: Option<Span>) -> StartLen {
119 self.push_str_inner(|this| {
120 this.strings.push_str(s);
121 span
122 })
123 }
124
125 pub fn extend_with_idents<I>(&mut self, separator: &str, iter: I) -> StartLen
126 where
127 I: IntoIterator<Item = &'a syn::Ident>,
128 {
129 self.push_str_inner(|this| {
130 use std::fmt::Write;
131 let mut last_span = None;
132 for ident in iter {
133 last_span = Some(ident.span());
134 let _ = write!(this.strings, "{}", ident);
135 this.push_str(separator, last_span);
136 }
137 last_span
138 })
139 }
140
141 pub fn extend_with_display<I, T>(&mut self, separator: &str, iter: I) -> StartLen
142 where
143 I: IntoIterator<Item = (T, Span)>,
144 T: Display,
145 {
146 self.push_str_inner(|this| {
147 use std::fmt::Write;
148 let mut last_span = None;
149 for (elem, span) in iter {
150 last_span = Some(span);
151 let _ = write!(this.strings, "{}", elem);
152 this.push_str(separator, Some(span));
153 }
154 last_span
155 })
156 }
157
158 #[inline(never)]
159 #[cold]
160 pub(crate) fn string_overflow_err(&mut self, span: Option<Span>) {
161 if self.overflowed_strings.is_ok() {
162 self.overflowed_strings.push_err(syn_err!(
163 span.unwrap_or_else(Span::call_site),
164 "Cannot have more than 64 kylobytes of identifiers in the type combined.
165 This amount is approximate since it stores separators after some identifiers.\
166 ",
167 ));
168 }
169 }
170
171 pub(crate) fn extend_with_lifetime_indices<I>(&mut self, iter: I) -> LifetimeRange
172 where
173 I: IntoIterator<Item = LifetimeIndex>,
174 {
175 let start = self.lifetime_indices.len();
176 self.lifetime_indices.extend(iter);
177 let len = self.lifetime_indices.len() - start;
178
179 if len <= 5 {
180 let mut drainer = self.lifetime_indices.drain(start..).fuse();
181 LifetimeRange::from_array([
182 drainer.next().unwrap_or(LifetimeIndex::NONE),
183 drainer.next().unwrap_or(LifetimeIndex::NONE),
184 drainer.next().unwrap_or(LifetimeIndex::NONE),
185 drainer.next().unwrap_or(LifetimeIndex::NONE),
186 drainer.next().unwrap_or(LifetimeIndex::NONE),
187 ])
188 } else {
189 if (len & 1) == 1 {
190 self.lifetime_indices.push(LifetimeIndex::NONE);
191 }
192
193 let half_len = self.lifetime_indices.len() / 2;
194 if half_len > LifetimeRange::MAX_START {
195 self.lifetime_overflow_start_err();
196 LifetimeRange::DUMMY
197 } else if half_len > LifetimeRange::MAX_LEN {
198 self.lifetime_overflow_len_err();
199 LifetimeRange::DUMMY
200 } else {
201 LifetimeRange::from_range(start / 2..half_len)
202 }
203 }
204 }
205
206 #[inline(never)]
207 #[cold]
208 pub(crate) fn lifetime_overflow_start_err(&mut self) {
209 if self.overflowed_lifetime_indices.is_ok() {
210 self.overflowed_lifetime_indices.push_err(syn_err!(
211 Span::call_site(),
212 "Cannot have more than {} lifetimes arguments within a type definition.\n\
213 The amount is approximate,\n
214 since this stores 5 or fewer lifetimes in fields/function pointers inline,
215 and those don't contribute to the lifetime arguments limit.",
216 LifetimeRange::MAX_START * 2,
217 ));
218 }
219 }
220
221 #[inline(never)]
222 #[cold]
223 pub(crate) fn lifetime_overflow_len_err(&mut self) {
224 if self.overflowed_lifetime_indices.is_ok() {
225 self.overflowed_lifetime_indices.push_err(syn_err!(
226 Span::call_site(),
227 "Cannot have more than {} lifetimes arguments within \
228 a field or function pointer.\n",
229 LifetimeRange::MAX_LEN * 2,
230 ));
231 }
232 }
233
234 pub(crate) fn push_type(
235 &mut self,
236 layout_ctor: LayoutConstructor,
237 type_: &'a syn::Type,
238 ) -> TypeLayoutIndex {
239 let type_layouts = &mut self.type_layouts;
240
241 let key = (layout_ctor, type_);
242
243 let len = *self.type_layouts_map.entry(key).or_insert_with(move || {
244 let len = type_layouts.len();
245 type_layouts.push(key);
246 len as u16
247 });
248 if len > TypeLayoutIndex::MAX_VAL_U16 {
249 self.construct_type_overflow_err();
250 TypeLayoutIndex::DUMMY
251 } else {
252 TypeLayoutIndex::from_u10(len)
253 }
254 }
255
256 pub(crate) fn extend_type<I>(&mut self, layout_ctor: LayoutConstructor, types: I) -> StartLen
257 where
258 I: IntoIterator<Item = &'a syn::Type>,
259 {
260 let start = self.type_layouts.len();
261 for ty in types {
262 self.type_layouts.push((layout_ctor, ty));
263 }
264 let end = self.type_layouts.len();
265
266 if end > TypeLayoutIndex::MAX_VAL {
267 self.construct_type_overflow_err();
268 StartLen::DUMMY
269 } else {
270 StartLen::from_start_len(start, end - start)
271 }
272 }
273
274 #[inline(never)]
275 #[cold]
276 fn construct_type_overflow_err(&mut self) {
277 if self.overflowed_type_layouts.is_ok() {
278 self.overflowed_type_layouts.push_err(syn_err!(
279 join_spans(
280 self.type_layouts
281 .drain(TypeLayoutIndex::MAX_VAL..)
282 .map(|(_, ty)| ty)
283 ),
284 "Cannot have more than {} unique types(ignoring lifetime parameters) \
285 within a type definition.",
286 TypeLayoutIndex::MAX_VAL,
287 ));
288 }
289 }
290
291 pub fn get_type(&self, index: usize) -> Option<&'a syn::Type> {
292 self.type_layouts.get(index).map(|(_, ty)| *ty)
293 }
294
295 pub(crate) fn extend_with_constants<I>(&mut self, iter: I) -> StartLen
296 where
297 I: IntoIterator<Item = &'a syn::Expr>,
298 {
299 let start = self.constants.len();
300 for expr in iter {
301 self.constants.push(expr);
302 }
303 let end = self.constants.len();
304 if end >= (1 << 8) {
305 self.construct_const_overflow_err();
306 StartLen::DUMMY
307 } else {
308 StartLen::from_start_len(start, end - start)
309 }
310 }
311
312 #[inline(never)]
313 #[cold]
314 fn construct_const_overflow_err(&mut self) {
315 if self.overflowed_constants.is_ok() {
316 self.overflowed_constants.push_err(syn_err!(
317 Span::call_site(),
318 "Cannot have more than {} unique types(ignoring lifetime parameters) \
319 within a type definition.",
320 TypeLayoutIndex::MAX_VAL,
321 ));
322 }
323 }
324
325 pub(crate) fn mono_shared_vars_tokenizer(&self) -> impl ToTokens + '_ {
326 ToTokenFnMut::new(move |ts| {
327 let lifetime_indices = self
328 .lifetime_indices
329 .chunks(2)
330 .map(|chunk| {
331 let first = chunk[0];
332 let second = chunk.get(1).map_or(LifetimeIndex::NONE, |x| *x);
333 LifetimeIndexPair::new(first, second).to_u8()
334 })
335 .piped(rslice_tokenizer);
336
337 let strings = &self.const_idents.strings;
338
339 quote!(
340 abi_stable::type_layout::MonoSharedVars::new(
341 #strings,
342 #lifetime_indices,
343 )
344 )
345 .to_tokens(ts);
346 })
347 }
348
349 pub(crate) fn shared_vars_tokenizer(
350 &self,
351 mono_type_layout: &'a syn::Ident,
352 ) -> impl ToTokens + '_ {
353 ToTokenFnMut::new(move |ts| {
354 let ct = self.ctokens;
355 let type_layouts = self
356 .type_layouts
357 .iter()
358 .map(|&(layout_ctor, ty)| make_get_type_layout_tokenizer(ty, layout_ctor, ct));
359
360 let constants = self.constants.iter();
361
362 quote!(
363 const __SABI_CONST_PARAMS: &'static [__ConstGeneric] = &[
364 #(__ConstGeneric::new(&#constants),)*
365 ];
366
367 const __SABI_SHARED_VARS: &'static __sabi_re::SharedVars =
368 &abi_stable::type_layout::SharedVars::new (
369 #mono_type_layout.shared_vars_static(),
370 abi_stable::_sabi_type_layouts!( #(#type_layouts,)* ),
371 __sabi_re::RSlice::from_slice(Self::__SABI_CONST_PARAMS),
372 );
373 )
374 .to_tokens(ts);
375 })
376 }
377}
378
379#[must_use]
380fn make_get_type_layout_tokenizer<'a, T: 'a>(
381 ty: T,
382 field_transparency: LayoutConstructor,
383 ct: &'a CommonTokens<'a>,
384) -> impl ToTokens + 'a
385where
386 T: ToTokens,
387{
388 ToTokenFnMut::new(move |ts| {
389 ty.to_tokens(ts);
390 let opt = match field_transparency {
391 LayoutConstructor::Regular => None,
392 LayoutConstructor::Opaque => Some(&ct.cap_opaque_field),
393 LayoutConstructor::SabiOpaque => Some(&ct.cap_sabi_opaque_field),
394 };
395
396 if let Some(assoc_const) = opt {
397 ct.equal.to_tokens(ts);
398 assoc_const.to_tokens(ts)
399 }
400 })
401}