refactor: Create ToothDisplay trait

This commit is contained in:
Guilhem 2022-08-04 16:45:53 +02:00
parent 519ae2a261
commit 1bae864faa
5 changed files with 152 additions and 73 deletions

View File

@ -1,4 +1,4 @@
use crate::display::format_dentition;
use crate::display::{ToothCliFormatter, ToothDisplay};
use crate::lib::NotationKind;
use crate::lib::Tooth;
use clap::{Parser, Subcommand, ValueEnum};
@ -26,6 +26,8 @@ enum Action {
notation: NotationKindArg,
#[clap(takes_value = false, short = 'p', long)]
primary: bool,
#[clap(value_parser)]
value: Option<String>,
},
}
#[derive(Parser, Debug)]
@ -64,8 +66,28 @@ pub fn run_cli() {
println!("{}", output_string);
}
Action::Display { notation, primary } => {
println!("{}", format_dentition(!primary, &convert_kind(notation)))
Action::Display {
notation,
primary,
value,
} => {
let converted_value = match value {
Some(t) => {
let tooth_result = Tooth::from(t, &notation.into());
match tooth_result {
Ok(tr) => Some(tr),
Err(err) => {
eprintln!("{}", err);
return;
}
}
}
None => None,
};
println!(
"{}",
ToothCliFormatter::format(&notation.into(), !primary, &converted_value)
);
}
};
}

View File

@ -1,67 +0,0 @@
use crate::lib::NotationKind;
use crate::lib::{QuadrantKind, Tooth, ToothType};
use owo_colors::{OwoColorize, Style};
enum JawKind {
Top,
Bottom,
}
fn format_tooth(tooth: &Tooth, notation: &NotationKind) -> String {
let tooth_label = tooth.to(notation);
let mut style = Style::new();
style = match &tooth.get_type() {
ToothType::Canine => style.yellow(),
ToothType::Incisor => style.green(),
ToothType::Premolar => style.cyan(),
ToothType::Molar => style.blue(),
};
format!(" {}", tooth_label.style(style))
}
fn format_quadrant(quadrant: QuadrantKind, permanent: bool, notation: &NotationKind) -> String {
let max = Tooth::quadrant_max(permanent);
let format_tooth = |i| {
let tooth = Tooth::new(i, quadrant, permanent).unwrap();
format_tooth(&tooth, notation)
};
if quadrant == QuadrantKind::TopLeft || quadrant == QuadrantKind::BottomLeft {
(1..=max).rev().map(format_tooth).collect()
} else {
(1..=max).map(format_tooth).collect()
}
}
fn format_jaw(jaw: JawKind, permanent: bool, notation: &NotationKind) -> String {
let (quadrant_1, quadrant_2) = match jaw {
JawKind::Top => (QuadrantKind::TopLeft, QuadrantKind::TopRight),
JawKind::Bottom => (QuadrantKind::BottomLeft, QuadrantKind::BottomRight),
};
format!(
" {} |{}",
format_quadrant(quadrant_1, permanent, notation),
format_quadrant(quadrant_2, permanent, notation)
)
}
pub fn format_dentition(permanent: bool, notation: &NotationKind) -> String {
let item_count = Tooth::quadrant_max(permanent);
let item_width = match (notation, permanent) {
(NotationKind::Iso, _) => 2,
(NotationKind::Uns, true) => 2,
(NotationKind::Uns, false) => 1,
(NotationKind::Alphanumeric, _) => 3,
};
let jaw_len = (item_width + 1) * (item_count * 2 + 1);
let mut result = String::with_capacity((jaw_len * 4).into());
result.push_str(&format_jaw(JawKind::Top, permanent, notation));
result.push_str("\nR ");
for _ in 1..=jaw_len {
result.push_str("-");
}
result.push_str(" L\n");
result.push_str(&format_jaw(JawKind::Bottom, permanent, notation));
result
}

110
src/display/cli.rs Normal file
View File

