1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
5pub struct Length(i32);
6
7impl Length {
8 const EMUS_PER_INCH: i32 = 914400;
9 const EMUS_PER_CENTIPOINT: i32 = 127;
10 const EMUS_PER_CM: i32 = 360000;
11 const EMUS_PER_MM: i32 = 36000;
12 const EMUS_PER_PT: i32 = 12700;
13
14 pub fn new(emu: i32) -> Self {
16 Length(emu)
17 }
18
19 pub fn inches(&self) -> f64 {
21 self.0 as f64 / Self::EMUS_PER_INCH as f64
22 }
23
24 pub fn centipoints(&self) -> i32 {
26 self.0 / Self::EMUS_PER_CENTIPOINT
27 }
28
29 pub fn cm(&self) -> f64 {
31 self.0 as f64 / Self::EMUS_PER_CM as f64
32 }
33
34 pub fn emu(&self) -> i32 {
36 self.0
37 }
38
39 pub fn mm(&self) -> f64 {
41 self.0 as f64 / Self::EMUS_PER_MM as f64
42 }
43
44 pub fn pt(&self) -> f64 {
46 self.0 as f64 / Self::EMUS_PER_PT as f64
47 }
48}
49
50impl From<i32> for Length {
51 fn from(emu: i32) -> Self {
52 Length(emu)
53 }
54}
55
56impl From<Length> for i32 {
57 fn from(length: Length) -> Self {
58 length.0
59 }
60}
61
62pub fn inches(value: f64) -> Length {
64 Length((value * Length::EMUS_PER_INCH as f64) as i32)
65}
66
67pub fn centipoints(value: i32) -> Length {
69 Length(value * Length::EMUS_PER_CENTIPOINT)
70}
71
72pub fn cm(value: f64) -> Length {
74 Length((value * Length::EMUS_PER_CM as f64) as i32)
75}
76
77pub fn emu(value: i32) -> Length {
79 Length(value)
80}
81
82pub fn mm(value: f64) -> Length {
84 Length((value * Length::EMUS_PER_MM as f64) as i32)
85}
86
87pub fn pt(value: f64) -> Length {
89 Length((value * Length::EMUS_PER_PT as f64) as i32)
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_length_from_inches() {
98 let len = inches(1.0);
99 assert_eq!(len.emu(), 914400);
100 assert_eq!(len.inches(), 1.0);
101 }
102
103 #[test]
104 fn test_length_from_cm() {
105 let len = cm(2.54);
106 assert!((len.inches() - 1.0).abs() < 0.01);
107 assert!((len.cm() - 2.54).abs() < 0.001);
108 }
109
110 #[test]
111 fn test_length_from_mm() {
112 let len = mm(25.4);
113 assert!((len.inches() - 1.0).abs() < 0.01);
114 assert!((len.mm() - 25.4).abs() < 0.01);
115 }
116
117 #[test]
118 fn test_length_from_pt() {
119 let len = pt(72.0);
120 assert!((len.inches() - 1.0).abs() < 0.01);
121 assert!((len.pt() - 72.0).abs() < 0.01);
122 }
123
124 #[test]
125 fn test_length_from_emu() {
126 let len = emu(914400);
127 assert_eq!(len.emu(), 914400);
128 assert_eq!(len.inches(), 1.0);
129 }
130
131 #[test]
132 fn test_length_from_centipoints() {
133 let len = centipoints(7200);
134 assert_eq!(len.centipoints(), 7200);
135 assert!((len.pt() - 72.0).abs() < 0.1);
136 }
137
138 #[test]
139 fn test_length_new() {
140 let len = Length::new(914400);
141 assert_eq!(len.emu(), 914400);
142 }
143
144 #[test]
145 fn test_length_from_i32() {
146 let len: Length = 914400.into();
147 assert_eq!(len.emu(), 914400);
148 }
149
150 #[test]
151 fn test_i32_from_length() {
152 let len = inches(1.0);
153 let emu_val: i32 = len.into();
154 assert_eq!(emu_val, 914400);
155 }
156
157 #[test]
158 fn test_length_comparison() {
159 let len1 = inches(1.0);
160 let len2 = inches(2.0);
161 assert!(len1 < len2);
162 assert!(len2 > len1);
163 assert_eq!(len1, inches(1.0));
164 }
165
166 #[test]
167 fn test_length_clone() {
168 let len1 = inches(1.0);
169 let len2 = len1;
170 assert_eq!(len1, len2);
171 }
172
173 #[test]
174 fn test_zero_length() {
175 let len = emu(0);
176 assert_eq!(len.emu(), 0);
177 assert_eq!(len.inches(), 0.0);
178 assert_eq!(len.cm(), 0.0);
179 assert_eq!(len.mm(), 0.0);
180 assert_eq!(len.pt(), 0.0);
181 }
182
183 #[test]
184 fn test_negative_length() {
185 let len = emu(-914400);
186 assert_eq!(len.emu(), -914400);
187 assert_eq!(len.inches(), -1.0);
188 }
189
190 #[test]
191 fn test_common_slide_dimensions() {
192 let width = inches(10.0);
194 assert_eq!(width.emu(), 9144000);
195
196 let height = inches(7.5);
198 assert_eq!(height.emu(), 6858000);
199 }
200}