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