use super::types::{GridTrack, GridTrackKind, TrackCounts};
use crate::geometry::AbsoluteAxis;
use crate::style::{LengthPercentage, RepetitionCount, TrackSizingFunction};
use crate::style_helpers::TaffyAuto;
use crate::util::sys::{ceil, floor, Vec};
use crate::util::MaybeMath;
use crate::util::ResolveOrZero;
use crate::{GenericGridTemplateComponent, GenericRepetition, GridContainerStyle};
pub(crate) enum AutoRepeatStrategy {
MaxRepetitionsThatDoNotOverflow,
MinRepetitionsThatDoOverflow,
}
pub(crate) fn compute_explicit_grid_size_in_axis(
style: &impl GridContainerStyle,
auto_fit_container_size: Option<f32>,
auto_fit_strategy: AutoRepeatStrategy,
resolve_calc_value: impl Fn(*const (), f32) -> f32,
axis: AbsoluteAxis,
) -> (u16, u16) {
let template = match axis {
AbsoluteAxis::Horizontal => style.grid_template_columns(),
AbsoluteAxis::Vertical => style.grid_template_rows(),
};
let Some(template) = template else {
return (0, 0);
};
let track_count = template.len();
if track_count == 0 {
return (0, 0);
}
let template_has_repetitions_with_zero_tracks = template.clone().any(|track_def| match track_def {
GenericGridTemplateComponent::Single(_) => false,
GenericGridTemplateComponent::Repeat(repeat) => repeat.track_count() == 0,
});
if template_has_repetitions_with_zero_tracks {
return (0, 0);
}
let non_auto_repeating_track_count = template
.clone()
.map(|track_def| match track_def {
GenericGridTemplateComponent::Single(_) => 1,
GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
RepetitionCount::Count(count) => count * repeat.track_count(),
RepetitionCount::AutoFit | RepetitionCount::AutoFill => 0,
},
})
.sum::<u16>();
let auto_repetition_count: u16 = template.clone().filter(|track_def| track_def.is_auto_repetition()).count() as u16;
let all_track_defs_have_fixed_component = template.clone().all(|track_def| match track_def {
GenericGridTemplateComponent::Single(sizing_function) => sizing_function.has_fixed_component(),
GenericGridTemplateComponent::Repeat(repeat) => {
repeat.tracks().all(|sizing_function| sizing_function.has_fixed_component())
}
});
let template_is_valid =
auto_repetition_count == 0 || (auto_repetition_count == 1 && all_track_defs_have_fixed_component);
if !template_is_valid {
return (0, 0);
}
if auto_repetition_count == 0 {
return (0, non_auto_repeating_track_count);
}
let repetition_definition = template
.clone()
.find_map(|def| match def {
GenericGridTemplateComponent::Single(_) => None,
GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
RepetitionCount::Count(_) => None,
RepetitionCount::AutoFit | RepetitionCount::AutoFill => Some(repeat),
},
})
.unwrap();
let repetition_definition_iter = repetition_definition.tracks();
let repetition_track_count = repetition_definition_iter.len() as u16;
let num_repetitions: u16 = match auto_fit_container_size {
None => 1,
Some(inner_container_size) => {
let parent_size = Some(inner_container_size);
fn track_definite_value(
sizing_function: TrackSizingFunction,
parent_size: Option<f32>,
calc_resolver: impl Fn(*const (), f32) -> f32,
) -> f32 {
let max_size = sizing_function.max.definite_value(parent_size, &calc_resolver);
let min_size = sizing_function.min.definite_value(parent_size, &calc_resolver);
max_size.map(|max| max.maybe_max(min_size)).or(min_size).unwrap()
}
let non_repeating_track_used_space: f32 = template
.clone()
.map(|track_def| match track_def {
GenericGridTemplateComponent::Single(sizing_function) => {
track_definite_value(sizing_function, parent_size, &resolve_calc_value)
}
GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
RepetitionCount::Count(count) => {
let sum = repeat
.tracks()
.map(|sizing_function| {
track_definite_value(sizing_function, parent_size, &resolve_calc_value)
})
.sum::<f32>();
sum * (count as f32)
}
RepetitionCount::AutoFit | RepetitionCount::AutoFill => 0.0,
},
})
.sum();
let gap_size = style.gap().get_abs(axis).resolve_or_zero(Some(inner_container_size), &resolve_calc_value);
let per_repetition_track_used_space: f32 = repetition_definition_iter
.map(|sizing_function| track_definite_value(sizing_function, parent_size, &resolve_calc_value))
.sum::<f32>();
let first_repetition_and_non_repeating_tracks_used_space = non_repeating_track_used_space
+ per_repetition_track_used_space
+ ((non_auto_repeating_track_count + repetition_track_count).saturating_sub(1) as f32 * gap_size);
if first_repetition_and_non_repeating_tracks_used_space > inner_container_size {
1u16
} else {
let per_repetition_gap_used_space = (repetition_track_count as f32) * gap_size;
let per_repetition_used_space = per_repetition_track_used_space + per_repetition_gap_used_space;
let num_repetition_that_fit = (inner_container_size
- first_repetition_and_non_repeating_tracks_used_space)
/ per_repetition_used_space;
match auto_fit_strategy {
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow => (floor(num_repetition_that_fit) as u16) + 1,
AutoRepeatStrategy::MinRepetitionsThatDoOverflow => (ceil(num_repetition_that_fit) as u16) + 1,
}
}
}
};
let grid_template_track_count = non_auto_repeating_track_count + (repetition_track_count * num_repetitions);
(num_repetitions, grid_template_track_count)
}
pub(super) fn initialize_grid_tracks(
tracks: &mut Vec<GridTrack>,
counts: TrackCounts,
style: &impl GridContainerStyle,
axis: AbsoluteAxis,
track_has_items: impl Fn(usize) -> bool,
) {
let track_template;
let auto_tracks;
let gap;
match axis {
AbsoluteAxis::Horizontal => {
track_template = style.grid_template_columns();
auto_tracks = style.grid_auto_columns();
gap = style.gap().width;
}
AbsoluteAxis::Vertical => {
track_template = style.grid_template_rows();
auto_tracks = style.grid_auto_rows();
gap = style.gap().height;
}
};
tracks.clear();
tracks.reserve((counts.len() * 2) + 1);
tracks.push(GridTrack::gutter(gap));
let auto_track_count = auto_tracks.len();
let non_auto_repeating_track_count = track_template
.clone()
.map(|track_template| {
track_template
.map(|track_def| match track_def {
GenericGridTemplateComponent::Single(_) => 1,
GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
RepetitionCount::Count(count) => count * repeat.track_count(),
RepetitionCount::AutoFit | RepetitionCount::AutoFill => 0,
},
})
.sum::<u16>()
})
.unwrap_or(0);
if counts.negative_implicit > 0 {
if auto_track_count == 0 {
let iter = core::iter::repeat(TrackSizingFunction::AUTO);
create_implicit_tracks(tracks, counts.negative_implicit, iter, gap)
} else {
let offset = auto_track_count - (counts.negative_implicit as usize % auto_track_count);
let iter = auto_tracks.clone().cycle().skip(offset);
create_implicit_tracks(tracks, counts.negative_implicit, iter, gap)
}
}
let mut current_track_index = (counts.negative_implicit) as usize;
if counts.explicit > 0 {
if let Some(track_template) = track_template {
track_template.for_each(|track_sizing_function| {
match track_sizing_function {
GenericGridTemplateComponent::Single(sizing_function) => {
tracks.push(GridTrack::new(
sizing_function.min_sizing_function(),
sizing_function.max_sizing_function(),
));
tracks.push(GridTrack::gutter(gap));
current_track_index += 1;
}
GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
RepetitionCount::Count(count) => {
let track_iter = repeat.tracks();
let track_iter = track_iter.cycle().take(repeat.track_count() as usize * count as usize);
track_iter.for_each(|sizing_function| {
tracks.push(GridTrack::new(
sizing_function.min_sizing_function(),
sizing_function.max_sizing_function(),
));
tracks.push(GridTrack::gutter(gap));
current_track_index += 1;
});
}
RepetitionCount::AutoFit | RepetitionCount::AutoFill => {
let auto_repeated_track_count = (counts.explicit - non_auto_repeating_track_count) as usize;
let iter = repeat.tracks().cycle();
for track_def in iter.take(auto_repeated_track_count) {
let mut track =
GridTrack::new(track_def.min_sizing_function(), track_def.max_sizing_function());
let mut gutter = GridTrack::gutter(gap);
if repeat.count() == RepetitionCount::AutoFit && !track_has_items(current_track_index) {
track.collapse();
gutter.collapse();
}
tracks.push(track);
tracks.push(gutter);
current_track_index += 1;
}
let is_last = current_track_index == counts.len();
if repeat.count() == RepetitionCount::AutoFit && is_last {
for previous_track in tracks.iter_mut().rev() {
if previous_track.kind == GridTrackKind::Track && !previous_track.is_collapsed {
break;
}
previous_track.collapse();
}
}
}
},
}
});
}
}
let grid_area_tracks = (counts.negative_implicit + counts.explicit) - current_track_index as u16;
if auto_track_count == 0 {
let iter = core::iter::repeat(TrackSizingFunction::AUTO);
create_implicit_tracks(tracks, counts.positive_implicit + grid_area_tracks, iter, gap)
} else {
let iter = auto_tracks.clone().cycle();
create_implicit_tracks(tracks, counts.positive_implicit + grid_area_tracks, iter, gap)
}
tracks.first_mut().unwrap().collapse();
tracks.last_mut().unwrap().collapse();
}
fn create_implicit_tracks(
tracks: &mut Vec<GridTrack>,
count: u16,
mut auto_tracks_iter: impl Iterator<Item = TrackSizingFunction>,
gap: LengthPercentage,
) {
for _ in 0..count {
let track_def = auto_tracks_iter.next().unwrap();
tracks.push(GridTrack::new(track_def.min_sizing_function(), track_def.max_sizing_function()));
tracks.push(GridTrack::gutter(gap));
}
}
#[cfg(test)]
mod test {
use super::compute_explicit_grid_size_in_axis;
use super::initialize_grid_tracks;
use crate::compute::grid::explicit_grid::AutoRepeatStrategy;
use crate::compute::grid::types::GridTrackKind;
use crate::compute::grid::types::TrackCounts;
use crate::compute::grid::util::*;
use crate::geometry::AbsoluteAxis;
use crate::prelude::*;
use crate::sys::DefaultCheapStr;
#[test]
fn explicit_grid_sizing_no_repeats() {
let grid_style = (600.0, 600.0, 2, 4).into_grid();
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 2);
assert_eq!(row_count, 4);
assert_eq!(auto_col_reps, 0);
assert_eq!(auto_row_reps, 0);
}
#[test]
fn explicit_grid_sizing_auto_fill_exact_fit() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
size: Size { width: length(120.0), height: length(80.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
..Default::default()
};
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 3);
assert_eq!(row_count, 4);
assert_eq!(auto_col_reps, 3);
assert_eq!(auto_row_reps, 4);
}
#[test]
fn explicit_grid_sizing_auto_fill_non_exact_fit() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
size: Size { width: length(140.0), height: length(90.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
..Default::default()
};
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 3);
assert_eq!(row_count, 4);
assert_eq!(auto_col_reps, 3);
assert_eq!(auto_row_reps, 4);
}
#[test]
fn explicit_grid_sizing_auto_fill_min_size_exact_fit() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
min_size: Size { width: length(120.0), height: length(80.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
..Default::default()
};
let inner_container_size = Size { width: Some(120.0), height: Some(80.0) };
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
inner_container_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
inner_container_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 3);
assert_eq!(row_count, 4);
assert_eq!(auto_col_reps, 3);
assert_eq!(auto_row_reps, 4);
}
#[test]
fn explicit_grid_sizing_auto_fill_min_size_non_exact_fit() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
min_size: Size { width: length(140.0), height: length(90.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
..Default::default()
};
let inner_container_size = Size { width: Some(140.0), height: Some(90.0) };
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
inner_container_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
inner_container_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 4);
assert_eq!(row_count, 5);
assert_eq!(auto_col_reps, 4);
assert_eq!(auto_row_reps, 5);
}
#[test]
fn explicit_grid_sizing_auto_fill_multiple_repeated_tracks() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
size: Size { width: length(140.0), height: length(100.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0), length(20.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0), length(10.0)])],
..Default::default()
};
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 4); assert_eq!(row_count, 6); assert_eq!(auto_col_reps, 2);
assert_eq!(auto_row_reps, 3);
}
#[test]
fn explicit_grid_sizing_auto_fill_gap() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
size: Size { width: length(140.0), height: length(100.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
gap: length(20.0),
..Default::default()
};
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 2); assert_eq!(row_count, 3); assert_eq!(auto_col_reps, 2);
assert_eq!(auto_row_reps, 3);
}
#[test]
fn explicit_grid_sizing_no_defined_size() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
grid_template_columns: vec![repeat(AutoFill, vec![length(40.0), percent(0.5), length(20.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
gap: length(20.0),
..Default::default()
};
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 3);
assert_eq!(row_count, 1);
assert_eq!(auto_col_reps, 1);
assert_eq!(auto_row_reps, 1);
}
#[test]
fn explicit_grid_sizing_mix_repeated_and_non_repeated() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
size: Size { width: length(140.0), height: length(100.0) },
grid_template_columns: vec![length(20.0), repeat(AutoFill, vec![length(40.0)])],
grid_template_rows: vec![length(40.0), repeat(AutoFill, vec![length(20.0)])],
gap: length(20.0),
..Default::default()
};
let preferred_size = grid_style.size.map(|s| s.into_option());
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
preferred_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 3); assert_eq!(row_count, 2); assert_eq!(auto_col_reps, 2);
assert_eq!(auto_row_reps, 1);
}
#[test]
fn explicit_grid_sizing_mix_with_padding() {
use RepetitionCount::AutoFill;
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
size: Size { width: length(120.0), height: length(120.0) },
padding: Rect { left: length(10.0), right: length(10.0), top: length(20.0), bottom: length(20.0) },
grid_template_columns: vec![repeat(AutoFill, vec![length(20.0)])],
grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
..Default::default()
};
let inner_container_size = Size { width: Some(100.0), height: Some(80.0) };
let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
&grid_style,
inner_container_size.get_abs(AbsoluteAxis::Horizontal),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
&grid_style,
inner_container_size.get_abs(AbsoluteAxis::Vertical),
AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
|_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(col_count, 5); assert_eq!(row_count, 4); assert_eq!(auto_col_reps, 5);
assert_eq!(auto_row_reps, 4);
}
#[test]
fn test_initialize_grid_tracks() {
let minpx0 = MinTrackSizingFunction::from_length(0.0);
let minpx20 = MinTrackSizingFunction::from_length(20.0);
let minpx100 = MinTrackSizingFunction::from_length(100.0);
let maxpx0 = MaxTrackSizingFunction::from_length(0.0);
let maxpx20 = MaxTrackSizingFunction::from_length(20.0);
let maxpx100 = MaxTrackSizingFunction::from_length(100.0);
let grid_style: Style<DefaultCheapStr> = Style {
display: Display::Grid,
gap: length(20.0),
grid_template_columns: vec![length(100.0), minmax(length(100.0), fr(2.0)), fr(1.0)],
grid_auto_columns: vec![auto(), length(100.0)],
..Default::default()
};
let track_counts = TrackCounts {
negative_implicit: 3,
explicit: grid_style.grid_template_columns.len() as u16,
positive_implicit: 3,
};
let mut tracks = Vec::new();
initialize_grid_tracks(&mut tracks, track_counts, &grid_style, AbsoluteAxis::Horizontal, |_| false);
let expected = vec![
(GridTrackKind::Gutter, minpx0, maxpx0),
(GridTrackKind::Track, minpx100, maxpx100),
(GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, auto(), auto()),
(GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, minpx100, maxpx100),
(GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, minpx100, maxpx100),
(GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, minpx100, MaxTrackSizingFunction::from_fr(2.0)), (GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, auto(), MaxTrackSizingFunction::from_fr(1.0)), (GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, auto(), auto()),
(GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, minpx100, maxpx100),
(GridTrackKind::Gutter, minpx20, maxpx20),
(GridTrackKind::Track, auto(), auto()),
(GridTrackKind::Gutter, minpx0, maxpx0),
];
assert_eq!(tracks.len(), expected.len(), "Number of tracks doesn't match");
for (idx, (actual, (kind, min, max))) in tracks.into_iter().zip(expected).enumerate() {
assert_eq!(actual.kind, kind, "Track {idx} (0-based index)");
assert_eq!(actual.min_track_sizing_function, min, "Track {idx} (0-based index)");
assert_eq!(actual.max_track_sizing_function, max, "Track {idx} (0-based index)");
}
}
}