1use crate::{BinderInfo, Expr, Level, Name};
6
7use super::types::{
8 AnnotationTable, BiMap, ColorScheme, DiagMeta, Doc, DocBuilder, EscapeHelper, EventCounter,
9 ExprPrinter, FmtWidth, FrequencyTable, IdDispenser, IndentStyle, IntervalSet, LoopClock,
10 MemoSlot, PrettyConfig, PrettyDoc, PrettyPrinterState, PrettyTable, PrettyToken, PrintConfig,
11 SExprPrinter, ScopeStack, SimpleLruCache, Slot, SparseBitSet, StringInterner, Timestamp,
12 TokenPrinter, TypedId, WorkQueue, WorkStack,
13};
14
15pub(super) fn level_to_nat(level: &Level) -> Option<u32> {
17 match level {
18 Level::Zero => Some(0),
19 Level::Succ(l) => level_to_nat(l).map(|n| n + 1),
20 _ => None,
21 }
22}
23pub(super) fn level_to_offset(level: &Level) -> (&Level, u32) {
25 match level {
26 Level::Succ(l) => {
27 let (base, offset) = level_to_offset(l);
28 (base, offset + 1)
29 }
30 _ => (level, 0),
31 }
32}
33pub(super) fn collect_app_args(expr: &Expr) -> (&Expr, Vec<&Expr>) {
35 let mut args = Vec::new();
36 let mut e = expr;
37 while let Expr::App(f, a) = e {
38 args.push(a.as_ref());
39 e = f;
40 }
41 args.reverse();
42 (e, args)
43}
44pub fn print_expr(expr: &Expr) -> String {
46 let mut printer = ExprPrinter::new();
47 printer
48 .print(expr)
49 .expect("pretty-printer must succeed on valid expression");
50 printer.output()
51}
52pub fn print_expr_ascii(expr: &Expr) -> String {
54 let mut printer = ExprPrinter::new().with_unicode(false);
55 printer
56 .print(expr)
57 .expect("pretty-printer must succeed on valid expression");
58 printer.output()
59}
60pub fn print_expr_with_config(expr: &Expr, config: PrintConfig) -> String {
62 let mut printer = ExprPrinter::with_config(config);
63 printer
64 .print(expr)
65 .expect("pretty-printer must succeed on valid expression");
66 printer.output()
67}
68pub fn print_level(level: &Level) -> String {
70 let mut printer = ExprPrinter::new();
71 printer
72 .print_level(level)
73 .expect("pretty-printer must succeed on valid level");
74 printer.output()
75}
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::Literal;
80 #[test]
81 fn test_print_sort_prop() {
82 let expr = Expr::Sort(Level::zero());
83 let output = print_expr(&expr);
84 assert_eq!(output, "Prop");
85 }
86 #[test]
87 fn test_print_sort_type() {
88 let expr = Expr::Sort(Level::succ(Level::zero()));
89 let output = print_expr(&expr);
90 assert_eq!(output, "Type");
91 }
92 #[test]
93 fn test_print_sort_type_n() {
94 let expr = Expr::Sort(Level::succ(Level::succ(Level::zero())));
95 let output = print_expr(&expr);
96 assert_eq!(output, "Type 1");
97 }
98 #[test]
99 fn test_print_sort_param() {
100 let expr = Expr::Sort(Level::param(Name::str("u")));
101 let output = print_expr(&expr);
102 assert_eq!(output, "Sort u");
103 }
104 #[test]
105 fn test_print_bvar() {
106 let expr = Expr::BVar(0);
107 assert_eq!(print_expr(&expr), "#0");
108 }
109 #[test]
110 fn test_print_const() {
111 let expr = Expr::Const(Name::str("Nat"), vec![]);
112 assert_eq!(print_expr(&expr), "Nat");
113 }
114 #[test]
115 fn test_print_const_with_levels() {
116 let expr = Expr::Const(Name::str("List"), vec![Level::succ(Level::zero())]);
117 let config = PrintConfig::verbose();
118 let output = print_expr_with_config(&expr, config);
119 assert!(output.contains("List"));
120 assert!(output.contains("1"));
121 }
122 #[test]
123 fn test_print_lit() {
124 let expr = Expr::Lit(Literal::Nat(42));
125 assert_eq!(print_expr(&expr), "42");
126 }
127 #[test]
128 fn test_print_app() {
129 let f = Expr::Const(Name::str("f"), vec![]);
130 let a = Expr::Lit(Literal::Nat(1));
131 let app = Expr::App(Box::new(f), Box::new(a));
132 let output = print_expr(&app);
133 assert!(output.contains("f"));
134 assert!(output.contains("1"));
135 }
136 #[test]
137 fn test_print_lambda_unicode() {
138 let ty = Expr::Sort(Level::zero());
139 let body = Expr::BVar(0);
140 let lam = Expr::Lam(
141 BinderInfo::Default,
142 Name::str("x"),
143 Box::new(ty),
144 Box::new(body),
145 );
146 let output = print_expr(&lam);
147 assert!(output.contains("λ"));
148 assert!(output.contains("x"));
149 }
150 #[test]
151 fn test_print_lambda_ascii() {
152 let ty = Expr::Sort(Level::zero());
153 let body = Expr::BVar(0);
154 let lam = Expr::Lam(
155 BinderInfo::Default,
156 Name::str("x"),
157 Box::new(ty),
158 Box::new(body),
159 );
160 let output = print_expr_ascii(&lam);
161 assert!(output.contains("fun"));
162 }
163 #[test]
164 fn test_print_pi_arrow() {
165 let ty = Expr::Sort(Level::succ(Level::zero()));
166 let body = Expr::Sort(Level::succ(Level::zero()));
167 let pi = Expr::Pi(
168 BinderInfo::Default,
169 Name::str("_"),
170 Box::new(ty),
171 Box::new(body),
172 );
173 let output = print_expr(&pi);
174 assert!(output.contains("→"));
175 }
176 #[test]
177 fn test_print_pi_forall() {
178 let ty = Expr::Sort(Level::succ(Level::zero()));
179 let body = Expr::BVar(0);
180 let pi = Expr::Pi(
181 BinderInfo::Default,
182 Name::str("x"),
183 Box::new(ty),
184 Box::new(body),
185 );
186 let output = print_expr(&pi);
187 assert!(output.contains("∀"));
188 assert!(output.contains("x"));
189 }
190 #[test]
191 fn test_print_implicit_binder() {
192 let ty = Expr::Sort(Level::succ(Level::zero()));
193 let body = Expr::BVar(0);
194 let pi = Expr::Pi(
195 BinderInfo::Implicit,
196 Name::str("α"),
197 Box::new(ty),
198 Box::new(body),
199 );
200 let output = print_expr(&pi);
201 assert!(output.contains("{"));
202 assert!(output.contains("}"));
203 }
204 #[test]
205 fn test_print_inst_implicit_binder() {
206 let ty = Expr::Const(Name::str("Monad"), vec![]);
207 let body = Expr::BVar(0);
208 let pi = Expr::Pi(
209 BinderInfo::InstImplicit,
210 Name::str("m"),
211 Box::new(ty),
212 Box::new(body),
213 );
214 let output = print_expr(&pi);
215 assert!(output.contains("["));
216 assert!(output.contains("]"));
217 }
218 #[test]
219 fn test_print_level_nat() {
220 let level = Level::succ(Level::succ(Level::succ(Level::zero())));
221 let output = print_level(&level);
222 assert_eq!(output, "3");
223 }
224 #[test]
225 fn test_print_level_param_plus() {
226 let level = Level::succ(Level::param(Name::str("u")));
227 let output = print_level(&level);
228 assert_eq!(output, "u+1");
229 }
230 #[test]
231 fn test_print_level_mvar() {
232 let level = Level::MVar(crate::LevelMVarId(42));
233 let output = print_level(&level);
234 assert_eq!(output, "?u_42");
235 }
236 #[test]
237 fn test_print_config_verbose() {
238 let config = PrintConfig::verbose();
239 assert!(config.show_implicit);
240 assert!(config.show_universes);
241 }
242 #[test]
243 fn test_print_config_ascii() {
244 let config = PrintConfig::ascii();
245 assert!(!config.unicode);
246 }
247}
248#[allow(dead_code)]
250pub fn expr_to_doc(expr: &Expr) -> Doc {
251 expr_to_doc_prec(expr, 0)
252}
253pub(super) fn expr_to_doc_prec(expr: &Expr, prec: u32) -> Doc {
254 match expr {
255 Expr::Sort(level) => Doc::text(format!("Sort({})", level)),
256 Expr::BVar(i) => Doc::text(format!("#{}", i)),
257 Expr::FVar(id) => Doc::text(format!("@{}", id.0)),
258 Expr::Const(name, _) => Doc::text(name.to_string()),
259 Expr::Lit(lit) => Doc::text(format!("{}", lit)),
260 Expr::App(f, a) => {
261 let fd = expr_to_doc_prec(f, 10);
262 let ad = expr_to_doc_prec(a, 11);
263 let inner = fd.concat(Doc::text(" ")).concat(ad);
264 if prec > 10 {
265 Doc::text("(").concat(inner).concat(Doc::text(")"))
266 } else {
267 inner
268 }
269 }
270 Expr::Lam(_, name, ty, body) => {
271 let header = Doc::text(format!("fun ({} : ", name))
272 .concat(expr_to_doc_prec(ty, 0))
273 .concat(Doc::text(") -> "));
274 let bd = expr_to_doc_prec(body, 0);
275 let inner = header.concat(bd);
276 if prec > 0 {
277 Doc::text("(").concat(inner).concat(Doc::text(")"))
278 } else {
279 inner
280 }
281 }
282 Expr::Pi(_, name, ty, body) => {
283 if name.is_anonymous() || *name == Name::str("_") {
284 let td = expr_to_doc_prec(ty, 25);
285 let bd = expr_to_doc_prec(body, 24);
286 let inner = td.concat(Doc::text(" -> ")).concat(bd);
287 if prec > 0 {
288 Doc::text("(").concat(inner).concat(Doc::text(")"))
289 } else {
290 inner
291 }
292 } else {
293 let header = Doc::text(format!("forall ({} : ", name))
294 .concat(expr_to_doc_prec(ty, 0))
295 .concat(Doc::text("), "));
296 let bd = expr_to_doc_prec(body, 0);
297 let inner = header.concat(bd);
298 if prec > 0 {
299 Doc::text("(").concat(inner).concat(Doc::text(")"))
300 } else {
301 inner
302 }
303 }
304 }
305 Expr::Let(name, ty, val, body) => {
306 let line1 = Doc::text(format!("let {} : ", name))
307 .concat(expr_to_doc_prec(ty, 0))
308 .concat(Doc::text(" := "))
309 .concat(expr_to_doc_prec(val, 0));
310 let line2 = Doc::text("in ").concat(expr_to_doc_prec(body, 0));
311 Doc::Nest(2, Box::new(line1.concat(Doc::line()).concat(line2)))
312 }
313 Expr::Proj(name, idx, e) => {
314 expr_to_doc_prec(e, 11).concat(Doc::text(format!(".{}.{}", name, idx)))
315 }
316 }
317}
318#[allow(dead_code)]
320pub fn print_name_str(name: &Name) -> String {
321 name.to_string()
322}
323#[allow(dead_code)]
325pub fn is_simple_name(name: &Name) -> bool {
326 matches!(name, Name::Str(parent, _) if matches!(parent.as_ref(), Name::Anonymous))
327}
328#[allow(dead_code)]
330pub fn expr_summary(expr: &Expr) -> String {
331 match expr {
332 Expr::Sort(l) => format!("Sort({})", l),
333 Expr::BVar(i) => format!("BVar({})", i),
334 Expr::FVar(id) => format!("FVar({})", id.0),
335 Expr::Const(n, _) => format!("Const({})", n),
336 Expr::App(_, _) => {
337 let (head, args) = collect_app_args(expr);
338 format!("App({}, {} args)", expr_summary(head), args.len())
339 }
340 Expr::Lam(_, n, _, _) => format!("Lam({})", n),
341 Expr::Pi(_, n, _, _) => {
342 if n.is_anonymous() || *n == Name::str("_") {
343 "Pi(->)".to_string()
344 } else {
345 format!("Pi(forall {})", n)
346 }
347 }
348 Expr::Let(n, _, _, _) => format!("Let({})", n),
349 Expr::Lit(l) => format!("Lit({})", l),
350 Expr::Proj(n, i, _) => format!("Proj({}.{})", n, i),
351 }
352}
353#[allow(dead_code)]
355pub mod ansi {
356 pub const RESET: &str = "\x1b[0m";
358 pub const BOLD: &str = "\x1b[1m";
360 pub const DIM: &str = "\x1b[2m";
362 pub const RED: &str = "\x1b[31m";
364 pub const GREEN: &str = "\x1b[32m";
366 pub const YELLOW: &str = "\x1b[33m";
368 pub const BLUE: &str = "\x1b[34m";
370 pub const MAGENTA: &str = "\x1b[35m";
372 pub const CYAN: &str = "\x1b[36m";
374}
375#[allow(dead_code)]
379pub fn colorize(expr: &Expr) -> String {
380 match expr {
381 Expr::Sort(_) => format!("{}{}{}", ansi::BLUE, print_expr(expr), ansi::RESET),
382 Expr::Lit(_) => format!("{}{}{}", ansi::YELLOW, print_expr(expr), ansi::RESET),
383 Expr::Const(_, _) => {
384 format!("{}{}{}", ansi::GREEN, print_expr(expr), ansi::RESET)
385 }
386 _ => print_expr(expr),
387 }
388}
389#[cfg(test)]
390mod extra_prettyprint_tests {
391 use super::*;
392 use crate::Literal;
393 #[test]
394 fn test_doc_text_render() {
395 let d = Doc::text("hello");
396 assert_eq!(d.render(80), "hello");
397 }
398 #[test]
399 fn test_doc_concat() {
400 let d = Doc::text("foo").concat(Doc::text("bar"));
401 assert_eq!(d.render(80), "foobar");
402 }
403 #[test]
404 fn test_doc_line() {
405 let d = Doc::text("a").concat(Doc::line()).concat(Doc::text("b"));
406 let rendered = d.render(80);
407 assert!(rendered.contains('\n'));
408 assert!(rendered.contains('a'));
409 assert!(rendered.contains('b'));
410 }
411 #[test]
412 fn test_doc_nest() {
413 let d = Doc::nest(4, Doc::text("x").concat(Doc::line()).concat(Doc::text("y")));
414 let rendered = d.render(80);
415 if let Some(pos) = rendered.find('\n') {
416 let rest = &rendered[pos + 1..];
417 assert!(rest.starts_with(" "));
418 }
419 }
420 #[test]
421 fn test_expr_to_doc_sort() {
422 let e = Expr::Sort(Level::zero());
423 let d = expr_to_doc(&e);
424 let s = d.render(80);
425 assert_eq!(s, "Sort(0)");
426 }
427 #[test]
428 fn test_expr_to_doc_bvar() {
429 let d = expr_to_doc(&Expr::BVar(3));
430 assert_eq!(d.render(80), "#3");
431 }
432 #[test]
433 fn test_expr_to_doc_const() {
434 let d = expr_to_doc(&Expr::Const(Name::str("Nat"), vec![]));
435 assert_eq!(d.render(80), "Nat");
436 }
437 #[test]
438 fn test_expr_to_doc_app() {
439 let f = Expr::Const(Name::str("f"), vec![]);
440 let a = Expr::Lit(Literal::Nat(1));
441 let app = Expr::App(Box::new(f), Box::new(a));
442 let d = expr_to_doc(&app);
443 let s = d.render(80);
444 assert!(s.contains("f"));
445 assert!(s.contains("1"));
446 }
447 #[test]
448 fn test_expr_summary_sort() {
449 let s = expr_summary(&Expr::Sort(Level::zero()));
450 assert_eq!(s, "Sort(0)");
451 }
452 #[test]
453 fn test_expr_summary_app() {
454 let f = Expr::Const(Name::str("g"), vec![]);
455 let a = Expr::Lit(Literal::Nat(5));
456 let b = Expr::Lit(Literal::Nat(6));
457 let app = Expr::App(Box::new(Expr::App(Box::new(f), Box::new(a))), Box::new(b));
458 let s = expr_summary(&app);
459 assert!(s.contains("2 args"));
460 assert!(s.contains("g"));
461 }
462 #[test]
463 fn test_expr_summary_pi_arrow() {
464 let pi = Expr::Pi(
465 BinderInfo::Default,
466 Name::str("_"),
467 Box::new(Expr::Sort(Level::zero())),
468 Box::new(Expr::Sort(Level::zero())),
469 );
470 let s = expr_summary(&pi);
471 assert!(s.contains("->"));
472 }
473 #[test]
474 fn test_expr_summary_let() {
475 let e = Expr::Let(
476 Name::str("x"),
477 Box::new(Expr::Sort(Level::zero())),
478 Box::new(Expr::BVar(0)),
479 Box::new(Expr::BVar(0)),
480 );
481 let s = expr_summary(&e);
482 assert!(s.contains("x"));
483 }
484 #[test]
485 fn test_is_simple_name_true() {
486 let n = Name::Str(Box::new(Name::Anonymous), "foo".to_string());
487 assert!(is_simple_name(&n));
488 }
489 #[test]
490 fn test_is_simple_name_false() {
491 let n = Name::Str(
492 Box::new(Name::Str(Box::new(Name::Anonymous), "A".to_string())),
493 "b".to_string(),
494 );
495 assert!(!is_simple_name(&n));
496 }
497 #[test]
498 fn test_print_name_str() {
499 let n = Name::str("MyName");
500 assert_eq!(print_name_str(&n), "MyName");
501 }
502 #[test]
503 fn test_colorize_sort_contains_text() {
504 let e = Expr::Sort(Level::zero());
505 let c = colorize(&e);
506 assert!(c.contains("Prop") || c.contains("Sort"));
507 }
508 #[test]
509 fn test_colorize_lit_contains_number() {
510 let e = Expr::Lit(crate::Literal::Nat(42));
511 let c = colorize(&e);
512 assert!(c.contains("42"));
513 }
514 #[test]
515 fn test_print_expr_let() {
516 let e = Expr::Let(
517 Name::str("x"),
518 Box::new(Expr::Sort(Level::zero())),
519 Box::new(Expr::Lit(crate::Literal::Nat(1))),
520 Box::new(Expr::BVar(0)),
521 );
522 let s = print_expr(&e);
523 assert!(s.contains("let"));
524 assert!(s.contains("x"));
525 }
526 #[test]
527 fn test_print_expr_proj() {
528 let e = Expr::Proj(Name::str("Prod"), 0, Box::new(Expr::BVar(0)));
529 let s = print_expr(&e);
530 assert!(s.contains("Prod"));
531 }
532}
533#[cfg(test)]
534mod tests_prettyprint_extra {
535 use super::*;
536 #[test]
537 fn test_color_scheme() {
538 let cs = ColorScheme::DEFAULT;
539 assert!(cs.is_colored());
540 assert!(!ColorScheme::MONO.is_colored());
541 }
542 #[test]
543 fn test_indent_style() {
544 let s2 = IndentStyle::Spaces(2);
545 assert_eq!(s2.one_level(), " ");
546 assert_eq!(s2.for_depth(3), " ");
547 let tabs = IndentStyle::Tabs;
548 assert_eq!(tabs.one_level(), "\t");
549 }
550 #[test]
551 fn test_pretty_doc_render() {
552 let doc = PrettyDoc::concat(
553 PrettyDoc::text("fun "),
554 PrettyDoc::concat(
555 PrettyDoc::text("x"),
556 PrettyDoc::concat(PrettyDoc::text(" ->"), PrettyDoc::Newline),
557 ),
558 );
559 let rendered = doc.render(80, IndentStyle::Spaces(2));
560 assert!(rendered.contains("fun x ->"));
561 }
562 #[test]
563 fn test_pretty_token_raw() {
564 let tok = PrettyToken::Keyword("theorem".to_string());
565 assert_eq!(tok.raw_text(), "theorem");
566 let space = PrettyToken::Space;
567 assert_eq!(space.raw_text(), " ");
568 }
569 #[test]
570 fn test_token_printer() {
571 let config = PrettyConfig::default_config();
572 let printer = TokenPrinter::new(config);
573 let tokens = vec![
574 PrettyToken::Keyword("theorem".into()),
575 PrettyToken::Space,
576 PrettyToken::Ident("foo".into()),
577 ];
578 let result = printer.render(&tokens);
579 assert_eq!(result, "theorem foo");
580 }
581 #[test]
582 fn test_sexpr_printer() {
583 let p = SExprPrinter::new();
584 let s = p.app("Pi", &["x", "Nat", "body"]);
585 assert_eq!(s, "(Pi x Nat body)");
586 let empty = p.app("Unit", &[]);
587 assert_eq!(empty, "Unit");
588 }
589 #[test]
590 fn test_fmt_width() {
591 assert_eq!(FmtWidth::decimal_width(0), 1);
592 assert_eq!(FmtWidth::decimal_width(999), 3);
593 assert_eq!(FmtWidth::pad_right("hi", 5), "hi ");
594 assert_eq!(FmtWidth::pad_left("hi", 5), " hi");
595 assert_eq!(FmtWidth::center("hi", 6), " hi ");
596 }
597 #[test]
598 fn test_pretty_table() {
599 let mut tbl = PrettyTable::new(vec!["Name".into(), "Value".into()]);
600 tbl.add_row(vec!["alpha".into(), "1".into()]);
601 tbl.add_row(vec!["beta".into(), "2".into()]);
602 let rendered = tbl.render();
603 assert!(rendered.contains("Name"));
604 assert!(rendered.contains("alpha"));
605 }
606}
607#[cfg(test)]
608mod tests_prettyprint_extra2 {
609 use super::*;
610 #[test]
611 fn test_printer_state() {
612 let mut ps = PrettyPrinterState::new(80, IndentStyle::Spaces(2));
613 ps.write("hello");
614 assert_eq!(ps.col, 5);
615 ps.push_indent();
616 ps.newline();
617 assert_eq!(ps.col, 2);
618 let out = ps.finish();
619 assert!(out.contains("hello"));
620 }
621 #[test]
622 fn test_doc_builder() {
623 let doc = DocBuilder::text("fun")
624 .then_text(" x")
625 .then_text(" ->")
626 .then_newline()
627 .then_text(" body")
628 .build();
629 let rendered = doc.render(80, IndentStyle::Spaces(2));
630 assert!(rendered.contains("fun x ->"));
631 }
632}
633#[cfg(test)]
634mod tests_escape_helper {
635 use super::*;
636 #[test]
637 fn test_escape_unescape() {
638 let original = "hello\nworld\t\"end\"";
639 let escaped = EscapeHelper::escape_str(original);
640 assert!(escaped.starts_with('"'));
641 let unescaped = EscapeHelper::unescape_str(&escaped);
642 assert_eq!(unescaped, original);
643 }
644}
645#[cfg(test)]
646mod tests_common_infra {
647 use super::*;
648 #[test]
649 fn test_event_counter() {
650 let mut ec = EventCounter::new();
651 ec.inc("hit");
652 ec.inc("hit");
653 ec.inc("miss");
654 assert_eq!(ec.get("hit"), 2);
655 assert_eq!(ec.get("miss"), 1);
656 assert_eq!(ec.total(), 3);
657 ec.reset();
658 assert_eq!(ec.total(), 0);
659 }
660 #[test]
661 fn test_diag_meta() {
662 let mut m = DiagMeta::new();
663 m.add("os", "linux");
664 m.add("arch", "x86_64");
665 assert_eq!(m.get("os"), Some("linux"));
666 assert_eq!(m.len(), 2);
667 let s = m.to_string();
668 assert!(s.contains("os=linux"));
669 }
670 #[test]
671 fn test_scope_stack() {
672 let mut ss = ScopeStack::new();
673 ss.push("Nat");
674 ss.push("succ");
675 assert_eq!(ss.current(), Some("succ"));
676 assert_eq!(ss.depth(), 2);
677 assert_eq!(ss.path(), "Nat.succ");
678 ss.pop();
679 assert_eq!(ss.current(), Some("Nat"));
680 }
681 #[test]
682 fn test_annotation_table() {
683 let mut tbl = AnnotationTable::new();
684 tbl.annotate("doc", "first line");
685 tbl.annotate("doc", "second line");
686 assert_eq!(tbl.get_all("doc").len(), 2);
687 assert!(tbl.has("doc"));
688 assert!(!tbl.has("other"));
689 }
690 #[test]
691 fn test_work_stack() {
692 let mut ws = WorkStack::new();
693 ws.push(1u32);
694 ws.push(2u32);
695 assert_eq!(ws.pop(), Some(2));
696 assert_eq!(ws.len(), 1);
697 }
698 #[test]
699 fn test_work_queue() {
700 let mut wq = WorkQueue::new();
701 wq.enqueue(1u32);
702 wq.enqueue(2u32);
703 assert_eq!(wq.dequeue(), Some(1));
704 assert_eq!(wq.len(), 1);
705 }
706 #[test]
707 fn test_sparse_bit_set() {
708 let mut bs = SparseBitSet::new(128);
709 bs.set(5);
710 bs.set(63);
711 bs.set(64);
712 assert!(bs.get(5));
713 assert!(bs.get(63));
714 assert!(bs.get(64));
715 assert!(!bs.get(0));
716 assert_eq!(bs.count_ones(), 3);
717 bs.clear(5);
718 assert!(!bs.get(5));
719 }
720 #[test]
721 fn test_loop_clock() {
722 let mut clk = LoopClock::start();
723 for _ in 0..10 {
724 clk.tick();
725 }
726 assert_eq!(clk.iters(), 10);
727 assert!(clk.elapsed_us() >= 0.0);
728 }
729}
730#[cfg(test)]
731mod tests_extra_data_structures {
732 use super::*;
733 #[test]
734 fn test_simple_lru_cache() {
735 let mut cache: SimpleLruCache<&str, u32> = SimpleLruCache::new(3);
736 cache.put("a", 1);
737 cache.put("b", 2);
738 cache.put("c", 3);
739 assert_eq!(cache.get(&"a"), Some(&1));
740 cache.put("d", 4);
741 assert!(cache.len() <= 3);
742 }
743 #[test]
744 fn test_string_interner() {
745 let mut si = StringInterner::new();
746 let id1 = si.intern("hello");
747 let id2 = si.intern("hello");
748 assert_eq!(id1, id2);
749 let id3 = si.intern("world");
750 assert_ne!(id1, id3);
751 assert_eq!(si.get(id1), Some("hello"));
752 assert_eq!(si.len(), 2);
753 }
754 #[test]
755 fn test_frequency_table() {
756 let mut ft = FrequencyTable::new();
757 ft.record("a");
758 ft.record("b");
759 ft.record("a");
760 ft.record("a");
761 assert_eq!(ft.freq(&"a"), 3);
762 assert_eq!(ft.freq(&"b"), 1);
763 assert_eq!(ft.most_frequent(), Some((&"a", 3)));
764 assert_eq!(ft.total(), 4);
765 assert_eq!(ft.distinct(), 2);
766 }
767 #[test]
768 fn test_bimap() {
769 let mut bm: BiMap<u32, &str> = BiMap::new();
770 bm.insert(1, "one");
771 bm.insert(2, "two");
772 assert_eq!(bm.get_b(&1), Some(&"one"));
773 assert_eq!(bm.get_a(&"two"), Some(&2));
774 assert_eq!(bm.len(), 2);
775 }
776}
777#[cfg(test)]
778mod tests_interval_set {
779 use super::*;
780 #[test]
781 fn test_interval_set() {
782 let mut s = IntervalSet::new();
783 s.add(1, 5);
784 s.add(3, 8);
785 assert_eq!(s.num_intervals(), 1);
786 assert_eq!(s.cardinality(), 8);
787 assert!(s.contains(4));
788 assert!(!s.contains(9));
789 s.add(10, 15);
790 assert_eq!(s.num_intervals(), 2);
791 }
792}
793#[allow(dead_code)]
795pub fn now_us() -> Timestamp {
796 let us = std::time::SystemTime::UNIX_EPOCH
797 .elapsed()
798 .map(|d| d.as_micros() as u64)
799 .unwrap_or(0);
800 Timestamp::from_us(us)
801}
802#[cfg(test)]
803mod tests_typed_utilities {
804 use super::*;
805 #[test]
806 fn test_timestamp() {
807 let t1 = Timestamp::from_us(1000);
808 let t2 = Timestamp::from_us(1500);
809 assert_eq!(t2.elapsed_since(t1), 500);
810 assert!(t1 < t2);
811 }
812 #[test]
813 fn test_typed_id() {
814 struct Foo;
815 let id: TypedId<Foo> = TypedId::new(42);
816 assert_eq!(id.raw(), 42);
817 assert_eq!(format!("{id}"), "#42");
818 }
819 #[test]
820 fn test_id_dispenser() {
821 struct Bar;
822 let mut disp: IdDispenser<Bar> = IdDispenser::new();
823 let a = disp.next();
824 let b = disp.next();
825 assert_eq!(a.raw(), 0);
826 assert_eq!(b.raw(), 1);
827 assert_eq!(disp.count(), 2);
828 }
829 #[test]
830 fn test_slot() {
831 let mut slot: Slot<u32> = Slot::empty();
832 assert!(!slot.is_filled());
833 slot.fill(99);
834 assert!(slot.is_filled());
835 assert_eq!(slot.get(), Some(&99));
836 let v = slot.take();
837 assert_eq!(v, Some(99));
838 assert!(!slot.is_filled());
839 }
840 #[test]
841 #[should_panic]
842 fn test_slot_double_fill() {
843 let mut slot: Slot<u32> = Slot::empty();
844 slot.fill(1);
845 slot.fill(2);
846 }
847 #[test]
848 fn test_memo_slot() {
849 let mut ms: MemoSlot<u32> = MemoSlot::new();
850 assert!(!ms.is_cached());
851 let val = ms.get_or_compute(|| 42);
852 assert_eq!(*val, 42);
853 assert!(ms.is_cached());
854 ms.invalidate();
855 assert!(!ms.is_cached());
856 }
857}