lightningcss/values/
rect.rs

1//! Generic values for four sided properties.
2
3use crate::error::{ParserError, PrinterError};
4use crate::printer::Printer;
5use crate::traits::{IsCompatible, Parse, ToCss};
6#[cfg(feature = "visitor")]
7use crate::visitor::Visit;
8use cssparser::*;
9
10/// A generic value that represents a value for four sides of a box,
11/// e.g. border-width, margin, padding, etc.
12///
13/// When serialized, as few components as possible are written when
14/// there are duplicate values.
15#[derive(Clone, Debug, PartialEq, Eq)]
16#[cfg_attr(feature = "visitor", derive(Visit))]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
19#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
20pub struct Rect<T>(
21  /// The top component.
22  pub T,
23  /// The right component.
24  pub T,
25  /// The bottom component.
26  pub T,
27  /// The left component.
28  pub T,
29);
30
31impl<T> Rect<T> {
32  /// Returns a new `Rect<T>` value.
33  pub fn new(first: T, second: T, third: T, fourth: T) -> Self {
34    Rect(first, second, third, fourth)
35  }
36}
37
38impl<T: Default + Clone> Default for Rect<T> {
39  fn default() -> Rect<T> {
40    Rect::all(T::default())
41  }
42}
43
44impl<T> Rect<T>
45where
46  T: Clone,
47{
48  /// Returns a rect with all the values equal to `v`.
49  pub fn all(v: T) -> Self {
50    Rect::new(v.clone(), v.clone(), v.clone(), v)
51  }
52
53  /// Parses a new `Rect<T>` value with the given parse function.
54  pub fn parse_with<'i, 't, Parse>(
55    input: &mut Parser<'i, 't>,
56    parse: Parse,
57  ) -> Result<Self, ParseError<'i, ParserError<'i>>>
58  where
59    Parse: Fn(&mut Parser<'i, 't>) -> Result<T, ParseError<'i, ParserError<'i>>>,
60  {
61    let first = parse(input)?;
62    let second = if let Ok(second) = input.try_parse(|i| parse(i)) {
63      second
64    } else {
65      // <first>
66      return Ok(Self::new(first.clone(), first.clone(), first.clone(), first));
67    };
68    let third = if let Ok(third) = input.try_parse(|i| parse(i)) {
69      third
70    } else {
71      // <first> <second>
72      return Ok(Self::new(first.clone(), second.clone(), first, second));
73    };
74    let fourth = if let Ok(fourth) = input.try_parse(|i| parse(i)) {
75      fourth
76    } else {
77      // <first> <second> <third>
78      return Ok(Self::new(first, second.clone(), third, second));
79    };
80    // <first> <second> <third> <fourth>
81    Ok(Self::new(first, second, third, fourth))
82  }
83}
84
85impl<'i, T> Parse<'i> for Rect<T>
86where
87  T: Clone + PartialEq + Parse<'i>,
88{
89  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
90    Self::parse_with(input, T::parse)
91  }
92}
93
94impl<T> ToCss for Rect<T>
95where
96  T: PartialEq + ToCss,
97{
98  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
99  where
100    W: std::fmt::Write,
101  {
102    self.0.to_css(dest)?;
103    let same_vertical = self.0 == self.2;
104    let same_horizontal = self.1 == self.3;
105    if same_vertical && same_horizontal && self.0 == self.1 {
106      return Ok(());
107    }
108    dest.write_str(" ")?;
109    self.1.to_css(dest)?;
110    if same_vertical && same_horizontal {
111      return Ok(());
112    }
113    dest.write_str(" ")?;
114    self.2.to_css(dest)?;
115    if same_horizontal {
116      return Ok(());
117    }
118    dest.write_str(" ")?;
119    self.3.to_css(dest)
120  }
121}
122
123impl<T: IsCompatible> IsCompatible for Rect<T> {
124  fn is_compatible(&self, browsers: crate::targets::Browsers) -> bool {
125    self.0.is_compatible(browsers)
126      && self.1.is_compatible(browsers)
127      && self.2.is_compatible(browsers)
128      && self.3.is_compatible(browsers)
129  }
130}