typst_library/layout/
regions.rs1use std::fmt::{self, Debug, Formatter};
2
3use crate::layout::{Abs, Axes, Size};
4
5#[derive(Debug, Copy, Clone, Hash)]
7pub struct Region {
8    pub size: Size,
10    pub expand: Axes<bool>,
13}
14
15impl Region {
16    pub fn new(size: Size, expand: Axes<bool>) -> Self {
18        Self { size, expand }
19    }
20}
21
22impl From<Region> for Regions<'_> {
23    fn from(region: Region) -> Self {
24        Regions {
25            size: region.size,
26            expand: region.expand,
27            full: region.size.y,
28            backlog: &[],
29            last: None,
30        }
31    }
32}
33
34#[derive(Copy, Clone, Hash)]
42pub struct Regions<'a> {
43    pub size: Size,
45    pub expand: Axes<bool>,
48    pub full: Abs,
50    pub backlog: &'a [Abs],
52    pub last: Option<Abs>,
55}
56
57impl Regions<'_> {
58    pub fn repeat(size: Size, expand: Axes<bool>) -> Self {
60        Self {
61            size,
62            full: size.y,
63            backlog: &[],
64            last: Some(size.y),
65            expand,
66        }
67    }
68
69    pub fn base(&self) -> Size {
74        Size::new(self.size.x, self.full)
75    }
76
77    pub fn map<'v, F>(&self, backlog: &'v mut Vec<Abs>, mut f: F) -> Regions<'v>
82    where
83        F: FnMut(Size) -> Size,
84    {
85        let x = self.size.x;
86        backlog.clear();
87        backlog.extend(self.backlog.iter().map(|&y| f(Size::new(x, y)).y));
88        Regions {
89            size: f(self.size),
90            full: f(Size::new(x, self.full)).y,
91            backlog,
92            last: self.last.map(|y| f(Size::new(x, y)).y),
93            expand: self.expand,
94        }
95    }
96
97    pub fn is_full(&self) -> bool {
99        Abs::zero().fits(self.size.y) && self.may_progress()
100    }
101
102    pub fn may_break(&self) -> bool {
104        !self.backlog.is_empty() || self.last.is_some()
105    }
106
107    pub fn may_progress(&self) -> bool {
110        !self.backlog.is_empty() || self.last.is_some_and(|height| self.size.y != height)
111    }
112
113    pub fn next(&mut self) {
115        if let Some(height) = self
116            .backlog
117            .split_first()
118            .map(|(first, tail)| {
119                self.backlog = tail;
120                *first
121            })
122            .or(self.last)
123        {
124            self.size.y = height;
125            self.full = height;
126        }
127    }
128
129    pub fn iter(&self) -> impl Iterator<Item = Size> + '_ {
134        let first = std::iter::once(self.size);
135        let backlog = self.backlog.iter();
136        let last = self.last.iter().cycle();
137        first.chain(backlog.chain(last).map(|&h| Size::new(self.size.x, h)))
138    }
139}
140
141impl Debug for Regions<'_> {
142    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
143        f.write_str("Regions ")?;
144        let mut list = f.debug_list();
145        let mut prev = self.size.y;
146        list.entry(&self.size);
147        for &height in self.backlog {
148            list.entry(&Size::new(self.size.x, height));
149            prev = height;
150        }
151        if let Some(last) = self.last {
152            if last != prev {
153                list.entry(&Size::new(self.size.x, last));
154            }
155            list.entry(&(..));
156        }
157        list.finish()
158    }
159}