1#![allow(unused_imports)]
2
3#![forbid(unsafe_code)]
264#![allow(missing_docs)]
265#![warn(clippy::all)]
266
267pub mod arena;
268pub mod expr;
269pub mod level;
270pub mod name;
271
272pub use arena::{Arena, Idx};
274pub use expr::{BinderInfo, Expr, FVarId, Literal};
275pub use level::{Level, LevelMVarId};
276pub use name::Name;
277pub mod subst;
278
279pub use subst::{abstract_expr, instantiate};
280pub mod env;
281pub mod reduce;
282
283pub use env::{Declaration, EnvError, Environment};
284pub use reduce::{reduce_nat_op, Reducer, ReducibilityHint};
285pub mod error;
286pub mod infer;
287
288pub mod r#abstract;
290pub mod declaration;
291pub mod equiv_manager;
292pub mod expr_cache;
293pub mod expr_util;
294pub mod instantiate;
295
296pub use declaration::{
297 instantiate_level_params, AxiomVal, ConstantInfo, ConstantVal, ConstructorVal,
298 DefinitionSafety, DefinitionVal, InductiveVal, OpaqueVal, QuotKind, QuotVal, RecursorRule,
299 RecursorVal, TheoremVal,
300};
301pub use equiv_manager::EquivManager;
302
303pub use error::KernelError;
304pub use infer::{LocalDecl, TypeChecker};
305pub mod abstract_interp;
306pub mod alpha;
307pub mod axiom;
308pub mod beta;
309pub mod builtin;
310pub mod check;
311pub mod congruence;
312pub mod context;
313pub mod conversion;
314pub mod def_eq;
315pub mod eta;
316pub mod export;
317pub mod inductive;
318pub mod match_compile;
319pub mod normalize;
320pub mod prettyprint;
321pub mod proof;
322pub mod quotient;
323pub mod reduction;
324pub mod serial;
325pub mod simp;
326pub mod struct_eta;
327pub mod substitution;
328pub mod termination;
329pub mod trace;
330pub mod type_erasure;
331pub mod typeclasses;
332pub mod universe;
333pub mod whnf;
334
335pub mod bench_support;
337pub mod cache;
339pub mod ffi;
341pub mod no_std_compat;
343
344pub use alpha::{alpha_equiv, canonicalize};
345pub use axiom::{
346 classify_axiom, extract_axioms, has_unsafe_dependencies, transitive_axiom_deps, AxiomSafety,
347 AxiomValidator,
348};
349pub use beta::{beta_normalize, beta_step, beta_under_binder, is_beta_normal, mk_beta_redex};
350pub use builtin::{init_builtin_env, is_nat_op, is_string_op};
351pub use check::{check_constant_info, check_constant_infos, check_declaration, check_declarations};
352pub use congruence::{
353 mk_congr_theorem, mk_congr_theorem_with_fixed, CongrArgKind, CongruenceClosure,
354 CongruenceTheorem,
355};
356pub use context::{ContextSnapshot, NameGenerator};
357pub use conversion::ConversionChecker;
358pub use def_eq::{is_def_eq_simple, DefEqChecker};
359pub use eta::{eta_contract, eta_expand, is_eta_expandable};
360pub use export::{
361 deserialize_module_header, export_environment, import_module, serialize_module, ExportedModule,
362 ModuleCache,
363};
364pub use inductive::{check_inductive, reduce_recursor, InductiveEnv, InductiveType, IntroRule};
365pub use match_compile::{
366 CompileResult, ConstructorInfo as MatchConstructorInfo, DecisionTree, MatchArm, MatchCompiler,
367 Pattern,
368};
369pub use normalize::{alpha_eq_env, evaluate, is_normal_form, normalize_env, normalize_whnf};
370pub use prettyprint::{print_expr, print_expr_ascii, ExprPrinter};
371pub use proof::ProofTerm;
372pub use quotient::{
373 check_equivalence_relation, check_quot_usage, is_quot_type_expr, quot_eq, reduce_quot_lift,
374 QuotUsageKind, QuotientType,
375};
376pub use simp::{alpha_eq, normalize, simplify};
377pub use termination::{ParamInfo, RecCallInfo, TerminationChecker, TerminationResult};
378pub use trace::{TraceEvent, TraceLevel, Tracer};
379pub use typeclasses::{
380 is_class_constraint, Instance as KernelInstance, Method as KernelMethod,
381 TypeClass as KernelTypeClass, TypeClassRegistry as KernelTypeClassRegistry,
382};
383pub use universe::{UnivChecker, UnivConstraint};
384pub use whnf::{is_whnf, whnf, whnf_is_lambda, whnf_is_pi, whnf_is_sort};
385
386pub const KERNEL_VERSION: &str = env!("CARGO_PKG_VERSION");
392
393#[allow(dead_code)]
395pub fn kernel_version() -> (u32, u32, u32) {
396 let v = KERNEL_VERSION;
397 let parts: Vec<u32> = v.split('.').filter_map(|s| s.parse().ok()).collect();
398 match parts.as_slice() {
399 [major, minor, patch, ..] => (*major, *minor, *patch),
400 [major, minor] => (*major, *minor, 0),
401 [major] => (*major, 0, 0),
402 [] => (0, 0, 0),
403 }
404}
405
406#[allow(dead_code)]
408pub fn mk_prop() -> Expr {
409 Expr::Sort(Level::zero())
410}
411
412#[allow(dead_code)]
414pub fn mk_type0() -> Expr {
415 Expr::Sort(Level::succ(Level::zero()))
416}
417
418#[allow(dead_code)]
420pub fn mk_type1() -> Expr {
421 Expr::Sort(Level::succ(Level::succ(Level::zero())))
422}
423
424#[allow(dead_code)]
426pub fn mk_sort(level: Level) -> Expr {
427 Expr::Sort(level)
428}
429
430#[allow(dead_code)]
432pub fn mk_nat_lit(n: u64) -> Expr {
433 Expr::Lit(Literal::Nat(n))
434}
435
436#[allow(dead_code)]
438pub fn mk_string_lit(s: &str) -> Expr {
439 Expr::Lit(Literal::Str(s.to_string()))
440}
441
442#[allow(dead_code)]
444pub fn mk_app(f: Expr, a: Expr) -> Expr {
445 Expr::App(Box::new(f), Box::new(a))
446}
447
448#[allow(dead_code)]
450pub fn mk_app_spine(f: Expr, args: Vec<Expr>) -> Expr {
451 args.into_iter().fold(f, mk_app)
452}
453
454#[allow(dead_code)]
456pub fn mk_pi(name: Name, dom: Expr, cod: Expr) -> Expr {
457 Expr::Pi(BinderInfo::Default, name, Box::new(dom), Box::new(cod))
458}
459
460#[allow(dead_code)]
462pub fn mk_pi_chain(binders: Vec<(Name, Expr)>, ret: Expr) -> Expr {
463 binders
464 .into_iter()
465 .rev()
466 .fold(ret, |acc, (n, ty)| mk_pi(n, ty, acc))
467}
468
469#[allow(dead_code)]
471pub fn mk_lam(name: Name, dom: Expr, body: Expr) -> Expr {
472 Expr::Lam(BinderInfo::Default, name, Box::new(dom), Box::new(body))
473}
474
475#[allow(dead_code)]
477pub fn mk_lam_chain(binders: Vec<(Name, Expr)>, body: Expr) -> Expr {
478 binders
479 .into_iter()
480 .rev()
481 .fold(body, |acc, (n, ty)| mk_lam(n, ty, acc))
482}
483
484#[allow(dead_code)]
488pub fn unfold_app(expr: &Expr) -> (&Expr, Vec<&Expr>) {
489 let mut args = Vec::new();
490 let mut cur = expr;
491 while let Expr::App(f, a) = cur {
492 args.push(a.as_ref());
493 cur = f;
494 }
495 args.reverse();
496 (cur, args)
497}
498
499#[allow(dead_code)]
501pub fn app_arity(expr: &Expr) -> usize {
502 match expr {
503 Expr::App(f, _) => 1 + app_arity(f),
504 _ => 0,
505 }
506}
507
508#[allow(dead_code)]
510pub fn count_pi_binders(expr: &Expr) -> usize {
511 match expr {
512 Expr::Pi(_, _, _, body) => 1 + count_pi_binders(body),
513 _ => 0,
514 }
515}
516
517#[allow(dead_code)]
519pub fn count_lam_binders(expr: &Expr) -> usize {
520 match expr {
521 Expr::Lam(_, _, _, body) => 1 + count_lam_binders(body),
522 _ => 0,
523 }
524}
525
526#[allow(dead_code)]
528pub fn is_closed(expr: &Expr) -> bool {
529 is_closed_at(expr, 0)
530}
531
532fn is_closed_at(expr: &Expr, depth: u32) -> bool {
533 match expr {
534 Expr::BVar(i) => *i < depth,
535 Expr::FVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => true,
536 Expr::App(f, a) => is_closed_at(f, depth) && is_closed_at(a, depth),
537 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => {
538 is_closed_at(dom, depth) && is_closed_at(body, depth + 1)
539 }
540 Expr::Let(_, ty, val, body) => {
541 is_closed_at(ty, depth) && is_closed_at(val, depth) && is_closed_at(body, depth + 1)
542 }
543 Expr::Proj(_, _, e) => is_closed_at(e, depth),
544 }
545}
546
547#[allow(dead_code)]
549pub fn is_ground(expr: &Expr) -> bool {
550 match expr {
551 Expr::BVar(_) | Expr::FVar(_) => false,
552 Expr::Sort(_) | Expr::Lit(_) => true,
553 Expr::Const(_, _) => true,
554 Expr::App(f, a) => is_ground(f) && is_ground(a),
555 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => is_ground(dom) && is_ground(body),
556 Expr::Let(_, ty, val, body) => is_ground(ty) && is_ground(val) && is_ground(body),
557 Expr::Proj(_, _, e) => is_ground(e),
558 }
559}
560
561#[allow(dead_code)]
563pub fn expr_size(expr: &Expr) -> usize {
564 match expr {
565 Expr::BVar(_) | Expr::FVar(_) | Expr::Sort(_) | Expr::Lit(_) | Expr::Const(_, _) => 1,
566 Expr::App(f, a) => 1 + expr_size(f) + expr_size(a),
567 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => {
568 1 + expr_size(dom) + expr_size(body)
569 }
570 Expr::Let(_, ty, val, body) => 1 + expr_size(ty) + expr_size(val) + expr_size(body),
571 Expr::Proj(_, _, e) => 1 + expr_size(e),
572 }
573}
574
575#[allow(dead_code)]
577pub fn has_metavars(expr: &Expr) -> bool {
578 match expr {
579 Expr::App(f, a) => has_metavars(f) || has_metavars(a),
580 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => {
581 has_metavars(dom) || has_metavars(body)
582 }
583 Expr::Let(_, ty, val, body) => has_metavars(ty) || has_metavars(val) || has_metavars(body),
584 Expr::Proj(_, _, e) => has_metavars(e),
585 _ => false,
586 }
587}
588
589#[allow(dead_code)]
591pub fn collect_const_names(expr: &Expr) -> Vec<Name> {
592 let mut names = Vec::new();
593 collect_const_names_rec(expr, &mut names);
594 names
595}
596
597fn collect_const_names_rec(expr: &Expr, acc: &mut Vec<Name>) {
598 match expr {
599 Expr::Const(n, _) => acc.push(n.clone()),
600 Expr::App(f, a) => {
601 collect_const_names_rec(f, acc);
602 collect_const_names_rec(a, acc);
603 }
604 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => {
605 collect_const_names_rec(dom, acc);
606 collect_const_names_rec(body, acc);
607 }
608 Expr::Let(_, ty, val, body) => {
609 collect_const_names_rec(ty, acc);
610 collect_const_names_rec(val, acc);
611 collect_const_names_rec(body, acc);
612 }
613 Expr::Proj(_, _, e) => collect_const_names_rec(e, acc),
614 _ => {}
615 }
616}
617
618#[allow(dead_code)]
620pub fn collect_fvars(expr: &Expr) -> Vec<FVarId> {
621 let mut fvars = Vec::new();
622 collect_fvars_rec(expr, &mut fvars);
623 fvars
624}
625
626fn collect_fvars_rec(expr: &Expr, acc: &mut Vec<FVarId>) {
627 match expr {
628 Expr::FVar(id) => acc.push(*id),
629 Expr::App(f, a) => {
630 collect_fvars_rec(f, acc);
631 collect_fvars_rec(a, acc);
632 }
633 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => {
634 collect_fvars_rec(dom, acc);
635 collect_fvars_rec(body, acc);
636 }
637 Expr::Let(_, ty, val, body) => {
638 collect_fvars_rec(ty, acc);
639 collect_fvars_rec(val, acc);
640 collect_fvars_rec(body, acc);
641 }
642 Expr::Proj(_, _, e) => collect_fvars_rec(e, acc),
643 _ => {}
644 }
645}
646
647#[allow(dead_code)]
649pub fn expr_head(expr: &Expr) -> &Expr {
650 match expr {
651 Expr::App(f, _) => expr_head(f),
652 _ => expr,
653 }
654}
655
656#[allow(dead_code)]
658pub fn is_app_of(expr: &Expr, name: &Name) -> bool {
659 matches!(expr_head(expr), Expr::Const(n, _) if n == name)
660}
661
662#[allow(dead_code)]
666pub fn max_bvar_index(expr: &Expr) -> Option<u32> {
667 max_bvar_index_at(expr, 0)
668}
669
670fn max_bvar_index_at(expr: &Expr, depth: u32) -> Option<u32> {
671 match expr {
672 Expr::BVar(i) => {
673 if *i >= depth {
674 Some(*i - depth)
675 } else {
676 None
677 }
678 }
679 Expr::App(f, a) => {
680 let l = max_bvar_index_at(f, depth);
681 let r = max_bvar_index_at(a, depth);
682 match (l, r) {
683 (Some(a), Some(b)) => Some(a.max(b)),
684 (x, None) | (None, x) => x,
685 }
686 }
687 Expr::Lam(_, _, dom, body) | Expr::Pi(_, _, dom, body) => {
688 let l = max_bvar_index_at(dom, depth);
689 let r = max_bvar_index_at(body, depth + 1);
690 match (l, r) {
691 (Some(a), Some(b)) => Some(a.max(b)),
692 (x, None) | (None, x) => x,
693 }
694 }
695 Expr::Let(_, ty, val, body) => {
696 let t = max_bvar_index_at(ty, depth);
697 let v = max_bvar_index_at(val, depth);
698 let b = max_bvar_index_at(body, depth + 1);
699 [t, v, b].into_iter().flatten().reduce(|a, b| a.max(b))
700 }
701 Expr::Proj(_, _, e) => max_bvar_index_at(e, depth),
702 _ => None,
703 }
704}
705
706#[cfg(test)]
707mod kernel_util_tests {
708 use super::*;
709
710 #[test]
711 fn test_kernel_version_parses() {
712 let (major, minor, patch) = kernel_version();
713 let _ = (major, minor, patch); }
715
716 #[test]
717 fn test_mk_prop() {
718 assert!(matches!(mk_prop(), Expr::Sort(l) if l == Level::zero()));
719 }
720
721 #[test]
722 fn test_mk_type0() {
723 assert!(matches!(mk_type0(), Expr::Sort(l) if l == Level::succ(Level::zero())));
724 }
725
726 #[test]
727 fn test_mk_nat_lit() {
728 assert!(matches!(mk_nat_lit(42), Expr::Lit(Literal::Nat(_))));
729 }
730
731 #[test]
732 fn test_mk_string_lit() {
733 assert!(matches!(mk_string_lit("hello"), Expr::Lit(Literal::Str(_))));
734 }
735
736 #[test]
737 fn test_mk_app_spine_empty() {
738 let f = Expr::Const(Name::str("f"), vec![]);
739 let result = mk_app_spine(f.clone(), vec![]);
740 assert_eq!(result, f);
741 }
742
743 #[test]
744 fn test_mk_app_spine() {
745 let f = Expr::Const(Name::str("f"), vec![]);
746 let a = Expr::Const(Name::str("a"), vec![]);
747 let b = Expr::Const(Name::str("b"), vec![]);
748 let result = mk_app_spine(f, vec![a, b]);
749 assert!(matches!(result, Expr::App(_, _)));
750 assert_eq!(app_arity(&result), 2);
751 }
752
753 #[test]
754 fn test_unfold_app() {
755 let f = Expr::Const(Name::str("f"), vec![]);
756 let a = Expr::Const(Name::str("a"), vec![]);
757 let b = Expr::Const(Name::str("b"), vec![]);
758 let e = mk_app_spine(f, vec![a, b]);
759 let (head, args) = unfold_app(&e);
760 assert!(matches!(head, Expr::Const(n, _) if n == &Name::str("f")));
761 assert_eq!(args.len(), 2);
762 }
763
764 #[test]
765 fn test_is_closed_bvar_0() {
766 let e = Expr::BVar(0);
768 assert!(!is_closed(&e)); }
770
771 #[test]
772 fn test_is_closed_const() {
773 let e = Expr::Const(Name::str("Nat"), vec![]);
774 assert!(is_closed(&e));
775 }
776
777 #[test]
778 fn test_is_ground_const() {
779 let e = Expr::Const(Name::str("Nat"), vec![]);
780 assert!(is_ground(&e));
781 }
782
783 #[test]
784 fn test_is_ground_fvar() {
785 let e = Expr::FVar(FVarId(0));
786 assert!(!is_ground(&e));
787 }
788
789 #[test]
790 fn test_expr_size_atom() {
791 assert_eq!(expr_size(&Expr::BVar(0)), 1);
792 assert_eq!(expr_size(&Expr::Sort(Level::zero())), 1);
793 }
794
795 #[test]
796 fn test_expr_size_app() {
797 let e = mk_app(Expr::BVar(0), Expr::BVar(1));
798 assert_eq!(expr_size(&e), 3); }
800
801 #[test]
802 fn test_has_metavars_false() {
803 let e = Expr::Const(Name::str("f"), vec![]);
804 assert!(!has_metavars(&e));
805 }
806
807 #[test]
808 fn test_has_metavars_true() {
809 let e = Expr::FVar(FVarId(0));
811 assert!(!has_metavars(&e));
812 }
813
814 #[test]
815 fn test_collect_const_names() {
816 let e = mk_app(
817 Expr::Const(Name::str("f"), vec![]),
818 Expr::Const(Name::str("a"), vec![]),
819 );
820 let names = collect_const_names(&e);
821 assert!(names.contains(&Name::str("f")));
822 assert!(names.contains(&Name::str("a")));
823 }
824
825 #[test]
826 fn test_is_app_of() {
827 let e = mk_app(
828 Expr::Const(Name::str("List"), vec![]),
829 Expr::Const(Name::str("Nat"), vec![]),
830 );
831 assert!(is_app_of(&e, &Name::str("List")));
832 assert!(!is_app_of(&e, &Name::str("Nat")));
833 }
834
835 #[test]
836 fn test_count_pi_binders() {
837 let p = mk_pi(Name::str("x"), mk_prop(), mk_prop());
838 assert_eq!(count_pi_binders(&p), 1);
839 }
840
841 #[test]
842 fn test_count_lam_binders() {
843 let l = mk_lam(Name::str("x"), mk_prop(), Expr::BVar(0));
844 assert_eq!(count_lam_binders(&l), 1);
845 }
846}
847
848#[allow(dead_code)]
852pub fn has_let_binders(expr: &Expr) -> bool {
853 match expr {
854 Expr::Let(_, ty, val, body) => {
855 let _ = (
856 has_let_binders(ty),
857 has_let_binders(val),
858 has_let_binders(body),
859 );
860 true
861 }
862 Expr::App(f, a) => has_let_binders(f) || has_let_binders(a),
863 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
864 has_let_binders(ty) || has_let_binders(body)
865 }
866 Expr::Proj(_, _, e) => has_let_binders(e),
867 _ => false,
868 }
869}
870
871#[allow(dead_code)]
873pub fn has_projections(expr: &Expr) -> bool {
874 match expr {
875 Expr::Proj(_, _, _) => true,
876 Expr::App(f, a) => has_projections(f) || has_projections(a),
877 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
878 has_projections(ty) || has_projections(body)
879 }
880 Expr::Let(_, ty, val, body) => {
881 has_projections(ty) || has_projections(val) || has_projections(body)
882 }
883 _ => false,
884 }
885}
886
887#[allow(dead_code)]
889pub fn count_apps(expr: &Expr) -> usize {
890 match expr {
891 Expr::App(f, a) => 1 + count_apps(f) + count_apps(a),
892 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => count_apps(ty) + count_apps(body),
893 Expr::Let(_, ty, val, body) => count_apps(ty) + count_apps(val) + count_apps(body),
894 Expr::Proj(_, _, e) => count_apps(e),
895 _ => 0,
896 }
897}
898
899#[allow(dead_code)]
901pub fn count_sorts(expr: &Expr) -> usize {
902 match expr {
903 Expr::Sort(_) => 1,
904 Expr::App(f, a) => count_sorts(f) + count_sorts(a),
905 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => count_sorts(ty) + count_sorts(body),
906 Expr::Let(_, ty, val, body) => count_sorts(ty) + count_sorts(val) + count_sorts(body),
907 Expr::Proj(_, _, e) => count_sorts(e),
908 _ => 0,
909 }
910}
911
912#[allow(dead_code)]
914pub fn is_literal(expr: &Expr) -> bool {
915 matches!(expr, Expr::Lit(_))
916}
917
918#[allow(dead_code)]
920pub fn is_sort(expr: &Expr) -> bool {
921 matches!(expr, Expr::Sort(_))
922}
923
924#[allow(dead_code)]
926pub fn is_pi(expr: &Expr) -> bool {
927 matches!(expr, Expr::Pi(_, _, _, _))
928}
929
930#[allow(dead_code)]
932pub fn is_lam(expr: &Expr) -> bool {
933 matches!(expr, Expr::Lam(_, _, _, _))
934}
935
936#[allow(dead_code)]
938pub fn is_app(expr: &Expr) -> bool {
939 matches!(expr, Expr::App(_, _))
940}
941
942#[allow(dead_code)]
944pub fn is_const(expr: &Expr) -> bool {
945 matches!(expr, Expr::Const(_, _))
946}
947
948#[allow(dead_code)]
950pub fn const_name(expr: &Expr) -> Option<&Name> {
951 match expr {
952 Expr::Const(n, _) => Some(n),
953 _ => None,
954 }
955}
956
957#[allow(dead_code)]
961pub fn strip_pi_binders(expr: &Expr) -> (Vec<(BinderInfo, Name, Expr)>, &Expr) {
962 let mut binders = Vec::new();
963 let mut current = expr;
964 while let Expr::Pi(bi, n, ty, body) = current {
965 binders.push((*bi, n.clone(), ty.as_ref().clone()));
966 current = body;
967 }
968 (binders, current)
969}
970
971#[allow(dead_code)]
975pub fn strip_lam_binders(expr: &Expr) -> (Vec<(BinderInfo, Name, Expr)>, &Expr) {
976 let mut binders = Vec::new();
977 let mut current = expr;
978 while let Expr::Lam(bi, n, ty, body) = current {
979 binders.push((*bi, n.clone(), ty.as_ref().clone()));
980 current = body;
981 }
982 (binders, current)
983}
984
985#[allow(dead_code)]
987pub fn build_pi_from_binders(binders: &[(BinderInfo, Name, Expr)], inner: Expr) -> Expr {
988 binders.iter().rev().fold(inner, |acc, (bi, n, ty)| {
989 Expr::Pi(*bi, n.clone(), Box::new(ty.clone()), Box::new(acc))
990 })
991}
992
993#[allow(dead_code)]
995pub fn build_lam_from_binders(binders: &[(BinderInfo, Name, Expr)], body: Expr) -> Expr {
996 binders.iter().rev().fold(body, |acc, (bi, n, ty)| {
997 Expr::Lam(*bi, n.clone(), Box::new(ty.clone()), Box::new(acc))
998 })
999}
1000
1001#[allow(dead_code)]
1006pub fn replace_const(expr: &Expr, name: &Name, replacement: &Expr) -> Expr {
1007 match expr {
1008 Expr::Const(n, _) if n == name => replacement.clone(),
1009 Expr::App(f, a) => Expr::App(
1010 Box::new(replace_const(f, name, replacement)),
1011 Box::new(replace_const(a, name, replacement)),
1012 ),
1013 Expr::Lam(bi, n, ty, body) => Expr::Lam(
1014 *bi,
1015 n.clone(),
1016 Box::new(replace_const(ty, name, replacement)),
1017 Box::new(replace_const(body, name, replacement)),
1018 ),
1019 Expr::Pi(bi, n, ty, body) => Expr::Pi(
1020 *bi,
1021 n.clone(),
1022 Box::new(replace_const(ty, name, replacement)),
1023 Box::new(replace_const(body, name, replacement)),
1024 ),
1025 Expr::Let(n, ty, val, body) => Expr::Let(
1026 n.clone(),
1027 Box::new(replace_const(ty, name, replacement)),
1028 Box::new(replace_const(val, name, replacement)),
1029 Box::new(replace_const(body, name, replacement)),
1030 ),
1031 Expr::Proj(n, i, s) => {
1032 Expr::Proj(n.clone(), *i, Box::new(replace_const(s, name, replacement)))
1033 }
1034 e => e.clone(),
1035 }
1036}
1037
1038#[allow(dead_code)]
1042pub fn is_eta_reducible(expr: &Expr) -> bool {
1043 match expr {
1044 Expr::Lam(_, _, _, body) => {
1045 if let Expr::App(f, a) = body.as_ref() {
1046 if matches!(a.as_ref(), Expr::BVar(0)) {
1047 return !contains_bvar(f, 0, 0);
1049 }
1050 }
1051 false
1052 }
1053 _ => false,
1054 }
1055}
1056
1057#[allow(dead_code)]
1059pub fn contains_bvar(expr: &Expr, idx: u32, depth: u32) -> bool {
1060 match expr {
1061 Expr::BVar(i) => *i == idx + depth,
1062 Expr::App(f, a) => contains_bvar(f, idx, depth) || contains_bvar(a, idx, depth),
1063 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
1064 contains_bvar(ty, idx, depth) || contains_bvar(body, idx, depth + 1)
1065 }
1066 Expr::Let(_, ty, val, body) => {
1067 contains_bvar(ty, idx, depth)
1068 || contains_bvar(val, idx, depth)
1069 || contains_bvar(body, idx, depth + 1)
1070 }
1071 Expr::Proj(_, _, s) => contains_bvar(s, idx, depth),
1072 _ => false,
1073 }
1074}
1075
1076#[allow(dead_code)]
1078pub fn syntactically_equal(e1: &Expr, e2: &Expr) -> bool {
1079 e1 == e2
1080}
1081
1082#[allow(dead_code)]
1084pub fn collect_literals(expr: &Expr) -> Vec<Literal> {
1085 let mut lits = Vec::new();
1086 collect_lits_rec(expr, &mut lits);
1087 lits
1088}
1089
1090fn collect_lits_rec(expr: &Expr, acc: &mut Vec<Literal>) {
1091 match expr {
1092 Expr::Lit(l) => acc.push(l.clone()),
1093 Expr::App(f, a) => {
1094 collect_lits_rec(f, acc);
1095 collect_lits_rec(a, acc);
1096 }
1097 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
1098 collect_lits_rec(ty, acc);
1099 collect_lits_rec(body, acc);
1100 }
1101 Expr::Let(_, ty, val, body) => {
1102 collect_lits_rec(ty, acc);
1103 collect_lits_rec(val, acc);
1104 collect_lits_rec(body, acc);
1105 }
1106 Expr::Proj(_, _, e) => collect_lits_rec(e, acc),
1107 _ => {}
1108 }
1109}
1110
1111#[allow(dead_code)]
1113pub fn max_binder_depth(expr: &Expr) -> u32 {
1114 max_binder_depth_impl(expr, 0)
1115}
1116
1117fn max_binder_depth_impl(expr: &Expr, depth: u32) -> u32 {
1118 match expr {
1119 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
1120 let ty_d = max_binder_depth_impl(ty, depth);
1121 let body_d = max_binder_depth_impl(body, depth + 1);
1122 ty_d.max(body_d).max(depth + 1)
1123 }
1124 Expr::Let(_, ty, val, body) => {
1125 let ty_d = max_binder_depth_impl(ty, depth);
1126 let val_d = max_binder_depth_impl(val, depth);
1127 let body_d = max_binder_depth_impl(body, depth + 1);
1128 ty_d.max(val_d).max(body_d)
1129 }
1130 Expr::App(f, a) => max_binder_depth_impl(f, depth).max(max_binder_depth_impl(a, depth)),
1131 Expr::Proj(_, _, e) => max_binder_depth_impl(e, depth),
1132 _ => depth,
1133 }
1134}
1135
1136#[cfg(test)]
1137mod kernel_extra_tests {
1138 use super::*;
1139
1140 fn nat() -> Expr {
1141 Expr::Const(Name::str("Nat"), vec![])
1142 }
1143 fn prop() -> Expr {
1144 Expr::Sort(Level::zero())
1145 }
1146
1147 #[test]
1148 fn test_is_literal_true() {
1149 assert!(is_literal(&Expr::Lit(Literal::Nat(42))));
1150 }
1151
1152 #[test]
1153 fn test_is_literal_false() {
1154 assert!(!is_literal(&nat()));
1155 }
1156
1157 #[test]
1158 fn test_is_sort() {
1159 assert!(is_sort(&prop()));
1160 assert!(!is_sort(&nat()));
1161 }
1162
1163 #[test]
1164 fn test_is_pi() {
1165 let p = mk_pi(Name::str("x"), prop(), prop());
1166 assert!(is_pi(&p));
1167 assert!(!is_pi(&nat()));
1168 }
1169
1170 #[test]
1171 fn test_is_lam() {
1172 let l = mk_lam(Name::str("x"), prop(), Expr::BVar(0));
1173 assert!(is_lam(&l));
1174 assert!(!is_lam(&nat()));
1175 }
1176
1177 #[test]
1178 fn test_is_app() {
1179 let e = mk_app(nat(), nat());
1180 assert!(is_app(&e));
1181 assert!(!is_app(&nat()));
1182 }
1183
1184 #[test]
1185 fn test_is_const() {
1186 assert!(is_const(&nat()));
1187 assert!(!is_const(&Expr::BVar(0)));
1188 }
1189
1190 #[test]
1191 fn test_const_name() {
1192 assert_eq!(const_name(&nat()), Some(&Name::str("Nat")));
1193 assert!(const_name(&Expr::BVar(0)).is_none());
1194 }
1195
1196 #[test]
1197 fn test_strip_pi_binders_none() {
1198 let nat_expr = nat();
1199 let (binders, inner) = strip_pi_binders(&nat_expr);
1200 assert!(binders.is_empty());
1201 assert_eq!(*inner, nat());
1202 }
1203
1204 #[test]
1205 fn test_strip_pi_binders_one() {
1206 let p = mk_pi(Name::str("x"), prop(), prop());
1207 let (binders, _inner) = strip_pi_binders(&p);
1208 assert_eq!(binders.len(), 1);
1209 }
1210
1211 #[test]
1212 fn test_strip_lam_binders_one() {
1213 let l = mk_lam(Name::str("x"), prop(), Expr::BVar(0));
1214 let (binders, _body) = strip_lam_binders(&l);
1215 assert_eq!(binders.len(), 1);
1216 }
1217
1218 #[test]
1219 fn test_build_pi_from_binders() {
1220 let binders = vec![(BinderInfo::Default, Name::str("x"), prop())];
1221 let ty = build_pi_from_binders(&binders, prop());
1222 assert!(is_pi(&ty));
1223 }
1224
1225 #[test]
1226 fn test_build_lam_from_binders() {
1227 let binders = vec![(BinderInfo::Default, Name::str("x"), prop())];
1228 let l = build_lam_from_binders(&binders, Expr::BVar(0));
1229 assert!(is_lam(&l));
1230 }
1231
1232 #[test]
1233 fn test_replace_const() {
1234 let e = nat();
1235 let result = replace_const(&e, &Name::str("Nat"), &prop());
1236 assert_eq!(result, prop());
1237 }
1238
1239 #[test]
1240 fn test_replace_const_in_app() {
1241 let e = mk_app(nat(), nat());
1242 let result = replace_const(&e, &Name::str("Nat"), &prop());
1243 if let Expr::App(f, a) = &result {
1244 assert_eq!(**f, prop());
1245 assert_eq!(**a, prop());
1246 }
1247 }
1248
1249 #[test]
1250 fn test_count_apps_zero() {
1251 assert_eq!(count_apps(&nat()), 0);
1252 }
1253
1254 #[test]
1255 fn test_count_apps_one() {
1256 let e = mk_app(nat(), nat());
1257 assert_eq!(count_apps(&e), 1);
1258 }
1259
1260 #[test]
1261 fn test_count_sorts_one() {
1262 assert_eq!(count_sorts(&prop()), 1);
1263 }
1264
1265 #[test]
1266 fn test_count_sorts_zero() {
1267 assert_eq!(count_sorts(&nat()), 0);
1268 }
1269
1270 #[test]
1271 fn test_contains_bvar_true() {
1272 assert!(contains_bvar(&Expr::BVar(0), 0, 0));
1273 }
1274
1275 #[test]
1276 fn test_contains_bvar_false() {
1277 assert!(!contains_bvar(&Expr::BVar(1), 0, 0));
1278 }
1279
1280 #[test]
1281 fn test_syntactically_equal() {
1282 assert!(syntactically_equal(&nat(), &nat()));
1283 assert!(!syntactically_equal(&nat(), &prop()));
1284 }
1285
1286 #[test]
1287 fn test_collect_literals() {
1288 let e = mk_app(Expr::Lit(Literal::Nat(1)), Expr::Lit(Literal::Nat(2)));
1289 let lits = collect_literals(&e);
1290 assert_eq!(lits.len(), 2);
1291 }
1292
1293 #[test]
1294 fn test_max_binder_depth_zero() {
1295 assert_eq!(max_binder_depth(&nat()), 0);
1296 }
1297
1298 #[test]
1299 fn test_max_binder_depth_one() {
1300 let l = mk_lam(Name::str("x"), prop(), Expr::BVar(0));
1301 assert_eq!(max_binder_depth(&l), 1);
1302 }
1303
1304 #[test]
1305 fn test_is_eta_reducible_false() {
1306 assert!(!is_eta_reducible(&nat()));
1307 let not_eta = Expr::Lam(
1309 BinderInfo::Default,
1310 Name::str("x"),
1311 Box::new(prop()),
1312 Box::new(Expr::App(
1313 Box::new(Expr::BVar(0)), Box::new(Expr::BVar(0)),
1315 )),
1316 );
1317 assert!(!is_eta_reducible(¬_eta));
1318 }
1319
1320 #[test]
1321 fn test_has_let_binders_false() {
1322 assert!(!has_let_binders(&nat()));
1323 assert!(!has_let_binders(&mk_pi(Name::str("x"), prop(), prop())));
1324 }
1325
1326 #[test]
1327 fn test_has_projections_false() {
1328 assert!(!has_projections(&nat()));
1329 assert!(!has_projections(&Expr::BVar(0)));
1330 }
1331}
1332
1333#[allow(dead_code)]
1337pub struct StatSummary {
1338 count: u64,
1339 sum: f64,
1340 min: f64,
1341 max: f64,
1342}
1343
1344#[allow(dead_code)]
1345impl StatSummary {
1346 pub fn new() -> Self {
1348 Self {
1349 count: 0,
1350 sum: 0.0,
1351 min: f64::INFINITY,
1352 max: f64::NEG_INFINITY,
1353 }
1354 }
1355
1356 pub fn record(&mut self, val: f64) {
1358 self.count += 1;
1359 self.sum += val;
1360 if val < self.min {
1361 self.min = val;
1362 }
1363 if val > self.max {
1364 self.max = val;
1365 }
1366 }
1367
1368 pub fn mean(&self) -> Option<f64> {
1370 if self.count == 0 {
1371 None
1372 } else {
1373 Some(self.sum / self.count as f64)
1374 }
1375 }
1376
1377 pub fn min(&self) -> Option<f64> {
1379 if self.count == 0 {
1380 None
1381 } else {
1382 Some(self.min)
1383 }
1384 }
1385
1386 pub fn max(&self) -> Option<f64> {
1388 if self.count == 0 {
1389 None
1390 } else {
1391 Some(self.max)
1392 }
1393 }
1394
1395 pub fn count(&self) -> u64 {
1397 self.count
1398 }
1399}
1400
1401impl Default for StatSummary {
1402 fn default() -> Self {
1403 Self::new()
1404 }
1405}
1406
1407#[allow(dead_code)]
1409pub struct TransformStat {
1410 before: StatSummary,
1411 after: StatSummary,
1412}
1413
1414#[allow(dead_code)]
1415impl TransformStat {
1416 pub fn new() -> Self {
1418 Self {
1419 before: StatSummary::new(),
1420 after: StatSummary::new(),
1421 }
1422 }
1423
1424 pub fn record_before(&mut self, v: f64) {
1426 self.before.record(v);
1427 }
1428
1429 pub fn record_after(&mut self, v: f64) {
1431 self.after.record(v);
1432 }
1433
1434 pub fn mean_ratio(&self) -> Option<f64> {
1436 let b = self.before.mean()?;
1437 let a = self.after.mean()?;
1438 if b.abs() < f64::EPSILON {
1439 return None;
1440 }
1441 Some(a / b)
1442 }
1443}
1444
1445impl Default for TransformStat {
1446 fn default() -> Self {
1447 Self::new()
1448 }
1449}
1450
1451#[allow(dead_code)]
1453pub struct SmallMap<K: Ord + Clone, V: Clone> {
1454 entries: Vec<(K, V)>,
1455}
1456
1457#[allow(dead_code)]
1458impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1459 pub fn new() -> Self {
1461 Self {
1462 entries: Vec::new(),
1463 }
1464 }
1465
1466 pub fn insert(&mut self, key: K, val: V) {
1468 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1469 Ok(i) => self.entries[i].1 = val,
1470 Err(i) => self.entries.insert(i, (key, val)),
1471 }
1472 }
1473
1474 pub fn get(&self, key: &K) -> Option<&V> {
1476 self.entries
1477 .binary_search_by_key(&key, |(k, _)| k)
1478 .ok()
1479 .map(|i| &self.entries[i].1)
1480 }
1481
1482 pub fn len(&self) -> usize {
1484 self.entries.len()
1485 }
1486
1487 pub fn is_empty(&self) -> bool {
1489 self.entries.is_empty()
1490 }
1491
1492 pub fn keys(&self) -> Vec<&K> {
1494 self.entries.iter().map(|(k, _)| k).collect()
1495 }
1496
1497 pub fn values(&self) -> Vec<&V> {
1499 self.entries.iter().map(|(_, v)| v).collect()
1500 }
1501}
1502
1503impl<K: Ord + Clone, V: Clone> Default for SmallMap<K, V> {
1504 fn default() -> Self {
1505 Self::new()
1506 }
1507}
1508
1509#[allow(dead_code)]
1511pub struct LabelSet {
1512 labels: Vec<String>,
1513}
1514
1515#[allow(dead_code)]
1516impl LabelSet {
1517 pub fn new() -> Self {
1519 Self { labels: Vec::new() }
1520 }
1521
1522 pub fn add(&mut self, label: impl Into<String>) {
1524 let s = label.into();
1525 if !self.labels.contains(&s) {
1526 self.labels.push(s);
1527 }
1528 }
1529
1530 pub fn has(&self, label: &str) -> bool {
1532 self.labels.iter().any(|l| l == label)
1533 }
1534
1535 pub fn count(&self) -> usize {
1537 self.labels.len()
1538 }
1539
1540 pub fn all(&self) -> &[String] {
1542 &self.labels
1543 }
1544}
1545
1546impl Default for LabelSet {
1547 fn default() -> Self {
1548 Self::new()
1549 }
1550}
1551
1552#[allow(dead_code)]
1554pub struct ConfigNode {
1555 key: String,
1556 value: Option<String>,
1557 children: Vec<ConfigNode>,
1558}
1559
1560#[allow(dead_code)]
1561impl ConfigNode {
1562 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1564 Self {
1565 key: key.into(),
1566 value: Some(value.into()),
1567 children: Vec::new(),
1568 }
1569 }
1570
1571 pub fn section(key: impl Into<String>) -> Self {
1573 Self {
1574 key: key.into(),
1575 value: None,
1576 children: Vec::new(),
1577 }
1578 }
1579
1580 pub fn add_child(&mut self, child: ConfigNode) {
1582 self.children.push(child);
1583 }
1584
1585 pub fn key(&self) -> &str {
1587 &self.key
1588 }
1589
1590 pub fn value(&self) -> Option<&str> {
1592 self.value.as_deref()
1593 }
1594
1595 pub fn num_children(&self) -> usize {
1597 self.children.len()
1598 }
1599
1600 pub fn lookup(&self, path: &str) -> Option<&str> {
1602 let mut parts = path.splitn(2, '.');
1603 let head = parts.next()?;
1604 let tail = parts.next();
1605 if head != self.key {
1606 return None;
1607 }
1608 match tail {
1609 None => self.value.as_deref(),
1610 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1611 }
1612 }
1613
1614 fn lookup_relative(&self, path: &str) -> Option<&str> {
1615 let mut parts = path.splitn(2, '.');
1616 let head = parts.next()?;
1617 let tail = parts.next();
1618 if head != self.key {
1619 return None;
1620 }
1621 match tail {
1622 None => self.value.as_deref(),
1623 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1624 }
1625 }
1626}
1627
1628#[allow(dead_code)]
1630pub struct VersionedRecord<T: Clone> {
1631 history: Vec<T>,
1632}
1633
1634#[allow(dead_code)]
1635impl<T: Clone> VersionedRecord<T> {
1636 pub fn new(initial: T) -> Self {
1638 Self {
1639 history: vec![initial],
1640 }
1641 }
1642
1643 pub fn update(&mut self, val: T) {
1645 self.history.push(val);
1646 }
1647
1648 pub fn current(&self) -> &T {
1650 self.history
1651 .last()
1652 .expect("VersionedRecord history is always non-empty after construction")
1653 }
1654
1655 pub fn at_version(&self, n: usize) -> Option<&T> {
1657 self.history.get(n)
1658 }
1659
1660 pub fn version(&self) -> usize {
1662 self.history.len() - 1
1663 }
1664
1665 pub fn has_history(&self) -> bool {
1667 self.history.len() > 1
1668 }
1669}
1670
1671#[allow(dead_code)]
1673pub struct SimpleDag {
1674 edges: Vec<Vec<usize>>,
1676}
1677
1678#[allow(dead_code)]
1679impl SimpleDag {
1680 pub fn new(n: usize) -> Self {
1682 Self {
1683 edges: vec![Vec::new(); n],
1684 }
1685 }
1686
1687 pub fn add_edge(&mut self, from: usize, to: usize) {
1689 if from < self.edges.len() {
1690 self.edges[from].push(to);
1691 }
1692 }
1693
1694 pub fn successors(&self, node: usize) -> &[usize] {
1696 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1697 }
1698
1699 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1701 let mut visited = vec![false; self.edges.len()];
1702 self.dfs(from, to, &mut visited)
1703 }
1704
1705 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1706 if cur == target {
1707 return true;
1708 }
1709 if cur >= visited.len() || visited[cur] {
1710 return false;
1711 }
1712 visited[cur] = true;
1713 for &next in self.successors(cur) {
1714 if self.dfs(next, target, visited) {
1715 return true;
1716 }
1717 }
1718 false
1719 }
1720
1721 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1723 let n = self.edges.len();
1724 let mut in_degree = vec![0usize; n];
1725 for succs in &self.edges {
1726 for &s in succs {
1727 if s < n {
1728 in_degree[s] += 1;
1729 }
1730 }
1731 }
1732 let mut queue: std::collections::VecDeque<usize> =
1733 (0..n).filter(|&i| in_degree[i] == 0).collect();
1734 let mut order = Vec::new();
1735 while let Some(node) = queue.pop_front() {
1736 order.push(node);
1737 for &s in self.successors(node) {
1738 if s < n {
1739 in_degree[s] -= 1;
1740 if in_degree[s] == 0 {
1741 queue.push_back(s);
1742 }
1743 }
1744 }
1745 }
1746 if order.len() == n {
1747 Some(order)
1748 } else {
1749 None
1750 }
1751 }
1752
1753 pub fn num_nodes(&self) -> usize {
1755 self.edges.len()
1756 }
1757}
1758
1759#[allow(dead_code)]
1761pub struct FocusStack<T> {
1762 items: Vec<T>,
1763}
1764
1765#[allow(dead_code)]
1766impl<T> FocusStack<T> {
1767 pub fn new() -> Self {
1769 Self { items: Vec::new() }
1770 }
1771
1772 pub fn focus(&mut self, item: T) {
1774 self.items.push(item);
1775 }
1776
1777 pub fn blur(&mut self) -> Option<T> {
1779 self.items.pop()
1780 }
1781
1782 pub fn current(&self) -> Option<&T> {
1784 self.items.last()
1785 }
1786
1787 pub fn depth(&self) -> usize {
1789 self.items.len()
1790 }
1791
1792 pub fn is_empty(&self) -> bool {
1794 self.items.is_empty()
1795 }
1796}
1797
1798impl<T> Default for FocusStack<T> {
1799 fn default() -> Self {
1800 Self::new()
1801 }
1802}
1803
1804#[cfg(test)]
1805mod tests_padding_infra {
1806 use super::*;
1807
1808 #[test]
1809 fn test_stat_summary() {
1810 let mut ss = StatSummary::new();
1811 ss.record(10.0);
1812 ss.record(20.0);
1813 ss.record(30.0);
1814 assert_eq!(ss.count(), 3);
1815 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
1816 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
1817 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
1818 }
1819
1820 #[test]
1821 fn test_transform_stat() {
1822 let mut ts = TransformStat::new();
1823 ts.record_before(100.0);
1824 ts.record_after(80.0);
1825 let ratio = ts.mean_ratio().expect("ratio should be present");
1826 assert!((ratio - 0.8).abs() < 1e-9);
1827 }
1828
1829 #[test]
1830 fn test_small_map() {
1831 let mut m: SmallMap<u32, &str> = SmallMap::new();
1832 m.insert(3, "three");
1833 m.insert(1, "one");
1834 m.insert(2, "two");
1835 assert_eq!(m.get(&2), Some(&"two"));
1836 assert_eq!(m.len(), 3);
1837 let keys = m.keys();
1839 assert_eq!(*keys[0], 1);
1840 assert_eq!(*keys[2], 3);
1841 }
1842
1843 #[test]
1844 fn test_label_set() {
1845 let mut ls = LabelSet::new();
1846 ls.add("foo");
1847 ls.add("bar");
1848 ls.add("foo"); assert_eq!(ls.count(), 2);
1850 assert!(ls.has("bar"));
1851 assert!(!ls.has("baz"));
1852 }
1853
1854 #[test]
1855 fn test_config_node() {
1856 let mut root = ConfigNode::section("root");
1857 let child = ConfigNode::leaf("key", "value");
1858 root.add_child(child);
1859 assert_eq!(root.num_children(), 1);
1860 }
1861
1862 #[test]
1863 fn test_versioned_record() {
1864 let mut vr = VersionedRecord::new(0u32);
1865 vr.update(1);
1866 vr.update(2);
1867 assert_eq!(*vr.current(), 2);
1868 assert_eq!(vr.version(), 2);
1869 assert!(vr.has_history());
1870 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
1871 }
1872
1873 #[test]
1874 fn test_simple_dag() {
1875 let mut dag = SimpleDag::new(4);
1876 dag.add_edge(0, 1);
1877 dag.add_edge(1, 2);
1878 dag.add_edge(2, 3);
1879 assert!(dag.can_reach(0, 3));
1880 assert!(!dag.can_reach(3, 0));
1881 let order = dag.topological_sort().expect("order should be present");
1882 assert_eq!(order, vec![0, 1, 2, 3]);
1883 }
1884
1885 #[test]
1886 fn test_focus_stack() {
1887 let mut fs: FocusStack<&str> = FocusStack::new();
1888 fs.focus("a");
1889 fs.focus("b");
1890 assert_eq!(fs.current(), Some(&"b"));
1891 assert_eq!(fs.depth(), 2);
1892 fs.blur();
1893 assert_eq!(fs.current(), Some(&"a"));
1894 }
1895}
1896
1897#[allow(dead_code)]
1899pub struct WindowIterator<'a, T> {
1900 data: &'a [T],
1901 pos: usize,
1902 window: usize,
1903}
1904
1905#[allow(dead_code)]
1906impl<'a, T> WindowIterator<'a, T> {
1907 pub fn new(data: &'a [T], window: usize) -> Self {
1909 Self {
1910 data,
1911 pos: 0,
1912 window,
1913 }
1914 }
1915}
1916
1917impl<'a, T> Iterator for WindowIterator<'a, T> {
1918 type Item = &'a [T];
1919
1920 fn next(&mut self) -> Option<Self::Item> {
1921 if self.pos + self.window > self.data.len() {
1922 return None;
1923 }
1924 let slice = &self.data[self.pos..self.pos + self.window];
1925 self.pos += 1;
1926 Some(slice)
1927 }
1928}
1929
1930#[allow(dead_code)]
1932pub struct NonEmptyVec<T> {
1933 head: T,
1934 tail: Vec<T>,
1935}
1936
1937#[allow(dead_code)]
1938impl<T> NonEmptyVec<T> {
1939 pub fn singleton(val: T) -> Self {
1941 Self {
1942 head: val,
1943 tail: Vec::new(),
1944 }
1945 }
1946
1947 pub fn push(&mut self, val: T) {
1949 self.tail.push(val);
1950 }
1951
1952 pub fn first(&self) -> &T {
1954 &self.head
1955 }
1956
1957 pub fn last(&self) -> &T {
1959 self.tail.last().unwrap_or(&self.head)
1960 }
1961
1962 pub fn len(&self) -> usize {
1964 1 + self.tail.len()
1965 }
1966
1967 pub fn is_empty(&self) -> bool {
1969 self.len() == 0
1970 }
1971
1972 pub fn to_vec(&self) -> Vec<&T> {
1974 let mut v = vec![&self.head];
1975 v.extend(self.tail.iter());
1976 v
1977 }
1978}
1979
1980#[cfg(test)]
1981mod tests_extra_iterators {
1982 use super::*;
1983
1984 #[test]
1985 fn test_window_iterator() {
1986 let data = vec![1u32, 2, 3, 4, 5];
1987 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
1988 assert_eq!(windows.len(), 3);
1989 assert_eq!(windows[0], &[1, 2, 3]);
1990 assert_eq!(windows[2], &[3, 4, 5]);
1991 }
1992
1993 #[test]
1994 fn test_non_empty_vec() {
1995 let mut nev = NonEmptyVec::singleton(10u32);
1996 nev.push(20);
1997 nev.push(30);
1998 assert_eq!(nev.len(), 3);
1999 assert_eq!(*nev.first(), 10);
2000 assert_eq!(*nev.last(), 30);
2001 }
2002}
2003
2004#[allow(dead_code)]
2008pub struct SlidingSum {
2009 window: Vec<f64>,
2010 capacity: usize,
2011 pos: usize,
2012 sum: f64,
2013 count: usize,
2014}
2015
2016#[allow(dead_code)]
2017impl SlidingSum {
2018 pub fn new(capacity: usize) -> Self {
2020 Self {
2021 window: vec![0.0; capacity],
2022 capacity,
2023 pos: 0,
2024 sum: 0.0,
2025 count: 0,
2026 }
2027 }
2028
2029 pub fn push(&mut self, val: f64) {
2031 let oldest = self.window[self.pos];
2032 self.sum -= oldest;
2033 self.sum += val;
2034 self.window[self.pos] = val;
2035 self.pos = (self.pos + 1) % self.capacity;
2036 if self.count < self.capacity {
2037 self.count += 1;
2038 }
2039 }
2040
2041 pub fn sum(&self) -> f64 {
2043 self.sum
2044 }
2045
2046 pub fn mean(&self) -> Option<f64> {
2048 if self.count == 0 {
2049 None
2050 } else {
2051 Some(self.sum / self.count as f64)
2052 }
2053 }
2054
2055 pub fn count(&self) -> usize {
2057 self.count
2058 }
2059}
2060
2061#[allow(dead_code)]
2063pub struct PathBuf {
2064 components: Vec<String>,
2065}
2066
2067#[allow(dead_code)]
2068impl PathBuf {
2069 pub fn new() -> Self {
2071 Self {
2072 components: Vec::new(),
2073 }
2074 }
2075
2076 pub fn push(&mut self, comp: impl Into<String>) {
2078 self.components.push(comp.into());
2079 }
2080
2081 pub fn pop(&mut self) {
2083 self.components.pop();
2084 }
2085
2086 pub fn as_str(&self) -> String {
2088 self.components.join("/")
2089 }
2090
2091 pub fn depth(&self) -> usize {
2093 self.components.len()
2094 }
2095
2096 pub fn clear(&mut self) {
2098 self.components.clear();
2099 }
2100}
2101
2102impl Default for PathBuf {
2103 fn default() -> Self {
2104 Self::new()
2105 }
2106}
2107
2108#[allow(dead_code)]
2110pub struct RawFnPtr {
2111 ptr: usize,
2113 arity: usize,
2114 name: String,
2115}
2116
2117#[allow(dead_code)]
2118impl RawFnPtr {
2119 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
2121 Self {
2122 ptr,
2123 arity,
2124 name: name.into(),
2125 }
2126 }
2127
2128 pub fn arity(&self) -> usize {
2130 self.arity
2131 }
2132
2133 pub fn name(&self) -> &str {
2135 &self.name
2136 }
2137
2138 pub fn raw(&self) -> usize {
2140 self.ptr
2141 }
2142}
2143
2144#[allow(dead_code)]
2146pub struct StringPool {
2147 free: Vec<String>,
2148}
2149
2150#[allow(dead_code)]
2151impl StringPool {
2152 pub fn new() -> Self {
2154 Self { free: Vec::new() }
2155 }
2156
2157 pub fn take(&mut self) -> String {
2159 self.free.pop().unwrap_or_default()
2160 }
2161
2162 pub fn give(&mut self, mut s: String) {
2164 s.clear();
2165 self.free.push(s);
2166 }
2167
2168 pub fn free_count(&self) -> usize {
2170 self.free.len()
2171 }
2172}
2173
2174impl Default for StringPool {
2175 fn default() -> Self {
2176 Self::new()
2177 }
2178}
2179
2180#[allow(dead_code)]
2182pub struct TransitiveClosure {
2183 adj: Vec<Vec<usize>>,
2184 n: usize,
2185}
2186
2187#[allow(dead_code)]
2188impl TransitiveClosure {
2189 pub fn new(n: usize) -> Self {
2191 Self {
2192 adj: vec![Vec::new(); n],
2193 n,
2194 }
2195 }
2196
2197 pub fn add_edge(&mut self, from: usize, to: usize) {
2199 if from < self.n {
2200 self.adj[from].push(to);
2201 }
2202 }
2203
2204 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
2206 let mut visited = vec![false; self.n];
2207 let mut queue = std::collections::VecDeque::new();
2208 queue.push_back(start);
2209 while let Some(node) = queue.pop_front() {
2210 if node >= self.n || visited[node] {
2211 continue;
2212 }
2213 visited[node] = true;
2214 for &next in &self.adj[node] {
2215 queue.push_back(next);
2216 }
2217 }
2218 (0..self.n).filter(|&i| visited[i]).collect()
2219 }
2220
2221 pub fn can_reach(&self, from: usize, to: usize) -> bool {
2223 self.reachable_from(from).contains(&to)
2224 }
2225}
2226
2227#[allow(dead_code)]
2229pub struct TokenBucket {
2230 capacity: u64,
2231 tokens: u64,
2232 refill_per_ms: u64,
2233 last_refill: std::time::Instant,
2234}
2235
2236#[allow(dead_code)]
2237impl TokenBucket {
2238 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
2240 Self {
2241 capacity,
2242 tokens: capacity,
2243 refill_per_ms,
2244 last_refill: std::time::Instant::now(),
2245 }
2246 }
2247
2248 pub fn try_consume(&mut self, n: u64) -> bool {
2250 self.refill();
2251 if self.tokens >= n {
2252 self.tokens -= n;
2253 true
2254 } else {
2255 false
2256 }
2257 }
2258
2259 fn refill(&mut self) {
2260 let now = std::time::Instant::now();
2261 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
2262 if elapsed_ms > 0 {
2263 let new_tokens = elapsed_ms * self.refill_per_ms;
2264 self.tokens = (self.tokens + new_tokens).min(self.capacity);
2265 self.last_refill = now;
2266 }
2267 }
2268
2269 pub fn available(&self) -> u64 {
2271 self.tokens
2272 }
2273
2274 pub fn capacity(&self) -> u64 {
2276 self.capacity
2277 }
2278}
2279
2280#[allow(dead_code)]
2282#[allow(missing_docs)]
2283pub struct RewriteRule {
2284 pub name: String,
2286 pub lhs: String,
2288 pub rhs: String,
2290 pub conditional: bool,
2292}
2293
2294#[allow(dead_code)]
2295impl RewriteRule {
2296 pub fn unconditional(
2298 name: impl Into<String>,
2299 lhs: impl Into<String>,
2300 rhs: impl Into<String>,
2301 ) -> Self {
2302 Self {
2303 name: name.into(),
2304 lhs: lhs.into(),
2305 rhs: rhs.into(),
2306 conditional: false,
2307 }
2308 }
2309
2310 pub fn conditional(
2312 name: impl Into<String>,
2313 lhs: impl Into<String>,
2314 rhs: impl Into<String>,
2315 ) -> Self {
2316 Self {
2317 name: name.into(),
2318 lhs: lhs.into(),
2319 rhs: rhs.into(),
2320 conditional: true,
2321 }
2322 }
2323
2324 pub fn display(&self) -> String {
2326 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
2327 }
2328}
2329
2330#[allow(dead_code)]
2332pub struct RewriteRuleSet {
2333 rules: Vec<RewriteRule>,
2334}
2335
2336#[allow(dead_code)]
2337impl RewriteRuleSet {
2338 pub fn new() -> Self {
2340 Self { rules: Vec::new() }
2341 }
2342
2343 pub fn add(&mut self, rule: RewriteRule) {
2345 self.rules.push(rule);
2346 }
2347
2348 pub fn len(&self) -> usize {
2350 self.rules.len()
2351 }
2352
2353 pub fn is_empty(&self) -> bool {
2355 self.rules.is_empty()
2356 }
2357
2358 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
2360 self.rules.iter().filter(|r| r.conditional).collect()
2361 }
2362
2363 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
2365 self.rules.iter().filter(|r| !r.conditional).collect()
2366 }
2367
2368 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
2370 self.rules.iter().find(|r| r.name == name)
2371 }
2372}
2373
2374impl Default for RewriteRuleSet {
2375 fn default() -> Self {
2376 Self::new()
2377 }
2378}
2379
2380#[cfg(test)]
2381mod tests_padding2 {
2382 use super::*;
2383
2384 #[test]
2385 fn test_sliding_sum() {
2386 let mut ss = SlidingSum::new(3);
2387 ss.push(1.0);
2388 ss.push(2.0);
2389 ss.push(3.0);
2390 assert!((ss.sum() - 6.0).abs() < 1e-9);
2391 ss.push(4.0); assert!((ss.sum() - 9.0).abs() < 1e-9);
2393 assert_eq!(ss.count(), 3);
2394 }
2395
2396 #[test]
2397 fn test_path_buf() {
2398 let mut pb = PathBuf::new();
2399 pb.push("src");
2400 pb.push("main");
2401 assert_eq!(pb.as_str(), "src/main");
2402 assert_eq!(pb.depth(), 2);
2403 pb.pop();
2404 assert_eq!(pb.as_str(), "src");
2405 }
2406
2407 #[test]
2408 fn test_string_pool() {
2409 let mut pool = StringPool::new();
2410 let s = pool.take();
2411 assert!(s.is_empty());
2412 pool.give("hello".to_string());
2413 let s2 = pool.take();
2414 assert!(s2.is_empty()); assert_eq!(pool.free_count(), 0);
2416 }
2417
2418 #[test]
2419 fn test_transitive_closure() {
2420 let mut tc = TransitiveClosure::new(4);
2421 tc.add_edge(0, 1);
2422 tc.add_edge(1, 2);
2423 tc.add_edge(2, 3);
2424 assert!(tc.can_reach(0, 3));
2425 assert!(!tc.can_reach(3, 0));
2426 let r = tc.reachable_from(0);
2427 assert_eq!(r.len(), 4);
2428 }
2429
2430 #[test]
2431 fn test_token_bucket() {
2432 let mut tb = TokenBucket::new(100, 10);
2433 assert_eq!(tb.available(), 100);
2434 assert!(tb.try_consume(50));
2435 assert_eq!(tb.available(), 50);
2436 assert!(!tb.try_consume(60)); assert_eq!(tb.capacity(), 100);
2438 }
2439
2440 #[test]
2441 fn test_rewrite_rule_set() {
2442 let mut rrs = RewriteRuleSet::new();
2443 rrs.add(RewriteRule::unconditional(
2444 "beta",
2445 "App(Lam(x, b), v)",
2446 "b[x:=v]",
2447 ));
2448 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
2449 assert_eq!(rrs.len(), 2);
2450 assert_eq!(rrs.unconditional_rules().len(), 1);
2451 assert_eq!(rrs.conditional_rules().len(), 1);
2452 assert!(rrs.get("beta").is_some());
2453 let disp = rrs
2454 .get("beta")
2455 .expect("element at \'beta\' should exist")
2456 .display();
2457 assert!(disp.contains("→"));
2458 }
2459}
2460
2461#[allow(dead_code)]
2465#[allow(missing_docs)]
2466pub enum DecisionNode {
2467 Leaf(String),
2469 Branch {
2471 key: String,
2472 val: String,
2473 yes_branch: Box<DecisionNode>,
2474 no_branch: Box<DecisionNode>,
2475 },
2476}
2477
2478#[allow(dead_code)]
2479impl DecisionNode {
2480 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
2482 match self {
2483 DecisionNode::Leaf(action) => action.as_str(),
2484 DecisionNode::Branch {
2485 key,
2486 val,
2487 yes_branch,
2488 no_branch,
2489 } => {
2490 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
2491 if actual == val.as_str() {
2492 yes_branch.evaluate(ctx)
2493 } else {
2494 no_branch.evaluate(ctx)
2495 }
2496 }
2497 }
2498 }
2499
2500 pub fn depth(&self) -> usize {
2502 match self {
2503 DecisionNode::Leaf(_) => 0,
2504 DecisionNode::Branch {
2505 yes_branch,
2506 no_branch,
2507 ..
2508 } => 1 + yes_branch.depth().max(no_branch.depth()),
2509 }
2510 }
2511}
2512
2513#[allow(dead_code)]
2515pub struct FlatSubstitution {
2516 pairs: Vec<(String, String)>,
2517}
2518
2519#[allow(dead_code)]
2520impl FlatSubstitution {
2521 pub fn new() -> Self {
2523 Self { pairs: Vec::new() }
2524 }
2525
2526 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
2528 self.pairs.push((from.into(), to.into()));
2529 }
2530
2531 pub fn apply(&self, s: &str) -> String {
2533 let mut result = s.to_string();
2534 for (from, to) in &self.pairs {
2535 result = result.replace(from.as_str(), to.as_str());
2536 }
2537 result
2538 }
2539
2540 pub fn len(&self) -> usize {
2542 self.pairs.len()
2543 }
2544
2545 pub fn is_empty(&self) -> bool {
2547 self.pairs.is_empty()
2548 }
2549}
2550
2551impl Default for FlatSubstitution {
2552 fn default() -> Self {
2553 Self::new()
2554 }
2555}
2556
2557#[allow(dead_code)]
2559pub struct Stopwatch {
2560 start: std::time::Instant,
2561 splits: Vec<f64>,
2562}
2563
2564#[allow(dead_code)]
2565impl Stopwatch {
2566 pub fn start() -> Self {
2568 Self {
2569 start: std::time::Instant::now(),
2570 splits: Vec::new(),
2571 }
2572 }
2573
2574 pub fn split(&mut self) {
2576 self.splits.push(self.elapsed_ms());
2577 }
2578
2579 pub fn elapsed_ms(&self) -> f64 {
2581 self.start.elapsed().as_secs_f64() * 1000.0
2582 }
2583
2584 pub fn splits(&self) -> &[f64] {
2586 &self.splits
2587 }
2588
2589 pub fn num_splits(&self) -> usize {
2591 self.splits.len()
2592 }
2593}
2594
2595#[allow(dead_code)]
2597pub enum Either2<A, B> {
2598 First(A),
2600 Second(B),
2602}
2603
2604#[allow(dead_code)]
2605impl<A, B> Either2<A, B> {
2606 pub fn is_first(&self) -> bool {
2608 matches!(self, Either2::First(_))
2609 }
2610
2611 pub fn is_second(&self) -> bool {
2613 matches!(self, Either2::Second(_))
2614 }
2615
2616 pub fn first(self) -> Option<A> {
2618 match self {
2619 Either2::First(a) => Some(a),
2620 _ => None,
2621 }
2622 }
2623
2624 pub fn second(self) -> Option<B> {
2626 match self {
2627 Either2::Second(b) => Some(b),
2628 _ => None,
2629 }
2630 }
2631
2632 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
2634 match self {
2635 Either2::First(a) => Either2::First(f(a)),
2636 Either2::Second(b) => Either2::Second(b),
2637 }
2638 }
2639}
2640
2641#[allow(dead_code)]
2643pub struct WriteOnce<T> {
2644 value: std::cell::Cell<Option<T>>,
2645}
2646
2647#[allow(dead_code)]
2648impl<T: Copy> WriteOnce<T> {
2649 pub fn new() -> Self {
2651 Self {
2652 value: std::cell::Cell::new(None),
2653 }
2654 }
2655
2656 pub fn write(&self, val: T) -> bool {
2658 if self.value.get().is_some() {
2659 return false;
2660 }
2661 self.value.set(Some(val));
2662 true
2663 }
2664
2665 pub fn read(&self) -> Option<T> {
2667 self.value.get()
2668 }
2669
2670 pub fn is_written(&self) -> bool {
2672 self.value.get().is_some()
2673 }
2674}
2675
2676impl<T: Copy> Default for WriteOnce<T> {
2677 fn default() -> Self {
2678 Self::new()
2679 }
2680}
2681
2682#[allow(dead_code)]
2684pub struct SparseVec<T: Default + Clone + PartialEq> {
2685 entries: std::collections::HashMap<usize, T>,
2686 default_: T,
2687 logical_len: usize,
2688}
2689
2690#[allow(dead_code)]
2691impl<T: Default + Clone + PartialEq> SparseVec<T> {
2692 pub fn new(len: usize) -> Self {
2694 Self {
2695 entries: std::collections::HashMap::new(),
2696 default_: T::default(),
2697 logical_len: len,
2698 }
2699 }
2700
2701 pub fn set(&mut self, idx: usize, val: T) {
2703 if val == self.default_ {
2704 self.entries.remove(&idx);
2705 } else {
2706 self.entries.insert(idx, val);
2707 }
2708 }
2709
2710 pub fn get(&self, idx: usize) -> &T {
2712 self.entries.get(&idx).unwrap_or(&self.default_)
2713 }
2714
2715 pub fn len(&self) -> usize {
2717 self.logical_len
2718 }
2719
2720 pub fn is_empty(&self) -> bool {
2722 self.len() == 0
2723 }
2724
2725 pub fn nnz(&self) -> usize {
2727 self.entries.len()
2728 }
2729}
2730
2731#[allow(dead_code)]
2733pub struct StackCalc {
2734 stack: Vec<i64>,
2735}
2736
2737#[allow(dead_code)]
2738impl StackCalc {
2739 pub fn new() -> Self {
2741 Self { stack: Vec::new() }
2742 }
2743
2744 pub fn push(&mut self, n: i64) {
2746 self.stack.push(n);
2747 }
2748
2749 pub fn add(&mut self) {
2751 let b = self
2752 .stack
2753 .pop()
2754 .expect("stack must have at least two values for add");
2755 let a = self
2756 .stack
2757 .pop()
2758 .expect("stack must have at least two values for add");
2759 self.stack.push(a + b);
2760 }
2761
2762 pub fn sub(&mut self) {
2764 let b = self
2765 .stack
2766 .pop()
2767 .expect("stack must have at least two values for sub");
2768 let a = self
2769 .stack
2770 .pop()
2771 .expect("stack must have at least two values for sub");
2772 self.stack.push(a - b);
2773 }
2774
2775 pub fn mul(&mut self) {
2777 let b = self
2778 .stack
2779 .pop()
2780 .expect("stack must have at least two values for mul");
2781 let a = self
2782 .stack
2783 .pop()
2784 .expect("stack must have at least two values for mul");
2785 self.stack.push(a * b);
2786 }
2787
2788 pub fn peek(&self) -> Option<i64> {
2790 self.stack.last().copied()
2791 }
2792
2793 pub fn depth(&self) -> usize {
2795 self.stack.len()
2796 }
2797}
2798
2799impl Default for StackCalc {
2800 fn default() -> Self {
2801 Self::new()
2802 }
2803}
2804
2805#[cfg(test)]
2806mod tests_padding3 {
2807 use super::*;
2808
2809 #[test]
2810 fn test_decision_node() {
2811 let tree = DecisionNode::Branch {
2812 key: "x".into(),
2813 val: "1".into(),
2814 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
2815 no_branch: Box::new(DecisionNode::Leaf("no".into())),
2816 };
2817 let mut ctx = std::collections::HashMap::new();
2818 ctx.insert("x".into(), "1".into());
2819 assert_eq!(tree.evaluate(&ctx), "yes");
2820 ctx.insert("x".into(), "2".into());
2821 assert_eq!(tree.evaluate(&ctx), "no");
2822 assert_eq!(tree.depth(), 1);
2823 }
2824
2825 #[test]
2826 fn test_flat_substitution() {
2827 let mut sub = FlatSubstitution::new();
2828 sub.add("foo", "bar");
2829 sub.add("baz", "qux");
2830 assert_eq!(sub.apply("foo and baz"), "bar and qux");
2831 assert_eq!(sub.len(), 2);
2832 }
2833
2834 #[test]
2835 fn test_stopwatch() {
2836 let mut sw = Stopwatch::start();
2837 sw.split();
2838 sw.split();
2839 assert_eq!(sw.num_splits(), 2);
2840 assert!(sw.elapsed_ms() >= 0.0);
2841 for &s in sw.splits() {
2842 assert!(s >= 0.0);
2843 }
2844 }
2845
2846 #[test]
2847 fn test_either2() {
2848 let e: Either2<i32, &str> = Either2::First(42);
2849 assert!(e.is_first());
2850 let mapped = e.map_first(|x| x * 2);
2851 assert_eq!(mapped.first(), Some(84));
2852
2853 let e2: Either2<i32, &str> = Either2::Second("hello");
2854 assert!(e2.is_second());
2855 assert_eq!(e2.second(), Some("hello"));
2856 }
2857
2858 #[test]
2859 fn test_write_once() {
2860 let wo: WriteOnce<u32> = WriteOnce::new();
2861 assert!(!wo.is_written());
2862 assert!(wo.write(42));
2863 assert!(!wo.write(99)); assert_eq!(wo.read(), Some(42));
2865 }
2866
2867 #[test]
2868 fn test_sparse_vec() {
2869 let mut sv: SparseVec<i32> = SparseVec::new(100);
2870 sv.set(5, 10);
2871 sv.set(50, 20);
2872 assert_eq!(*sv.get(5), 10);
2873 assert_eq!(*sv.get(50), 20);
2874 assert_eq!(*sv.get(0), 0); assert_eq!(sv.nnz(), 2);
2876 sv.set(5, 0); assert_eq!(sv.nnz(), 1);
2878 }
2879
2880 #[test]
2881 fn test_stack_calc() {
2882 let mut calc = StackCalc::new();
2883 calc.push(3);
2884 calc.push(4);
2885 calc.add();
2886 assert_eq!(calc.peek(), Some(7));
2887 calc.push(2);
2888 calc.mul();
2889 assert_eq!(calc.peek(), Some(14));
2890 }
2891}