easyofd_core/
ofd_model.rs1use crate::error::OfdResult;
4use crate::model::OfdPage;
5
6#[derive(Debug, Clone)]
8pub struct OfdField {
9 pub name: &'static str,
11 pub position: (f64, f64),
13 pub font: &'static str,
15 pub size: f64,
17 pub weight: u32,
19 pub italic: bool,
21 pub color: u32,
23 pub kind: OfdFieldKind,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum OfdFieldKind {
30 Text,
32 Image,
34}
35
36pub trait OfdModel: Sized {
42 fn schema() -> &'static [OfdField];
44
45 fn page_size() -> (f64, f64) {
47 (210.0, 297.0) }
49
50 fn to_page(&self) -> OfdResult<OfdPage>;
56
57 fn to_pages(items: &[Self]) -> OfdResult<Vec<OfdPage>> {
63 items.iter().map(Self::to_page).collect()
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::error::OfdError;
71 use crate::model::{ContentObject, TextObject};
72
73 struct TestModel {
75 text: String,
76 }
77
78 impl OfdModel for TestModel {
79 fn schema() -> &'static [OfdField] {
80 &[OfdField {
81 name: "text",
82 position: (10.0, 20.0),
83 font: "SimSun",
84 size: 12.0,
85 weight: 400,
86 italic: false,
87 color: 0,
88 kind: OfdFieldKind::Text,
89 }]
90 }
91
92 fn to_page(&self) -> OfdResult<OfdPage> {
93 let mut page = OfdPage::new(210.0, 297.0);
94 page.add_text(TextObject::new(10.0, 20.0, &self.text));
95 Ok(page)
96 }
97 }
98
99 struct FailingModel;
101
102 impl OfdModel for FailingModel {
103 fn schema() -> &'static [OfdField] {
104 &[]
105 }
106 fn to_page(&self) -> OfdResult<OfdPage> {
107 Err(OfdError::Model("deliberate failure".into()))
108 }
109 }
110
111 #[test]
112 fn test_ofd_field_clone_debug() {
113 let f = OfdField {
114 name: "x",
115 position: (1.0, 2.0),
116 font: "f",
117 size: 10.0,
118 weight: 400,
119 italic: false,
120 color: 0,
121 kind: OfdFieldKind::Text,
122 };
123 let f2 = f.clone();
124 assert_eq!(f2.name, "x");
125 assert!(format!("{f:?}").contains("OfdField"));
126 }
127
128 #[test]
129 fn test_ofd_field_kind_clone_copy_debug() {
130 let k = OfdFieldKind::Image;
131 let k2 = k;
132 assert_eq!(k2, OfdFieldKind::Image);
133 assert_ne!(OfdFieldKind::Text, OfdFieldKind::Image);
134 assert!(format!("{k:?}").contains("Image"));
135 }
136
137 #[test]
138 fn test_ofd_model_default_page_size() {
139 assert_eq!(TestModel::page_size(), (210.0, 297.0));
141 }
142
143 #[test]
144 fn test_ofd_model_to_page() {
145 let m = TestModel {
146 text: "hello".into(),
147 };
148 let page = m.to_page().unwrap();
149 assert!((page.width - 210.0).abs() < f64::EPSILON);
150 assert!((page.height - 297.0).abs() < f64::EPSILON);
151 assert_eq!(page.content.len(), 1);
152 assert!(matches!(&page.content[0], ContentObject::Text(t) if t.text == "hello"));
153 }
154
155 #[test]
156 fn test_ofd_model_to_pages() {
157 let items = vec![
158 TestModel { text: "a".into() },
159 TestModel { text: "b".into() },
160 ];
161 let pages = TestModel::to_pages(&items).unwrap();
162 assert_eq!(pages.len(), 2);
163 }
164
165 #[test]
166 fn test_ofd_model_to_pages_empty() {
167 let items: Vec<TestModel> = vec![];
168 let pages = TestModel::to_pages(&items).unwrap();
169 assert!(pages.is_empty());
170 }
171
172 #[test]
173 fn test_ofd_model_to_pages_error() {
174 let items = vec![FailingModel];
175 let result = FailingModel::to_pages(&items);
176 assert!(result.is_err());
177 }
178
179 #[test]
180 fn test_ofd_model_schema() {
181 let schema = TestModel::schema();
182 assert_eq!(schema.len(), 1);
183 assert_eq!(schema[0].name, "text");
184 }
185
186 #[test]
187 fn test_failing_model_schema() {
188 let schema = FailingModel::schema();
189 assert!(schema.is_empty());
190 }
191}