1use super::{
3 AlignContent, AlignItems, AlignSelf, CheapCloneStr, CompactLength, CoreStyle, Dimension, JustifyContent,
4 LengthPercentage, LengthPercentageAuto, Style,
5};
6use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
7use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size};
8use crate::style_helpers::*;
9use crate::sys::{DefaultCheapStr, Vec};
10use core::cmp::{max, min};
11use core::fmt::Debug;
12
13#[derive(Debug, Clone, PartialEq)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16pub struct GridTemplateArea<CustomIdent: CheapCloneStr> {
17 #[cfg_attr(feature = "serde", serde(deserialize_with = "crate::util::deserialize_from_str"))]
19 pub name: CustomIdent,
20 pub row_start: u16,
22 pub row_end: u16,
24 pub column_start: u16,
26 pub column_end: u16,
28}
29
30#[derive(Debug, Clone, PartialEq)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33pub struct NamedGridLine<CustomIdent: CheapCloneStr> {
34 #[cfg_attr(feature = "serde", serde(deserialize_with = "crate::util::deserialize_from_str"))]
36 pub name: CustomIdent,
37 pub index: u16,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq)]
43pub(crate) enum GridAreaAxis {
44 Row,
46 Column,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq)]
52pub(crate) enum GridAreaEnd {
53 Start,
55 End,
57}
58
59pub trait GenericRepetition {
61 type CustomIdent: CheapCloneStr;
63 type RepetitionTrackList<'a>: Iterator<Item = TrackSizingFunction> + ExactSizeIterator + Clone
65 where
66 Self: 'a;
67
68 type TemplateLineNames<'a>: TemplateLineNames<'a, Self::CustomIdent>
70 where
71 Self: 'a;
72 fn count(&self) -> RepetitionCount;
74 fn tracks(&self) -> Self::RepetitionTrackList<'_>;
76 fn track_count(&self) -> u16 {
78 self.tracks().len() as u16
79 }
80 fn lines_names(&self) -> Self::TemplateLineNames<'_>;
82}
83
84#[rustfmt::skip]
87pub trait TemplateLineNames<'a, S: CheapCloneStr> : Iterator<Item = Self::LineNameSet<'a>> + ExactSizeIterator + Clone where Self: 'a {
88 type LineNameSet<'b>: Iterator<Item = &'b S> + ExactSizeIterator + Clone where Self: 'b;
91}
92
93impl<'a, S: CheapCloneStr> TemplateLineNames<'a, S>
94 for core::iter::Map<core::slice::Iter<'a, Vec<S>>, fn(&Vec<S>) -> core::slice::Iter<'_, S>>
95{
96 type LineNameSet<'b>
97 = core::slice::Iter<'b, S>
98 where
99 Self: 'b;
100}
101
102#[derive(Copy, Clone)]
103pub enum GenericGridTemplateComponent<S, Repetition>
106where
107 S: CheapCloneStr,
108 Repetition: GenericRepetition<CustomIdent = S>,
109{
110 Single(TrackSizingFunction),
112 Repeat(Repetition),
114}
115
116impl<S, Repetition> GenericGridTemplateComponent<S, Repetition>
117where
118 S: CheapCloneStr,
119 Repetition: GenericRepetition<CustomIdent = S>,
120{
121 pub fn is_auto_repetition(&self) -> bool {
123 match self {
124 Self::Single(_) => false,
125 Self::Repeat(repeat) => matches!(repeat.count(), RepetitionCount::AutoFit | RepetitionCount::AutoFill),
126 }
127 }
128}
129
130pub trait GridContainerStyle: CoreStyle {
132 type Repetition<'a>: GenericRepetition<CustomIdent = Self::CustomIdent>
134 where
135 Self: 'a;
136
137 type TemplateTrackList<'a>: Iterator<Item = GenericGridTemplateComponent<Self::CustomIdent, Self::Repetition<'a>>>
139 + ExactSizeIterator
140 + Clone
141 where
142 Self: 'a;
143
144 type AutoTrackList<'a>: Iterator<Item = TrackSizingFunction> + ExactSizeIterator + Clone
146 where
147 Self: 'a;
148
149 type TemplateLineNames<'a>: TemplateLineNames<'a, Self::CustomIdent>
152 where
153 Self: 'a;
154
155 type GridTemplateAreas<'a>: IntoIterator<Item = GridTemplateArea<Self::CustomIdent>>
157 where
158 Self: 'a;
159
160 fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>>;
165 fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>>;
167 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_>;
169 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_>;
171
172 fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>>;
174 fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>>;
176 fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>>;
178
179 #[inline(always)]
181 fn grid_auto_flow(&self) -> GridAutoFlow {
182 Style::<Self::CustomIdent>::DEFAULT.grid_auto_flow
183 }
184
185 #[inline(always)]
187 fn gap(&self) -> Size<LengthPercentage> {
188 Style::<Self::CustomIdent>::DEFAULT.gap
189 }
190
191 #[inline(always)]
195 fn align_content(&self) -> Option<AlignContent> {
196 Style::<Self::CustomIdent>::DEFAULT.align_content
197 }
198 #[inline(always)]
200 fn justify_content(&self) -> Option<JustifyContent> {
201 Style::<Self::CustomIdent>::DEFAULT.justify_content
202 }
203 #[inline(always)]
205 fn align_items(&self) -> Option<AlignItems> {
206 Style::<Self::CustomIdent>::DEFAULT.align_items
207 }
208 #[inline(always)]
210 fn justify_items(&self) -> Option<AlignItems> {
211 Style::<Self::CustomIdent>::DEFAULT.justify_items
212 }
213
214 #[inline(always)]
216 fn grid_template_tracks(&self, axis: AbsoluteAxis) -> Option<Self::TemplateTrackList<'_>> {
217 match axis {
218 AbsoluteAxis::Horizontal => self.grid_template_columns(),
219 AbsoluteAxis::Vertical => self.grid_template_rows(),
220 }
221 }
222
223 #[inline(always)]
225 fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
226 match axis {
227 AbstractAxis::Inline => self.justify_content().unwrap_or(AlignContent::Stretch),
228 AbstractAxis::Block => self.align_content().unwrap_or(AlignContent::Stretch),
229 }
230 }
231}
232
233pub trait GridItemStyle: CoreStyle {
235 #[inline(always)]
237 fn grid_row(&self) -> Line<GridPlacement<Self::CustomIdent>> {
238 Default::default()
239 }
240 #[inline(always)]
242 fn grid_column(&self) -> Line<GridPlacement<Self::CustomIdent>> {
243 Default::default()
244 }
245
246 #[inline(always)]
249 fn align_self(&self) -> Option<AlignSelf> {
250 Style::<Self::CustomIdent>::DEFAULT.align_self
251 }
252 #[inline(always)]
255 fn justify_self(&self) -> Option<AlignSelf> {
256 Style::<Self::CustomIdent>::DEFAULT.justify_self
257 }
258
259 #[inline(always)]
261 fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement<Self::CustomIdent>> {
262 match axis {
263 AbsoluteAxis::Horizontal => self.grid_column(),
264 AbsoluteAxis::Vertical => self.grid_row(),
265 }
266 }
267}
268
269#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
277#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
278pub enum GridAutoFlow {
279 #[default]
281 Row,
282 Column,
284 RowDense,
286 ColumnDense,
288}
289
290impl GridAutoFlow {
291 pub fn is_dense(&self) -> bool {
294 match self {
295 Self::Row | Self::Column => false,
296 Self::RowDense | Self::ColumnDense => true,
297 }
298 }
299
300 pub fn primary_axis(&self) -> AbsoluteAxis {
303 match self {
304 Self::Row | Self::RowDense => AbsoluteAxis::Horizontal,
305 Self::Column | Self::ColumnDense => AbsoluteAxis::Vertical,
306 }
307 }
308}
309
310#[derive(Copy, Clone, PartialEq, Eq, Debug)]
318#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
319pub enum GenericGridPlacement<LineType: GridCoordinate> {
320 Auto,
322 Line(LineType),
324 Span(u16),
326}
327
328pub(crate) type OriginZeroGridPlacement = GenericGridPlacement<OriginZeroLine>;
330
331pub(crate) type NonNamedGridPlacement = GenericGridPlacement<GridLine>;
335
336#[derive(Clone, PartialEq, Debug, Default)]
342#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
343pub enum GridPlacement<S: CheapCloneStr = DefaultCheapStr> {
344 #[default]
346 Auto,
347 Line(GridLine),
349 NamedLine(S, i16),
351 Span(u16),
353 NamedSpan(S, u16),
358}
359impl<S: CheapCloneStr> TaffyAuto for GridPlacement<S> {
360 const AUTO: Self = Self::Auto;
361}
362impl<S: CheapCloneStr> TaffyGridLine for GridPlacement<S> {
363 fn from_line_index(index: i16) -> Self {
364 GridPlacement::<S>::Line(GridLine::from(index))
365 }
366}
367impl<S: CheapCloneStr> TaffyGridLine for Line<GridPlacement<S>> {
368 fn from_line_index(index: i16) -> Self {
369 Line { start: GridPlacement::<S>::from_line_index(index), end: GridPlacement::<S>::Auto }
370 }
371}
372impl<S: CheapCloneStr> TaffyGridSpan for GridPlacement<S> {
373 fn from_span(span: u16) -> Self {
374 GridPlacement::<S>::Span(span)
375 }
376}
377impl<S: CheapCloneStr> TaffyGridSpan for Line<GridPlacement<S>> {
378 fn from_span(span: u16) -> Self {
379 Line { start: GridPlacement::<S>::from_span(span), end: GridPlacement::<S>::Auto }
380 }
381}
382
383impl<S: CheapCloneStr> GridPlacement<S> {
384 pub fn into_origin_zero_placement_ignoring_named(&self, explicit_track_count: u16) -> OriginZeroGridPlacement {
386 match self {
387 Self::Auto => OriginZeroGridPlacement::Auto,
388 Self::Span(span) => OriginZeroGridPlacement::Span(*span),
389 Self::Line(line) => match line.as_i16() {
392 0 => OriginZeroGridPlacement::Auto,
393 _ => OriginZeroGridPlacement::Line(line.into_origin_zero_line(explicit_track_count)),
394 },
395 Self::NamedLine(_, _) => OriginZeroGridPlacement::Auto,
396 Self::NamedSpan(_, _) => OriginZeroGridPlacement::Auto,
397 }
398 }
399}
400
401impl<S: CheapCloneStr> Line<GridPlacement<S>> {
402 pub fn into_origin_zero_ignoring_named(&self, explicit_track_count: u16) -> Line<OriginZeroGridPlacement> {
404 Line {
405 start: self.start.into_origin_zero_placement_ignoring_named(explicit_track_count),
406 end: self.end.into_origin_zero_placement_ignoring_named(explicit_track_count),
407 }
408 }
409}
410
411impl NonNamedGridPlacement {
412 pub fn into_origin_zero_placement(
414 &self,
415 explicit_track_count: u16,
416 ) -> OriginZeroGridPlacement {
418 match self {
419 Self::Auto => OriginZeroGridPlacement::Auto,
420 Self::Span(span) => OriginZeroGridPlacement::Span(*span),
421 Self::Line(line) => match line.as_i16() {
424 0 => OriginZeroGridPlacement::Auto,
425 _ => OriginZeroGridPlacement::Line(line.into_origin_zero_line(explicit_track_count)),
426 },
427 }
428 }
429}
430
431impl<T: GridCoordinate> Line<GenericGridPlacement<T>> {
432 pub fn indefinite_span(&self) -> u16 {
435 use GenericGridPlacement as GP;
436 match (self.start, self.end) {
437 (GP::Line(_), GP::Auto) => 1,
438 (GP::Auto, GP::Line(_)) => 1,
439 (GP::Auto, GP::Auto) => 1,
440 (GP::Line(_), GP::Span(span)) => span,
441 (GP::Span(span), GP::Line(_)) => span,
442 (GP::Span(span), GP::Auto) => span,
443 (GP::Auto, GP::Span(span)) => span,
444 (GP::Span(span), GP::Span(_)) => span,
445 (GP::Line(_), GP::Line(_)) => panic!("indefinite_span should only be called on indefinite grid tracks"),
446 }
447 }
448}
449
450impl<S: CheapCloneStr> Line<GridPlacement<S>> {
451 #[inline]
452 pub fn is_definite(&self) -> bool {
456 match (&self.start, &self.end) {
457 (GridPlacement::Line(line), _) if line.as_i16() != 0 => true,
458 (_, GridPlacement::Line(line)) if line.as_i16() != 0 => true,
459 (GridPlacement::NamedLine(_, _), _) => true,
460 (_, GridPlacement::NamedLine(_, _)) => true,
461 _ => false,
462 }
463 }
464}
465
466impl Line<NonNamedGridPlacement> {
467 #[inline]
468 pub fn is_definite(&self) -> bool {
472 match (&self.start, &self.end) {
473 (GenericGridPlacement::Line(line), _) if line.as_i16() != 0 => true,
474 (_, GenericGridPlacement::Line(line)) if line.as_i16() != 0 => true,
475 _ => false,
476 }
477 }
478
479 pub fn into_origin_zero(&self, explicit_track_count: u16) -> Line<OriginZeroGridPlacement> {
481 Line {
482 start: self.start.into_origin_zero_placement(explicit_track_count),
483 end: self.end.into_origin_zero_placement(explicit_track_count),
484 }
485 }
486}
487
488impl Line<OriginZeroGridPlacement> {
489 #[inline]
490 pub fn is_definite(&self) -> bool {
493 matches!((self.start, self.end), (GenericGridPlacement::Line(_), _) | (_, GenericGridPlacement::Line(_)))
494 }
495
496 pub fn resolve_definite_grid_lines(&self) -> Line<OriginZeroLine> {
499 use OriginZeroGridPlacement as GP;
500 match (self.start, self.end) {
501 (GP::Line(line1), GP::Line(line2)) => {
502 if line1 == line2 {
503 Line { start: line1, end: line1 + 1 }
504 } else {
505 Line { start: min(line1, line2), end: max(line1, line2) }
506 }
507 }
508 (GP::Line(line), GP::Span(span)) => Line { start: line, end: line + span },
509 (GP::Line(line), GP::Auto) => Line { start: line, end: line + 1 },
510 (GP::Span(span), GP::Line(line)) => Line { start: line - span, end: line },
511 (GP::Auto, GP::Line(line)) => Line { start: line - 1, end: line },
512 _ => panic!("resolve_definite_grid_tracks should only be called on definite grid tracks"),
513 }
514 }
515
516 pub fn resolve_absolutely_positioned_grid_tracks(&self) -> Line<Option<OriginZeroLine>> {
526 use OriginZeroGridPlacement as GP;
527 match (self.start, self.end) {
528 (GP::Line(track1), GP::Line(track2)) => {
529 if track1 == track2 {
530 Line { start: Some(track1), end: Some(track1 + 1) }
531 } else {
532 Line { start: Some(min(track1, track2)), end: Some(max(track1, track2)) }
533 }
534 }
535 (GP::Line(track), GP::Span(span)) => Line { start: Some(track), end: Some(track + span) },
536 (GP::Line(track), GP::Auto) => Line { start: Some(track), end: None },
537 (GP::Span(span), GP::Line(track)) => Line { start: Some(track - span), end: Some(track) },
538 (GP::Auto, GP::Line(track)) => Line { start: None, end: Some(track) },
539 _ => Line { start: None, end: None },
540 }
541 }
542
543 pub fn resolve_indefinite_grid_tracks(&self, start: OriginZeroLine) -> Line<OriginZeroLine> {
546 use OriginZeroGridPlacement as GP;
547 match (self.start, self.end) {
548 (GP::Auto, GP::Auto) => Line { start, end: start + 1 },
549 (GP::Span(span), GP::Auto) => Line { start, end: start + span },
550 (GP::Auto, GP::Span(span)) => Line { start, end: start + span },
551 (GP::Span(span), GP::Span(_)) => Line { start, end: start + span },
552 _ => panic!("resolve_indefinite_grid_tracks should only be called on indefinite grid tracks"),
553 }
554 }
555}
556
557impl<S: CheapCloneStr> Default for Line<GridPlacement<S>> {
559 fn default() -> Self {
560 Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto }
561 }
562}
563
564#[derive(Copy, Clone, PartialEq, Debug)]
570#[cfg_attr(feature = "serde", derive(Serialize))]
571pub struct MaxTrackSizingFunction(pub(crate) CompactLength);
572impl TaffyZero for MaxTrackSizingFunction {
573 const ZERO: Self = Self(CompactLength::ZERO);
574}
575impl TaffyAuto for MaxTrackSizingFunction {
576 const AUTO: Self = Self(CompactLength::AUTO);
577}
578impl TaffyMinContent for MaxTrackSizingFunction {
579 const MIN_CONTENT: Self = Self(CompactLength::MIN_CONTENT);
580}
581impl TaffyMaxContent for MaxTrackSizingFunction {
582 const MAX_CONTENT: Self = Self(CompactLength::MAX_CONTENT);
583}
584impl FromLength for MaxTrackSizingFunction {
585 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
586 Self::length(value.into())
587 }
588}
589impl FromPercent for MaxTrackSizingFunction {
590 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
591 Self::percent(value.into())
592 }
593}
594impl TaffyFitContent for MaxTrackSizingFunction {
595 fn fit_content(argument: LengthPercentage) -> Self {
596 Self(CompactLength::fit_content(argument))
597 }
598}
599impl FromFr for MaxTrackSizingFunction {
600 fn from_fr<Input: Into<f32> + Copy>(value: Input) -> Self {
601 Self::fr(value.into())
602 }
603}
604impl From<LengthPercentage> for MaxTrackSizingFunction {
605 fn from(input: LengthPercentage) -> Self {
606 Self(input.0)
607 }
608}
609impl From<LengthPercentageAuto> for MaxTrackSizingFunction {
610 fn from(input: LengthPercentageAuto) -> Self {
611 Self(input.0)
612 }
613}
614impl From<Dimension> for MaxTrackSizingFunction {
615 fn from(input: Dimension) -> Self {
616 Self(input.0)
617 }
618}
619impl From<MinTrackSizingFunction> for MaxTrackSizingFunction {
620 fn from(input: MinTrackSizingFunction) -> Self {
621 Self(input.0)
622 }
623}
624#[cfg(feature = "serde")]
625impl<'de> serde::Deserialize<'de> for MaxTrackSizingFunction {
626 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
627 where
628 D: serde::Deserializer<'de>,
629 {
630 let inner = CompactLength::deserialize(deserializer)?;
631 if matches!(
633 inner.tag(),
634 CompactLength::LENGTH_TAG
635 | CompactLength::PERCENT_TAG
636 | CompactLength::AUTO_TAG
637 | CompactLength::MIN_CONTENT_TAG
638 | CompactLength::MAX_CONTENT_TAG
639 | CompactLength::FIT_CONTENT_PX_TAG
640 | CompactLength::FIT_CONTENT_PERCENT_TAG
641 | CompactLength::FR_TAG
642 ) {
643 Ok(Self(inner))
644 } else {
645 Err(serde::de::Error::custom("Invalid tag"))
646 }
647 }
648}
649
650impl MaxTrackSizingFunction {
651 #[inline(always)]
654 pub const fn length(val: f32) -> Self {
655 Self(CompactLength::length(val))
656 }
657
658 #[inline(always)]
662 pub const fn percent(val: f32) -> Self {
663 Self(CompactLength::percent(val))
664 }
665
666 #[inline(always)]
669 pub const fn auto() -> Self {
670 Self(CompactLength::auto())
671 }
672
673 #[inline(always)]
676 pub const fn min_content() -> Self {
677 Self(CompactLength::min_content())
678 }
679
680 #[inline(always)]
683 pub const fn max_content() -> Self {
684 Self(CompactLength::max_content())
685 }
686
687 #[inline(always)]
697 pub const fn fit_content_px(limit: f32) -> Self {
698 Self(CompactLength::fit_content_px(limit))
699 }
700
701 #[inline(always)]
711 pub const fn fit_content_percent(limit: f32) -> Self {
712 Self(CompactLength::fit_content_percent(limit))
713 }
714
715 #[inline(always)]
719 pub const fn fr(val: f32) -> Self {
720 Self(CompactLength::fr(val))
721 }
722
723 #[inline]
728 #[cfg(feature = "calc")]
729 pub fn calc(ptr: *const ()) -> Self {
730 Self(CompactLength::calc(ptr))
731 }
732
733 #[allow(unsafe_code)]
737 pub unsafe fn from_raw(val: CompactLength) -> Self {
738 Self(val)
739 }
740
741 pub fn into_raw(self) -> CompactLength {
743 self.0
744 }
745
746 #[inline(always)]
748 pub fn is_intrinsic(&self) -> bool {
749 self.0.is_intrinsic()
750 }
751
752 #[inline(always)]
756 pub fn is_max_content_alike(&self) -> bool {
757 self.0.is_max_content_alike()
758 }
759
760 #[inline(always)]
762 pub fn is_fr(&self) -> bool {
763 self.0.is_fr()
764 }
765
766 #[inline(always)]
768 pub fn is_auto(&self) -> bool {
769 self.0.is_auto()
770 }
771
772 #[inline(always)]
774 pub fn is_min_content(&self) -> bool {
775 self.0.is_min_content()
776 }
777
778 #[inline(always)]
780 pub fn is_max_content(&self) -> bool {
781 self.0.is_max_content()
782 }
783
784 #[inline(always)]
786 pub fn is_fit_content(&self) -> bool {
787 self.0.is_fit_content()
788 }
789
790 #[inline(always)]
792 pub fn is_max_or_fit_content(&self) -> bool {
793 self.0.is_max_or_fit_content()
794 }
795
796 #[inline(always)]
798 pub fn has_definite_value(self, parent_size: Option<f32>) -> bool {
799 match self.0.tag() {
800 CompactLength::LENGTH_TAG => true,
801 CompactLength::PERCENT_TAG => parent_size.is_some(),
802 #[cfg(feature = "calc")]
803 _ if self.0.is_calc() => parent_size.is_some(),
804 _ => false,
805 }
806 }
807
808 #[inline(always)]
812 pub fn definite_value(
813 self,
814 parent_size: Option<f32>,
815 calc_resolver: impl Fn(*const (), f32) -> f32,
816 ) -> Option<f32> {
817 match self.0.tag() {
818 CompactLength::LENGTH_TAG => Some(self.0.value()),
819 CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
820 #[cfg(feature = "calc")]
821 _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
822 _ => None,
823 }
824 }
825
826 #[inline(always)]
833 pub fn definite_limit(
834 self,
835 parent_size: Option<f32>,
836 calc_resolver: impl Fn(*const (), f32) -> f32,
837 ) -> Option<f32> {
838 match self.0.tag() {
839 CompactLength::FIT_CONTENT_PX_TAG => Some(self.0.value()),
840 CompactLength::FIT_CONTENT_PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
841 _ => self.definite_value(parent_size, calc_resolver),
842 }
843 }
844
845 #[inline(always)]
848 pub fn resolved_percentage_size(
849 self,
850 parent_size: f32,
851 calc_resolver: impl Fn(*const (), f32) -> f32,
852 ) -> Option<f32> {
853 self.0.resolved_percentage_size(parent_size, calc_resolver)
854 }
855
856 #[inline(always)]
858 pub fn uses_percentage(self) -> bool {
859 self.0.uses_percentage()
860 }
861}
862
863#[derive(Copy, Clone, PartialEq, Debug)]
869#[cfg_attr(feature = "serde", derive(Serialize))]
870pub struct MinTrackSizingFunction(pub(crate) CompactLength);
871impl TaffyZero for MinTrackSizingFunction {
872 const ZERO: Self = Self(CompactLength::ZERO);
873}
874impl TaffyAuto for MinTrackSizingFunction {
875 const AUTO: Self = Self(CompactLength::AUTO);
876}
877impl TaffyMinContent for MinTrackSizingFunction {
878 const MIN_CONTENT: Self = Self(CompactLength::MIN_CONTENT);
879}
880impl TaffyMaxContent for MinTrackSizingFunction {
881 const MAX_CONTENT: Self = Self(CompactLength::MAX_CONTENT);
882}
883impl FromLength for MinTrackSizingFunction {
884 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
885 Self::length(value.into())
886 }
887}
888impl FromPercent for MinTrackSizingFunction {
889 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
890 Self::percent(value.into())
891 }
892}
893impl From<LengthPercentage> for MinTrackSizingFunction {
894 fn from(input: LengthPercentage) -> Self {
895 Self(input.0)
896 }
897}
898impl From<LengthPercentageAuto> for MinTrackSizingFunction {
899 fn from(input: LengthPercentageAuto) -> Self {
900 Self(input.0)
901 }
902}
903impl From<Dimension> for MinTrackSizingFunction {
904 fn from(input: Dimension) -> Self {
905 Self(input.0)
906 }
907}
908#[cfg(feature = "serde")]
909impl<'de> serde::Deserialize<'de> for MinTrackSizingFunction {
910 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
911 where
912 D: serde::Deserializer<'de>,
913 {
914 let inner = CompactLength::deserialize(deserializer)?;
915 if matches!(
917 inner.tag(),
918 CompactLength::LENGTH_TAG
919 | CompactLength::PERCENT_TAG
920 | CompactLength::AUTO_TAG
921 | CompactLength::MIN_CONTENT_TAG
922 | CompactLength::MAX_CONTENT_TAG
923 | CompactLength::FIT_CONTENT_PX_TAG
924 | CompactLength::FIT_CONTENT_PERCENT_TAG
925 ) {
926 Ok(Self(inner))
927 } else {
928 Err(serde::de::Error::custom("Invalid tag"))
929 }
930 }
931}
932
933impl MinTrackSizingFunction {
934 #[inline(always)]
937 pub const fn length(val: f32) -> Self {
938 Self(CompactLength::length(val))
939 }
940
941 #[inline(always)]
945 pub const fn percent(val: f32) -> Self {
946 Self(CompactLength::percent(val))
947 }
948
949 #[inline(always)]
952 pub const fn auto() -> Self {
953 Self(CompactLength::auto())
954 }
955
956 #[inline(always)]
959 pub const fn min_content() -> Self {
960 Self(CompactLength::min_content())
961 }
962
963 #[inline(always)]
966 pub const fn max_content() -> Self {
967 Self(CompactLength::max_content())
968 }
969
970 #[inline]
975 #[cfg(feature = "calc")]
976 pub fn calc(ptr: *const ()) -> Self {
977 Self(CompactLength::calc(ptr))
978 }
979
980 #[allow(unsafe_code)]
984 pub unsafe fn from_raw(val: CompactLength) -> Self {
985 Self(val)
986 }
987
988 pub fn into_raw(self) -> CompactLength {
990 self.0
991 }
992
993 #[inline(always)]
995 pub fn is_intrinsic(&self) -> bool {
996 self.0.is_intrinsic()
997 }
998
999 #[inline(always)]
1001 pub fn is_min_or_max_content(&self) -> bool {
1002 self.0.is_min_or_max_content()
1003 }
1004
1005 #[inline(always)]
1007 pub fn is_fr(&self) -> bool {
1008 self.0.is_fr()
1009 }
1010
1011 #[inline(always)]
1013 pub fn is_auto(&self) -> bool {
1014 self.0.is_auto()
1015 }
1016
1017 #[inline(always)]
1019 pub fn is_min_content(&self) -> bool {
1020 self.0.is_min_content()
1021 }
1022
1023 #[inline(always)]
1025 pub fn is_max_content(&self) -> bool {
1026 self.0.is_max_content()
1027 }
1028
1029 #[inline(always)]
1033 pub fn definite_value(
1034 self,
1035 parent_size: Option<f32>,
1036 calc_resolver: impl Fn(*const (), f32) -> f32,
1037 ) -> Option<f32> {
1038 match self.0.tag() {
1039 CompactLength::LENGTH_TAG => Some(self.0.value()),
1040 CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
1041 #[cfg(feature = "calc")]
1042 _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
1043 _ => None,
1044 }
1045 }
1046
1047 #[inline(always)]
1050 pub fn resolved_percentage_size(
1051 self,
1052 parent_size: f32,
1053 calc_resolver: impl Fn(*const (), f32) -> f32,
1054 ) -> Option<f32> {
1055 self.0.resolved_percentage_size(parent_size, calc_resolver)
1056 }
1057
1058 #[inline(always)]
1060 pub fn uses_percentage(self) -> bool {
1061 #[cfg(feature = "calc")]
1062 {
1063 matches!(self.0.tag(), CompactLength::PERCENT_TAG) || self.0.is_calc()
1064 }
1065 #[cfg(not(feature = "calc"))]
1066 {
1067 matches!(self.0.tag(), CompactLength::PERCENT_TAG)
1068 }
1069 }
1070}
1071
1072pub type TrackSizingFunction = MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>;
1077impl TrackSizingFunction {
1078 pub fn min_sizing_function(&self) -> MinTrackSizingFunction {
1080 self.min
1081 }
1082 pub fn max_sizing_function(&self) -> MaxTrackSizingFunction {
1084 self.max
1085 }
1086 pub fn has_fixed_component(&self) -> bool {
1088 self.min.0.is_length_or_percentage() || self.max.0.is_length_or_percentage()
1089 }
1090}
1091impl TaffyAuto for TrackSizingFunction {
1092 const AUTO: Self = Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::AUTO };
1093}
1094impl TaffyMinContent for TrackSizingFunction {
1095 const MIN_CONTENT: Self =
1096 Self { min: MinTrackSizingFunction::MIN_CONTENT, max: MaxTrackSizingFunction::MIN_CONTENT };
1097}
1098impl TaffyMaxContent for TrackSizingFunction {
1099 const MAX_CONTENT: Self =
1100 Self { min: MinTrackSizingFunction::MAX_CONTENT, max: MaxTrackSizingFunction::MAX_CONTENT };
1101}
1102impl TaffyFitContent for TrackSizingFunction {
1103 fn fit_content(argument: LengthPercentage) -> Self {
1104 Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::fit_content(argument) }
1105 }
1106}
1107impl TaffyZero for TrackSizingFunction {
1108 const ZERO: Self = Self { min: MinTrackSizingFunction::ZERO, max: MaxTrackSizingFunction::ZERO };
1109}
1110impl FromLength for TrackSizingFunction {
1111 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
1112 Self { min: MinTrackSizingFunction::from_length(value), max: MaxTrackSizingFunction::from_length(value) }
1113 }
1114}
1115impl FromPercent for TrackSizingFunction {
1116 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
1117 Self { min: MinTrackSizingFunction::from_percent(percent), max: MaxTrackSizingFunction::from_percent(percent) }
1118 }
1119}
1120impl FromFr for TrackSizingFunction {
1121 fn from_fr<Input: Into<f32> + Copy>(flex: Input) -> Self {
1122 Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::from_fr(flex) }
1123 }
1124}
1125impl From<LengthPercentage> for TrackSizingFunction {
1126 fn from(input: LengthPercentage) -> Self {
1127 Self { min: input.into(), max: input.into() }
1128 }
1129}
1130impl From<LengthPercentageAuto> for TrackSizingFunction {
1131 fn from(input: LengthPercentageAuto) -> Self {
1132 Self { min: input.into(), max: input.into() }
1133 }
1134}
1135impl From<Dimension> for TrackSizingFunction {
1136 fn from(input: Dimension) -> Self {
1137 Self { min: input.into(), max: input.into() }
1138 }
1139}
1140
1141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1146#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1147pub enum RepetitionCount {
1148 AutoFill,
1151 AutoFit,
1154 Count(u16),
1156}
1157impl From<u16> for RepetitionCount {
1158 fn from(value: u16) -> Self {
1159 Self::Count(value)
1160 }
1161}
1162
1163#[derive(Debug)]
1166pub struct InvalidStringRepetitionValue;
1167#[cfg(feature = "std")]
1168impl std::error::Error for InvalidStringRepetitionValue {}
1169impl core::fmt::Display for InvalidStringRepetitionValue {
1170 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1171 f.write_str("&str can only be converted to GridTrackRepetition if it's value is 'auto-fit' or 'auto-fill'")
1172 }
1173}
1174impl TryFrom<&str> for RepetitionCount {
1175 type Error = InvalidStringRepetitionValue;
1176 fn try_from(value: &str) -> Result<Self, InvalidStringRepetitionValue> {
1177 match value {
1178 "auto-fit" => Ok(Self::AutoFit),
1179 "auto-fill" => Ok(Self::AutoFill),
1180 _ => Err(InvalidStringRepetitionValue),
1181 }
1182 }
1183}
1184
1185#[derive(Clone, PartialEq, Debug)]
1187#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1188pub struct GridTemplateRepetition<S: CheapCloneStr> {
1189 pub count: RepetitionCount,
1191 pub tracks: Vec<TrackSizingFunction>,
1193 pub line_names: Vec<Vec<S>>,
1195}
1196
1197#[rustfmt::skip]
1198impl<S: CheapCloneStr> GenericRepetition for &'_ GridTemplateRepetition<S> {
1199 type CustomIdent = S;
1200 type RepetitionTrackList<'a> = core::iter::Copied<core::slice::Iter<'a, TrackSizingFunction>> where Self: 'a;
1201 type TemplateLineNames<'a> = core::iter::Map<core::slice::Iter<'a, Vec<S>>, fn(&Vec<S>) -> core::slice::Iter<'_, S>> where Self: 'a;
1202 #[inline(always)]
1203 fn count(&self) -> RepetitionCount {
1204 self.count
1205 }
1206 #[inline(always)]
1207 fn track_count(&self) -> u16 {
1208 self.tracks.len() as u16
1209 }
1210 #[inline(always)]
1211 fn tracks(&self) -> Self::RepetitionTrackList<'_> {
1212 self.tracks.iter().copied()
1213 }
1214 #[inline(always)]
1215 fn lines_names(&self) -> Self::TemplateLineNames<'_> {
1216 self.line_names.iter().map(|names| names.iter())
1217 }
1218}
1219
1220#[derive(Clone, PartialEq, Debug)]
1225#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1226pub enum GridTemplateComponent<S: CheapCloneStr> {
1227 Single(TrackSizingFunction),
1229 Repeat(GridTemplateRepetition<S>),
1232}
1233
1234impl<S: CheapCloneStr> GridTemplateComponent<S> {
1235 pub fn as_component_ref(&self) -> GenericGridTemplateComponent<S, &GridTemplateRepetition<S>> {
1237 match self {
1238 GridTemplateComponent::Single(size) => GenericGridTemplateComponent::Single(*size),
1239 GridTemplateComponent::Repeat(repetition) => GenericGridTemplateComponent::Repeat(repetition),
1240 }
1241 }
1242}
1243
1244impl<S: CheapCloneStr> GridTemplateComponent<S> {
1245 pub fn is_auto_repetition(&self) -> bool {
1247 matches!(
1248 self,
1249 Self::Repeat(GridTemplateRepetition { count: RepetitionCount::AutoFit | RepetitionCount::AutoFill, .. })
1250 )
1251 }
1252}
1253impl<S: CheapCloneStr> TaffyAuto for GridTemplateComponent<S> {
1254 const AUTO: Self = Self::Single(TrackSizingFunction::AUTO);
1255}
1256impl<S: CheapCloneStr> TaffyMinContent for GridTemplateComponent<S> {
1257 const MIN_CONTENT: Self = Self::Single(TrackSizingFunction::MIN_CONTENT);
1258}
1259impl<S: CheapCloneStr> TaffyMaxContent for GridTemplateComponent<S> {
1260 const MAX_CONTENT: Self = Self::Single(TrackSizingFunction::MAX_CONTENT);
1261}
1262impl<S: CheapCloneStr> TaffyFitContent for GridTemplateComponent<S> {
1263 fn fit_content(argument: LengthPercentage) -> Self {
1264 Self::Single(TrackSizingFunction::fit_content(argument))
1265 }
1266}
1267impl<S: CheapCloneStr> TaffyZero for GridTemplateComponent<S> {
1268 const ZERO: Self = Self::Single(TrackSizingFunction::ZERO);
1269}
1270impl<S: CheapCloneStr> FromLength for GridTemplateComponent<S> {
1271 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
1272 Self::Single(TrackSizingFunction::from_length(value))
1273 }
1274}
1275impl<S: CheapCloneStr> FromPercent for GridTemplateComponent<S> {
1276 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
1277 Self::Single(TrackSizingFunction::from_percent(percent))
1278 }
1279}
1280impl<S: CheapCloneStr> FromFr for GridTemplateComponent<S> {
1281 fn from_fr<Input: Into<f32> + Copy>(flex: Input) -> Self {
1282 Self::Single(TrackSizingFunction::from_fr(flex))
1283 }
1284}
1285impl<S: CheapCloneStr> From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> for GridTemplateComponent<S> {
1286 fn from(input: MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>) -> Self {
1287 Self::Single(input)
1288 }
1289}