# structmap [![Actions][actions-badge]][actions-url] [![crates.io version][crates-structmap-badge]][crates-structmap] [![Docs][docs-badge]][docs.rs] [actions-badge]: https://github.com/ex0dus-0x/structmap/workflows/CI/badge.svg?branch=master [actions-url]: https://github.com/ex0dus-0x/structmap/actions [crates-structmap-badge]: https://img.shields.io/crates/v/structmap.svg [crates-structmap]: https://crates.io/crates/structmap [docs-badge]: https://docs.rs/structmap/badge.svg [docs.rs]: https://docs.rs/structmap Procedural macro crate for converting between Rust `struct` types and associative containers. ```rust use std::collections::BTreeMap; // converting between a struct like ... struct SomeData { key: String } // ... and a BTreeMap like ... let somedata_hm: BTreeMap = BTreeMap::new(); ``` This removes the need to pattern match on attributes and keys when making a conversion. This was largely inspired by [previous work](https://cprimozic.net/blog/writing-a-hashmap-to-struct-procedural-macro-in-rust/) done by [@Ameobea](https://github.com/Ameobea), but extends on it much further to support conversion both ways, generic value types, and Rust 2018 conventions. ## Usage In your `Cargo.toml` file, include the crate as so: ```toml [dependencies] structmap = "0.1" ``` Now let's demonstrate conversion! Note that your `struct` type should extend the `Default` trait for type conversion to account for uninitialized attributes. __structmap__ supports conversion between two types of map aliases: 1. `StringMap` - Strings for both keys and values. Conversion is supported only one-way at the moment from struct to BTreeMap, but not the other way around. 2. `GenericMap` - Generic [serde](https://docs.serde.rs/serde_json/enum.Value.html)-style `Value`s as values. Conversion is supported both ways, but limited. ### Map to Struct ```rust use structmap::FromMap; use structmap_derive::FromMap; #[derive(FromMap)] struct TestStruct { name: String, value: i64, } impl Default for TestStruct { fn default() -> Self { Self { name: String::new(), value: 0 } } } fn main() { // create a hashmap with key-value pairs let mut hm = GenericMap::new(); // `Value` is an enum wrapper to support genericized types, to support structs // with varying types for their fields. hm.insert(String::from("name"), Value::new(String::from("example"))); hm.insert(String::from("value"), Value::new(0_i64)); // convert hashmap to struct, and check attributes let test: TestStruct = TestStruct::from_genericmap(hm); assert!(test.name == "example"); assert!(test.value == 0); } ``` ### Struct to Map ```rust use structmap::{ToMap, value::Value}; use structmap_derive::ToMap; use std::collections::BTreeMap; #[derive(ToMap, Default)] struct TestStruct { name: String, value: i64, } // impl Default ... fn main() { let test_struct = TestStruct { name: String::from("example"), value: 0, }; // convert struct to generic map, and check attributes let hm: BTreeMap = TestStruct::to_genericmap(test_struct); assert!(hm.get("name").unwrap().string().unwrap() == "example"); assert!(hm.get("value").unwrap().i64().unwrap() == 0); let test_struct = TestStruct { name: String::from("example"), value: 0, }; // convert struct to string map, and check attributes let hm: BTreeMap = TestStruct::to_stringmap(test_struct); assert!(hm.get("name").unwrap() == "example"); assert!(hm.get("value").unwrap() == "0"); } ``` Need a different key name when converting from a `struct` to a map container? Use `#[rename]` for struct attributes! ```rust use structmap::ToMap; use structmap_derive::ToMap; #[derive(ToMap, Default)] struct TestStruct { #[rename(name = "Full Name")] name: String, #[rename(name = "Data")] value: String, } ``` ## Contributions All complex types, include dynamic arrays, `Option`s, `Result`s and data structures are not yet supported (which you can help implement!). Feel free to let me know if there are any outstanding features that should be implemented! ## License [MIT License](https://codemuch.tech/license.txt)