1use alloc::string::{String, ToString};
4
5use crate::props::formatter::PrintAsCssValue;
6
7#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[repr(C)]
10pub enum LayoutDisplay {
11 None,
13 #[default]
14 Block,
15 Inline,
16 InlineBlock,
17
18 Flex,
20 InlineFlex,
21
22 Table,
24 InlineTable,
25 TableRowGroup,
26 TableHeaderGroup,
27 TableFooterGroup,
28 TableRow,
29 TableColumnGroup,
30 TableColumn,
31 TableCell,
32 TableCaption,
33
34 FlowRoot,
35
36 ListItem,
38
39 RunIn,
41 Marker,
42
43 Grid,
45 InlineGrid,
46}
47
48impl LayoutDisplay {
49 pub fn creates_block_context(&self) -> bool {
50 matches!(
51 self,
52 LayoutDisplay::Block
53 | LayoutDisplay::Flex
54 | LayoutDisplay::Grid
55 | LayoutDisplay::Table
56 | LayoutDisplay::ListItem
57 )
58 }
59
60 pub fn creates_flex_context(&self) -> bool {
61 matches!(self, LayoutDisplay::Flex | LayoutDisplay::InlineFlex)
62 }
63
64 pub fn creates_table_context(&self) -> bool {
65 matches!(self, LayoutDisplay::Table | LayoutDisplay::InlineTable)
66 }
67
68 pub fn is_inline_level(&self) -> bool {
69 matches!(
70 self,
71 LayoutDisplay::Inline
72 | LayoutDisplay::InlineBlock
73 | LayoutDisplay::InlineFlex
74 | LayoutDisplay::InlineTable
75 | LayoutDisplay::InlineGrid
76 )
77 }
78}
79
80impl PrintAsCssValue for LayoutDisplay {
81 fn print_as_css_value(&self) -> String {
82 String::from(match self {
83 LayoutDisplay::None => "none",
84 LayoutDisplay::Block => "block",
85 LayoutDisplay::Inline => "inline",
86 LayoutDisplay::InlineBlock => "inline-block",
87 LayoutDisplay::Flex => "flex",
88 LayoutDisplay::InlineFlex => "inline-flex",
89 LayoutDisplay::Table => "table",
90 LayoutDisplay::InlineTable => "inline-table",
91 LayoutDisplay::TableRowGroup => "table-row-group",
92 LayoutDisplay::TableHeaderGroup => "table-header-group",
93 LayoutDisplay::TableFooterGroup => "table-footer-group",
94 LayoutDisplay::TableRow => "table-row",
95 LayoutDisplay::TableColumnGroup => "table-column-group",
96 LayoutDisplay::TableColumn => "table-column",
97 LayoutDisplay::TableCell => "table-cell",
98 LayoutDisplay::TableCaption => "table-caption",
99 LayoutDisplay::ListItem => "list-item",
100 LayoutDisplay::RunIn => "run-in",
101 LayoutDisplay::Marker => "marker",
102 LayoutDisplay::FlowRoot => "flow-root",
103 LayoutDisplay::Grid => "grid",
104 LayoutDisplay::InlineGrid => "inline-grid",
105 })
106 }
107}
108
109#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
111#[repr(C)]
112pub enum LayoutFloat {
113 Left,
114 Right,
115 None,
116}
117
118impl Default for LayoutFloat {
119 fn default() -> Self {
120 LayoutFloat::None
121 }
122}
123
124impl PrintAsCssValue for LayoutFloat {
125 fn print_as_css_value(&self) -> String {
126 String::from(match self {
127 LayoutFloat::Left => "left",
128 LayoutFloat::Right => "right",
129 LayoutFloat::None => "none",
130 })
131 }
132}
133
134#[cfg(feature = "parser")]
137#[derive(Clone, PartialEq)]
138pub enum LayoutDisplayParseError<'a> {
139 InvalidValue(&'a str),
140}
141
142#[cfg(feature = "parser")]
143impl_debug_as_display!(LayoutDisplayParseError<'a>);
144
145#[cfg(feature = "parser")]
146impl_display! { LayoutDisplayParseError<'a>, {
147 InvalidValue(val) => format!("Invalid display value: \"{}\"", val),
148}}
149
150#[cfg(feature = "parser")]
151#[derive(Debug, Clone, PartialEq)]
152pub enum LayoutDisplayParseErrorOwned {
153 InvalidValue(String),
154}
155
156#[cfg(feature = "parser")]
157impl<'a> LayoutDisplayParseError<'a> {
158 pub fn to_contained(&self) -> LayoutDisplayParseErrorOwned {
159 match self {
160 Self::InvalidValue(s) => LayoutDisplayParseErrorOwned::InvalidValue(s.to_string()),
161 }
162 }
163}
164
165#[cfg(feature = "parser")]
166impl LayoutDisplayParseErrorOwned {
167 pub fn to_shared<'a>(&'a self) -> LayoutDisplayParseError<'a> {
168 match self {
169 Self::InvalidValue(s) => LayoutDisplayParseError::InvalidValue(s.as_str()),
170 }
171 }
172}
173
174#[cfg(feature = "parser")]
175pub fn parse_layout_display<'a>(
176 input: &'a str,
177) -> Result<LayoutDisplay, LayoutDisplayParseError<'a>> {
178 let input = input.trim();
179 match input {
180 "none" => Ok(LayoutDisplay::None),
181 "block" => Ok(LayoutDisplay::Block),
182 "inline" => Ok(LayoutDisplay::Inline),
183 "inline-block" => Ok(LayoutDisplay::InlineBlock),
184 "flex" => Ok(LayoutDisplay::Flex),
185 "inline-flex" => Ok(LayoutDisplay::InlineFlex),
186 "table" => Ok(LayoutDisplay::Table),
187 "inline-table" => Ok(LayoutDisplay::InlineTable),
188 "table-row-group" => Ok(LayoutDisplay::TableRowGroup),
189 "table-header-group" => Ok(LayoutDisplay::TableHeaderGroup),
190 "table-footer-group" => Ok(LayoutDisplay::TableFooterGroup),
191 "table-row" => Ok(LayoutDisplay::TableRow),
192 "table-column-group" => Ok(LayoutDisplay::TableColumnGroup),
193 "table-column" => Ok(LayoutDisplay::TableColumn),
194 "table-cell" => Ok(LayoutDisplay::TableCell),
195 "table-caption" => Ok(LayoutDisplay::TableCaption),
196 "list-item" => Ok(LayoutDisplay::ListItem),
197 "run-in" => Ok(LayoutDisplay::RunIn),
198 "marker" => Ok(LayoutDisplay::Marker),
199 "grid" => Ok(LayoutDisplay::Grid),
200 "inline-grid" => Ok(LayoutDisplay::InlineGrid),
201 "flow-root" => Ok(LayoutDisplay::FlowRoot),
202 _ => Err(LayoutDisplayParseError::InvalidValue(input)),
203 }
204}
205
206#[cfg(feature = "parser")]
207#[derive(Clone, PartialEq)]
208pub enum LayoutFloatParseError<'a> {
209 InvalidValue(&'a str),
210}
211
212#[cfg(feature = "parser")]
213impl_debug_as_display!(LayoutFloatParseError<'a>);
214
215#[cfg(feature = "parser")]
216impl_display! { LayoutFloatParseError<'a>, {
217 InvalidValue(val) => format!("Invalid float value: \"{}\"", val),
218}}
219
220#[cfg(feature = "parser")]
221#[derive(Debug, Clone, PartialEq)]
222pub enum LayoutFloatParseErrorOwned {
223 InvalidValue(String),
224}
225
226#[cfg(feature = "parser")]
227impl<'a> LayoutFloatParseError<'a> {
228 pub fn to_contained(&self) -> LayoutFloatParseErrorOwned {
229 match self {
230 Self::InvalidValue(s) => LayoutFloatParseErrorOwned::InvalidValue(s.to_string()),
231 }
232 }
233}
234
235#[cfg(feature = "parser")]
236impl LayoutFloatParseErrorOwned {
237 pub fn to_shared<'a>(&'a self) -> LayoutFloatParseError<'a> {
238 match self {
239 Self::InvalidValue(s) => LayoutFloatParseError::InvalidValue(s.as_str()),
240 }
241 }
242}
243
244#[cfg(feature = "parser")]
245pub fn parse_layout_float<'a>(input: &'a str) -> Result<LayoutFloat, LayoutFloatParseError<'a>> {
246 let input = input.trim();
247 match input {
248 "left" => Ok(LayoutFloat::Left),
249 "right" => Ok(LayoutFloat::Right),
250 "none" => Ok(LayoutFloat::None),
251 _ => Err(LayoutFloatParseError::InvalidValue(input)),
252 }
253}
254
255#[cfg(all(test, feature = "parser"))]
256mod tests {
257 use super::*;
258
259 #[test]
260 fn test_parse_layout_display() {
261 assert_eq!(parse_layout_display("block").unwrap(), LayoutDisplay::Block);
262 assert_eq!(
263 parse_layout_display("inline").unwrap(),
264 LayoutDisplay::Inline
265 );
266 assert_eq!(
267 parse_layout_display("inline-block").unwrap(),
268 LayoutDisplay::InlineBlock
269 );
270 assert_eq!(parse_layout_display("flex").unwrap(), LayoutDisplay::Flex);
271 assert_eq!(
272 parse_layout_display("inline-flex").unwrap(),
273 LayoutDisplay::InlineFlex
274 );
275 assert_eq!(parse_layout_display("grid").unwrap(), LayoutDisplay::Grid);
276 assert_eq!(
277 parse_layout_display("inline-grid").unwrap(),
278 LayoutDisplay::InlineGrid
279 );
280 assert_eq!(parse_layout_display("none").unwrap(), LayoutDisplay::None);
281 assert_eq!(
282 parse_layout_display("flow-root").unwrap(),
283 LayoutDisplay::FlowRoot
284 );
285 assert_eq!(
286 parse_layout_display("list-item").unwrap(),
287 LayoutDisplay::ListItem
288 );
289 assert!(parse_layout_display("inherit").is_err());
292 assert!(parse_layout_display("initial").is_err());
293
294 assert_eq!(parse_layout_display("table").unwrap(), LayoutDisplay::Table);
296 assert_eq!(
297 parse_layout_display("inline-table").unwrap(),
298 LayoutDisplay::InlineTable
299 );
300 assert_eq!(
301 parse_layout_display("table-row").unwrap(),
302 LayoutDisplay::TableRow
303 );
304 assert_eq!(
305 parse_layout_display("table-cell").unwrap(),
306 LayoutDisplay::TableCell
307 );
308 assert_eq!(
309 parse_layout_display("table-caption").unwrap(),
310 LayoutDisplay::TableCaption
311 );
312 assert_eq!(
313 parse_layout_display("table-column-group").unwrap(),
314 LayoutDisplay::TableColumnGroup
315 );
316 assert_eq!(
317 parse_layout_display("table-header-group").unwrap(),
318 LayoutDisplay::TableHeaderGroup
319 );
320 assert_eq!(
321 parse_layout_display("table-footer-group").unwrap(),
322 LayoutDisplay::TableFooterGroup
323 );
324 assert_eq!(
325 parse_layout_display("table-row-group").unwrap(),
326 LayoutDisplay::TableRowGroup
327 );
328
329 assert_eq!(
331 parse_layout_display(" inline-flex ").unwrap(),
332 LayoutDisplay::InlineFlex
333 );
334
335 assert!(parse_layout_display("invalid-value").is_err());
337 assert!(parse_layout_display("").is_err());
338 assert!(parse_layout_display("display").is_err());
339 }
340
341 #[test]
342 fn test_parse_layout_float() {
343 assert_eq!(parse_layout_float("left").unwrap(), LayoutFloat::Left);
344 assert_eq!(parse_layout_float("right").unwrap(), LayoutFloat::Right);
345 assert_eq!(parse_layout_float("none").unwrap(), LayoutFloat::None);
346
347 assert_eq!(parse_layout_float(" right ").unwrap(), LayoutFloat::Right);
349
350 assert!(parse_layout_float("center").is_err());
352 assert!(parse_layout_float("").is_err());
353 assert!(parse_layout_float("float-left").is_err());
354 }
355}