use pass_lang::{Outcome, Pass, PassError, PassManager};
struct CollapseSpaces;
impl Pass<String> for CollapseSpaces {
fn name(&self) -> &'static str {
"collapse-spaces"
}
fn run(&mut self, unit: &mut String) -> Result<Outcome, PassError> {
if !unit.contains(" ") {
return Ok(Outcome::Unchanged);
}
*unit = unit.replace(" ", " ");
Ok(Outcome::Changed)
}
}
struct TrimTrailing;
impl Pass<String> for TrimTrailing {
fn name(&self) -> &'static str {
"trim-trailing"
}
fn run(&mut self, unit: &mut String) -> Result<Outcome, PassError> {
let trimmed = unit.trim_end();
if trimmed.len() == unit.len() {
return Ok(Outcome::Unchanged);
}
unit.truncate(trimmed.len());
Ok(Outcome::Changed)
}
}
struct Lowercase;
impl Pass<String> for Lowercase {
fn name(&self) -> &'static str {
"lowercase"
}
fn run(&mut self, unit: &mut String) -> Result<Outcome, PassError> {
if !unit.bytes().any(|b| b.is_ascii_uppercase()) {
return Ok(Outcome::Unchanged);
}
unit.make_ascii_lowercase();
Ok(Outcome::Changed)
}
}
fn main() {
let mut text = String::from("Hello World ");
println!("before: {text:?}");
let mut pm = PassManager::new();
pm.add(CollapseSpaces).add(TrimTrailing).add(Lowercase);
let report = pm
.run_to_fixpoint(&mut text, 16)
.expect("none of these passes can fail");
println!("after: {text:?}");
println!(
"sweeps={} changes={} converged={}",
report.iterations(),
report.changes(),
report.converged(),
);
assert_eq!(text, "hello world");
assert!(report.converged());
}