use crate::reactive::Prop;
pub(crate) trait AllFinite {
fn all_finite(&self) -> bool;
}
impl AllFinite for f32 {
fn all_finite(&self) -> bool {
f32::is_finite(*self)
}
}
pub(crate) trait FiniteOr<T> {
fn get_finite_or(&self, default: T, id: crate::tree::WidgetId, property: &'static str) -> T;
fn get_finite_or_quietly(&self, default: T) -> T;
}
impl<T: AllFinite + Clone + 'static> FiniteOr<T> for Prop<T> {
fn get_finite_or(&self, default: T, id: crate::tree::WidgetId, property: &'static str) -> T {
match self.get() {
Some(value) if value.all_finite() => value,
Some(_) => {
crate::reactive::diagnostics::non_finite_value(id, property);
default
}
None => default,
}
}
fn get_finite_or_quietly(&self, default: T) -> T {
match self.get() {
Some(value) if value.all_finite() => value,
_ => default,
}
}
}
pub(crate) fn first_finite_override<T: AllFinite + Clone + 'static>(
overrides: &[Prop<T>],
base: T,
) -> T {
for declared in overrides {
if let Some(value) = declared.get()
&& value.all_finite()
{
return value;
}
}
base
}
macro_rules! finite_by_channels {
($($t:ty),* $(,)?) => {
$(impl AllFinite for $t {
fn all_finite(&self) -> bool {
crate::animation::Animatable::channels(self)
.iter()
.copied()
.all(f32::is_finite)
}
})*
};
}
finite_by_channels!(
crate::widgets::Color,
crate::renderer::Shadow,
crate::widgets::Padding,
crate::widgets::Corners,
crate::transform::Translate,
crate::transform::Scale,
);
impl AllFinite for crate::widgets::LinearGradient {
fn all_finite(&self) -> bool {
self.start_color.all_finite() && self.end_color.all_finite()
}
}
impl<T: AllFinite> AllFinite for Option<T> {
fn all_finite(&self) -> bool {
self.as_ref().is_none_or(AllFinite::all_finite)
}
}
impl AllFinite for crate::layout::Length {
fn all_finite(&self) -> bool {
[self.extent().declared_size(), self.min(), self.max()]
.into_iter()
.flatten()
.all(f32::is_finite)
}
}
impl AllFinite for crate::pivot::Pivot {
fn all_finite(&self) -> bool {
use crate::pivot::{HorizontalAnchor as H, VerticalAnchor as V};
let horizontal = match self.horizontal {
H::Percent(p) | H::Px(p) => p.is_finite(),
_ => true,
};
let vertical = match self.vertical {
V::Percent(p) | V::Px(p) => p.is_finite(),
_ => true,
};
horizontal && vertical
}
}