taffy/style/
available_space.rs

1//! Style type for representing available space as a sizing constraint
2use crate::{
3    prelude::{FromLength, TaffyMaxContent, TaffyMinContent, TaffyZero},
4    sys::abs,
5    Size,
6};
7
8/// The amount of space available to a node in a given axis
9/// <https://www.w3.org/TR/css-sizing-3/#available>
10#[derive(Copy, Clone, Debug, PartialEq)]
11#[cfg_attr(feature = "serde", derive(Serialize))]
12pub enum AvailableSpace {
13    /// The amount of space available is the specified number of pixels
14    Definite(f32),
15    /// The amount of space available is indefinite and the node should be laid out under a min-content constraint
16    MinContent,
17    /// The amount of space available is indefinite and the node should be laid out under a max-content constraint
18    MaxContent,
19}
20impl TaffyZero for AvailableSpace {
21    const ZERO: Self = Self::Definite(0.0);
22}
23impl TaffyMaxContent for AvailableSpace {
24    const MAX_CONTENT: Self = Self::MaxContent;
25}
26impl TaffyMinContent for AvailableSpace {
27    const MIN_CONTENT: Self = Self::MinContent;
28}
29impl FromLength for AvailableSpace {
30    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
31        Self::Definite(value.into())
32    }
33}
34
35impl AvailableSpace {
36    /// Returns true for definite values, else false
37    pub fn is_definite(self) -> bool {
38        matches!(self, AvailableSpace::Definite(_))
39    }
40
41    /// Convert to Option
42    /// Definite values become Some(value). Constraints become None.
43    pub fn into_option(self) -> Option<f32> {
44        match self {
45            AvailableSpace::Definite(value) => Some(value),
46            _ => None,
47        }
48    }
49
50    /// Return the definite value or a default value
51    pub fn unwrap_or(self, default: f32) -> f32 {
52        self.into_option().unwrap_or(default)
53    }
54
55    /// Return the definite value. Panic is the value is not definite.
56    #[track_caller]
57    pub fn unwrap(self) -> f32 {
58        self.into_option().unwrap()
59    }
60
61    /// Return self if definite or a default value
62    pub fn or(self, default: AvailableSpace) -> AvailableSpace {
63        match self {
64            AvailableSpace::Definite(_) => self,
65            _ => default,
66        }
67    }
68
69    /// Return self if definite or a the result of the default value callback
70    pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace {
71        match self {
72            AvailableSpace::Definite(_) => self,
73            _ => default_cb(),
74        }
75    }
76
77    /// Return the definite value or the result of the default value callback
78    pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 {
79        self.into_option().unwrap_or_else(default_cb)
80    }
81
82    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
83    pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
84        match value {
85            Some(value) => AvailableSpace::Definite(value),
86            None => self,
87        }
88    }
89
90    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
91    pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace {
92        match self {
93            AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)),
94            _ => self,
95        }
96    }
97
98    /// Compute free_space given the passed used_space
99    pub fn compute_free_space(&self, used_space: f32) -> f32 {
100        match self {
101            AvailableSpace::MaxContent => f32::INFINITY,
102            AvailableSpace::MinContent => 0.0,
103            AvailableSpace::Definite(available_space) => available_space - used_space,
104        }
105    }
106
107    /// Compare equality with another AvailableSpace, treating definite values
108    /// that are within f32::EPSILON of each other as equal
109    pub fn is_roughly_equal(self, other: AvailableSpace) -> bool {
110        use AvailableSpace::*;
111        match (self, other) {
112            (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON,
113            (MinContent, MinContent) => true,
114            (MaxContent, MaxContent) => true,
115            _ => false,
116        }
117    }
118}
119
120impl From<f32> for AvailableSpace {
121    fn from(value: f32) -> Self {
122        Self::Definite(value)
123    }
124}
125
126impl From<Option<f32>> for AvailableSpace {
127    fn from(option: Option<f32>) -> Self {
128        match option {
129            Some(value) => Self::Definite(value),
130            None => Self::MaxContent,
131        }
132    }
133}
134
135impl Size<AvailableSpace> {
136    /// Convert `Size<AvailableSpace>` into `Size<Option<f32>>`
137    pub fn into_options(self) -> Size<Option<f32>> {
138        Size { width: self.width.into_option(), height: self.height.into_option() }
139    }
140
141    /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
142    pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> {
143        Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) }
144    }
145}