1use crate::Error;
3use std::{cmp::Ordering, str::FromStr};
4
5#[derive(Clone, Copy, Debug)]
41pub enum Unit {
42 Auto,
44 Ch(f64),
46 Cm(f64),
48 Dpi(f64),
50 Dpcm(f64),
52 Dppx(f64),
54 Em(f64),
56 Fr(f64),
58 In(f64),
60 Mm(f64),
62 Pc(f64),
64 Pt(f64),
66 Px(f64),
68 Q(f64),
70 Rem(f64),
72 Vh(f64),
74 Vmax(f64),
76 Vmin(f64),
78 Vw(f64),
80 Percent(f64),
82 None(f64),
84}
85
86impl Eq for Unit {}
87
88impl PartialEq for Unit {
89 fn eq(&self, o: &Self) -> bool {
90 self.to_string().eq(&o.to_string())
91 }
92}
93
94impl Ord for Unit {
95 fn cmp(&self, _: &Self) -> Ordering {
96 Ordering::Equal
97 }
98}
99
100impl PartialOrd for Unit {
101 fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
102 None
103 }
104}
105
106impl Default for Unit {
107 fn default() -> Unit {
108 Unit::Auto
109 }
110}
111
112impl FromStr for Unit {
113 type Err = Error;
114
115 fn from_str(s: &str) -> Result<Unit, Self::Err> {
116 let t = s.trim();
117 let u = t
118 .find(|c: char| !c.is_numeric() && !c.eq(&'.'))
119 .unwrap_or(0);
120
121 let v: f64 = t[..u]
122 .trim()
123 .parse()
124 .unwrap_or_else(|_| t[u..].trim().parse().unwrap_or(1.0));
125
126 Ok(match t[u..].trim().to_ascii_lowercase().as_str() {
127 "auto" | "inherit" => Unit::Auto,
128 "ch" => Unit::Ch(v),
129 "cm" => Unit::Cm(v),
130 "dpcm" => Unit::Dpcm(v),
131 "dpi" => Unit::Dpi(v),
132 "dppx" => Unit::Dppx(v),
133 "em" => Unit::Em(v),
134 "fr" => Unit::Fr(v),
135 "in" => Unit::In(v),
136 "mm" => Unit::Mm(v),
137 "pc" => Unit::Pc(v),
138 "pt" => Unit::Pt(v),
139 "px" => Unit::Px(v),
140 "q" => Unit::Q(v),
141 "rem" => Unit::Rem(v),
142 "vh" => Unit::Vh(v),
143 "vmax" => Unit::Vmax(v),
144 "vmin" => Unit::Vmin(v),
145 "vw" => Unit::Vw(v),
146 "%" => Unit::Percent(t[..u].parse().unwrap_or(100.0)),
147 _ => Unit::None(v),
148 })
149 }
150}
151
152impl ToString for Unit {
153 fn to_string(&self) -> String {
154 match self {
155 Unit::Auto => "auto".into(),
156 Unit::Ch(n) => format!("{:.1}ch", n),
157 Unit::Cm(n) => format!("{:.1}cm", n),
158 Unit::Dpcm(n) => format!("{:.1}dpcm", n),
159 Unit::Dpi(n) => format!("{:.1}dpi", n),
160 Unit::Dppx(n) => format!("{:.1}dppx", n),
161 Unit::Em(n) => format!("{:.1}em", n),
162 Unit::Fr(n) => format!("{:.1}fr", n),
163 Unit::In(n) => format!("{:.1}in", n),
164 Unit::Mm(n) => format!("{:.1}mm", n),
165 Unit::Pc(n) => format!("{:.1}pc", n),
166 Unit::Pt(n) => format!("{:.1}pt", n),
167 Unit::Px(n) => format!("{:.1}px", n),
168 Unit::Q(n) => format!("{:.1}Q", n),
169 Unit::Rem(n) => format!("{:.1}rem", n),
170 Unit::Vh(n) => format!("{:.1}vh", n),
171 Unit::Vmax(n) => format!("{:.1}vmax", n),
172 Unit::Vmin(n) => format!("{:.1}vmin", n),
173 Unit::Vw(n) => format!("{:.1}vw", n),
174 Unit::Percent(n) => format!("{:.1}%", n),
175 Unit::None(n) => format!("{:.0}", n),
176 }
177 }
178}
179
180#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
182pub struct VecUnit(pub Vec<Unit>);
183
184impl Default for VecUnit {
185 fn default() -> VecUnit {
186 VecUnit(vec![Unit::None(0.0)])
187 }
188}
189
190impl ToString for VecUnit {
191 fn to_string(&self) -> String {
192 self.0
193 .iter()
194 .map(|u| u.to_string())
195 .collect::<Vec<String>>()
196 .join(" ")
197 }
198}
199
200impl From<Vec<Unit>> for VecUnit {
201 fn from(vu: Vec<Unit>) -> VecUnit {
202 VecUnit(vu)
203 }
204}