use std::collections::HashMap;
use std::fmt;
use std::fmt::Debug;
use std::io;
use std::io::Write;
#[derive(PartialEq, Debug)]
pub struct Procedure {
title: String,
description: String,
steps: Vec<Step>,
}
impl Procedure {
pub fn new(title: &str, description: &str) -> Self {
Procedure {
title: title.to_string(),
description: description.to_string(),
steps: vec![],
}
}
pub fn add_manual_step(mut self, title: &str, instructions: &str) -> Self {
let new_step = Step::new_manual(title, instructions);
self.steps.push(new_step);
self
}
pub fn add_automated_step<F>(mut self, title: &str, automation: F) -> Self
where
F: Fn(HashMap<String, String>) -> HashMap<String, String> + 'static,
{
let new_step = Step::new_automated(title, Box::new(automation));
self.steps.push(new_step);
self
}
pub fn execute(self) {
println!("# {}\n", self.title);
println!("{}\n", self.description);
print!("Press [Enter] to begin ");
std::io::stdout().flush().expect("failed");
let mut _input: String = String::new();
io::stdin().read_line(&mut _input).expect("failed!");
println!();
let state = HashMap::new();
self.steps.iter().fold(state, handle_step);
println!("done!");
}
}
fn handle_step(state: HashMap<String, String>, step: &Step) -> HashMap<String, String> {
match step {
Step::Automated(automated_step) => {
println!("## {}\n", automated_step.title);
(automated_step.automation)(state)
}
Step::Manual(manual_step) => {
println!("## {}\n", manual_step.title);
println!("{}\n", manual_step.instructions);
print!("Press [Enter] to continue ");
std::io::stdout().flush().expect("failed");
let mut _input: String = String::new();
io::stdin().read_line(&mut _input).expect("failed!");
println!();
println!("hello");
state
}
}
}
#[derive(PartialEq, Debug)]
enum Step {
Manual(ManualStep),
Automated(AutomatedStep),
}
impl Step {
pub fn new_manual(title: &str, instructions: &str) -> Step {
Step::Manual(ManualStep {
title: title.to_string(),
instructions: instructions.to_string(),
})
}
pub fn new_automated(title: &str, automation: Automation) -> Step {
Step::Automated(AutomatedStep {
title: title.to_string(),
automation,
})
}
}
#[derive(PartialEq, Debug)]
struct ManualStep {
title: String,
instructions: String,
}
pub type Automation = Box<dyn Fn(HashMap<String, String>) -> HashMap<String, String>>;
struct AutomatedStep {
title: String,
automation: Automation,
}
impl PartialEq for AutomatedStep {
fn eq(&self, other: &Self) -> bool {
self.title == other.title
}
}
impl Debug for AutomatedStep {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AutomatedStep")
.field("title", &self.title)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let p = Procedure::new("hello", "world");
assert_eq!(
Procedure {
title: "hello".to_string(),
description: "world".to_string(),
steps: vec![]
},
p
);
}
#[test]
fn procedure_with_manual_step() {
let p = Procedure::new("hello", "world").add_manual_step("step", "instructions");
assert_eq!(
Procedure {
title: "hello".to_string(),
description: "world".to_string(),
steps: vec![Step::Manual(ManualStep {
title: "step".to_string(),
instructions: "instructions".to_string()
})],
},
p
);
}
}