abi_stable_derive/stable_abi/
nonexhaustive.rs

1use std::collections::HashMap;
2
3use core_extensions::SelfOps;
4
5use syn::{visit_mut::VisitMut, Ident};
6
7use quote::{quote, ToTokens};
8
9use proc_macro2::{Span, TokenStream as TokenStream2};
10
11use as_derive_utils::{
12    datastructure::DataStructure,
13    gen_params_in::{GenParamsIn, InWhat},
14    return_spanned_err, spanned_err,
15    to_token_fn::ToTokenFnMut,
16};
17
18use super::{
19    attribute_parsing::{StabilityKind, StableAbiOptions},
20    common_tokens::CommonTokens,
21    StartLen,
22};
23
24use crate::{
25    arenas::{AllocMethods, Arenas},
26    impl_interfacetype::{private_associated_type, UsableTrait, TRAIT_LIST},
27    literals_constructors::rstr_tokenizer,
28    parse_utils::{parse_str_as_ident, parse_str_as_path},
29    set_span_visitor::SetSpanVisitor,
30    utils::{LinearResult, SynResultExt},
31};
32
33/// Used while parsing the `#[sabi(kind(WithNonExhaustive(...)))]` attribute.
34#[derive(Clone, Default)]
35pub(crate) struct UncheckedNonExhaustive<'a> {
36    pub(crate) alignment: Option<ExprOrType<'a>>,
37    pub(crate) size: Option<ExprOrType<'a>>,
38    pub(crate) enum_interface: Option<EnumInterface<'a>>,
39    pub(crate) assert_nonexh: Vec<&'a syn::Type>,
40}
41
42/// The configuration for code generation related to nonexhaustive enums.
43#[derive(Clone)]
44pub(crate) struct NonExhaustive<'a> {
45    pub(crate) nonexhaustive_alias: &'a Ident,
46    /// The identifier for the interface parameter of `NonExhaustive<>`(the third one).
47    pub(crate) nonexhaustive_marker: &'a Ident,
48    /// The identifier for the storage space used to store the enum within `NonExhaustive<>`
49    pub(crate) enum_storage: &'a Ident,
50    /// The alignment of `#enum_storage`
51    pub(crate) alignment: ExprOrType<'a>,
52    /// The size of `#enum_storage`
53    pub(crate) size: ExprOrType<'a>,
54    /// The InterfaceType-implementing marker struct this will generate,
55    /// if this is:
56    ///     - `Some(EnumInterface::New{..})`:it will use a new struct as the InterfaceType.
57    ///     - `Some(EnumInterface::Old{..})`:it will use an existing type as the InterfaceType.
58    ///     - `None`: it will use `()` as the InterfaceType.
59    /// rather than generate one.
60    pub(crate) enum_interface: Option<EnumInterface<'a>>,
61    /// The identifier of the InterfaceType-implementing struct this will generate.
62    pub(crate) new_interface: Option<&'a Ident>,
63    /// The type used as the InterfaceType parameter of `NonExhaustive<>` by default.
64    pub(crate) default_interface: TokenStream2,
65    /// The types that will be tested as being compatible with their storage and interface.
66    pub(crate) assert_nonexh: Vec<&'a syn::Type>,
67    /// This is a trait aliasing the constraints required when
68    /// wrapping the enum inside `NonExhaustive<>`.
69    /// This is None when the enum uses a pre-existing InterfaceType as
70    /// its interface (the third type parameter of `NonExhaustive<>`)
71    pub(crate) bounds_trait: Option<BoundsTrait<'a>>,
72    /// The constructor functions generated for each variant,
73    /// with the enum wrapped inside `NonExhaustive<>`
74    pub(crate) ne_variants: Vec<NEVariant<'a>>,
75}
76
77/// The configuration required to generate a trait aliasing the constraints required when
78/// wrapping the enum inside `NonExhaustive<>`.
79#[derive(Clone)]
80pub struct BoundsTrait<'a> {
81    ident: &'a Ident,
82    bounds: Vec<&'a syn::Path>,
83}
84
85#[derive(Clone)]
86pub struct UncheckedNEVariant {
87    pub(crate) constructor: Option<UncheckedVariantConstructor>,
88    pub(crate) is_hidden: bool,
89}
90
91#[derive(Clone)]
92pub struct NEVariant<'a> {
93    pub(crate) constructor: Option<VariantConstructor<'a>>,
94    pub(crate) is_hidden: bool,
95}
96
97/// How a NonExhaustive<Enum,...> is constructed
98#[derive(Clone)]
99pub enum UncheckedVariantConstructor {
100    /// Constructs an enum variant using a function
101    /// with parameters of the same type as the fields.
102    Regular,
103    /// Constructs an enum variant containing a pointer,
104    /// using a function taking the referent of the pointer.
105    Boxed,
106}
107
108/// How variant(s) of the enum wrapped inside `NonExhaustive<>` is constructed.
109#[derive(Clone)]
110pub enum VariantConstructor<'a> {
111    /// Constructs an enum variant using a function
112    /// with parameters of the same type as the fields.
113    Regular,
114    /// Constructs an enum variant containing a pointer,
115    /// using a function taking the referent of the pointer.
116    ///
117    /// The type of the referent is extracted from the first type parameter
118    /// in the type of the only field of a variant.
119    Boxed {
120        referent: Option<&'a syn::Type>,
121        pointer: &'a syn::Type,
122    },
123}
124
125/// The InterfaceType of the enum,used as the third type parameter of NonExhaustive.
126#[derive(Clone)]
127pub(crate) enum EnumInterface<'a> {
128    New(NewEnumInterface<'a>),
129    Old(&'a syn::Type),
130}
131
132/// The traits that are specified in `impl InterfaceType for Enum_Interface`,
133/// which specifies the traits that are required when wrapping the enum in `NonExhaustive<>`,
134/// and are then available when using it.
135#[derive(Default, Clone)]
136pub(crate) struct NewEnumInterface<'a> {
137    pub(crate) impld: Vec<&'a Ident>,
138    pub(crate) unimpld: Vec<&'a Ident>,
139}
140
141impl<'a> NonExhaustive<'a> {
142    pub fn new(
143        mut unchecked: UncheckedNonExhaustive<'a>,
144        ne_variants: Vec<UncheckedNEVariant>,
145        ds: &'a DataStructure<'a>,
146        arenas: &'a Arenas,
147    ) -> Result<Self, syn::Error> {
148        let name = ds.name;
149
150        let alignment = unchecked.alignment.unwrap_or(ExprOrType::Usize);
151
152        let parse_ident = move |s: &str, span: Option<Span>| -> &'a Ident {
153            let mut ident = parse_str_as_ident(s);
154            if let Some(span) = span {
155                ident.set_span(span)
156            }
157            arenas.alloc(ident)
158        };
159
160        let mut errors = LinearResult::ok(());
161
162        let size = unchecked.size.unwrap_or_else(|| {
163            errors.push_err(spanned_err!(
164                name,
165                "\n\
166                You must specify the size of the enum storage in NonExhaustive<> using \
167                the `size=integer literal` or `size=\"type\"` argument inside of \
168                the `#[sabi(kind(WithNonExhaustive(...)))]` helper attribute.\n\
169                "
170            ));
171            ExprOrType::Int(0)
172        });
173
174        let mut bounds_trait = None::<BoundsTrait<'a>>;
175
176        if let Some(EnumInterface::New(enum_interface)) = &mut unchecked.enum_interface {
177            let mut trait_map = TRAIT_LIST
178                .iter()
179                .map(|x| (parse_ident(x.name, None), x))
180                .collect::<HashMap<&'a syn::Ident, &'static UsableTrait>>();
181
182            let mut bounds_trait_inner = Vec::<&'a syn::Path>::new();
183
184            for &trait_ in &enum_interface.impld {
185                match trait_map.remove(trait_) {
186                    Some(ut) => {
187                        use crate::impl_interfacetype::WhichTrait as WT;
188                        if let WT::Deserialize = ut.which_trait {
189                            continue;
190                        }
191                        let mut full_path = parse_str_as_path(ut.full_path)?;
192
193                        SetSpanVisitor::new(trait_.span()).visit_path_mut(&mut full_path);
194
195                        bounds_trait_inner.push(arenas.alloc(full_path));
196                    }
197                    None => {
198                        // This is an internal error.
199                        panic!("Trait {} was not in TRAIT_LIST.", trait_)
200                    }
201                }
202            }
203
204            bounds_trait = Some(BoundsTrait {
205                ident: parse_ident(&format!("{}_Bounds", name), None),
206                bounds: bounds_trait_inner,
207            });
208
209            for &trait_ in &enum_interface.unimpld {
210                // This is an internal error.
211                assert!(
212                    trait_map.remove(trait_).is_some(),
213                    "Trait {} was not in TRAIT_LIST.",
214                    trait_
215                );
216            }
217
218            for (trait_, _) in trait_map {
219                enum_interface.unimpld.push(trait_);
220            }
221        }
222
223        let (default_interface, new_interface) = match unchecked.enum_interface {
224            Some(EnumInterface::New { .. }) => {
225                let name = parse_ident(&format!("{}_Interface", name), None);
226                (name.into_token_stream(), Some(name))
227            }
228            Some(EnumInterface::Old(ty)) => ((&ty).into_token_stream(), None),
229            None => (quote!(()), None),
230        };
231
232        let ne_variants = ne_variants
233            .into_iter()
234            .zip(&ds.variants)
235            .map(|(vc, variant)| {
236                let constructor = match vc.constructor {
237                    Some(UncheckedVariantConstructor::Regular) => Some(VariantConstructor::Regular),
238                    Some(UncheckedVariantConstructor::Boxed) => match variant.fields.first() {
239                        Some(first_field) => Some(VariantConstructor::Boxed {
240                            referent: extract_first_type_param(first_field.ty),
241                            pointer: first_field.ty,
242                        }),
243                        None => Some(VariantConstructor::Regular),
244                    },
245                    None => None,
246                };
247
248                NEVariant {
249                    constructor,
250                    is_hidden: vc.is_hidden,
251                }
252            })
253            .collect();
254
255        errors.into_result()?;
256
257        Ok(Self {
258            nonexhaustive_alias: parse_ident(&format!("{}_NE", name), None),
259            nonexhaustive_marker: parse_ident(&format!("{}_NEMarker", name), None),
260            enum_storage: parse_ident(&format!("{}_Storage", name), None),
261            alignment,
262            size,
263            enum_interface: unchecked.enum_interface,
264            default_interface,
265            new_interface,
266            assert_nonexh: unchecked.assert_nonexh,
267            bounds_trait,
268            ne_variants,
269        })
270    }
271}
272
273#[derive(Copy, Clone)]
274pub enum ExprOrType<'a> {
275    Int(usize),
276    Expr(&'a syn::Expr),
277    Type(&'a syn::Type),
278    Usize,
279}
280
281/// Extracts the first type parameter of a generic type.
282fn extract_first_type_param(ty: &syn::Type) -> Option<&syn::Type> {
283    match ty {
284        syn::Type::Path(path) => {
285            if path.qself.is_some() {
286                return None;
287            }
288            let args = &path.path.segments.last()?.arguments;
289            let args = match args {
290                syn::PathArguments::AngleBracketed(x) => x,
291                _ => return None,
292            };
293            args.args.iter().find_map(|arg| match arg {
294                syn::GenericArgument::Type(ty) => Some(ty),
295                _ => None,
296            })
297        }
298        _ => None,
299    }
300}
301
302fn hide_docs_if<T, F>(opt: &Option<T>, func: F) -> String
303where
304    F: FnOnce() -> String,
305{
306    if opt.is_some() {
307        String::new()
308    } else {
309        func()
310    }
311}
312
313/// Outputs the nonexhausitve-enum-related items,
314/// outside the module generated by StableAbi.
315pub(crate) fn tokenize_nonexhaustive_items<'a>(
316    ds: &'a DataStructure<'a>,
317    config: &'a StableAbiOptions<'a>,
318    _ct: &'a CommonTokens<'a>,
319) -> impl ToTokens + 'a {
320    ToTokenFnMut::new(move |ts| {
321        let this = match &config.kind {
322            StabilityKind::NonExhaustive(x) => x,
323            _ => return,
324        };
325        let doc_hidden_attr = config.doc_hidden_attr;
326        let vis = ds.vis;
327        let nonexhaustive_alias = this.nonexhaustive_alias;
328        let nonexhaustive_marker = this.nonexhaustive_marker;
329        let enum_storage = this.enum_storage;
330
331        let (aligner_attribute, aligner_field) = match this.alignment {
332            ExprOrType::Int(bytes) => {
333                let bytes = crate::utils::expr_from_int(bytes as _);
334                (Some(quote!(#[repr(align(#bytes))])), None)
335            }
336            ExprOrType::Expr(expr) => (
337                None,
338                Some(quote!(
339                    __aligner: [
340                        ::abi_stable::pmr::GetAlignerFor<::abi_stable::pmr::u8, #expr>;
341                        0
342                    ]
343                )),
344            ),
345            ExprOrType::Type(ty) => (None, Some(quote!(__aligner:[#ty;0],))),
346            ExprOrType::Usize => (
347                None,
348                Some(quote!(__aligner: [::abi_stable::pmr::usize; 0],)),
349            ),
350        };
351
352        let aligner_size = match this.size {
353            ExprOrType::Int(size) => quote!( #size ),
354            ExprOrType::Expr(expr) => quote!( (#expr) ),
355            ExprOrType::Type(ty) => quote!( ::std::mem::size_of::<#ty>() ),
356            ExprOrType::Usize => quote!(::std::mem::size_of::<::abi_stable::pmr::usize>()),
357        };
358
359        let name = ds.name;
360
361        let generics_header = GenParamsIn::new(ds.generics, InWhat::ImplHeader);
362
363        let mut type_generics_decl = GenParamsIn::new(ds.generics, InWhat::ImplHeader);
364        type_generics_decl.set_no_bounds();
365
366        let type_generics_use = GenParamsIn::new(ds.generics, InWhat::ItemUse);
367
368        let mut storage_docs = String::new();
369        let mut alias_docs = String::new();
370        let mut marker_docs = String::new();
371
372        if doc_hidden_attr.is_none() {
373            storage_docs = format!(
374                "The default InlineStorage that `NonExhaustive` uses for \
375                 [`{E}`](./enum.{E}.html).",
376                E = name
377            );
378            alias_docs = format!(
379                "An alias for `NonExhaustive` wrapping a [`{E}`](./enum.{E}.html).",
380                E = name
381            );
382            marker_docs = format!(
383                "A marker type which implements StableAbi with the layout of \
384                 [`{E}`](./enum.{E}.html),\
385                 used as a phantom field of NonExhaustive.",
386                E = name
387            );
388        }
389
390        let default_interface = &this.default_interface;
391
392        quote!(
393            #[doc=#storage_docs]
394            #[repr(C)]
395            #[derive(::abi_stable::StableAbi)]
396            #aligner_attribute
397            #vis struct #enum_storage{
398                #[sabi(unsafe_opaque_field)]
399                _filler:[u8; #aligner_size ],
400                #aligner_field
401            }
402
403            #[doc=#alias_docs]
404            #vis type #nonexhaustive_alias<#type_generics_decl>=
405                ::abi_stable::pmr::NonExhaustive<
406                    #name<#type_generics_use>,
407                    #enum_storage,
408                    #default_interface,
409                >;
410
411            unsafe impl ::abi_stable::pmr::InlineStorage for #enum_storage{}
412
413            #[doc=#marker_docs]
414            #vis struct #nonexhaustive_marker<T,S>(
415                std::marker::PhantomData<T>,
416                std::marker::PhantomData<S>,
417            );
418        )
419        .to_tokens(ts);
420
421        if let Some(BoundsTrait { ident, bounds }) = &this.bounds_trait {
422            let trait_docs = hide_docs_if(&doc_hidden_attr, || {
423                format!(
424                    "An alias for the traits that \
425                    `NonExhaustive<{E},_,_>` requires to be constructed,\
426                    and implements afterwards.",
427                    E = name
428                )
429            });
430
431            quote!(
432                #[doc=#trait_docs]
433                #vis trait #ident:#(#bounds+)*{}
434
435                impl<This> #ident for This
436                where
437                    This:#(#bounds+)*
438                {}
439            )
440            .to_tokens(ts);
441        }
442
443        if let Some(new_interface) = this.new_interface {
444            let interface_docs = hide_docs_if(&doc_hidden_attr, || {
445                format!(
446                    "Describes the traits required when constructing a \
447                     `NonExhaustive<>` from [`{E}`](./enum.{E}.html),\
448                     by implementing `InterfaceType`.",
449                    E = name
450                )
451            });
452
453            quote!(
454                #[doc=#interface_docs]
455                #[repr(C)]
456                #[derive(::abi_stable::StableAbi)]
457                #vis struct #new_interface;
458            )
459            .to_tokens(ts);
460        }
461
462        if this.ne_variants.iter().any(|x| x.constructor.is_some()) {
463            let constructors = this
464                .ne_variants
465                .iter()
466                .cloned()
467                .zip(&ds.variants)
468                .filter_map(|(vc, variant)| {
469                    let constructor = vc.constructor.as_ref()?;
470                    let variant_ident = variant.name;
471                    let mut method_name = parse_str_as_ident(&format!("{}_NE", variant.name));
472                    method_name.set_span(variant.name.span());
473
474                    let method_docs = if vc.is_hidden {
475                        quote!(#[doc(hidden)])
476                    } else {
477                        let v_doc = format!(
478                            "Constructs the `{}::{}` variant inside a `NonExhaustive`.",
479                            ds.name, variant.name,
480                        );
481                        quote!(#[doc= #v_doc])
482                    };
483
484                    match constructor {
485                        VariantConstructor::Regular => {
486                            let field_names_a = variant.fields.iter().map(|x| x.pat_ident());
487                            let field_names_b = field_names_a.clone();
488                            let field_names_c = variant.fields.iter().map(|x| &x.ident);
489                            let field_types = variant.fields.iter().map(|x| x.ty);
490                            quote! {
491                                #method_docs
492                                #vis fn #method_name(
493                                    #( #field_names_a : #field_types ,)*
494                                )->#nonexhaustive_alias<#type_generics_use> {
495                                    let x=#name::#variant_ident{
496                                        #( #field_names_c:#field_names_b, )*
497                                    };
498                                    #nonexhaustive_alias::new(x)
499                                }
500                            }
501                        }
502                        VariantConstructor::Boxed { referent, pointer } => {
503                            let ptr_field_ident = &variant.fields[0].ident;
504                            let type_param = ToTokenFnMut::new(|ts| match referent {
505                                Some(x) => x.to_tokens(ts),
506                                None => {
507                                    quote!( <#pointer as ::abi_stable::pmr::GetPointerKind>::PtrTarget )
508                                        .to_tokens(ts)
509                                }
510                            });
511
512                            quote! {
513                                #method_docs
514                                #vis fn #method_name(
515                                    value:#type_param,
516                                )->#nonexhaustive_alias<#type_generics_use> {
517                                    let x=<#pointer>::new(value);
518                                    let x=#name::#variant_ident{
519                                        #ptr_field_ident:x,
520                                    };
521                                    #nonexhaustive_alias::new(x)
522                                }
523                            }
524                        }
525                    }
526                    .piped(Some)
527                });
528
529            let preds = ds.generics.where_clause.as_ref().map(|w| &w.predicates);
530
531            let bound = match &this.bounds_trait {
532                Some(BoundsTrait { ident, .. }) => quote!(#ident),
533                None => quote!(
534                    ::abi_stable::pmr::NonExhaustiveMarkerVTable<
535                        #enum_storage,
536                        #default_interface,
537                    >
538                ),
539            };
540
541            quote!(
542                #[allow(non_snake_case)]
543                impl<#generics_header> #name<#type_generics_use>
544                where
545                    Self: #bound ,
546                    #preds
547                {
548                    #(#constructors)*
549                }
550            )
551            .to_tokens(ts);
552        }
553    })
554}
555
556/// Outputs the nonexhausitve-enum-related impl blocks,
557/// inside the module generated by StableAbi.
558pub(crate) fn tokenize_enum_info<'a>(
559    ds: &'a DataStructure<'a>,
560    variant_names_start_len: StartLen,
561    config: &'a StableAbiOptions<'a>,
562    ct: &'a CommonTokens<'a>,
563) -> Result<impl ToTokens + 'a, syn::Error> {
564    let opt_type_ident = config.repr.type_ident();
565    if let (StabilityKind::NonExhaustive { .. }, None) = (&config.kind, &opt_type_ident) {
566        return_spanned_err!(
567            ds.name,
568            "Attempted to get type of discriminant for this representation:\n\t{:?}",
569            config.repr
570        );
571    }
572
573    Ok(ToTokenFnMut::new(move |ts| {
574        let this = match &config.kind {
575            StabilityKind::NonExhaustive(x) => x,
576            _ => return,
577        };
578
579        let name = ds.name;
580        let name_str = rstr_tokenizer(ds.name.to_string());
581
582        let strings_const = &config.const_idents.strings;
583
584        let discriminants = ds
585            .variants
586            .iter()
587            .map(|x| x.discriminant)
588            .collect::<Vec<Option<&'a syn::Expr>>>();
589
590        let discriminant_tokens = config
591            .repr
592            .tokenize_discriminant_slice(discriminants.iter().cloned(), ct);
593
594        let discriminant_type = match &opt_type_ident {
595            Some(x) => x,
596            None => unreachable!(),
597        };
598
599        let vn_start = variant_names_start_len.start;
600        let vn_len = variant_names_start_len.len;
601
602        let nonexhaustive_marker = this.nonexhaustive_marker;
603        let enum_storage = this.enum_storage;
604
605        let mut start_discrs = Vec::new();
606        let mut end_discrs = Vec::new();
607        if !discriminants.is_empty() {
608            let mut first_index = 0;
609
610            for (mut i, discr) in discriminants[1..].iter().cloned().enumerate() {
611                i += 1;
612                if discr.is_some() {
613                    start_discrs.push(first_index);
614                    end_discrs.push(i - 1);
615                    first_index = i;
616                }
617            }
618
619            start_discrs.push(first_index);
620            end_discrs.push(discriminants.len() - 1);
621        }
622
623        let generics_header =
624            GenParamsIn::with_after_types(ds.generics, InWhat::ImplHeader, &ct.und_storage);
625
626        let generics_use = GenParamsIn::new(ds.generics, InWhat::ImplHeader);
627
628        let default_interface = &this.default_interface;
629
630        let (impl_generics, ty_generics, where_clause) = ds.generics.split_for_impl();
631
632        let preds = where_clause.as_ref().map(|w| &w.predicates);
633
634        quote!(
635
636            unsafe impl #impl_generics __sabi_re::GetStaticEquivalent_ for #name #ty_generics
637            where
638                #nonexhaustive_marker <Self,#enum_storage> :
639                    __sabi_re::GetStaticEquivalent_,
640                #preds
641            {
642                type StaticEquivalent=__sabi_re::GetStaticEquivalent<
643                    #nonexhaustive_marker <Self,#enum_storage>
644                >;
645            }
646
647            unsafe impl #impl_generics __sabi_re::GetEnumInfo for #name #ty_generics
648            #where_clause
649            {
650                type Discriminant=#discriminant_type;
651
652                type DefaultStorage=#enum_storage;
653
654                type DefaultInterface=#default_interface;
655
656                const ENUM_INFO:&'static __sabi_re::EnumInfo=
657                    &__sabi_re::EnumInfo::_for_derive(
658                        #name_str,
659                        #strings_const,
660                        ::abi_stable::type_layout::StartLen::new(#vn_start,#vn_len),
661                    );
662
663                const DISCRIMINANTS: &'static[#discriminant_type]=
664                    #discriminant_tokens;
665
666                fn is_valid_discriminant(discriminant:#discriminant_type)->bool{
667                    #(
668                        (
669                            <Self as __sabi_re::GetEnumInfo>::DISCRIMINANTS[#start_discrs]
670                            <= discriminant &&
671                            discriminant <=
672                            <Self as __sabi_re::GetEnumInfo>::DISCRIMINANTS[#end_discrs]
673                        )||
674                    )*
675                    false
676                }
677            }
678
679
680            unsafe impl<#generics_header>
681                __sabi_re::NonExhaustiveMarker<__Storage>
682            for #name <#generics_use>
683            #where_clause
684            {
685                type Marker = #nonexhaustive_marker<Self,__Storage>;
686            }
687
688
689        )
690        .to_tokens(ts);
691
692        let self_type: syn::Type;
693        let self_type_buf: Vec<&syn::Type>;
694        let assert_nonexh = if this.assert_nonexh.is_empty() && ds.generics.params.is_empty() {
695            let name = ds.name;
696            self_type = syn::parse_quote!(#name);
697            self_type_buf = vec![&self_type];
698            &self_type_buf
699        } else {
700            &this.assert_nonexh
701        };
702
703        if !assert_nonexh.is_empty() {
704            let assertions = assert_nonexh.iter().cloned();
705            let assertions_str = assert_nonexh
706                .iter()
707                .map(|x| x.to_token_stream().to_string());
708            let enum_storage_str = enum_storage.to_string();
709            quote!(
710                #(
711                    const _: () = ::abi_stable::pmr::assert_correct_storage::<#assertions, #enum_storage>(
712                        ::abi_stable::pmr::AssertCsArgs{
713                            enum_ty: #assertions_str,
714                            storage_ty: #enum_storage_str,
715                        }
716                    );
717                )*
718            )
719            .to_tokens(ts);
720        }
721
722        match &this.enum_interface {
723            Some(EnumInterface::New(NewEnumInterface { impld, unimpld })) => {
724                let enum_interface = parse_str_as_ident(&format!("{}_Interface", name));
725
726                let priv_assocty = private_associated_type();
727
728                let impld_a = impld.iter();
729                let impld_b = impld.iter();
730
731                let unimpld_a = unimpld.iter();
732                let unimpld_b = unimpld.iter();
733
734                let const_ident =
735                    parse_str_as_ident(&format!("_impl_InterfaceType_constant_{}", name,));
736
737                quote!(
738                    const #const_ident:()={
739                        use abi_stable::{
740                            InterfaceType,
741                            type_level::{
742                                impl_enum::{Implemented,Unimplemented},
743                                trait_marker,
744                            },
745                        };
746                        impl InterfaceType for #enum_interface {
747                            #( type #impld_a=Implemented<trait_marker::#impld_b>; )*
748                            #( type #unimpld_a=Unimplemented<trait_marker::#unimpld_b>; )*
749                            type #priv_assocty=();
750                        }
751                    };
752                )
753                .to_tokens(ts);
754            }
755            Some(EnumInterface::Old { .. }) => {}
756            None => {}
757        }
758    }))
759}