1use alloc::string::{String, ToString};
4use core::num::ParseIntError;
5
6use crate::props::{
7 basic::{
8 color::{parse_css_color, ColorU, CssColorParseError, CssColorParseErrorOwned},
9 pixel::{
10 parse_pixel_value, CssPixelValueParseError, CssPixelValueParseErrorOwned, PixelValue,
11 },
12 },
13 formatter::PrintAsCssValue,
14 style::border::{
15 parse_border_style, BorderStyle, CssBorderStyleParseError, CssBorderStyleParseErrorOwned,
16 },
17};
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22#[repr(C, u8)]
23pub enum ColumnCount {
24 Auto,
25 Integer(u32),
26}
27
28impl Default for ColumnCount {
29 fn default() -> Self {
30 Self::Auto
31 }
32}
33
34impl PrintAsCssValue for ColumnCount {
35 fn print_as_css_value(&self) -> String {
36 match self {
37 Self::Auto => "auto".to_string(),
38 Self::Integer(i) => i.to_string(),
39 }
40 }
41}
42
43#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
46#[repr(C, u8)]
47pub enum ColumnWidth {
48 Auto,
49 Length(PixelValue),
50}
51
52impl Default for ColumnWidth {
53 fn default() -> Self {
54 Self::Auto
55 }
56}
57
58impl PrintAsCssValue for ColumnWidth {
59 fn print_as_css_value(&self) -> String {
60 match self {
61 Self::Auto => "auto".to_string(),
62 Self::Length(px) => px.print_as_css_value(),
63 }
64 }
65}
66
67#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
70#[repr(C)]
71pub enum ColumnSpan {
72 None,
73 All,
74}
75
76impl Default for ColumnSpan {
77 fn default() -> Self {
78 Self::None
79 }
80}
81
82impl PrintAsCssValue for ColumnSpan {
83 fn print_as_css_value(&self) -> String {
84 String::from(match self {
85 Self::None => "none",
86 Self::All => "all",
87 })
88 }
89}
90
91#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
94#[repr(C)]
95pub enum ColumnFill {
96 Auto,
97 Balance,
98}
99
100impl Default for ColumnFill {
101 fn default() -> Self {
102 Self::Balance
103 }
104}
105
106impl PrintAsCssValue for ColumnFill {
107 fn print_as_css_value(&self) -> String {
108 String::from(match self {
109 Self::Auto => "auto",
110 Self::Balance => "balance",
111 })
112 }
113}
114
115#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
118#[repr(C)]
119pub struct ColumnRuleWidth {
120 pub inner: PixelValue,
121}
122
123impl Default for ColumnRuleWidth {
124 fn default() -> Self {
125 Self {
126 inner: PixelValue::const_px(3),
127 }
128 }
129}
130
131impl PrintAsCssValue for ColumnRuleWidth {
132 fn print_as_css_value(&self) -> String {
133 self.inner.print_as_css_value()
134 }
135}
136
137#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
138#[repr(C)]
139pub struct ColumnRuleStyle {
140 pub inner: BorderStyle,
141}
142
143impl Default for ColumnRuleStyle {
144 fn default() -> Self {
145 Self {
146 inner: BorderStyle::None,
147 }
148 }
149}
150
151impl PrintAsCssValue for ColumnRuleStyle {
152 fn print_as_css_value(&self) -> String {
153 self.inner.print_as_css_value()
154 }
155}
156
157#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
158#[repr(C)]
159pub struct ColumnRuleColor {
160 pub inner: ColorU,
161}
162
163impl Default for ColumnRuleColor {
164 fn default() -> Self {
165 Self {
166 inner: ColorU::BLACK,
167 } }
169}
170
171impl PrintAsCssValue for ColumnRuleColor {
172 fn print_as_css_value(&self) -> String {
173 self.inner.to_hash()
174 }
175}
176
177impl crate::format_rust_code::FormatAsRustCode for ColumnCount {
179 fn format_as_rust_code(&self, _tabs: usize) -> String {
180 match self {
181 ColumnCount::Auto => String::from("ColumnCount::Auto"),
182 ColumnCount::Integer(i) => format!("ColumnCount::Integer({})", i),
183 }
184 }
185}
186
187impl crate::format_rust_code::FormatAsRustCode for ColumnWidth {
188 fn format_as_rust_code(&self, tabs: usize) -> String {
189 match self {
190 ColumnWidth::Auto => String::from("ColumnWidth::Auto"),
191 ColumnWidth::Length(px) => format!(
192 "ColumnWidth::Length({})",
193 crate::format_rust_code::format_pixel_value(px)
194 ),
195 }
196 }
197}
198
199impl crate::format_rust_code::FormatAsRustCode for ColumnSpan {
200 fn format_as_rust_code(&self, _tabs: usize) -> String {
201 match self {
202 ColumnSpan::None => String::from("ColumnSpan::None"),
203 ColumnSpan::All => String::from("ColumnSpan::All"),
204 }
205 }
206}
207
208impl crate::format_rust_code::FormatAsRustCode for ColumnFill {
209 fn format_as_rust_code(&self, _tabs: usize) -> String {
210 match self {
211 ColumnFill::Auto => String::from("ColumnFill::Auto"),
212 ColumnFill::Balance => String::from("ColumnFill::Balance"),
213 }
214 }
215}
216
217impl crate::format_rust_code::FormatAsRustCode for ColumnRuleWidth {
218 fn format_as_rust_code(&self, _tabs: usize) -> String {
219 format!(
220 "ColumnRuleWidth {{ inner: {} }}",
221 crate::format_rust_code::format_pixel_value(&self.inner)
222 )
223 }
224}
225
226impl crate::format_rust_code::FormatAsRustCode for ColumnRuleStyle {
227 fn format_as_rust_code(&self, tabs: usize) -> String {
228 format!(
229 "ColumnRuleStyle {{ inner: {} }}",
230 self.inner.format_as_rust_code(tabs)
231 )
232 }
233}
234
235impl crate::format_rust_code::FormatAsRustCode for ColumnRuleColor {
236 fn format_as_rust_code(&self, _tabs: usize) -> String {
237 format!(
238 "ColumnRuleColor {{ inner: {} }}",
239 crate::format_rust_code::format_color_value(&self.inner)
240 )
241 }
242}
243
244#[cfg(feature = "parser")]
247mod parser {
248 use super::*;
249
250 #[derive(Clone, PartialEq)]
253 pub enum ColumnCountParseError<'a> {
254 InvalidValue(&'a str),
255 ParseInt(ParseIntError),
256 }
257
258 impl_debug_as_display!(ColumnCountParseError<'a>);
259 impl_display! { ColumnCountParseError<'a>, {
260 InvalidValue(v) => format!("Invalid column-count value: \"{}\"", v),
261 ParseInt(e) => format!("Invalid integer for column-count: {}", e),
262 }}
263
264 #[derive(Debug, Clone, PartialEq)]
265 pub enum ColumnCountParseErrorOwned {
266 InvalidValue(String),
267 ParseInt(String),
268 }
269
270 impl<'a> ColumnCountParseError<'a> {
271 pub fn to_contained(&self) -> ColumnCountParseErrorOwned {
272 match self {
273 Self::InvalidValue(s) => ColumnCountParseErrorOwned::InvalidValue(s.to_string()),
274 Self::ParseInt(e) => ColumnCountParseErrorOwned::ParseInt(e.to_string()),
275 }
276 }
277 }
278
279 impl ColumnCountParseErrorOwned {
280 pub fn to_shared<'a>(&'a self) -> ColumnCountParseError<'a> {
281 match self {
282 Self::InvalidValue(s) => ColumnCountParseError::InvalidValue(s),
283 Self::ParseInt(_) => ColumnCountParseError::InvalidValue("invalid integer"), }
285 }
286 }
287
288 pub fn parse_column_count<'a>(
289 input: &'a str,
290 ) -> Result<ColumnCount, ColumnCountParseError<'a>> {
291 let trimmed = input.trim();
292 if trimmed == "auto" {
293 return Ok(ColumnCount::Auto);
294 }
295 let val: u32 = trimmed
296 .parse()
297 .map_err(|e| ColumnCountParseError::ParseInt(e))?;
298 Ok(ColumnCount::Integer(val))
299 }
300
301 #[derive(Clone, PartialEq)]
304 pub enum ColumnWidthParseError<'a> {
305 InvalidValue(&'a str),
306 PixelValue(CssPixelValueParseError<'a>),
307 }
308
309 impl_debug_as_display!(ColumnWidthParseError<'a>);
310 impl_display! { ColumnWidthParseError<'a>, {
311 InvalidValue(v) => format!("Invalid column-width value: \"{}\"", v),
312 PixelValue(e) => format!("{}", e),
313 }}
314 impl_from! { CssPixelValueParseError<'a>, ColumnWidthParseError::PixelValue }
315
316 #[derive(Debug, Clone, PartialEq)]
317 pub enum ColumnWidthParseErrorOwned {
318 InvalidValue(String),
319 PixelValue(CssPixelValueParseErrorOwned),
320 }
321
322 impl<'a> ColumnWidthParseError<'a> {
323 pub fn to_contained(&self) -> ColumnWidthParseErrorOwned {
324 match self {
325 Self::InvalidValue(s) => ColumnWidthParseErrorOwned::InvalidValue(s.to_string()),
326 Self::PixelValue(e) => ColumnWidthParseErrorOwned::PixelValue(e.to_contained()),
327 }
328 }
329 }
330
331 impl ColumnWidthParseErrorOwned {
332 pub fn to_shared<'a>(&'a self) -> ColumnWidthParseError<'a> {
333 match self {
334 Self::InvalidValue(s) => ColumnWidthParseError::InvalidValue(s),
335 Self::PixelValue(e) => ColumnWidthParseError::PixelValue(e.to_shared()),
336 }
337 }
338 }
339
340 pub fn parse_column_width<'a>(
341 input: &'a str,
342 ) -> Result<ColumnWidth, ColumnWidthParseError<'a>> {
343 let trimmed = input.trim();
344 if trimmed == "auto" {
345 return Ok(ColumnWidth::Auto);
346 }
347 Ok(ColumnWidth::Length(parse_pixel_value(trimmed)?))
348 }
349
350 macro_rules! define_simple_column_parser {
352 (
353 $fn_name:ident,
354 $struct_name:ident,
355 $error_name:ident,
356 $error_owned_name:ident,
357 $prop_name:expr,
358 $($val:expr => $variant:path),+
359 ) => {
360 #[derive(Clone, PartialEq)]
361 pub enum $error_name<'a> {
362 InvalidValue(&'a str),
363 }
364
365 impl_debug_as_display!($error_name<'a>);
366 impl_display! { $error_name<'a>, {
367 InvalidValue(v) => format!("Invalid {} value: \"{}\"", $prop_name, v),
368 }}
369
370 #[derive(Debug, Clone, PartialEq)]
371 pub enum $error_owned_name {
372 InvalidValue(String),
373 }
374
375 impl<'a> $error_name<'a> {
376 pub fn to_contained(&self) -> $error_owned_name {
377 match self {
378 Self::InvalidValue(s) => $error_owned_name::InvalidValue(s.to_string()),
379 }
380 }
381 }
382
383 impl $error_owned_name {
384 pub fn to_shared<'a>(&'a self) -> $error_name<'a> {
385 match self {
386 Self::InvalidValue(s) => $error_name::InvalidValue(s.as_str()),
387 }
388 }
389 }
390
391 pub fn $fn_name<'a>(input: &'a str) -> Result<$struct_name, $error_name<'a>> {
392 match input.trim() {
393 $( $val => Ok($variant), )+
394 _ => Err($error_name::InvalidValue(input)),
395 }
396 }
397 };
398 }
399
400 define_simple_column_parser!(
401 parse_column_span,
402 ColumnSpan,
403 ColumnSpanParseError,
404 ColumnSpanParseErrorOwned,
405 "column-span",
406 "none" => ColumnSpan::None,
407 "all" => ColumnSpan::All
408 );
409
410 define_simple_column_parser!(
411 parse_column_fill,
412 ColumnFill,
413 ColumnFillParseError,
414 ColumnFillParseErrorOwned,
415 "column-fill",
416 "auto" => ColumnFill::Auto,
417 "balance" => ColumnFill::Balance
418 );
419
420 #[derive(Clone, PartialEq)]
423 pub enum ColumnRuleWidthParseError<'a> {
424 Pixel(CssPixelValueParseError<'a>),
425 }
426 impl_debug_as_display!(ColumnRuleWidthParseError<'a>);
427 impl_display! { ColumnRuleWidthParseError<'a>, { Pixel(e) => format!("{}", e) }}
428 impl_from! { CssPixelValueParseError<'a>, ColumnRuleWidthParseError::Pixel }
429 #[derive(Debug, Clone, PartialEq)]
430 pub enum ColumnRuleWidthParseErrorOwned {
431 Pixel(CssPixelValueParseErrorOwned),
432 }
433 impl<'a> ColumnRuleWidthParseError<'a> {
434 pub fn to_contained(&self) -> ColumnRuleWidthParseErrorOwned {
435 match self {
436 ColumnRuleWidthParseError::Pixel(e) => {
437 ColumnRuleWidthParseErrorOwned::Pixel(e.to_contained())
438 }
439 }
440 }
441 }
442 impl ColumnRuleWidthParseErrorOwned {
443 pub fn to_shared<'a>(&'a self) -> ColumnRuleWidthParseError<'a> {
444 match self {
445 ColumnRuleWidthParseErrorOwned::Pixel(e) => {
446 ColumnRuleWidthParseError::Pixel(e.to_shared())
447 }
448 }
449 }
450 }
451 pub fn parse_column_rule_width<'a>(
452 input: &'a str,
453 ) -> Result<ColumnRuleWidth, ColumnRuleWidthParseError<'a>> {
454 Ok(ColumnRuleWidth {
455 inner: parse_pixel_value(input)?,
456 })
457 }
458
459 #[derive(Clone, PartialEq)]
460 pub enum ColumnRuleStyleParseError<'a> {
461 Style(CssBorderStyleParseError<'a>),
462 }
463 impl_debug_as_display!(ColumnRuleStyleParseError<'a>);
464 impl_display! { ColumnRuleStyleParseError<'a>, { Style(e) => format!("{}", e) }}
465 impl_from! { CssBorderStyleParseError<'a>, ColumnRuleStyleParseError::Style }
466 #[derive(Debug, Clone, PartialEq)]
467 pub enum ColumnRuleStyleParseErrorOwned {
468 Style(CssBorderStyleParseErrorOwned),
469 }
470 impl<'a> ColumnRuleStyleParseError<'a> {
471 pub fn to_contained(&self) -> ColumnRuleStyleParseErrorOwned {
472 match self {
473 ColumnRuleStyleParseError::Style(e) => {
474 ColumnRuleStyleParseErrorOwned::Style(e.to_contained())
475 }
476 }
477 }
478 }
479 impl ColumnRuleStyleParseErrorOwned {
480 pub fn to_shared<'a>(&'a self) -> ColumnRuleStyleParseError<'a> {
481 match self {
482 ColumnRuleStyleParseErrorOwned::Style(e) => {
483 ColumnRuleStyleParseError::Style(e.to_shared())
484 }
485 }
486 }
487 }
488 pub fn parse_column_rule_style<'a>(
489 input: &'a str,
490 ) -> Result<ColumnRuleStyle, ColumnRuleStyleParseError<'a>> {
491 Ok(ColumnRuleStyle {
492 inner: parse_border_style(input)?,
493 })
494 }
495
496 #[derive(Clone, PartialEq)]
497 pub enum ColumnRuleColorParseError<'a> {
498 Color(CssColorParseError<'a>),
499 }
500 impl_debug_as_display!(ColumnRuleColorParseError<'a>);
501 impl_display! { ColumnRuleColorParseError<'a>, { Color(e) => format!("{}", e) }}
502 impl_from! { CssColorParseError<'a>, ColumnRuleColorParseError::Color }
503 #[derive(Debug, Clone, PartialEq)]
504 pub enum ColumnRuleColorParseErrorOwned {
505 Color(CssColorParseErrorOwned),
506 }
507 impl<'a> ColumnRuleColorParseError<'a> {
508 pub fn to_contained(&self) -> ColumnRuleColorParseErrorOwned {
509 match self {
510 ColumnRuleColorParseError::Color(e) => {
511 ColumnRuleColorParseErrorOwned::Color(e.to_contained())
512 }
513 }
514 }
515 }
516 impl ColumnRuleColorParseErrorOwned {
517 pub fn to_shared<'a>(&'a self) -> ColumnRuleColorParseError<'a> {
518 match self {
519 ColumnRuleColorParseErrorOwned::Color(e) => {
520 ColumnRuleColorParseError::Color(e.to_shared())
521 }
522 }
523 }
524 }
525 pub fn parse_column_rule_color<'a>(
526 input: &'a str,
527 ) -> Result<ColumnRuleColor, ColumnRuleColorParseError<'a>> {
528 Ok(ColumnRuleColor {
529 inner: parse_css_color(input)?,
530 })
531 }
532}
533
534#[cfg(feature = "parser")]
535pub use parser::*;
536
537#[cfg(all(test, feature = "parser"))]
538mod tests {
539 use super::*;
540
541 #[test]
542 fn test_parse_column_count() {
543 assert_eq!(parse_column_count("auto").unwrap(), ColumnCount::Auto);
544 assert_eq!(parse_column_count("3").unwrap(), ColumnCount::Integer(3));
545 assert!(parse_column_count("none").is_err());
546 assert!(parse_column_count("2.5").is_err());
547 }
548
549 #[test]
550 fn test_parse_column_width() {
551 assert_eq!(parse_column_width("auto").unwrap(), ColumnWidth::Auto);
552 assert_eq!(
553 parse_column_width("200px").unwrap(),
554 ColumnWidth::Length(PixelValue::px(200.0))
555 );
556 assert_eq!(
557 parse_column_width("15em").unwrap(),
558 ColumnWidth::Length(PixelValue::em(15.0))
559 );
560 assert!(parse_column_width("50%").is_ok()); }
562
563 #[test]
564 fn test_parse_column_span() {
565 assert_eq!(parse_column_span("none").unwrap(), ColumnSpan::None);
566 assert_eq!(parse_column_span("all").unwrap(), ColumnSpan::All);
567 assert!(parse_column_span("2").is_err());
568 }
569
570 #[test]
571 fn test_parse_column_fill() {
572 assert_eq!(parse_column_fill("auto").unwrap(), ColumnFill::Auto);
573 assert_eq!(parse_column_fill("balance").unwrap(), ColumnFill::Balance);
574 assert!(parse_column_fill("none").is_err());
575 }
576
577 #[test]
578 fn test_parse_column_rule() {
579 assert_eq!(
580 parse_column_rule_width("5px").unwrap().inner,
581 PixelValue::px(5.0)
582 );
583 assert_eq!(
584 parse_column_rule_style("dotted").unwrap().inner,
585 BorderStyle::Dotted
586 );
587 assert_eq!(parse_column_rule_color("blue").unwrap().inner, ColorU::BLUE);
588 }
589}