lightningcss/values/
rect.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Generic values for four sided properties.

use crate::error::{ParserError, PrinterError};
use crate::printer::Printer;
use crate::traits::{IsCompatible, Parse, ToCss};
#[cfg(feature = "visitor")]
use crate::visitor::Visit;
use cssparser::*;

/// A generic value that represents a value for four sides of a box,
/// e.g. border-width, margin, padding, etc.
///
/// When serialized, as few components as possible are written when
/// there are duplicate values.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "visitor", derive(Visit))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
pub struct Rect<T>(
  /// The top component.
  pub T,
  /// The right component.
  pub T,
  /// The bottom component.
  pub T,
  /// The left component.
  pub T,
);

impl<T> Rect<T> {
  /// Returns a new `Rect<T>` value.
  pub fn new(first: T, second: T, third: T, fourth: T) -> Self {
    Rect(first, second, third, fourth)
  }
}

impl<T: Default + Clone> Default for Rect<T> {
  fn default() -> Rect<T> {
    Rect::all(T::default())
  }
}

impl<T> Rect<T>
where
  T: Clone,
{
  /// Returns a rect with all the values equal to `v`.
  pub fn all(v: T) -> Self {
    Rect::new(v.clone(), v.clone(), v.clone(), v)
  }

  /// Parses a new `Rect<T>` value with the given parse function.
  pub fn parse_with<'i, 't, Parse>(
    input: &mut Parser<'i, 't>,
    parse: Parse,
  ) -> Result<Self, ParseError<'i, ParserError<'i>>>
  where
    Parse: Fn(&mut Parser<'i, 't>) -> Result<T, ParseError<'i, ParserError<'i>>>,
  {
    let first = parse(input)?;
    let second = if let Ok(second) = input.try_parse(|i| parse(i)) {
      second
    } else {
      // <first>
      return Ok(Self::new(first.clone(), first.clone(), first.clone(), first));
    };
    let third = if let Ok(third) = input.try_parse(|i| parse(i)) {
      third
    } else {
      // <first> <second>
      return Ok(Self::new(first.clone(), second.clone(), first, second));
    };
    let fourth = if let Ok(fourth) = input.try_parse(|i| parse(i)) {
      fourth
    } else {
      // <first> <second> <third>
      return Ok(Self::new(first, second.clone(), third, second));
    };
    // <first> <second> <third> <fourth>
    Ok(Self::new(first, second, third, fourth))
  }
}

impl<'i, T> Parse<'i> for Rect<T>
where
  T: Clone + PartialEq + Parse<'i>,
{
  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
    Self::parse_with(input, T::parse)
  }
}

impl<T> ToCss for Rect<T>
where
  T: PartialEq + ToCss,
{
  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
  where
    W: std::fmt::Write,
  {
    self.0.to_css(dest)?;
    let same_vertical = self.0 == self.2;
    let same_horizontal = self.1 == self.3;
    if same_vertical && same_horizontal && self.0 == self.1 {
      return Ok(());
    }
    dest.write_str(" ")?;
    self.1.to_css(dest)?;
    if same_vertical && same_horizontal {
      return Ok(());
    }
    dest.write_str(" ")?;
    self.2.to_css(dest)?;
    if same_horizontal {
      return Ok(());
    }
    dest.write_str(" ")?;
    self.3.to_css(dest)
  }
}

impl<T: IsCompatible> IsCompatible for Rect<T> {
  fn is_compatible(&self, browsers: crate::targets::Browsers) -> bool {
    self.0.is_compatible(browsers)
      && self.1.is_compatible(browsers)
      && self.2.is_compatible(browsers)
      && self.3.is_compatible(browsers)
  }
}