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 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 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("e!(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("e!(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("e!(#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("e!(#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 ¶m.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}