//! Vendor prefixes. #![allow(non_upper_case_globals)] use crate::error::PrinterError; use crate::printer::Printer; use crate::traits::ToCss; #[cfg(feature = "visitor")] use crate::visitor::{Visit, VisitTypes, Visitor}; use bitflags::bitflags; bitflags! { /// Bit flags that represent one or more vendor prefixes, such as /// `-webkit` or `-moz`. /// /// Multiple flags can be combined to represent /// more than one prefix. During printing, the rule or property will /// be duplicated for each prefix flag that is enabled. This enables /// vendor prefixes to be added without increasing memory usage. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub struct VendorPrefix: u8 { /// The `-webkit` vendor prefix. const WebKit = 0b00000010; /// The `-moz` vendor prefix. const Moz = 0b00000100; /// The `-ms` vendor prefix. const Ms = 0b00001000; /// The `-o` vendor prefix. const O = 0b00010000; /// No vendor prefixes. const None = 0b00000001; } } impl Default for VendorPrefix { fn default() -> VendorPrefix { VendorPrefix::None } } impl VendorPrefix { /// Returns a vendor prefix flag from a prefix string (without the leading `-`). pub fn from_str(s: &str) -> VendorPrefix { match s { "webkit" => VendorPrefix::WebKit, "moz" => VendorPrefix::Moz, "ms" => VendorPrefix::Ms, "o" => VendorPrefix::O, _ => unreachable!(), } } /// Returns VendorPrefix::None if empty. #[inline] pub fn or_none(self) -> Self { self.or(VendorPrefix::None) } /// Returns `other` if `self` is empty #[inline] pub fn or(self, other: Self) -> Self { if self.is_empty() { other } else { self } } } impl ToCss for VendorPrefix { fn to_css(&self, dest: &mut Printer) -> Result<(), PrinterError> where W: std::fmt::Write, { cssparser::ToCss::to_css(self, dest)?; Ok(()) } } impl cssparser::ToCss for VendorPrefix { fn to_css(&self, dest: &mut W) -> std::fmt::Result where W: std::fmt::Write, { match *self { VendorPrefix::WebKit => dest.write_str("-webkit-"), VendorPrefix::Moz => dest.write_str("-moz-"), VendorPrefix::Ms => dest.write_str("-ms-"), VendorPrefix::O => dest.write_str("-o-"), _ => Ok(()), } } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for VendorPrefix { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let mut values = Vec::new(); if *self != VendorPrefix::None { if self.contains(VendorPrefix::None) { values.push("none"); } if self.contains(VendorPrefix::WebKit) { values.push("webkit"); } if self.contains(VendorPrefix::Moz) { values.push("moz"); } if self.contains(VendorPrefix::Ms) { values.push("ms"); } if self.contains(VendorPrefix::O) { values.push("o"); } } values.serialize(serializer) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> serde::Deserialize<'de> for VendorPrefix { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { use crate::values::string::CowArcStr; let values = Vec::>::deserialize(deserializer)?; if values.is_empty() { return Ok(VendorPrefix::None); } let mut res = VendorPrefix::empty(); for value in values { res |= match value.as_ref() { "none" => VendorPrefix::None, "webkit" => VendorPrefix::WebKit, "moz" => VendorPrefix::Moz, "ms" => VendorPrefix::Ms, "o" => VendorPrefix::O, _ => continue, }; } Ok(res) } } #[cfg(feature = "visitor")] #[cfg_attr(docsrs, doc(cfg(feature = "visitor")))] impl<'i, V: ?Sized + Visitor<'i, T>, T: Visit<'i, T, V>> Visit<'i, T, V> for VendorPrefix { const CHILD_TYPES: VisitTypes = VisitTypes::empty(); fn visit_children(&mut self, _: &mut V) -> Result<(), V::Error> { Ok(()) } } #[cfg(feature = "jsonschema")] #[cfg_attr(docsrs, doc(cfg(feature = "jsonschema")))] impl schemars::JsonSchema for VendorPrefix { fn is_referenceable() -> bool { true } fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { #[derive(schemars::JsonSchema)] #[schemars(rename_all = "lowercase")] #[allow(dead_code)] enum Prefix { None, WebKit, Moz, Ms, O, } Vec::::json_schema(gen) } fn schema_name() -> String { "VendorPrefix".into() } }