math_core_renderer_internal/
length.rs1#[cfg(feature = "serde")]
6use serde::Serialize;
7use strum_macros::IntoStaticStr;
8
9#[derive(Debug, Clone, Copy, PartialEq, IntoStaticStr)]
10#[cfg_attr(feature = "serde", derive(Serialize))]
11pub enum LengthUnit {
12 #[strum(serialize = "rem")]
14 Rem,
15 #[strum(serialize = "em")]
17 Em,
18 #[strum(serialize = "ex")]
19 Ex,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq)]
23#[cfg_attr(feature = "serde", derive(Serialize))]
24pub struct Length {
25 value: LengthValue,
26 pub(crate) unit: LengthUnit,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq)]
30#[cfg_attr(feature = "serde", derive(Serialize))]
31#[repr(transparent)]
32#[cfg_attr(feature = "serde", serde(transparent))]
33pub struct LengthValue(pub(crate) f32);
34
35impl Length {
36 pub const fn new(value: f32, unit: LengthUnit) -> Self {
37 Length {
38 value: LengthValue(value),
39 unit,
40 }
41 }
42
43 pub fn push_to_string(&self, output: &mut String) {
44 let mut buffer = dtoa::Buffer::new();
45 let result = buffer.format(self.value.0);
46 output.push_str(result.strip_suffix(".0").unwrap_or(result));
48 if self.value.0 != 0.0 {
49 output.push_str(<&'static str>::from(self.unit));
50 }
51 }
52
53 pub const fn none() -> Self {
54 Length {
55 value: LengthValue(f32::NAN),
56 unit: LengthUnit::Rem,
57 }
58 }
59
60 pub const fn zero() -> Self {
61 Length {
62 value: LengthValue(0.0),
63 unit: LengthUnit::Rem,
64 }
65 }
66
67 pub const fn into_parts(self) -> (LengthValue, LengthUnit) {
68 (self.value, self.unit)
69 }
70
71 pub fn from_parts(value: LengthValue, unit: LengthUnit) -> Option<Self> {
72 if value.0.is_finite() {
73 Some(Length { value, unit })
74 } else {
75 None
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use LengthUnit::*;
84
85 #[test]
86 fn write() {
87 let mut output = String::new();
88 Length::new(0.0, Rem).push_to_string(&mut output);
89 assert_eq!(&output, "0");
90 output.clear();
91 Length::new(1.0, Rem).push_to_string(&mut output);
92 assert_eq!(&output, "1rem");
93 output.clear();
94 Length::new(10.0, Rem).push_to_string(&mut output);
95 assert_eq!(&output, "10rem");
96 output.clear();
97 Length::new(5965232.0, Rem).push_to_string(&mut output);
98 assert_eq!(&output, "5965232rem");
99 output.clear();
100 Length::new(-5965232.0, Rem).push_to_string(&mut output);
101 assert_eq!(&output, "-5965232rem");
102 }
103
104 #[test]
105 fn write_relative() {
106 let mut output = String::new();
107 Length::new(0.0, Em).push_to_string(&mut output);
108 assert_eq!(&output, "0");
109 output.clear();
110 Length::new(0.0, Ex).push_to_string(&mut output);
111 assert_eq!(&output, "0");
112 output.clear();
113 Length::new(1.0, Em).push_to_string(&mut output);
114 assert_eq!(&output, "1em");
115 output.clear();
116 Length::new(1.0, Ex).push_to_string(&mut output);
117 assert_eq!(&output, "1ex");
118 output.clear();
119 Length::new(546.0, Em).push_to_string(&mut output);
120 assert_eq!(&output, "546em");
121 output.clear();
122 Length::new(546.0, Ex).push_to_string(&mut output);
123 assert_eq!(&output, "546ex");
124 output.clear();
125 Length::new(-546.0, Em).push_to_string(&mut output);
126 assert_eq!(&output, "-546em");
127 output.clear();
128 Length::new(-546.0, Ex).push_to_string(&mut output);
129 assert_eq!(&output, "-546ex");
130 output.clear();
131 }
132}