From 75a4cfb2e43e8d872ccbdd8a170fbf172d7497e7 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Tue, 10 Jun 2025 02:31:53 -0300 Subject: [PATCH] change Repeatable to struct --- crates/typst-layout/src/grid/layouter.rs | 22 +++++---- crates/typst-layout/src/grid/repeated.rs | 18 +++----- crates/typst-layout/src/grid/rowspans.rs | 27 ++++++----- .../typst-library/src/layout/grid/resolve.rs | 46 ++++++++----------- 4 files changed, 54 insertions(+), 59 deletions(-) diff --git a/crates/typst-layout/src/grid/layouter.rs b/crates/typst-layout/src/grid/layouter.rs index 0d86cbdfa..8a6e1fc34 100644 --- a/crates/typst-layout/src/grid/layouter.rs +++ b/crates/typst-layout/src/grid/layouter.rs @@ -274,7 +274,8 @@ impl<'a> GridLayouter<'a> { pub fn layout(mut self, engine: &mut Engine) -> SourceResult { self.measure_columns(engine)?; - if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { + if let Some(footer) = self.grid.footer.as_ref().and_then(Repeatable::as_repeated) + { // Ensure rows in the first region will be aware of the possible // presence of the footer. self.prepare_footer(footer, engine, 0)?; @@ -296,7 +297,9 @@ impl<'a> GridLayouter<'a> { } } - if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { + if let Some(footer) = + self.grid.footer.as_ref().and_then(Repeatable::as_repeated) + { if y >= footer.start { if y == footer.start { self.layout_footer(footer, engine, self.finished.len())?; @@ -1564,14 +1567,15 @@ impl<'a> GridLayouter<'a> { // TODO(subfooters): explicitly check for short-lived footers. // TODO(subfooters): widow prevention for non-repeated footers with a // similar mechanism / when implementing multiple footers. - let footer_would_be_widow = - matches!(self.grid.footer, Some(Repeatable::Repeated(_))) - && self.current.lrows.is_empty() - && self.current.could_progress_at_top; + let footer_would_be_widow = matches!(&self.grid.footer, Some(footer) if footer.repeated) + && self.current.lrows.is_empty() + && self.current.could_progress_at_top; let mut laid_out_footer_start = None; if !footer_would_be_widow { - if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { + if let Some(footer) = + self.grid.footer.as_ref().and_then(Repeatable::as_repeated) + { // Don't layout the footer if it would be alone with the header // in the page (hence the widow check), and don't layout it // twice (check below). @@ -1735,7 +1739,9 @@ impl<'a> GridLayouter<'a> { self.current.repeating_header_heights.clear(); let disambiguator = self.finished.len(); - if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { + if let Some(footer) = + self.grid.footer.as_ref().and_then(Repeatable::as_repeated) + { self.prepare_footer(footer, engine, disambiguator)?; } diff --git a/crates/typst-layout/src/grid/repeated.rs b/crates/typst-layout/src/grid/repeated.rs index 4f74210eb..61ef6988d 100644 --- a/crates/typst-layout/src/grid/repeated.rs +++ b/crates/typst-layout/src/grid/repeated.rs @@ -170,7 +170,7 @@ impl<'a> GridLayouter<'a> { } for header in self.pending_headers { - if let Repeatable::Repeated(header) = header { + if header.repeated { // Vector remains sorted by increasing levels: // - 'pending_headers' themselves are sorted, since we only // push non-mutually-conflicting headers at a time. @@ -238,8 +238,8 @@ impl<'a> GridLayouter<'a> { self.current.initial_after_repeats = self.regions.size.y; } - if let Some(Repeatable::Repeated(footer)) = &self.grid.footer { - if skipped_region { + if let Some(footer) = &self.grid.footer { + if footer.repeated && skipped_region { // Simulate the footer again; the region's 'full' might have // changed. self.regions.size.y += self.current.footer_height; @@ -321,13 +321,13 @@ impl<'a> GridLayouter<'a> { let mut has_non_repeated_pending_header = false; for header in self.pending_headers { - if matches!(header, Repeatable::NotRepeated(_)) { + if !header.repeated { self.current.initial_after_repeats = self.regions.size.y; has_non_repeated_pending_header = true; } let header_height = self.layout_header_rows(header.unwrap(), engine, disambiguator, false)?; - if matches!(header, Repeatable::Repeated(_)) { + if header.repeated { self.current.repeating_header_height += header_height; self.current.repeating_header_heights.push(header_height); } @@ -410,7 +410,7 @@ impl<'a> GridLayouter<'a> { // it is guaranteed this header won't appear in a future // region, so multi-page rows and cells can effectively ignore // this header. - if !short_lived && matches!(header, Repeatable::Repeated(_)) { + if !short_lived && header.repeated { self.current.repeating_header_height += header_height; self.current.repeating_header_heights.push(header_height); if at_top { @@ -519,11 +519,7 @@ impl<'a> GridLayouter<'a> { // anyway, so this is mostly for correctness. self.regions.size.y += self.current.footer_height; - let repeats = self - .grid - .footer - .as_ref() - .is_some_and(|f| matches!(f, Repeatable::Repeated(_))); + let repeats = self.grid.footer.as_ref().is_some_and(|f| f.repeated); let footer_len = self.grid.rows.len() - footer.start; self.unbreakable_rows_left += footer_len; diff --git a/crates/typst-layout/src/grid/rowspans.rs b/crates/typst-layout/src/grid/rowspans.rs index b391f7e79..02ea14813 100644 --- a/crates/typst-layout/src/grid/rowspans.rs +++ b/crates/typst-layout/src/grid/rowspans.rs @@ -238,8 +238,8 @@ impl GridLayouter<'_> { // current row is dynamic and depends on the amount of upcoming // unbreakable cells (with or without a rowspan setting). let mut amount_unbreakable_rows = None; - if let Some(Repeatable::NotRepeated(footer)) = &self.grid.footer { - if current_row >= footer.start { + if let Some(footer) = &self.grid.footer { + if !footer.repeated && current_row >= footer.start { // Non-repeated footer, so keep it unbreakable. // // TODO(subfooters): This will become unnecessary @@ -400,7 +400,7 @@ impl GridLayouter<'_> { if breakable && (!self.repeating_headers.is_empty() || !self.pending_headers.is_empty() - || matches!(self.grid.footer, Some(Repeatable::Repeated(_)))) + || matches!(&self.grid.footer, Some(footer) if footer.repeated)) { // Subtract header and footer height from all upcoming regions // when measuring the cell, including the last repeated region. @@ -1176,14 +1176,15 @@ impl<'a> RowspanSimulator<'a> { (None, Abs::zero()) }; - let footer_height = - if let Some(Repeatable::Repeated(footer)) = &layouter.grid.footer { - layouter - .simulate_footer(footer, &self.regions, engine, disambiguator)? - .height - } else { - Abs::zero() - }; + let footer_height = if let Some(footer) = + layouter.grid.footer.as_ref().and_then(Repeatable::as_repeated) + { + layouter + .simulate_footer(footer, &self.regions, engine, disambiguator)? + .height + } else { + Abs::zero() + }; let mut skipped_region = false; @@ -1211,7 +1212,9 @@ impl<'a> RowspanSimulator<'a> { }; } - if let Some(Repeatable::Repeated(footer)) = &layouter.grid.footer { + if let Some(footer) = + layouter.grid.footer.as_ref().and_then(Repeatable::as_repeated) + { self.footer_height = if skipped_region { // Simulate footers again, at the new region, as // the full region height may change. diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index 8641c3659..d6a67d12c 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -465,23 +465,23 @@ impl Footer { } } -/// A possibly repeatable grid child. +/// A possibly repeatable grid child (header or footer). /// /// It still exists even when not repeatable, but must not have additional /// considerations by grid layout, other than for consistency (such as making /// a certain group of rows unbreakable). -pub enum Repeatable { - /// The user asked this grid child to repeat. - Repeated(T), - /// The user asked this grid child to not repeat. - NotRepeated(T), +pub struct Repeatable { + inner: T, + + /// Whether the user requested the child to repeat. + pub repeated: bool, } impl Deref for Repeatable { type Target = T; fn deref(&self) -> &Self::Target { - self.unwrap() + &self.inner } } @@ -490,28 +490,23 @@ impl Repeatable { /// it repeats. #[inline] pub fn unwrap(&self) -> &T { - match self { - Self::Repeated(repeated) => repeated, - Self::NotRepeated(not_repeated) => not_repeated, - } + &self.inner } /// Gets the value inside this repeatable, regardless of whether /// it repeats (mutably). #[inline] pub fn unwrap_mut(&mut self) -> &mut T { - match self { - Self::Repeated(repeated) => repeated, - Self::NotRepeated(not_repeated) => not_repeated, - } + &mut self.inner } /// Returns `Some` if the value is repeated, `None` otherwise. #[inline] pub fn as_repeated(&self) -> Option<&T> { - match self { - Self::Repeated(repeated) => Some(repeated), - Self::NotRepeated(_) => None, + if self.repeated { + Some(&self.inner) + } else { + None } } } @@ -906,7 +901,7 @@ impl<'a> CellGrid<'a> { #[inline] pub fn has_repeated_headers(&self) -> bool { - self.headers.iter().any(|h| matches!(h, Repeatable::Repeated(_))) + self.headers.iter().any(|h| h.repeated) } } @@ -1614,11 +1609,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> { conflicting_header.unwrap_mut().short_lived = true; } - headers.push(if row_group.repeat { - Repeatable::Repeated(data) - } else { - Repeatable::NotRepeated(data) - }); + headers.push(Repeatable { inner: data, repeated: row_group.repeat }); } RowGroupKind::Footer => { @@ -1920,10 +1911,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> { // footers. // TODO(subfooters): Switch this to marking the last N // consecutive footers as short lived. - if repeat_footer && at_least_one_cell { - Repeatable::Repeated(footer) - } else { - Repeatable::NotRepeated(footer) + Repeatable { + inner: footer, + repeated: repeat_footer && at_least_one_cell, } });