//! Guards the lockstep rules: the core must not use anything whose result //! can differ between machines or between runs. use std::fs; use std::path::{Path, PathBuf}; /// Text that must not appear anywhere in the source of the core, and why. const FORBIDDEN: &[(&str, &str)] = &[ ("f32", "floating point results can differ between machines"), ("f64", "floating point results can differ between machines"), ( "HashMap", "iteration order differs between runs; use BTreeMap or Vec", ), ( "HashSet", "iteration order differs between runs; use BTreeSet or Vec", ), ("std::time", "the core must not read the clock"), ("Instant", "the core must not read the clock"), ("SystemTime", "the core must not read the clock"), ("std::thread", "the core must stay single-threaded"), ("std::env", "the core must not depend on the environment"), ( "std::fs", "the core must not touch files; the shell does that", ), ( "std::net", "the core must not open connections; the shell does that", ), ("unsafe", "the core forbids unsafe code"), ]; fn rust_files(dir: &Path, out: &mut Vec) { for entry in fs::read_dir(dir).expect("source directory is readable") { let path = entry.expect("directory entry is readable").path(); if path.is_dir() { rust_files(&path, out); } else if path.extension().is_some_and(|ext| ext == "rs") { out.push(path); } } } #[test] fn core_source_uses_no_forbidden_apis() { let src = Path::new(env!("CARGO_MANIFEST_DIR")).join("src"); let mut files = Vec::new(); rust_files(&src, &mut files); files.sort(); assert!( !files.is_empty(), "no source files found in {}", src.display() ); let mut problems = Vec::new(); for file in &files { let text = fs::read_to_string(file).expect("source file is readable"); for (number, line) in text.lines().enumerate() { for (needle, reason) in FORBIDDEN { if line.contains(needle) { problems.push(format!( "{}:{}: `{needle}`: {reason}", file.display(), number + 1 )); } } } } assert!( problems.is_empty(), "forbidden APIs in the core:\n{}", problems.join("\n") ); }