taffy/style/
available_space.rs1use crate::{
3 prelude::{FromLength, TaffyMaxContent, TaffyMinContent, TaffyZero},
4 sys::abs,
5 Size,
6};
7
8#[cfg(feature = "parse")]
9use crate::util::parse::{from_str_from_css, parse_css_str_entirely, CssParseResult, FromCss, Parser, Token};
10
11#[derive(Copy, Clone, Debug, PartialEq)]
14#[cfg_attr(feature = "serde", derive(Serialize))]
15pub enum AvailableSpace {
16 Definite(f32),
18 MinContent,
20 MaxContent,
22}
23impl TaffyZero for AvailableSpace {
24 const ZERO: Self = Self::Definite(0.0);
25}
26impl TaffyMaxContent for AvailableSpace {
27 const MAX_CONTENT: Self = Self::MaxContent;
28}
29impl TaffyMinContent for AvailableSpace {
30 const MIN_CONTENT: Self = Self::MinContent;
31}
32impl FromLength for AvailableSpace {
33 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
34 Self::Definite(value.into())
35 }
36}
37
38#[cfg(feature = "parse")]
39impl FromCss for AvailableSpace {
40 fn from_css<'i>(parser: &mut Parser<'i, '_>) -> CssParseResult<'i, Self> {
41 match parser.next()?.clone() {
42 Token::Number { value, .. } if value >= 0.0 => Ok(Self::Definite(value)),
43 Token::Dimension { value, .. } if value >= 0.0 => Ok(Self::Definite(value)),
44 Token::Ident(ident) if ident == "max-content" => Ok(Self::MaxContent),
45 Token::Ident(ident) if ident == "min-content" => Ok(Self::MinContent),
46 token => Err(parser.new_unexpected_token_error(token))?,
47 }
48 }
49}
50#[cfg(feature = "parse")]
51from_str_from_css!(AvailableSpace);
52
53impl AvailableSpace {
54 pub const fn is_definite(self) -> bool {
56 matches!(self, AvailableSpace::Definite(_))
57 }
58
59 pub const fn into_option(self) -> Option<f32> {
62 match self {
63 AvailableSpace::Definite(value) => Some(value),
64 _ => None,
65 }
66 }
67
68 pub fn unwrap_or(self, default: f32) -> f32 {
70 self.into_option().unwrap_or(default)
71 }
72
73 #[track_caller]
75 pub fn unwrap(self) -> f32 {
76 self.into_option().unwrap()
77 }
78
79 pub fn or(self, default: AvailableSpace) -> AvailableSpace {
81 match self {
82 AvailableSpace::Definite(_) => self,
83 _ => default,
84 }
85 }
86
87 pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace {
89 match self {
90 AvailableSpace::Definite(_) => self,
91 _ => default_cb(),
92 }
93 }
94
95 pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 {
97 self.into_option().unwrap_or_else(default_cb)
98 }
99
100 pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
102 match value {
103 Some(value) => AvailableSpace::Definite(value),
104 None => self,
105 }
106 }
107
108 pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace {
110 match self {
111 AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)),
112 _ => self,
113 }
114 }
115
116 pub fn compute_free_space(&self, used_space: f32) -> f32 {
118 match self {
119 AvailableSpace::MaxContent => f32::INFINITY,
120 AvailableSpace::MinContent => 0.0,
121 AvailableSpace::Definite(available_space) => available_space - used_space,
122 }
123 }
124
125 pub fn is_roughly_equal(self, other: AvailableSpace) -> bool {
128 use AvailableSpace::*;
129 match (self, other) {
130 (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON,
131 (MinContent, MinContent) => true,
132 (MaxContent, MaxContent) => true,
133 _ => false,
134 }
135 }
136}
137
138impl From<f32> for AvailableSpace {
139 fn from(value: f32) -> Self {
140 Self::Definite(value)
141 }
142}
143
144impl From<Option<f32>> for AvailableSpace {
145 fn from(option: Option<f32>) -> Self {
146 match option {
147 Some(value) => Self::Definite(value),
148 None => Self::MaxContent,
149 }
150 }
151}
152
153impl Size<AvailableSpace> {
154 pub fn into_options(self) -> Size<Option<f32>> {
156 Size { width: self.width.into_option(), height: self.height.into_option() }
157 }
158
159 pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> {
161 Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) }
162 }
163}