5 releases

new 0.2.2 Jan 15, 2025
0.2.1 Dec 9, 2024
0.2.0 Dec 9, 2024
0.1.1 Dec 5, 2024
0.1.0 Dec 5, 2024

#872 in Parser implementations

Download history 6/week @ 2024-09-25 430/week @ 2024-12-04 614/week @ 2024-12-11 676/week @ 2024-12-18 623/week @ 2024-12-25 825/week @ 2025-01-01 713/week @ 2025-01-08

2,996 downloads per month
Used in bacon

MIT license

37KB
943 lines

Introspect Query

MIT Latest Version docs Chat on Miaou

IQ (Introspect Query) lets you query standard structs, maps, enums, arrays, tuples, and nested combinations of these, to get deep values with a simple path syntax.

Values jut have to implement serde's Serialize trait. Both values and queries are dynamic, and can be provided at runtime.

IQ is efficient: the explored value isn't serialized, the Serialize trait is used to visit it and the visit goes only to the desired target, skipping other branches.

See the IQ trait for all extract functions.

use iq::IQ;
use serde::{ Deserialize, Serialize };

#[derive(Debug, Serialize)]
struct Car {
    pub engine: String,
    pub passengers: Vec<Dog>,
    pub driver: Dog,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Dog {
    pub name: String,
    pub ears: u8,
}

let car = Car {
    engine: "V8".to_string(),
    passengers: vec![
        Dog {
            name: "Roverandom".to_string(),
            ears: 1,
        },
        Dog {
            name: "Laïka".to_string(),
            ears: 2,
        },
    ],
    driver: Dog {
        name: "Rex".to_string(),
        ears: 2,
    },
};

// extract "primitive" values as strings with extract_primitive
assert_eq!(car.extract_primitive("driver.ears").unwrap(), "2");
assert_eq!(car.extract_primitive("driver.name").unwrap(), "Rex");
assert_eq!(car.extract_primitive("passengers.1.name").unwrap(), "Laïka");
assert_eq!(car.extract_primitive("passengers.1"), None); // it's not a primitive

// extract any value as Json with extract_json
assert_eq!(car.extract_json("wrong.path"), None);
assert_eq!(car.extract_json("driver.ears").unwrap(), "2");
assert_eq!(car.extract_json("driver.name").unwrap(), r#""Rex""#);
assert_eq!(
    car.extract_json("passengers.0").unwrap(),
    r#"{"name":"Roverandom","ears":1}"#
);
assert_eq!(car.extract_json("passengers.3"), None);

// extract any deserializable value with extract_value
assert_eq!(car.extract_value("driver.ears").unwrap(), Some(2));
assert_eq!(
    car.extract_value("passengers.1").unwrap(),
    Some(Dog {
        name: "Laïka".to_string(),
        ears: 2
    }),
);

// You don't have to concat tokens if you build the path
assert_eq!(
    car.extract_primitive(vec!["passengers", "0", "ears"])
        .unwrap(),
    "1"
);

// Extract functions are available both on the IQ trait and as standalone functions.
assert_eq!(iq::extract_primitive(&car, "driver.name").unwrap(), "Rex");


// If iq is compiled with the "template" feature, you get a mini templating utility
let template = iq::Template::new("{driver.name} drives a {engine} car.");
assert_eq!(template.render(&car), "Rex drives a V8 car.");

IQ also works with enums, maps, and tuples: more tests can be found in libs.rs.

Dependencies

~0.7–2MB
~42K SLoC