o2o_impl/
expand.rs

1use std::{collections::HashMap, iter::Peekable, slice::Iter};
2
3use crate::{
4    ast::{DataType, DataTypeMember, Enum, Field, Struct, Variant},
5    attr::{ApplicableAttr, ChildParentData, ChildPath, DataTypeAttrs, GhostData, GhostIdent, Kind, MemberAttrCore, ParentChildField, TraitAttrCore, TypeHint},
6    validate::validate,
7};
8use proc_macro2::{Span, TokenStream};
9use quote::{format_ident, quote, ToTokens};
10
11#[cfg(feature = "syn2")]
12use syn2 as syn;
13
14use syn::{
15    parse_quote, Data, DeriveInput, Error, GenericArgument, GenericParam, Index, Lifetime,
16    Member::{self, Named, Unnamed}, Result
17};
18
19pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
20    match &node.data {
21        Data::Struct(data) => {
22            let input = Struct::from_syn(node, data)?;
23            let input = DataType::Struct(&input);
24            validate(&input)?;
25            Ok(data_type_impl(input))
26        },
27        Data::Enum(data) => {
28            let input = Enum::from_syn(node, data)?;
29            let input = DataType::Enum(&input);
30            validate(&input)?;
31            Ok(data_type_impl(input))
32        },
33        _ => Err(Error::new_spanned(node, "#[derive(o2o)] only supports structs and enums.")),
34    }
35}
36
37#[derive(Clone, Copy, PartialEq)]
38enum ImplType {
39    Struct,
40    Enum,
41    Variant,
42}
43
44impl ImplType {
45    fn is_variant(self) -> bool {
46        self == ImplType::Variant
47    }
48}
49
50struct ImplContext<'a> {
51    input: &'a DataType<'a>,
52    impl_type: ImplType,
53    struct_attr: &'a TraitAttrCore,
54    kind: Kind,
55    dst_ty: &'a TokenStream,
56    src_ty: &'a TokenStream,
57    has_post_init: bool,
58    fallible: bool,
59}
60
61struct ChildRenderContext<'a> {
62    pub ty: &'a syn::Path,
63    pub type_hint: TypeHint
64}
65
66impl<'a> From<&'a ChildParentData> for ChildRenderContext<'a> {
67    fn from(value: &'a ChildParentData) -> Self {
68        ChildRenderContext { ty: &value.ty, type_hint: value.type_hint }
69    }
70}
71
72struct FieldContainer<'a> {
73    gr_idx: usize,
74    path: String,
75    field_data: FieldData<'a>
76}
77
78enum FieldData<'a> {
79    Field(&'a Field),
80    GhostData(&'a GhostData),
81    ParentChildField(&'a Field, &'a ParentChildField),
82}
83
84enum VariantData<'a> {
85    Variant(&'a Variant),
86    GhostData(&'a GhostData),
87}
88
89fn data_type_impl(input: DataType) -> TokenStream {
90    let ty = input.get_ident().to_token_stream();
91    let attrs = input.get_attrs();
92
93    let impl_type = match input {
94        DataType::Struct(_) => ImplType::Struct,
95        DataType::Enum(_) => ImplType::Enum,
96    };
97
98    let impls = std::iter::empty().chain(attrs.iter_for_kind_core(&Kind::FromOwned, false).map(|struct_attr| ImplContext {
99        input: &input, impl_type, struct_attr,
100        kind: Kind::FromOwned,
101        dst_ty: &ty,
102        src_ty: &struct_attr.ty.path,
103        has_post_init: false,
104        fallible: false,
105    })).chain(attrs.iter_for_kind_core(&Kind::FromOwned, true).map(|struct_attr| ImplContext {
106        input: &input, impl_type, struct_attr,
107        kind: Kind::FromOwned,
108        dst_ty: &ty,
109        src_ty: &struct_attr.ty.path,
110        has_post_init: false,
111        fallible: true,
112    })).chain(attrs.iter_for_kind_core(&Kind::FromRef, false).map(|struct_attr| ImplContext {
113        input: &input, impl_type, struct_attr,
114        kind: Kind::FromRef,
115        dst_ty: &ty,
116        src_ty: &struct_attr.ty.path,
117        has_post_init: false,
118        fallible: false,
119    })).chain(attrs.iter_for_kind_core(&Kind::FromRef, true).map(|struct_attr| ImplContext {
120        input: &input, impl_type, struct_attr,
121        kind: Kind::FromRef,
122        dst_ty: &ty,
123        src_ty: &struct_attr.ty.path,
124        has_post_init: false,
125        fallible: true,
126    })).chain(attrs.iter_for_kind_core(&Kind::OwnedInto, false).map(|struct_attr| ImplContext {
127        input: &input, impl_type, struct_attr,
128        kind: Kind::OwnedInto,
129        dst_ty: &struct_attr.ty.path,
130        src_ty: &ty,
131        has_post_init: false,
132        fallible: false,
133    })).chain(attrs.iter_for_kind_core(&Kind::OwnedInto, true).map(|struct_attr| ImplContext {
134        input: &input, impl_type, struct_attr,
135        kind: Kind::OwnedInto,
136        dst_ty: &struct_attr.ty.path,
137        src_ty: &ty,
138        has_post_init: false,
139        fallible: true,
140    })).chain(attrs.iter_for_kind_core(&Kind::RefInto, false).map(|struct_attr| ImplContext {
141        input: &input, impl_type, struct_attr,
142        kind: Kind::RefInto,
143        dst_ty: &struct_attr.ty.path,
144        src_ty: &ty,
145        has_post_init: false,
146        fallible: false,
147    })).chain(attrs.iter_for_kind_core(&Kind::RefInto, true).map(|struct_attr| ImplContext {
148        input: &input, impl_type, struct_attr,
149        kind: Kind::RefInto,
150        dst_ty: &struct_attr.ty.path,
151        src_ty: &ty,
152        has_post_init: false,
153        fallible: true,
154    })).chain(attrs.iter_for_kind_core(&Kind::OwnedIntoExisting, false).map(|struct_attr| ImplContext {
155        input: &input, impl_type, struct_attr,
156        kind: Kind::OwnedIntoExisting,
157        dst_ty: &struct_attr.ty.path,
158        src_ty: &ty,
159        has_post_init: false,
160        fallible: false,
161    })).chain(attrs.iter_for_kind_core(&Kind::OwnedIntoExisting, true).map(|struct_attr| ImplContext {
162        input: &input, impl_type, struct_attr,
163        kind: Kind::OwnedIntoExisting,
164        dst_ty: &struct_attr.ty.path,
165        src_ty: &ty,
166        has_post_init: false,
167        fallible: true,
168    })).chain(attrs.iter_for_kind_core(&Kind::RefIntoExisting, false).map(|struct_attr| ImplContext {
169        input: &input, impl_type, struct_attr,
170        kind: Kind::RefIntoExisting,
171        dst_ty: &struct_attr.ty.path,
172        src_ty: &ty,
173        has_post_init: false,
174        fallible: false,
175    })).chain(attrs.iter_for_kind_core(&Kind::RefIntoExisting, true).map(|struct_attr| ImplContext {
176        input: &input, impl_type, struct_attr,
177        kind: Kind::RefIntoExisting,
178        dst_ty: &struct_attr.ty.path,
179        src_ty: &ty,
180        has_post_init: false,
181        fallible: true,
182    })).map(|mut ctx| quote_trait(&input, &mut ctx));
183
184    quote! { #(#impls)* }
185}
186
187fn main_code_block(ctx: &ImplContext) -> TokenStream {
188    if let Some(quick_return) = &ctx.struct_attr.quick_return {
189        //TODO: Consider removing quick returns for into_existing because they are confusing
190        if ctx.kind.is_into_existing() {
191            let action = quote_action(&quick_return.token_stream, None, ctx);
192            return quote!(*other = #action;);
193        }
194        return quote_action(&quick_return.token_stream, None, ctx);
195    }
196
197    match ctx.input {
198        DataType::Struct(s) => struct_main_code_block(s, ctx),
199        DataType::Enum(e) => enum_main_code_block(e, ctx),
200    }
201}
202
203fn main_code_block_ok(ctx: &ImplContext) -> TokenStream {
204    if let Some(quick_return) = &ctx.struct_attr.quick_return {
205        //TODO: Consider removing quick returns for into_existing because they are confusing
206        if ctx.kind.is_into_existing() {
207            let action = quote_action(&quick_return.token_stream, None, ctx);
208            return quote!(*other = #action;);
209        }
210        return quote_action(&quick_return.token_stream, None, ctx);
211    }
212
213    let inner = match ctx.input {
214        DataType::Struct(s) => struct_main_code_block(s, ctx),
215        DataType::Enum(e) => enum_main_code_block(e, ctx),
216    };
217
218    if ctx.has_post_init {
219        inner
220    } else {
221        quote!(Ok(#inner))
222    }
223}
224
225fn struct_main_code_block(input: &Struct, ctx: &ImplContext) -> TokenStream {
226    let struct_init_block = struct_init_block(input, ctx);
227
228    match ctx.kind {
229        Kind::FromOwned | Kind::FromRef => {
230            let dst = ctx.dst_ty;
231            quote!(#dst #struct_init_block)
232        },
233        Kind::OwnedInto | Kind::RefInto => {
234            let dst = if ctx.struct_attr.ty.nameless_tuple || ctx.has_post_init {
235                TokenStream::new()
236            } else {
237                ctx.dst_ty.clone()
238            };
239            quote!(#dst #struct_init_block)
240        },
241        Kind::OwnedIntoExisting | Kind::RefIntoExisting => struct_init_block,
242    }
243}
244
245fn enum_main_code_block(input: &Enum, ctx: &ImplContext) -> TokenStream {
246    let enum_init_block = enum_init_block(input, ctx);
247
248    match ctx.kind {
249        Kind::FromOwned | Kind::FromRef => {
250            let match_expr = if let Some(ts) = &ctx.struct_attr.match_expr { replace_tilde_or_at_in_expr(&ts.token_stream, Some(&quote!(value)), None) } else { quote!(value) };
251            quote!(match #match_expr #enum_init_block)
252        },
253        Kind::OwnedInto | Kind::RefInto => {
254            let match_expr = if let Some(ts) = &ctx.struct_attr.match_expr { replace_tilde_or_at_in_expr(&ts.token_stream, Some(&quote!(self)), None) } else { quote!(self) };
255            quote!(match #match_expr #enum_init_block)
256        },
257        Kind::OwnedIntoExisting | Kind::RefIntoExisting => enum_init_block,
258    }
259}
260
261fn struct_init_block<'a>(input: &'a Struct, ctx: &ImplContext) -> TokenStream {
262    if (!ctx.kind.is_from() && ctx.struct_attr.type_hint == TypeHint::Unit) || (ctx.kind.is_from() && input.unit) {
263        return TokenStream::new();
264    }
265
266    let mut group_paths = HashMap::<String, usize>::new();
267    group_paths.insert("".into(), 0);
268
269    let mut make_tuple = |path: String, field_data: FieldData<'a>| {
270        if group_paths.contains_key(&path) {
271            let gr_idx = *group_paths.get(&path).unwrap();
272            (FieldContainer { gr_idx, path, field_data }, false)
273        } else {
274            group_paths.insert(path.clone(), group_paths.len());
275            (FieldContainer { gr_idx: group_paths.len() - 1, path, field_data}, true)
276        }
277    };
278
279    let mut fields: Vec<FieldContainer> = vec![];
280
281    fields.extend(input.fields.iter()
282        .flat_map(|x| {
283            let fields: Vec<FieldContainer> = if let Some(p) = x.attrs.parameterized_parent_attr(&ctx.struct_attr.ty).map(|a| a.child_fields.as_ref().unwrap()) {
284                p.iter().map(|p| make_tuple(format!("{}{}", &x.member_str, &p.sub_path_tokens.to_string().replace(' ', "")), FieldData::ParentChildField(x, p)).0).collect()
285            } else {
286                let path = x.attrs.child(&ctx.struct_attr.ty).map(|x| x.get_child_path_str(None)).unwrap_or(&x.member_str);
287                vec![make_tuple(path.to_string(), FieldData::Field(x)).0]
288            };
289            fields.into_iter()
290        }));
291
292    fields.extend(input.attrs.ghosts_attrs.iter()
293        .flat_map(|x| &x.attr.ghost_data)
294        .filter_map(|x| {
295            let res = make_tuple(x.get_child_path_str(None).into(), FieldData::GhostData(x));
296            res.1.then_some(res.0)
297        }));
298
299    fields.sort_by(|a, b| a.gr_idx.cmp(&b.gr_idx));
300
301    struct_init_block_inner(&mut fields.iter().peekable(), input.named_fields, ctx, None)
302}
303
304fn struct_init_block_inner(
305    members: &mut Peekable<Iter<FieldContainer>>,
306    named_fields: bool, 
307    ctx: &ImplContext,
308    field_ctx: Option<(&ChildPath, Option<&ChildRenderContext>, usize)>
309) -> TokenStream
310{
311    let type_hint = ctx.struct_attr.type_hint;
312    let type_hint = field_ctx.map_or(type_hint, |x|x.1.map_or(type_hint, |x|x.type_hint));
313
314    let mut fragments: Vec<TokenStream> = vec![];
315    let mut idx: usize = 0;
316
317    while let Some(FieldContainer { path, field_data, .. }) = members.peek() {
318        if let Some(field_ctx) = field_ctx {
319            let p = field_ctx.0.get_child_path_str(Some(field_ctx.2));
320            if path != p && !path.starts_with(format!("{p}.").as_str()) {
321                break;
322            }
323        }
324
325        match field_data {
326            FieldData::Field(f) => {
327                let attrs = &f.attrs;
328                if !ctx.kind.is_from() && (attrs.ghost(&ctx.struct_attr.ty, &ctx.kind).is_some() || attrs.has_parent_attr(&ctx.struct_attr.ty)) {
329                    members.next();
330                    continue;
331                }
332
333                if ctx.kind.is_from() {
334                    if let Some(ghost_attr) = attrs.ghost(&ctx.struct_attr.ty, &ctx.kind) {
335                        if ghost_attr.action.is_none() {
336                            members.next();
337                            continue;
338                        }
339                    }
340                }
341
342                let fragment = match attrs.child(&ctx.struct_attr.ty) {
343                    Some(child_attr) => render_child_fragment(&child_attr.child_path, members, ctx, field_ctx.map(|x|x.2), type_hint, || render_struct_line(f, ctx, type_hint, idx, None)),
344                    None => {
345                        members.next();
346                        render_struct_line(f, ctx, type_hint, idx, None)
347                    }
348                };
349                fragments.push(fragment);
350                idx += 1;
351            },
352            FieldData::GhostData(g) => {
353                let child_path = &g.child_path.as_ref().unwrap();
354                let fragment = render_child_fragment(child_path, members, ctx, field_ctx.map(|x|x.2), type_hint, TokenStream::new);
355                fragments.push(fragment);
356                idx += 1;
357            },
358            FieldData::ParentChildField(f, p) => {
359                let type_hint = if type_hint == TypeHint::Unspecified { if ctx.input.named_fields() {TypeHint::Struct} else {TypeHint::Tuple} } else { type_hint };
360                let fragment = render_parent_child_fragment(f, p, members, p.named_fields(), ctx, field_ctx.map(|x|x.2), || render_struct_line(f, ctx, type_hint, idx, Some(p)));
361                fragments.push(fragment);
362                idx += 1;
363            }
364        }
365    }
366
367    if !ctx.kind.is_from() {
368        if let Some(ghost_attr) = ctx.input.get_attrs().ghosts_attr(&ctx.struct_attr.ty, &ctx.kind) {
369            ghost_attr.ghost_data.iter().for_each(|x| match (&x.child_path, field_ctx) {
370                (Some(_), Some(field_ctx)) => {
371                    if x.get_child_path_str(None) == field_ctx.0.get_child_path_str(Some(field_ctx.2)) {
372                        fragments.push(render_ghost_line(x, ctx))
373                    }
374                }
375                (None, None) => fragments.push(render_ghost_line(x, ctx)),
376                _ => (),
377            });
378        }
379    }
380
381    if let Some(update) = &ctx.struct_attr.update {
382        let a = quote_action(&update.token_stream, None, ctx);
383        fragments.push(quote!(..#a))
384    }
385
386    if ctx.has_post_init || ctx.kind.is_into_existing() {
387        return quote!(#(#fragments)*);
388    }
389
390    match (&ctx.kind, type_hint, named_fields) {
391        (Kind::FromOwned | Kind::FromRef, _, true) => quote!({#(#fragments)*}),
392        (Kind::FromOwned | Kind::FromRef, _, false) => quote!((#(#fragments)*)),
393        (_, TypeHint::Struct, _) => quote!({#(#fragments)*}),
394        (_, TypeHint::Tuple, _) => quote!((#(#fragments)*)),
395        (_, TypeHint::Unspecified, true) => quote!({#(#fragments)*}),
396        (_, TypeHint::Unspecified, false) => quote!((#(#fragments)*)),
397        (_, TypeHint::Unit, _) => unreachable!("2"),
398    }
399}
400
401fn enum_init_block(input: &Enum, ctx: &ImplContext) -> TokenStream {
402    let mut fields: Vec<VariantData> = vec![];
403
404    fields.extend(input.variants.iter()
405        .map(VariantData::Variant).collect::<Vec<VariantData>>());
406    
407    fields.extend(input.attrs.ghosts_attrs.iter()
408        .flat_map(|x| &x.attr.ghost_data)
409        .map(VariantData::GhostData));
410
411    enum_init_block_inner(&mut fields.iter().peekable(), ctx)
412}
413
414fn enum_init_block_inner(members: &mut Peekable<Iter<VariantData>>, ctx: &ImplContext) -> TokenStream {
415    let mut fragments: Vec<TokenStream> = vec![];
416
417    while let Some(member_data) = members.peek() {
418        match member_data {
419            VariantData::Variant(v) => {
420                let attrs = &v.attrs;
421                if ctx.kind.is_from() && attrs.ghost(&ctx.struct_attr.ty, &ctx.kind).is_some() {
422                    members.next();
423                    continue;
424                }
425
426                if !ctx.kind.is_from() {
427                    if let Some(ghost_attr) = attrs.ghost(&ctx.struct_attr.ty, &ctx.kind) {
428                        if ghost_attr.action.is_none() {
429                            members.next();
430                            continue;
431                        }
432                    }
433                }
434
435                members.next();
436                let fragment = render_enum_line(v, ctx);
437                fragments.push(fragment);
438            }
439            VariantData::GhostData(ghost_data) => {
440                members.next();
441                let fragment = render_enum_ghost_line(ghost_data, ctx);
442                fragments.push(fragment);
443            }
444        }
445    }
446
447    if let Some(default_case) = &ctx.struct_attr.default_case {
448        let g = quote_action(&default_case.token_stream, None, ctx);
449        fragments.push(quote!(_ #g))
450    }
451
452    quote!({#(#fragments)*})
453}
454
455fn variant_destruct_block(input: &Struct, ctx: &ImplContext) -> TokenStream {
456    let (mut idents, type_hint) = match (input.named_fields, ctx.kind, ctx.struct_attr.type_hint) {
457        (true, Kind::OwnedInto | Kind::RefInto | Kind::OwnedIntoExisting | Kind::RefIntoExisting, _) | 
458        (true, _, TypeHint::Struct | TypeHint::Unspecified) | 
459        (false, Kind::FromOwned | Kind::FromRef, TypeHint::Struct) => (
460            input.fields.iter().filter(|x| !ctx.kind.is_from() || x.attrs.ghost(&ctx.struct_attr.ty, &ctx.kind).is_none())
461                .map(|x| {
462                    let attr = x.attrs.applicable_attr(&ctx.kind, ctx.fallible, &ctx.struct_attr.ty);
463
464                    if !ctx.kind.is_from() || attr.is_none() {
465                        let ident = &x.member;
466                        quote!(#ident ,)
467                    } else if let Some(attr) = attr {
468                        let ident = attr.get_field_name_or(&x.member);
469                        quote!(#ident ,)
470                    } else { unreachable!("3") }
471                }).collect(),
472            TypeHint::Struct,
473        ),
474        (_, Kind::FromOwned | Kind::FromRef, TypeHint::Unit) => (vec![], TypeHint::Unit),
475        _ => (
476            input.fields.iter().filter(|x| !ctx.kind.is_from() || x.attrs.ghost(&ctx.struct_attr.ty, &ctx.kind).is_none())
477                .map(|x| {
478                    let ident = format_ident!("f{}", x.idx);
479                    quote!(#ident ,)
480                }).collect(),
481            TypeHint::Tuple,
482        ),
483    };
484
485    if ctx.kind.is_from() {
486        idents.extend(input.attrs.ghosts_attrs.iter().flat_map(|x| &x.attr.ghost_data).map(|x| {
487            let ghost_ident = x.ghost_ident.get_ident();
488            let ident = match ghost_ident {
489                Named(ident) => ident.to_token_stream(),
490                Unnamed(index) => format_ident!("f{}", index.index).to_token_stream(),
491            };
492            quote!(#ident ,)
493        }));
494    }
495
496    match type_hint {
497        TypeHint::Struct => quote!({#(#idents)*}),
498        TypeHint::Tuple => quote!((#(#idents)*)),
499        TypeHint::Unit => TokenStream::new(),
500        _ => unreachable!("4"),
501    }
502}
503
504fn render_child_fragment<F: Fn() -> TokenStream>(
505    child_path: &ChildPath,
506    fields: &mut Peekable<Iter<FieldContainer>>,
507    ctx: &ImplContext,
508    depth: Option<usize>,
509    type_hint: TypeHint,
510    render_line: F
511) -> TokenStream
512{
513    if depth.is_none() || depth.unwrap() < child_path.child_path_str.len() - 1 {
514        let new_depth = depth.map_or(0, |x|x+1);
515        match ctx.kind {
516            Kind::OwnedInto | Kind::RefInto => {
517                let mut child_parents = ctx.input.get_attrs().child_parents_attr(&ctx.struct_attr.ty).unwrap().child_parents.iter();
518                let child_data = child_parents.find(|child_data| child_data.check_match(child_path.get_child_path_str(Some(new_depth)))).unwrap();
519                
520                render_child(&child_data.into(), fields, ctx.input.named_fields(), ctx, (child_path, new_depth), type_hint)
521            },
522            Kind::OwnedIntoExisting | Kind::RefIntoExisting => render_existing_child(fields, ctx.input.named_fields(), ctx, (child_path, new_depth)),
523            Kind::FromOwned | Kind::FromRef => {
524                fields.next();
525                render_line()
526            }
527        }
528    } else {
529        fields.next();
530        render_line()
531    }
532}
533
534fn render_parent_child_fragment<F: Fn() -> TokenStream>(
535    field: &Field,
536    parent_child_field: &ParentChildField,
537    fields: &mut Peekable<Iter<FieldContainer>>,
538    named_fields: bool,
539    ctx: &ImplContext,
540    depth: Option<usize>,
541    render_line: F
542) -> TokenStream
543{
544    if depth.is_none() || depth.unwrap() < parent_child_field.sub_path.len() {
545        let new_depth = depth.map_or(0, |x|x+1);
546        if ctx.kind.is_from() {
547            let ty = if let Some(depth) = depth { parent_child_field.sub_path[depth].1.as_ref().unwrap() } else { field.ty.as_ref().unwrap() };
548            let child_data = ChildRenderContext { ty, type_hint: ctx.struct_attr.type_hint };
549            let child_path = ChildPath::new(field.member.clone(), parent_child_field.sub_path.iter().map(|x|x.0.clone()));
550            render_child(&child_data, fields, named_fields, ctx, (&child_path, new_depth), if ctx.input.named_fields() {TypeHint::Struct} else {TypeHint::Tuple})
551        } else {
552            fields.next();
553            render_line()
554        }
555    } else {
556        fields.next();
557        render_line()
558    }
559}
560
561fn struct_pre_init(ctx: &ImplContext) -> Option<TokenStream> {
562    if let Some(init_data) = &ctx.struct_attr.init_data {
563        let g = init_data.iter().map(|x| {
564            let a = &x.ident;
565            let b = quote_action(&x.action, None, ctx);
566
567            quote!(let #a = #b;)
568        });
569        Some(TokenStream::from_iter(g))
570    } else {
571        None
572    }
573}
574
575fn struct_post_init(input: &DataType, ctx: &ImplContext) -> Option<TokenStream> {
576    let mut fragments: Vec<TokenStream> = vec![];
577
578    input.get_members().iter().for_each(|f| {
579        if !ctx.kind.is_from() && f.get_attrs().has_parameterless_parent_attr(&ctx.struct_attr.ty) {
580            match f {
581                DataTypeMember::Field(f) => fragments.push(render_parent(f, ctx)),
582                DataTypeMember::Variant(_) => todo!(),
583            }
584        }
585    });
586
587    if fragments.is_empty() {
588        return None;
589    }
590    Some(quote!(#(#fragments)*))
591}
592
593fn render_parent(f: &Field, ctx: &ImplContext) -> TokenStream {
594    let member = &f.member;
595    match (&ctx.kind, ctx.fallible) {
596        (Kind::OwnedIntoExisting, false) => quote!(self.#member.into_existing(other);),
597        (Kind::RefIntoExisting, false) => quote!((&(self.#member)).into_existing(other);),
598        (Kind::OwnedInto, false) => quote!(self.#member.into_existing(&mut obj);),
599        (Kind::RefInto, false) => quote!((&(self.#member)).into_existing(&mut obj);),
600        (Kind::OwnedIntoExisting, true) => quote!(self.#member.try_into_existing(other)?;),
601        (Kind::RefIntoExisting, true) => quote!((&(self.#member)).try_into_existing(other)?;),
602        (Kind::OwnedInto, true) => quote!(self.#member.try_into_existing(&mut obj)?;),
603        (Kind::RefInto, true) => quote!((&(self.#member)).try_into_existing(&mut obj)?;),
604        _ => unreachable!("5"),
605    }
606}
607
608fn render_child(
609    child_data: &ChildRenderContext,
610    fields: &mut Peekable<Iter<FieldContainer>>,
611    named_fields: bool,
612    ctx: &ImplContext,
613    field_ctx: (&ChildPath, usize),
614    hint: TypeHint) -> TokenStream
615{
616    let child_path = field_ctx.0;
617    let child_name = child_path.child_path[field_ctx.1].to_token_stream();
618    let ty = &child_data.ty;
619    let init = struct_init_block_inner(fields, named_fields, ctx, Some((field_ctx.0, Some(child_data), field_ctx.1)));
620    match (ctx.input.named_fields(), hint) {
621        (true, TypeHint::Struct | TypeHint::Unspecified) => quote!(#child_name: #ty #init,),
622        (true, TypeHint::Tuple) => quote!(#ty #init,),
623        (false, TypeHint::Tuple | TypeHint::Unspecified) => quote!(#ty #init,),
624        (false, TypeHint::Struct) => quote!(#child_name: #ty #init,),
625        (_, TypeHint::Unit) => unreachable!("15"),
626    }
627}
628
629fn render_existing_child(
630    fields: &mut Peekable<Iter<FieldContainer>>,
631    named_fields: bool,
632    ctx: &ImplContext,
633    field_ctx: (&ChildPath, usize)
634) -> TokenStream
635{
636    let child_attr = field_ctx.0;
637    let path = child_attr.get_child_path_str(Some(field_ctx.1));
638    let child_parents_attr = ctx.input.get_attrs().child_parents_attr(&ctx.struct_attr.ty);
639    let child_data = child_parents_attr.and_then(|x| x.child_parents.iter().find(|child_data| child_data.check_match(path)));
640    struct_init_block_inner(fields, named_fields, ctx, Some((field_ctx.0, child_data.map(|x|x.into()).as_ref(), field_ctx.1)))
641}
642
643fn render_struct_line(
644    f: &Field,
645    ctx: &ImplContext,
646    hint: TypeHint,
647    idx: usize,
648    parent_child: Option<&ParentChildField>
649) -> TokenStream
650{
651    let member = parent_child.map(|p| &p.this_member)
652        .unwrap_or(&f.member);
653    let attr = parent_child.map(|p| ApplicableAttr::ParentChildField(p, ctx.kind))
654        .or_else(|| f.attrs.applicable_attr(&ctx.kind, ctx.fallible, &ctx.struct_attr.ty));
655    let get_field_path = |x: &Member| match f.attrs.child(&ctx.struct_attr.ty) {
656        Some(child_attr) => {
657            let ch = child_attr.child_path.child_path.to_token_stream();
658            quote!(#ch.#x)
659        }
660        None => x.to_token_stream(),
661    };
662    let get_child_field_path = |x: &Member| match parent_child {
663        Some(p) => {
664            let sub_path = &p.sub_path_tokens;
665            quote!(#x #sub_path.#member)
666        },
667        None => x.to_token_stream()
668    };
669
670    let obj = if ctx.impl_type.is_variant() { TokenStream::new() } else {
671        match ctx.kind {
672            Kind::OwnedInto => quote!(self.),
673            Kind::RefInto => quote!(self.),
674            Kind::FromOwned => quote!(value.),
675            Kind::FromRef => quote!(value.),
676            Kind::OwnedIntoExisting => quote!(self.),
677            Kind::RefIntoExisting => quote!(self.),
678        }
679    };
680
681    match (member, attr, &ctx.kind, hint) {
682        (Named(ident), None, Kind::OwnedInto | Kind::RefInto, TypeHint::Struct | TypeHint::Unspecified) =>
683            if ctx.has_post_init { quote!(obj.#ident = #obj #ident;) } else { quote!(#ident: #obj #ident,) },
684        (Named(ident), None, Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Struct | TypeHint::Unspecified) => {
685            let field_path = get_field_path(&f.member);
686            quote!(other.#field_path = #obj #ident;)
687        },
688        (Named(ident), None, Kind::OwnedInto | Kind::RefInto, TypeHint::Tuple) => 
689            quote!(#obj #ident,),
690        (Named(ident), None, Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Tuple) => {
691            let index = Unnamed(Index { index: f.idx as u32, span: Span::call_site() });
692            quote!(other.#index = #obj #ident;)
693        },
694        (Named(ident), None, Kind::FromOwned | Kind::FromRef, TypeHint::Struct | TypeHint::Unspecified | TypeHint::Unit) =>
695            if f.attrs.has_parent_attr(&ctx.struct_attr.ty) {
696                match (ctx.kind.is_ref(), ctx.fallible) {
697                    (true, true) => quote!(#ident: value.try_into()?,),
698                    (true, false) => quote!(#ident: value.into(),),
699                    (false, true) => quote!(#ident: (&value).try_into()?,),
700                    (false, false) => quote!(#ident: (&value).into(),),
701                }
702            } else {
703                let field_path = get_field_path(&f.member);
704                quote!(#ident: #obj #field_path,)
705            },
706        (Named(ident), None, Kind::FromOwned | Kind::FromRef, TypeHint::Tuple) => {
707            let index = Unnamed(Index { index: f.idx as u32, span: Span::call_site() });
708            let field_path = if ctx.impl_type.is_variant() { get_field_path(&Named(format_ident!("f{}", index))) } else { get_field_path(&index) };
709            quote!(#ident: #obj #field_path,)
710        },
711        (Unnamed(index), None, Kind::OwnedInto | Kind::RefInto, TypeHint::Tuple | TypeHint::Unspecified) =>
712            if ctx.has_post_init {
713                let index2 = Unnamed(Index { index: idx as u32, span: Span::call_site() });
714                quote!(obj.#index2 = #obj #index;)
715            } else {
716                let index = if ctx.impl_type.is_variant() { format_ident!("f{}", index.index).to_token_stream() } else { index.to_token_stream() };
717                quote!(#obj #index,)
718            },
719        (Unnamed(index), None, Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Tuple | TypeHint::Unspecified) => {
720            let index2 = Unnamed(Index { index: f.idx as u32, span: Span::call_site() });
721            quote!(other.#index2 = #obj #index;)
722        },
723        (Unnamed(index), None, Kind::FromOwned | Kind::FromRef, TypeHint::Tuple | TypeHint::Unspecified | TypeHint::Unit) =>
724            if f.attrs.has_parent_attr(&ctx.struct_attr.ty) {
725                match (ctx.kind.is_ref(), ctx.fallible) {
726                    (true, true) => quote!(value.try_into()?,),
727                    (true, false) => quote!(value.into(),),
728                    (false, true) => quote!((&value).try_into()?,),
729                    (false, false) => quote!((&value).into(),),
730                }
731            } else {
732                let field_path = if ctx.impl_type.is_variant() { get_field_path(&Named(format_ident!("f{}", index.index))) } else { get_field_path(&f.member) };
733                quote!(#obj #field_path,)
734            },
735        (Unnamed(_), None, _, TypeHint::Struct) =>
736            if f.attrs.has_parent_attr(&ctx.struct_attr.ty) {
737                match (ctx.kind.is_ref(), ctx.fallible) {
738                    (true, true) => quote!(value.try_into()?,),
739                    (true, false) => quote!(value.into(),),
740                    (false, true) => quote!((&value).try_into()?,),
741                    (false, false) => quote!((&value).into(),),
742                }
743            } else {
744                unreachable!("6")
745            },
746        (Named(_), Some(attr), Kind::OwnedInto | Kind::RefInto, TypeHint::Struct | TypeHint::Unspecified) => {
747            let field_name = attr.get_field_name_or(&f.member);
748            let field_path = get_child_field_path(&f.member);
749            let right_side = attr.get_action_or(Some(&field_path), ctx, || quote!(#obj #field_path));
750            if ctx.has_post_init { quote!(obj.#field_name = #right_side;) } else { quote!(#field_name: #right_side,) }
751        },
752        (Named(_), Some(attr), Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Struct | TypeHint::Unspecified) => {
753            let left_field_path = get_field_path(attr.get_field_name_or(&f.member));
754            let right_field_path = get_child_field_path(&f.member);
755            let right_side = attr.get_action_or(Some(&right_field_path), ctx, || quote!(#obj #right_field_path));
756            quote!(other.#left_field_path = #right_side;)
757        },
758        (Named(_), Some(attr), Kind::OwnedInto | Kind::RefInto, TypeHint::Tuple) => {
759            let right_field_path = get_child_field_path(&f.member);
760            let right_side = attr.get_action_or(Some(&right_field_path), ctx, || quote!(#obj #right_field_path));
761            quote!(#right_side,)
762        },
763        (Named(_), Some(attr), Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Tuple) => {
764            let left_field_path = get_field_path(&Unnamed(Index { index: idx as u32, span: Span::call_site() }));
765            let right_field_path = get_child_field_path(&f.member);
766            let right_side = attr.get_action_or(Some(&right_field_path), ctx, || quote!(#obj #right_field_path));
767            quote!(other.#left_field_path = #right_side;)
768        },
769        (Named(_), Some(attr), Kind::FromOwned | Kind::FromRef, TypeHint::Struct | TypeHint::Unspecified | TypeHint::Unit) => {
770            let right_side = attr.get_stuff(&obj, get_field_path, ctx, || &f.member);
771            let idnt = parent_child.map_or(&f.member, |g| &g.this_member);
772            quote!(#idnt: #right_side,)
773        },
774        (Named(ident), Some(attr), Kind::FromOwned | Kind::FromRef, TypeHint::Tuple) => {
775            let or = Named(format_ident!("f{}", f.idx));
776            let right_side = attr.get_stuff(&obj, get_field_path, ctx, || if ctx.impl_type.is_variant() { &or } else { &f.member });
777            quote!(#ident: #right_side,)
778        },
779        (Unnamed(index), Some(attr), Kind::OwnedInto | Kind::RefInto, TypeHint::Tuple | TypeHint::Unspecified) => {
780            let index = if ctx.impl_type.is_variant() { &Member::Named(format_ident!("f{}", index.index)) } else { &f.member };
781            let field_path = get_child_field_path(index);
782            let right_side = attr.get_action_or(Some(&field_path), ctx, || quote!(#obj #field_path));
783            quote!(#right_side,)
784        },
785        (Unnamed(_), Some(attr), Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Tuple | TypeHint::Unspecified) => {
786            let left_field_path = get_field_path(attr.get_field_name_or(&f.member));
787            let right_field_path = get_child_field_path(&f.member);
788            let right_side = attr.get_action_or(Some(&right_field_path), ctx, || quote!(#obj #right_field_path));
789            quote!(other.#left_field_path = #right_side;)
790        },
791        (Unnamed(index), Some(attr), Kind::OwnedInto | Kind::RefInto, TypeHint::Struct) => {
792            let field_name = attr.get_ident();
793            let field_path = get_child_field_path(&f.member);
794            let or = if ctx.impl_type.is_variant() { format_ident!("f{}", index.index).to_token_stream() } else { field_path };
795            let right_side = attr.get_action_or(Some(&or), ctx, || quote!(#obj #or));
796            if ctx.has_post_init {
797                quote!(obj.#field_name = #right_side;)
798            } else {
799                quote!(#field_name: #right_side,)
800            }
801        },
802        (Unnamed(_), Some(attr), Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Struct) => {
803            let left_field_path = get_field_path(attr.get_ident());
804            let right_field_path = get_child_field_path(&f.member);
805            let right_side = attr.get_action_or(Some(&right_field_path), ctx, || quote!(#obj #right_field_path));
806            quote!(other.#left_field_path = #right_side;)
807        },
808        (Unnamed(index), Some(attr), Kind::FromOwned | Kind::FromRef, _) => {
809            let or = Named(format_ident!("f{}", index.index));
810            let right_side = attr.get_stuff(&obj, get_field_path, ctx, || if ctx.impl_type.is_variant() { &or } else { &f.member });
811            quote!(#right_side,)
812        },
813        (_, _, Kind::OwnedInto | Kind::RefInto | Kind::OwnedIntoExisting | Kind::RefIntoExisting, TypeHint::Unit) => TokenStream::new(),
814    }
815}
816
817fn render_enum_line(v: &Variant, ctx: &ImplContext) -> TokenStream {
818    let attr = v.attrs.applicable_attr(&ctx.kind, ctx.fallible, &ctx.struct_attr.ty);
819    let lit = v.attrs.lit(&ctx.struct_attr.ty);
820    let pat = v.attrs.pat(&ctx.struct_attr.ty);
821    let var = v.attrs.type_hint(&ctx.struct_attr.ty);
822
823    let src = ctx.src_ty;
824    let dst = ctx.dst_ty;
825
826    let ident = &v.ident;
827
828    let variant_struct: Struct<'_> = Struct {
829        attrs: DataTypeAttrs { ghosts_attrs: v.attrs.ghosts_attrs.clone(), ..Default::default() },
830        ident,
831        generics: &Default::default(),
832        fields: v.fields.clone(),
833        named_fields: v.named_fields,
834        unit: v.unit,
835    };
836
837    let mut struct_attr = ctx.struct_attr.clone();
838    let type_hint = var.map_or(TypeHint::Unspecified, |x| x.type_hint);
839    struct_attr.type_hint = type_hint;
840
841    let new_ctx = ImplContext {
842        input: &DataType::Struct(&variant_struct),
843        struct_attr: &struct_attr,
844        impl_type: ImplType::Variant,
845        ..*ctx
846    };
847
848    let empty_fields = variant_struct.fields.is_empty();
849    let destr = if empty_fields && (!new_ctx.kind.is_from() || type_hint.maybe(TypeHint::Unit)) {
850        TokenStream::new()
851    } else if empty_fields && new_ctx.kind.is_from() && type_hint == TypeHint::Tuple {
852        quote!((..))
853    } else if empty_fields && new_ctx.kind.is_from() && type_hint == TypeHint::Struct {
854        quote!({ .. })
855    } else {
856        variant_destruct_block(&variant_struct, &new_ctx)
857    };
858
859    let init = if attr.as_ref().is_some_and(|x| x.has_action()) || empty_fields && type_hint.maybe(TypeHint::Unit) {
860        TokenStream::new()
861    } else {
862        struct_init_block(&variant_struct, &new_ctx)
863    };
864
865    match (v.named_fields, attr, lit, pat, &ctx.kind) {
866        (_, None, None, None, _) => {
867            quote!(#src::#ident #destr => #dst::#ident #init,)
868        },
869        (_, Some(attr), None, None, Kind::FromOwned | Kind::FromRef) => {
870            let member = Named(ident.clone());
871            let right_side = attr.get_action_or(Some(&quote!(#ident)), ctx, || quote!(#dst::#ident #init));
872            let ident2 = attr.get_field_name_or(&member);
873            quote!(#src::#ident2 #destr => #right_side,)
874        },
875        (_, Some(attr), None, None, Kind::OwnedInto | Kind::RefInto) => {
876            let member = Named(ident.clone());
877            let right_side = attr.get_stuff(&quote!(#dst::), |x| quote!(#x #init), ctx, || &member);
878            quote!(#src::#ident #destr => #right_side,)
879        },
880        (_, None, Some(lit), None, Kind::FromOwned | Kind::FromRef) => {
881            let left_side = &lit.tokens;
882            quote!(#left_side => #dst::#ident #init,)
883        },
884        (_, None, Some(lit), None, Kind::OwnedInto | Kind::RefInto) => {
885            let right_side = &lit.tokens;
886            quote!(#src::#ident #destr => #right_side,)
887        },
888        (_, None, None, Some(pat), Kind::FromOwned | Kind::FromRef) => {
889            let left_side = &pat.tokens;
890            quote!(#left_side => #dst::#ident #init,)
891        },
892        (_, Some(attr), None, Some(_), Kind::OwnedInto | Kind::RefInto) => {
893            let right_side = attr.get_action_or(None, ctx, TokenStream::new);
894            quote!(#src::#ident #destr => #right_side,)
895        }
896        _ => todo!(),
897    }
898}
899
900fn render_ghost_line(ghost_data: &GhostData, ctx: &ImplContext) -> TokenStream {
901    let ch = match &ghost_data.child_path {
902        Some(ghost_data) => {
903            let ch = ghost_data.child_path.to_token_stream();
904            quote!(#ch.)
905        }
906        None => TokenStream::new(),
907    };
908    let right_side = quote_action(&ghost_data.action, None, ctx);
909    let ghost_ident = &ghost_data.ghost_ident.get_ident();
910    match (ghost_ident, &ctx.kind) {
911        (Named(ident), Kind::OwnedInto | Kind::RefInto) => quote!(#ident: #right_side,),
912        (Unnamed(_), Kind::OwnedInto | Kind::RefInto) => quote!(#right_side,),
913        (Named(ident), Kind::OwnedIntoExisting | Kind::RefIntoExisting) => quote!(other.#ch #ident = #right_side;),
914        (Unnamed(index), Kind::OwnedIntoExisting | Kind::RefIntoExisting) => quote!(other.#ch #index = #right_side;),
915        (_, _) => unreachable!("7"),
916    }
917}
918
919fn render_enum_ghost_line(ghost_data: &GhostData, ctx: &ImplContext) -> TokenStream {
920    let src = ctx.src_ty;
921    let right_side = quote_action(&ghost_data.action, None, ctx);
922
923    match &ghost_data.ghost_ident {
924        GhostIdent::Member(ghost_ident) => match (ghost_ident, ctx.kind.is_from()) {
925            (Unnamed(_), _) => unreachable!("17"),
926            (Named(ident), true) => quote!(#src::#ident => #right_side,),
927            (_, false) => TokenStream::new(),
928        },
929        GhostIdent::Destruction(destr) => {
930            if ctx.kind.is_from() {
931                quote!(#src::#destr => #right_side,)
932            } else {
933                TokenStream::new()
934            }
935        }
936    }
937}
938
939fn replace_tilde_or_at_in_expr(input: &TokenStream, at_tokens: Option<&TokenStream>, tilde_tokens: Option<&TokenStream>) -> TokenStream {
940    let mut tokens = Vec::new();
941
942    input.clone().into_iter().for_each(|x| {
943        let f = match x {
944            proc_macro2::TokenTree::Group(group) => {
945                let inner = replace_tilde_or_at_in_expr(&group.stream(), at_tokens, tilde_tokens);
946                match group.delimiter() {
947                    proc_macro2::Delimiter::Parenthesis => quote!(( #inner )),
948                    proc_macro2::Delimiter::Brace => quote!({ #inner }),
949                    proc_macro2::Delimiter::Bracket => quote!([ #inner ]),
950                    proc_macro2::Delimiter::None => quote!(#inner),
951                }
952            }
953            proc_macro2::TokenTree::Punct(punct) => {
954                let ch = punct.as_char();
955
956                if ch == '~' {
957                    quote!(#tilde_tokens)
958                } else if ch == '@' {
959                    quote!(#at_tokens)
960                } else {
961                    quote!(#punct)
962                }
963            }
964            _ => quote!(#x),
965        };
966
967        tokens.push(f)
968    });
969
970    TokenStream::from_iter(tokens)
971}
972
973fn quote_action(action: &TokenStream, tilde_postfix: Option<&TokenStream>, ctx: &ImplContext) -> TokenStream {
974    let dst = ctx.dst_ty;
975    let ident = match ctx.kind {
976        Kind::FromOwned | Kind::FromRef => quote!(value),
977        _ => quote!(self),
978    };
979    let path = match ctx.impl_type {
980        ImplType::Struct => quote!(#ident.#tilde_postfix),
981        ImplType::Enum => quote!(#dst::#tilde_postfix),
982        ImplType::Variant => quote!(#tilde_postfix),
983    };
984    replace_tilde_or_at_in_expr(action, Some(&ident), Some(&path))
985}
986
987struct QuoteTraitParams<'a> {
988    pub attr: Option<&'a TokenStream>,
989    pub impl_attr: Option<&'a TokenStream>,
990    pub inner_attr: Option<&'a TokenStream>,
991    pub dst: &'a TokenStream,
992    pub src: &'a TokenStream,
993    pub these_gens: TokenStream,
994    pub those_gens: TokenStream,
995    pub impl_gens: TokenStream,
996    pub where_clause: Option<TokenStream>,
997    pub r: Option<TokenStream>,
998}
999
1000fn get_quote_trait_params<'a>(input: &DataType, ctx: &'a ImplContext) -> QuoteTraitParams<'a> {
1001    let mut impl_gens = input.get_generics().clone();
1002
1003    let these_lts: Vec<&Lifetime> = input.get_generics().params.iter().filter_map(|g| match g {
1004        GenericParam::Lifetime(l) => Some(&l.lifetime),
1005        _ => None
1006    }).collect();
1007
1008    let those_lts: Vec<&Lifetime> = ctx.struct_attr.ty.generics.as_ref().map(|g| g.args.iter().filter_map(|g| match g {
1009        GenericArgument::Lifetime(l) => Some(l),
1010        _ => None
1011    }).collect()).unwrap_or_default();
1012
1013    let ref_lts = ctx.kind.is_ref().then_some(
1014        if ctx.kind.is_from() { these_lts } else { those_lts.clone() }
1015    ).unwrap_or_default();
1016
1017    for lt in those_lts {
1018        let missing_lt = impl_gens.params.iter().all(|param| {
1019            if let GenericParam::Lifetime(param) = param {
1020                &param.lifetime != lt
1021            } else { false }
1022        });
1023
1024        if missing_lt {
1025            let gen = GenericArgument::Lifetime(lt.clone());
1026            impl_gens.params.push(parse_quote!(#gen));
1027        }
1028    }
1029
1030    if !ref_lts.is_empty() {
1031        impl_gens.params.push(parse_quote!('o2o: #( #ref_lts )+*));
1032    }
1033
1034    QuoteTraitParams { 
1035        attr: ctx.struct_attr.attribute.as_ref(), 
1036        impl_attr: ctx.struct_attr.impl_attribute.as_ref(), 
1037        inner_attr: ctx.struct_attr.inner_attribute.as_ref(), 
1038        dst: ctx.dst_ty, 
1039        src: ctx.src_ty, 
1040        these_gens: input.get_generics().to_token_stream(),
1041        those_gens: ctx.struct_attr.ty.generics.to_token_stream(),
1042        impl_gens: impl_gens.to_token_stream(), 
1043        where_clause: input.get_attrs().where_attr(&ctx.struct_attr.ty).map(|x| {
1044            let where_clause = &x.where_clause;
1045            quote!(where #where_clause)
1046        }), 
1047        r: ctx.kind.is_ref().then_some(if ref_lts.is_empty() { quote!(&) } else { quote!(&'o2o) }) 
1048    }
1049}
1050
1051fn quote_trait(input: &DataType, ctx: &mut ImplContext) -> TokenStream {
1052    let pre_init = struct_pre_init(ctx);
1053    let post_init = if ctx.kind.is_from() { None } else {
1054        struct_post_init(input, ctx)
1055    };
1056    ctx.has_post_init = post_init.is_some();
1057
1058    match (ctx.kind, ctx.fallible) {
1059        (Kind::FromOwned, false) | (Kind::FromRef, false) => quote_from_trait(input, ctx, pre_init, main_code_block(ctx)),
1060        (Kind::FromOwned, true) | (Kind::FromRef, true) => quote_try_from_trait(input, ctx, pre_init, main_code_block_ok(ctx)),
1061        (Kind::OwnedInto, false) | (Kind::RefInto, false) => quote_into_trait(input, ctx, pre_init, main_code_block(ctx), post_init),
1062        (Kind::OwnedInto, true) | (Kind::RefInto, true) => quote_try_into_trait(input, ctx, pre_init, main_code_block_ok(ctx), post_init),
1063        (Kind::OwnedIntoExisting, false) | (Kind::RefIntoExisting, false) => quote_into_existing_trait(input, ctx, pre_init, main_code_block(ctx), post_init),
1064        (Kind::OwnedIntoExisting, true) | (Kind::RefIntoExisting, true) => quote_try_into_existing_trait(input, ctx, pre_init, main_code_block(ctx), post_init),
1065    }
1066}
1067
1068fn quote_from_trait(input: &DataType, ctx: &ImplContext, pre_init: Option<TokenStream>, init: TokenStream) -> TokenStream {
1069    let QuoteTraitParams { attr, impl_attr, inner_attr, dst, src, these_gens, those_gens, impl_gens, where_clause, r } = get_quote_trait_params(input, ctx);
1070    quote! {
1071        #impl_attr
1072        impl #impl_gens ::core::convert::From<#r #src #those_gens> for #dst #these_gens #where_clause {
1073            #attr
1074            fn from(value: #r #src #those_gens) -> #dst #these_gens {
1075                #inner_attr
1076                #pre_init
1077                #init
1078            }
1079        }
1080    }
1081}
1082
1083fn quote_try_from_trait(input: &DataType, ctx: &ImplContext, pre_init: Option<TokenStream>, init: TokenStream) -> TokenStream {
1084    let QuoteTraitParams { attr, impl_attr, inner_attr, dst, src, these_gens, those_gens, impl_gens, where_clause, r } = get_quote_trait_params(input, ctx);
1085    let err_ty = &ctx.struct_attr.err_ty.as_ref().unwrap().path;
1086    quote! {
1087        #impl_attr
1088        impl #impl_gens ::core::convert::TryFrom<#r #src #those_gens> for #dst #these_gens #where_clause {
1089            type Error = #err_ty;
1090            #attr
1091            fn try_from(value: #r #src #those_gens) -> ::core::result::Result<#dst #these_gens, #err_ty> {
1092                #inner_attr
1093                #pre_init
1094                #init
1095            }
1096        }
1097    }
1098}
1099
1100fn quote_into_trait(input: &DataType, ctx: &ImplContext, pre_init: Option<TokenStream>, init: TokenStream, post_init: Option<TokenStream>) -> TokenStream {
1101    let QuoteTraitParams { attr, impl_attr, inner_attr, dst, src, these_gens, those_gens, impl_gens, where_clause, r } = get_quote_trait_params(input, ctx);
1102
1103    let body = match post_init {
1104        Some(post_init) => quote! {
1105            let mut obj: #dst = Default::default();
1106            #init
1107            #post_init
1108            obj
1109        },
1110        None => quote! {
1111            #pre_init
1112            #init
1113        },
1114    };
1115
1116    quote! {
1117        #impl_attr
1118        impl #impl_gens ::core::convert::Into<#dst #those_gens> for #r #src #these_gens #where_clause {
1119            #attr
1120            fn into(self) -> #dst #those_gens {
1121                #inner_attr
1122                #body
1123            }
1124        }
1125    }
1126}
1127
1128fn quote_try_into_trait(input: &DataType, ctx: &ImplContext, pre_init: Option<TokenStream>, init: TokenStream, post_init: Option<TokenStream>) -> TokenStream {
1129    let QuoteTraitParams { attr, impl_attr, inner_attr, dst, src, these_gens, those_gens, impl_gens, where_clause, r } = get_quote_trait_params(input, ctx);
1130    let err_ty = &ctx.struct_attr.err_ty.as_ref().unwrap().path;
1131
1132    let body = match post_init {
1133        Some(post_init) => quote! {
1134            let mut obj: #dst = Default::default();
1135            #init
1136            #post_init
1137            Ok(obj)
1138        },
1139        None => quote! {
1140            #pre_init
1141            #init
1142        },
1143    };
1144
1145    quote! {
1146        #impl_attr
1147        impl #impl_gens ::core::convert::TryInto<#dst #those_gens> for #r #src #these_gens #where_clause {
1148            type Error = #err_ty;
1149            #attr
1150            fn try_into(self) -> ::core::result::Result<#dst #those_gens, #err_ty> {
1151                #inner_attr
1152                #body
1153            }
1154        }
1155    }
1156}
1157
1158fn quote_into_existing_trait(input: &DataType, ctx: &ImplContext, pre_init: Option<TokenStream>, init: TokenStream, post_init: Option<TokenStream>) -> TokenStream {
1159    let QuoteTraitParams { attr, impl_attr, inner_attr, dst, src, these_gens, those_gens, impl_gens, where_clause, r } = get_quote_trait_params(input, ctx);
1160    quote! {
1161        #impl_attr
1162        impl #impl_gens o2o::traits::IntoExisting<#dst #those_gens> for #r #src #these_gens #where_clause {
1163            #attr
1164            fn into_existing(self, other: &mut #dst #those_gens) {
1165                #inner_attr
1166                #pre_init
1167                #init
1168                #post_init
1169            }
1170        }
1171    }
1172}
1173
1174fn quote_try_into_existing_trait(input: &DataType, ctx: &ImplContext, pre_init: Option<TokenStream>, init: TokenStream, post_init: Option<TokenStream>) -> TokenStream {
1175    let QuoteTraitParams { attr, impl_attr, inner_attr, dst, src, these_gens, those_gens, impl_gens, where_clause, r } = get_quote_trait_params(input, ctx);
1176    let err_ty = &ctx.struct_attr.err_ty.as_ref().unwrap().path;
1177    quote! {
1178        #impl_attr
1179        impl #impl_gens o2o::traits::TryIntoExisting<#dst #those_gens> for #r #src #these_gens #where_clause {
1180            type Error = #err_ty;
1181            #attr
1182            fn try_into_existing(self, other: &mut #dst #those_gens) -> ::core::result::Result<(), #err_ty> {
1183                #inner_attr
1184                #pre_init
1185                #init
1186                #post_init
1187                Ok(())
1188            }
1189        }
1190    }
1191}
1192
1193impl<'a> ApplicableAttr<'a> {
1194    fn get_ident(&'a self) -> &'a Member {
1195        match self {
1196            ApplicableAttr::Field(MemberAttrCore { member, .. }) => match member {
1197                Some(val) => val,
1198                None => unreachable!("8"),
1199            },
1200            ApplicableAttr::ParentChildField(p, kind) => {
1201                let attr = p.get_for_kind(kind);
1202                match attr.as_ref() {
1203                    Some(attr) => match attr.that_member.as_ref() {
1204                        Some(val) => val,
1205                        None => unreachable!("18"),
1206                    },
1207                    None => unreachable!("19")
1208                }
1209            }
1210            ApplicableAttr::Ghost(_) => unreachable!("9"),
1211        }
1212    }
1213
1214    fn has_action(&self) -> bool {
1215        match self {
1216            ApplicableAttr::Field(f) => f.action.is_some(),
1217            ApplicableAttr::Ghost(g) => g.action.is_some(),
1218            ApplicableAttr::ParentChildField(p, kind) => p.get_for_kind(kind).is_some_and(|x| x.action.is_some()),
1219        }
1220    }
1221
1222    fn get_field_name_or(&'a self, field: &'a Member) -> &'a Member {
1223        match self {
1224            ApplicableAttr::Field(MemberAttrCore { member, .. }) => match member {
1225                Some(val) => val,
1226                None => field,
1227            },
1228            ApplicableAttr::Ghost(_) => unreachable!("10"),
1229            ApplicableAttr::ParentChildField(p, kind) => {
1230                let attr = p.get_for_kind(kind);
1231
1232                match attr.as_ref() {
1233                    Some(attr) =>  match attr.that_member.as_ref() {
1234                        Some(val) => val,
1235                        None => &p.this_member,
1236                    },
1237                    None => &p.this_member
1238                }
1239            }
1240        }
1241    }
1242
1243    fn get_action_or<F: Fn() -> TokenStream>(&self, field_path: Option<&TokenStream>, ctx: &ImplContext, or: F) -> TokenStream {
1244        match self {
1245            ApplicableAttr::Field(MemberAttrCore { action, .. }) => match action {
1246                Some(val) => quote_action(val, field_path, ctx),
1247                None => or(),
1248            },
1249            ApplicableAttr::ParentChildField(p, kind) => {
1250                let attr = p.get_for_kind(kind);
1251
1252                match attr.as_ref() {
1253                    Some(attr) => match attr.action.as_ref() {
1254                        Some(val) => quote_action(val, field_path, ctx),
1255                        None => or()
1256                    },
1257                    None => or()
1258                }
1259            }
1260            ApplicableAttr::Ghost(_) => unreachable!("11"),
1261        }
1262    }
1263
1264    fn get_stuff<F1: Fn(&Member) -> TokenStream, F2: Fn() -> &'a Member>(&self, obj: &TokenStream, field_path: F1, ctx: &ImplContext, or: F2) -> TokenStream {
1265        let get_stuff = |member: &Option<Member>, action: &Option<TokenStream>| {
1266            match (member, action) {
1267                (Some(ident), Some(action)) => if let Unnamed(index) = ident {
1268                        if ctx.impl_type.is_variant() {
1269                            let ident = Named(format_ident!("f{}", index.index));
1270                            quote_action(action, Some(&field_path(&ident)), ctx)
1271                        } else {
1272                            quote_action(action, Some(&field_path(ident)), ctx)
1273                        }
1274                    } else {
1275                        quote_action(action, Some(&field_path(ident)), ctx)
1276                    },
1277                (Some(ident), None) => {
1278                    let field_path = field_path(ident);
1279                    quote!(#obj #field_path)
1280                }
1281                (None, Some(action)) => quote_action(action, Some(&field_path(or())), ctx),
1282                _ => unreachable!("12"),
1283            }
1284        };
1285        match self {
1286            ApplicableAttr::Field(MemberAttrCore { member, action, .. }) => get_stuff(member, action),
1287            ApplicableAttr::ParentChildField(p, kind) => {
1288                let attr = p.get_for_kind(kind);
1289
1290                if attr.is_some_and(|x|x.that_member.is_some()) {
1291                    let attr = attr.unwrap();
1292                    get_stuff(&attr.that_member, &attr.action)
1293                } else {
1294                    get_stuff(&Some(p.this_member.clone()), attr.map_or(&None, |x| &x.action))
1295                }
1296            },
1297            ApplicableAttr::Ghost(ghost_attr) => quote_action(ghost_attr.action.as_ref().unwrap(), None, ctx),
1298        }
1299    }
1300}