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