1use alloc::string::{String, ToString};
12
13use crate::{
14 format_rust_code::FormatAsRustCode,
15 props::{
16 basic::pixel::{CssPixelValueParseError, PixelValue},
17 formatter::PrintAsCssValue,
18 },
19};
20
21#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
29#[repr(C)]
30#[derive(Default)]
31pub enum LayoutTableLayout {
32 #[default]
35 Auto,
36 Fixed,
40}
41
42
43impl PrintAsCssValue for LayoutTableLayout {
44 fn print_as_css_value(&self) -> String {
45 match self {
46 LayoutTableLayout::Auto => "auto".to_string(),
47 LayoutTableLayout::Fixed => "fixed".to_string(),
48 }
49 }
50}
51
52impl FormatAsRustCode for LayoutTableLayout {
53 fn format_as_rust_code(&self, _tabs: usize) -> String {
54 match self {
55 LayoutTableLayout::Auto => "LayoutTableLayout::Auto".to_string(),
56 LayoutTableLayout::Fixed => "LayoutTableLayout::Fixed".to_string(),
57 }
58 }
59}
60
61#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
69#[repr(C)]
70#[derive(Default)]
71pub enum StyleBorderCollapse {
72 #[default]
75 Separate,
76 Collapse,
79}
80
81
82impl PrintAsCssValue for StyleBorderCollapse {
83 fn print_as_css_value(&self) -> String {
84 match self {
85 StyleBorderCollapse::Separate => "separate".to_string(),
86 StyleBorderCollapse::Collapse => "collapse".to_string(),
87 }
88 }
89}
90
91impl FormatAsRustCode for StyleBorderCollapse {
92 fn format_as_rust_code(&self, _tabs: usize) -> String {
93 match self {
94 StyleBorderCollapse::Separate => "StyleBorderCollapse::Separate".to_string(),
95 StyleBorderCollapse::Collapse => "StyleBorderCollapse::Collapse".to_string(),
96 }
97 }
98}
99
100#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
111#[repr(C)]
112pub struct LayoutBorderSpacing {
113 pub horizontal: PixelValue,
115 pub vertical: PixelValue,
117}
118
119impl Default for LayoutBorderSpacing {
120 fn default() -> Self {
121 Self {
123 horizontal: PixelValue::const_px(0),
124 vertical: PixelValue::const_px(0),
125 }
126 }
127}
128
129impl LayoutBorderSpacing {
130 pub const fn new(spacing: PixelValue) -> Self {
132 Self {
133 horizontal: spacing,
134 vertical: spacing,
135 }
136 }
137
138 pub const fn new_separate(horizontal: PixelValue, vertical: PixelValue) -> Self {
140 Self {
141 horizontal,
142 vertical,
143 }
144 }
145}
146
147impl PrintAsCssValue for LayoutBorderSpacing {
148 fn print_as_css_value(&self) -> String {
149 if self.horizontal == self.vertical {
150 self.horizontal.to_string()
152 } else {
153 format!("{} {}", self.horizontal, self.vertical)
155 }
156 }
157}
158
159impl FormatAsRustCode for LayoutBorderSpacing {
160 fn format_as_rust_code(&self, _tabs: usize) -> String {
161 use crate::format_rust_code::format_pixel_value;
162 format!(
163 "LayoutBorderSpacing {{ horizontal: {}, vertical: {} }}",
164 format_pixel_value(&self.horizontal),
165 format_pixel_value(&self.vertical)
166 )
167 }
168}
169
170#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
176#[repr(C)]
177#[derive(Default)]
178pub enum StyleCaptionSide {
179 #[default]
181 Top,
182 Bottom,
184}
185
186
187impl PrintAsCssValue for StyleCaptionSide {
188 fn print_as_css_value(&self) -> String {
189 match self {
190 StyleCaptionSide::Top => "top".to_string(),
191 StyleCaptionSide::Bottom => "bottom".to_string(),
192 }
193 }
194}
195
196impl FormatAsRustCode for StyleCaptionSide {
197 fn format_as_rust_code(&self, _tabs: usize) -> String {
198 match self {
199 StyleCaptionSide::Top => "StyleCaptionSide::Top".to_string(),
200 StyleCaptionSide::Bottom => "StyleCaptionSide::Bottom".to_string(),
201 }
202 }
203}
204
205#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
212#[repr(C)]
213#[derive(Default)]
214pub enum StyleEmptyCells {
215 #[default]
217 Show,
218 Hide,
220}
221
222
223impl PrintAsCssValue for StyleEmptyCells {
224 fn print_as_css_value(&self) -> String {
225 match self {
226 StyleEmptyCells::Show => "show".to_string(),
227 StyleEmptyCells::Hide => "hide".to_string(),
228 }
229 }
230}
231
232impl FormatAsRustCode for StyleEmptyCells {
233 fn format_as_rust_code(&self, _tabs: usize) -> String {
234 match self {
235 StyleEmptyCells::Show => "StyleEmptyCells::Show".to_string(),
236 StyleEmptyCells::Hide => "StyleEmptyCells::Hide".to_string(),
237 }
238 }
239}
240
241#[derive(Debug, Clone, PartialEq)]
245pub(crate) enum LayoutTableLayoutParseError<'a> {
246 InvalidKeyword(&'a str),
247}
248
249pub(crate) fn parse_table_layout<'a>(
251 input: &'a str,
252) -> Result<LayoutTableLayout, LayoutTableLayoutParseError<'a>> {
253 match input.trim() {
254 "auto" => Ok(LayoutTableLayout::Auto),
255 "fixed" => Ok(LayoutTableLayout::Fixed),
256 other => Err(LayoutTableLayoutParseError::InvalidKeyword(other)),
257 }
258}
259
260#[derive(Debug, Clone, PartialEq)]
262pub(crate) enum StyleBorderCollapseParseError<'a> {
263 InvalidKeyword(&'a str),
264}
265
266pub(crate) fn parse_border_collapse<'a>(
268 input: &'a str,
269) -> Result<StyleBorderCollapse, StyleBorderCollapseParseError<'a>> {
270 match input.trim() {
271 "separate" => Ok(StyleBorderCollapse::Separate),
272 "collapse" => Ok(StyleBorderCollapse::Collapse),
273 other => Err(StyleBorderCollapseParseError::InvalidKeyword(other)),
274 }
275}
276
277#[derive(Debug, Clone, PartialEq)]
279pub(crate) enum LayoutBorderSpacingParseError<'a> {
280 PixelValue(CssPixelValueParseError<'a>),
281 InvalidFormat,
282}
283
284pub(crate) fn parse_border_spacing<'a>(
287 input: &'a str,
288) -> Result<LayoutBorderSpacing, LayoutBorderSpacingParseError<'a>> {
289 use crate::props::basic::parse_pixel_value;
290
291 let parts: Vec<&str> = input.split_whitespace().collect();
292
293 match parts.len() {
294 1 => {
295 let value =
297 parse_pixel_value(parts[0]).map_err(LayoutBorderSpacingParseError::PixelValue)?;
298 Ok(LayoutBorderSpacing::new(value))
299 }
300 2 => {
301 let horizontal =
303 parse_pixel_value(parts[0]).map_err(LayoutBorderSpacingParseError::PixelValue)?;
304 let vertical =
305 parse_pixel_value(parts[1]).map_err(LayoutBorderSpacingParseError::PixelValue)?;
306 Ok(LayoutBorderSpacing::new_separate(horizontal, vertical))
307 }
308 _ => Err(LayoutBorderSpacingParseError::InvalidFormat),
309 }
310}
311
312#[derive(Debug, Clone, PartialEq)]
314pub(crate) enum StyleCaptionSideParseError<'a> {
315 InvalidKeyword(&'a str),
316}
317
318pub(crate) fn parse_caption_side<'a>(
320 input: &'a str,
321) -> Result<StyleCaptionSide, StyleCaptionSideParseError<'a>> {
322 match input.trim() {
323 "top" => Ok(StyleCaptionSide::Top),
324 "bottom" => Ok(StyleCaptionSide::Bottom),
325 other => Err(StyleCaptionSideParseError::InvalidKeyword(other)),
326 }
327}
328
329#[derive(Debug, Clone, PartialEq)]
331pub(crate) enum StyleEmptyCellsParseError<'a> {
332 InvalidKeyword(&'a str),
333}
334
335pub(crate) fn parse_empty_cells<'a>(
337 input: &'a str,
338) -> Result<StyleEmptyCells, StyleEmptyCellsParseError<'a>> {
339 match input.trim() {
340 "show" => Ok(StyleEmptyCells::Show),
341 "hide" => Ok(StyleEmptyCells::Hide),
342 other => Err(StyleEmptyCellsParseError::InvalidKeyword(other)),
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn test_parse_table_layout() {
352 assert_eq!(parse_table_layout("auto").unwrap(), LayoutTableLayout::Auto);
353 assert_eq!(
354 parse_table_layout("fixed").unwrap(),
355 LayoutTableLayout::Fixed
356 );
357 assert!(parse_table_layout("invalid").is_err());
358 }
359
360 #[test]
361 fn test_parse_border_collapse() {
362 assert_eq!(
363 parse_border_collapse("separate").unwrap(),
364 StyleBorderCollapse::Separate
365 );
366 assert_eq!(
367 parse_border_collapse("collapse").unwrap(),
368 StyleBorderCollapse::Collapse
369 );
370 assert!(parse_border_collapse("invalid").is_err());
371 }
372
373 #[test]
374 fn test_parse_border_spacing() {
375 let spacing1 = parse_border_spacing("5px").unwrap();
376 assert_eq!(spacing1.horizontal, PixelValue::const_px(5));
377 assert_eq!(spacing1.vertical, PixelValue::const_px(5));
378
379 let spacing2 = parse_border_spacing("5px 10px").unwrap();
380 assert_eq!(spacing2.horizontal, PixelValue::const_px(5));
381 assert_eq!(spacing2.vertical, PixelValue::const_px(10));
382 }
383
384 #[test]
385 fn test_parse_caption_side() {
386 assert_eq!(parse_caption_side("top").unwrap(), StyleCaptionSide::Top);
387 assert_eq!(
388 parse_caption_side("bottom").unwrap(),
389 StyleCaptionSide::Bottom
390 );
391 assert!(parse_caption_side("invalid").is_err());
392 }
393
394 #[test]
395 fn test_parse_empty_cells() {
396 assert_eq!(parse_empty_cells("show").unwrap(), StyleEmptyCells::Show);
397 assert_eq!(parse_empty_cells("hide").unwrap(), StyleEmptyCells::Hide);
398 assert!(parse_empty_cells("invalid").is_err());
399 }
400}