1use alloc::string::{String, ToString};
4
5#[cfg(feature = "parser")]
6use crate::props::basic::pixel::parse_pixel_value;
7use crate::props::{
8 basic::pixel::{CssPixelValueParseError, CssPixelValueParseErrorOwned, PixelValue},
9 formatter::PrintAsCssValue,
10 macros::PixelValueTaker,
11};
12
13#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[repr(C)]
18pub enum LayoutPosition {
19 Static,
20 Relative,
21 Absolute,
22 Fixed,
23 Sticky,
24}
25
26impl LayoutPosition {
27 pub fn is_positioned(&self) -> bool {
28 *self != LayoutPosition::Static
29 }
30}
31
32impl Default for LayoutPosition {
33 fn default() -> Self {
34 LayoutPosition::Static
35 }
36}
37
38impl PrintAsCssValue for LayoutPosition {
39 fn print_as_css_value(&self) -> String {
40 String::from(match self {
41 LayoutPosition::Static => "static",
42 LayoutPosition::Relative => "relative",
43 LayoutPosition::Absolute => "absolute",
44 LayoutPosition::Fixed => "fixed",
45 LayoutPosition::Sticky => "sticky",
46 })
47 }
48}
49
50impl_enum_fmt!(LayoutPosition, Static, Fixed, Absolute, Relative, Sticky);
51
52#[derive(Clone, PartialEq)]
55pub enum LayoutPositionParseError<'a> {
56 InvalidValue(&'a str),
57}
58
59impl_debug_as_display!(LayoutPositionParseError<'a>);
60impl_display! { LayoutPositionParseError<'a>, {
61 InvalidValue(val) => format!("Invalid position value: \"{}\"", val),
62}}
63
64#[derive(Debug, Clone, PartialEq)]
65pub enum LayoutPositionParseErrorOwned {
66 InvalidValue(String),
67}
68
69impl<'a> LayoutPositionParseError<'a> {
70 pub fn to_contained(&self) -> LayoutPositionParseErrorOwned {
71 match self {
72 LayoutPositionParseError::InvalidValue(s) => {
73 LayoutPositionParseErrorOwned::InvalidValue(s.to_string())
74 }
75 }
76 }
77}
78
79impl LayoutPositionParseErrorOwned {
80 pub fn to_shared<'a>(&'a self) -> LayoutPositionParseError<'a> {
81 match self {
82 LayoutPositionParseErrorOwned::InvalidValue(s) => {
83 LayoutPositionParseError::InvalidValue(s.as_str())
84 }
85 }
86 }
87}
88
89#[cfg(feature = "parser")]
90pub fn parse_layout_position<'a>(
91 input: &'a str,
92) -> Result<LayoutPosition, LayoutPositionParseError<'a>> {
93 let input = input.trim();
94 match input {
95 "static" => Ok(LayoutPosition::Static),
96 "relative" => Ok(LayoutPosition::Relative),
97 "absolute" => Ok(LayoutPosition::Absolute),
98 "fixed" => Ok(LayoutPosition::Fixed),
99 _ => Err(LayoutPositionParseError::InvalidValue(input)),
100 }
101}
102
103macro_rules! define_position_property {
106 ($struct_name:ident) => {
107 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
108 #[repr(C)]
109 pub struct $struct_name {
110 pub inner: PixelValue,
111 }
112
113 impl ::core::fmt::Debug for $struct_name {
114 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
115 write!(f, "{}", self.inner)
116 }
117 }
118
119 impl PixelValueTaker for $struct_name {
120 fn from_pixel_value(inner: PixelValue) -> Self {
121 Self { inner }
122 }
123 }
124
125 impl_pixel_value!($struct_name);
126
127 impl PrintAsCssValue for $struct_name {
128 fn print_as_css_value(&self) -> String {
129 format!("{}", self.inner)
130 }
131 }
132 };
133}
134
135define_position_property!(LayoutTop);
136define_position_property!(LayoutRight);
137define_position_property!(LayoutInsetBottom);
138define_position_property!(LayoutLeft);
139
140#[derive(Clone, PartialEq)]
143pub enum LayoutTopParseError<'a> {
144 PixelValue(CssPixelValueParseError<'a>),
145}
146impl_debug_as_display!(LayoutTopParseError<'a>);
147impl_display! { LayoutTopParseError<'a>, { PixelValue(e) => format!("{}", e), }}
148impl_from!(CssPixelValueParseError<'a>, LayoutTopParseError::PixelValue);
149
150#[derive(Debug, Clone, PartialEq)]
151pub enum LayoutTopParseErrorOwned {
152 PixelValue(CssPixelValueParseErrorOwned),
153}
154impl<'a> LayoutTopParseError<'a> {
155 pub fn to_contained(&self) -> LayoutTopParseErrorOwned {
156 match self {
157 LayoutTopParseError::PixelValue(e) => {
158 LayoutTopParseErrorOwned::PixelValue(e.to_contained())
159 }
160 }
161 }
162}
163impl LayoutTopParseErrorOwned {
164 pub fn to_shared<'a>(&'a self) -> LayoutTopParseError<'a> {
165 match self {
166 LayoutTopParseErrorOwned::PixelValue(e) => {
167 LayoutTopParseError::PixelValue(e.to_shared())
168 }
169 }
170 }
171}
172
173#[cfg(feature = "parser")]
174pub fn parse_layout_top<'a>(input: &'a str) -> Result<LayoutTop, LayoutTopParseError<'a>> {
175 parse_pixel_value(input)
176 .map(|v| LayoutTop { inner: v })
177 .map_err(Into::into)
178}
179
180#[derive(Clone, PartialEq)]
183pub enum LayoutRightParseError<'a> {
184 PixelValue(CssPixelValueParseError<'a>),
185}
186impl_debug_as_display!(LayoutRightParseError<'a>);
187impl_display! { LayoutRightParseError<'a>, { PixelValue(e) => format!("{}", e), }}
188impl_from!(
189 CssPixelValueParseError<'a>,
190 LayoutRightParseError::PixelValue
191);
192
193#[derive(Debug, Clone, PartialEq)]
194pub enum LayoutRightParseErrorOwned {
195 PixelValue(CssPixelValueParseErrorOwned),
196}
197impl<'a> LayoutRightParseError<'a> {
198 pub fn to_contained(&self) -> LayoutRightParseErrorOwned {
199 match self {
200 LayoutRightParseError::PixelValue(e) => {
201 LayoutRightParseErrorOwned::PixelValue(e.to_contained())
202 }
203 }
204 }
205}
206impl LayoutRightParseErrorOwned {
207 pub fn to_shared<'a>(&'a self) -> LayoutRightParseError<'a> {
208 match self {
209 LayoutRightParseErrorOwned::PixelValue(e) => {
210 LayoutRightParseError::PixelValue(e.to_shared())
211 }
212 }
213 }
214}
215
216#[cfg(feature = "parser")]
217pub fn parse_layout_right<'a>(input: &'a str) -> Result<LayoutRight, LayoutRightParseError<'a>> {
218 parse_pixel_value(input)
219 .map(|v| LayoutRight { inner: v })
220 .map_err(Into::into)
221}
222
223#[derive(Clone, PartialEq)]
226pub enum LayoutInsetBottomParseError<'a> {
227 PixelValue(CssPixelValueParseError<'a>),
228}
229impl_debug_as_display!(LayoutInsetBottomParseError<'a>);
230impl_display! { LayoutInsetBottomParseError<'a>, { PixelValue(e) => format!("{}", e), }}
231impl_from!(
232 CssPixelValueParseError<'a>,
233 LayoutInsetBottomParseError::PixelValue
234);
235
236#[derive(Debug, Clone, PartialEq)]
237pub enum LayoutInsetBottomParseErrorOwned {
238 PixelValue(CssPixelValueParseErrorOwned),
239}
240impl<'a> LayoutInsetBottomParseError<'a> {
241 pub fn to_contained(&self) -> LayoutInsetBottomParseErrorOwned {
242 match self {
243 LayoutInsetBottomParseError::PixelValue(e) => {
244 LayoutInsetBottomParseErrorOwned::PixelValue(e.to_contained())
245 }
246 }
247 }
248}
249impl LayoutInsetBottomParseErrorOwned {
250 pub fn to_shared<'a>(&'a self) -> LayoutInsetBottomParseError<'a> {
251 match self {
252 LayoutInsetBottomParseErrorOwned::PixelValue(e) => {
253 LayoutInsetBottomParseError::PixelValue(e.to_shared())
254 }
255 }
256 }
257}
258
259#[cfg(feature = "parser")]
260pub fn parse_layout_bottom<'a>(
261 input: &'a str,
262) -> Result<LayoutInsetBottom, LayoutInsetBottomParseError<'a>> {
263 parse_pixel_value(input)
264 .map(|v| LayoutInsetBottom { inner: v })
265 .map_err(Into::into)
266}
267
268#[derive(Clone, PartialEq)]
271pub enum LayoutLeftParseError<'a> {
272 PixelValue(CssPixelValueParseError<'a>),
273}
274impl_debug_as_display!(LayoutLeftParseError<'a>);
275impl_display! { LayoutLeftParseError<'a>, { PixelValue(e) => format!("{}", e), }}
276impl_from!(
277 CssPixelValueParseError<'a>,
278 LayoutLeftParseError::PixelValue
279);
280
281#[derive(Debug, Clone, PartialEq)]
282pub enum LayoutLeftParseErrorOwned {
283 PixelValue(CssPixelValueParseErrorOwned),
284}
285impl<'a> LayoutLeftParseError<'a> {
286 pub fn to_contained(&self) -> LayoutLeftParseErrorOwned {
287 match self {
288 LayoutLeftParseError::PixelValue(e) => {
289 LayoutLeftParseErrorOwned::PixelValue(e.to_contained())
290 }
291 }
292 }
293}
294impl LayoutLeftParseErrorOwned {
295 pub fn to_shared<'a>(&'a self) -> LayoutLeftParseError<'a> {
296 match self {
297 LayoutLeftParseErrorOwned::PixelValue(e) => {
298 LayoutLeftParseError::PixelValue(e.to_shared())
299 }
300 }
301 }
302}
303
304#[cfg(feature = "parser")]
305pub fn parse_layout_left<'a>(input: &'a str) -> Result<LayoutLeft, LayoutLeftParseError<'a>> {
306 parse_pixel_value(input)
307 .map(|v| LayoutLeft { inner: v })
308 .map_err(Into::into)
309}
310
311#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
315#[repr(C, u8)]
316pub enum LayoutZIndex {
317 Auto,
318 Integer(i32),
319}
320
321impl crate::format_rust_code::FormatAsRustCode for LayoutZIndex {
323 fn format_as_rust_code(&self, _tabs: usize) -> String {
324 match self {
325 LayoutZIndex::Auto => String::from("LayoutZIndex::Auto"),
326 LayoutZIndex::Integer(val) => {
327 format!("LayoutZIndex::Integer({})", val)
328 }
329 }
330 }
331}
332
333impl Default for LayoutZIndex {
334 fn default() -> Self {
335 LayoutZIndex::Auto
336 }
337}
338
339impl PrintAsCssValue for LayoutZIndex {
340 fn print_as_css_value(&self) -> String {
341 match self {
342 LayoutZIndex::Auto => String::from("auto"),
343 LayoutZIndex::Integer(val) => val.to_string(),
344 }
345 }
346}
347
348#[derive(Clone, PartialEq)]
351pub enum LayoutZIndexParseError<'a> {
352 InvalidValue(&'a str),
353 ParseInt(::core::num::ParseIntError, &'a str),
354}
355impl_debug_as_display!(LayoutZIndexParseError<'a>);
356impl_display! { LayoutZIndexParseError<'a>, {
357 InvalidValue(val) => format!("Invalid z-index value: \"{}\"", val),
358 ParseInt(e, s) => format!("Invalid z-index integer \"{}\": {}", s, e),
359}}
360
361#[derive(Debug, Clone, PartialEq)]
362pub enum LayoutZIndexParseErrorOwned {
363 InvalidValue(String),
364 ParseInt(String, String),
365}
366
367impl<'a> LayoutZIndexParseError<'a> {
368 pub fn to_contained(&self) -> LayoutZIndexParseErrorOwned {
369 match self {
370 LayoutZIndexParseError::InvalidValue(s) => {
371 LayoutZIndexParseErrorOwned::InvalidValue(s.to_string())
372 }
373 LayoutZIndexParseError::ParseInt(e, s) => {
374 LayoutZIndexParseErrorOwned::ParseInt(e.to_string(), s.to_string())
375 }
376 }
377 }
378}
379
380impl LayoutZIndexParseErrorOwned {
381 pub fn to_shared<'a>(&'a self) -> LayoutZIndexParseError<'a> {
382 match self {
383 LayoutZIndexParseErrorOwned::InvalidValue(s) => {
384 LayoutZIndexParseError::InvalidValue(s.as_str())
385 }
386 LayoutZIndexParseErrorOwned::ParseInt(_e, s) => {
387 LayoutZIndexParseError::InvalidValue(s.as_str())
389 }
390 }
391 }
392}
393
394#[cfg(feature = "parser")]
395pub fn parse_layout_z_index<'a>(
396 input: &'a str,
397) -> Result<LayoutZIndex, LayoutZIndexParseError<'a>> {
398 let input = input.trim();
399 if input == "auto" {
400 return Ok(LayoutZIndex::Auto);
401 }
402
403 match input.parse::<i32>() {
404 Ok(val) => Ok(LayoutZIndex::Integer(val)),
405 Err(e) => Err(LayoutZIndexParseError::ParseInt(e, input)),
406 }
407}
408
409#[cfg(all(test, feature = "parser"))]
410mod tests {
411 use super::*;
412
413 #[test]
414 fn test_parse_layout_position() {
415 assert_eq!(
416 parse_layout_position("static").unwrap(),
417 LayoutPosition::Static
418 );
419 assert_eq!(
420 parse_layout_position("relative").unwrap(),
421 LayoutPosition::Relative
422 );
423 assert_eq!(
424 parse_layout_position("absolute").unwrap(),
425 LayoutPosition::Absolute
426 );
427 assert_eq!(
428 parse_layout_position("fixed").unwrap(),
429 LayoutPosition::Fixed
430 );
431 }
432
433 #[test]
434 fn test_parse_layout_position_whitespace() {
435 assert_eq!(
436 parse_layout_position(" absolute ").unwrap(),
437 LayoutPosition::Absolute
438 );
439 }
440
441 #[test]
442 fn test_parse_layout_position_invalid() {
443 assert!(parse_layout_position("sticky").is_err());
444 assert!(parse_layout_position("").is_err());
445 assert!(parse_layout_position("absolutely").is_err());
446 }
447
448 #[test]
449 fn test_parse_layout_z_index() {
450 assert_eq!(parse_layout_z_index("auto").unwrap(), LayoutZIndex::Auto);
451 assert_eq!(
452 parse_layout_z_index("10").unwrap(),
453 LayoutZIndex::Integer(10)
454 );
455 assert_eq!(parse_layout_z_index("0").unwrap(), LayoutZIndex::Integer(0));
456 assert_eq!(
457 parse_layout_z_index("-5").unwrap(),
458 LayoutZIndex::Integer(-5)
459 );
460 assert_eq!(
461 parse_layout_z_index(" 999 ").unwrap(),
462 LayoutZIndex::Integer(999)
463 );
464 }
465
466 #[test]
467 fn test_parse_layout_z_index_invalid() {
468 assert!(parse_layout_z_index("10px").is_err());
469 assert!(parse_layout_z_index("1.5").is_err());
470 assert!(parse_layout_z_index("none").is_err());
471 assert!(parse_layout_z_index("").is_err());
472 }
473
474 #[test]
475 fn test_parse_offsets() {
476 assert_eq!(
477 parse_layout_top("10px").unwrap(),
478 LayoutTop {
479 inner: PixelValue::px(10.0)
480 }
481 );
482 assert_eq!(
483 parse_layout_right("5%").unwrap(),
484 LayoutRight {
485 inner: PixelValue::percent(5.0)
486 }
487 );
488 assert_eq!(
489 parse_layout_bottom("2.5em").unwrap(),
490 LayoutInsetBottom {
491 inner: PixelValue::em(2.5)
492 }
493 );
494 assert_eq!(
495 parse_layout_left("0").unwrap(),
496 LayoutLeft {
497 inner: PixelValue::px(0.0)
498 }
499 );
500 }
501
502 #[test]
503 fn test_parse_offsets_invalid() {
504 assert!(parse_layout_top("auto").is_err());
506 assert!(parse_layout_right("").is_err());
507 assert!(parse_layout_bottom("10 px").is_ok());
509 assert!(parse_layout_left("ten pixels").is_err());
510 }
511}