use std::str::FromStr;
use crate::cells::column_name_to_number;
pub enum Command {
Get {
cell_identifier: CellIdentifier,
},
Set {
cell_identifier: CellIdentifier,
cell_expr: String,
},
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct CellIdentifier {
pub col: u32,
pub row: u32,
}
impl FromStr for Command {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
const MAX_PARTS: usize = 3;
let opt = (|| {
let mut parts = s.splitn(MAX_PARTS, |c: char| c.is_ascii_whitespace());
let command = parts.next()?;
let cell_identifier = parts.next()?.parse::<CellIdentifier>().ok()?;
let request = match command {
"get" => {
let non_empty_rest = parts.next().is_some();
if non_empty_rest {
return None;
}
Self::Get { cell_identifier }
}
"set" => {
let cell_expr = parts.next()?.to_string();
Self::Set {
cell_identifier,
cell_expr,
}
}
_ => return None,
};
Some(request)
})();
opt.ok_or_else(|| format!("Error parsing request: {s}"))
}
}
impl FromStr for CellIdentifier {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let opt = (|| {
let col_name = s
.chars()
.take_while(char::is_ascii_uppercase)
.collect::<String>();
if col_name.is_empty() {
return None;
}
let col = column_name_to_number(&col_name);
let row = s
.chars()
.skip_while(char::is_ascii_uppercase)
.collect::<String>()
.parse::<u32>()
.ok()?
.checked_sub(1)?;
Some(Self { col, row })
})();
opt.ok_or_else(|| format!("Error parsing cell position: {s}"))
}
}