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::NotationKind;
use crate::lib::Tooth; use crate::lib::Tooth;
use clap::{Parser, Subcommand, ValueEnum}; use clap::{Parser, Subcommand, ValueEnum};
@ -26,6 +26,8 @@ enum Action {
notation: NotationKindArg, notation: NotationKindArg,
#[clap(takes_value = false, short = 'p', long)] #[clap(takes_value = false, short = 'p', long)]
primary: bool, primary: bool,
#[clap(value_parser)]
value: Option<String>,
}, },
} }
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -43,9 +45,9 @@ impl Into<NotationKind> for NotationKindArg {
impl Into<NotationKind> for &NotationKindArg { impl Into<NotationKind> for &NotationKindArg {
fn into(self) -> NotationKind { fn into(self) -> NotationKind {
match self { match self {
NotationKindArg::Iso => NotationKind::Iso, NotationKindArg::Iso => NotationKind::Iso,
NotationKindArg::Uns => NotationKind::Uns, NotationKindArg::Uns => NotationKind::Uns,
NotationKindArg::Alphanumeric => NotationKind::Alphanumeric, NotationKindArg::Alphanumeric => NotationKind::Alphanumeric,
} }
} }
} }
@ -64,8 +66,28 @@ pub fn run_cli() {
println!("{}", output_string); println!("{}", output_string);
} }
Action::Display { notation, primary } => { Action::Display {
println!("{}", format_dentition(!primary, &convert_kind(notation))) 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, Molar,
} }
#[derive(PartialEq)]
pub struct Tooth { pub struct Tooth {
quadrant: QuadrantKind, quadrant: QuadrantKind,
number: u8, number: u8,