1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use std::error::Error;

use quote::quote;
use syn::{parse_quote, Stmt};

use crate::{ConstructableStructure, EnumStructure, Structure, TypeOfSelf};

/// A intermediate type that wraps a [Structure]
pub struct Item<'a> {
    pub structure: &'a mut Structure,
    pub self_type: TypeOfSelf,
}

impl Item<'_> {
    /// Evaluates every constructable form of item and asks to produce a vector of statements to operate on item
    pub fn map_constructable(
        &mut self,
        cb: impl for<'a> Fn(ConstructableStructure<'a>) -> Result<Vec<Stmt>, Box<dyn Error>>,
    ) -> Result<Vec<Stmt>, Box<dyn Error>> {
        let type_of_self = self.self_type;
        match self.structure {
            Structure::Enum(EnumStructure {
                attrs: ref enum_attrs,
                variants,
                ..
            }) => {
                let branches = variants
                    .iter_mut()
                    .map(|variant| {
                        let result = cb(ConstructableStructure::EnumVariant(variant, enum_attrs));
                        match result {
                            Ok(lines) => {
                                let pattern = variant
                                    .fields
                                    .to_pattern(variant.full_path.clone(), type_of_self);
                                Ok(quote!( #pattern => {
                                    #(#lines)*
                                }))
                            }
                            Err(err) => Err(err),
                        }
                    })
                    .collect::<Result<Vec<_>, _>>()?;

                Ok(vec![parse_quote!(match self {
                    #(#branches)*
                })])
            }
            Structure::Struct(r#struct) => {
                let result = cb(ConstructableStructure::Struct(r#struct));
                match result {
                    Ok(mut lines) => {
                        let pattern = r#struct
                            .fields
                            .to_pattern(r#struct.name.clone().into(), self.self_type);
                        let destructuring_stmt = parse_quote! {
                            let #pattern = self;
                        };
                        lines.insert(0, destructuring_stmt);
                        Ok(lines)
                    }
                    Err(err) => Err(err),
                }
            }
        }
    }
}