use crate::error::Result;
use crate::step::OptionChoice;
use crate::step::option::OptionResult;
pub trait OptionHandler: Send + Sync {
fn select_option(&self, choices: &[OptionChoice], plan: Option<&str>) -> Result<OptionResult>;
}
pub struct CliOptionHandler;
impl OptionHandler for CliOptionHandler {
fn select_option(&self, choices: &[OptionChoice], plan: Option<&str>) -> Result<OptionResult> {
crate::step::option::run_option(choices, plan)
}
}
#[cfg(test)]
pub struct NoOpOptionHandler;
#[cfg(test)]
impl OptionHandler for NoOpOptionHandler {
fn select_option(
&self,
_choices: &[OptionChoice],
_plan: Option<&str>,
) -> Result<OptionResult> {
panic!(
"NoOpOptionHandler: unexpected option step -- use FirstChoiceOptionHandler if option steps are expected"
);
}
}
#[cfg(test)]
pub struct FirstChoiceOptionHandler {
call_count: std::sync::atomic::AtomicUsize,
}
#[cfg(test)]
impl Default for FirstChoiceOptionHandler {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
impl FirstChoiceOptionHandler {
#[must_use]
pub fn new() -> Self {
Self {
call_count: std::sync::atomic::AtomicUsize::new(0),
}
}
pub fn call_count(&self) -> usize {
self.call_count.load(std::sync::atomic::Ordering::Relaxed)
}
}
#[cfg(test)]
impl OptionHandler for FirstChoiceOptionHandler {
fn select_option(&self, choices: &[OptionChoice], _plan: Option<&str>) -> Result<OptionResult> {
self.call_count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let (next, text_input) = match choices.first() {
Some(OptionChoice::TextInput { next, .. }) => (next.clone(), Some(String::new())),
Some(OptionChoice::Selector { next, .. }) => (next.clone(), None),
None => (None, None),
};
Ok(OptionResult {
next_step: next,
text_input,
})
}
}