context_mapper/lib.rs
1//! Universal library for struct mapping. Provides multiple methods to
2//! generate HashMaps with values of any type
3//!
4//! # Example problem
5//!
6//! Let's assume that we've got this struct
7//! ```
8//! struct Person {
9//! name: String
10//! /// Age in years
11//! age: usize,
12//! /// Dept in $ in the certain banks
13//! dept: BTreeMap<String, f64>,
14//! /// Amount of money in banks. Accounts in $
15//! bank_account: BTreeMap<String, f64>,
16//! /// Amount of money in the wallet in $
17//! wallet: f64,
18//! /// Amount of money in the crypto in crypto-wallets. Transformed to $
19//! crypto: BTreeMap<String, f64>
20//! }
21//! ```
22//!
23//! Now, we want to get a few info:
24//! 1. `avg(&self) -> HashMap<String, f64>` returning average amount of money in every field
25//! 2. `max(&self) -> HashMap<String, f64>` returning max amount of money in every field
26//! 3. `info(&self) -> HashMap<String, String>` returning general information about fields
27//! 4. `detail_info(&self) -> HashMap<String, String>`. Similar to 3, but with more info
28//!
29//! We would need to implement it manually. It's cumbersome and inconvinient. That's where
30//! `context_mapper` becomes a handy tool:
31//!
32//! ```
33//! #[derive(ContextMapper)]
34//! // F64 traits
35//! #[context_mapper(
36//! trait(
37//! context = p01::average,
38//! type = f64,
39//! converter = MyAvgTrait::avg,
40//! generic(
41//! name = Averager,
42//! method_name = avg
43//! )
44//! ),
45//! trait(
46//! context = p02::max,
47//! type = f64,
48//! converter = MyMaxTrait::max,
49//! simple(
50//! name = Maximizer,
51//! method_name = max
52//! )
53//! )
54//! )]
55//! // String traits
56//! #[context_mapper(
57//! trait(
58//! context = p03::general,
59//! type = String,
60//! converter = std::string::ToString::to_string,
61//! generic(
62//! path = GenInfo,
63//! method_name = info
64//! )
65//! ),
66//! trait(
67//! context = p04::max,
68//! type = f64,
69//! converter = generic_info,
70//! simple(
71//! path = my::DetailedInfo,
72//! method_name = info
73//! )
74//! )
75//! )]
76//! struct Person {
77//! #[context_attribute(context(name=p01::average, skip))]
78//! #[context_attribute(context(name=p02::max, skip))]
79//! name: String
80//!
81//! /// Age in years
82//! #[context_attribute(context(name=p01::average, skip))]
83//! #[context_attribute(context(name=p02::max, skip))]
84//! age: usize,
85//!
86//! /// Dept in $ in the certain banks
87//! #[context_attribute(
88//! context(name=p02::max, converter=punishment::with_interests)
89//! )]
90//! dept: BTreeMap<String, f64>,
91//!
92//! /// Amount of money in banks. Accounts in $
93//! bank_account: BTreeMap<String, f64>,
94//! /// Amount of money in the wallet in $
95//! wallet: f64,
96//! /// Amount of money in the crypto in crypto-wallets. Transformed to $
97//! crypto: BTreeMap<String, f64>
98//! }
99//! ```
100//!
101//! # Macros documentation
102//! See [`ContextMapper`] for detailed info
103//!
104//! # Comparsion to similar libraries
105//!
106//! ## serde
107//!
108//! The main difference between `context_mapper` and `serde` is the approach.
109//! `serde` defines single, powerful way of serializing / deserializing
110//! structures, enums etc. On the other hand `context_mapper` does not enforce
111//! any standard on the serialization. Its main purpose is to simplify generation of
112//! the repetitive struct -> map mappings. Also, it does not support nested structures
113//!
114//! ## structmap
115//!
116//! While being inspiration for this library, `structmap` is more similar
117//! to serde, than `context_mapper`. Both libraries provide way of converision
118//! of the struct to map of strings. However `structmap` allows users to convert
119//! objects from map and then convert them to map. On the other hand it does not
120//! allow multiple contexts (multiple maps generation)
121//!
122pub use context_mapper_derive::ContextMapper;
123use std::collections::HashMap;
124
125pub struct Error(pub String);
126impl Error {
127 pub fn new<T: std::error::Error>(s: T) -> Self {
128 Self(s.to_string())
129 }
130}
131
132impl<T: std::error::Error> From<T> for Error {
133 fn from(value: T) -> Self {
134 Self(value.to_string())
135 }
136}
137
138pub trait IntoType<ContextType> {
139 fn into_type_map(&self) -> HashMap<String, ContextType>;
140}
141
142pub trait TryIntoType<ContextType> {
143 type Error;
144 fn try_into_type_map(&self) -> Result<HashMap<String, ContextType>, Self::Error>;
145}