1use super::{
3 AlignContent, AlignItems, AlignSelf, CompactLength, CoreStyle, Dimension, JustifyContent, LengthPercentage,
4 LengthPercentageAuto, Style,
5};
6use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
7use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size};
8use crate::style_helpers::*;
9use crate::util::sys::GridTrackVec;
10use core::borrow::Borrow;
11use core::cmp::{max, min};
12use core::convert::Infallible;
13
14pub trait GridContainerStyle: CoreStyle {
16 type TemplateTrackList<'a>: Borrow<[TrackSizingFunction]>
18 where
19 Self: 'a;
20 type AutoTrackList<'a>: Borrow<[NonRepeatedTrackSizingFunction]>
22 where
23 Self: 'a;
24
25 fn grid_template_rows(&self) -> Self::TemplateTrackList<'_>;
30 fn grid_template_columns(&self) -> Self::TemplateTrackList<'_>;
32 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_>;
34 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_>;
36
37 #[inline(always)]
39 fn grid_auto_flow(&self) -> GridAutoFlow {
40 Style::DEFAULT.grid_auto_flow
41 }
42
43 #[inline(always)]
45 fn gap(&self) -> Size<LengthPercentage> {
46 Style::DEFAULT.gap
47 }
48
49 #[inline(always)]
53 fn align_content(&self) -> Option<AlignContent> {
54 Style::DEFAULT.align_content
55 }
56 #[inline(always)]
58 fn justify_content(&self) -> Option<JustifyContent> {
59 Style::DEFAULT.justify_content
60 }
61 #[inline(always)]
63 fn align_items(&self) -> Option<AlignItems> {
64 Style::DEFAULT.align_items
65 }
66 #[inline(always)]
68 fn justify_items(&self) -> Option<AlignItems> {
69 Style::DEFAULT.justify_items
70 }
71
72 #[inline(always)]
74 fn grid_template_tracks(&self, axis: AbsoluteAxis) -> Self::TemplateTrackList<'_> {
75 match axis {
76 AbsoluteAxis::Horizontal => self.grid_template_columns(),
77 AbsoluteAxis::Vertical => self.grid_template_rows(),
78 }
79 }
80
81 #[inline(always)]
83 fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
84 match axis {
85 AbstractAxis::Inline => self.justify_content().unwrap_or(AlignContent::Stretch),
86 AbstractAxis::Block => self.align_content().unwrap_or(AlignContent::Stretch),
87 }
88 }
89}
90
91pub trait GridItemStyle: CoreStyle {
93 #[inline(always)]
95 fn grid_row(&self) -> Line<GridPlacement> {
96 Style::DEFAULT.grid_row
97 }
98 #[inline(always)]
100 fn grid_column(&self) -> Line<GridPlacement> {
101 Style::DEFAULT.grid_column
102 }
103
104 #[inline(always)]
107 fn align_self(&self) -> Option<AlignSelf> {
108 Style::DEFAULT.align_self
109 }
110 #[inline(always)]
113 fn justify_self(&self) -> Option<AlignSelf> {
114 Style::DEFAULT.justify_self
115 }
116
117 #[inline(always)]
119 fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement> {
120 match axis {
121 AbsoluteAxis::Horizontal => self.grid_column(),
122 AbsoluteAxis::Vertical => self.grid_row(),
123 }
124 }
125}
126
127#[derive(Copy, Clone, PartialEq, Eq, Debug)]
135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136pub enum GridAutoFlow {
137 Row,
139 Column,
141 RowDense,
143 ColumnDense,
145}
146
147impl Default for GridAutoFlow {
148 fn default() -> Self {
149 Self::Row
150 }
151}
152
153impl GridAutoFlow {
154 pub fn is_dense(&self) -> bool {
157 match self {
158 Self::Row | Self::Column => false,
159 Self::RowDense | Self::ColumnDense => true,
160 }
161 }
162
163 pub fn primary_axis(&self) -> AbsoluteAxis {
166 match self {
167 Self::Row | Self::RowDense => AbsoluteAxis::Horizontal,
168 Self::Column | Self::ColumnDense => AbsoluteAxis::Vertical,
169 }
170 }
171}
172
173#[derive(Copy, Clone, PartialEq, Eq, Debug)]
181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
182pub enum GenericGridPlacement<LineType: GridCoordinate> {
183 Auto,
185 Line(LineType),
187 Span(u16),
189}
190
191pub(crate) type OriginZeroGridPlacement = GenericGridPlacement<OriginZeroLine>;
193
194pub type GridPlacement = GenericGridPlacement<GridLine>;
200impl TaffyAuto for GridPlacement {
201 const AUTO: Self = Self::Auto;
202}
203impl TaffyGridLine for GridPlacement {
204 fn from_line_index(index: i16) -> Self {
205 GridPlacement::Line(GridLine::from(index))
206 }
207}
208impl TaffyGridLine for Line<GridPlacement> {
209 fn from_line_index(index: i16) -> Self {
210 Line { start: GridPlacement::from_line_index(index), end: GridPlacement::Auto }
211 }
212}
213impl TaffyGridSpan for GridPlacement {
214 fn from_span(span: u16) -> Self {
215 GridPlacement::Span(span)
216 }
217}
218impl TaffyGridSpan for Line<GridPlacement> {
219 fn from_span(span: u16) -> Self {
220 Line { start: GridPlacement::from_span(span), end: GridPlacement::Auto }
221 }
222}
223
224impl Default for GridPlacement {
225 fn default() -> Self {
226 Self::Auto
227 }
228}
229
230impl GridPlacement {
231 pub fn into_origin_zero_placement(self, explicit_track_count: u16) -> OriginZeroGridPlacement {
233 match self {
234 Self::Auto => OriginZeroGridPlacement::Auto,
235 Self::Span(span) => OriginZeroGridPlacement::Span(span),
236 Self::Line(line) => match line.as_i16() {
239 0 => OriginZeroGridPlacement::Auto,
240 _ => OriginZeroGridPlacement::Line(line.into_origin_zero_line(explicit_track_count)),
241 },
242 }
243 }
244}
245
246impl<T: GridCoordinate> Line<GenericGridPlacement<T>> {
247 pub fn indefinite_span(&self) -> u16 {
250 use GenericGridPlacement as GP;
251 match (self.start, self.end) {
252 (GP::Line(_), GP::Auto) => 1,
253 (GP::Auto, GP::Line(_)) => 1,
254 (GP::Auto, GP::Auto) => 1,
255 (GP::Line(_), GP::Span(span)) => span,
256 (GP::Span(span), GP::Line(_)) => span,
257 (GP::Span(span), GP::Auto) => span,
258 (GP::Auto, GP::Span(span)) => span,
259 (GP::Span(span), GP::Span(_)) => span,
260 (GP::Line(_), GP::Line(_)) => panic!("indefinite_span should only be called on indefinite grid tracks"),
261 }
262 }
263}
264
265impl Line<GridPlacement> {
266 #[inline]
267 pub fn is_definite(&self) -> bool {
271 match (self.start, self.end) {
272 (GenericGridPlacement::Line(line), _) if line.as_i16() != 0 => true,
273 (_, GenericGridPlacement::Line(line)) if line.as_i16() != 0 => true,
274 _ => false,
275 }
276 }
277
278 pub fn into_origin_zero(&self, explicit_track_count: u16) -> Line<OriginZeroGridPlacement> {
280 Line {
281 start: self.start.into_origin_zero_placement(explicit_track_count),
282 end: self.end.into_origin_zero_placement(explicit_track_count),
283 }
284 }
285}
286
287impl Line<OriginZeroGridPlacement> {
288 #[inline]
289 pub fn is_definite(&self) -> bool {
292 matches!((self.start, self.end), (GenericGridPlacement::Line(_), _) | (_, GenericGridPlacement::Line(_)))
293 }
294
295 pub fn resolve_definite_grid_lines(&self) -> Line<OriginZeroLine> {
298 use OriginZeroGridPlacement as GP;
299 match (self.start, self.end) {
300 (GP::Line(line1), GP::Line(line2)) => {
301 if line1 == line2 {
302 Line { start: line1, end: line1 + 1 }
303 } else {
304 Line { start: min(line1, line2), end: max(line1, line2) }
305 }
306 }
307 (GP::Line(line), GP::Span(span)) => Line { start: line, end: line + span },
308 (GP::Line(line), GP::Auto) => Line { start: line, end: line + 1 },
309 (GP::Span(span), GP::Line(line)) => Line { start: line - span, end: line },
310 (GP::Auto, GP::Line(line)) => Line { start: line - 1, end: line },
311 _ => panic!("resolve_definite_grid_tracks should only be called on definite grid tracks"),
312 }
313 }
314
315 pub fn resolve_absolutely_positioned_grid_tracks(&self) -> Line<Option<OriginZeroLine>> {
325 use OriginZeroGridPlacement as GP;
326 match (self.start, self.end) {
327 (GP::Line(track1), GP::Line(track2)) => {
328 if track1 == track2 {
329 Line { start: Some(track1), end: Some(track1 + 1) }
330 } else {
331 Line { start: Some(min(track1, track2)), end: Some(max(track1, track2)) }
332 }
333 }
334 (GP::Line(track), GP::Span(span)) => Line { start: Some(track), end: Some(track + span) },
335 (GP::Line(track), GP::Auto) => Line { start: Some(track), end: None },
336 (GP::Span(span), GP::Line(track)) => Line { start: Some(track - span), end: Some(track) },
337 (GP::Auto, GP::Line(track)) => Line { start: None, end: Some(track) },
338 _ => Line { start: None, end: None },
339 }
340 }
341
342 pub fn resolve_indefinite_grid_tracks(&self, start: OriginZeroLine) -> Line<OriginZeroLine> {
345 use OriginZeroGridPlacement as GP;
346 match (self.start, self.end) {
347 (GP::Auto, GP::Auto) => Line { start, end: start + 1 },
348 (GP::Span(span), GP::Auto) => Line { start, end: start + span },
349 (GP::Auto, GP::Span(span)) => Line { start, end: start + span },
350 (GP::Span(span), GP::Span(_)) => Line { start, end: start + span },
351 _ => panic!("resolve_indefinite_grid_tracks should only be called on indefinite grid tracks"),
352 }
353 }
354}
355
356impl Default for Line<GridPlacement> {
358 fn default() -> Self {
359 Line { start: GridPlacement::Auto, end: GridPlacement::Auto }
360 }
361}
362
363#[derive(Copy, Clone, PartialEq, Debug)]
369#[cfg_attr(feature = "serde", derive(Serialize))]
370pub struct MaxTrackSizingFunction(pub(crate) CompactLength);
371impl TaffyZero for MaxTrackSizingFunction {
372 const ZERO: Self = Self(CompactLength::ZERO);
373}
374impl TaffyAuto for MaxTrackSizingFunction {
375 const AUTO: Self = Self(CompactLength::AUTO);
376}
377impl TaffyMinContent for MaxTrackSizingFunction {
378 const MIN_CONTENT: Self = Self(CompactLength::MIN_CONTENT);
379}
380impl TaffyMaxContent for MaxTrackSizingFunction {
381 const MAX_CONTENT: Self = Self(CompactLength::MAX_CONTENT);
382}
383impl FromLength for MaxTrackSizingFunction {
384 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
385 Self::length(value.into())
386 }
387}
388impl FromPercent for MaxTrackSizingFunction {
389 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
390 Self::percent(value.into())
391 }
392}
393impl TaffyFitContent for MaxTrackSizingFunction {
394 fn fit_content(argument: LengthPercentage) -> Self {
395 Self(CompactLength::fit_content(argument))
396 }
397}
398impl FromFr for MaxTrackSizingFunction {
399 fn from_fr<Input: Into<f32> + Copy>(value: Input) -> Self {
400 Self::fr(value.into())
401 }
402}
403impl From<LengthPercentage> for MaxTrackSizingFunction {
404 fn from(input: LengthPercentage) -> Self {
405 Self(input.0)
406 }
407}
408impl From<LengthPercentageAuto> for MaxTrackSizingFunction {
409 fn from(input: LengthPercentageAuto) -> Self {
410 Self(input.0)
411 }
412}
413impl From<Dimension> for MaxTrackSizingFunction {
414 fn from(input: Dimension) -> Self {
415 Self(input.0)
416 }
417}
418impl From<MinTrackSizingFunction> for MaxTrackSizingFunction {
419 fn from(input: MinTrackSizingFunction) -> Self {
420 Self(input.0)
421 }
422}
423#[cfg(feature = "serde")]
424impl<'de> serde::Deserialize<'de> for MaxTrackSizingFunction {
425 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
426 where
427 D: serde::Deserializer<'de>,
428 {
429 let inner = CompactLength::deserialize(deserializer)?;
430 if matches!(
432 inner.tag(),
433 CompactLength::LENGTH_TAG
434 | CompactLength::PERCENT_TAG
435 | CompactLength::AUTO_TAG
436 | CompactLength::MIN_CONTENT_TAG
437 | CompactLength::MAX_CONTENT_TAG
438 | CompactLength::FIT_CONTENT_PX_TAG
439 | CompactLength::FIT_CONTENT_PERCENT_TAG
440 | CompactLength::FR_TAG
441 ) {
442 Ok(Self(inner))
443 } else {
444 Err(serde::de::Error::custom("Invalid tag"))
445 }
446 }
447}
448
449impl MaxTrackSizingFunction {
450 #[inline(always)]
453 pub const fn length(val: f32) -> Self {
454 Self(CompactLength::length(val))
455 }
456
457 #[inline(always)]
461 pub const fn percent(val: f32) -> Self {
462 Self(CompactLength::percent(val))
463 }
464
465 #[inline(always)]
468 pub const fn auto() -> Self {
469 Self(CompactLength::auto())
470 }
471
472 #[inline(always)]
475 pub const fn min_content() -> Self {
476 Self(CompactLength::min_content())
477 }
478
479 #[inline(always)]
482 pub const fn max_content() -> Self {
483 Self(CompactLength::max_content())
484 }
485
486 #[inline(always)]
496 pub const fn fit_content_px(limit: f32) -> Self {
497 Self(CompactLength::fit_content_px(limit))
498 }
499
500 #[inline(always)]
510 pub const fn fit_content_percent(limit: f32) -> Self {
511 Self(CompactLength::fit_content_percent(limit))
512 }
513
514 #[inline(always)]
518 pub const fn fr(val: f32) -> Self {
519 Self(CompactLength::fr(val))
520 }
521
522 #[inline]
527 #[cfg(feature = "calc")]
528 pub fn calc(ptr: *const ()) -> Self {
529 Self(CompactLength::calc(ptr))
530 }
531
532 #[allow(unsafe_code)]
536 pub unsafe fn from_raw(val: CompactLength) -> Self {
537 Self(val)
538 }
539
540 pub fn into_raw(self) -> CompactLength {
542 self.0
543 }
544
545 #[inline(always)]
547 pub fn is_intrinsic(&self) -> bool {
548 self.0.is_intrinsic()
549 }
550
551 #[inline(always)]
555 pub fn is_max_content_alike(&self) -> bool {
556 self.0.is_max_content_alike()
557 }
558
559 #[inline(always)]
561 pub fn is_fr(&self) -> bool {
562 self.0.is_fr()
563 }
564
565 #[inline(always)]
567 pub fn is_auto(&self) -> bool {
568 self.0.is_auto()
569 }
570
571 #[inline(always)]
573 pub fn is_min_content(&self) -> bool {
574 self.0.is_min_content()
575 }
576
577 #[inline(always)]
579 pub fn is_max_content(&self) -> bool {
580 self.0.is_max_content()
581 }
582
583 #[inline(always)]
585 pub fn is_fit_content(&self) -> bool {
586 self.0.is_fit_content()
587 }
588
589 #[inline(always)]
591 pub fn is_max_or_fit_content(&self) -> bool {
592 self.0.is_max_or_fit_content()
593 }
594
595 #[inline(always)]
597 pub fn has_definite_value(self, parent_size: Option<f32>) -> bool {
598 match self.0.tag() {
599 CompactLength::LENGTH_TAG => true,
600 CompactLength::PERCENT_TAG => parent_size.is_some(),
601 #[cfg(feature = "calc")]
602 _ if self.0.is_calc() => parent_size.is_some(),
603 _ => false,
604 }
605 }
606
607 #[inline(always)]
611 pub fn definite_value(
612 self,
613 parent_size: Option<f32>,
614 calc_resolver: impl Fn(*const (), f32) -> f32,
615 ) -> Option<f32> {
616 match self.0.tag() {
617 CompactLength::LENGTH_TAG => Some(self.0.value()),
618 CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
619 #[cfg(feature = "calc")]
620 _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
621 _ => None,
622 }
623 }
624
625 #[inline(always)]
632 pub fn definite_limit(
633 self,
634 parent_size: Option<f32>,
635 calc_resolver: impl Fn(*const (), f32) -> f32,
636 ) -> Option<f32> {
637 match self.0.tag() {
638 CompactLength::FIT_CONTENT_PX_TAG => Some(self.0.value()),
639 CompactLength::FIT_CONTENT_PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
640 _ => self.definite_value(parent_size, calc_resolver),
641 }
642 }
643
644 #[inline(always)]
647 pub fn resolved_percentage_size(
648 self,
649 parent_size: f32,
650 calc_resolver: impl Fn(*const (), f32) -> f32,
651 ) -> Option<f32> {
652 self.0.resolved_percentage_size(parent_size, calc_resolver)
653 }
654
655 #[inline(always)]
657 pub fn uses_percentage(self) -> bool {
658 self.0.uses_percentage()
659 }
660}
661
662#[derive(Copy, Clone, PartialEq, Debug)]
668#[cfg_attr(feature = "serde", derive(Serialize))]
669pub struct MinTrackSizingFunction(pub(crate) CompactLength);
670impl TaffyZero for MinTrackSizingFunction {
671 const ZERO: Self = Self(CompactLength::ZERO);
672}
673impl TaffyAuto for MinTrackSizingFunction {
674 const AUTO: Self = Self(CompactLength::AUTO);
675}
676impl TaffyMinContent for MinTrackSizingFunction {
677 const MIN_CONTENT: Self = Self(CompactLength::MIN_CONTENT);
678}
679impl TaffyMaxContent for MinTrackSizingFunction {
680 const MAX_CONTENT: Self = Self(CompactLength::MAX_CONTENT);
681}
682impl FromLength for MinTrackSizingFunction {
683 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
684 Self::length(value.into())
685 }
686}
687impl FromPercent for MinTrackSizingFunction {
688 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
689 Self::percent(value.into())
690 }
691}
692impl From<LengthPercentage> for MinTrackSizingFunction {
693 fn from(input: LengthPercentage) -> Self {
694 Self(input.0)
695 }
696}
697impl From<LengthPercentageAuto> for MinTrackSizingFunction {
698 fn from(input: LengthPercentageAuto) -> Self {
699 Self(input.0)
700 }
701}
702impl From<Dimension> for MinTrackSizingFunction {
703 fn from(input: Dimension) -> Self {
704 Self(input.0)
705 }
706}
707#[cfg(feature = "serde")]
708impl<'de> serde::Deserialize<'de> for MinTrackSizingFunction {
709 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
710 where
711 D: serde::Deserializer<'de>,
712 {
713 let inner = CompactLength::deserialize(deserializer)?;
714 if matches!(
716 inner.tag(),
717 CompactLength::LENGTH_TAG
718 | CompactLength::PERCENT_TAG
719 | CompactLength::AUTO_TAG
720 | CompactLength::MIN_CONTENT_TAG
721 | CompactLength::MAX_CONTENT_TAG
722 | CompactLength::FIT_CONTENT_PX_TAG
723 | CompactLength::FIT_CONTENT_PERCENT_TAG
724 ) {
725 Ok(Self(inner))
726 } else {
727 Err(serde::de::Error::custom("Invalid tag"))
728 }
729 }
730}
731
732impl MinTrackSizingFunction {
733 #[inline(always)]
736 pub const fn length(val: f32) -> Self {
737 Self(CompactLength::length(val))
738 }
739
740 #[inline(always)]
744 pub const fn percent(val: f32) -> Self {
745 Self(CompactLength::percent(val))
746 }
747
748 #[inline(always)]
751 pub const fn auto() -> Self {
752 Self(CompactLength::auto())
753 }
754
755 #[inline(always)]
758 pub const fn min_content() -> Self {
759 Self(CompactLength::min_content())
760 }
761
762 #[inline(always)]
765 pub const fn max_content() -> Self {
766 Self(CompactLength::max_content())
767 }
768
769 #[inline]
774 #[cfg(feature = "calc")]
775 pub fn calc(ptr: *const ()) -> Self {
776 Self(CompactLength::calc(ptr))
777 }
778
779 #[allow(unsafe_code)]
783 pub unsafe fn from_raw(val: CompactLength) -> Self {
784 Self(val)
785 }
786
787 pub fn into_raw(self) -> CompactLength {
789 self.0
790 }
791
792 #[inline(always)]
794 pub fn is_intrinsic(&self) -> bool {
795 self.0.is_intrinsic()
796 }
797
798 #[inline(always)]
800 pub fn is_min_or_max_content(&self) -> bool {
801 self.0.is_min_or_max_content()
802 }
803
804 #[inline(always)]
806 pub fn is_fr(&self) -> bool {
807 self.0.is_fr()
808 }
809
810 #[inline(always)]
812 pub fn is_auto(&self) -> bool {
813 self.0.is_auto()
814 }
815
816 #[inline(always)]
818 pub fn is_min_content(&self) -> bool {
819 self.0.is_min_content()
820 }
821
822 #[inline(always)]
824 pub fn is_max_content(&self) -> bool {
825 self.0.is_max_content()
826 }
827
828 #[inline(always)]
832 pub fn definite_value(
833 self,
834 parent_size: Option<f32>,
835 calc_resolver: impl Fn(*const (), f32) -> f32,
836 ) -> Option<f32> {
837 match self.0.tag() {
838 CompactLength::LENGTH_TAG => Some(self.0.value()),
839 CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
840 #[cfg(feature = "calc")]
841 _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
842 _ => None,
843 }
844 }
845
846 #[inline(always)]
849 pub fn resolved_percentage_size(
850 self,
851 parent_size: f32,
852 calc_resolver: impl Fn(*const (), f32) -> f32,
853 ) -> Option<f32> {
854 self.0.resolved_percentage_size(parent_size, calc_resolver)
855 }
856
857 #[inline(always)]
859 pub fn uses_percentage(self) -> bool {
860 #[cfg(feature = "calc")]
861 {
862 matches!(self.0.tag(), CompactLength::PERCENT_TAG) || self.0.is_calc()
863 }
864 #[cfg(not(feature = "calc"))]
865 {
866 matches!(self.0.tag(), CompactLength::PERCENT_TAG)
867 }
868 }
869}
870
871pub type NonRepeatedTrackSizingFunction = MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>;
876impl NonRepeatedTrackSizingFunction {
877 pub fn min_sizing_function(&self) -> MinTrackSizingFunction {
879 self.min
880 }
881 pub fn max_sizing_function(&self) -> MaxTrackSizingFunction {
883 self.max
884 }
885 pub fn has_fixed_component(&self) -> bool {
887 self.min.0.is_length_or_percentage() || self.max.0.is_length_or_percentage()
888 }
889}
890impl TaffyAuto for NonRepeatedTrackSizingFunction {
891 const AUTO: Self = Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::AUTO };
892}
893impl TaffyMinContent for NonRepeatedTrackSizingFunction {
894 const MIN_CONTENT: Self =
895 Self { min: MinTrackSizingFunction::MIN_CONTENT, max: MaxTrackSizingFunction::MIN_CONTENT };
896}
897impl TaffyMaxContent for NonRepeatedTrackSizingFunction {
898 const MAX_CONTENT: Self =
899 Self { min: MinTrackSizingFunction::MAX_CONTENT, max: MaxTrackSizingFunction::MAX_CONTENT };
900}
901impl TaffyFitContent for NonRepeatedTrackSizingFunction {
902 fn fit_content(argument: LengthPercentage) -> Self {
903 Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::fit_content(argument) }
904 }
905}
906impl TaffyZero for NonRepeatedTrackSizingFunction {
907 const ZERO: Self = Self { min: MinTrackSizingFunction::ZERO, max: MaxTrackSizingFunction::ZERO };
908}
909impl FromLength for NonRepeatedTrackSizingFunction {
910 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
911 Self { min: MinTrackSizingFunction::from_length(value), max: MaxTrackSizingFunction::from_length(value) }
912 }
913}
914impl FromPercent for NonRepeatedTrackSizingFunction {
915 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
916 Self { min: MinTrackSizingFunction::from_percent(percent), max: MaxTrackSizingFunction::from_percent(percent) }
917 }
918}
919impl FromFr for NonRepeatedTrackSizingFunction {
920 fn from_fr<Input: Into<f32> + Copy>(flex: Input) -> Self {
921 Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::from_fr(flex) }
922 }
923}
924impl From<LengthPercentage> for NonRepeatedTrackSizingFunction {
925 fn from(input: LengthPercentage) -> Self {
926 Self { min: input.into(), max: input.into() }
927 }
928}
929impl From<LengthPercentageAuto> for NonRepeatedTrackSizingFunction {
930 fn from(input: LengthPercentageAuto) -> Self {
931 Self { min: input.into(), max: input.into() }
932 }
933}
934impl From<Dimension> for NonRepeatedTrackSizingFunction {
935 fn from(input: Dimension) -> Self {
936 Self { min: input.into(), max: input.into() }
937 }
938}
939
940#[derive(Clone, Copy, Debug, PartialEq, Eq)]
945#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
946pub enum GridTrackRepetition {
947 AutoFill,
950 AutoFit,
953 Count(u16),
955}
956impl TryFrom<u16> for GridTrackRepetition {
957 type Error = Infallible;
958 fn try_from(value: u16) -> Result<Self, Infallible> {
959 Ok(Self::Count(value))
960 }
961}
962
963#[derive(Debug)]
966pub struct InvalidStringRepetitionValue;
967#[cfg(feature = "std")]
968impl std::error::Error for InvalidStringRepetitionValue {}
969impl core::fmt::Display for InvalidStringRepetitionValue {
970 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
971 f.write_str("&str can only be converted to GridTrackRepetition if it's value is 'auto-fit' or 'auto-fill'")
972 }
973}
974impl TryFrom<&str> for GridTrackRepetition {
975 type Error = InvalidStringRepetitionValue;
976 fn try_from(value: &str) -> Result<Self, InvalidStringRepetitionValue> {
977 match value {
978 "auto-fit" => Ok(Self::AutoFit),
979 "auto-fill" => Ok(Self::AutoFill),
980 _ => Err(InvalidStringRepetitionValue),
981 }
982 }
983}
984
985#[derive(Clone, PartialEq, Debug)]
988#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
989pub enum TrackSizingFunction {
990 Single(NonRepeatedTrackSizingFunction),
992 Repeat(GridTrackRepetition, GridTrackVec<NonRepeatedTrackSizingFunction>),
995}
996impl TrackSizingFunction {
997 pub fn is_auto_repetition(&self) -> bool {
999 matches!(self, Self::Repeat(GridTrackRepetition::AutoFit | GridTrackRepetition::AutoFill, _))
1000 }
1001}
1002impl TaffyAuto for TrackSizingFunction {
1003 const AUTO: Self = Self::Single(NonRepeatedTrackSizingFunction::AUTO);
1004}
1005impl TaffyMinContent for TrackSizingFunction {
1006 const MIN_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MIN_CONTENT);
1007}
1008impl TaffyMaxContent for TrackSizingFunction {
1009 const MAX_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MAX_CONTENT);
1010}
1011impl TaffyFitContent for TrackSizingFunction {
1012 fn fit_content(argument: LengthPercentage) -> Self {
1013 Self::Single(NonRepeatedTrackSizingFunction::fit_content(argument))
1014 }
1015}
1016impl TaffyZero for TrackSizingFunction {
1017 const ZERO: Self = Self::Single(NonRepeatedTrackSizingFunction::ZERO);
1018}
1019impl FromLength for TrackSizingFunction {
1020 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
1021 Self::Single(NonRepeatedTrackSizingFunction::from_length(value))
1022 }
1023}
1024impl FromPercent for TrackSizingFunction {
1025 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
1026 Self::Single(NonRepeatedTrackSizingFunction::from_percent(percent))
1027 }
1028}
1029impl FromFr for TrackSizingFunction {
1030 fn from_fr<Input: Into<f32> + Copy>(flex: Input) -> Self {
1031 Self::Single(NonRepeatedTrackSizingFunction::from_fr(flex))
1032 }
1033}
1034impl From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> for TrackSizingFunction {
1035 fn from(input: MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>) -> Self {
1036 Self::Single(input)
1037 }
1038}