use crate::Error;
use std::{cmp::Ordering, str::FromStr};
#[derive(Clone, Copy, Debug)]
pub enum Unit {
Auto,
Ch(f64),
Cm(f64),
Dpi(f64),
Dpcm(f64),
Dppx(f64),
Em(f64),
Fr(f64),
In(f64),
Mm(f64),
Pc(f64),
Pt(f64),
Px(f64),
Q(f64),
Rem(f64),
Vh(f64),
Vmax(f64),
Vmin(f64),
Vw(f64),
Percent(f64),
None(f64),
}
impl Eq for Unit {}
impl PartialEq for Unit {
fn eq(&self, o: &Self) -> bool {
self.to_string().eq(&o.to_string())
}
}
impl Ord for Unit {
fn cmp(&self, _: &Self) -> Ordering {
Ordering::Equal
}
}
impl PartialOrd for Unit {
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
None
}
}
impl Default for Unit {
fn default() -> Unit {
Unit::Auto
}
}
impl FromStr for Unit {
type Err = Error;
fn from_str(s: &str) -> Result<Unit, Self::Err> {
let t = s.trim();
let u = t
.find(|c: char| !c.is_numeric() && !c.eq(&'.'))
.unwrap_or(0);
let v: f64 = t[..u]
.trim()
.parse()
.unwrap_or_else(|_| t[u..].trim().parse().unwrap_or(1.0));
Ok(match t[u..].trim().to_ascii_lowercase().as_str() {
"auto" | "inherit" => Unit::Auto,
"ch" => Unit::Ch(v),
"cm" => Unit::Cm(v),
"dpcm" => Unit::Dpcm(v),
"dpi" => Unit::Dpi(v),
"dppx" => Unit::Dppx(v),
"em" => Unit::Em(v),
"fr" => Unit::Fr(v),
"in" => Unit::In(v),
"mm" => Unit::Mm(v),
"pc" => Unit::Pc(v),
"pt" => Unit::Pt(v),
"px" => Unit::Px(v),
"q" => Unit::Q(v),
"rem" => Unit::Rem(v),
"vh" => Unit::Vh(v),
"vmax" => Unit::Vmax(v),
"vmin" => Unit::Vmin(v),
"vw" => Unit::Vw(v),
"%" => Unit::Percent(t[..u].parse().unwrap_or(100.0)),
_ => Unit::None(v),
})
}
}
impl ToString for Unit {
fn to_string(&self) -> String {
match self {
Unit::Auto => "auto".into(),
Unit::Ch(n) => format!("{:.1}ch", n),
Unit::Cm(n) => format!("{:.1}cm", n),
Unit::Dpcm(n) => format!("{:.1}dpcm", n),
Unit::Dpi(n) => format!("{:.1}dpi", n),
Unit::Dppx(n) => format!("{:.1}dppx", n),
Unit::Em(n) => format!("{:.1}em", n),
Unit::Fr(n) => format!("{:.1}fr", n),
Unit::In(n) => format!("{:.1}in", n),
Unit::Mm(n) => format!("{:.1}mm", n),
Unit::Pc(n) => format!("{:.1}pc", n),
Unit::Pt(n) => format!("{:.1}pt", n),
Unit::Px(n) => format!("{:.1}px", n),
Unit::Q(n) => format!("{:.1}Q", n),
Unit::Rem(n) => format!("{:.1}rem", n),
Unit::Vh(n) => format!("{:.1}vh", n),
Unit::Vmax(n) => format!("{:.1}vmax", n),
Unit::Vmin(n) => format!("{:.1}vmin", n),
Unit::Vw(n) => format!("{:.1}vw", n),
Unit::Percent(n) => format!("{:.1}%", n),
Unit::None(n) => format!("{:.0}", n),
}
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct VecUnit(pub Vec<Unit>);
impl Default for VecUnit {
fn default() -> VecUnit {
VecUnit(vec![Unit::None(0.0)])
}
}
impl ToString for VecUnit {
fn to_string(&self) -> String {
self.0
.iter()
.map(|u| u.to_string())
.collect::<Vec<String>>()
.join(" ")
}
}
impl From<Vec<Unit>> for VecUnit {
fn from(vu: Vec<Unit>) -> VecUnit {
VecUnit(vu)
}
}