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}