lightningcss/
vendor_prefix.rs

1//! Vendor prefixes.
2
3#![allow(non_upper_case_globals)]
4
5use crate::error::PrinterError;
6use crate::printer::Printer;
7use crate::traits::ToCss;
8#[cfg(feature = "visitor")]
9use crate::visitor::{Visit, VisitTypes, Visitor};
10use bitflags::bitflags;
11
12bitflags! {
13  /// Bit flags that represent one or more vendor prefixes, such as
14  /// `-webkit` or `-moz`.
15  ///
16  /// Multiple flags can be combined to represent
17  /// more than one prefix. During printing, the rule or property will
18  /// be duplicated for each prefix flag that is enabled. This enables
19  /// vendor prefixes to be added without increasing memory usage.
20  #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
21  #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
22  pub struct VendorPrefix: u8 {
23    /// The `-webkit` vendor prefix.
24    const WebKit = 0b00000010;
25    /// The `-moz` vendor prefix.
26    const Moz    = 0b00000100;
27    /// The `-ms` vendor prefix.
28    const Ms     = 0b00001000;
29    /// The `-o` vendor prefix.
30    const O      = 0b00010000;
31    /// No vendor prefixes.
32    const None   = 0b00000001;
33  }
34}
35
36impl Default for VendorPrefix {
37  fn default() -> VendorPrefix {
38    VendorPrefix::None
39  }
40}
41
42impl VendorPrefix {
43  /// Returns a vendor prefix flag from a prefix string (without the leading `-`).
44  pub fn from_str(s: &str) -> VendorPrefix {
45    match s {
46      "webkit" => VendorPrefix::WebKit,
47      "moz" => VendorPrefix::Moz,
48      "ms" => VendorPrefix::Ms,
49      "o" => VendorPrefix::O,
50      _ => unreachable!(),
51    }
52  }
53
54  /// Returns VendorPrefix::None if empty.
55  #[inline]
56  pub fn or_none(self) -> Self {
57    self.or(VendorPrefix::None)
58  }
59
60  /// Returns `other` if `self` is empty
61  #[inline]
62  pub fn or(self, other: Self) -> Self {
63    if self.is_empty() {
64      other
65    } else {
66      self
67    }
68  }
69}
70
71impl ToCss for VendorPrefix {
72  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
73  where
74    W: std::fmt::Write,
75  {
76    cssparser::ToCss::to_css(self, dest)?;
77    Ok(())
78  }
79}
80
81impl cssparser::ToCss for VendorPrefix {
82  fn to_css<W>(&self, dest: &mut W) -> std::fmt::Result
83  where
84    W: std::fmt::Write,
85  {
86    match *self {
87      VendorPrefix::WebKit => dest.write_str("-webkit-"),
88      VendorPrefix::Moz => dest.write_str("-moz-"),
89      VendorPrefix::Ms => dest.write_str("-ms-"),
90      VendorPrefix::O => dest.write_str("-o-"),
91      _ => Ok(()),
92    }
93  }
94}
95
96#[cfg(feature = "serde")]
97#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
98impl serde::Serialize for VendorPrefix {
99  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
100  where
101    S: serde::Serializer,
102  {
103    let mut values = Vec::new();
104    if *self != VendorPrefix::None {
105      if self.contains(VendorPrefix::None) {
106        values.push("none");
107      }
108      if self.contains(VendorPrefix::WebKit) {
109        values.push("webkit");
110      }
111      if self.contains(VendorPrefix::Moz) {
112        values.push("moz");
113      }
114      if self.contains(VendorPrefix::Ms) {
115        values.push("ms");
116      }
117      if self.contains(VendorPrefix::O) {
118        values.push("o");
119      }
120    }
121    values.serialize(serializer)
122  }
123}
124
125#[cfg(feature = "serde")]
126#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
127impl<'de> serde::Deserialize<'de> for VendorPrefix {
128  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
129  where
130    D: serde::Deserializer<'de>,
131  {
132    use crate::values::string::CowArcStr;
133    let values = Vec::<CowArcStr<'de>>::deserialize(deserializer)?;
134    if values.is_empty() {
135      return Ok(VendorPrefix::None);
136    }
137    let mut res = VendorPrefix::empty();
138    for value in values {
139      res |= match value.as_ref() {
140        "none" => VendorPrefix::None,
141        "webkit" => VendorPrefix::WebKit,
142        "moz" => VendorPrefix::Moz,
143        "ms" => VendorPrefix::Ms,
144        "o" => VendorPrefix::O,
145        _ => continue,
146      };
147    }
148    Ok(res)
149  }
150}
151
152#[cfg(feature = "visitor")]
153#[cfg_attr(docsrs, doc(cfg(feature = "visitor")))]
154impl<'i, V: ?Sized + Visitor<'i, T>, T: Visit<'i, T, V>> Visit<'i, T, V> for VendorPrefix {
155  const CHILD_TYPES: VisitTypes = VisitTypes::empty();
156  fn visit_children(&mut self, _: &mut V) -> Result<(), V::Error> {
157    Ok(())
158  }
159}
160
161#[cfg(feature = "jsonschema")]
162#[cfg_attr(docsrs, doc(cfg(feature = "jsonschema")))]
163impl schemars::JsonSchema for VendorPrefix {
164  fn is_referenceable() -> bool {
165    true
166  }
167
168  fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
169    #[derive(schemars::JsonSchema)]
170    #[schemars(rename_all = "lowercase")]
171    #[allow(dead_code)]
172    enum Prefix {
173      None,
174      WebKit,
175      Moz,
176      Ms,
177      O,
178    }
179
180    Vec::<Prefix>::json_schema(gen)
181  }
182
183  fn schema_name() -> String {
184    "VendorPrefix".into()
185  }
186}