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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Universal library for struct mapping. Provides multiple methods to
//! generate HashMaps with values of any type
//!
//! # Example problem
//!
//! Let's assume that we've got this struct
//! ```
//! struct Person {
//!     name: String
//!     /// Age in years
//!     age: usize,
//!     /// Dept in $ in the certain banks
//!     dept: BTreeMap<String, f64>,
//!     /// Amount of money in banks. Accounts in $
//!     bank_account: BTreeMap<String, f64>,
//!     /// Amount of money in the wallet in $
//!     wallet: f64,
//!     /// Amount of money in the crypto in crypto-wallets. Transformed to $
//!     crypto: BTreeMap<String, f64>
//! }
//! ```
//!
//! Now, we want to get a few info:
//! 1. `avg(&self) -> HashMap<String, f64>` returning average amount of money in every field
//! 2. `max(&self) -> HashMap<String, f64>` returning max amount of money in every field
//! 3. `info(&self) -> HashMap<String, String>` returning general information about fields
//! 4. `detail_info(&self) -> HashMap<String, String>`. Similar to 3, but with more info
//!
//! We would need to implement it manually. It's cumbersome and inconvinient. That's where
//! `context_mapper` becomes a handy tool:
//!
//! ```
//! #[derive(ContextMapper)]
//! // F64 traits
//! #[context_mapper(
//!     trait(
//!         context = p01::average,
//!         type = f64,
//!         converter = MyAvgTrait::avg,
//!         generic(
//!             name = Averager,
//!             method_name = avg
//!         )
//!     ),
//!     trait(
//!         context = p02::max,
//!         type = f64,
//!         converter = MyMaxTrait::max,
//!         simple(
//!             name = Maximizer,
//!             method_name = max
//!         )
//!     )
//! )]
//! // String traits
//! #[context_mapper(
//!     trait(
//!         context = p03::general,
//!         type = String,
//!         converter = std::string::ToString::to_string,
//!         generic(
//!             path = GenInfo,
//!             method_name = info
//!         )
//!     ),
//!     trait(
//!         context = p04::max,
//!         type = f64,
//!         converter = generic_info,
//!         simple(
//!             path = my::DetailedInfo,
//!             method_name = info
//!         )
//!     )
//! )]
//! struct Person {
//!     #[context_attribute(context(name=p01::average, skip))]
//!     #[context_attribute(context(name=p02::max, skip))]
//!     name: String
//!
//!     /// Age in years
//!     #[context_attribute(context(name=p01::average, skip))]
//!     #[context_attribute(context(name=p02::max, skip))]
//!     age: usize,
//!
//!     /// Dept in $ in the certain banks
//!     #[context_attribute(
//!         context(name=p02::max, converter=punishment::with_interests)
//!     )]
//!     dept: BTreeMap<String, f64>,
//!
//!     /// Amount of money in banks. Accounts in $
//!     bank_account: BTreeMap<String, f64>,
//!     /// Amount of money in the wallet in $
//!     wallet: f64,
//!     /// Amount of money in the crypto in crypto-wallets. Transformed to $
//!     crypto: BTreeMap<String, f64>
//! }
//! ```
//!
//! # Macros documentation
//! See [`ContextMapper`] for detailed info
//!
//! # Comparsion to similar libraries
//!
//! ## serde
//!
//! The main difference between `context_mapper` and `serde` is the approach.
//! `serde` defines single, powerful way of serializing / deserializing
//! structures, enums etc. On the other hand `context_mapper` does not enforce
//! any standard on the serialization. Its main purpose is to simplify generation of
//! the repetitive struct -> map mappings. Also, it does not support nested structures
//!
//! ## structmap
//!
//! While being inspiration for this library, `structmap` is more similar 
//! to serde, than `context_mapper`. Both libraries provide way of converision
//! of the struct to map of strings. However `structmap` allows users to convert
//! objects from map and then convert them to map. On the other hand it does not
//! allow multiple contexts (multiple maps generation)
//!
pub use context_mapper_derive::ContextMapper;
use std::collections::HashMap;

pub struct Error(pub String);
impl Error {
    pub fn new<T: std::error::Error>(s: T) -> Self {
        Self(s.to_string())
    }
}

impl<T: std::error::Error> From<T> for Error {
    fn from(value: T) -> Self {
        Self(value.to_string())
    }
}

pub trait IntoType<ContextType> {
    fn into_type_map(&self) -> HashMap<String, ContextType>;
}

pub trait TryIntoType<ContextType> {
    type Error;
    fn try_into_type_map(&self) -> Result<HashMap<String, ContextType>, Self::Error>;
}