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