1use std::fmt::Write as _;
23use std::time::{Duration, Instant};
24
25use leaf_ffi::LeafDoc;
26
27fn main() {
28 let mut args = std::env::args().skip(1);
29 let source = match args.next().as_deref() {
30 Some("--dump") => {
33 let path = args.next().expect("--dump takes a path");
34 std::fs::write(&path, generated()).unwrap_or_else(|e| panic!("{path}: {e}"));
35 return;
36 }
37 Some(path) => std::fs::read_to_string(path).unwrap_or_else(|e| panic!("{path}: {e}")),
38 None => generated(),
39 };
40 let words = source.split_whitespace().count();
41 let profile = if cfg!(debug_assertions) {
42 "dev"
43 } else {
44 "release"
45 };
46 println!(
47 "document: {} bytes, {words} words · profile: {profile}\n",
48 source.len()
49 );
50
51 let open = Instant::now();
52 let doc = LeafDoc::new(source.clone(), "markdown".into()).expect("parse");
53 let opened = open.elapsed();
54 let first = Instant::now();
55 let view = doc.set_unwrapped();
56 let first_view = first.elapsed();
57 let runs: usize = view.rows.iter().map(|r| r.runs.len()).sum();
58 println!("rows: {} · runs: {runs}", view.rows.len());
59 println!("{:<52} {:>10}", "open (twig parse)", fmt(opened));
60 println!(
61 "{:<52} {:>10}",
62 "first view (build the map + the frame)",
63 fmt(first_view)
64 );
65
66 let len = doc.doc_end_offset();
67 let mid = len / 2;
68 let mid_utf16 = doc.utf16_index_for_offset(mid);
69 let mid_row = doc.pos_for_offset(mid).row;
70
71 row("view() — the whole frame, unchanged", || {
73 std::hint::black_box(doc.view());
74 });
75 row("pos_for_offset (mid-document)", || {
76 std::hint::black_box(doc.pos_for_offset(mid));
77 });
78 row("utf16_index_for_offset (mid-document)", || {
79 doc.utf16_index_for_offset(mid);
80 });
81 row("offset_for_utf16_index (mid-document)", || {
82 doc.offset_for_utf16_index(mid_utf16);
83 });
84 row("text_in_range (whole document)", || {
85 std::hint::black_box(doc.text_in_range(0, len));
86 });
87 row("counts", || {
88 std::hint::black_box(doc.counts());
89 });
90
91 row("click_ch (place the caret)", || {
93 std::hint::black_box(doc.click_ch(mid_row, 3, false));
94 });
95 row("click_ch extend (grow a selection)", || {
96 doc.click_ch(mid_row, 0, false);
97 std::hint::black_box(doc.click_ch(mid_row + 4, 0, true));
98 });
99 doc.click_ch(mid_row, 3, false);
100 row("selection_counts (rows selected)", || {
101 doc.click_ch(mid_row, 0, false);
102 doc.click_ch(mid_row + 4, 0, true);
103 std::hint::black_box(doc.selection_counts());
104 });
105 doc.click_ch(mid_row, 3, false);
106 row("insert one character", || {
107 std::hint::black_box(doc.insert("x".into()));
108 });
109 row("utf16_index_for_offset (first after an edit)", || {
113 doc.insert("x".into());
114 doc.utf16_index_for_offset(mid);
115 });
116 row("newline", || {
117 std::hint::black_box(doc.newline());
118 });
119
120 let inc = LeafDoc::new(source, "markdown".into()).expect("parse");
125 inc.set_incremental_frames(true);
126 let _ = inc.set_unwrapped();
127 let lifted = inc.click_ch(mid_row, 3, false).rows.len();
128 row(
129 &format!("click_ch, as a change ({lifted} rows lifted)"),
130 || {
131 std::hint::black_box(inc.click_ch(mid_row, 3, false));
132 },
133 );
134 let lifted = inc.insert("x".into()).rows.len();
135 row(
136 &format!("insert one character, as a change ({lifted} rows lifted)"),
137 || {
138 std::hint::black_box(inc.insert("x".into()));
139 },
140 );
141 inc.click_ch(mid_row, 0, false);
142 let lifted = inc.click_ch(mid_row + 4, 0, true).rows.len();
143 row(
144 &format!("click_ch extend, as a change ({lifted} rows lifted)"),
145 || {
146 inc.click_ch(mid_row, 0, false);
147 std::hint::black_box(inc.click_ch(mid_row + 4, 0, true));
148 },
149 );
150}
151
152fn row(label: &str, mut f: impl FnMut()) {
154 let mut samples: Vec<Duration> = (0..7)
155 .map(|_| {
156 let t = Instant::now();
157 f();
158 t.elapsed()
159 })
160 .collect();
161 samples.sort();
162 println!("{label:<52} {:>10}", fmt(samples[samples.len() / 2]));
163}
164
165fn fmt(d: Duration) -> String {
166 let us = d.as_micros();
167 if us >= 10_000 {
168 format!("{:.1} ms", us as f64 / 1000.0)
169 } else {
170 format!("{us} µs")
171 }
172}
173
174fn generated() -> String {
178 let words: Vec<&str> = "the document carries its own identity and a reference resolves \
179 against whatever archive holds it so that moving a file between checkouts changes \
180 nothing a reader can see each node names its root which is what lets a foreign \
181 parent stand in for a path nobody has written down yet"
182 .split_whitespace()
183 .collect();
184 let mut out = String::from("# A generated design document\n\n");
185 let mut w = 0usize;
186 let mut para = 0usize;
187 while w < 14_000 {
188 if para.is_multiple_of(9) {
189 let _ = writeln!(out, "## Section {}\n", para / 9 + 1);
190 }
191 match para % 11 {
192 7 => {
193 for i in 0..5 {
194 let _ = writeln!(out, "- item {i} with `code_{i}` and *emphasis* in it");
195 w += 8;
196 }
197 out.push('\n');
198 }
199 9 => {
200 out.push_str("| key | value | note |\n|---|---|---|\n");
201 for i in 0..4 {
202 let _ = writeln!(out, "| `k{i}` | value {i} | a short note |");
203 w += 6;
204 }
205 out.push('\n');
206 }
207 10 => {
208 out.push_str("```rust\nfn example() -> u32 {\n 42\n}\n```\n\n");
209 w += 6;
210 }
211 _ => {
212 let n = 40 + (para * 17) % 90;
213 for i in 0..n {
214 let word = words[(para * 7 + i * 3) % words.len()];
215 match (para + i) % 23 {
216 0 => {
217 let _ = write!(out, "`{word}_{i}` ");
218 }
219 5 => {
220 let _ = write!(out, "*{word}* ");
221 }
222 11 => {
223 let _ = write!(out, "[{word}](https://example.org/{para}/{i}) ");
224 }
225 17 => {
226 let _ = write!(out, "**{word}** ");
227 }
228 _ => {
229 out.push_str(word);
230 out.push(' ');
231 }
232 }
233 }
234 w += n;
235 out.push_str("\n\n");
236 }
237 }
238 para += 1;
239 }
240 out
241}