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 pub fn creates_block_context(&self) -> bool {
64 matches!(
65 self,
66 LayoutDisplay::Block
67 | LayoutDisplay::FlowRoot
68 | LayoutDisplay::Flex
69 | LayoutDisplay::Grid
70 | LayoutDisplay::Table
71 | LayoutDisplay::ListItem
72 )
73 }
74
75 pub fn creates_flex_context(&self) -> bool {
77 matches!(self, LayoutDisplay::Flex | LayoutDisplay::InlineFlex)
78 }
79
80 pub fn creates_table_context(&self) -> bool {
83 matches!(self, LayoutDisplay::Table | LayoutDisplay::InlineTable)
84 }
85
86 pub fn is_layout_internal(&self) -> bool {
90 matches!(
91 self,
92 LayoutDisplay::TableRowGroup
93 | LayoutDisplay::TableHeaderGroup
94 | LayoutDisplay::TableFooterGroup
95 | LayoutDisplay::TableRow
96 | LayoutDisplay::TableColumnGroup
97 | LayoutDisplay::TableColumn
98 | LayoutDisplay::TableCell
99 | LayoutDisplay::TableCaption
100 )
101 }
102
103 pub fn is_inline_level(&self) -> bool {
108 matches!(
109 self,
110 LayoutDisplay::Inline
111 | LayoutDisplay::InlineBlock
112 | LayoutDisplay::InlineFlex
113 | LayoutDisplay::InlineTable
114 | LayoutDisplay::InlineGrid
115 )
116 }
117}
118
119impl PrintAsCssValue for LayoutDisplay {
121 fn print_as_css_value(&self) -> String {
122 String::from(match self {
123 LayoutDisplay::None => "none",
124 LayoutDisplay::Block => "block",
125 LayoutDisplay::Inline => "inline",
126 LayoutDisplay::InlineBlock => "inline-block",
127 LayoutDisplay::Flex => "flex",
128 LayoutDisplay::InlineFlex => "inline-flex",
129 LayoutDisplay::Table => "table",
130 LayoutDisplay::InlineTable => "inline-table",
131 LayoutDisplay::TableRowGroup => "table-row-group",
132 LayoutDisplay::TableHeaderGroup => "table-header-group",
133 LayoutDisplay::TableFooterGroup => "table-footer-group",
134 LayoutDisplay::TableRow => "table-row",
135 LayoutDisplay::TableColumnGroup => "table-column-group",
136 LayoutDisplay::TableColumn => "table-column",
137 LayoutDisplay::TableCell => "table-cell",
138 LayoutDisplay::TableCaption => "table-caption",
139 LayoutDisplay::ListItem => "list-item",
140 LayoutDisplay::RunIn => "run-in",
141 LayoutDisplay::Marker => "marker",
142 LayoutDisplay::FlowRoot => "flow-root",
143 LayoutDisplay::Grid => "grid",
144 LayoutDisplay::InlineGrid => "inline-grid",
145 LayoutDisplay::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 LayoutFloat::Left => "left",
164 LayoutFloat::Right => "right",
165 LayoutFloat::None => "none",
166 })
167 }
168}
169
170#[cfg(feature = "parser")]
173#[derive(Clone, PartialEq)]
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)]
188#[repr(C, u8)]
189pub enum LayoutDisplayParseErrorOwned {
190 InvalidValue(AzString),
191}
192
193#[cfg(feature = "parser")]
194impl<'a> LayoutDisplayParseError<'a> {
195 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 pub fn to_shared<'a>(&'a self) -> LayoutDisplayParseError<'a> {
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<'a>(
213 input: &'a str,
214) -> Result<LayoutDisplay, LayoutDisplayParseError<'a>> {
215 let input = input.trim();
216 match input {
217 "none" => Ok(LayoutDisplay::None),
218 "block" => Ok(LayoutDisplay::Block),
219 "inline" => Ok(LayoutDisplay::Inline),
220 "inline-block" => Ok(LayoutDisplay::InlineBlock),
222 "flex" => Ok(LayoutDisplay::Flex),
223 "inline-flex" => Ok(LayoutDisplay::InlineFlex),
224 "table" => Ok(LayoutDisplay::Table),
225 "inline-table" => Ok(LayoutDisplay::InlineTable),
226 "table-row-group" => Ok(LayoutDisplay::TableRowGroup),
227 "table-header-group" => Ok(LayoutDisplay::TableHeaderGroup),
228 "table-footer-group" => Ok(LayoutDisplay::TableFooterGroup),
229 "table-row" => Ok(LayoutDisplay::TableRow),
230 "table-column-group" => Ok(LayoutDisplay::TableColumnGroup),
231 "table-column" => Ok(LayoutDisplay::TableColumn),
232 "table-cell" => Ok(LayoutDisplay::TableCell),
233 "table-caption" => Ok(LayoutDisplay::TableCaption),
234 "list-item" => Ok(LayoutDisplay::ListItem),
235 "run-in" => Ok(LayoutDisplay::RunIn),
236 "marker" => Ok(LayoutDisplay::Marker),
237 "grid" => Ok(LayoutDisplay::Grid),
238 "inline-grid" => Ok(LayoutDisplay::InlineGrid),
239 "flow-root" => Ok(LayoutDisplay::FlowRoot),
240 "contents" => Ok(LayoutDisplay::Contents),
241 _ => Err(LayoutDisplayParseError::InvalidValue(input)),
242 }
243}
244
245#[cfg(feature = "parser")]
246#[derive(Clone, PartialEq)]
247pub enum LayoutFloatParseError<'a> {
248 InvalidValue(&'a str),
249}
250
251#[cfg(feature = "parser")]
252impl_debug_as_display!(LayoutFloatParseError<'a>);
253
254#[cfg(feature = "parser")]
255impl_display! { LayoutFloatParseError<'a>, {
256 InvalidValue(val) => format!("Invalid float value: \"{}\"", val),
257}}
258
259#[cfg(feature = "parser")]
260#[derive(Debug, Clone, PartialEq)]
261#[repr(C, u8)]
262pub enum LayoutFloatParseErrorOwned {
263 InvalidValue(AzString),
264}
265
266#[cfg(feature = "parser")]
267impl<'a> LayoutFloatParseError<'a> {
268 pub fn to_contained(&self) -> LayoutFloatParseErrorOwned {
269 match self {
270 Self::InvalidValue(s) => LayoutFloatParseErrorOwned::InvalidValue(s.to_string().into()),
271 }
272 }
273}
274
275#[cfg(feature = "parser")]
276impl LayoutFloatParseErrorOwned {
277 pub fn to_shared<'a>(&'a self) -> LayoutFloatParseError<'a> {
278 match self {
279 Self::InvalidValue(s) => LayoutFloatParseError::InvalidValue(s.as_str()),
280 }
281 }
282}
283
284#[cfg(feature = "parser")]
285pub fn parse_layout_float<'a>(input: &'a str) -> Result<LayoutFloat, LayoutFloatParseError<'a>> {
286 let input = input.trim();
287 match input {
288 "left" => Ok(LayoutFloat::Left),
289 "right" => Ok(LayoutFloat::Right),
290 "none" => Ok(LayoutFloat::None),
291 _ => Err(LayoutFloatParseError::InvalidValue(input)),
292 }
293}
294
295#[cfg(all(test, feature = "parser"))]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn test_parse_layout_display() {
301 assert_eq!(parse_layout_display("block").unwrap(), LayoutDisplay::Block);
302 assert_eq!(
303 parse_layout_display("inline").unwrap(),
304 LayoutDisplay::Inline
305 );
306 assert_eq!(
307 parse_layout_display("inline-block").unwrap(),
308 LayoutDisplay::InlineBlock
309 );
310 assert_eq!(parse_layout_display("flex").unwrap(), LayoutDisplay::Flex);
311 assert_eq!(
312 parse_layout_display("inline-flex").unwrap(),
313 LayoutDisplay::InlineFlex
314 );
315 assert_eq!(parse_layout_display("grid").unwrap(), LayoutDisplay::Grid);
316 assert_eq!(
317 parse_layout_display("inline-grid").unwrap(),
318 LayoutDisplay::InlineGrid
319 );
320 assert_eq!(parse_layout_display("none").unwrap(), LayoutDisplay::None);
321 assert_eq!(
322 parse_layout_display("flow-root").unwrap(),
323 LayoutDisplay::FlowRoot
324 );
325 assert_eq!(
326 parse_layout_display("list-item").unwrap(),
327 LayoutDisplay::ListItem
328 );
329 assert!(parse_layout_display("inherit").is_err());
332 assert!(parse_layout_display("initial").is_err());
333
334 assert_eq!(parse_layout_display("table").unwrap(), LayoutDisplay::Table);
336 assert_eq!(
337 parse_layout_display("inline-table").unwrap(),
338 LayoutDisplay::InlineTable
339 );
340 assert_eq!(
341 parse_layout_display("table-row").unwrap(),
342 LayoutDisplay::TableRow
343 );
344 assert_eq!(
345 parse_layout_display("table-cell").unwrap(),
346 LayoutDisplay::TableCell
347 );
348 assert_eq!(
349 parse_layout_display("table-caption").unwrap(),
350 LayoutDisplay::TableCaption
351 );
352 assert_eq!(
353 parse_layout_display("table-column-group").unwrap(),
354 LayoutDisplay::TableColumnGroup
355 );
356 assert_eq!(
357 parse_layout_display("table-header-group").unwrap(),
358 LayoutDisplay::TableHeaderGroup
359 );
360 assert_eq!(
361 parse_layout_display("table-footer-group").unwrap(),
362 LayoutDisplay::TableFooterGroup
363 );
364 assert_eq!(
365 parse_layout_display("table-row-group").unwrap(),
366 LayoutDisplay::TableRowGroup
367 );
368
369 assert_eq!(
371 parse_layout_display(" inline-flex ").unwrap(),
372 LayoutDisplay::InlineFlex
373 );
374
375 assert!(parse_layout_display("invalid-value").is_err());
377 assert!(parse_layout_display("").is_err());
378 assert!(parse_layout_display("display").is_err());
379 }
380
381 #[test]
382 fn test_parse_layout_float() {
383 assert_eq!(parse_layout_float("left").unwrap(), LayoutFloat::Left);
384 assert_eq!(parse_layout_float("right").unwrap(), LayoutFloat::Right);
385 assert_eq!(parse_layout_float("none").unwrap(), LayoutFloat::None);
386
387 assert_eq!(parse_layout_float(" right ").unwrap(), LayoutFloat::Right);
389
390 assert!(parse_layout_float("center").is_err());
392 assert!(parse_layout_float("").is_err());
393 assert!(parse_layout_float("float-left").is_err());
394 }
395}