use picojson::{Event, PullParser, SliceParser};
const REAL_WORLD_JSON: &str = r#"
{
"user_id": "u-12345",
"username": "jdoe",
"email": "jdoe@example.com",
"is_active": true,
"feature_flags": {
"new_dashboard": true,
"beta_access": false,
"experimental_api": null
},
"products": [
{
"product_id": "p-001",
"name": "Widget A",
"stock": 99,
"tags": ["gadget", "tech"]
},
{
"product_id": "p-002",
"name": "Widget B",
"stock": 150,
"tags": ["gadget", "classic"]
},
{
"product_id": "p-003",
"name": "Widget C",
"stock": 42,
"tags": ["new", "tech"]
}
],
"metadata": {
"last_login": "2025-06-29T10:00:00Z",
"notes": "A string with an escape sequence \n here."
}
}
"#;
#[derive(Default)]
struct ExtractedData {
email: Option<std::string::String>,
second_product_id: Option<std::string::String>,
new_dashboard_status: Option<bool>,
}
#[derive(PartialEq, Clone, Copy, Debug)]
enum ExtractionState {
Idle,
InProductsArray,
InFeatureFlags,
ExpectingEmail,
ExpectingProductId,
ExpectingNewDashboardStatus,
}
#[test]
fn test_selective_extraction() {
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(REAL_WORLD_JSON, &mut scratch);
let mut extracted = ExtractedData::default();
let mut state = ExtractionState::Idle;
let mut product_index = 0;
let mut array_depth = 0;
loop {
let event = match parser.next() {
Some(Ok(event)) => event,
Some(Err(e)) => panic!("Parse error: {:?}", e),
None => break, };
match event {
Event::Key(key) => {
state = match (state, &*key) {
(_, "email") => ExtractionState::ExpectingEmail,
(_, "products") => ExtractionState::InProductsArray,
(ExtractionState::InProductsArray, "product_id") => {
ExtractionState::ExpectingProductId
}
(_, "feature_flags") => ExtractionState::InFeatureFlags,
(ExtractionState::InFeatureFlags, "new_dashboard") => {
ExtractionState::ExpectingNewDashboardStatus
}
(current_state, _) => current_state,
};
}
Event::String(s) => match (state, product_index) {
(ExtractionState::ExpectingEmail, _) => {
extracted.email = Some(s.as_ref().to_owned());
state = ExtractionState::Idle;
}
(ExtractionState::ExpectingProductId, 1) => {
extracted.second_product_id = Some(s.as_ref().to_owned());
state = ExtractionState::InProductsArray;
}
(ExtractionState::ExpectingProductId, _) => {
state = ExtractionState::InProductsArray;
}
_ => {}
},
Event::Bool(b) => {
if state == ExtractionState::ExpectingNewDashboardStatus {
extracted.new_dashboard_status = Some(b);
state = ExtractionState::InFeatureFlags;
}
}
Event::StartArray => {
if state == ExtractionState::InProductsArray {
array_depth += 1;
if array_depth == 1 {
product_index = 0;
}
}
}
Event::EndObject => match state {
ExtractionState::InProductsArray => {
product_index += 1;
}
ExtractionState::InFeatureFlags => {
state = ExtractionState::Idle;
}
_ => {}
},
Event::EndArray => {
if state == ExtractionState::InProductsArray {
array_depth -= 1;
if array_depth == 0 {
state = ExtractionState::Idle;
}
}
}
_ => {}
}
}
assert_eq!(extracted.email, Some("jdoe@example.com".to_string()));
assert_eq!(extracted.second_product_id, Some("p-002".to_string()));
assert_eq!(extracted.new_dashboard_status, Some(true));
}