1#[cfg(feature = "parse")]
12use crate::util::parse::{CssParseResult, FromCss, Parser, Token};
13
14use crate::style::Direction;
15
16#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23#[repr(u8)]
24pub enum AlignItemsKeyword {
25 #[default]
27 Normal,
28 Start,
30 End,
32 FlexStart,
37 FlexEnd,
42 SelfStart,
48 SelfEnd,
54 Center,
56 Baseline,
58 Stretch,
60}
61
62#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68#[repr(u8)]
69pub enum AlignContentKeyword {
70 #[default]
73 Normal,
74 Start,
76 End,
78 FlexStart,
80 FlexEnd,
82 Center,
84 Stretch,
86 SpaceBetween,
89 SpaceEvenly,
92 SpaceAround,
95}
96
97impl AlignContentKeyword {
98 pub(crate) fn reversed(self) -> Self {
104 match self {
105 Self::Start => Self::End,
106 Self::End => Self::Start,
107 Self::FlexStart => Self::FlexEnd,
108 Self::FlexEnd => Self::FlexStart,
109 Self::Stretch => Self::End,
110 Self::Normal | Self::Center | Self::SpaceBetween | Self::SpaceEvenly | Self::SpaceAround => self,
111 }
112 }
113}
114
115#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[repr(u8)]
135pub enum AlignmentSafety {
136 #[default]
140 Default,
141 Unsafe,
144 Safe,
147}
148
149#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
155pub struct AlignItems {
156 pub keyword: AlignItemsKeyword,
158 pub safety: AlignmentSafety,
160}
161
162impl AlignItems {
163 pub const NORMAL: Self = Self { keyword: AlignItemsKeyword::Normal, safety: AlignmentSafety::Default };
165 pub const START: Self = Self { keyword: AlignItemsKeyword::Start, safety: AlignmentSafety::Default };
167 pub const END: Self = Self { keyword: AlignItemsKeyword::End, safety: AlignmentSafety::Default };
169 pub const FLEX_START: Self = Self { keyword: AlignItemsKeyword::FlexStart, safety: AlignmentSafety::Default };
171 pub const FLEX_END: Self = Self { keyword: AlignItemsKeyword::FlexEnd, safety: AlignmentSafety::Default };
173 pub const SELF_START: Self = Self { keyword: AlignItemsKeyword::SelfStart, safety: AlignmentSafety::Default };
175 pub const SELF_END: Self = Self { keyword: AlignItemsKeyword::SelfEnd, safety: AlignmentSafety::Default };
177 pub const CENTER: Self = Self { keyword: AlignItemsKeyword::Center, safety: AlignmentSafety::Default };
179 pub const BASELINE: Self = Self { keyword: AlignItemsKeyword::Baseline, safety: AlignmentSafety::Default };
181 pub const STRETCH: Self = Self { keyword: AlignItemsKeyword::Stretch, safety: AlignmentSafety::Default };
183 pub const SAFE_START: Self = Self { keyword: AlignItemsKeyword::Start, safety: AlignmentSafety::Safe };
186 pub const SAFE_END: Self = Self { keyword: AlignItemsKeyword::End, safety: AlignmentSafety::Safe };
189 pub const SAFE_FLEX_START: Self = Self { keyword: AlignItemsKeyword::FlexStart, safety: AlignmentSafety::Safe };
192 pub const SAFE_FLEX_END: Self = Self { keyword: AlignItemsKeyword::FlexEnd, safety: AlignmentSafety::Safe };
195 pub const SAFE_CENTER: Self = Self { keyword: AlignItemsKeyword::Center, safety: AlignmentSafety::Safe };
198 pub const SAFE_SELF_START: Self = Self { keyword: AlignItemsKeyword::SelfStart, safety: AlignmentSafety::Safe };
201 pub const SAFE_SELF_END: Self = Self { keyword: AlignItemsKeyword::SelfEnd, safety: AlignmentSafety::Safe };
204
205 #[inline]
207 pub const fn is_safe(self) -> bool {
208 matches!(self.safety, AlignmentSafety::Safe)
209 }
210
211 #[inline]
213 pub const fn with_safety(self, safety: AlignmentSafety) -> Self {
214 Self { keyword: self.keyword, safety }
215 }
216
217 #[inline]
219 pub const fn keyword(self) -> AlignItemsKeyword {
220 self.keyword
221 }
222
223 #[inline(always)]
226 pub const fn is_stretch_or_normal(self) -> bool {
227 matches!(self.keyword, AlignItemsKeyword::Stretch | AlignItemsKeyword::Normal)
228 }
229
230 #[inline]
241 pub fn resolve_self_relative(
242 self,
243 item_direction: Direction,
244 container_direction: Direction,
245 axis_is_inline: bool,
246 ) -> Self {
247 let flip = axis_is_inline && item_direction != container_direction;
248 let keyword = match self.keyword {
249 AlignItemsKeyword::SelfStart => {
250 if flip {
251 AlignItemsKeyword::End
252 } else {
253 AlignItemsKeyword::Start
254 }
255 }
256 AlignItemsKeyword::SelfEnd => {
257 if flip {
258 AlignItemsKeyword::Start
259 } else {
260 AlignItemsKeyword::End
261 }
262 }
263 other => other,
264 };
265 Self { keyword, safety: self.safety }
266 }
267}
268
269#[cfg(feature = "parse")]
270impl FromCss for AlignItems {
271 fn from_css<'i>(input: &mut Parser<'i, '_>) -> CssParseResult<'i, Self> {
272 let first = input.expect_ident()?.clone();
273 cssparser::match_ignore_ascii_case! { &*first,
274 "safe" => {
275 let pos = input.expect_ident()?.clone();
276 cssparser::match_ignore_ascii_case! { &*pos,
277 "start" => Ok(Self::SAFE_START),
278 "end" => Ok(Self::SAFE_END),
279 "flex-start" => Ok(Self::SAFE_FLEX_START),
280 "flex-end" => Ok(Self::SAFE_FLEX_END),
281 "self-start" => Ok(Self::SAFE_SELF_START),
282 "self-end" => Ok(Self::SAFE_SELF_END),
283 "center" => Ok(Self::SAFE_CENTER),
284 _ => Err(input.new_unexpected_token_error(Token::Ident(pos))),
285 }
286 },
287 "unsafe" => {
288 let pos = input.expect_ident()?.clone();
289 let keyword = cssparser::match_ignore_ascii_case! { &*pos,
290 "start" => AlignItemsKeyword::Start,
291 "end" => AlignItemsKeyword::End,
292 "flex-start" => AlignItemsKeyword::FlexStart,
293 "flex-end" => AlignItemsKeyword::FlexEnd,
294 "self-start" => AlignItemsKeyword::SelfStart,
295 "self-end" => AlignItemsKeyword::SelfEnd,
296 "center" => AlignItemsKeyword::Center,
297 _ => return Err(input.new_unexpected_token_error(Token::Ident(pos))),
298 };
299 Ok(Self { keyword, safety: AlignmentSafety::Unsafe })
300 },
301 "normal" => Ok(Self::NORMAL),
302 "start" => Ok(Self::START),
303 "end" => Ok(Self::END),
304 "flex-start" => Ok(Self::FLEX_START),
305 "flex-end" => Ok(Self::FLEX_END),
306 "self-start" => Ok(Self::SELF_START),
307 "self-end" => Ok(Self::SELF_END),
308 "center" => Ok(Self::CENTER),
309 "baseline" => Ok(Self::BASELINE),
310 "stretch" => Ok(Self::STRETCH),
311 _ => Err(input.new_unexpected_token_error(Token::Ident(first))),
312 }
313 }
314}
315
316#[cfg(feature = "parse")]
317crate::util::parse::from_str_from_css!(AlignItems);
318
319pub type JustifyItems = AlignItems;
325pub type AlignSelf = AlignItems;
333pub type JustifySelf = AlignItems;
341
342#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
348pub struct AlignContent {
349 pub keyword: AlignContentKeyword,
351 pub safety: AlignmentSafety,
353}
354
355impl AlignContent {
356 pub const NORMAL: Self = Self { keyword: AlignContentKeyword::Normal, safety: AlignmentSafety::Default };
358 pub const START: Self = Self { keyword: AlignContentKeyword::Start, safety: AlignmentSafety::Default };
360 pub const END: Self = Self { keyword: AlignContentKeyword::End, safety: AlignmentSafety::Default };
362 pub const FLEX_START: Self = Self { keyword: AlignContentKeyword::FlexStart, safety: AlignmentSafety::Default };
364 pub const FLEX_END: Self = Self { keyword: AlignContentKeyword::FlexEnd, safety: AlignmentSafety::Default };
366 pub const CENTER: Self = Self { keyword: AlignContentKeyword::Center, safety: AlignmentSafety::Default };
368 pub const STRETCH: Self = Self { keyword: AlignContentKeyword::Stretch, safety: AlignmentSafety::Default };
370 pub const SPACE_BETWEEN: Self =
372 Self { keyword: AlignContentKeyword::SpaceBetween, safety: AlignmentSafety::Default };
373 pub const SPACE_EVENLY: Self = Self { keyword: AlignContentKeyword::SpaceEvenly, safety: AlignmentSafety::Default };
375 pub const SPACE_AROUND: Self = Self { keyword: AlignContentKeyword::SpaceAround, safety: AlignmentSafety::Default };
377 pub const SAFE_START: Self = Self { keyword: AlignContentKeyword::Start, safety: AlignmentSafety::Safe };
380 pub const SAFE_END: Self = Self { keyword: AlignContentKeyword::End, safety: AlignmentSafety::Safe };
383 pub const SAFE_FLEX_START: Self = Self { keyword: AlignContentKeyword::FlexStart, safety: AlignmentSafety::Safe };
386 pub const SAFE_FLEX_END: Self = Self { keyword: AlignContentKeyword::FlexEnd, safety: AlignmentSafety::Safe };
389 pub const SAFE_CENTER: Self = Self { keyword: AlignContentKeyword::Center, safety: AlignmentSafety::Safe };
392
393 #[inline]
395 pub const fn is_safe(self) -> bool {
396 matches!(self.safety, AlignmentSafety::Safe)
397 }
398
399 #[inline]
401 pub const fn with_safety(self, safety: AlignmentSafety) -> Self {
402 Self { keyword: self.keyword, safety }
403 }
404
405 #[inline]
407 pub const fn keyword(self) -> AlignContentKeyword {
408 self.keyword
409 }
410}
411
412#[cfg(feature = "parse")]
413impl FromCss for AlignContent {
414 fn from_css<'i>(input: &mut Parser<'i, '_>) -> CssParseResult<'i, Self> {
415 let first = input.expect_ident()?.clone();
416 cssparser::match_ignore_ascii_case! { &*first,
417 "safe" => {
418 let pos = input.expect_ident()?.clone();
419 cssparser::match_ignore_ascii_case! { &*pos,
420 "start" => Ok(Self::SAFE_START),
421 "end" => Ok(Self::SAFE_END),
422 "flex-start" => Ok(Self::SAFE_FLEX_START),
423 "flex-end" => Ok(Self::SAFE_FLEX_END),
424 "center" => Ok(Self::SAFE_CENTER),
425 _ => Err(input.new_unexpected_token_error(Token::Ident(pos))),
426 }
427 },
428 "unsafe" => {
429 let pos = input.expect_ident()?.clone();
430 let keyword = cssparser::match_ignore_ascii_case! { &*pos,
431 "start" => AlignContentKeyword::Start,
432 "end" => AlignContentKeyword::End,
433 "flex-start" => AlignContentKeyword::FlexStart,
434 "flex-end" => AlignContentKeyword::FlexEnd,
435 "center" => AlignContentKeyword::Center,
436 _ => return Err(input.new_unexpected_token_error(Token::Ident(pos))),
437 };
438 Ok(Self { keyword, safety: AlignmentSafety::Unsafe })
439 },
440 "normal" => Ok(Self::NORMAL),
441 "start" => Ok(Self::START),
442 "end" => Ok(Self::END),
443 "flex-start" => Ok(Self::FLEX_START),
444 "flex-end" => Ok(Self::FLEX_END),
445 "center" => Ok(Self::CENTER),
446 "stretch" => Ok(Self::STRETCH),
447 "space-between" => Ok(Self::SPACE_BETWEEN),
448 "space-evenly" => Ok(Self::SPACE_EVENLY),
449 "space-around" => Ok(Self::SPACE_AROUND),
450 _ => Err(input.new_unexpected_token_error(Token::Ident(first))),
451 }
452 }
453}
454
455#[cfg(feature = "parse")]
456crate::util::parse::from_str_from_css!(AlignContent);
457
458pub type JustifyContent = AlignContent;
464
465#[cfg(feature = "serde")]
474const ALIGN_ITEMS_NAMES: &[&str] = &[
475 "Normal",
476 "Start",
477 "End",
478 "FlexStart",
479 "FlexEnd",
480 "SelfStart",
481 "SelfEnd",
482 "Center",
483 "Baseline",
484 "Stretch",
485 "SafeStart",
486 "SafeEnd",
487 "SafeFlexStart",
488 "SafeFlexEnd",
489 "SafeSelfStart",
490 "SafeSelfEnd",
491 "SafeCenter",
492 "UnsafeStart",
493 "UnsafeEnd",
494 "UnsafeFlexStart",
495 "UnsafeFlexEnd",
496 "UnsafeSelfStart",
497 "UnsafeSelfEnd",
498 "UnsafeCenter",
499];
500
501#[cfg(feature = "serde")]
502impl serde::Serialize for AlignItems {
503 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
504 let name = match (self.keyword, self.safety) {
505 (AlignItemsKeyword::Start, AlignmentSafety::Default) => "Start",
506 (AlignItemsKeyword::End, AlignmentSafety::Default) => "End",
507 (AlignItemsKeyword::FlexStart, AlignmentSafety::Default) => "FlexStart",
508 (AlignItemsKeyword::FlexEnd, AlignmentSafety::Default) => "FlexEnd",
509 (AlignItemsKeyword::SelfStart, AlignmentSafety::Default) => "SelfStart",
510 (AlignItemsKeyword::SelfEnd, AlignmentSafety::Default) => "SelfEnd",
511 (AlignItemsKeyword::Center, AlignmentSafety::Default) => "Center",
512 (AlignItemsKeyword::Start, AlignmentSafety::Unsafe) => "UnsafeStart",
513 (AlignItemsKeyword::End, AlignmentSafety::Unsafe) => "UnsafeEnd",
514 (AlignItemsKeyword::FlexStart, AlignmentSafety::Unsafe) => "UnsafeFlexStart",
515 (AlignItemsKeyword::FlexEnd, AlignmentSafety::Unsafe) => "UnsafeFlexEnd",
516 (AlignItemsKeyword::SelfStart, AlignmentSafety::Unsafe) => "UnsafeSelfStart",
517 (AlignItemsKeyword::SelfEnd, AlignmentSafety::Unsafe) => "UnsafeSelfEnd",
518 (AlignItemsKeyword::Center, AlignmentSafety::Unsafe) => "UnsafeCenter",
519 (AlignItemsKeyword::Normal, _) => "Normal",
520 (AlignItemsKeyword::Baseline, _) => "Baseline",
521 (AlignItemsKeyword::Stretch, _) => "Stretch",
522 (AlignItemsKeyword::Start, AlignmentSafety::Safe) => "SafeStart",
523 (AlignItemsKeyword::End, AlignmentSafety::Safe) => "SafeEnd",
524 (AlignItemsKeyword::FlexStart, AlignmentSafety::Safe) => "SafeFlexStart",
525 (AlignItemsKeyword::FlexEnd, AlignmentSafety::Safe) => "SafeFlexEnd",
526 (AlignItemsKeyword::SelfStart, AlignmentSafety::Safe) => "SafeSelfStart",
527 (AlignItemsKeyword::SelfEnd, AlignmentSafety::Safe) => "SafeSelfEnd",
528 (AlignItemsKeyword::Center, AlignmentSafety::Safe) => "SafeCenter",
529 };
530 serializer.serialize_str(name)
531 }
532}
533
534#[cfg(feature = "serde")]
535impl<'de> serde::Deserialize<'de> for AlignItems {
536 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
537 struct AlignItemsVisitor;
538 impl<'de> serde::de::Visitor<'de> for AlignItemsVisitor {
539 type Value = AlignItems;
540 fn expecting(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
541 fmt.write_str("an AlignItems variant tag string")
542 }
543 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
544 Ok(match v {
545 "Normal" => AlignItems::NORMAL,
546 "Start" => AlignItems::START,
547 "End" => AlignItems::END,
548 "FlexStart" => AlignItems::FLEX_START,
549 "FlexEnd" => AlignItems::FLEX_END,
550 "SelfStart" => AlignItems::SELF_START,
551 "SelfEnd" => AlignItems::SELF_END,
552 "Center" => AlignItems::CENTER,
553 "Baseline" => AlignItems::BASELINE,
554 "Stretch" => AlignItems::STRETCH,
555 "SafeStart" => AlignItems::SAFE_START,
556 "SafeEnd" => AlignItems::SAFE_END,
557 "SafeFlexStart" => AlignItems::SAFE_FLEX_START,
558 "SafeFlexEnd" => AlignItems::SAFE_FLEX_END,
559 "SafeSelfStart" => AlignItems::SAFE_SELF_START,
560 "SafeSelfEnd" => AlignItems::SAFE_SELF_END,
561 "SafeCenter" => AlignItems::SAFE_CENTER,
562 "UnsafeStart" => AlignItems::START.with_safety(AlignmentSafety::Unsafe),
563 "UnsafeEnd" => AlignItems::END.with_safety(AlignmentSafety::Unsafe),
564 "UnsafeFlexStart" => AlignItems::FLEX_START.with_safety(AlignmentSafety::Unsafe),
565 "UnsafeFlexEnd" => AlignItems::FLEX_END.with_safety(AlignmentSafety::Unsafe),
566 "UnsafeSelfStart" => AlignItems::SELF_START.with_safety(AlignmentSafety::Unsafe),
567 "UnsafeSelfEnd" => AlignItems::SELF_END.with_safety(AlignmentSafety::Unsafe),
568 "UnsafeCenter" => AlignItems::CENTER.with_safety(AlignmentSafety::Unsafe),
569 other => return Err(E::unknown_variant(other, ALIGN_ITEMS_NAMES)),
570 })
571 }
572 }
573 deserializer.deserialize_str(AlignItemsVisitor)
574 }
575}
576
577#[cfg(feature = "serde")]
580const ALIGN_CONTENT_NAMES: &[&str] = &[
581 "Normal",
582 "Start",
583 "End",
584 "FlexStart",
585 "FlexEnd",
586 "Center",
587 "Stretch",
588 "SpaceBetween",
589 "SpaceEvenly",
590 "SpaceAround",
591 "SafeStart",
592 "SafeEnd",
593 "SafeFlexStart",
594 "SafeFlexEnd",
595 "SafeCenter",
596 "UnsafeStart",
597 "UnsafeEnd",
598 "UnsafeFlexStart",
599 "UnsafeFlexEnd",
600 "UnsafeCenter",
601];
602
603#[cfg(feature = "serde")]
604impl serde::Serialize for AlignContent {
605 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
606 let name = match (self.keyword, self.safety) {
607 (AlignContentKeyword::Start, AlignmentSafety::Default) => "Start",
608 (AlignContentKeyword::End, AlignmentSafety::Default) => "End",
609 (AlignContentKeyword::FlexStart, AlignmentSafety::Default) => "FlexStart",
610 (AlignContentKeyword::FlexEnd, AlignmentSafety::Default) => "FlexEnd",
611 (AlignContentKeyword::Center, AlignmentSafety::Default) => "Center",
612 (AlignContentKeyword::Start, AlignmentSafety::Unsafe) => "UnsafeStart",
613 (AlignContentKeyword::End, AlignmentSafety::Unsafe) => "UnsafeEnd",
614 (AlignContentKeyword::FlexStart, AlignmentSafety::Unsafe) => "UnsafeFlexStart",
615 (AlignContentKeyword::FlexEnd, AlignmentSafety::Unsafe) => "UnsafeFlexEnd",
616 (AlignContentKeyword::Center, AlignmentSafety::Unsafe) => "UnsafeCenter",
617 (AlignContentKeyword::Normal, _) => "Normal",
618 (AlignContentKeyword::Stretch, _) => "Stretch",
619 (AlignContentKeyword::SpaceBetween, _) => "SpaceBetween",
620 (AlignContentKeyword::SpaceEvenly, _) => "SpaceEvenly",
621 (AlignContentKeyword::SpaceAround, _) => "SpaceAround",
622 (AlignContentKeyword::Start, AlignmentSafety::Safe) => "SafeStart",
623 (AlignContentKeyword::End, AlignmentSafety::Safe) => "SafeEnd",
624 (AlignContentKeyword::FlexStart, AlignmentSafety::Safe) => "SafeFlexStart",
625 (AlignContentKeyword::FlexEnd, AlignmentSafety::Safe) => "SafeFlexEnd",
626 (AlignContentKeyword::Center, AlignmentSafety::Safe) => "SafeCenter",
627 };
628 serializer.serialize_str(name)
629 }
630}
631
632#[cfg(feature = "serde")]
633impl<'de> serde::Deserialize<'de> for AlignContent {
634 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
635 struct AlignContentVisitor;
636 impl<'de> serde::de::Visitor<'de> for AlignContentVisitor {
637 type Value = AlignContent;
638 fn expecting(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
639 fmt.write_str("an AlignContent variant tag string")
640 }
641 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
642 Ok(match v {
643 "Normal" => AlignContent::NORMAL,
644 "Start" => AlignContent::START,
645 "End" => AlignContent::END,
646 "FlexStart" => AlignContent::FLEX_START,
647 "FlexEnd" => AlignContent::FLEX_END,
648 "Center" => AlignContent::CENTER,
649 "Stretch" => AlignContent::STRETCH,
650 "SpaceBetween" => AlignContent::SPACE_BETWEEN,
651 "SpaceEvenly" => AlignContent::SPACE_EVENLY,
652 "SpaceAround" => AlignContent::SPACE_AROUND,
653 "SafeStart" => AlignContent::SAFE_START,
654 "SafeEnd" => AlignContent::SAFE_END,
655 "SafeFlexStart" => AlignContent::SAFE_FLEX_START,
656 "SafeFlexEnd" => AlignContent::SAFE_FLEX_END,
657 "SafeCenter" => AlignContent::SAFE_CENTER,
658 "UnsafeStart" => AlignContent::START.with_safety(AlignmentSafety::Unsafe),
659 "UnsafeEnd" => AlignContent::END.with_safety(AlignmentSafety::Unsafe),
660 "UnsafeFlexStart" => AlignContent::FLEX_START.with_safety(AlignmentSafety::Unsafe),
661 "UnsafeFlexEnd" => AlignContent::FLEX_END.with_safety(AlignmentSafety::Unsafe),
662 "UnsafeCenter" => AlignContent::CENTER.with_safety(AlignmentSafety::Unsafe),
663 other => return Err(E::unknown_variant(other, ALIGN_CONTENT_NAMES)),
664 })
665 }
666 }
667 deserializer.deserialize_str(AlignContentVisitor)
668 }
669}
670
671#[cfg(test)]
672mod tests {
673 use super::*;
674 use core::mem::size_of;
675
676 #[test]
679 fn align_types_within_size_budget() {
680 assert!(size_of::<AlignItems>() <= 2, "AlignItems grew to {}", size_of::<AlignItems>());
681 assert!(size_of::<AlignContent>() <= 2, "AlignContent grew to {}", size_of::<AlignContent>());
682 assert!(size_of::<Option<AlignItems>>() <= 3);
683 }
684
685 #[test]
686 fn align_items_is_safe() {
687 assert!(AlignItems::SAFE_START.is_safe());
688 assert!(AlignItems::SAFE_END.is_safe());
689 assert!(AlignItems::SAFE_FLEX_START.is_safe());
690 assert!(AlignItems::SAFE_FLEX_END.is_safe());
691 assert!(AlignItems::SAFE_CENTER.is_safe());
692 assert!(!AlignItems::START.is_safe());
693 assert!(!AlignItems::END.is_safe());
694 assert!(!AlignItems::FLEX_START.is_safe());
695 assert!(!AlignItems::FLEX_END.is_safe());
696 assert!(!AlignItems::CENTER.is_safe());
697 assert!(!AlignItems::BASELINE.is_safe());
698 assert!(!AlignItems::STRETCH.is_safe());
699 assert!(AlignItems::SAFE_SELF_START.is_safe());
700 assert!(AlignItems::SAFE_SELF_END.is_safe());
701 assert!(!AlignItems::SELF_START.is_safe());
702 assert!(!AlignItems::SELF_END.is_safe());
703 assert!(!AlignItems::NORMAL.is_safe());
704 }
705
706 #[test]
707 fn align_items_keyword_strips_safe() {
708 assert_eq!(AlignItems::SAFE_START.keyword(), AlignItemsKeyword::Start);
709 assert_eq!(AlignItems::SAFE_END.keyword(), AlignItemsKeyword::End);
710 assert_eq!(AlignItems::SAFE_FLEX_START.keyword(), AlignItemsKeyword::FlexStart);
711 assert_eq!(AlignItems::SAFE_FLEX_END.keyword(), AlignItemsKeyword::FlexEnd);
712 assert_eq!(AlignItems::SAFE_CENTER.keyword(), AlignItemsKeyword::Center);
713 assert_eq!(AlignItems::SAFE_SELF_START.keyword(), AlignItemsKeyword::SelfStart);
714 assert_eq!(AlignItems::SAFE_SELF_END.keyword(), AlignItemsKeyword::SelfEnd);
715 }
716
717 #[test]
718 fn align_items_keyword_passthrough() {
719 assert_eq!(AlignItems::START.keyword(), AlignItemsKeyword::Start);
720 assert_eq!(AlignItems::STRETCH.keyword(), AlignItemsKeyword::Stretch);
721 assert_eq!(AlignItems::BASELINE.keyword(), AlignItemsKeyword::Baseline);
722 assert_eq!(AlignItems::FLEX_START.keyword(), AlignItemsKeyword::FlexStart);
723 assert_eq!(AlignItems::NORMAL.keyword(), AlignItemsKeyword::Normal);
724 }
725
726 #[test]
727 fn align_items_default_is_normal() {
728 assert_eq!(AlignItems::default(), AlignItems::NORMAL);
729 assert_eq!(AlignItemsKeyword::default(), AlignItemsKeyword::Normal);
730 assert_eq!(AlignmentSafety::default(), AlignmentSafety::Default);
731 }
732
733 #[test]
734 fn resolve_self_relative_inline_axis() {
735 use Direction::{Ltr, Rtl};
736 assert_eq!(AlignItems::SELF_START.resolve_self_relative(Ltr, Ltr, true), AlignItems::START);
738 assert_eq!(AlignItems::SELF_END.resolve_self_relative(Ltr, Ltr, true), AlignItems::END);
739 assert_eq!(AlignItems::SELF_START.resolve_self_relative(Rtl, Rtl, true), AlignItems::START);
740 assert_eq!(AlignItems::SELF_END.resolve_self_relative(Rtl, Rtl, true), AlignItems::END);
741 assert_eq!(AlignItems::SELF_START.resolve_self_relative(Ltr, Rtl, true), AlignItems::END);
743 assert_eq!(AlignItems::SELF_END.resolve_self_relative(Ltr, Rtl, true), AlignItems::START);
744 assert_eq!(AlignItems::SELF_START.resolve_self_relative(Rtl, Ltr, true), AlignItems::END);
745 assert_eq!(AlignItems::SELF_END.resolve_self_relative(Rtl, Ltr, true), AlignItems::START);
746 assert_eq!(AlignItems::SAFE_SELF_START.resolve_self_relative(Ltr, Rtl, true), AlignItems::SAFE_END);
748 assert_eq!(AlignItems::START.resolve_self_relative(Ltr, Rtl, true), AlignItems::START);
750 assert_eq!(AlignItems::FLEX_END.resolve_self_relative(Ltr, Rtl, true), AlignItems::FLEX_END);
751 assert_eq!(AlignItems::NORMAL.resolve_self_relative(Ltr, Rtl, true), AlignItems::NORMAL);
752 }
753
754 #[test]
755 fn resolve_self_relative_block_axis() {
756 use Direction::{Ltr, Rtl};
757 assert_eq!(AlignItems::SELF_START.resolve_self_relative(Ltr, Rtl, false), AlignItems::START);
759 assert_eq!(AlignItems::SELF_END.resolve_self_relative(Rtl, Ltr, false), AlignItems::END);
760 }
761
762 #[test]
763 fn align_content_is_safe() {
764 assert!(AlignContent::SAFE_START.is_safe());
765 assert!(AlignContent::SAFE_CENTER.is_safe());
766 assert!(!AlignContent::SPACE_BETWEEN.is_safe());
767 assert!(!AlignContent::STRETCH.is_safe());
768 assert!(!AlignContent::NORMAL.is_safe());
769 }
770
771 #[test]
772 fn align_content_keyword_strips_safe() {
773 assert_eq!(AlignContent::SAFE_START.keyword(), AlignContentKeyword::Start);
774 assert_eq!(AlignContent::SAFE_FLEX_END.keyword(), AlignContentKeyword::FlexEnd);
775 assert_eq!(AlignContent::SAFE_CENTER.keyword(), AlignContentKeyword::Center);
776 assert_eq!(AlignContent::SPACE_BETWEEN.keyword(), AlignContentKeyword::SpaceBetween);
777 assert_eq!(AlignContent::NORMAL.keyword(), AlignContentKeyword::Normal);
778 assert_eq!(JustifyContent::NORMAL, AlignContent::NORMAL);
779 }
780
781 #[test]
782 fn align_content_keyword_reversed_swaps_start_end() {
783 assert_eq!(AlignContentKeyword::Start.reversed(), AlignContentKeyword::End);
784 assert_eq!(AlignContentKeyword::End.reversed(), AlignContentKeyword::Start);
785 assert_eq!(AlignContentKeyword::FlexStart.reversed(), AlignContentKeyword::FlexEnd);
786 assert_eq!(AlignContentKeyword::FlexEnd.reversed(), AlignContentKeyword::FlexStart);
787 assert_eq!(AlignContentKeyword::Stretch.reversed(), AlignContentKeyword::End);
789 assert_eq!(AlignContentKeyword::Normal.reversed(), AlignContentKeyword::Normal);
790 assert_eq!(AlignContentKeyword::Center.reversed(), AlignContentKeyword::Center);
791 assert_eq!(AlignContentKeyword::SpaceBetween.reversed(), AlignContentKeyword::SpaceBetween);
792 assert_eq!(AlignContentKeyword::SpaceEvenly.reversed(), AlignContentKeyword::SpaceEvenly);
793 assert_eq!(AlignContentKeyword::SpaceAround.reversed(), AlignContentKeyword::SpaceAround);
794 }
795
796 #[cfg(feature = "parse")]
797 #[test]
798 fn parse_align_items_plain() {
799 assert_eq!("start".parse::<AlignItems>().unwrap(), AlignItems::START);
800 assert_eq!("end".parse::<AlignItems>().unwrap(), AlignItems::END);
801 assert_eq!("flex-start".parse::<AlignItems>().unwrap(), AlignItems::FLEX_START);
802 assert_eq!("flex-end".parse::<AlignItems>().unwrap(), AlignItems::FLEX_END);
803 assert_eq!("center".parse::<AlignItems>().unwrap(), AlignItems::CENTER);
804 assert_eq!("self-start".parse::<AlignItems>().unwrap(), AlignItems::SELF_START);
805 assert_eq!("self-end".parse::<AlignItems>().unwrap(), AlignItems::SELF_END);
806 assert_eq!("baseline".parse::<AlignItems>().unwrap(), AlignItems::BASELINE);
807 assert_eq!("stretch".parse::<AlignItems>().unwrap(), AlignItems::STRETCH);
808 }
809
810 #[test]
811 fn align_content_default_is_normal() {
812 assert_eq!(AlignContent::default(), AlignContent::NORMAL);
813 assert_eq!(JustifyContent::default(), JustifyContent::NORMAL);
814 }
815
816 #[cfg(feature = "parse")]
817 #[test]
818 fn parse_align_items_normal() {
819 assert_eq!("normal".parse::<AlignItems>().unwrap(), AlignItems::NORMAL);
820 assert_eq!("NORMAL".parse::<AlignItems>().unwrap(), AlignItems::NORMAL);
821 assert_eq!(AlignItems::NORMAL.safety, AlignmentSafety::Default);
822 assert!("auto".parse::<AlignSelf>().is_err());
824 }
825
826 #[cfg(feature = "parse")]
827 #[test]
828 fn parse_align_items_safe() {
829 assert_eq!("safe start".parse::<AlignItems>().unwrap(), AlignItems::SAFE_START);
830 assert_eq!("safe end".parse::<AlignItems>().unwrap(), AlignItems::SAFE_END);
831 assert_eq!("safe flex-start".parse::<AlignItems>().unwrap(), AlignItems::SAFE_FLEX_START);
832 assert_eq!("safe flex-end".parse::<AlignItems>().unwrap(), AlignItems::SAFE_FLEX_END);
833 assert_eq!("safe self-start".parse::<AlignItems>().unwrap(), AlignItems::SAFE_SELF_START);
834 assert_eq!("safe self-end".parse::<AlignItems>().unwrap(), AlignItems::SAFE_SELF_END);
835 assert_eq!("safe center".parse::<AlignItems>().unwrap(), AlignItems::SAFE_CENTER);
836 }
837
838 #[cfg(feature = "parse")]
839 #[test]
840 fn parse_align_items_safe_case_insensitive() {
841 assert_eq!("SAFE Start".parse::<AlignItems>().unwrap(), AlignItems::SAFE_START);
842 assert_eq!("Safe FLEX-end".parse::<AlignItems>().unwrap(), AlignItems::SAFE_FLEX_END);
843 }
844
845 #[cfg(feature = "parse")]
846 #[test]
847 fn parse_align_items_unsafe() {
848 let unsafe_ = |keyword| AlignItems { keyword, safety: AlignmentSafety::Unsafe };
849 assert_eq!("unsafe start".parse::<AlignItems>().unwrap(), unsafe_(AlignItemsKeyword::Start));
850 assert_eq!("unsafe end".parse::<AlignItems>().unwrap(), unsafe_(AlignItemsKeyword::End));
851 assert_eq!("unsafe self-start".parse::<AlignItems>().unwrap(), unsafe_(AlignItemsKeyword::SelfStart));
852 assert_eq!("unsafe self-end".parse::<AlignItems>().unwrap(), unsafe_(AlignItemsKeyword::SelfEnd));
853 assert_eq!("unsafe center".parse::<AlignItems>().unwrap(), unsafe_(AlignItemsKeyword::Center));
854 assert_eq!(AlignItems::START.safety, AlignmentSafety::Default);
856 }
857
858 #[cfg(feature = "parse")]
859 #[test]
860 fn parse_align_items_rejects_invalid_safe_combos() {
861 assert!("safe stretch".parse::<AlignItems>().is_err());
862 assert!("safe baseline".parse::<AlignItems>().is_err());
863 assert!("safe space-between".parse::<AlignItems>().is_err());
864 assert!("safe".parse::<AlignItems>().is_err());
865 assert!("safe garbage".parse::<AlignItems>().is_err());
866 assert!("unsafe stretch".parse::<AlignItems>().is_err());
867 assert!("unsafe baseline".parse::<AlignItems>().is_err());
868 assert!("safe normal".parse::<AlignItems>().is_err());
869 assert!("safe auto".parse::<AlignItems>().is_err());
870 assert!("unsafe normal".parse::<AlignItems>().is_err());
871 assert!("unsafe auto".parse::<AlignItems>().is_err());
872 }
873
874 #[cfg(feature = "parse")]
875 #[test]
876 fn parse_align_content_plain() {
877 assert_eq!("normal".parse::<AlignContent>().unwrap(), AlignContent::NORMAL);
878 assert_eq!("Normal".parse::<JustifyContent>().unwrap(), JustifyContent::NORMAL);
879 assert_eq!(AlignContent::NORMAL.safety, AlignmentSafety::Default);
880 assert_eq!("start".parse::<AlignContent>().unwrap(), AlignContent::START);
881 assert_eq!("space-between".parse::<AlignContent>().unwrap(), AlignContent::SPACE_BETWEEN);
882 assert_eq!("space-evenly".parse::<AlignContent>().unwrap(), AlignContent::SPACE_EVENLY);
883 assert_eq!("space-around".parse::<AlignContent>().unwrap(), AlignContent::SPACE_AROUND);
884 assert_eq!("stretch".parse::<AlignContent>().unwrap(), AlignContent::STRETCH);
885 }
886
887 #[cfg(feature = "parse")]
888 #[test]
889 fn parse_align_content_safe() {
890 assert_eq!("safe start".parse::<AlignContent>().unwrap(), AlignContent::SAFE_START);
891 assert_eq!("safe end".parse::<AlignContent>().unwrap(), AlignContent::SAFE_END);
892 assert_eq!("safe flex-start".parse::<AlignContent>().unwrap(), AlignContent::SAFE_FLEX_START);
893 assert_eq!("safe flex-end".parse::<AlignContent>().unwrap(), AlignContent::SAFE_FLEX_END);
894 assert_eq!("safe center".parse::<AlignContent>().unwrap(), AlignContent::SAFE_CENTER);
895 }
896
897 #[cfg(feature = "parse")]
898 #[test]
899 fn parse_align_content_unsafe() {
900 let unsafe_ = |keyword| AlignContent { keyword, safety: AlignmentSafety::Unsafe };
901 assert_eq!("unsafe start".parse::<AlignContent>().unwrap(), unsafe_(AlignContentKeyword::Start));
902 assert_eq!("unsafe flex-end".parse::<AlignContent>().unwrap(), unsafe_(AlignContentKeyword::FlexEnd));
903 }
904
905 #[cfg(feature = "parse")]
906 #[test]
907 fn parse_align_content_rejects_invalid_safe_combos() {
908 assert!("safe stretch".parse::<AlignContent>().is_err());
909 assert!("safe space-between".parse::<AlignContent>().is_err());
910 assert!("safe space-evenly".parse::<AlignContent>().is_err());
911 assert!("safe space-around".parse::<AlignContent>().is_err());
912 assert!("safe".parse::<AlignContent>().is_err());
913 assert!("unsafe stretch".parse::<AlignContent>().is_err());
914 assert!("unsafe space-between".parse::<AlignContent>().is_err());
915 assert!("safe normal".parse::<AlignContent>().is_err());
916 assert!("unsafe normal".parse::<AlignContent>().is_err());
917 assert!("auto".parse::<AlignContent>().is_err());
918 }
919
920 #[cfg(feature = "serde")]
921 #[test]
922 fn serde_align_items_round_trip() {
923 let cases = [
924 (AlignItems::NORMAL, "\"Normal\""),
925 (AlignItems::START, "\"Start\""),
926 (AlignItems::END, "\"End\""),
927 (AlignItems::FLEX_START, "\"FlexStart\""),
928 (AlignItems::FLEX_END, "\"FlexEnd\""),
929 (AlignItems::CENTER, "\"Center\""),
930 (AlignItems::BASELINE, "\"Baseline\""),
931 (AlignItems::STRETCH, "\"Stretch\""),
932 (AlignItems::SAFE_START, "\"SafeStart\""),
933 (AlignItems::SAFE_END, "\"SafeEnd\""),
934 (AlignItems::SAFE_FLEX_START, "\"SafeFlexStart\""),
935 (AlignItems::SAFE_FLEX_END, "\"SafeFlexEnd\""),
936 (AlignItems::SAFE_CENTER, "\"SafeCenter\""),
937 (AlignItems::SELF_START, "\"SelfStart\""),
938 (AlignItems::SELF_END, "\"SelfEnd\""),
939 (AlignItems::SAFE_SELF_START, "\"SafeSelfStart\""),
940 (AlignItems::SAFE_SELF_END, "\"SafeSelfEnd\""),
941 ];
942 for (value, expected) in cases {
943 let serialized = serde_json::to_string(&value).unwrap();
944 assert_eq!(serialized, expected, "serialize {:?}", value);
945 let deserialized: AlignItems = serde_json::from_str(expected).unwrap();
946 assert_eq!(deserialized, value, "round-trip {:?}", value);
947 }
948 assert!(serde_json::from_str::<AlignItems>("\"NotAVariant\"").is_err());
949 }
950
951 #[cfg(feature = "serde")]
952 #[test]
953 fn serde_align_content_round_trip() {
954 let cases = [
955 (AlignContent::NORMAL, "\"Normal\""),
956 (AlignContent::START, "\"Start\""),
957 (AlignContent::END, "\"End\""),
958 (AlignContent::FLEX_START, "\"FlexStart\""),
959 (AlignContent::FLEX_END, "\"FlexEnd\""),
960 (AlignContent::CENTER, "\"Center\""),
961 (AlignContent::STRETCH, "\"Stretch\""),
962 (AlignContent::SPACE_BETWEEN, "\"SpaceBetween\""),
963 (AlignContent::SPACE_EVENLY, "\"SpaceEvenly\""),
964 (AlignContent::SPACE_AROUND, "\"SpaceAround\""),
965 (AlignContent::SAFE_START, "\"SafeStart\""),
966 (AlignContent::SAFE_END, "\"SafeEnd\""),
967 (AlignContent::SAFE_FLEX_START, "\"SafeFlexStart\""),
968 (AlignContent::SAFE_FLEX_END, "\"SafeFlexEnd\""),
969 (AlignContent::SAFE_CENTER, "\"SafeCenter\""),
970 ];
971 for (value, expected) in cases {
972 let serialized = serde_json::to_string(&value).unwrap();
973 assert_eq!(serialized, expected, "serialize {:?}", value);
974 let deserialized: AlignContent = serde_json::from_str(expected).unwrap();
975 assert_eq!(deserialized, value, "round-trip {:?}", value);
976 }
977 assert!(serde_json::from_str::<AlignContent>("\"NotAVariant\"").is_err());
978 }
979}