#key-pair #pair #key-value

guzzle

A derivable trait for consuming key value pairs into structs

2 releases (1 stable)

1.0.0 Jan 7, 2020
0.1.0 Sep 2, 2019

#2166 in Data structures

MIT license

20KB
227 lines

Guzzle

GitHub release GitHub license

What is is?

Guzzle is a Custom Derive that will help you pass a stream of keys and values into a struct.

Usage

Derive Guzzle, then use the attribute tags to annotate your struct

use guzzle::Guzzle;

#[derive(Default, Guzzle)]
struct GuzzleExample {
    /// This field is annotated with no_guzzle, therefore it will not be parsed by guzzle
    #[no_guzzle]
    ignored: String,

    /// This field is not annotated, so if a key matches the field name, it will set the value
    basic: String,

    /// This field is annotated, but with no keys, so it uses the field name as a key
    /// Currently `#[guzzle]` doesn't do anything different to the default behavior (see
    /// above), but in the future the default behaviour may be toggleable.
    #[guzzle]
    basic_too: String,

    /// This field may be filled from multiple keys
    #[guzzle(keys = ["one", "two"])]
    listed_keys: String,

    /// This field is not a string, you must provider a parser that will transform it into
    /// the correct type
    #[guzzle(parser = u64_parser)]
    other_types: u64,

    /// This field isn't a string and has multiple keys
    #[guzzle(parser = u64_parser, keys = ["three", "four"])]
    other_types_with_listed_keys: u64,

    /// Guzzle will wire up this field so that data being guzzled by the `GuzzleExample`
    /// will first be sent to the `TypeThatAlsoImplementsGuzzle`. If the
    /// `TypeThatAlsoImplementsGuzzle` consumes the value, `GuzzleExample` will not.
    #[deep_guzzle]
    recurse_guzzle_to_populate_this_field: TypeThatAlsoImplementsGuzzle,
}

// This is the deeply nested `TypeThatAlsoImplementsGuzzle`
#[derive(Default, Guzzle)]
struct TypeThatAlsoImplementsGuzzle {
    /// This struct represents some deeply nested data
    #[guzzle(keys = ["deep_data"], parser = bool_parser)]
    deeply_nested_data: bool
}

// These are the parsers referenced above
fn u64_parser(s: String) -> u64 {
    s.parse().unwrap()
}
fn bool_parser(s: String) -> bool {
    s.parse().unwrap()
}

// These are our keys and values
let example_data: Vec<(&str, String)> = vec![
    ("basic", "basic info".to_string()),
    ("basic_too", "more basic info".to_string()),
    ("one", "1".to_string()),
    ("two", "2".to_string()),
    ("other_types", "20".to_string()),
    ("three", "3".to_string()),
    ("four", "4".to_string()),
    ("ignored", "ignored data".to_string()),
    ("deep_data", "true".to_string())
];

// Create our object
let mut guzzle_example = GuzzleExample::default();

// Feed our keys and values to our object, capturing any that weren't consumed
let remaining_data: Vec<(&str, String)> = example_data
    .into_iter()
    .filter_map(|v| guzzle_example.guzzle(v))
    .collect();

// All appropriate fields are now set
assert_eq!(guzzle_example.basic, "basic info".to_string());
assert_eq!(guzzle_example.basic_too, "more basic info".to_string());
assert_eq!(guzzle_example.listed_keys, "2".to_string());
assert_eq!(guzzle_example.other_types, 20);
assert_eq!(guzzle_example.other_types_with_listed_keys, 4);

// Including the deeply nested field
assert!(guzzle_example.recurse_guzzle_to_populate_this_field.deeply_nested_data);

// Ignored data is left over
assert!(guzzle_example.ignored.is_empty());
assert_eq!(remaining_data, vec![("ignored", "ignored data".to_string())]);

Example Use Case

This project came out of a need to take Wordpress metadata data and put it into complex Rust structs.

Dependencies

~1.3–1.9MB
~43K SLoC