1use alloc::string::{String, ToString};
4use core::fmt;
5
6use crate::{
7 format_rust_code::FormatAsRustCode,
8 props::{
9 basic::{
10 error::{InvalidValueErr, InvalidValueErrOwned},
11 length::{PercentageParseError, PercentageParseErrorOwned, PercentageValue},
12 pixel::{CssPixelValueParseError, CssPixelValueParseErrorOwned, PixelValue},
13 ColorU, CssDuration,
14 },
15 formatter::PrintAsCssValue,
16 macros::PixelValueTaker,
17 },
18};
19
20#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[repr(C)]
27pub struct StyleTextColor {
28 pub inner: crate::props::basic::color::ColorU,
29}
30
31impl fmt::Debug for StyleTextColor {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 write!(f, "{}", self.print_as_css_value())
34 }
35}
36
37impl StyleTextColor {
38 pub fn interpolate(&self, other: &Self, t: f32) -> Self {
39 Self {
40 inner: self.inner.interpolate(&other.inner, t),
41 }
42 }
43}
44
45impl PrintAsCssValue for StyleTextColor {
46 fn print_as_css_value(&self) -> String {
47 self.inner.to_hash()
48 }
49}
50
51#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55#[repr(C)]
56pub enum StyleTextAlign {
57 Left,
58 Center,
59 Right,
60 Justify,
61 #[default]
62 Start,
63 End,
64}
65
66impl_option!(
67 StyleTextAlign,
68 OptionStyleTextAlign,
69 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
70);
71
72impl PrintAsCssValue for StyleTextAlign {
73 fn print_as_css_value(&self) -> String {
74 String::from(match self {
75 StyleTextAlign::Left => "left",
76 StyleTextAlign::Center => "center",
77 StyleTextAlign::Right => "right",
78 StyleTextAlign::Justify => "justify",
79 StyleTextAlign::Start => "start",
80 StyleTextAlign::End => "end",
81 })
82 }
83}
84
85#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
89#[repr(C)]
90pub struct StyleLetterSpacing {
91 pub inner: PixelValue,
92}
93
94impl fmt::Debug for StyleLetterSpacing {
95 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 write!(f, "{}", self.inner)
97 }
98}
99impl Default for StyleLetterSpacing {
100 fn default() -> Self {
101 Self {
102 inner: PixelValue::const_px(0),
103 }
104 }
105}
106impl_pixel_value!(StyleLetterSpacing);
107impl PixelValueTaker for StyleLetterSpacing {
108 fn from_pixel_value(inner: PixelValue) -> Self {
109 Self { inner }
110 }
111}
112impl PrintAsCssValue for StyleLetterSpacing {
113 fn print_as_css_value(&self) -> String {
114 format!("{}", self.inner)
115 }
116}
117
118#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
122#[repr(C)]
123pub struct StyleWordSpacing {
124 pub inner: PixelValue,
125}
126
127impl fmt::Debug for StyleWordSpacing {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 write!(f, "{}", self.inner)
130 }
131}
132impl Default for StyleWordSpacing {
133 fn default() -> Self {
134 Self {
135 inner: PixelValue::const_px(0),
136 }
137 }
138}
139impl_pixel_value!(StyleWordSpacing);
140impl PixelValueTaker for StyleWordSpacing {
141 fn from_pixel_value(inner: PixelValue) -> Self {
142 Self { inner }
143 }
144}
145impl PrintAsCssValue for StyleWordSpacing {
146 fn print_as_css_value(&self) -> String {
147 format!("{}", self.inner)
148 }
149}
150
151#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
155#[repr(C)]
156pub struct StyleLineHeight {
157 pub inner: PercentageValue,
158}
159impl Default for StyleLineHeight {
160 fn default() -> Self {
161 Self {
162 inner: PercentageValue::const_new(120),
163 }
164 }
165}
166impl_percentage_value!(StyleLineHeight);
167impl PrintAsCssValue for StyleLineHeight {
168 fn print_as_css_value(&self) -> String {
169 format!("{}", self.inner)
170 }
171}
172
173#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
177#[repr(C)]
178pub struct StyleTabSize {
179 pub inner: PixelValue, }
181
182impl fmt::Debug for StyleTabSize {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 write!(f, "{}", self.inner)
185 }
186}
187impl Default for StyleTabSize {
188 fn default() -> Self {
189 Self {
190 inner: PixelValue::em(8.0),
191 }
192 }
193}
194impl_pixel_value!(StyleTabSize);
195impl PixelValueTaker for StyleTabSize {
196 fn from_pixel_value(inner: PixelValue) -> Self {
197 Self { inner }
198 }
199}
200impl PrintAsCssValue for StyleTabSize {
201 fn print_as_css_value(&self) -> String {
202 format!("{}", self.inner)
203 }
204}
205
206#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
212#[repr(C)]
213pub enum StyleWhiteSpace {
214 Normal,
216 Pre,
218 Nowrap,
220 PreWrap,
222 PreLine,
224 BreakSpaces,
226}
227impl Default for StyleWhiteSpace {
228 fn default() -> Self {
229 StyleWhiteSpace::Normal
230 }
231}
232impl_option!(
233 StyleWhiteSpace,
234 OptionStyleWhiteSpace,
235 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
236);
237impl PrintAsCssValue for StyleWhiteSpace {
238 fn print_as_css_value(&self) -> String {
239 String::from(match self {
240 StyleWhiteSpace::Normal => "normal",
241 StyleWhiteSpace::Pre => "pre",
242 StyleWhiteSpace::Nowrap => "nowrap",
243 StyleWhiteSpace::PreWrap => "pre-wrap",
244 StyleWhiteSpace::PreLine => "pre-line",
245 StyleWhiteSpace::BreakSpaces => "break-spaces",
246 })
247 }
248}
249
250#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
254#[repr(C)]
255pub enum StyleHyphens {
256 Auto,
257 None,
258}
259impl Default for StyleHyphens {
260 fn default() -> Self {
261 StyleHyphens::None
262 }
263}
264impl_option!(
265 StyleHyphens,
266 OptionStyleHyphens,
267 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
268);
269impl PrintAsCssValue for StyleHyphens {
270 fn print_as_css_value(&self) -> String {
271 String::from(match self {
272 StyleHyphens::Auto => "auto",
273 StyleHyphens::None => "none",
274 })
275 }
276}
277
278#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
282#[repr(C)]
283pub enum StyleDirection {
284 Ltr,
285 Rtl,
286}
287impl Default for StyleDirection {
288 fn default() -> Self {
289 StyleDirection::Ltr
290 }
291}
292impl_option!(
293 StyleDirection,
294 OptionStyleDirection,
295 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
296);
297impl PrintAsCssValue for StyleDirection {
298 fn print_as_css_value(&self) -> String {
299 String::from(match self {
300 StyleDirection::Ltr => "ltr",
301 StyleDirection::Rtl => "rtl",
302 })
303 }
304}
305
306#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
311#[repr(C)]
312pub enum StyleUserSelect {
313 Auto,
315 Text,
317 None,
319 All,
321}
322impl Default for StyleUserSelect {
323 fn default() -> Self {
324 StyleUserSelect::Auto
325 }
326}
327impl_option!(
328 StyleUserSelect,
329 OptionStyleUserSelect,
330 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
331);
332impl PrintAsCssValue for StyleUserSelect {
333 fn print_as_css_value(&self) -> String {
334 String::from(match self {
335 StyleUserSelect::Auto => "auto",
336 StyleUserSelect::Text => "text",
337 StyleUserSelect::None => "none",
338 StyleUserSelect::All => "all",
339 })
340 }
341}
342
343#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
347#[repr(C)]
348pub enum StyleTextDecoration {
349 None,
351 Underline,
353 Overline,
355 LineThrough,
357}
358impl Default for StyleTextDecoration {
359 fn default() -> Self {
360 StyleTextDecoration::None
361 }
362}
363impl_option!(
364 StyleTextDecoration,
365 OptionStyleTextDecoration,
366 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
367);
368impl PrintAsCssValue for StyleTextDecoration {
369 fn print_as_css_value(&self) -> String {
370 String::from(match self {
371 StyleTextDecoration::None => "none",
372 StyleTextDecoration::Underline => "underline",
373 StyleTextDecoration::Overline => "overline",
374 StyleTextDecoration::LineThrough => "line-through",
375 })
376 }
377}
378
379#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
383#[repr(C)]
384pub enum StyleVerticalAlign {
385 Baseline,
387 Top,
389 Middle,
391 Bottom,
393 Sub,
395 Superscript,
397 TextTop,
399 TextBottom,
401}
402
403impl_option!(
404 StyleVerticalAlign,
405 OptionStyleVerticalAlign,
406 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
407);
408
409impl Default for StyleVerticalAlign {
410 fn default() -> Self {
411 StyleVerticalAlign::Baseline
412 }
413}
414impl PrintAsCssValue for StyleVerticalAlign {
415 fn print_as_css_value(&self) -> String {
416 String::from(match self {
417 StyleVerticalAlign::Baseline => "baseline",
418 StyleVerticalAlign::Top => "top",
419 StyleVerticalAlign::Middle => "middle",
420 StyleVerticalAlign::Bottom => "bottom",
421 StyleVerticalAlign::Sub => "sub",
422 StyleVerticalAlign::Superscript => "super",
423 StyleVerticalAlign::TextTop => "text-top",
424 StyleVerticalAlign::TextBottom => "text-bottom",
425 })
426 }
427}
428
429impl crate::format_rust_code::FormatAsRustCode for StyleVerticalAlign {
430 fn format_as_rust_code(&self, _: usize) -> String {
431 match self {
432 StyleVerticalAlign::Baseline => "StyleVerticalAlign::Baseline",
433 StyleVerticalAlign::Top => "StyleVerticalAlign::Top",
434 StyleVerticalAlign::Middle => "StyleVerticalAlign::Middle",
435 StyleVerticalAlign::Bottom => "StyleVerticalAlign::Bottom",
436 StyleVerticalAlign::Sub => "StyleVerticalAlign::Sub",
437 StyleVerticalAlign::Superscript => "StyleVerticalAlign::Superscript",
438 StyleVerticalAlign::TextTop => "StyleVerticalAlign::TextTop",
439 StyleVerticalAlign::TextBottom => "StyleVerticalAlign::TextBottom",
440 }
441 .to_string()
442 }
443}
444
445#[cfg(feature = "parser")]
448use crate::props::basic::{
449 color::{parse_css_color, CssColorParseError, CssColorParseErrorOwned},
450 DurationParseError,
451};
452
453#[cfg(feature = "parser")]
454#[derive(Clone, PartialEq)]
455pub enum StyleTextColorParseError<'a> {
456 ColorParseError(CssColorParseError<'a>),
457}
458#[cfg(feature = "parser")]
459impl_debug_as_display!(StyleTextColorParseError<'a>);
460#[cfg(feature = "parser")]
461impl_display! { StyleTextColorParseError<'a>, {
462 ColorParseError(e) => format!("Invalid color: {}", e),
463}}
464#[cfg(feature = "parser")]
465impl_from!(
466 CssColorParseError<'a>,
467 StyleTextColorParseError::ColorParseError
468);
469
470#[cfg(feature = "parser")]
471#[derive(Debug, Clone, PartialEq)]
472pub enum StyleTextColorParseErrorOwned {
473 ColorParseError(CssColorParseErrorOwned),
474}
475
476#[cfg(feature = "parser")]
477impl<'a> StyleTextColorParseError<'a> {
478 pub fn to_contained(&self) -> StyleTextColorParseErrorOwned {
479 match self {
480 Self::ColorParseError(e) => {
481 StyleTextColorParseErrorOwned::ColorParseError(e.to_contained())
482 }
483 }
484 }
485}
486
487#[cfg(feature = "parser")]
488impl StyleTextColorParseErrorOwned {
489 pub fn to_shared<'a>(&'a self) -> StyleTextColorParseError<'a> {
490 match self {
491 Self::ColorParseError(e) => StyleTextColorParseError::ColorParseError(e.to_shared()),
492 }
493 }
494}
495
496#[cfg(feature = "parser")]
497pub fn parse_style_text_color(input: &str) -> Result<StyleTextColor, StyleTextColorParseError> {
498 parse_css_color(input)
499 .map(|inner| StyleTextColor { inner })
500 .map_err(|e| StyleTextColorParseError::ColorParseError(e))
501}
502
503#[cfg(feature = "parser")]
504#[derive(Clone, PartialEq)]
505pub enum StyleTextAlignParseError<'a> {
506 InvalidValue(InvalidValueErr<'a>),
507}
508#[cfg(feature = "parser")]
509impl_debug_as_display!(StyleTextAlignParseError<'a>);
510#[cfg(feature = "parser")]
511impl_display! { StyleTextAlignParseError<'a>, {
512 InvalidValue(e) => format!("Invalid text-align value: \"{}\"", e.0),
513}}
514#[cfg(feature = "parser")]
515impl_from!(InvalidValueErr<'a>, StyleTextAlignParseError::InvalidValue);
516
517#[cfg(feature = "parser")]
518#[derive(Debug, Clone, PartialEq)]
519pub enum StyleTextAlignParseErrorOwned {
520 InvalidValue(InvalidValueErrOwned),
521}
522
523#[cfg(feature = "parser")]
524impl<'a> StyleTextAlignParseError<'a> {
525 pub fn to_contained(&self) -> StyleTextAlignParseErrorOwned {
526 match self {
527 Self::InvalidValue(e) => StyleTextAlignParseErrorOwned::InvalidValue(e.to_contained()),
528 }
529 }
530}
531
532#[cfg(feature = "parser")]
533impl StyleTextAlignParseErrorOwned {
534 pub fn to_shared<'a>(&'a self) -> StyleTextAlignParseError<'a> {
535 match self {
536 Self::InvalidValue(e) => StyleTextAlignParseError::InvalidValue(e.to_shared()),
537 }
538 }
539}
540
541#[cfg(feature = "parser")]
542pub fn parse_style_text_align(input: &str) -> Result<StyleTextAlign, StyleTextAlignParseError> {
543 match input.trim() {
544 "left" => Ok(StyleTextAlign::Left),
545 "center" => Ok(StyleTextAlign::Center),
546 "right" => Ok(StyleTextAlign::Right),
547 "justify" => Ok(StyleTextAlign::Justify),
548 "start" => Ok(StyleTextAlign::Start),
549 "end" => Ok(StyleTextAlign::End),
550 other => Err(StyleTextAlignParseError::InvalidValue(InvalidValueErr(
551 other,
552 ))),
553 }
554}
555
556#[cfg(feature = "parser")]
557#[derive(Clone, PartialEq)]
558pub enum StyleLetterSpacingParseError<'a> {
559 PixelValue(CssPixelValueParseError<'a>),
560}
561#[cfg(feature = "parser")]
562impl_debug_as_display!(StyleLetterSpacingParseError<'a>);
563#[cfg(feature = "parser")]
564impl_display! { StyleLetterSpacingParseError<'a>, {
565 PixelValue(e) => format!("Invalid letter-spacing value: {}", e),
566}}
567#[cfg(feature = "parser")]
568impl_from!(
569 CssPixelValueParseError<'a>,
570 StyleLetterSpacingParseError::PixelValue
571);
572
573#[cfg(feature = "parser")]
574#[derive(Debug, Clone, PartialEq)]
575pub enum StyleLetterSpacingParseErrorOwned {
576 PixelValue(CssPixelValueParseErrorOwned),
577}
578
579#[cfg(feature = "parser")]
580impl<'a> StyleLetterSpacingParseError<'a> {
581 pub fn to_contained(&self) -> StyleLetterSpacingParseErrorOwned {
582 match self {
583 Self::PixelValue(e) => StyleLetterSpacingParseErrorOwned::PixelValue(e.to_contained()),
584 }
585 }
586}
587
588#[cfg(feature = "parser")]
589impl StyleLetterSpacingParseErrorOwned {
590 pub fn to_shared<'a>(&'a self) -> StyleLetterSpacingParseError<'a> {
591 match self {
592 Self::PixelValue(e) => StyleLetterSpacingParseError::PixelValue(e.to_shared()),
593 }
594 }
595}
596
597#[cfg(feature = "parser")]
598pub fn parse_style_letter_spacing(
599 input: &str,
600) -> Result<StyleLetterSpacing, StyleLetterSpacingParseError> {
601 crate::props::basic::pixel::parse_pixel_value(input)
602 .map(|inner| StyleLetterSpacing { inner })
603 .map_err(|e| StyleLetterSpacingParseError::PixelValue(e))
604}
605
606#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
610#[repr(C)]
611pub struct StyleTextIndent {
612 pub inner: PixelValue,
613}
614
615impl fmt::Debug for StyleTextIndent {
616 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
617 write!(f, "{}", self.print_as_css_value())
618 }
619}
620
621impl_pixel_value!(StyleTextIndent);
622
623impl PrintAsCssValue for StyleTextIndent {
624 fn print_as_css_value(&self) -> String {
625 self.inner.to_string()
626 }
627}
628
629impl crate::format_rust_code::FormatAsRustCode for StyleTextIndent {
630 fn format_as_rust_code(&self, _tabs: usize) -> String {
631 format!(
632 "StyleTextIndent {{ inner: PixelValue::const_px(0) /* {} */ }}",
633 self.inner
634 )
635 }
636}
637
638#[cfg(feature = "parser")]
639#[derive(Clone, PartialEq)]
640pub enum StyleTextIndentParseError<'a> {
641 PixelValue(CssPixelValueParseError<'a>),
642}
643#[cfg(feature = "parser")]
644impl_debug_as_display!(StyleTextIndentParseError<'a>);
645#[cfg(feature = "parser")]
646impl_display! { StyleTextIndentParseError<'a>, {
647 PixelValue(e) => format!("Invalid text-indent value: {}", e),
648}}
649#[cfg(feature = "parser")]
650impl_from!(
651 CssPixelValueParseError<'a>,
652 StyleTextIndentParseError::PixelValue
653);
654
655#[cfg(feature = "parser")]
656#[derive(Debug, Clone, PartialEq)]
657pub enum StyleTextIndentParseErrorOwned {
658 PixelValue(CssPixelValueParseErrorOwned),
659}
660
661#[cfg(feature = "parser")]
662impl<'a> StyleTextIndentParseError<'a> {
663 pub fn to_contained(&self) -> StyleTextIndentParseErrorOwned {
664 match self {
665 Self::PixelValue(e) => StyleTextIndentParseErrorOwned::PixelValue(e.to_contained()),
666 }
667 }
668}
669
670#[cfg(feature = "parser")]
671impl StyleTextIndentParseErrorOwned {
672 pub fn to_shared<'a>(&'a self) -> StyleTextIndentParseError<'a> {
673 match self {
674 Self::PixelValue(e) => StyleTextIndentParseError::PixelValue(e.to_shared()),
675 }
676 }
677}
678
679#[cfg(feature = "parser")]
680pub fn parse_style_text_indent(input: &str) -> Result<StyleTextIndent, StyleTextIndentParseError> {
681 crate::props::basic::pixel::parse_pixel_value(input)
682 .map(|inner| StyleTextIndent { inner })
683 .map_err(|e| StyleTextIndentParseError::PixelValue(e))
684}
685
686#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
688#[repr(C)]
689pub struct StyleInitialLetter {
690 pub size: u32,
691 pub sink: crate::corety::OptionU32,
692}
693
694impl FormatAsRustCode for StyleInitialLetter {
695 fn format_as_rust_code(&self, _tabs: usize) -> String {
696 format!("{:?}", self)
697 }
698}
699
700impl PrintAsCssValue for StyleInitialLetter {
701 fn print_as_css_value(&self) -> String {
702 if let crate::corety::OptionU32::Some(sink) = self.sink {
703 format!("{} {}", self.size, sink)
704 } else {
705 format!("{}", self.size)
706 }
707 }
708}
709
710#[cfg(feature = "parser")]
711#[derive(Clone, PartialEq)]
712pub enum StyleInitialLetterParseError<'a> {
713 InvalidFormat(&'a str),
714 InvalidSize(&'a str),
715 InvalidSink(&'a str),
716}
717#[cfg(feature = "parser")]
718impl_debug_as_display!(StyleInitialLetterParseError<'a>);
719#[cfg(feature = "parser")]
720impl_display! { StyleInitialLetterParseError<'a>, {
721 InvalidFormat(e) => format!("Invalid initial-letter format: {}", e),
722 InvalidSize(e) => format!("Invalid initial-letter size: {}", e),
723 InvalidSink(e) => format!("Invalid initial-letter sink: {}", e),
724}}
725
726#[cfg(feature = "parser")]
727#[derive(Debug, Clone, PartialEq)]
728pub enum StyleInitialLetterParseErrorOwned {
729 InvalidFormat(String),
730 InvalidSize(String),
731 InvalidSink(String),
732}
733
734#[cfg(feature = "parser")]
735impl<'a> StyleInitialLetterParseError<'a> {
736 pub fn to_contained(&self) -> StyleInitialLetterParseErrorOwned {
737 match self {
738 Self::InvalidFormat(s) => {
739 StyleInitialLetterParseErrorOwned::InvalidFormat(s.to_string())
740 }
741 Self::InvalidSize(s) => StyleInitialLetterParseErrorOwned::InvalidSize(s.to_string()),
742 Self::InvalidSink(s) => StyleInitialLetterParseErrorOwned::InvalidSink(s.to_string()),
743 }
744 }
745}
746
747#[cfg(feature = "parser")]
748impl StyleInitialLetterParseErrorOwned {
749 pub fn to_shared<'a>(&'a self) -> StyleInitialLetterParseError<'a> {
750 match self {
751 Self::InvalidFormat(s) => StyleInitialLetterParseError::InvalidFormat(s.as_str()),
752 Self::InvalidSize(s) => StyleInitialLetterParseError::InvalidSize(s.as_str()),
753 Self::InvalidSink(s) => StyleInitialLetterParseError::InvalidSink(s.as_str()),
754 }
755 }
756}
757
758#[cfg(feature = "parser")]
759impl From<StyleInitialLetterParseError<'_>> for StyleInitialLetterParseErrorOwned {
760 fn from(e: StyleInitialLetterParseError) -> Self {
761 match e {
762 StyleInitialLetterParseError::InvalidFormat(s) => {
763 StyleInitialLetterParseErrorOwned::InvalidFormat(s.to_string())
764 }
765 StyleInitialLetterParseError::InvalidSize(s) => {
766 StyleInitialLetterParseErrorOwned::InvalidSize(s.to_string())
767 }
768 StyleInitialLetterParseError::InvalidSink(s) => {
769 StyleInitialLetterParseErrorOwned::InvalidSink(s.to_string())
770 }
771 }
772 }
773}
774
775#[cfg(feature = "parser")]
776impl_display! { StyleInitialLetterParseErrorOwned, {
777 InvalidFormat(e) => format!("Invalid initial-letter format: {}", e),
778 InvalidSize(e) => format!("Invalid initial-letter size: {}", e),
779 InvalidSink(e) => format!("Invalid initial-letter sink: {}", e),
780}}
781
782#[cfg(feature = "parser")]
783pub fn parse_style_initial_letter<'a>(
784 input: &'a str,
785) -> Result<StyleInitialLetter, StyleInitialLetterParseError<'a>> {
786 let input = input.trim();
787 let parts: Vec<&str> = input.split_whitespace().collect();
788
789 if parts.is_empty() {
790 return Err(StyleInitialLetterParseError::InvalidFormat(input));
791 }
792
793 let size = parts[0]
795 .parse::<u32>()
796 .map_err(|_| StyleInitialLetterParseError::InvalidSize(parts[0]))?;
797
798 if size == 0 {
799 return Err(StyleInitialLetterParseError::InvalidSize(parts[0]));
800 }
801
802 let sink = if parts.len() > 1 {
804 crate::corety::OptionU32::Some(
805 parts[1]
806 .parse::<u32>()
807 .map_err(|_| StyleInitialLetterParseError::InvalidSink(parts[1]))?,
808 )
809 } else {
810 crate::corety::OptionU32::None
811 };
812
813 Ok(StyleInitialLetter { size, sink })
814}
815
816#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
818#[repr(C)]
819pub struct StyleLineClamp {
820 pub max_lines: usize,
821}
822
823impl FormatAsRustCode for StyleLineClamp {
824 fn format_as_rust_code(&self, _tabs: usize) -> String {
825 format!("{:?}", self)
826 }
827}
828
829impl PrintAsCssValue for StyleLineClamp {
830 fn print_as_css_value(&self) -> String {
831 format!("{}", self.max_lines)
832 }
833}
834
835#[cfg(feature = "parser")]
836#[derive(Clone, PartialEq)]
837pub enum StyleLineClampParseError<'a> {
838 InvalidValue(&'a str),
839 ZeroValue,
840}
841#[cfg(feature = "parser")]
842impl_debug_as_display!(StyleLineClampParseError<'a>);
843#[cfg(feature = "parser")]
844impl_display! { StyleLineClampParseError<'a>, {
845 InvalidValue(e) => format!("Invalid line-clamp value: {}", e),
846 ZeroValue => format!("line-clamp cannot be zero"),
847}}
848
849#[cfg(feature = "parser")]
850#[derive(Debug, Clone, PartialEq)]
851pub enum StyleLineClampParseErrorOwned {
852 InvalidValue(String),
853 ZeroValue,
854}
855
856#[cfg(feature = "parser")]
857impl<'a> StyleLineClampParseError<'a> {
858 pub fn to_contained(&self) -> StyleLineClampParseErrorOwned {
859 match self {
860 Self::InvalidValue(s) => StyleLineClampParseErrorOwned::InvalidValue(s.to_string()),
861 Self::ZeroValue => StyleLineClampParseErrorOwned::ZeroValue,
862 }
863 }
864}
865
866#[cfg(feature = "parser")]
867impl StyleLineClampParseErrorOwned {
868 pub fn to_shared<'a>(&'a self) -> StyleLineClampParseError<'a> {
869 match self {
870 Self::InvalidValue(s) => StyleLineClampParseError::InvalidValue(s.as_str()),
871 Self::ZeroValue => StyleLineClampParseError::ZeroValue,
872 }
873 }
874}
875
876#[cfg(feature = "parser")]
877impl From<StyleLineClampParseError<'_>> for StyleLineClampParseErrorOwned {
878 fn from(e: StyleLineClampParseError) -> Self {
879 e.to_contained()
880 }
881}
882
883#[cfg(feature = "parser")]
884impl_display! { StyleLineClampParseErrorOwned, {
885 InvalidValue(e) => format!("Invalid line-clamp value: {}", e),
886 ZeroValue => format!("line-clamp cannot be zero"),
887}}
888
889#[cfg(feature = "parser")]
890pub fn parse_style_line_clamp<'a>(
891 input: &'a str,
892) -> Result<StyleLineClamp, StyleLineClampParseError<'a>> {
893 let input = input.trim();
894
895 let max_lines = input
896 .parse::<usize>()
897 .map_err(|_| StyleLineClampParseError::InvalidValue(input))?;
898
899 if max_lines == 0 {
900 return Err(StyleLineClampParseError::ZeroValue);
901 }
902
903 Ok(StyleLineClamp { max_lines })
904}
905
906#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
908#[repr(C)]
909pub struct StyleHangingPunctuation {
910 pub enabled: bool,
911}
912
913impl Default for StyleHangingPunctuation {
914 fn default() -> Self {
915 Self { enabled: false }
916 }
917}
918
919impl FormatAsRustCode for StyleHangingPunctuation {
920 fn format_as_rust_code(&self, _tabs: usize) -> String {
921 format!("{:?}", self)
922 }
923}
924
925impl PrintAsCssValue for StyleHangingPunctuation {
926 fn print_as_css_value(&self) -> String {
927 if self.enabled {
928 "first allow-end last force-end".to_string()
929 } else {
930 "none".to_string()
931 }
932 }
933}
934
935#[cfg(feature = "parser")]
936#[derive(Clone, PartialEq)]
937pub enum StyleHangingPunctuationParseError<'a> {
938 InvalidValue(&'a str),
939}
940#[cfg(feature = "parser")]
941impl_debug_as_display!(StyleHangingPunctuationParseError<'a>);
942#[cfg(feature = "parser")]
943impl_display! { StyleHangingPunctuationParseError<'a>, {
944 InvalidValue(e) => format!("Invalid hanging-punctuation value: {}", e),
945}}
946
947#[cfg(feature = "parser")]
948#[derive(Debug, Clone, PartialEq)]
949pub enum StyleHangingPunctuationParseErrorOwned {
950 InvalidValue(String),
951}
952
953#[cfg(feature = "parser")]
954impl<'a> StyleHangingPunctuationParseError<'a> {
955 pub fn to_contained(&self) -> StyleHangingPunctuationParseErrorOwned {
956 match self {
957 Self::InvalidValue(s) => {
958 StyleHangingPunctuationParseErrorOwned::InvalidValue(s.to_string())
959 }
960 }
961 }
962}
963
964#[cfg(feature = "parser")]
965impl StyleHangingPunctuationParseErrorOwned {
966 pub fn to_shared<'a>(&'a self) -> StyleHangingPunctuationParseError<'a> {
967 match self {
968 Self::InvalidValue(s) => StyleHangingPunctuationParseError::InvalidValue(s.as_str()),
969 }
970 }
971}
972
973#[cfg(feature = "parser")]
974impl From<StyleHangingPunctuationParseError<'_>> for StyleHangingPunctuationParseErrorOwned {
975 fn from(e: StyleHangingPunctuationParseError) -> Self {
976 e.to_contained()
977 }
978}
979
980#[cfg(feature = "parser")]
981impl_display! { StyleHangingPunctuationParseErrorOwned, {
982 InvalidValue(e) => format!("Invalid hanging-punctuation value: {}", e),
983}}
984
985#[cfg(feature = "parser")]
986pub fn parse_style_hanging_punctuation<'a>(
987 input: &'a str,
988) -> Result<StyleHangingPunctuation, StyleHangingPunctuationParseError<'a>> {
989 let input = input.trim().to_lowercase();
990
991 let enabled = input != "none";
994
995 Ok(StyleHangingPunctuation { enabled })
996}
997
998#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1000#[repr(C, u8)]
1001pub enum StyleTextCombineUpright {
1002 None,
1003 All,
1004 Digits(u8),
1005}
1006
1007impl Default for StyleTextCombineUpright {
1008 fn default() -> Self {
1009 Self::None
1010 }
1011}
1012
1013impl FormatAsRustCode for StyleTextCombineUpright {
1014 fn format_as_rust_code(&self, _tabs: usize) -> String {
1015 format!("{:?}", self)
1016 }
1017}
1018
1019impl PrintAsCssValue for StyleTextCombineUpright {
1020 fn print_as_css_value(&self) -> String {
1021 match self {
1022 Self::None => "none".to_string(),
1023 Self::All => "all".to_string(),
1024 Self::Digits(n) => format!("digits {}", n),
1025 }
1026 }
1027}
1028
1029#[cfg(feature = "parser")]
1030#[derive(Clone, PartialEq)]
1031pub enum StyleTextCombineUprightParseError<'a> {
1032 InvalidValue(&'a str),
1033 InvalidDigits(&'a str),
1034}
1035#[cfg(feature = "parser")]
1036impl_debug_as_display!(StyleTextCombineUprightParseError<'a>);
1037#[cfg(feature = "parser")]
1038impl_display! { StyleTextCombineUprightParseError<'a>, {
1039 InvalidValue(e) => format!("Invalid text-combine-upright value: {}", e),
1040 InvalidDigits(e) => format!("Invalid text-combine-upright digits: {}", e),
1041}}
1042
1043#[cfg(feature = "parser")]
1044#[derive(Debug, Clone, PartialEq)]
1045pub enum StyleTextCombineUprightParseErrorOwned {
1046 InvalidValue(String),
1047 InvalidDigits(String),
1048}
1049
1050#[cfg(feature = "parser")]
1051impl<'a> StyleTextCombineUprightParseError<'a> {
1052 pub fn to_contained(&self) -> StyleTextCombineUprightParseErrorOwned {
1053 match self {
1054 Self::InvalidValue(s) => {
1055 StyleTextCombineUprightParseErrorOwned::InvalidValue(s.to_string())
1056 }
1057 Self::InvalidDigits(s) => {
1058 StyleTextCombineUprightParseErrorOwned::InvalidDigits(s.to_string())
1059 }
1060 }
1061 }
1062}
1063
1064#[cfg(feature = "parser")]
1065impl StyleTextCombineUprightParseErrorOwned {
1066 pub fn to_shared<'a>(&'a self) -> StyleTextCombineUprightParseError<'a> {
1067 match self {
1068 Self::InvalidValue(s) => StyleTextCombineUprightParseError::InvalidValue(s.as_str()),
1069 Self::InvalidDigits(s) => StyleTextCombineUprightParseError::InvalidDigits(s.as_str()),
1070 }
1071 }
1072}
1073
1074#[cfg(feature = "parser")]
1075impl From<StyleTextCombineUprightParseError<'_>> for StyleTextCombineUprightParseErrorOwned {
1076 fn from(e: StyleTextCombineUprightParseError) -> Self {
1077 e.to_contained()
1078 }
1079}
1080
1081#[cfg(feature = "parser")]
1082impl_display! { StyleTextCombineUprightParseErrorOwned, {
1083 InvalidValue(e) => format!("Invalid text-combine-upright value: {}", e),
1084 InvalidDigits(e) => format!("Invalid text-combine-upright digits: {}", e),
1085}}
1086
1087#[cfg(feature = "parser")]
1088pub fn parse_style_text_combine_upright<'a>(
1089 input: &'a str,
1090) -> Result<StyleTextCombineUpright, StyleTextCombineUprightParseError<'a>> {
1091 let trimmed = input.trim();
1092
1093 if trimmed.eq_ignore_ascii_case("none") {
1094 Ok(StyleTextCombineUpright::None)
1095 } else if trimmed.eq_ignore_ascii_case("all") {
1096 Ok(StyleTextCombineUpright::All)
1097 } else if trimmed.starts_with("digits") {
1098 let parts: Vec<&str> = trimmed.split_whitespace().collect();
1099 if parts.len() == 2 {
1100 let n = parts[1]
1101 .parse::<u8>()
1102 .map_err(|_| StyleTextCombineUprightParseError::InvalidDigits(input))?;
1103 if n >= 2 && n <= 4 {
1104 Ok(StyleTextCombineUpright::Digits(n))
1105 } else {
1106 Err(StyleTextCombineUprightParseError::InvalidDigits(input))
1107 }
1108 } else {
1109 Ok(StyleTextCombineUpright::Digits(2))
1111 }
1112 } else {
1113 Err(StyleTextCombineUprightParseError::InvalidValue(input))
1114 }
1115}
1116
1117#[cfg(feature = "parser")]
1118#[derive(Clone, PartialEq)]
1119pub enum StyleWordSpacingParseError<'a> {
1120 PixelValue(CssPixelValueParseError<'a>),
1121}
1122#[cfg(feature = "parser")]
1123impl_debug_as_display!(StyleWordSpacingParseError<'a>);
1124#[cfg(feature = "parser")]
1125impl_display! { StyleWordSpacingParseError<'a>, {
1126 PixelValue(e) => format!("Invalid word-spacing value: {}", e),
1127}}
1128#[cfg(feature = "parser")]
1129impl_from!(
1130 CssPixelValueParseError<'a>,
1131 StyleWordSpacingParseError::PixelValue
1132);
1133
1134#[cfg(feature = "parser")]
1135#[derive(Debug, Clone, PartialEq)]
1136pub enum StyleWordSpacingParseErrorOwned {
1137 PixelValue(CssPixelValueParseErrorOwned),
1138}
1139
1140#[cfg(feature = "parser")]
1141impl<'a> StyleWordSpacingParseError<'a> {
1142 pub fn to_contained(&self) -> StyleWordSpacingParseErrorOwned {
1143 match self {
1144 Self::PixelValue(e) => StyleWordSpacingParseErrorOwned::PixelValue(e.to_contained()),
1145 }
1146 }
1147}
1148
1149#[cfg(feature = "parser")]
1150impl StyleWordSpacingParseErrorOwned {
1151 pub fn to_shared<'a>(&'a self) -> StyleWordSpacingParseError<'a> {
1152 match self {
1153 Self::PixelValue(e) => StyleWordSpacingParseError::PixelValue(e.to_shared()),
1154 }
1155 }
1156}
1157
1158#[cfg(feature = "parser")]
1159pub fn parse_style_word_spacing(
1160 input: &str,
1161) -> Result<StyleWordSpacing, StyleWordSpacingParseError> {
1162 crate::props::basic::pixel::parse_pixel_value(input)
1163 .map(|inner| StyleWordSpacing { inner })
1164 .map_err(|e| StyleWordSpacingParseError::PixelValue(e))
1165}
1166
1167#[cfg(feature = "parser")]
1168#[derive(Clone, PartialEq)]
1169pub enum StyleLineHeightParseError {
1170 Percentage(PercentageParseError),
1171}
1172#[cfg(feature = "parser")]
1173impl_debug_as_display!(StyleLineHeightParseError);
1174#[cfg(feature = "parser")]
1175impl_display! { StyleLineHeightParseError, {
1176 Percentage(e) => format!("Invalid line-height value: {}", e),
1177}}
1178#[cfg(feature = "parser")]
1179impl_from!(PercentageParseError, StyleLineHeightParseError::Percentage);
1180
1181#[cfg(feature = "parser")]
1182#[derive(Debug, Clone, PartialEq)]
1183pub enum StyleLineHeightParseErrorOwned {
1184 Percentage(PercentageParseErrorOwned),
1185}
1186
1187#[cfg(feature = "parser")]
1188impl StyleLineHeightParseError {
1189 pub fn to_contained(&self) -> StyleLineHeightParseErrorOwned {
1190 match self {
1191 Self::Percentage(e) => StyleLineHeightParseErrorOwned::Percentage(e.to_contained()),
1192 }
1193 }
1194}
1195
1196#[cfg(feature = "parser")]
1197impl StyleLineHeightParseErrorOwned {
1198 pub fn to_shared(&self) -> StyleLineHeightParseError {
1199 match self {
1200 Self::Percentage(e) => StyleLineHeightParseError::Percentage(e.to_shared()),
1201 }
1202 }
1203}
1204
1205#[cfg(feature = "parser")]
1206pub fn parse_style_line_height(input: &str) -> Result<StyleLineHeight, StyleLineHeightParseError> {
1207 crate::props::basic::length::parse_percentage_value(input)
1208 .map(|inner| StyleLineHeight { inner })
1209 .map_err(|e| StyleLineHeightParseError::Percentage(e))
1210}
1211
1212#[cfg(feature = "parser")]
1213#[derive(Clone, PartialEq)]
1214pub enum StyleTabSizeParseError<'a> {
1215 PixelValue(CssPixelValueParseError<'a>),
1216}
1217#[cfg(feature = "parser")]
1218impl_debug_as_display!(StyleTabSizeParseError<'a>);
1219#[cfg(feature = "parser")]
1220impl_display! { StyleTabSizeParseError<'a>, {
1221 PixelValue(e) => format!("Invalid tab-size value: {}", e),
1222}}
1223#[cfg(feature = "parser")]
1224impl_from!(
1225 CssPixelValueParseError<'a>,
1226 StyleTabSizeParseError::PixelValue
1227);
1228
1229#[cfg(feature = "parser")]
1230#[derive(Debug, Clone, PartialEq)]
1231pub enum StyleTabSizeParseErrorOwned {
1232 PixelValue(CssPixelValueParseErrorOwned),
1233}
1234
1235#[cfg(feature = "parser")]
1236impl<'a> StyleTabSizeParseError<'a> {
1237 pub fn to_contained(&self) -> StyleTabSizeParseErrorOwned {
1238 match self {
1239 Self::PixelValue(e) => StyleTabSizeParseErrorOwned::PixelValue(e.to_contained()),
1240 }
1241 }
1242}
1243
1244#[cfg(feature = "parser")]
1245impl StyleTabSizeParseErrorOwned {
1246 pub fn to_shared<'a>(&'a self) -> StyleTabSizeParseError<'a> {
1247 match self {
1248 Self::PixelValue(e) => StyleTabSizeParseError::PixelValue(e.to_shared()),
1249 }
1250 }
1251}
1252
1253#[cfg(feature = "parser")]
1254pub fn parse_style_tab_size(input: &str) -> Result<StyleTabSize, StyleTabSizeParseError> {
1255 if let Ok(number) = input.trim().parse::<f32>() {
1256 Ok(StyleTabSize {
1257 inner: PixelValue::em(number),
1258 })
1259 } else {
1260 crate::props::basic::pixel::parse_pixel_value(input)
1261 .map(|v| StyleTabSize { inner: v })
1262 .map_err(|e| StyleTabSizeParseError::PixelValue(e))
1263 }
1264}
1265
1266#[cfg(feature = "parser")]
1267#[derive(Clone, PartialEq)]
1268pub enum StyleWhiteSpaceParseError<'a> {
1269 InvalidValue(InvalidValueErr<'a>),
1270}
1271#[cfg(feature = "parser")]
1272impl_debug_as_display!(StyleWhiteSpaceParseError<'a>);
1273#[cfg(feature = "parser")]
1274impl_display! { StyleWhiteSpaceParseError<'a>, {
1275 InvalidValue(e) => format!("Invalid white-space value: \"{}\"", e.0),
1276}}
1277#[cfg(feature = "parser")]
1278impl_from!(InvalidValueErr<'a>, StyleWhiteSpaceParseError::InvalidValue);
1279
1280#[cfg(feature = "parser")]
1281#[derive(Debug, Clone, PartialEq)]
1282pub enum StyleWhiteSpaceParseErrorOwned {
1283 InvalidValue(InvalidValueErrOwned),
1284}
1285
1286#[cfg(feature = "parser")]
1287impl<'a> StyleWhiteSpaceParseError<'a> {
1288 pub fn to_contained(&self) -> StyleWhiteSpaceParseErrorOwned {
1289 match self {
1290 Self::InvalidValue(e) => StyleWhiteSpaceParseErrorOwned::InvalidValue(e.to_contained()),
1291 }
1292 }
1293}
1294
1295#[cfg(feature = "parser")]
1296impl StyleWhiteSpaceParseErrorOwned {
1297 pub fn to_shared<'a>(&'a self) -> StyleWhiteSpaceParseError<'a> {
1298 match self {
1299 Self::InvalidValue(e) => StyleWhiteSpaceParseError::InvalidValue(e.to_shared()),
1300 }
1301 }
1302}
1303
1304#[cfg(feature = "parser")]
1305pub fn parse_style_white_space(input: &str) -> Result<StyleWhiteSpace, StyleWhiteSpaceParseError> {
1306 match input.trim() {
1307 "normal" => Ok(StyleWhiteSpace::Normal),
1308 "pre" => Ok(StyleWhiteSpace::Pre),
1309 "nowrap" | "no-wrap" => Ok(StyleWhiteSpace::Nowrap),
1310 "pre-wrap" => Ok(StyleWhiteSpace::PreWrap),
1311 "pre-line" => Ok(StyleWhiteSpace::PreLine),
1312 "break-spaces" => Ok(StyleWhiteSpace::BreakSpaces),
1313 other => Err(StyleWhiteSpaceParseError::InvalidValue(InvalidValueErr(
1314 other,
1315 ))),
1316 }
1317}
1318
1319#[cfg(feature = "parser")]
1320#[derive(Clone, PartialEq)]
1321pub enum StyleHyphensParseError<'a> {
1322 InvalidValue(InvalidValueErr<'a>),
1323}
1324#[cfg(feature = "parser")]
1325impl_debug_as_display!(StyleHyphensParseError<'a>);
1326#[cfg(feature = "parser")]
1327impl_display! { StyleHyphensParseError<'a>, {
1328 InvalidValue(e) => format!("Invalid hyphens value: \"{}\"", e.0),
1329}}
1330#[cfg(feature = "parser")]
1331impl_from!(InvalidValueErr<'a>, StyleHyphensParseError::InvalidValue);
1332
1333#[cfg(feature = "parser")]
1334#[derive(Debug, Clone, PartialEq)]
1335pub enum StyleHyphensParseErrorOwned {
1336 InvalidValue(InvalidValueErrOwned),
1337}
1338
1339#[cfg(feature = "parser")]
1340impl<'a> StyleHyphensParseError<'a> {
1341 pub fn to_contained(&self) -> StyleHyphensParseErrorOwned {
1342 match self {
1343 Self::InvalidValue(e) => StyleHyphensParseErrorOwned::InvalidValue(e.to_contained()),
1344 }
1345 }
1346}
1347
1348#[cfg(feature = "parser")]
1349impl StyleHyphensParseErrorOwned {
1350 pub fn to_shared<'a>(&'a self) -> StyleHyphensParseError<'a> {
1351 match self {
1352 Self::InvalidValue(e) => StyleHyphensParseError::InvalidValue(e.to_shared()),
1353 }
1354 }
1355}
1356
1357#[cfg(feature = "parser")]
1358pub fn parse_style_hyphens(input: &str) -> Result<StyleHyphens, StyleHyphensParseError> {
1359 match input.trim() {
1360 "auto" => Ok(StyleHyphens::Auto),
1361 "none" => Ok(StyleHyphens::None),
1362 other => Err(StyleHyphensParseError::InvalidValue(InvalidValueErr(other))),
1363 }
1364}
1365
1366#[cfg(feature = "parser")]
1367#[derive(Clone, PartialEq)]
1368pub enum StyleDirectionParseError<'a> {
1369 InvalidValue(InvalidValueErr<'a>),
1370}
1371#[cfg(feature = "parser")]
1372impl_debug_as_display!(StyleDirectionParseError<'a>);
1373#[cfg(feature = "parser")]
1374impl_display! { StyleDirectionParseError<'a>, {
1375 InvalidValue(e) => format!("Invalid direction value: \"{}\"", e.0),
1376}}
1377#[cfg(feature = "parser")]
1378impl_from!(InvalidValueErr<'a>, StyleDirectionParseError::InvalidValue);
1379
1380#[cfg(feature = "parser")]
1381#[derive(Debug, Clone, PartialEq)]
1382pub enum StyleDirectionParseErrorOwned {
1383 InvalidValue(InvalidValueErrOwned),
1384}
1385
1386#[cfg(feature = "parser")]
1387impl<'a> StyleDirectionParseError<'a> {
1388 pub fn to_contained(&self) -> StyleDirectionParseErrorOwned {
1389 match self {
1390 Self::InvalidValue(e) => StyleDirectionParseErrorOwned::InvalidValue(e.to_contained()),
1391 }
1392 }
1393}
1394
1395#[cfg(feature = "parser")]
1396impl StyleDirectionParseErrorOwned {
1397 pub fn to_shared<'a>(&'a self) -> StyleDirectionParseError<'a> {
1398 match self {
1399 Self::InvalidValue(e) => StyleDirectionParseError::InvalidValue(e.to_shared()),
1400 }
1401 }
1402}
1403
1404#[cfg(feature = "parser")]
1405pub fn parse_style_direction(input: &str) -> Result<StyleDirection, StyleDirectionParseError> {
1406 match input.trim() {
1407 "ltr" => Ok(StyleDirection::Ltr),
1408 "rtl" => Ok(StyleDirection::Rtl),
1409 other => Err(StyleDirectionParseError::InvalidValue(InvalidValueErr(
1410 other,
1411 ))),
1412 }
1413}
1414
1415#[cfg(feature = "parser")]
1416#[derive(Clone, PartialEq)]
1417pub enum StyleUserSelectParseError<'a> {
1418 InvalidValue(InvalidValueErr<'a>),
1419}
1420#[cfg(feature = "parser")]
1421impl_debug_as_display!(StyleUserSelectParseError<'a>);
1422#[cfg(feature = "parser")]
1423impl_display! { StyleUserSelectParseError<'a>, {
1424 InvalidValue(e) => format!("Invalid user-select value: \"{}\"", e.0),
1425}}
1426#[cfg(feature = "parser")]
1427impl_from!(InvalidValueErr<'a>, StyleUserSelectParseError::InvalidValue);
1428
1429#[cfg(feature = "parser")]
1430#[derive(Debug, Clone, PartialEq)]
1431pub enum StyleUserSelectParseErrorOwned {
1432 InvalidValue(InvalidValueErrOwned),
1433}
1434
1435#[cfg(feature = "parser")]
1436impl<'a> StyleUserSelectParseError<'a> {
1437 pub fn to_contained(&self) -> StyleUserSelectParseErrorOwned {
1438 match self {
1439 Self::InvalidValue(e) => StyleUserSelectParseErrorOwned::InvalidValue(e.to_contained()),
1440 }
1441 }
1442}
1443
1444#[cfg(feature = "parser")]
1445impl StyleUserSelectParseErrorOwned {
1446 pub fn to_shared<'a>(&'a self) -> StyleUserSelectParseError<'a> {
1447 match self {
1448 Self::InvalidValue(e) => StyleUserSelectParseError::InvalidValue(e.to_shared()),
1449 }
1450 }
1451}
1452
1453#[cfg(feature = "parser")]
1454pub fn parse_style_user_select(input: &str) -> Result<StyleUserSelect, StyleUserSelectParseError> {
1455 match input.trim() {
1456 "auto" => Ok(StyleUserSelect::Auto),
1457 "text" => Ok(StyleUserSelect::Text),
1458 "none" => Ok(StyleUserSelect::None),
1459 "all" => Ok(StyleUserSelect::All),
1460 other => Err(StyleUserSelectParseError::InvalidValue(InvalidValueErr(
1461 other,
1462 ))),
1463 }
1464}
1465
1466#[cfg(feature = "parser")]
1467#[derive(Clone, PartialEq)]
1468pub enum StyleTextDecorationParseError<'a> {
1469 InvalidValue(InvalidValueErr<'a>),
1470}
1471#[cfg(feature = "parser")]
1472impl_debug_as_display!(StyleTextDecorationParseError<'a>);
1473#[cfg(feature = "parser")]
1474impl_display! { StyleTextDecorationParseError<'a>, {
1475 InvalidValue(e) => format!("Invalid text-decoration value: \"{}\"", e.0),
1476}}
1477#[cfg(feature = "parser")]
1478impl_from!(
1479 InvalidValueErr<'a>,
1480 StyleTextDecorationParseError::InvalidValue
1481);
1482
1483#[cfg(feature = "parser")]
1484#[derive(Debug, Clone, PartialEq)]
1485pub enum StyleTextDecorationParseErrorOwned {
1486 InvalidValue(InvalidValueErrOwned),
1487}
1488
1489#[cfg(feature = "parser")]
1490impl<'a> StyleTextDecorationParseError<'a> {
1491 pub fn to_contained(&self) -> StyleTextDecorationParseErrorOwned {
1492 match self {
1493 Self::InvalidValue(e) => {
1494 StyleTextDecorationParseErrorOwned::InvalidValue(e.to_contained())
1495 }
1496 }
1497 }
1498}
1499
1500#[cfg(feature = "parser")]
1501impl StyleTextDecorationParseErrorOwned {
1502 pub fn to_shared<'a>(&'a self) -> StyleTextDecorationParseError<'a> {
1503 match self {
1504 Self::InvalidValue(e) => StyleTextDecorationParseError::InvalidValue(e.to_shared()),
1505 }
1506 }
1507}
1508
1509#[cfg(feature = "parser")]
1510pub fn parse_style_text_decoration(
1511 input: &str,
1512) -> Result<StyleTextDecoration, StyleTextDecorationParseError> {
1513 match input.trim() {
1514 "none" => Ok(StyleTextDecoration::None),
1515 "underline" => Ok(StyleTextDecoration::Underline),
1516 "overline" => Ok(StyleTextDecoration::Overline),
1517 "line-through" => Ok(StyleTextDecoration::LineThrough),
1518 other => Err(StyleTextDecorationParseError::InvalidValue(
1519 InvalidValueErr(other),
1520 )),
1521 }
1522}
1523
1524#[cfg(feature = "parser")]
1525#[derive(Clone, PartialEq)]
1526pub enum StyleVerticalAlignParseError<'a> {
1527 InvalidValue(InvalidValueErr<'a>),
1528}
1529#[cfg(feature = "parser")]
1530impl_debug_as_display!(StyleVerticalAlignParseError<'a>);
1531#[cfg(feature = "parser")]
1532impl_display! { StyleVerticalAlignParseError<'a>, {
1533 InvalidValue(e) => format!("Invalid vertical-align value: \"{}\"", e.0),
1534}}
1535#[cfg(feature = "parser")]
1536impl_from!(
1537 InvalidValueErr<'a>,
1538 StyleVerticalAlignParseError::InvalidValue
1539);
1540
1541#[cfg(feature = "parser")]
1542#[derive(Debug, Clone, PartialEq)]
1543pub enum StyleVerticalAlignParseErrorOwned {
1544 InvalidValue(InvalidValueErrOwned),
1545}
1546
1547#[cfg(feature = "parser")]
1548impl<'a> StyleVerticalAlignParseError<'a> {
1549 pub fn to_contained(&self) -> StyleVerticalAlignParseErrorOwned {
1550 match self {
1551 Self::InvalidValue(e) => {
1552 StyleVerticalAlignParseErrorOwned::InvalidValue(e.to_contained())
1553 }
1554 }
1555 }
1556}
1557
1558#[cfg(feature = "parser")]
1559impl StyleVerticalAlignParseErrorOwned {
1560 pub fn to_shared<'a>(&'a self) -> StyleVerticalAlignParseError<'a> {
1561 match self {
1562 Self::InvalidValue(e) => StyleVerticalAlignParseError::InvalidValue(e.to_shared()),
1563 }
1564 }
1565}
1566
1567#[cfg(feature = "parser")]
1568pub fn parse_style_vertical_align(
1569 input: &str,
1570) -> Result<StyleVerticalAlign, StyleVerticalAlignParseError> {
1571 match input.trim() {
1572 "baseline" => Ok(StyleVerticalAlign::Baseline),
1573 "top" => Ok(StyleVerticalAlign::Top),
1574 "middle" => Ok(StyleVerticalAlign::Middle),
1575 "bottom" => Ok(StyleVerticalAlign::Bottom),
1576 "sub" => Ok(StyleVerticalAlign::Sub),
1577 "super" => Ok(StyleVerticalAlign::Superscript),
1578 "text-top" => Ok(StyleVerticalAlign::TextTop),
1579 "text-bottom" => Ok(StyleVerticalAlign::TextBottom),
1580 other => Err(StyleVerticalAlignParseError::InvalidValue(InvalidValueErr(
1581 other,
1582 ))),
1583 }
1584}
1585
1586#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1589#[repr(C)]
1590pub struct CaretColor {
1591 pub inner: ColorU,
1592}
1593
1594impl Default for CaretColor {
1595 fn default() -> Self {
1596 Self {
1597 inner: ColorU::BLACK,
1598 }
1599 }
1600}
1601
1602impl PrintAsCssValue for CaretColor {
1603 fn print_as_css_value(&self) -> String {
1604 self.inner.to_hash()
1605 }
1606}
1607
1608impl crate::format_rust_code::FormatAsRustCode for CaretColor {
1609 fn format_as_rust_code(&self, _tabs: usize) -> String {
1610 format!(
1611 "CaretColor {{ inner: {} }}",
1612 crate::format_rust_code::format_color_value(&self.inner)
1613 )
1614 }
1615}
1616
1617#[cfg(feature = "parser")]
1618pub fn parse_caret_color(input: &str) -> Result<CaretColor, CssColorParseError> {
1619 parse_css_color(input).map(|inner| CaretColor { inner })
1620}
1621
1622#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1625#[repr(C)]
1626pub struct CaretAnimationDuration {
1627 pub inner: CssDuration,
1628}
1629
1630impl Default for CaretAnimationDuration {
1631 fn default() -> Self {
1632 Self {
1633 inner: CssDuration { inner: 500 },
1634 } }
1636}
1637
1638impl PrintAsCssValue for CaretAnimationDuration {
1639 fn print_as_css_value(&self) -> String {
1640 self.inner.print_as_css_value()
1641 }
1642}
1643
1644impl crate::format_rust_code::FormatAsRustCode for CaretAnimationDuration {
1645 fn format_as_rust_code(&self, _tabs: usize) -> String {
1646 format!(
1647 "CaretAnimationDuration {{ inner: {} }}",
1648 self.inner.format_as_rust_code(0)
1649 )
1650 }
1651}
1652
1653#[cfg(feature = "parser")]
1654pub fn parse_caret_animation_duration(
1655 input: &str,
1656) -> Result<CaretAnimationDuration, DurationParseError> {
1657 use crate::props::basic::parse_duration;
1658
1659 parse_duration(input).map(|inner| CaretAnimationDuration { inner })
1660}
1661
1662#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1667#[repr(C)]
1668pub struct CaretWidth {
1669 pub inner: PixelValue,
1670}
1671
1672impl Default for CaretWidth {
1673 fn default() -> Self {
1674 Self {
1675 inner: PixelValue::px(2.0), }
1677 }
1678}
1679
1680impl PrintAsCssValue for CaretWidth {
1681 fn print_as_css_value(&self) -> String {
1682 self.inner.print_as_css_value()
1683 }
1684}
1685
1686impl crate::format_rust_code::FormatAsRustCode for CaretWidth {
1687 fn format_as_rust_code(&self, _tabs: usize) -> String {
1688 format!(
1689 "CaretWidth {{ inner: {} }}",
1690 self.inner.format_as_rust_code(0)
1691 )
1692 }
1693}
1694
1695#[cfg(feature = "parser")]
1696pub fn parse_caret_width(input: &str) -> Result<CaretWidth, CssPixelValueParseError> {
1697 use crate::props::basic::pixel::parse_pixel_value;
1698
1699 parse_pixel_value(input).map(|inner| CaretWidth { inner })
1700}
1701
1702impl From<StyleUserSelect> for crate::props::property::CssProperty {
1705 fn from(value: StyleUserSelect) -> Self {
1706 use crate::props::property::CssProperty;
1707 CssProperty::user_select(value)
1708 }
1709}
1710
1711impl From<StyleTextDecoration> for crate::props::property::CssProperty {
1712 fn from(value: StyleTextDecoration) -> Self {
1713 use crate::props::property::CssProperty;
1714 CssProperty::text_decoration(value)
1715 }
1716}
1717
1718#[cfg(all(test, feature = "parser"))]
1719mod tests {
1720 use super::*;
1721 use crate::props::basic::{color::ColorU, length::PercentageValue, pixel::PixelValue};
1722
1723 #[test]
1724 fn test_parse_style_text_color() {
1725 assert_eq!(
1726 parse_style_text_color("red").unwrap().inner,
1727 ColorU::new_rgb(255, 0, 0)
1728 );
1729 assert_eq!(
1730 parse_style_text_color("#aabbcc").unwrap().inner,
1731 ColorU::new_rgb(170, 187, 204)
1732 );
1733 assert!(parse_style_text_color("not-a-color").is_err());
1734 }
1735
1736 #[test]
1737 fn test_parse_style_text_align() {
1738 assert_eq!(
1739 parse_style_text_align("left").unwrap(),
1740 StyleTextAlign::Left
1741 );
1742 assert_eq!(
1743 parse_style_text_align("center").unwrap(),
1744 StyleTextAlign::Center
1745 );
1746 assert_eq!(
1747 parse_style_text_align("right").unwrap(),
1748 StyleTextAlign::Right
1749 );
1750 assert_eq!(
1751 parse_style_text_align("justify").unwrap(),
1752 StyleTextAlign::Justify
1753 );
1754 assert_eq!(
1755 parse_style_text_align("start").unwrap(),
1756 StyleTextAlign::Start
1757 );
1758 assert_eq!(parse_style_text_align("end").unwrap(), StyleTextAlign::End);
1759 assert!(parse_style_text_align("middle").is_err());
1760 }
1761
1762 #[test]
1763 fn test_parse_spacing() {
1764 assert_eq!(
1765 parse_style_letter_spacing("2px").unwrap().inner,
1766 PixelValue::px(2.0)
1767 );
1768 assert_eq!(
1769 parse_style_letter_spacing("-0.1em").unwrap().inner,
1770 PixelValue::em(-0.1)
1771 );
1772 assert_eq!(
1773 parse_style_word_spacing("0.5em").unwrap().inner,
1774 PixelValue::em(0.5)
1775 );
1776 }
1777
1778 #[test]
1779 fn test_parse_line_height() {
1780 assert_eq!(
1781 parse_style_line_height("1.5").unwrap().inner,
1782 PercentageValue::new(150.0)
1783 );
1784 assert_eq!(
1785 parse_style_line_height("120%").unwrap().inner,
1786 PercentageValue::new(120.0)
1787 );
1788 assert!(parse_style_line_height("20px").is_err()); }
1790
1791 #[test]
1792 fn test_parse_tab_size() {
1793 assert_eq!(
1795 parse_style_tab_size("4").unwrap().inner,
1796 PixelValue::em(4.0)
1797 );
1798 assert_eq!(
1799 parse_style_tab_size("20px").unwrap().inner,
1800 PixelValue::px(20.0)
1801 );
1802 }
1803
1804 #[test]
1805 fn test_parse_white_space() {
1806 assert_eq!(
1807 parse_style_white_space("normal").unwrap(),
1808 StyleWhiteSpace::Normal
1809 );
1810 assert_eq!(
1811 parse_style_white_space("pre").unwrap(),
1812 StyleWhiteSpace::Pre
1813 );
1814 assert_eq!(
1815 parse_style_white_space("nowrap").unwrap(),
1816 StyleWhiteSpace::Nowrap
1817 );
1818 assert!(parse_style_white_space("pre-wrap").is_err());
1819 }
1820}