certain_map_macros/
lib.rs

1// Copyright 2024 ihciah. All Rights Reserved.
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::{quote, quote_spanned, ToTokens};
6use syn::{
7    parse, parse::Parse, punctuated::Punctuated, Attribute, Expr, ExprLit, Field, Ident,
8    ItemStruct, Lit, Meta, Result, Token, Type, Visibility,
9};
10
11#[proc_macro]
12pub fn certain_map(input: TokenStream) -> TokenStream {
13    let cmap: CMap = match parse(input) {
14        Ok(m) => m,
15        Err(e) => return TokenStream::from(e.to_compile_error()),
16    };
17
18    let output = cmap.to_token_stream();
19    TokenStream::from(output)
20}
21
22#[derive(Copy, Clone, Default)]
23enum GenStyle {
24    // PreFilled generates a struct with all fields, allows to pass `&mut Handler`
25    // to avoid stack copy when passing or setting fields.
26    #[default]
27    PreFilled,
28    // Unfilled generates a struct with empty fields, when passing or setting fields,,
29    // it has to copy all fields to a new typed struct.
30    // It is easier to use, but may have performance overhead.
31    // This is default style for certain-map 0.2.*.
32    Unfilled,
33}
34
35struct CMap {
36    attrs: Vec<Attribute>,
37    vis: Visibility,
38    ident: Ident,
39    fields: Vec<Field>,
40    fields_meta: Vec<Option<Punctuated<Meta, Token![,]>>>,
41
42    span: Span,
43    style: GenStyle,
44}
45
46impl Parse for CMap {
47    fn parse(input: syn::parse::ParseStream) -> Result<Self> {
48        let span = input.span();
49        let mut definition = ItemStruct::parse(input)?;
50
51        if definition.generics.where_clause.is_some() {
52            return Err(syn::Error::new(
53                span,
54                "generic where clause is not supported",
55            ));
56        }
57        if definition.generics.type_params().next().is_some() {
58            return Err(syn::Error::new(span, "generic types are not supported"));
59        }
60        if definition.generics.lifetimes().next().is_some() {
61            return Err(syn::Error::new(span, "generic lifetimes are not supported"));
62        }
63
64        // parse #[style = "unfilled"] and remove it.
65        let mut style = GenStyle::default();
66        let mut remove_idx = None;
67        for (idx, attr) in definition.attrs.iter().enumerate() {
68            if let Ok(name_val) = attr.meta.require_name_value() {
69                if name_val.path.is_ident("style")
70                    && matches!(&name_val.value, Expr::Lit(ExprLit{lit: Lit::Str(l), ..}) if l.value().eq_ignore_ascii_case("unfilled"))
71                {
72                    style = GenStyle::Unfilled;
73                    remove_idx = Some(idx);
74                    break;
75                }
76            }
77        }
78        if let Some(idx) = remove_idx {
79            definition.attrs.remove(idx);
80        }
81
82        let fields: Vec<Field> = definition.fields.into_iter().collect();
83        if fields.iter().any(|f| f.ident.is_none()) {
84            return Err(syn::Error::new(
85                span,
86                "fields without names are not supported",
87            ));
88        }
89
90        let mut fields_meta = Vec::with_capacity(fields.len());
91        for field in fields.iter() {
92            let maybe_meta = if let Some(attr) = field.attrs.first() {
93                if !attr.path().is_ident("ensure") {
94                    return Err(syn::Error::new(
95                        span,
96                        "fields attr now only support #[ensure(Clone)]",
97                    ));
98                }
99                let nested =
100                    attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
101                if nested
102                    .iter()
103                    .any(|meta| !matches!(meta, Meta::Path(path) if path.is_ident("Clone")))
104                {
105                    return Err(syn::Error::new(
106                        span,
107                        "fields attr now only support #[ensure(Clone)]",
108                    ));
109                }
110                Some(nested)
111            } else {
112                None
113            };
114            fields_meta.push(maybe_meta);
115        }
116
117        Ok(CMap {
118            attrs: definition.attrs,
119            vis: definition.vis,
120            ident: definition.ident,
121            fields,
122            fields_meta,
123            span,
124            style,
125        })
126    }
127}
128
129impl CMap {
130    fn to_pre_filled_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
131        let mut derive_clone = false;
132        if let Some(derive) = Self::find_path_attr(&self.attrs, "derive") {
133            if derive.1 == "Clone" {
134                derive_clone = true;
135            }
136        }
137
138        let vis = &self.vis;
139        let ident = &self.ident;
140        let state_ident = quote::format_ident!("{ident}State");
141        let handler_ident = quote::format_ident!("{ident}Handler");
142        let generic_types: Vec<_> = (0..self.fields.len())
143            .map(generic_type)
144            .map(IdentOrTokens::from)
145            .collect();
146        let names: Vec<_> = self
147            .fields
148            .iter()
149            .map(|f| f.ident.as_ref().unwrap())
150            .collect();
151        let types: Vec<_> = self.fields.iter().map(|f| &f.ty).collect();
152
153        // struct definition
154        tokens.extend(quote_spanned! {
155            self.span =>
156                #vis struct #ident {
157                    #(#names: ::std::mem::MaybeUninit<#types>,)*
158                }
159                #[allow(non_camel_case_types)]
160                #vis struct #state_ident<#(#generic_types),*>
161                where
162                    #(#generic_types: ::certain_map::MaybeAvailable,)*
163                {
164                    #(#names: ::std::marker::PhantomData<#generic_types>,)*
165                }
166                #[allow(non_camel_case_types)]
167                #[repr(transparent)]
168                #vis struct #handler_ident<'a, #(#generic_types),*>
169                where
170                    #(#generic_types: ::certain_map::MaybeAvailable,)*
171                {
172                    inner: &'a mut #ident,
173                    state: #state_ident<#(#generic_types),*>,
174                }
175        });
176
177        // type alias
178        if let Some((_, empty_ident)) = Self::find_path_attr(&self.attrs, "empty") {
179            let vacancy_types =
180                std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
181            tokens.extend(quote_spanned! {
182                self.span =>
183                    #vis type #empty_ident<'a> = #handler_ident<'a, #(#vacancy_types),*>;
184            });
185        }
186
187        if let Some((_, full_ident)) = Self::find_path_attr(&self.attrs, "full") {
188            let occupied_types =
189                std::iter::repeat(quote!(::certain_map::OccupiedM)).take(self.fields.len());
190            tokens.extend(quote_spanned! {
191                self.span =>
192                    #vis type #full_ident<'a> = #handler_ident<'a, #(#occupied_types),*>;
193            });
194        }
195
196        let clone_with = if derive_clone {
197            quote_spanned! {
198                self.span =>
199                    #[allow(non_camel_case_types)]
200                    unsafe fn clone_with<#(#generic_types),*>(&self, _state: &#state_ident<#(#generic_types),*>) -> Self
201                    where
202                        #(#generic_types: ::certain_map::MaybeAvailable,)*
203                    {
204                        Self {
205                            #(#names: #generic_types::do_clone(&self.#names),)*
206                        }
207                    }
208            }
209        } else {
210            quote!()
211        };
212
213        // impl #ident
214        let vacancy_types =
215            std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
216        let vacancy_types2 =
217            std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
218        tokens.extend(quote_spanned! {
219            self.span =>
220                impl #ident {
221                    #[inline]
222                    pub const fn new() -> Self {
223                        Self {
224                            #(#names: ::std::mem::MaybeUninit::uninit(),)*
225                        }
226                    }
227                    #[inline]
228                    pub fn handler(&mut self) -> #handler_ident<'_, #(#vacancy_types),*> {
229                        #handler_ident {
230                            inner: self,
231                            state: #state_ident::new(),
232                        }
233                    }
234                    #clone_with
235                }
236                impl ::certain_map::Handler for #ident {
237                    type Hdr<'a> = #handler_ident<'a, #(#vacancy_types2),*>
238                    where
239                        Self: 'a;
240                    #[inline]
241                    fn handler(&mut self) -> Self::Hdr<'_> {
242                        self.handler()
243                    }
244                }
245                impl ::std::default::Default for #ident {
246                    #[inline]
247                    fn default() -> Self {
248                        Self::new()
249                    }
250                }
251        });
252
253        // impl #state_ident
254        tokens.extend(quote_spanned! {
255            self.span =>
256                #[allow(non_camel_case_types)]
257                impl<#(#generic_types),*> #state_ident<#(#generic_types),*>
258                where
259                    #(#generic_types: ::certain_map::MaybeAvailable,)*
260                {
261                    const fn new() -> Self {
262                        Self {
263                            #(#names: ::std::marker::PhantomData,)*
264                        }
265                    }
266                    /// # Safety
267                    /// The caller must make sure the attached map has the data of current state.
268                    #[inline]
269                    pub unsafe fn attach(self, inner: &mut #ident) -> #handler_ident<'_, #(#generic_types),*> {
270                        #handler_ident {
271                            inner,
272                            state: Self::new(),
273                        }
274                    }
275                }
276                #[allow(non_camel_case_types)]
277                impl<#(#generic_types),*> ::certain_map::Attach<#ident> for #state_ident<#(#generic_types),*>
278                where
279                    #(#generic_types: ::certain_map::MaybeAvailable,)*
280                {
281                    type Hdr<'a> = #handler_ident<'a, #(#generic_types),*>;
282                    #[inline]
283                    unsafe fn attach(self, store: &mut #ident) -> Self::Hdr<'_> {
284                        self.attach(store)
285                    }
286                }
287        });
288
289        if derive_clone {
290            // impl #handler_ident
291            tokens.extend(quote_spanned! {
292                self.span =>
293                    #[allow(non_camel_case_types)]
294                    impl<#(#generic_types),*> #handler_ident<'_, #(#generic_types),*>
295                    where
296                        #(#generic_types: ::certain_map::MaybeAvailable,)*
297                    {
298                        #[inline]
299                        pub fn fork(&self) -> (#ident, #state_ident<#(#generic_types),*>) {
300                            // Safety: we are sure about the state of the map.
301                            let inner = unsafe { self.inner.clone_with(&self.state) };
302                            (inner, #state_ident::new())
303                        }
304                    }
305                    #[allow(non_camel_case_types)]
306                    impl<#(#generic_types),*> ::certain_map::Fork for #handler_ident<'_, #(#generic_types),*>
307                    where
308                        #(#generic_types: ::certain_map::MaybeAvailable,)*
309                    {
310                        type Store = #ident;
311                        type State = #state_ident<#(#generic_types),*>;
312                        #[inline]
313                        fn fork(&self) -> (Self::Store, Self::State) {
314                            self.fork()
315                        }
316                    }
317            });
318        }
319
320        // impl Drop for #handler_ident
321        tokens.extend(quote_spanned! {
322            self.span =>
323                #[allow(non_camel_case_types)]
324                impl<#(#generic_types),*> Drop for #handler_ident<'_, #(#generic_types),*>
325                where
326                    #(#generic_types: ::certain_map::MaybeAvailable,)*
327                {
328                    fn drop(&mut self) {
329                        unsafe {
330                            #(#generic_types::do_drop(&mut self.inner.#names);)*
331                        }
332                    }
333                }
334        });
335
336        // impl ParamRef<T>/ParamMut<T>/ParamTake<T> for #handler_ident
337        for (idx, field) in self.fields.iter().enumerate() {
338            let ty = &field.ty;
339            let name = field.ident.as_ref().unwrap();
340            let generic_type = generic_type(idx);
341            let generic_types_rest1 = IgnoreIter::new(generic_types.iter(), idx);
342            let generic_types_rest2 = IgnoreIter::new(generic_types.iter(), idx);
343            let generic_types_rest3 = IgnoreIter::new(generic_types.iter(), idx);
344            let vacancy = IdentOrTokens::from(vacancy_type());
345            let generic_types_replaced_vacancy =
346                ReplaceIter::new(generic_types.iter(), idx, &vacancy);
347            tokens.extend(quote_spanned! {
348                self.span =>
349                    #[allow(non_camel_case_types)]
350                    impl<#(#generic_types),*> ::certain_map::ParamRef<#ty> for #handler_ident<'_, #(#generic_types),*>
351                    where
352                        #generic_type: ::certain_map::Available,
353                        #(#generic_types_rest1: ::certain_map::MaybeAvailable,)*
354                    {
355                        #[inline]
356                        fn param_ref(&self) -> &#ty {
357                            unsafe { #generic_type::do_ref(&self.inner.#name) }
358                        }
359                    }
360                    #[allow(non_camel_case_types)]
361                    impl<#(#generic_types),*> ::certain_map::ParamMut<#ty> for #handler_ident<'_, #(#generic_types),*>
362                    where
363                        #generic_type: ::certain_map::Available,
364                        #(#generic_types_rest2: ::certain_map::MaybeAvailable,)*
365                    {
366                        #[inline]
367                        fn param_mut(&mut self) -> &mut #ty {
368                            unsafe { #generic_type::do_mut(&mut self.inner.#name) }
369                        }
370                    }
371                    #[allow(non_camel_case_types)]
372                    impl<'a, #(#generic_types),*> ::certain_map::ParamTake<#ty> for #handler_ident<'a, #(#generic_types),*>
373                    where
374                        #generic_type: ::certain_map::Available,
375                        #(#generic_types_rest3: ::certain_map::MaybeAvailable,)*
376                    {
377                        type Transformed = #handler_ident<'a, #(#generic_types_replaced_vacancy),*>;
378                        #[inline]
379                        fn param_take(self) -> (Self::Transformed, #ty) {
380                            let item = unsafe { #generic_type::do_take(&self.inner.#name) };
381                            #[allow(clippy::missing_transmute_annotations)]
382                            (unsafe { ::std::mem::transmute(self) }, item)
383                        }
384                    }
385            });
386        }
387
388        // impl ParamMaybeRef<T>/ParamMaybeMut<T>/ParamSet<T>/ParamRemove<T> for #handler_ident
389        for (idx, field) in self.fields.iter().enumerate() {
390            let ty = &field.ty;
391            let name = field.ident.as_ref().unwrap();
392            let generic_type = generic_type(idx);
393
394            let occupied = IdentOrTokens::from(occupied_m_type());
395            let generic_types_replaced_occupied =
396                ReplaceIter::new(generic_types.iter(), idx, &occupied);
397            let vacancy = IdentOrTokens::from(vacancy_type());
398            let generic_types_replaced_vacancy =
399                ReplaceIter::new(generic_types.iter(), idx, &vacancy);
400            tokens.extend(quote_spanned! {
401                self.span =>
402                    #[allow(non_camel_case_types)]
403                    impl<#(#generic_types),*> ::certain_map::ParamMaybeRef<#ty> for #handler_ident<'_, #(#generic_types),*>
404                    where
405                        #(#generic_types: ::certain_map::MaybeAvailable,)*
406                    {
407                        #[inline]
408                        fn param_maybe_ref(&self) -> Option<&#ty> {
409                            unsafe { #generic_type::do_maybe_ref(&self.inner.#name) }
410                        }
411                    }
412                    #[allow(non_camel_case_types)]
413                    impl<#(#generic_types),*> ::certain_map::ParamMaybeMut<#ty> for #handler_ident<'_, #(#generic_types),*>
414                    where
415                        #(#generic_types: ::certain_map::MaybeAvailable,)*
416                    {
417                        #[inline]
418                        fn param_maybe_mut(&mut self) -> Option<&mut #ty> {
419                            unsafe { #generic_type::do_maybe_mut(&mut self.inner.#name) }
420                        }
421                    }
422                    #[allow(non_camel_case_types)]
423                    impl<'a, #(#generic_types),*> ::certain_map::ParamSet<#ty> for #handler_ident<'a, #(#generic_types),*>
424                    where
425                        #(#generic_types: ::certain_map::MaybeAvailable,)*
426                    {
427                        type Transformed = #handler_ident<'a, #(#generic_types_replaced_occupied),*>;
428                        #[inline]
429                        fn param_set(self, item: #ty) -> Self::Transformed {
430                            unsafe {
431                                #generic_type::do_set(&mut self.inner.#name, item);
432                                #[allow(clippy::missing_transmute_annotations)]
433                                ::std::mem::transmute(self)
434                            }
435                        }
436                    }
437                    #[allow(non_camel_case_types)]
438                    impl<'a, #(#generic_types),*> ::certain_map::ParamRemove<#ty> for #handler_ident<'a, #(#generic_types),*>
439                    where
440                        #(#generic_types: ::certain_map::MaybeAvailable,)*
441                    {
442                        type Transformed = #handler_ident<'a, #(#generic_types_replaced_vacancy),*>;
443                        #[inline]
444                        fn param_remove(self) -> Self::Transformed {
445                            unsafe {
446                                #generic_type::do_drop(&mut self.inner.#name);
447                                #[allow(clippy::missing_transmute_annotations)]
448                                ::std::mem::transmute(self)
449                            }
450                        }
451                    }
452            });
453        }
454
455        // impl Param<T> and Param<Option<T>> if #[ensure(Clone)] or derive_clone
456        for (idx, (field, maybe_meta)) in
457            self.fields.iter().zip(self.fields_meta.iter()).enumerate()
458        {
459            if derive_clone
460                || maybe_meta
461                    .iter()
462                    .flat_map(|x| x.iter())
463                    .any(|meta| matches!(meta, Meta::Path(path) if path.is_ident("Clone")))
464            {
465                let ty = &field.ty;
466                let name = field.ident.as_ref().unwrap();
467                let generic_type = generic_type(idx);
468                let generic_types_rest = IgnoreIter::new(generic_types.iter(), idx);
469                tokens.extend(quote_spanned! {
470                    self.span =>
471                        #[allow(non_camel_case_types)]
472                        impl<#(#generic_types),*> ::certain_map::Param<#ty> for #handler_ident<'_, #(#generic_types),*>
473                        where
474                            #generic_type: ::certain_map::Available,
475                            #(#generic_types_rest: ::certain_map::MaybeAvailable,)*
476                        {
477                            #[inline]
478                            fn param(&self) -> #ty {
479                                unsafe { #generic_type::do_read(&self.inner.#name) }
480                            }
481                        }
482                        #[allow(non_camel_case_types)]
483                        impl<#(#generic_types),*> ::certain_map::Param<Option<#ty>> for #handler_ident<'_, #(#generic_types),*>
484                        where
485                            #(#generic_types: ::certain_map::MaybeAvailable,)*
486                        {
487                            #[inline]
488                            fn param(&self) -> Option<#ty> {
489                                #[allow(clippy::clone_on_copy)]
490                                unsafe { #generic_type::do_maybe_ref(&self.inner.#name).cloned() }
491                            }
492                        }
493                });
494            }
495        }
496    }
497
498    fn to_unfilled_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
499        let mut attrs = self.attrs.clone();
500        let vis = &self.vis;
501        let ident = &self.ident;
502        let generic_types: Vec<_> = (0..self.fields.len())
503            .map(generic_type)
504            .map(IdentOrTokens::from)
505            .collect();
506        let names: Vec<_> = self
507            .fields
508            .iter()
509            .map(|f| f.ident.as_ref().unwrap())
510            .collect();
511
512        // struct definition
513        if let Some((empty_idx, empty_ident)) = Self::find_path_attr(&attrs, "empty") {
514            attrs.remove(empty_idx);
515            let vacancy_types =
516                std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
517            tokens.extend(quote_spanned! {
518                self.span =>
519                    #vis type #empty_ident = #ident<#(#vacancy_types),*>;
520            });
521        }
522
523        if let Some((full_idx, full_ident)) = Self::find_path_attr(&attrs, "full") {
524            attrs.remove(full_idx);
525            let occupied_types = self.fields.iter().map(|f| occupied_type(&f.ty));
526            tokens.extend(quote_spanned! {
527                self.span =>
528                    #vis type #full_ident = #ident<#(#occupied_types),*>;
529            });
530        }
531
532        tokens.extend(quote_spanned! {
533            self.span =>
534                #(#attrs)*
535                #vis struct #ident<#(#generic_types),*> {
536                    #(#names: #generic_types, )*
537                }
538        });
539
540        // impl new and Default
541        let vacancy_types1 =
542            std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
543        let vacancy_types2 =
544            std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
545        let vacancy_values =
546            std::iter::repeat(quote!(::certain_map::Vacancy)).take(self.fields.len());
547        tokens.extend(quote_spanned! {
548            self.span =>
549                impl ::std::default::Default for #ident<#(#vacancy_types1),*> {
550                    #[inline]
551                    fn default() -> Self {
552                        Self::new()
553                    }
554                }
555                impl #ident<#(#vacancy_types2),*> {
556                    pub const fn new() -> Self {
557                        Self {
558                            #(#names: #vacancy_values),*
559                        }
560                    }
561                }
562        });
563
564        // impl ParamRef<T>
565        for (idx, field) in self.fields.iter().enumerate() {
566            let ty = &field.ty;
567            let name = field.ident.as_ref().unwrap();
568            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
569            let occupied = IdentOrTokens::from(occupied_type(ty));
570            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &occupied);
571            tokens.extend(quote_spanned! {
572                self.span =>
573                    impl<#(#generic_types_ignored),*> ::certain_map::ParamRef<#ty> for #ident<#(#generic_types_replaced),*> {
574                        #[inline]
575                        fn param_ref(&self) -> &#ty {
576                            &self.#name.0
577                        }
578                    }
579            });
580        }
581
582        // impl ParamMaybeRef<T> for occupied
583        for (idx, field) in self.fields.iter().enumerate() {
584            let ty = &field.ty;
585            let name = field.ident.as_ref().unwrap();
586            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
587            let occupied = IdentOrTokens::from(occupied_type(ty));
588            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &occupied);
589            tokens.extend(quote_spanned! {
590                self.span =>
591                    impl<#(#generic_types_ignored),*> ::certain_map::ParamMaybeRef<#ty> for #ident<#(#generic_types_replaced),*> {
592                        #[inline]
593                        fn param_maybe_ref(&self) -> Option<&#ty> {
594                            Some(&self.#name.0)
595                        }
596                    }
597            });
598        }
599
600        // impl ParamMaybeRef<T> for vacancy
601        for (idx, field) in self.fields.iter().enumerate() {
602            let ty = &field.ty;
603            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
604            let vacancy = IdentOrTokens::from(vacancy_type());
605            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &vacancy);
606            tokens.extend(quote_spanned! {
607                self.span =>
608                    impl<#(#generic_types_ignored),*> ::certain_map::ParamMaybeRef<#ty> for #ident<#(#generic_types_replaced),*> {
609                        #[inline]
610                        fn param_maybe_ref(&self) -> Option<&#ty> {
611                            None
612                        }
613                    }
614            });
615        }
616
617        // impl ParamMut
618        for (idx, field) in self.fields.iter().enumerate() {
619            let ty = &field.ty;
620            let name = field.ident.as_ref().unwrap();
621            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
622            let occupied = IdentOrTokens::from(occupied_type(ty));
623            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &occupied);
624            tokens.extend(quote_spanned! {
625                self.span =>
626                    impl<#(#generic_types_ignored),*> ::certain_map::ParamMut<#ty> for #ident<#(#generic_types_replaced),*> {
627                        #[inline]
628                        fn param_mut(&mut self) -> &mut #ty {
629                            &mut self.#name.0
630                        }
631                    }
632            });
633        }
634
635        // impl ParamMaybeMut<T> for occupied
636        for (idx, field) in self.fields.iter().enumerate() {
637            let ty = &field.ty;
638            let name = field.ident.as_ref().unwrap();
639            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
640            let occupied = IdentOrTokens::from(occupied_type(ty));
641            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &occupied);
642            tokens.extend(quote_spanned! {
643                self.span =>
644                    impl<#(#generic_types_ignored),*> ::certain_map::ParamMaybeMut<#ty> for #ident<#(#generic_types_replaced),*> {
645                        #[inline]
646                        fn param_maybe_mut(&mut self) -> Option<&mut #ty> {
647                            Some(&mut self.#name.0)
648                        }
649                    }
650            });
651        }
652
653        // impl ParamMaybeMut<T> for vacancy
654        for (idx, field) in self.fields.iter().enumerate() {
655            let ty = &field.ty;
656            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
657            let vacancy = IdentOrTokens::from(vacancy_type());
658            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &vacancy);
659            tokens.extend(quote_spanned! {
660                self.span =>
661                    impl<#(#generic_types_ignored),*> ::certain_map::ParamMaybeMut<#ty> for #ident<#(#generic_types_replaced),*> {
662                        #[inline]
663                        fn param_maybe_mut(&mut self) -> Option<&mut #ty> {
664                            None
665                        }
666                    }
667            });
668        }
669
670        // impl Param<T> and Param<Option<T>> if #[ensure(Clone)]
671        for (idx, (field, maybe_meta)) in
672            self.fields.iter().zip(self.fields_meta.iter()).enumerate()
673        {
674            if maybe_meta
675                .iter()
676                .flat_map(|x| x.iter())
677                .any(|meta| matches!(meta, Meta::Path(path) if path.is_ident("Clone")))
678            {
679                let ty = &field.ty;
680                let name = field.ident.as_ref().unwrap();
681                let occupied = IdentOrTokens::from(occupied_type(ty));
682                let vacancy = IdentOrTokens::from(vacancy_type());
683
684                let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
685                let generic_types_occupied = ReplaceIter::new(generic_types.iter(), idx, &occupied);
686
687                let generic_types_ignored2 = IgnoreIter::new(generic_types.iter(), idx);
688                let generic_types_occupied2 =
689                    ReplaceIter::new(generic_types.iter(), idx, &occupied);
690
691                let generic_types_ignored3 = IgnoreIter::new(generic_types.iter(), idx);
692                let generic_types_vacancy = ReplaceIter::new(generic_types.iter(), idx, &vacancy);
693                tokens.extend(quote_spanned! {
694                self.span =>
695                    impl<#(#generic_types_ignored),*> ::certain_map::Param<#ty> for #ident<#(#generic_types_occupied),*> {
696                        #[inline]
697                        fn param(&self) -> #ty {
698                            #[allow(clippy::clone_on_copy)]
699                            self.#name.0.clone()
700                        }
701                    }
702                    impl<#(#generic_types_ignored2),*> ::certain_map::Param<Option<#ty>> for #ident<#(#generic_types_occupied2),*> {
703                        #[inline]
704                        fn param(&self) -> Option<#ty> {
705                            #[allow(clippy::clone_on_copy)]
706                            Some(self.#name.0.clone())
707                        }
708                    }
709                    impl<#(#generic_types_ignored3),*> ::certain_map::Param<Option<#ty>> for #ident<#(#generic_types_vacancy),*> {
710                        #[inline]
711                        fn param(&self) -> Option<#ty> {
712                            None
713                        }
714                    }
715                });
716            }
717        }
718
719        // impl ParamSet
720        for (idx, field) in self.fields.iter().enumerate() {
721            let ty = &field.ty;
722            let name = field.ident.as_ref().unwrap();
723            let occupied = IdentOrTokens::from(occupied_type(ty));
724            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &occupied);
725            let direct_assign = quote!(#name: ::certain_map::Occupied(item));
726            let assignations = ReplaceIter::new(
727                names.iter().map(|&name| quote!(#name: self.#name)),
728                idx,
729                direct_assign,
730            );
731            tokens.extend(quote_spanned! {
732                self.span =>
733                impl<#(#generic_types),*> ::certain_map::ParamSet<#ty> for #ident<#(#generic_types),*> {
734                    type Transformed = #ident<#(#generic_types_replaced),*>;
735
736                    #[inline]
737                    fn param_set(self, item: #ty) -> Self::Transformed {
738                        #ident {
739                            #(#assignations),*
740                        }
741                    }
742                }
743            });
744        }
745
746        // impl ParamRemove
747        for (idx, field) in self.fields.iter().enumerate() {
748            let ty = &field.ty;
749            let name = field.ident.as_ref().unwrap();
750            let vacancy = IdentOrTokens::from(vacancy_type());
751            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &vacancy);
752            let direct_assign = quote!(#name: ::certain_map::Vacancy);
753            let assignations = ReplaceIter::new(
754                names.iter().map(|&name| quote!(#name: self.#name)),
755                idx,
756                direct_assign,
757            );
758            tokens.extend(quote_spanned! {
759                self.span =>
760                impl<#(#generic_types),*> ::certain_map::ParamRemove<#ty> for #ident<#(#generic_types),*> {
761                    type Transformed = #ident<#(#generic_types_replaced),*>;
762
763                    #[inline]
764                    fn param_remove(self) -> Self::Transformed {
765                        #ident {
766                            #(#assignations),*
767                        }
768                    }
769                }
770            });
771        }
772
773        // impl ParamTake
774        for (idx, field) in self.fields.iter().enumerate() {
775            let ty = &field.ty;
776            let name = field.ident.as_ref().unwrap();
777            let generic_types_ignored = IgnoreIter::new(generic_types.iter(), idx);
778            let occupied = IdentOrTokens::from(occupied_type(ty));
779            let generic_types_replaced = ReplaceIter::new(generic_types.iter(), idx, &occupied);
780
781            let vacancy = IdentOrTokens::from(vacancy_type());
782            let generic_types_replaced_transformed =
783                ReplaceIter::new(generic_types.iter(), idx, &vacancy);
784            let direct_assign = quote!(#name: ::certain_map::Vacancy);
785            let assignations = ReplaceIter::new(
786                names.iter().map(|&name| quote!(#name: self.#name)),
787                idx,
788                direct_assign,
789            );
790            let removed_name = names[idx];
791            let removed = quote!(self.#removed_name);
792            tokens.extend(quote_spanned! {
793                self.span =>
794                impl<#(#generic_types_ignored),*> ::certain_map::ParamTake<#ty> for #ident<#(#generic_types_replaced),*> {
795                    type Transformed = #ident<#(#generic_types_replaced_transformed),*>;
796
797                    #[inline]
798                    fn param_take(self) -> (Self::Transformed, #ty) {
799                        let after_remove = #ident {
800                            #(#assignations),*
801                        };
802                        (after_remove, #removed.0)
803                    }
804                }
805            });
806        }
807    }
808
809    fn find_path_attr(attrs: &[Attribute], ident: &str) -> Option<(usize, Ident)> {
810        let mut default = None;
811        for (idx, attr) in attrs.iter().enumerate() {
812            if !attr.path().is_ident(ident) {
813                continue;
814            }
815            if let Ok(Meta::Path(path)) = attr.parse_args::<Meta>() {
816                if let Some(path) = path.get_ident() {
817                    default = Some((idx, path.clone()));
818                    break;
819                }
820            }
821        }
822        default
823    }
824}
825
826impl ToTokens for CMap {
827    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
828        match self.style {
829            GenStyle::PreFilled => self.to_pre_filled_tokens(tokens),
830            GenStyle::Unfilled => self.to_unfilled_tokens(tokens),
831        }
832    }
833}
834
835fn generic_type(num: usize) -> Ident {
836    quote::format_ident!("_CMT_{num}")
837}
838
839fn occupied_type(ty: &Type) -> proc_macro2::TokenStream {
840    quote! {::certain_map::Occupied<#ty>}
841}
842
843fn occupied_m_type() -> proc_macro2::TokenStream {
844    quote! {::certain_map::OccupiedM}
845}
846
847fn vacancy_type() -> proc_macro2::TokenStream {
848    quote! {::certain_map::Vacancy}
849}
850
851enum IdentOrTokens {
852    Ident(Ident),
853    Tokens(proc_macro2::TokenStream),
854}
855
856impl From<Ident> for IdentOrTokens {
857    fn from(value: Ident) -> Self {
858        Self::Ident(value)
859    }
860}
861
862impl From<proc_macro2::TokenStream> for IdentOrTokens {
863    fn from(value: proc_macro2::TokenStream) -> Self {
864        Self::Tokens(value)
865    }
866}
867
868impl ToTokens for IdentOrTokens {
869    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
870        match self {
871            IdentOrTokens::Ident(inner) => inner.to_tokens(tokens),
872            IdentOrTokens::Tokens(inner) => inner.to_tokens(tokens),
873        }
874    }
875}
876
877struct IgnoreIter<I> {
878    inner: I,
879    ignore: Option<usize>,
880}
881
882impl<I> IgnoreIter<I> {
883    fn new(iter: I, idx: usize) -> Self {
884        Self {
885            inner: iter,
886            ignore: Some(idx),
887        }
888    }
889}
890
891impl<I, Item> Iterator for IgnoreIter<I>
892where
893    I: Iterator<Item = Item>,
894{
895    type Item = Item;
896
897    fn next(&mut self) -> Option<Self::Item> {
898        match self.ignore.as_mut() {
899            None => self.inner.next(),
900            Some(i) if *i == 0 => {
901                self.ignore = None;
902                let _ = self.inner.next();
903                self.inner.next()
904            }
905            Some(i) => {
906                *i -= 1;
907                self.inner.next()
908            }
909        }
910    }
911}
912
913struct ReplaceIter<I, Item> {
914    inner: I,
915    replace: Option<(usize, Item)>,
916}
917
918impl<I, Item> ReplaceIter<I, Item> {
919    fn new(iter: I, idx: usize, item: Item) -> Self {
920        Self {
921            inner: iter,
922            replace: Some((idx, item)),
923        }
924    }
925}
926
927impl<I, Item> Iterator for ReplaceIter<I, Item>
928where
929    I: Iterator<Item = Item>,
930{
931    type Item = Item;
932
933    fn next(&mut self) -> Option<Self::Item> {
934        match self.replace.as_mut() {
935            None => self.inner.next(),
936            Some((i, _)) if *i == 0 => {
937                let item = unsafe { self.replace.take().unwrap_unchecked().1 };
938                let _ = self.inner.next();
939                Some(item)
940            }
941            Some((i, _)) => {
942                *i -= 1;
943                self.inner.next()
944            }
945        }
946    }
947}