Skip to main content

ppt_rs/
util.rs

1//! Utility functions and types for length conversions
2
3/// Base class for length values in English Metric Units (EMUs)
4#[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    /// Create a Length from EMUs
15    pub fn new(emu: i32) -> Self {
16        Length(emu)
17    }
18
19    /// Get length in inches
20    pub fn inches(&self) -> f64 {
21        self.0 as f64 / Self::EMUS_PER_INCH as f64
22    }
23
24    /// Get length in centipoints (hundredths of a point)
25    pub fn centipoints(&self) -> i32 {
26        self.0 / Self::EMUS_PER_CENTIPOINT
27    }
28
29    /// Get length in centimeters
30    pub fn cm(&self) -> f64 {
31        self.0 as f64 / Self::EMUS_PER_CM as f64
32    }
33
34    /// Get length in EMUs
35    pub fn emu(&self) -> i32 {
36        self.0
37    }
38
39    /// Get length in millimeters
40    pub fn mm(&self) -> f64 {
41        self.0 as f64 / Self::EMUS_PER_MM as f64
42    }
43
44    /// Get length in points
45    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
62/// Create a Length from inches
63pub fn inches(value: f64) -> Length {
64    Length((value * Length::EMUS_PER_INCH as f64) as i32)
65}
66
67/// Create a Length from centipoints
68pub fn centipoints(value: i32) -> Length {
69    Length(value * Length::EMUS_PER_CENTIPOINT)
70}
71
72/// Create a Length from centimeters
73pub fn cm(value: f64) -> Length {
74    Length((value * Length::EMUS_PER_CM as f64) as i32)
75}
76
77/// Create a Length from English Metric Units
78pub fn emu(value: i32) -> Length {
79    Length(value)
80}
81
82/// Create a Length from millimeters
83pub fn mm(value: f64) -> Length {
84    Length((value * Length::EMUS_PER_MM as f64) as i32)
85}
86
87/// Create a Length from points
88pub 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        // Standard slide width: 10 inches
193        let width = inches(10.0);
194        assert_eq!(width.emu(), 9144000);
195        
196        // Standard slide height: 7.5 inches
197        let height = inches(7.5);
198        assert_eq!(height.emu(), 6858000);
199    }
200}