1use alloc::string::{String, ToString};
12
13use crate::{
14 format_rust_code::FormatAsRustCode,
15 props::{
16 basic::pixel::{CssPixelValueParseError, CssPixelValueParseErrorOwned, PixelValue},
17 formatter::PrintAsCssValue,
18 macros::PixelValueTaker,
19 },
20};
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[repr(C)]
31pub enum LayoutTableLayout {
32 Auto,
35 Fixed,
39}
40
41impl Default for LayoutTableLayout {
42 fn default() -> Self {
43 Self::Auto
44 }
45}
46
47impl PrintAsCssValue for LayoutTableLayout {
48 fn print_as_css_value(&self) -> String {
49 match self {
50 LayoutTableLayout::Auto => "auto".to_string(),
51 LayoutTableLayout::Fixed => "fixed".to_string(),
52 }
53 }
54}
55
56impl FormatAsRustCode for LayoutTableLayout {
57 fn format_as_rust_code(&self, _tabs: usize) -> String {
58 match self {
59 LayoutTableLayout::Auto => "LayoutTableLayout::Auto".to_string(),
60 LayoutTableLayout::Fixed => "LayoutTableLayout::Fixed".to_string(),
61 }
62 }
63}
64
65#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73#[repr(C)]
74pub enum StyleBorderCollapse {
75 Separate,
78 Collapse,
81}
82
83impl Default for StyleBorderCollapse {
84 fn default() -> Self {
85 Self::Separate
86 }
87}
88
89impl PrintAsCssValue for StyleBorderCollapse {
90 fn print_as_css_value(&self) -> String {
91 match self {
92 StyleBorderCollapse::Separate => "separate".to_string(),
93 StyleBorderCollapse::Collapse => "collapse".to_string(),
94 }
95 }
96}
97
98impl FormatAsRustCode for StyleBorderCollapse {
99 fn format_as_rust_code(&self, _tabs: usize) -> String {
100 match self {
101 StyleBorderCollapse::Separate => "StyleBorderCollapse::Separate".to_string(),
102 StyleBorderCollapse::Collapse => "StyleBorderCollapse::Collapse".to_string(),
103 }
104 }
105}
106
107#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
118#[repr(C)]
119pub struct LayoutBorderSpacing {
120 pub horizontal: PixelValue,
122 pub vertical: PixelValue,
124}
125
126impl Default for LayoutBorderSpacing {
127 fn default() -> Self {
128 Self {
130 horizontal: PixelValue::const_px(0),
131 vertical: PixelValue::const_px(0),
132 }
133 }
134}
135
136impl LayoutBorderSpacing {
137 pub const fn new(spacing: PixelValue) -> Self {
139 Self {
140 horizontal: spacing,
141 vertical: spacing,
142 }
143 }
144
145 pub const fn new_separate(horizontal: PixelValue, vertical: PixelValue) -> Self {
147 Self {
148 horizontal,
149 vertical,
150 }
151 }
152
153 pub const fn zero() -> Self {
155 Self {
156 horizontal: PixelValue::const_px(0),
157 vertical: PixelValue::const_px(0),
158 }
159 }
160}
161
162impl PrintAsCssValue for LayoutBorderSpacing {
163 fn print_as_css_value(&self) -> String {
164 if self.horizontal == self.vertical {
165 self.horizontal.to_string()
167 } else {
168 format!("{} {}", self.horizontal, self.vertical)
170 }
171 }
172}
173
174impl FormatAsRustCode for LayoutBorderSpacing {
175 fn format_as_rust_code(&self, _tabs: usize) -> String {
176 use crate::format_rust_code::format_pixel_value;
177 format!(
178 "LayoutBorderSpacing {{ horizontal: {}, vertical: {} }}",
179 format_pixel_value(&self.horizontal),
180 format_pixel_value(&self.vertical)
181 )
182 }
183}
184
185#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
191#[repr(C)]
192pub enum StyleCaptionSide {
193 Top,
195 Bottom,
197}
198
199impl Default for StyleCaptionSide {
200 fn default() -> Self {
201 Self::Top
202 }
203}
204
205impl PrintAsCssValue for StyleCaptionSide {
206 fn print_as_css_value(&self) -> String {
207 match self {
208 StyleCaptionSide::Top => "top".to_string(),
209 StyleCaptionSide::Bottom => "bottom".to_string(),
210 }
211 }
212}
213
214impl FormatAsRustCode for StyleCaptionSide {
215 fn format_as_rust_code(&self, _tabs: usize) -> String {
216 match self {
217 StyleCaptionSide::Top => "StyleCaptionSide::Top".to_string(),
218 StyleCaptionSide::Bottom => "StyleCaptionSide::Bottom".to_string(),
219 }
220 }
221}
222
223#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
230#[repr(C)]
231pub enum StyleEmptyCells {
232 Show,
234 Hide,
236}
237
238impl Default for StyleEmptyCells {
239 fn default() -> Self {
240 Self::Show
241 }
242}
243
244impl PrintAsCssValue for StyleEmptyCells {
245 fn print_as_css_value(&self) -> String {
246 match self {
247 StyleEmptyCells::Show => "show".to_string(),
248 StyleEmptyCells::Hide => "hide".to_string(),
249 }
250 }
251}
252
253impl FormatAsRustCode for StyleEmptyCells {
254 fn format_as_rust_code(&self, _tabs: usize) -> String {
255 match self {
256 StyleEmptyCells::Show => "StyleEmptyCells::Show".to_string(),
257 StyleEmptyCells::Hide => "StyleEmptyCells::Hide".to_string(),
258 }
259 }
260}
261
262#[derive(Debug, Clone, PartialEq)]
266pub enum LayoutTableLayoutParseError<'a> {
267 InvalidKeyword(&'a str),
268}
269
270pub fn parse_table_layout<'a>(
272 input: &'a str,
273) -> Result<LayoutTableLayout, LayoutTableLayoutParseError<'a>> {
274 match input.trim() {
275 "auto" => Ok(LayoutTableLayout::Auto),
276 "fixed" => Ok(LayoutTableLayout::Fixed),
277 other => Err(LayoutTableLayoutParseError::InvalidKeyword(other)),
278 }
279}
280
281#[derive(Debug, Clone, PartialEq)]
283pub enum StyleBorderCollapseParseError<'a> {
284 InvalidKeyword(&'a str),
285}
286
287pub fn parse_border_collapse<'a>(
289 input: &'a str,
290) -> Result<StyleBorderCollapse, StyleBorderCollapseParseError<'a>> {
291 match input.trim() {
292 "separate" => Ok(StyleBorderCollapse::Separate),
293 "collapse" => Ok(StyleBorderCollapse::Collapse),
294 other => Err(StyleBorderCollapseParseError::InvalidKeyword(other)),
295 }
296}
297
298#[derive(Debug, Clone, PartialEq)]
300pub enum LayoutBorderSpacingParseError<'a> {
301 PixelValue(CssPixelValueParseError<'a>),
302 InvalidFormat,
303}
304
305pub fn parse_border_spacing<'a>(
308 input: &'a str,
309) -> Result<LayoutBorderSpacing, LayoutBorderSpacingParseError<'a>> {
310 use crate::props::basic::parse_pixel_value;
311
312 let parts: Vec<&str> = input.trim().split_whitespace().collect();
313
314 match parts.len() {
315 1 => {
316 let value =
318 parse_pixel_value(parts[0]).map_err(LayoutBorderSpacingParseError::PixelValue)?;
319 Ok(LayoutBorderSpacing::new(value))
320 }
321 2 => {
322 let horizontal =
324 parse_pixel_value(parts[0]).map_err(LayoutBorderSpacingParseError::PixelValue)?;
325 let vertical =
326 parse_pixel_value(parts[1]).map_err(LayoutBorderSpacingParseError::PixelValue)?;
327 Ok(LayoutBorderSpacing::new_separate(horizontal, vertical))
328 }
329 _ => Err(LayoutBorderSpacingParseError::InvalidFormat),
330 }
331}
332
333#[derive(Debug, Clone, PartialEq)]
335pub enum StyleCaptionSideParseError<'a> {
336 InvalidKeyword(&'a str),
337}
338
339pub fn parse_caption_side<'a>(
341 input: &'a str,
342) -> Result<StyleCaptionSide, StyleCaptionSideParseError<'a>> {
343 match input.trim() {
344 "top" => Ok(StyleCaptionSide::Top),
345 "bottom" => Ok(StyleCaptionSide::Bottom),
346 other => Err(StyleCaptionSideParseError::InvalidKeyword(other)),
347 }
348}
349
350#[derive(Debug, Clone, PartialEq)]
352pub enum StyleEmptyCellsParseError<'a> {
353 InvalidKeyword(&'a str),
354}
355
356pub fn parse_empty_cells<'a>(
358 input: &'a str,
359) -> Result<StyleEmptyCells, StyleEmptyCellsParseError<'a>> {
360 match input.trim() {
361 "show" => Ok(StyleEmptyCells::Show),
362 "hide" => Ok(StyleEmptyCells::Hide),
363 other => Err(StyleEmptyCellsParseError::InvalidKeyword(other)),
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn test_parse_table_layout() {
373 assert_eq!(parse_table_layout("auto").unwrap(), LayoutTableLayout::Auto);
374 assert_eq!(
375 parse_table_layout("fixed").unwrap(),
376 LayoutTableLayout::Fixed
377 );
378 assert!(parse_table_layout("invalid").is_err());
379 }
380
381 #[test]
382 fn test_parse_border_collapse() {
383 assert_eq!(
384 parse_border_collapse("separate").unwrap(),
385 StyleBorderCollapse::Separate
386 );
387 assert_eq!(
388 parse_border_collapse("collapse").unwrap(),
389 StyleBorderCollapse::Collapse
390 );
391 assert!(parse_border_collapse("invalid").is_err());
392 }
393
394 #[test]
395 fn test_parse_border_spacing() {
396 let spacing1 = parse_border_spacing("5px").unwrap();
397 assert_eq!(spacing1.horizontal, PixelValue::const_px(5));
398 assert_eq!(spacing1.vertical, PixelValue::const_px(5));
399
400 let spacing2 = parse_border_spacing("5px 10px").unwrap();
401 assert_eq!(spacing2.horizontal, PixelValue::const_px(5));
402 assert_eq!(spacing2.vertical, PixelValue::const_px(10));
403 }
404
405 #[test]
406 fn test_parse_caption_side() {
407 assert_eq!(parse_caption_side("top").unwrap(), StyleCaptionSide::Top);
408 assert_eq!(
409 parse_caption_side("bottom").unwrap(),
410 StyleCaptionSide::Bottom
411 );
412 assert!(parse_caption_side("invalid").is_err());
413 }
414
415 #[test]
416 fn test_parse_empty_cells() {
417 assert_eq!(parse_empty_cells("show").unwrap(), StyleEmptyCells::Show);
418 assert_eq!(parse_empty_cells("hide").unwrap(), StyleEmptyCells::Hide);
419 assert!(parse_empty_cells("invalid").is_err());
420 }
421}