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 pub const fn is_negative(self) -> bool {
80 self.value.0 < 0.0
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use LengthUnit::*;
88
89 #[test]
90 fn test_write() {
91 let mut output = String::new();
92 Length::new(0.0, Rem).push_to_string(&mut output);
93 assert_eq!(&output, "0");
94 output.clear();
95 Length::new(1.0, Rem).push_to_string(&mut output);
96 assert_eq!(&output, "1rem");
97 output.clear();
98 Length::new(10.0, Rem).push_to_string(&mut output);
99 assert_eq!(&output, "10rem");
100 output.clear();
101 Length::new(5965232.0, Rem).push_to_string(&mut output);
102 assert_eq!(&output, "5965232rem");
103 output.clear();
104 Length::new(-5965232.0, Rem).push_to_string(&mut output);
105 assert_eq!(&output, "-5965232rem");
106 }
107
108 #[test]
109 fn test_write_relative() {
110 let mut output = String::new();
111 Length::new(0.0, Em).push_to_string(&mut output);
112 assert_eq!(&output, "0");
113 output.clear();
114 Length::new(0.0, Ex).push_to_string(&mut output);
115 assert_eq!(&output, "0");
116 output.clear();
117 Length::new(1.0, Em).push_to_string(&mut output);
118 assert_eq!(&output, "1em");
119 output.clear();
120 Length::new(1.0, Ex).push_to_string(&mut output);
121 assert_eq!(&output, "1ex");
122 output.clear();
123 Length::new(546.0, Em).push_to_string(&mut output);
124 assert_eq!(&output, "546em");
125 output.clear();
126 Length::new(546.0, Ex).push_to_string(&mut output);
127 assert_eq!(&output, "546ex");
128 output.clear();
129 Length::new(-546.0, Em).push_to_string(&mut output);
130 assert_eq!(&output, "-546em");
131 output.clear();
132 Length::new(-546.0, Ex).push_to_string(&mut output);
133 assert_eq!(&output, "-546ex");
134 output.clear();
135 }
136}