1use 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 #[default]
27 PreFilled,
28 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}