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>;
}