diff --git a/Cargo.lock b/Cargo.lock index d9dc346..35f8c5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,6 +69,7 @@ name = "dental-notation" version = "0.1.0" dependencies = [ "clap", + "owo-colors", ] [[package]] @@ -120,6 +121,12 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + [[package]] name = "proc-macro-error" version = "1.0.4" diff --git a/Cargo.toml b/Cargo.toml index 4c51d97..b40ffe2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -clap = {version = "3.2.5", features = [ "derive" ] } \ No newline at end of file +clap = {version = "3.2.5", features = [ "derive" ] } +owo-colors = "3" \ No newline at end of file diff --git a/src/display.rs b/src/display.rs new file mode 100644 index 0000000..9ade6bd --- /dev/null +++ b/src/display.rs @@ -0,0 +1,67 @@ +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 +} diff --git a/src/lib.rs b/src/lib.rs index 801d45b..2dab6a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,13 @@ pub enum QuadrantKind { BottomRight, } +pub enum ToothType { + Incisor, + Canine, + Premolar, + Molar, +} + pub struct Tooth { quadrant: QuadrantKind, number: u8, @@ -20,7 +27,7 @@ pub struct Tooth { } impl Tooth { - fn _new(number: u8, quadrant: QuadrantKind, permanent: bool) -> Result { + pub fn new(number: u8, quadrant: QuadrantKind, permanent: bool) -> Result { if let Err(err) = Tooth::check_tooth_number(number, permanent) { return Err(err); } @@ -48,7 +55,7 @@ impl Tooth { } } - fn quadrant_max(permanent: bool) -> u8 { + pub fn quadrant_max(permanent: bool) -> u8 { if permanent { 8 } else { @@ -155,7 +162,7 @@ impl Tooth { }; if self.permanent { - value.to_string() + format!("{:2}", value) } else { ((value + 64) as char).to_string() } @@ -254,6 +261,15 @@ impl Tooth { Err(err) => Err(err), } } + + pub fn get_type(&self) -> ToothType { + match (&self.number, &self.permanent) { + (1..=2, _) => ToothType::Incisor, + (3, _) => ToothType::Canine, + (4..=5, true) => ToothType::Premolar, + _ => ToothType::Molar, + } + } } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs index 79286f4..5f12f15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod cli; +mod display; mod lib; fn main() {