1use crate::geometry::{Rect, Size};
4use crate::style_helpers::{FromLength, FromPercent, TaffyAuto, TaffyMaxContent, TaffyMinContent, TaffyZero};
5use crate::util::sys::abs;
6
7#[derive(Copy, Clone, PartialEq, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub enum LengthPercentage {
13 Length(f32),
16 Percent(f32),
20}
21impl TaffyZero for LengthPercentage {
22 const ZERO: Self = Self::Length(0.0);
23}
24impl FromLength for LengthPercentage {
25 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
26 Self::Length(value.into())
27 }
28}
29impl FromPercent for LengthPercentage {
30 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
31 Self::Percent(percent.into())
32 }
33}
34
35#[derive(Copy, Clone, PartialEq, Debug)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub enum LengthPercentageAuto {
41 Length(f32),
44 Percent(f32),
48 Auto,
50}
51impl TaffyZero for LengthPercentageAuto {
52 const ZERO: Self = Self::Length(0.0);
53}
54impl TaffyAuto for LengthPercentageAuto {
55 const AUTO: Self = Self::Auto;
56}
57impl FromLength for LengthPercentageAuto {
58 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
59 Self::Length(value.into())
60 }
61}
62impl FromPercent for LengthPercentageAuto {
63 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
64 Self::Percent(percent.into())
65 }
66}
67
68impl From<LengthPercentage> for LengthPercentageAuto {
69 fn from(input: LengthPercentage) -> Self {
70 match input {
71 LengthPercentage::Length(value) => Self::Length(value),
72 LengthPercentage::Percent(value) => Self::Percent(value),
73 }
74 }
75}
76
77impl LengthPercentageAuto {
78 #[inline(always)]
83 pub fn resolve_to_option(self, context: f32) -> Option<f32> {
84 match self {
85 Self::Length(length) => Some(length),
86 Self::Percent(percent) => Some(context * percent),
87 Self::Auto => None,
88 }
89 }
90
91 #[inline(always)]
93 pub fn is_auto(self) -> bool {
94 self == Self::Auto
95 }
96}
97
98#[derive(Copy, Clone, PartialEq, Debug)]
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103pub enum Dimension {
104 Length(f32),
107 Percent(f32),
111 Auto,
113}
114impl TaffyZero for Dimension {
115 const ZERO: Self = Self::Length(0.0);
116}
117impl TaffyAuto for Dimension {
118 const AUTO: Self = Self::Auto;
119}
120impl FromLength for Dimension {
121 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
122 Self::Length(value.into())
123 }
124}
125impl FromPercent for Dimension {
126 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
127 Self::Percent(percent.into())
128 }
129}
130
131impl From<LengthPercentage> for Dimension {
132 fn from(input: LengthPercentage) -> Self {
133 match input {
134 LengthPercentage::Length(value) => Self::Length(value),
135 LengthPercentage::Percent(value) => Self::Percent(value),
136 }
137 }
138}
139
140impl From<LengthPercentageAuto> for Dimension {
141 fn from(input: LengthPercentageAuto) -> Self {
142 match input {
143 LengthPercentageAuto::Length(value) => Self::Length(value),
144 LengthPercentageAuto::Percent(value) => Self::Percent(value),
145 LengthPercentageAuto::Auto => Self::Auto,
146 }
147 }
148}
149
150impl Dimension {
151 #[cfg(feature = "grid")]
153 pub fn into_option(self) -> Option<f32> {
154 match self {
155 Dimension::Length(value) => Some(value),
156 _ => None,
157 }
158 }
159}
160
161impl Rect<Dimension> {
162 #[must_use]
164 pub const fn from_length(start: f32, end: f32, top: f32, bottom: f32) -> Self {
165 Rect {
166 left: Dimension::Length(start),
167 right: Dimension::Length(end),
168 top: Dimension::Length(top),
169 bottom: Dimension::Length(bottom),
170 }
171 }
172
173 #[must_use]
175 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
176 Rect {
177 left: Dimension::Percent(start),
178 right: Dimension::Percent(end),
179 top: Dimension::Percent(top),
180 bottom: Dimension::Percent(bottom),
181 }
182 }
183}
184
185#[derive(Copy, Clone, Debug, PartialEq)]
188#[cfg_attr(feature = "serde", derive(Serialize))]
189pub enum AvailableSpace {
190 Definite(f32),
192 MinContent,
194 MaxContent,
196}
197impl TaffyZero for AvailableSpace {
198 const ZERO: Self = Self::Definite(0.0);
199}
200impl TaffyMaxContent for AvailableSpace {
201 const MAX_CONTENT: Self = Self::MaxContent;
202}
203impl TaffyMinContent for AvailableSpace {
204 const MIN_CONTENT: Self = Self::MinContent;
205}
206impl FromLength for AvailableSpace {
207 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
208 Self::Definite(value.into())
209 }
210}
211
212impl AvailableSpace {
213 pub fn is_definite(self) -> bool {
215 matches!(self, AvailableSpace::Definite(_))
216 }
217
218 pub fn into_option(self) -> Option<f32> {
221 match self {
222 AvailableSpace::Definite(value) => Some(value),
223 _ => None,
224 }
225 }
226
227 pub fn unwrap_or(self, default: f32) -> f32 {
229 self.into_option().unwrap_or(default)
230 }
231
232 #[track_caller]
234 pub fn unwrap(self) -> f32 {
235 self.into_option().unwrap()
236 }
237
238 pub fn or(self, default: AvailableSpace) -> AvailableSpace {
240 match self {
241 AvailableSpace::Definite(_) => self,
242 _ => default,
243 }
244 }
245
246 pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace {
248 match self {
249 AvailableSpace::Definite(_) => self,
250 _ => default_cb(),
251 }
252 }
253
254 pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 {
256 self.into_option().unwrap_or_else(default_cb)
257 }
258
259 pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
261 match value {
262 Some(value) => AvailableSpace::Definite(value),
263 None => self,
264 }
265 }
266
267 pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace {
269 match self {
270 AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)),
271 _ => self,
272 }
273 }
274
275 pub fn compute_free_space(&self, used_space: f32) -> f32 {
277 match self {
278 AvailableSpace::MaxContent => f32::INFINITY,
279 AvailableSpace::MinContent => 0.0,
280 AvailableSpace::Definite(available_space) => available_space - used_space,
281 }
282 }
283
284 pub fn is_roughly_equal(self, other: AvailableSpace) -> bool {
287 use AvailableSpace::*;
288 match (self, other) {
289 (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON,
290 (MinContent, MinContent) => true,
291 (MaxContent, MaxContent) => true,
292 _ => false,
293 }
294 }
295}
296
297impl From<f32> for AvailableSpace {
298 fn from(value: f32) -> Self {
299 Self::Definite(value)
300 }
301}
302
303impl From<Option<f32>> for AvailableSpace {
304 fn from(option: Option<f32>) -> Self {
305 match option {
306 Some(value) => Self::Definite(value),
307 None => Self::MaxContent,
308 }
309 }
310}
311
312impl Size<AvailableSpace> {
313 pub fn into_options(self) -> Size<Option<f32>> {
315 Size { width: self.width.into_option(), height: self.height.into_option() }
316 }
317
318 pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> {
320 Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) }
321 }
322}