Skip to main content

peacock_crest/
unit.rs

1use crate::style::prop_validation::TokenExpected;
2
3#[derive(Debug, Clone)]
4pub enum Length {
5    // absolute
6    Cm(f32),
7    Mm(f32),
8    Q(f32),
9    In(f32),
10    Pc(f32),
11    Pt(f32),
12    Px(f32),
13
14    // relative
15
16    // font
17    Cap(f32),
18    Ch(f32),
19    Em(f32),
20    Ex(f32),
21    Ic(f32),
22    Lh(f32),
23
24    // root element's font
25    RCap(f32),
26    RCh(f32),
27    REm(f32),
28    REx(f32),
29    RIc(f32),
30    RLh(f32),
31
32    // viewport
33    Vh(f32),
34    Vw(f32),
35    VMax(f32),
36    VMin(f32),
37    Vb(f32),
38    Vi(f32),
39
40    // container query
41    Cqw(f32),
42    Cqh(f32),
43    Cqi(f32),
44    Cqb(f32),
45    CqMin(f32),
46    CqMax(f32),
47}
48
49#[derive(Debug, Clone)]
50pub enum Angle {
51    Deg(f32),
52    Grad(f32),
53    Rad(f32),
54    Turn(f32),
55}
56
57#[derive(Debug, Clone)]
58pub enum Time {
59    Sec(f32),
60    Milli(f32),
61}
62
63#[derive(Debug, Clone)]
64pub enum Frequency {}
65
66#[derive(Debug, Clone)]
67pub enum Resolution {
68    Dpi(f32),
69    Dpcm(f32),
70    Dppx(f32),
71}
72
73#[derive(Debug, Clone, derive_more::From)]
74pub enum Dimension {
75    #[from]
76    Length(Length),
77    #[from]
78    Angle(Angle),
79    #[from]
80    Time(Time),
81    #[from]
82    Frequency(Frequency),
83    #[from]
84    Resolution(Resolution),
85}
86
87#[derive(Debug, Clone, derive_more::From)]
88pub struct Percentage(f32);
89
90#[derive(Debug, Clone, derive_more::From)]
91pub struct Hash(String);
92
93#[derive(Debug, Clone, derive_more::From)]
94pub enum Unit {
95    #[from]
96    Integer(i32),
97    #[from]
98    Number(f32),
99    #[from]
100    Dimension(Dimension),
101    #[from]
102    Percentage(Percentage),
103    #[from]
104    String(String),
105    #[from]
106    Hash(Hash),
107
108    #[from]
109    Function {
110        name: String,
111        required_return_type: TokenExpected,
112        params: Vec<Unit>,
113    },
114
115    #[from]
116    Shorthand(Box<Unit>, Box<Unit>),
117
118    UnknownIdent(String),
119}
120
121impl Length {
122    pub fn get(&self) -> f32 {
123        match self {
124            Length::Cm(num) => *num,
125            Length::Mm(num) => *num,
126            Length::Q(num) => *num,
127            Length::In(num) => *num,
128            Length::Pc(num) => *num,
129            Length::Pt(num) => *num,
130            Length::Px(num) => *num,
131
132            Length::Cap(num) => *num,
133            Length::Ch(num) => *num,
134            Length::Em(num) => *num,
135            Length::Ex(num) => *num,
136            Length::Ic(num) => *num,
137            Length::Lh(num) => *num,
138
139            Length::RCap(num) => *num,
140            Length::RCh(num) => *num,
141            Length::REm(num) => *num,
142            Length::REx(num) => *num,
143            Length::RIc(num) => *num,
144            Length::RLh(num) => *num,
145
146            Length::Vh(num) => *num,
147            Length::Vw(num) => *num,
148            Length::VMax(num) => *num,
149            Length::VMin(num) => *num,
150            Length::Vb(num) => *num,
151            Length::Vi(num) => *num,
152
153            Length::Cqw(num) => *num,
154            Length::Cqh(num) => *num,
155            Length::Cqi(num) => *num,
156            Length::Cqb(num) => *num,
157            Length::CqMin(num) => *num,
158            Length::CqMax(num) => *num,
159        }
160    }
161
162    pub fn from_pair(num: f32, unit: &str) -> Option<Self> {
163        match unit {
164            "cm" => Some(Self::Cm(num)),
165            "mm" => Some(Self::Mm(num)),
166            "Q" => Some(Self::Q(num)),
167            "in" => Some(Self::In(num)),
168            "pc" => Some(Self::Pc(num)),
169            "pt" => Some(Self::Pt(num)),
170            "px" => Some(Self::Px(num)),
171
172            "cap" => Some(Self::Cap(num)),
173            "ch" => Some(Self::Ch(num)),
174            "em" => Some(Self::Em(num)),
175            "ex" => Some(Self::Ex(num)),
176            "ic" => Some(Self::Ic(num)),
177            "lh" => Some(Self::Lh(num)),
178
179            "rcap" => Some(Self::RCap(num)),
180            "rch" => Some(Self::RCh(num)),
181            "rem" => Some(Self::REm(num)),
182            "rex" => Some(Self::REx(num)),
183            "ric" => Some(Self::RIc(num)),
184            "rlh" => Some(Self::RLh(num)),
185
186            "vh" => Some(Self::Vh(num)),
187            "vw" => Some(Self::Vw(num)),
188            "vMax" => Some(Self::VMax(num)),
189            "vMin" => Some(Self::VMin(num)),
190            "vb" => Some(Self::Vb(num)),
191            "vi" => Some(Self::Vi(num)),
192
193            "cqw" => Some(Self::Cqw(num)),
194            "cqh" => Some(Self::Cqh(num)),
195            "cqi" => Some(Self::Cqi(num)),
196            "cqb" => Some(Self::Cqb(num)),
197            "cqmin" => Some(Self::CqMin(num)),
198            "cqmax" => Some(Self::CqMax(num)),
199
200            _ => None,
201        }
202    }
203
204    /// Converts all CSS length units to pixels for standard units.
205    pub fn computed_value(self) -> f32 {
206        match self {
207            Length::Cm(cm) => cm * (96f32 / 2.54f32),
208            Length::Mm(mm) => mm * (96f32 / 25.4f32),
209            Length::Q(q) => q * (96f32 / 101.6f32),
210            Length::In(inches) => inches * (96f32 / 1f32),
211            Length::Pc(pc) => pc * (96f32 / 6f32),
212            Length::Pt(pt) => pt * (96f32 / 72f32),
213            Length::Px(px) => px,
214
215            _ => unimplemented!(),
216        }
217    }
218}
219
220impl Angle {
221    pub fn get(&self) -> f32 {
222        match self {
223            Angle::Deg(num) => *num,
224            Angle::Grad(num) => *num,
225            Angle::Rad(num) => *num,
226            Angle::Turn(num) => *num,
227        }
228    }
229
230    pub fn from_pair(num: f32, unit: &str) -> Option<Self> {
231        match unit {
232            "deg" => Some(Self::Deg(num)),
233            "grad" => Some(Self::Grad(num)),
234            "rad" => Some(Self::Rad(num)),
235            "turn" => Some(Self::Turn(num)),
236
237            _ => None,
238        }
239    }
240
241    /// Converts all CSS angle units to radians for standard units.
242    pub fn computed_value(self) -> f32 {
243        match self {
244            Angle::Deg(deg) => deg.to_radians(),
245            Angle::Grad(grad) => grad * std::f32::consts::PI / 200f32,
246            Angle::Rad(rad) => rad,
247            Angle::Turn(turn) => turn * std::f32::consts::TAU,
248        }
249    }
250}
251
252impl Time {
253    pub fn get(&self) -> f32 {
254        match self {
255            Time::Sec(num) => *num,
256            Time::Milli(num) => *num,
257        }
258    }
259
260    pub fn computed_value(self) -> f32 {
261        unimplemented!()
262    }
263}
264
265impl Frequency {
266    pub fn computed_value(self) -> f32 {
267        unimplemented!()
268    }
269}
270
271impl Resolution {
272    pub fn get(&self) -> f32 {
273        match self {
274            Resolution::Dpi(num) => *num,
275            Resolution::Dpcm(num) => *num,
276            Resolution::Dppx(num) => *num,
277        }
278    }
279
280    /// Converts Dpi and Dpcm to Dppx for standard units.
281    pub fn from_pair(num: f32, unit: &str) -> Option<Self> {
282        match unit {
283            "dpi" => Some(Self::Dpi(num)),
284            "dpcm" => Some(Self::Dpcm(num)),
285            "dppx" => Some(Self::Dppx(num)),
286            "x" => Some(Self::Dppx(num)),
287
288            _ => None,
289        }
290    }
291
292    /// Converts Dpi and Dpcm to Dppx for standard units.
293    pub fn computed_value(self) -> f32 {
294        match self {
295            Resolution::Dpi(dpi) => dpi / 96f32,
296            Resolution::Dpcm(dpcm) => dpcm * 2.54f32 / 96f32,
297            Resolution::Dppx(x) => x,
298        }
299    }
300}
301
302impl Dimension {
303    pub fn from_pair(num: f32, unit: &str) -> Option<Self> {
304        if let Some(length) = Length::from_pair(num, unit) {
305            Some(Self::Length(length))
306        } else if let Some(angle) = Angle::from_pair(num, unit) {
307            Some(Self::Angle(angle))
308        } else if let Some(resolution) = Resolution::from_pair(num, unit) {
309            Some(Self::Resolution(resolution))
310        } else {
311            None
312        }
313    }
314}
315
316impl Into<f32> for Length {
317    fn into(self) -> f32 {
318        self.get()
319    }
320}
321
322impl Into<f32> for Angle {
323    fn into(self) -> f32 {
324        match self {
325            Angle::Deg(num) => num,
326            Angle::Grad(num) => num,
327            Angle::Rad(num) => num,
328            Angle::Turn(num) => num,
329        }
330    }
331}
332
333impl Into<f32> for Time {
334    fn into(self) -> f32 {
335        match self {
336            Self::Sec(num) => num,
337            Self::Milli(num) => num,
338        }
339    }
340}
341
342impl Into<f32> for Resolution {
343    fn into(self) -> f32 {
344        match self {
345            Resolution::Dpi(val) => val,
346            Resolution::Dpcm(val) => val,
347            Resolution::Dppx(val) => val,
348        }
349    }
350}
351
352impl Into<f32> for Dimension {
353    fn into(self) -> f32 {
354        match self {
355            Dimension::Length(length) => length.into(),
356            Dimension::Angle(angle) => angle.into(),
357            Dimension::Time(_) => unimplemented!(),
358            Dimension::Frequency(_) => unimplemented!(),
359            Dimension::Resolution(resolution) => resolution.into(),
360        }
361    }
362}
363
364impl Into<f32> for Percentage {
365    fn into(self) -> f32 {
366        self.0
367    }
368}
369
370impl std::fmt::Display for Length {
371    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372        match self {
373            Length::Cm(val) => write!(f, "{val}cm"),
374            Length::Mm(val) => write!(f, "{val}mm"),
375            Length::Q(val) => write!(f, "{val}Q"),
376            Length::In(val) => write!(f, "{val}in"),
377            Length::Pc(val) => write!(f, "{val}pc"),
378            Length::Pt(val) => write!(f, "{val}pt"),
379            Length::Px(val) => write!(f, "{val}px"),
380
381            Length::Cap(val) => write!(f, "{val}cap"),
382            Length::Ch(val) => write!(f, "{val}ch"),
383            Length::Em(val) => write!(f, "{val}em"),
384            Length::Ex(val) => write!(f, "{val}ex"),
385            Length::Ic(val) => write!(f, "{val}ic"),
386            Length::Lh(val) => write!(f, "{val}lh"),
387
388            Length::RCap(val) => write!(f, "{val}rcap"),
389            Length::RCh(val) => write!(f, "{val}rch"),
390            Length::REm(val) => write!(f, "{val}rem"),
391            Length::REx(val) => write!(f, "{val}rex"),
392            Length::RIc(val) => write!(f, "{val}ric"),
393            Length::RLh(val) => write!(f, "{val}rlh"),
394
395            Length::Vh(val) => write!(f, "{val}vh"),
396            Length::Vw(val) => write!(f, "{val}vw"),
397            Length::VMax(val) => write!(f, "{val}vmax"),
398            Length::VMin(val) => write!(f, "{val}vmin"),
399            Length::Vb(val) => write!(f, "{val}vb"),
400            Length::Vi(val) => write!(f, "{val}vi"),
401
402            Length::Cqw(val) => write!(f, "{val}cqw"),
403            Length::Cqh(val) => write!(f, "{val}cqh"),
404            Length::Cqi(val) => write!(f, "{val}cqi"),
405            Length::Cqb(val) => write!(f, "{val}cqb"),
406            Length::CqMin(val) => write!(f, "{val}cqmin"),
407            Length::CqMax(val) => write!(f, "{val}cqmax"),
408        }
409    }
410}
411
412impl std::fmt::Display for Angle {
413    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
414        match self {
415            Angle::Deg(val) => write!(f, "{val}deg"),
416            Angle::Grad(val) => write!(f, "{val}grad"),
417            Angle::Rad(val) => write!(f, "{val}rad"),
418            Angle::Turn(val) => write!(f, "{val}turn"),
419        }
420    }
421}
422
423impl std::fmt::Display for Resolution {
424    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
425        match self {
426            Resolution::Dpi(val) => write!(f, "{val}dpi"),
427            Resolution::Dpcm(val) => write!(f, "{val}dpcm"),
428            Resolution::Dppx(val) => write!(f, "{val}x"),
429        }
430    }
431}
432
433impl std::fmt::Display for Dimension {
434    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
435        match self {
436            Dimension::Length(length) => write!(f, "{length}"),
437            Dimension::Angle(angle) => write!(f, "{angle}"),
438            Dimension::Time(time) => todo!(),
439            Dimension::Frequency(frequency) => todo!(),
440            Dimension::Resolution(resolution) => write!(f, "{resolution}"),
441        }
442    }
443}
444
445impl std::fmt::Display for Unit {
446    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
447        match self {
448            Unit::Integer(int) => write!(f, "{int}"),
449            Unit::Number(num) => write!(f, "{num}"),
450            Unit::Dimension(dimension) => write!(f, "{dimension}"),
451            Unit::Percentage(percentage) => write!(f, "{}", percentage.0),
452            Unit::String(string) => write!(f, r#""{string}""#),
453            Unit::Hash(hash) => write!(f, "#{}", hash.0),
454            Unit::Shorthand(val1, val2) => write!(f, "{val1}/{val2}"),
455            Unit::UnknownIdent(ident) => write!(f, "{ident}"),
456            Unit::Function {
457                name,
458                required_return_type,
459                params,
460            } => {
461                let param_string: String = params
462                    .iter()
463                    .map(|x| x.to_string())
464                    .collect::<Vec<_>>()
465                    .join(", ");
466
467                write!(f, "{name}({param_string})")
468            }
469        }
470    }
471}