use serde::Deserialize;
use serde_saphyr::Error;
use std::fmt::Write as _;
use std::time::Instant;
#[derive(Debug, Deserialize)]
struct Document {
defaults: Defaults,
items: Vec<Item>,
}
#[derive(Debug, Deserialize, Clone)]
struct Defaults {
enabled: bool,
roles: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct Item {
enabled: bool,
roles: Vec<String>,
id: usize,
name: String,
details: Details,
}
#[derive(Debug, Deserialize)]
struct Details {
description: String,
notes: Vec<String>,
}
fn build_large_yaml(target_size: usize) -> String {
let mut yaml = String::with_capacity(target_size + 1024);
yaml.push_str("---\n");
yaml.push_str("defaults:\n");
yaml.push_str(" enabled: &defaults_enabled true\n");
yaml.push_str(" roles: &defaults_roles\n");
yaml.push_str(" - reader\n");
yaml.push_str(" - writer\n");
yaml.push_str("items:\n");
let mut index = 0usize;
while yaml.len() < target_size {
let mut entry = format!(
" - enabled: *defaults_enabled\n roles: *defaults_roles\n id: {index}\n name: item_{index:05}\n details:\n description: \"Item number {index:05} includes repeated notes for benchmarking performance.\"\n notes:\n"
);
for note_index in 0..20 {
let _ = writeln!(
entry,
" - \"Note {note_index:02} for item {index:05}. This is repeated content to enlarge the YAML payload size considerably.\""
);
}
yaml.push_str(&entry);
index += 1;
}
yaml
}
fn main() -> Result<(), Error> {
let target_size = 25 * 1024 * 1024; let yaml = build_large_yaml(target_size);
println!(
"Generated YAML size: {:.2} MiB ({} bytes)",
yaml.len() as f64 / (1024.0 * 1024.0),
yaml.len()
);
let many: usize = usize::MAX;
let start = Instant::now();
let document: Document = serde_saphyr::from_str_with_options(
&yaml,
serde_saphyr::options! {
budget: serde_saphyr::budget! {
max_reader_input_bytes: None,
max_events: many,
max_aliases: many,
max_anchors: many,
max_depth: many,
max_documents: many,
max_nodes: many,
max_total_scalar_bytes: many,
max_merge_keys: many,
enforce_alias_anchor_ratio: false,
alias_anchor_min_aliases: many,
alias_anchor_ratio_multiplier: many,
},
},
)?;
let elapsed = start.elapsed();
let total_notes: usize = document
.items
.iter()
.map(|item| item.details.notes.len())
.sum();
let enabled_items = document.items.iter().filter(|item| item.enabled).count();
let combined_roles: usize = document.items.iter().map(|item| item.roles.len()).sum();
let name_checksum: usize = document.items.iter().map(|item| item.name.len()).sum();
let max_id = document.items.iter().map(|item| item.id).max().unwrap_or(0);
let description_bytes: usize = document
.items
.iter()
.map(|item| item.details.description.len())
.sum();
println!("Parsed {} items in {:.2?}", document.items.len(), elapsed);
println!(
"Defaults enabled: {} (roles: {}), enabled items: {}, combined roles references: {}",
document.defaults.enabled,
document.defaults.roles.len(),
enabled_items,
combined_roles
);
println!(
"Total notes: {} (name checksum: {}, max id: {}, description bytes: {})",
total_notes, name_checksum, max_id, description_bytes
);
Ok(())
}