@ -0,0 +1,110 @@
use super::JawKind;
use crate::display::ToothDisplay;
use crate::lib::{NotationKind, QuadrantKind, Tooth, ToothType};
use owo_colors::{OwoColorize, Style};
pub struct ToothCliFormatter;
impl ToothCliFormatter {
fn format_tooth(
tooth: &Tooth,
notation: &NotationKind,
selected_value: &Option<Tooth>,
) -> String {
let tooth_label = tooth.to(notation);
let mut style = Style::new();
style = match &tooth.get_type() {
ToothType::Canine => style.yellow(),
ToothType::Incisor => style.green(),
ToothType::Premolar => style.cyan(),
ToothType::Molar => style.blue(),
};
if let Some(t) = selected_value {
if t == tooth {
style = style.reversed();
}
}
format!(" {}", tooth_label.style(style))
}
fn format_quadrant(
notation: &NotationKind,
permanent: bool,
quadrant: QuadrantKind,
selected_value: &Option<Tooth>,
) -> String {
let max = Tooth::quadrant_max(permanent);
let format_tooth = |i| {
let tooth = Tooth::new(i, quadrant, permanent).unwrap();
ToothCliFormatter::format_tooth(&tooth, notation, selected_value)
};
if quadrant == QuadrantKind::TopLeft || quadrant == QuadrantKind::BottomLeft {
(1..=max).rev().map(format_tooth).collect()
} else {
(1..=max).map(format_tooth).collect()
}
}
fn format_jaw(
notation: &NotationKind,
permanent: bool,
jaw: JawKind,
selected_value: &Option<Tooth>,
) -> String {
let (quadrant_1, quadrant_2) = match jaw {
JawKind::Top => (QuadrantKind::TopLeft, QuadrantKind::TopRight),
JawKind::Bottom => (QuadrantKind::BottomLeft, QuadrantKind::BottomRight),
};
format!(
" {} |{}",
ToothCliFormatter::format_quadrant(notation, permanent, quadrant_1, selected_value),
ToothCliFormatter::format_quadrant(notation, permanent, quadrant_2, selected_value)
)
}
fn calculate_separator_len(notation: &NotationKind, permanent: bool) -> u8 {
let item_count = Tooth::quadrant_max(permanent);
let item_width = match (notation, permanent) {
(NotationKind::Iso, _) => 2,
(NotationKind::Uns, true) => 2,
(NotationKind::Uns, false) => 1,
(NotationKind::Alphanumeric, _) => 3,
};
(item_width + 1) * (item_count * 2 + 1)
}
pub fn format_dentition(
notation: &NotationKind,
permanent: bool,
selected_value: &Option<Tooth>,
) -> String {
let jaw_len = ToothCliFormatter::calculate_separator_len(notation, permanent);
let mut result = String::with_capacity((jaw_len * 4).into());
result.push_str(&ToothCliFormatter::format_jaw(
notation,
permanent,
JawKind::Top,
selected_value,
));
result.push_str("\nR ");
result.push_str(&"-".repeat(jaw_len.into()));
result.push_str(" L\n");
result.push_str(&ToothCliFormatter::format_jaw(
notation,
permanent,
JawKind::Bottom,
selected_value,
));
result
}
}
impl ToothDisplay for ToothCliFormatter {
fn format(notation: &NotationKind, permanent: bool, selected_value: &Option<Tooth>) -> String {
ToothCliFormatter::format_dentition(notation, permanent, selected_value)
}
}

13
src/display/mod.rs Normal file
View File

@ -0,0 +1,13 @@
pub use crate::display::cli::*;
use crate::lib::NotationKind;
use crate::lib::Tooth;
mod cli;
pub enum JawKind {
Top,
Bottom,
}
pub trait ToothDisplay {
fn format(notation: &NotationKind, permanent: bool, selected_value: &Option<Tooth>) -> String;
}

View File

@ -20,6 +20,7 @@ pub enum ToothType {
Molar,
}
#[derive(PartialEq)]
pub struct Tooth {
quadrant: QuadrantKind,
number: u8,