Skip to main content

ppt_rs/core/
traits.rs

1//! Core traits for PPTX elements
2
3/// Trait for types that can be converted to XML
4pub trait ToXml {
5    /// Generate XML representation of this element
6    fn to_xml(&self) -> String;
7
8    /// Write XML to a string buffer (more efficient for large documents)
9    fn write_xml(&self, writer: &mut String) {
10        writer.push_str(&self.to_xml());
11    }
12}
13
14/// Trait for positioned elements (x, y coordinates)
15pub trait Positioned {
16    /// Get X position in EMU
17    fn x(&self) -> u32;
18
19    /// Get Y position in EMU
20    fn y(&self) -> u32;
21
22    /// Set position
23    fn set_position(&mut self, x: u32, y: u32);
24}
25
26/// Trait for sized elements (width, height)
27pub trait Sized {
28    /// Get width in EMU
29    fn width(&self) -> u32;
30
31    /// Get height in EMU
32    fn height(&self) -> u32;
33
34    /// Set size
35    fn set_size(&mut self, width: u32, height: u32);
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    /// Verify generic dispatch works via ToXml trait objects
43    #[test]
44    fn test_to_xml_trait_dispatch() {
45        use crate::generator::text::{Paragraph, Run, TextFrame};
46
47        let items: Vec<Box<dyn ToXml>> = vec![
48            Box::new(Run::new("hello")),
49            Box::new(Paragraph::with_text("world")),
50            Box::new(TextFrame::with_text("frame")),
51        ];
52
53        for item in &items {
54            let xml = item.to_xml();
55            assert!(
56                !xml.is_empty(),
57                "ToXml dispatch should produce non-empty XML"
58            );
59        }
60
61        assert!(items[0].to_xml().contains("hello"));
62        assert!(items[1].to_xml().contains("world"));
63        assert!(items[2].to_xml().contains("frame"));
64    }
65
66    /// Verify Positioned trait works generically
67    #[test]
68    fn test_positioned_trait_dispatch() {
69        use crate::generator::images::Image;
70        use crate::generator::shapes::{Shape, ShapeType};
71
72        fn move_element(elem: &mut dyn Positioned, x: u32, y: u32) {
73            elem.set_position(x, y);
74        }
75
76        let mut shape = Shape::new(ShapeType::Rectangle, 0, 0, 1000, 1000);
77        let mut image = Image::new("test.png", 500, 500, "PNG");
78
79        move_element(&mut shape, 100, 200);
80        move_element(&mut image, 300, 400);
81
82        assert_eq!(shape.x(), 100);
83        assert_eq!(shape.y(), 200);
84        assert_eq!(image.x(), 300);
85        assert_eq!(image.y(), 400);
86    }
87
88    /// Verify ElementSized trait works generically
89    #[test]
90    fn test_element_sized_trait_dispatch() {
91        use crate::generator::images::Image;
92        use crate::generator::shapes::{Shape, ShapeType};
93
94        fn resize(elem: &mut dyn Sized, w: u32, h: u32) {
95            elem.set_size(w, h);
96        }
97
98        let mut shape = Shape::new(ShapeType::Rectangle, 0, 0, 1000, 1000);
99        let mut image = Image::new("test.png", 500, 500, "PNG");
100
101        resize(&mut shape, 2000, 3000);
102        resize(&mut image, 4000, 5000);
103
104        assert_eq!(shape.width(), 2000);
105        assert_eq!(shape.height(), 3000);
106        assert_eq!(image.width(), 4000);
107        assert_eq!(image.height(), 5000);
108    }
109}