1use std::collections::BTreeMap;
2use std::time::Instant;
3
4use dynamic::{Dynamic, ToYaml};
5
6fn gen_node(depth: i64, idx: i64) -> Dynamic {
7 let mut m: BTreeMap<smol_str::SmolStr, Dynamic> = BTreeMap::new();
8 m.insert("id".into(), Dynamic::I64(idx));
9 m.insert("name".into(), Dynamic::String(format!("user_{idx}").into()));
10 m.insert(
11 "email".into(),
12 Dynamic::String(format!("user{idx}@example.com").into()),
13 );
14 m.insert("active".into(), Dynamic::Bool(idx % 3 == 0));
15 m.insert("score".into(), Dynamic::F64((idx as f64) * 7.0 / 13.0));
16 let tags = vec![
17 Dynamic::String(format!("tag_{}", idx % 5).into()),
18 Dynamic::String(format!("tag_{}", idx % 7).into()),
19 ];
20 m.insert("tags".into(), Dynamic::list(tags));
21 if depth > 0 && idx % 10 == 0 {
22 let mut children = Vec::new();
23 for i in 0..3 {
24 children.push(gen_node(depth - 1, idx * 1000 + i));
25 }
26 m.insert("children".into(), Dynamic::list(children));
27 } else {
28 m.insert("note".into(), Dynamic::String("leaf node".into()));
29 }
30 Dynamic::map(m)
31}
32
33fn gen_dataset(n: i64) -> Dynamic {
34 let mut root: BTreeMap<smol_str::SmolStr, Dynamic> = BTreeMap::new();
35 root.insert("version".into(), Dynamic::String("1.0".into()));
36 root.insert(
37 "generated_at".into(),
38 Dynamic::String("2026-07-08T19:51:00Z".into()),
39 );
40 root.insert("count".into(), Dynamic::I64(n));
41 let mut users = Vec::new();
42 for i in 0..n {
43 users.push(gen_node(0, i));
44 }
45 root.insert("users".into(), Dynamic::list(users));
46 Dynamic::map(root)
47}
48
49fn main() {
50 for &size in &[1_000_i64, 10_000, 100_000] {
51 let t0 = Instant::now();
52 let data = gen_dataset(size);
53 let build_ms = t0.elapsed().as_millis();
54
55 let t1 = Instant::now();
56 let yaml = data.to_yaml_string();
57 let emit_ms = t1.elapsed().as_millis();
58 let yaml_len = yaml.len();
59
60 let t2 = Instant::now();
61 let back = match Dynamic::from_yaml_buf(yaml.as_bytes()) {
62 Ok(v) => v,
63 Err(e) => {
64 println!("parse error: {e}");
65 return;
66 }
67 };
68 let parse_ms = t2.elapsed().as_millis();
69
70 let back_count = back.get_dynamic("count").and_then(|v| v.as_int());
71 let back_users = back.get_dynamic("users");
72 let back_users_len = back_users.as_ref().map(|v| v.len()).unwrap_or(0);
73 let ok = back_count == Some(size) && back_users_len as i64 == size;
74
75 println!("---");
76 println!("size: {}", size);
77 println!("build: {} ms", build_ms);
78 println!(
79 "to_yaml: {} ms ({} bytes, {:.1} bytes/node)",
80 emit_ms,
81 yaml_len,
82 yaml_len as f64 / size as f64
83 );
84 println!(
85 "from_yaml: {} ms ({:.0} bytes/ms)",
86 parse_ms,
87 yaml_len as f64 / parse_ms.max(1) as f64
88 );
89 println!(
90 "round-trip: {}",
91 if ok { "ok" } else { "FAIL" }
92 );
93 }
94}