1use alloc::string::{String, ToString};
11use crate::corety::AzString;
12
13use crate::props::formatter::PrintAsCssValue;
14
15#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
23#[repr(C)]
24#[derive(Default)]
28pub enum LayoutWritingMode {
29 #[default]
31 HorizontalTb,
32 VerticalRl,
34 VerticalLr,
37}
38
39
40impl LayoutWritingMode {
41 #[must_use] pub const fn is_vertical(self) -> bool {
43 matches!(self, Self::VerticalRl | Self::VerticalLr)
44 }
45}
46
47impl core::fmt::Debug for LayoutWritingMode {
48 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
49 write!(f, "{}", self.print_as_css_value())
50 }
51}
52
53impl core::fmt::Display for LayoutWritingMode {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 write!(f, "{}", self.print_as_css_value())
56 }
57}
58
59impl PrintAsCssValue for LayoutWritingMode {
60 fn print_as_css_value(&self) -> String {
61 match self {
62 Self::HorizontalTb => "horizontal-tb".to_string(),
63 Self::VerticalRl => "vertical-rl".to_string(),
64 Self::VerticalLr => "vertical-lr".to_string(),
65 }
66 }
67}
68
69#[cfg(feature = "parser")]
70#[derive(Clone, PartialEq, Eq)]
71pub enum LayoutWritingModeParseError<'a> {
72 InvalidValue(&'a str),
73}
74
75#[cfg(feature = "parser")]
76impl_debug_as_display!(LayoutWritingModeParseError<'a>);
77#[cfg(feature = "parser")]
78impl_display! { LayoutWritingModeParseError<'a>, {
79 InvalidValue(e) => format!("Invalid writing-mode value: \"{}\"", e),
80}}
81
82#[cfg(feature = "parser")]
83#[derive(Debug, Clone, PartialEq, Eq)]
84#[repr(C, u8)]
85pub enum LayoutWritingModeParseErrorOwned {
86 InvalidValue(AzString),
87}
88
89#[cfg(feature = "parser")]
90impl LayoutWritingModeParseError<'_> {
91 #[must_use] pub fn to_contained(&self) -> LayoutWritingModeParseErrorOwned {
92 match self {
93 LayoutWritingModeParseError::InvalidValue(s) => {
94 LayoutWritingModeParseErrorOwned::InvalidValue((*s).to_string().into())
95 }
96 }
97 }
98}
99
100#[cfg(feature = "parser")]
101impl LayoutWritingModeParseErrorOwned {
102 #[must_use] pub fn to_shared(&self) -> LayoutWritingModeParseError<'_> {
103 match self {
104 Self::InvalidValue(s) => {
105 LayoutWritingModeParseError::InvalidValue(s.as_str())
106 }
107 }
108 }
109}
110
111#[cfg(feature = "parser")]
112pub fn parse_layout_writing_mode(
116 input: &str,
117) -> Result<LayoutWritingMode, LayoutWritingModeParseError<'_>> {
118 let input = input.trim();
119 match input {
120 "horizontal-tb" => Ok(LayoutWritingMode::HorizontalTb),
121 "vertical-rl" => Ok(LayoutWritingMode::VerticalRl),
122 "vertical-lr" | "tb-lr" => Ok(LayoutWritingMode::VerticalLr),
124 _ => Err(LayoutWritingModeParseError::InvalidValue(input)),
125 }
126}
127
128#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
132#[repr(C)]
133#[derive(Default)]
134pub enum LayoutClear {
135 #[default]
137 None,
138 Left,
140 Right,
142 Both,
144}
145
146
147impl core::fmt::Debug for LayoutClear {
148 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149 write!(f, "{}", self.print_as_css_value())
150 }
151}
152
153impl core::fmt::Display for LayoutClear {
154 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
155 write!(f, "{}", self.print_as_css_value())
156 }
157}
158
159impl PrintAsCssValue for LayoutClear {
160 fn print_as_css_value(&self) -> String {
161 match self {
162 Self::None => "none".to_string(),
163 Self::Left => "left".to_string(),
164 Self::Right => "right".to_string(),
165 Self::Both => "both".to_string(),
166 }
167 }
168}
169
170#[cfg(feature = "parser")]
171#[derive(Clone, PartialEq, Eq)]
172pub enum LayoutClearParseError<'a> {
173 InvalidValue(&'a str),
174}
175
176#[cfg(feature = "parser")]
177impl_debug_as_display!(LayoutClearParseError<'a>);
178#[cfg(feature = "parser")]
179impl_display! { LayoutClearParseError<'a>, {
180 InvalidValue(e) => format!("Invalid clear value: \"{}\"", e),
181}}
182
183#[cfg(feature = "parser")]
184#[derive(Debug, Clone, PartialEq, Eq)]
185#[repr(C, u8)]
186pub enum LayoutClearParseErrorOwned {
187 InvalidValue(AzString),
188}
189
190#[cfg(feature = "parser")]
191impl LayoutClearParseError<'_> {
192 #[must_use] pub fn to_contained(&self) -> LayoutClearParseErrorOwned {
193 match self {
194 LayoutClearParseError::InvalidValue(s) => {
195 LayoutClearParseErrorOwned::InvalidValue((*s).to_string().into())
196 }
197 }
198 }
199}
200
201#[cfg(feature = "parser")]
202impl LayoutClearParseErrorOwned {
203 #[must_use] pub fn to_shared(&self) -> LayoutClearParseError<'_> {
204 match self {
205 Self::InvalidValue(s) => {
206 LayoutClearParseError::InvalidValue(s.as_str())
207 }
208 }
209 }
210}
211
212#[cfg(feature = "parser")]
213pub fn parse_layout_clear(input: &str) -> Result<LayoutClear, LayoutClearParseError<'_>> {
217 let input = input.trim();
218 match input {
219 "none" => Ok(LayoutClear::None),
220 "left" => Ok(LayoutClear::Left),
221 "right" => Ok(LayoutClear::Right),
222 "both" => Ok(LayoutClear::Both),
223 _ => Err(LayoutClearParseError::InvalidValue(input)),
224 }
225}
226
227#[cfg(all(test, feature = "parser"))]
228mod tests {
229 use super::*;
230
231 #[test]
233 fn test_parse_writing_mode_horizontal_tb() {
234 assert_eq!(
235 parse_layout_writing_mode("horizontal-tb").unwrap(),
236 LayoutWritingMode::HorizontalTb
237 );
238 }
239
240 #[test]
241 fn test_parse_writing_mode_vertical_rl() {
242 assert_eq!(
243 parse_layout_writing_mode("vertical-rl").unwrap(),
244 LayoutWritingMode::VerticalRl
245 );
246 }
247
248 #[test]
249 fn test_parse_writing_mode_vertical_lr() {
250 assert_eq!(
251 parse_layout_writing_mode("vertical-lr").unwrap(),
252 LayoutWritingMode::VerticalLr
253 );
254 }
255
256 #[test]
257 fn test_parse_writing_mode_invalid() {
258 assert!(parse_layout_writing_mode("invalid").is_err());
259 assert!(parse_layout_writing_mode("horizontal").is_err());
260 }
261
262 #[test]
263 fn test_parse_writing_mode_whitespace() {
264 assert_eq!(
265 parse_layout_writing_mode(" vertical-rl ").unwrap(),
266 LayoutWritingMode::VerticalRl
267 );
268 }
269
270 #[test]
272 fn test_parse_layout_clear_none() {
273 assert_eq!(parse_layout_clear("none").unwrap(), LayoutClear::None);
274 }
275
276 #[test]
277 fn test_parse_layout_clear_left() {
278 assert_eq!(parse_layout_clear("left").unwrap(), LayoutClear::Left);
279 }
280
281 #[test]
282 fn test_parse_layout_clear_right() {
283 assert_eq!(parse_layout_clear("right").unwrap(), LayoutClear::Right);
284 }
285
286 #[test]
287 fn test_parse_layout_clear_both() {
288 assert_eq!(parse_layout_clear("both").unwrap(), LayoutClear::Both);
289 }
290
291 #[test]
292 fn test_parse_layout_clear_invalid() {
293 assert!(parse_layout_clear("invalid").is_err());
294 assert!(parse_layout_clear("all").is_err());
295 }
296
297 #[test]
298 fn test_parse_layout_clear_whitespace() {
299 assert_eq!(parse_layout_clear(" both ").unwrap(), LayoutClear::Both);
300 }
301
302 #[test]
304 fn test_print_writing_mode() {
305 assert_eq!(
306 LayoutWritingMode::HorizontalTb.print_as_css_value(),
307 "horizontal-tb"
308 );
309 assert_eq!(
310 LayoutWritingMode::VerticalRl.print_as_css_value(),
311 "vertical-rl"
312 );
313 assert_eq!(
314 LayoutWritingMode::VerticalLr.print_as_css_value(),
315 "vertical-lr"
316 );
317 }
318
319 #[test]
320 fn test_print_layout_clear() {
321 assert_eq!(LayoutClear::None.print_as_css_value(), "none");
322 assert_eq!(LayoutClear::Left.print_as_css_value(), "left");
323 assert_eq!(LayoutClear::Right.print_as_css_value(), "right");
324 assert_eq!(LayoutClear::Both.print_as_css_value(), "both");
325 }
326}