#mapper #maps #generate #different #mapping #context #macro

context-mapper

Single rust macro for generating different maps

2 releases

0.1.1 Feb 5, 2024
0.1.0 Feb 4, 2024

#1867 in Rust patterns

MIT and GPL-3.0-only

10KB
89 lines

Context Mapper

Single rust macro for generating different maps

Example

#[derive(ContextMapper)]
#[context_mapper(
    impl(
        context = info::general
        converter = MyConv::to_info,
        type = info::Info,
        fn = general_info
        vis = pub(crate)
    ),
    function(
        context = info::all
        converter = MyConv::to_info,
        type = info::Info,
        fn = all_info
    ),

)]
struct Person {
    name: String,
    address: info::Address,
    age: usize,

    /// Let's hide it for the geneal info, but show for the rest
    #[context_attribute(context(name=info::general, skip))]
    is_a_reptile: bool
}

//

let person = Person {
    //
};

person.general_info();
all_info(&person);

lib.rs:

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)

Dependencies

~0.7–1.1MB
~21K SLoC