//! Style type for representing available space as a sizing constraint use crate::{ prelude::{FromLength, TaffyMaxContent, TaffyMinContent, TaffyZero}, sys::abs, Size, }; /// The amount of space available to a node in a given axis /// #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize))] pub enum AvailableSpace { /// The amount of space available is the specified number of pixels Definite(f32), /// The amount of space available is indefinite and the node should be laid out under a min-content constraint MinContent, /// The amount of space available is indefinite and the node should be laid out under a max-content constraint MaxContent, } impl TaffyZero for AvailableSpace { const ZERO: Self = Self::Definite(0.0); } impl TaffyMaxContent for AvailableSpace { const MAX_CONTENT: Self = Self::MaxContent; } impl TaffyMinContent for AvailableSpace { const MIN_CONTENT: Self = Self::MinContent; } impl FromLength for AvailableSpace { fn from_length + Copy>(value: Input) -> Self { Self::Definite(value.into()) } } impl AvailableSpace { /// Returns true for definite values, else false pub const fn is_definite(self) -> bool { matches!(self, AvailableSpace::Definite(_)) } /// Convert to Option /// Definite values become Some(value). Constraints become None. pub const fn into_option(self) -> Option { match self { AvailableSpace::Definite(value) => Some(value), _ => None, } } /// Return the definite value or a default value pub fn unwrap_or(self, default: f32) -> f32 { self.into_option().unwrap_or(default) } /// Return the definite value. Panic is the value is not definite. #[track_caller] pub fn unwrap(self) -> f32 { self.into_option().unwrap() } /// Return self if definite or a default value pub fn or(self, default: AvailableSpace) -> AvailableSpace { match self { AvailableSpace::Definite(_) => self, _ => default, } } /// Return self if definite or a the result of the default value callback pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace { match self { AvailableSpace::Definite(_) => self, _ => default_cb(), } } /// Return the definite value or the result of the default value callback pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 { self.into_option().unwrap_or_else(default_cb) } /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self pub fn maybe_set(self, value: Option) -> AvailableSpace { match value { Some(value) => AvailableSpace::Definite(value), None => self, } } /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace { match self { AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)), _ => self, } } /// Compute free_space given the passed used_space pub fn compute_free_space(&self, used_space: f32) -> f32 { match self { AvailableSpace::MaxContent => f32::INFINITY, AvailableSpace::MinContent => 0.0, AvailableSpace::Definite(available_space) => available_space - used_space, } } /// Compare equality with another AvailableSpace, treating definite values /// that are within f32::EPSILON of each other as equal pub fn is_roughly_equal(self, other: AvailableSpace) -> bool { use AvailableSpace::*; match (self, other) { (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON, (MinContent, MinContent) => true, (MaxContent, MaxContent) => true, _ => false, } } } impl From for AvailableSpace { fn from(value: f32) -> Self { Self::Definite(value) } } impl From> for AvailableSpace { fn from(option: Option) -> Self { match option { Some(value) => Self::Definite(value), None => Self::MaxContent, } } } impl Size { /// Convert `Size` into `Size>` pub fn into_options(self) -> Size> { Size { width: self.width.into_option(), height: self.height.into_option() } } /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self pub fn maybe_set(self, value: Size>) -> Size { Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) } } }