1use alloc::string::{String, ToString};
6use crate::corety::AzString;
7
8#[cfg(feature = "parser")]
9use crate::props::basic::pixel::parse_pixel_value;
10use crate::props::{
11 basic::pixel::{CssPixelValueParseError, CssPixelValueParseErrorOwned, PixelValue},
12 formatter::PrintAsCssValue,
13 macros::PixelValueTaker,
14};
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(C)]
21#[derive(Default)]
22pub enum LayoutPosition {
23 #[default]
24 Static,
25 Relative,
26 Absolute,
27 Fixed,
28 Sticky,
29}
30
31impl LayoutPosition {
32 #[must_use] pub fn is_positioned(&self) -> bool {
33 *self != Self::Static
34 }
35}
36
37
38impl PrintAsCssValue for LayoutPosition {
39 fn print_as_css_value(&self) -> String {
40 String::from(match self {
41 Self::Static => "static",
42 Self::Relative => "relative",
43 Self::Absolute => "absolute",
44 Self::Fixed => "fixed",
45 Self::Sticky => "sticky",
46 })
47 }
48}
49
50impl_enum_fmt!(LayoutPosition, Static, Fixed, Absolute, Relative, Sticky);
51
52#[derive(Clone, PartialEq, Eq)]
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, Eq)]
65#[repr(C, u8)]
66pub enum LayoutPositionParseErrorOwned {
67 InvalidValue(AzString),
68}
69
70impl LayoutPositionParseError<'_> {
71 #[must_use] pub fn to_contained(&self) -> LayoutPositionParseErrorOwned {
72 match self {
73 LayoutPositionParseError::InvalidValue(s) => {
74 LayoutPositionParseErrorOwned::InvalidValue((*s).to_string().into())
75 }
76 }
77 }
78}
79
80impl LayoutPositionParseErrorOwned {
81 #[must_use] pub fn to_shared(&self) -> LayoutPositionParseError<'_> {
82 match self {
83 Self::InvalidValue(s) => {
84 LayoutPositionParseError::InvalidValue(s.as_str())
85 }
86 }
87 }
88}
89
90#[cfg(feature = "parser")]
91pub fn parse_layout_position(
95 input: &str,
96) -> Result<LayoutPosition, LayoutPositionParseError<'_>> {
97 let input = input.trim();
98 match input {
99 "static" => Ok(LayoutPosition::Static),
100 "relative" => Ok(LayoutPosition::Relative),
101 "absolute" => Ok(LayoutPosition::Absolute),
102 "fixed" => Ok(LayoutPosition::Fixed),
103 "sticky" => Ok(LayoutPosition::Sticky),
104 _ => Err(LayoutPositionParseError::InvalidValue(input)),
105 }
106}
107
108macro_rules! define_position_property {
111 ($struct_name:ident) => {
112 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
113 #[repr(C)]
114 pub struct $struct_name {
115 pub inner: PixelValue,
116 }
117
118 impl ::core::fmt::Debug for $struct_name {
119 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
120 write!(f, "{}", self.inner)
121 }
122 }
123
124 impl PixelValueTaker for $struct_name {
125 fn from_pixel_value(inner: PixelValue) -> Self {
126 Self { inner }
127 }
128 }
129
130 impl_pixel_value!($struct_name);
131
132 impl PrintAsCssValue for $struct_name {
133 fn print_as_css_value(&self) -> String {
134 format!("{}", self.inner)
135 }
136 }
137 };
138}
139
140define_position_property!(LayoutTop);
142define_position_property!(LayoutRight);
144define_position_property!(LayoutInsetBottom);
146define_position_property!(LayoutLeft);
148
149macro_rules! define_offset_parse_error {
152 ($struct_name:ident, $error_name:ident, $error_owned_name:ident, $parse_fn:ident) => {
153 #[derive(Clone, PartialEq, Eq)]
154 pub enum $error_name<'a> {
155 PixelValue(CssPixelValueParseError<'a>),
156 }
157 impl_debug_as_display!($error_name<'a>);
158 impl_display! { $error_name<'a>, { PixelValue(e) => format!("{}", e), }}
159 impl_from!(CssPixelValueParseError<'a>, $error_name::PixelValue);
160
161 #[derive(Debug, Clone, PartialEq, Eq)]
162 #[repr(C, u8)]
163 pub enum $error_owned_name {
164 PixelValue(CssPixelValueParseErrorOwned),
165 }
166 impl $error_name<'_> {
167 #[must_use] pub fn to_contained(&self) -> $error_owned_name {
168 match self {
169 $error_name::PixelValue(e) => {
170 $error_owned_name::PixelValue(e.to_contained())
171 }
172 }
173 }
174 }
175 impl $error_owned_name {
176 #[must_use] pub fn to_shared(&self) -> $error_name<'_> {
177 match self {
178 $error_owned_name::PixelValue(e) => {
179 $error_name::PixelValue(e.to_shared())
180 }
181 }
182 }
183 }
184
185 #[cfg(feature = "parser")]
186 pub fn $parse_fn(input: &str) -> Result<$struct_name, $error_name<'_>> {
190 parse_pixel_value(input)
191 .map(|v| $struct_name { inner: v })
192 .map_err(Into::into)
193 }
194 };
195}
196
197define_offset_parse_error!(LayoutTop, LayoutTopParseError, LayoutTopParseErrorOwned, parse_layout_top);
198define_offset_parse_error!(LayoutRight, LayoutRightParseError, LayoutRightParseErrorOwned, parse_layout_right);
199define_offset_parse_error!(LayoutInsetBottom, LayoutInsetBottomParseError, LayoutInsetBottomParseErrorOwned, parse_layout_bottom);
200define_offset_parse_error!(LayoutLeft, LayoutLeftParseError, LayoutLeftParseErrorOwned, parse_layout_left);
201
202#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
206#[repr(C, u8)]
207#[derive(Default)]
208pub enum LayoutZIndex {
209 #[default]
210 Auto,
211 Integer(i32),
212}
213
214impl crate::codegen::format::FormatAsRustCode for LayoutZIndex {
216 fn format_as_rust_code(&self, _tabs: usize) -> String {
217 match self {
218 Self::Auto => String::from("LayoutZIndex::Auto"),
219 Self::Integer(val) => {
220 format!("LayoutZIndex::Integer({val})")
221 }
222 }
223 }
224}
225
226
227impl PrintAsCssValue for LayoutZIndex {
228 fn print_as_css_value(&self) -> String {
229 match self {
230 Self::Auto => String::from("auto"),
231 Self::Integer(val) => val.to_string(),
232 }
233 }
234}
235
236#[derive(Clone, PartialEq, Eq)]
239pub enum LayoutZIndexParseError<'a> {
240 InvalidValue(&'a str),
241 ParseInt(::core::num::ParseIntError, &'a str),
242}
243impl_debug_as_display!(LayoutZIndexParseError<'a>);
244impl_display! { LayoutZIndexParseError<'a>, {
245 InvalidValue(val) => format!("Invalid z-index value: \"{}\"", val),
246 ParseInt(e, s) => format!("Invalid z-index integer \"{}\": {}", s, e),
247}}
248
249#[derive(Debug, Clone, PartialEq, Eq)]
252#[repr(C)]
253pub struct ParseIntErrorWithInput {
254 pub error: AzString,
256 pub input: AzString,
258}
259
260#[derive(Debug, Clone, PartialEq, Eq)]
261#[repr(C, u8)]
262pub enum LayoutZIndexParseErrorOwned {
263 InvalidValue(AzString),
264 ParseInt(ParseIntErrorWithInput),
265}
266
267impl LayoutZIndexParseError<'_> {
268 #[must_use] pub fn to_contained(&self) -> LayoutZIndexParseErrorOwned {
269 match self {
270 LayoutZIndexParseError::InvalidValue(s) => {
271 LayoutZIndexParseErrorOwned::InvalidValue((*s).to_string().into())
272 }
273 LayoutZIndexParseError::ParseInt(e, s) => {
274 LayoutZIndexParseErrorOwned::ParseInt(ParseIntErrorWithInput { error: e.to_string().into(), input: (*s).to_string().into() })
275 }
276 }
277 }
278}
279
280impl LayoutZIndexParseErrorOwned {
281 #[must_use] pub fn to_shared(&self) -> LayoutZIndexParseError<'_> {
287 match self {
288 Self::InvalidValue(s) => {
289 LayoutZIndexParseError::InvalidValue(s.as_str())
290 }
291 Self::ParseInt(e) => {
292 LayoutZIndexParseError::InvalidValue(e.input.as_str())
294 }
295 }
296 }
297}
298
299#[cfg(feature = "parser")]
300pub fn parse_layout_z_index(
304 input: &str,
305) -> Result<LayoutZIndex, LayoutZIndexParseError<'_>> {
306 let input = input.trim();
307 if input == "auto" {
308 return Ok(LayoutZIndex::Auto);
309 }
310
311 match input.parse::<i32>() {
312 Ok(val) => Ok(LayoutZIndex::Integer(val)),
313 Err(e) => Err(LayoutZIndexParseError::ParseInt(e, input)),
314 }
315}
316
317#[cfg(all(test, feature = "parser"))]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn test_parse_layout_position() {
323 assert_eq!(
324 parse_layout_position("static").unwrap(),
325 LayoutPosition::Static
326 );
327 assert_eq!(
328 parse_layout_position("relative").unwrap(),
329 LayoutPosition::Relative
330 );
331 assert_eq!(
332 parse_layout_position("absolute").unwrap(),
333 LayoutPosition::Absolute
334 );
335 assert_eq!(
336 parse_layout_position("fixed").unwrap(),
337 LayoutPosition::Fixed
338 );
339 assert_eq!(
340 parse_layout_position("sticky").unwrap(),
341 LayoutPosition::Sticky
342 );
343 }
344
345 #[test]
346 fn test_parse_layout_position_whitespace() {
347 assert_eq!(
348 parse_layout_position(" absolute ").unwrap(),
349 LayoutPosition::Absolute
350 );
351 }
352
353 #[test]
354 fn test_parse_layout_position_invalid() {
355 assert!(parse_layout_position("").is_err());
356 assert!(parse_layout_position("absolutely").is_err());
357 }
358
359 #[test]
360 fn test_parse_layout_z_index() {
361 assert_eq!(parse_layout_z_index("auto").unwrap(), LayoutZIndex::Auto);
362 assert_eq!(
363 parse_layout_z_index("10").unwrap(),
364 LayoutZIndex::Integer(10)
365 );
366 assert_eq!(parse_layout_z_index("0").unwrap(), LayoutZIndex::Integer(0));
367 assert_eq!(
368 parse_layout_z_index("-5").unwrap(),
369 LayoutZIndex::Integer(-5)
370 );
371 assert_eq!(
372 parse_layout_z_index(" 999 ").unwrap(),
373 LayoutZIndex::Integer(999)
374 );
375 }
376
377 #[test]
378 fn test_parse_layout_z_index_invalid() {
379 assert!(parse_layout_z_index("10px").is_err());
380 assert!(parse_layout_z_index("1.5").is_err());
381 assert!(parse_layout_z_index("none").is_err());
382 assert!(parse_layout_z_index("").is_err());
383 }
384
385 #[test]
386 fn test_parse_offsets() {
387 assert_eq!(
388 parse_layout_top("10px").unwrap(),
389 LayoutTop {
390 inner: PixelValue::px(10.0)
391 }
392 );
393 assert_eq!(
394 parse_layout_right("5%").unwrap(),
395 LayoutRight {
396 inner: PixelValue::percent(5.0)
397 }
398 );
399 assert_eq!(
400 parse_layout_bottom("2.5em").unwrap(),
401 LayoutInsetBottom {
402 inner: PixelValue::em(2.5)
403 }
404 );
405 assert_eq!(
406 parse_layout_left("0").unwrap(),
407 LayoutLeft {
408 inner: PixelValue::px(0.0)
409 }
410 );
411 }
412
413 #[test]
414 fn test_parse_offsets_invalid() {
415 assert!(parse_layout_top("auto").is_err());
417 assert!(parse_layout_right("").is_err());
418 assert!(parse_layout_bottom("10 px").is_ok());
420 assert!(parse_layout_left("ten pixels").is_err());
421 }
422}