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
use crate as css;
use css::PrintErr;
use css::Printer;
use css::VendorPrefix;
use css::css_properties::CustomPropertyName;
use css::css_properties::{Property, PropertyId, PropertyIdTag};
impl Property {
/// Returns the *raw* enum discriminant of this `Property` as a
/// [`PropertyIdTag`].
///
/// Unlike [`Property::property_id`], this does **not** look through
/// `Property::Unparsed` to the wrapped `UnparsedProperty::property_id` —
/// an `Unparsed` declaration always returns `PropertyIdTag::Unparsed`, and
/// a `Custom` declaration always returns `PropertyIdTag::Custom`.
///
/// This mirrors Zig's `@as(PropertyIdTag, property.*)` (a raw union-tag
/// coercion). Handlers that switch on the discriminant to project a parsed
/// payload — e.g. `SizeHandler` in `margin_padding.rs` — must use this so
/// an unparsed `margin-top: var(--x)` does not route into the parsed
/// `MarginTop` arm and panic in `extract_top`.
#[inline]
pub fn variant_tag(&self) -> PropertyIdTag {
match self {
Property::Unparsed(_) => PropertyIdTag::Unparsed,
Property::Custom(_) => PropertyIdTag::Custom,
// Every other `Property` variant maps 1:1 onto its `PropertyId`
// variant, so `property_id().tag()` is the discriminant.
_ => self.property_id().tag(),
}
}
}
/// Ordered single-bit prefix flags for the `inline for (VendorPrefix.FIELDS)`
/// Zig idiom. The crate-root `VendorPrefix::FIELDS` is a `&[&str]` name list;
/// the to_css loops here need the bitflag values directly, in Zig declaration
/// order (webkit, moz, ms, o, none).
pub(super) const PREFIX_FLAGS: [VendorPrefix; 5] = [
VendorPrefix::WEBKIT,
VendorPrefix::MOZ,
VendorPrefix::MS,
VendorPrefix::O,
VendorPrefix::NONE,
];
pub(super) mod property_id_mixin {
use super::*;
pub(crate) fn to_css(this: &PropertyId, dest: &mut Printer) -> Result<(), PrintErr> {
let name = this.name();
let prefix_value = this.prefix().or_none();
// PORT NOTE: Zig `inline for (VendorPrefix.FIELDS) |field|` + `@field` iterates each
// bitflag field and tests it. `PREFIX_FLAGS` is the same set in the same order;
// `contains` replaces the `@field` test.
dest.write_comma_separated(
PREFIX_FLAGS
.iter()
.copied()
.filter(|p| prefix_value.contains(*p)),
|d, p| {
p.to_css(d)?;
d.write_str(name)
},
)
}
pub(crate) fn parse(input: &mut css::Parser) -> css::Result<PropertyId> {
// PORT NOTE: `css::Result<T>` is assumed to alias `Result<T, css::ParserError>`;
// the Zig `.result`/`.err` switch collapses to `?`.
let name = input.expect_ident()?;
Ok(from_string(name))
}
pub(crate) fn from_string(name_: &[u8]) -> PropertyId {
let (prefix, trimmed_name) = VendorPrefix::strip_from(name_);
PropertyId::from_name_and_prefix(trimmed_name, prefix)
.unwrap_or_else(|| PropertyId::Custom(CustomPropertyName::from_str(name_)))
}
}
pub(super) mod property_mixin {
use super::*;
/// Serializes the CSS property, with an optional `!important` flag.
pub(crate) fn to_css(
this: &Property,
dest: &mut Printer,
important: bool,
) -> Result<(), PrintErr> {
if let Property::Custom(custom) = this {
custom.name.to_css(dest)?;
dest.delim(b':', false)?;
this.value_to_css(dest)?;
if important {
dest.whitespace()?;
dest.write_str(b"!important")?;
}
return Ok(());
}
let (name, prefix) = this.__to_css_helper();
// PORT NOTE: see property_id_mixin::to_css for the `inline for` + `@field` mapping.
dest.write_separated(
PREFIX_FLAGS.iter().copied().filter(|p| prefix.contains(*p)),
|d| {
d.write_char(b';')?;
d.newline()
},
|d, p| {
p.to_css(d)?;
d.write_str(name)?;
d.delim(b':', false)?;
this.value_to_css(d)?;
if important {
d.whitespace()?;
d.write_str(b"!important")?;
}
Ok(())
},
)
}
}
// ported from: src/css/properties/properties_impl.zig