From 52711562cfa725e1a64cbdc0964d587c9dff8a70 Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 28 Sep 2022 21:45:47 +0200 Subject: [PATCH 01/14] Move style to module folder --- src/{style.rs => style/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{style.rs => style/mod.rs} (100%) diff --git a/src/style.rs b/src/style/mod.rs similarity index 100% rename from src/style.rs rename to src/style/mod.rs From ec5803ec50e99819462de0af701124025c177bc7 Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 28 Sep 2022 21:59:32 +0200 Subject: [PATCH 02/14] Add CalcDimension to calculate dimensions --- src/style/calc_dimension.rs | 19 +++++++++++++++++++ src/style/mod.rs | 12 ++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/style/calc_dimension.rs diff --git a/src/style/calc_dimension.rs b/src/style/calc_dimension.rs new file mode 100644 index 000000000..f040bfdd5 --- /dev/null +++ b/src/style/calc_dimension.rs @@ -0,0 +1,19 @@ +use super::Dimension; + +/// A [`Dimension`] calculation. +/// +/// The values are calulated when the point values are resolved. +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum CalcDimension { + /// Add two [`Dimension`]s together. + Add(Box, Box), + + /// Subtract the right [`Dimension`] from the left one. + Sub(Box, Box), + + /// Multiply a [`Dimension`] with a constant. + Mul(Box, f32), + + /// Divide a [`Dimension`] by a constant. + Div(Box, f32), +} diff --git a/src/style/mod.rs b/src/style/mod.rs index d1f11dd86..b8395db34 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -1,7 +1,11 @@ //! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout +mod calc_dimension; + use crate::geometry::{Rect, Size}; +use self::calc_dimension::CalcDimension; + /// How [`Nodes`](crate::node::Node) are aligned relative to the cross axis /// /// The default behavior is [`AlignItems::Stretch`]. @@ -258,14 +262,22 @@ impl Default for FlexWrap { pub enum Dimension { /// The dimension is not given Undefined, + /// The dimension should be automatically computed Auto, + /// The dimension is stored in [points](https://en.wikipedia.org/wiki/Point_(typography)) /// /// Each point is about 0.353 mm in size. Points(f32), + /// The dimension is stored in percentage relative to the parent item. Percent(f32), + + /// A calculation of dimensions, similar to CSS's `calc()`. + /// + /// One use-case of this is to add a percentage value to a points value. + Calc(CalcDimension), } impl Default for Dimension { From 20710d2f795aea2cd77768c08e6cd340460ba06c Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Thu, 29 Sep 2022 19:32:34 +0200 Subject: [PATCH 03/14] Fix errors caused by Dimension not being Copy --- src/flexbox.rs | 11 +++++----- src/resolve.rs | 16 +++++++------- src/style/calc_dimension.rs | 4 +++- src/style/mod.rs | 42 ++++++++++++++++++------------------- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/flexbox.rs b/src/flexbox.rs index 2cc894871..ca5bfe6d9 100644 --- a/src/flexbox.rs +++ b/src/flexbox.rs @@ -109,7 +109,7 @@ struct AlgoConstants { impl Taffy { /// Computes the layout of [`Taffy`] according to the flexbox algorithm pub(crate) fn compute(&mut self, root: Node, size: Size>) { - let style = self.nodes[root].style; + let style = self.nodes[root].style.clone(); let has_root_min_max = style.min_size.width.is_defined() || style.min_size.height.is_defined() || style.max_size.width.is_defined() @@ -277,7 +277,7 @@ impl Taffy { min_size: child_style.min_size.maybe_resolve(constants.node_inner_size), max_size: child_style.max_size.maybe_resolve(constants.node_inner_size), - position: child_style.position.zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)), + position: child_style.position.clone().zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)), margin: child_style.margin.resolve_or_default(constants.node_inner_size.width), padding: child_style.padding.resolve_or_default(constants.node_inner_size.width), border: child_style.border.resolve_or_default(constants.node_inner_size.width), @@ -372,11 +372,12 @@ impl Taffy { ) { // TODO - this does not follow spec. See the TODOs below for child in flex_items.iter_mut() { - let child_style = self.nodes[child.node].style; + let child_style = &self.nodes[child.node].style; // A. If the item has a definite used flex basis, that’s the flex base size. - let flex_basis = child_style.flex_basis.maybe_resolve(constants.node_inner_size.main(constants.dir)); + let flex_basis = + child_style.flex_basis.clone().maybe_resolve(constants.node_inner_size.main(constants.dir)); if flex_basis.is_some() { child.flex_basis = flex_basis.unwrap_or(0.0); continue; @@ -1467,7 +1468,7 @@ impl Taffy { let container_width = constants.container_size.width.into(); let container_height = constants.container_size.height.into(); - let child_style = self.nodes[child].style; + let child_style = self.nodes[child].style.clone(); // X-axis let child_position_start = child_style.position.start.maybe_resolve(container_width); diff --git a/src/resolve.rs b/src/resolve.rs index bfe62d682..689dfb172 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -9,7 +9,7 @@ use crate::prelude::{Dimension, Rect, Size}; /// Will return a default value if it unable to resolve. pub(crate) trait ResolveOrDefault { /// Resolve a dimension that might be dependent on a context, with a default fallback value - fn resolve_or_default(self, context: TContext) -> TOutput; + fn resolve_or_default(&self, context: TContext) -> TOutput; } /// Trait to encapsulate behaviour where we need to resolve from a @@ -19,16 +19,16 @@ pub(crate) trait ResolveOrDefault { /// Will return a `None` if it unable to resolve. pub(crate) trait MaybeResolve { /// Resolve a dimension that might be dependent on a context, with `None` as fallback value - fn maybe_resolve(self, context: T) -> T; + fn maybe_resolve(&self, context: T) -> T; } impl MaybeResolve> for Dimension { /// Converts the given [`Dimension`] into a concrete value of points /// /// Can return `None` - fn maybe_resolve(self, context: Option) -> Option { + fn maybe_resolve(&self, context: Option) -> Option { match self { - Dimension::Points(points) => Some(points), + Dimension::Points(points) => Some(*points), // parent_dim * percent Dimension::Percent(percent) => context.map(|dim| dim * percent), _ => None, @@ -38,20 +38,20 @@ impl MaybeResolve> for Dimension { impl MaybeResolve>> for Size { /// Converts any `parent`-relative values for size into an absolute size - fn maybe_resolve(self, context: Size>) -> Size> { + fn maybe_resolve(&self, context: Size>) -> Size> { Size { width: self.width.maybe_resolve(context.width), height: self.height.maybe_resolve(context.height) } } } impl ResolveOrDefault, f32> for Dimension { /// Will return a default value of result is evaluated to `None` - fn resolve_or_default(self, context: Option) -> f32 { + fn resolve_or_default(&self, context: Option) -> f32 { self.maybe_resolve(context).unwrap_or(0.0) } } impl ResolveOrDefault>, Rect> for Rect { - fn resolve_or_default(self, context: Size>) -> Rect { + fn resolve_or_default(&self, context: Size>) -> Rect { Rect { start: self.start.resolve_or_default(context.width), end: self.end.resolve_or_default(context.width), @@ -62,7 +62,7 @@ impl ResolveOrDefault>, Rect> for Rect { } impl ResolveOrDefault, Rect> for Rect { - fn resolve_or_default(self, context: Option) -> Rect { + fn resolve_or_default(&self, context: Option) -> Rect { Rect { start: self.start.resolve_or_default(context), end: self.end.resolve_or_default(context), diff --git a/src/style/calc_dimension.rs b/src/style/calc_dimension.rs index f040bfdd5..4ae52ebde 100644 --- a/src/style/calc_dimension.rs +++ b/src/style/calc_dimension.rs @@ -1,9 +1,11 @@ +//! Dimensions that are have to be calculated while resolving. + use super::Dimension; /// A [`Dimension`] calculation. /// /// The values are calulated when the point values are resolved. -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] pub enum CalcDimension { /// Add two [`Dimension`]s together. Add(Box, Box), diff --git a/src/style/mod.rs b/src/style/mod.rs index b8395db34..6223f20ba 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -257,7 +257,7 @@ impl Default for FlexWrap { /// /// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size`]. /// The default value is [`Dimension::Undefined`]. -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Dimension { /// The dimension is not given @@ -288,7 +288,7 @@ impl Default for Dimension { impl Dimension { /// Is this value defined? - pub(crate) fn is_defined(self) -> bool { + pub(crate) fn is_defined(&self) -> bool { matches!(self, Dimension::Points(_) | Dimension::Percent(_)) } } @@ -379,7 +379,7 @@ impl Default for Size { /// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model). /// /// If the behavior does not match the flexbox layout algorithm on the web, please file a bug! -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(default))] pub struct FlexboxLayout { @@ -465,81 +465,81 @@ impl FlexboxLayout { /// If the `direction` is row-oriented, the min width. Otherwise the min height pub(crate) fn min_main_size(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.min_size.width + self.min_size.clone().width } else { - self.min_size.height + self.min_size.clone().height } } /// If the `direction` is row-oriented, the max width. Otherwise the max height pub(crate) fn max_main_size(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.max_size.width + self.max_size.clone().width } else { - self.max_size.height + self.max_size.clone().height } } /// If the `direction` is row-oriented, the margin start. Otherwise the margin top pub(crate) fn main_margin_start(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.margin.start + self.margin.clone().start } else { - self.margin.top + self.margin.clone().top } } /// If the `direction` is row-oriented, the margin end. Otherwise the margin bottom pub(crate) fn main_margin_end(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.margin.end + self.margin.clone().end } else { - self.margin.bottom + self.margin.clone().bottom } } /// If the `direction` is row-oriented, the height. Otherwise the width pub(crate) fn cross_size(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.size.height + self.size.clone().height } else { - self.size.width + self.size.clone().width } } /// If the `direction` is row-oriented, the min height. Otherwise the min width pub(crate) fn min_cross_size(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.min_size.height + self.min_size.clone().height } else { - self.min_size.width + self.min_size.clone().width } } /// If the `direction` is row-oriented, the max height. Otherwise the max width pub(crate) fn max_cross_size(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.max_size.height + self.max_size.clone().height } else { - self.max_size.width + self.max_size.clone().width } } /// If the `direction` is row-oriented, the margin top. Otherwise the margin start pub(crate) fn cross_margin_start(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.margin.top + self.margin.clone().top } else { - self.margin.start + self.margin.clone().start } } /// If the `direction` is row-oriented, the margin bottom. Otherwise the margin end pub(crate) fn cross_margin_end(&self, direction: FlexDirection) -> Dimension { if direction.is_row() { - self.margin.bottom + self.margin.clone().bottom } else { - self.margin.end + self.margin.clone().end } } From ed1ee24529b624839af8535b98c9032406ac37c4 Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Thu, 29 Sep 2022 19:50:49 +0200 Subject: [PATCH 04/14] Implement maybe_resolve for CalcDimension --- src/resolve.rs | 3 ++- src/style/calc_dimension.rs | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/resolve.rs b/src/resolve.rs index 689dfb172..debec062d 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -31,7 +31,8 @@ impl MaybeResolve> for Dimension { Dimension::Points(points) => Some(*points), // parent_dim * percent Dimension::Percent(percent) => context.map(|dim| dim * percent), - _ => None, + Dimension::Calc(calc) => calc.maybe_resolve(context), + Dimension::Auto | Dimension::Undefined => None, } } } diff --git a/src/style/calc_dimension.rs b/src/style/calc_dimension.rs index 4ae52ebde..bf4568961 100644 --- a/src/style/calc_dimension.rs +++ b/src/style/calc_dimension.rs @@ -1,5 +1,7 @@ //! Dimensions that are have to be calculated while resolving. +use crate::resolve::MaybeResolve; + use super::Dimension; /// A [`Dimension`] calculation. @@ -19,3 +21,23 @@ pub enum CalcDimension { /// Divide a [`Dimension`] by a constant. Div(Box, f32), } + +impl MaybeResolve> for CalcDimension { + fn maybe_resolve(&self, context: Option) -> Option { + match self { + CalcDimension::Add(lhs, rhs) => lhs + .maybe_resolve(context) + .zip(rhs.maybe_resolve(context)) + .map(|(lhs_value, rhs_value)| lhs_value + rhs_value), + + CalcDimension::Sub(lhs, rhs) => lhs + .maybe_resolve(context) + .zip(rhs.maybe_resolve(context)) + .map(|(lhs_value, rhs_value)| lhs_value - rhs_value), + + CalcDimension::Mul(lhs, factor) => lhs.maybe_resolve(context).map(|lhs_value| lhs_value * factor), + + CalcDimension::Div(lhs, divisor) => lhs.maybe_resolve(context).map(|lhs_value| lhs_value / divisor), + } + } +} From a8c495278b158df69790d624a93c461307c9d790 Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Thu, 29 Sep 2022 20:16:51 +0200 Subject: [PATCH 05/14] Move dimension to separate module --- src/style/dimension.rs | 43 +++++++++++++++++++++++++++++++++++++++++ src/style/mod.rs | 44 +++--------------------------------------- 2 files changed, 46 insertions(+), 41 deletions(-) create mode 100644 src/style/dimension.rs diff --git a/src/style/dimension.rs b/src/style/dimension.rs new file mode 100644 index 000000000..434b49db9 --- /dev/null +++ b/src/style/dimension.rs @@ -0,0 +1,43 @@ +//! A unit of linear measurement. + +use super::CalcDimension; + +/// A unit of linear measurement +/// +/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size`]. +/// The default value is [`Dimension::Undefined`]. +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum Dimension { + /// The dimension is not given + Undefined, + + /// The dimension should be automatically computed + Auto, + + /// The dimension is stored in [points](https://en.wikipedia.org/wiki/Point_(typography)) + /// + /// Each point is about 0.353 mm in size. + Points(f32), + + /// The dimension is stored in percentage relative to the parent item. + Percent(f32), + + /// A calculation of dimensions, similar to CSS's `calc()`. + /// + /// One use-case of this is to add a percentage value to a points value. + Calc(CalcDimension), +} + +impl Default for Dimension { + fn default() -> Self { + Self::Undefined + } +} + +impl Dimension { + /// Is this value defined? + pub(crate) fn is_defined(&self) -> bool { + matches!(self, Dimension::Points(_) | Dimension::Percent(_)) + } +} diff --git a/src/style/mod.rs b/src/style/mod.rs index 6223f20ba..8242d93cf 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -1,10 +1,12 @@ //! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout mod calc_dimension; +mod dimension; use crate::geometry::{Rect, Size}; -use self::calc_dimension::CalcDimension; +pub use self::calc_dimension::CalcDimension; +pub use self::dimension::Dimension; /// How [`Nodes`](crate::node::Node) are aligned relative to the cross axis /// @@ -253,46 +255,6 @@ impl Default for FlexWrap { } } -/// A unit of linear measurement -/// -/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size`]. -/// The default value is [`Dimension::Undefined`]. -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Dimension { - /// The dimension is not given - Undefined, - - /// The dimension should be automatically computed - Auto, - - /// The dimension is stored in [points](https://en.wikipedia.org/wiki/Point_(typography)) - /// - /// Each point is about 0.353 mm in size. - Points(f32), - - /// The dimension is stored in percentage relative to the parent item. - Percent(f32), - - /// A calculation of dimensions, similar to CSS's `calc()`. - /// - /// One use-case of this is to add a percentage value to a points value. - Calc(CalcDimension), -} - -impl Default for Dimension { - fn default() -> Self { - Self::Undefined - } -} - -impl Dimension { - /// Is this value defined? - pub(crate) fn is_defined(&self) -> bool { - matches!(self, Dimension::Points(_) | Dimension::Percent(_)) - } -} - impl Default for Rect { fn default() -> Self { Self { start: Default::default(), end: Default::default(), top: Default::default(), bottom: Default::default() } From 6da4f7584d6cc100b8a74ad3f24bff9cc8d9e67c Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Thu, 29 Sep 2022 20:28:54 +0200 Subject: [PATCH 06/14] Implement numerical operations for Dimension --- src/style/dimension.rs | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/style/dimension.rs b/src/style/dimension.rs index 434b49db9..10d1dcd8f 100644 --- a/src/style/dimension.rs +++ b/src/style/dimension.rs @@ -1,5 +1,7 @@ //! A unit of linear measurement. +use core::ops::{Add, Div, Mul, Sub}; + use super::CalcDimension; /// A unit of linear measurement @@ -41,3 +43,78 @@ impl Dimension { matches!(self, Dimension::Points(_) | Dimension::Percent(_)) } } + +impl Add for Dimension { + type Output = Dimension; + + fn add(self, rhs: Dimension) -> Self::Output { + match (self, rhs) { + (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, + (Dimension::Auto, _) | (_, Dimension::Auto) => Dimension::Auto, + (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs + rhs), + (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs + rhs), + // Result can't be known in advance, defer calculation until resolving the actual values + (lhs, rhs) => Dimension::Calc(CalcDimension::Add(Box::new(lhs), Box::new(rhs))), + } + } +} + +impl Sub for Dimension { + type Output = Dimension; + + fn sub(self, rhs: Dimension) -> Self::Output { + match (self, rhs) { + (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, + (Dimension::Auto, _) | (_, Dimension::Auto) => Dimension::Auto, + (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs - rhs), + (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs - rhs), + // Result can't be known in advance, defer calculation until resolving the actual values + (lhs, rhs) => Dimension::Calc(CalcDimension::Sub(Box::new(lhs), Box::new(rhs))), + } + } +} + +impl Mul for Dimension { + type Output = Dimension; + + fn mul(self, factor: f32) -> Self::Output { + match (self, factor) { + (Dimension::Undefined, _) => Dimension::Undefined, + (Dimension::Auto, _) => Dimension::Auto, + (Dimension::Points(lhs), factor) => Dimension::Points(lhs * factor), + (Dimension::Percent(lhs), factor) => Dimension::Percent(lhs * factor), + // Result can't be known in advance, defer calculation until resolving the actual values + (lhs, factor) => Dimension::Calc(CalcDimension::Mul(Box::new(lhs), factor)), + } + } +} + +impl Mul for f32 { + type Output = Dimension; + + fn mul(self, rhs: Dimension) -> Self::Output { + match (self, rhs) { + (_, Dimension::Undefined) => Dimension::Undefined, + (_, Dimension::Auto) => Dimension::Auto, + (factor, Dimension::Points(lhs)) => Dimension::Points(lhs * factor), + (factor, Dimension::Percent(lhs)) => Dimension::Percent(lhs * factor), + // Result can't be known in advance, defer calculation until resolving the actual values + (factor, rhs) => Dimension::Calc(CalcDimension::Mul(Box::new(rhs), factor)), + } + } +} + +impl Div for Dimension { + type Output = Dimension; + + fn div(self, divisor: f32) -> Self::Output { + match (self, divisor) { + (Dimension::Undefined, _) => Dimension::Undefined, + (Dimension::Auto, _) => Dimension::Auto, + (Dimension::Points(lhs), divisor) => Dimension::Points(lhs / divisor), + (Dimension::Percent(lhs), divisor) => Dimension::Percent(lhs / divisor), + // Result can't be known in advance, defer calculation until resolving the actual values + (lhs, divisor) => Dimension::Calc(CalcDimension::Div(Box::new(lhs), divisor)), + } + } +} From abdeb59f81427b45f1aaba72df77126a2a9787ff Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Thu, 29 Sep 2022 21:05:55 +0200 Subject: [PATCH 07/14] Simplify match statements for Mul and Div implementations --- src/style/dimension.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/style/dimension.rs b/src/style/dimension.rs index 10d1dcd8f..8fce4b50d 100644 --- a/src/style/dimension.rs +++ b/src/style/dimension.rs @@ -78,13 +78,13 @@ impl Mul for Dimension { type Output = Dimension; fn mul(self, factor: f32) -> Self::Output { - match (self, factor) { - (Dimension::Undefined, _) => Dimension::Undefined, - (Dimension::Auto, _) => Dimension::Auto, - (Dimension::Points(lhs), factor) => Dimension::Points(lhs * factor), - (Dimension::Percent(lhs), factor) => Dimension::Percent(lhs * factor), + match self { + Dimension::Undefined => Dimension::Undefined, + Dimension::Auto => Dimension::Auto, + Dimension::Points(lhs) => Dimension::Points(lhs * factor), + Dimension::Percent(lhs) => Dimension::Percent(lhs * factor), // Result can't be known in advance, defer calculation until resolving the actual values - (lhs, factor) => Dimension::Calc(CalcDimension::Mul(Box::new(lhs), factor)), + lhs => Dimension::Calc(CalcDimension::Mul(Box::new(lhs), factor)), } } } @@ -93,13 +93,13 @@ impl Mul for f32 { type Output = Dimension; fn mul(self, rhs: Dimension) -> Self::Output { - match (self, rhs) { - (_, Dimension::Undefined) => Dimension::Undefined, - (_, Dimension::Auto) => Dimension::Auto, - (factor, Dimension::Points(lhs)) => Dimension::Points(lhs * factor), - (factor, Dimension::Percent(lhs)) => Dimension::Percent(lhs * factor), + match rhs { + Dimension::Undefined => Dimension::Undefined, + Dimension::Auto => Dimension::Auto, + Dimension::Points(lhs) => Dimension::Points(lhs * self), + Dimension::Percent(lhs) => Dimension::Percent(lhs * self), // Result can't be known in advance, defer calculation until resolving the actual values - (factor, rhs) => Dimension::Calc(CalcDimension::Mul(Box::new(rhs), factor)), + rhs => Dimension::Calc(CalcDimension::Mul(Box::new(rhs), self)), } } } @@ -108,13 +108,13 @@ impl Div for Dimension { type Output = Dimension; fn div(self, divisor: f32) -> Self::Output { - match (self, divisor) { - (Dimension::Undefined, _) => Dimension::Undefined, - (Dimension::Auto, _) => Dimension::Auto, - (Dimension::Points(lhs), divisor) => Dimension::Points(lhs / divisor), - (Dimension::Percent(lhs), divisor) => Dimension::Percent(lhs / divisor), + match self { + Dimension::Undefined => Dimension::Undefined, + Dimension::Auto => Dimension::Auto, + Dimension::Points(lhs) => Dimension::Points(lhs / divisor), + Dimension::Percent(lhs) => Dimension::Percent(lhs / divisor), // Result can't be known in advance, defer calculation until resolving the actual values - (lhs, divisor) => Dimension::Calc(CalcDimension::Div(Box::new(lhs), divisor)), + lhs => Dimension::Calc(CalcDimension::Div(Box::new(lhs), divisor)), } } } From 86e89877c5471745e16bf00d8020009b2c6f0bea Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 16:44:45 +0200 Subject: [PATCH 08/14] Improve documentation for calculated dimensions --- src/style/calc_dimension.rs | 11 ++ src/style/dimension.rs | 271 ++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) diff --git a/src/style/calc_dimension.rs b/src/style/calc_dimension.rs index bf4568961..38580794f 100644 --- a/src/style/calc_dimension.rs +++ b/src/style/calc_dimension.rs @@ -23,20 +23,31 @@ pub enum CalcDimension { } impl MaybeResolve> for CalcDimension { + /// Resolve the calculations to concrete values. + /// + /// If any side resolves to [`None`], [`None`] is also returned. fn maybe_resolve(&self, context: Option) -> Option { match self { + // Resolve both sides and add them together + // If either side resolves to `None`, return `None` CalcDimension::Add(lhs, rhs) => lhs .maybe_resolve(context) .zip(rhs.maybe_resolve(context)) .map(|(lhs_value, rhs_value)| lhs_value + rhs_value), + // Resolve both sides and subtract them + // If either side resolves to `None`, return `None` CalcDimension::Sub(lhs, rhs) => lhs .maybe_resolve(context) .zip(rhs.maybe_resolve(context)) .map(|(lhs_value, rhs_value)| lhs_value - rhs_value), + // Resolve the left side and multiply it by the factor + // If the left side resolves to `None`, return `None` CalcDimension::Mul(lhs, factor) => lhs.maybe_resolve(context).map(|lhs_value| lhs_value * factor), + // Resolve the left side and divide it by the factor + // If the left side resolves to `None`, return `None` CalcDimension::Div(lhs, divisor) => lhs.maybe_resolve(context).map(|lhs_value| lhs_value / divisor), } } diff --git a/src/style/dimension.rs b/src/style/dimension.rs index 8fce4b50d..4766e3e12 100644 --- a/src/style/dimension.rs +++ b/src/style/dimension.rs @@ -28,6 +28,28 @@ pub enum Dimension { /// A calculation of dimensions, similar to CSS's `calc()`. /// /// One use-case of this is to add a percentage value to a points value. + /// + /// Usually, you don't want to construct this variant yourself. + /// Instead use the `+`, `-`, `*` and `/` operators. + /// + /// # Example + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let calc = Dimension::Points(10.0) + Dimension::Percent(50.0); + /// let expected = Dimension::Calc( + /// CalcDimension::Add( + /// Box::new(Dimension::Points(10.0)), + /// Box::new(Dimension::Percent(50.0)) + /// ) + /// ); + /// assert_eq!(calc, expected); + /// ``` + /// + /// The actual result is then calculated when resolving the absolute values. + /// See [`Dimension::maybe_resolve`]. Calc(CalcDimension), } @@ -47,6 +69,48 @@ impl Dimension { impl Add for Dimension { type Output = Dimension; + /// Add two [`Dimension`]s together. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(13.0) + Dimension::Points(5.5); + /// assert_eq!(result, Dimension::Points(18.5)); + /// ``` + /// + /// If any of the operants is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(28.0) + Dimension::Undefined; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let result = Dimension::Points(5.0) + Dimension::Percent(80.0); + /// let expected = Dimension::Calc( + /// CalcDimension::Add( + /// Box::new(Dimension::Points(5.0)), + /// Box::new(Dimension::Percent(80.0)) + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` fn add(self, rhs: Dimension) -> Self::Output { match (self, rhs) { (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, @@ -62,6 +126,48 @@ impl Add for Dimension { impl Sub for Dimension { type Output = Dimension; + /// Subtract one [`Dimension`] from another. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(13.0) - Dimension::Points(5.5); + /// assert_eq!(result, Dimension::Points(7.5)); + /// ``` + /// + /// If any of the operants is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(28.0) - Dimension::Undefined; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let result = Dimension::Percent(80.0) - Dimension::Points(5.0); + /// let expected = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` fn sub(self, rhs: Dimension) -> Self::Output { match (self, rhs) { (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, @@ -77,6 +183,61 @@ impl Sub for Dimension { impl Mul for Dimension { type Output = Dimension; + /// Multiply a [`Dimension`] with a constant factor. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(2.0) * 5.0; + /// assert_eq!(result, Dimension::Points(10.0)); + /// ``` + /// + /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Undefined * 3.0; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let lhs = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// let result = lhs * 3.0; + /// let expected = Dimension::Calc( + /// CalcDimension::Mul( + /// Box::new( + /// Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ) + /// ), + /// 3.0 + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` fn mul(self, factor: f32) -> Self::Output { match self { Dimension::Undefined => Dimension::Undefined, @@ -92,6 +253,61 @@ impl Mul for Dimension { impl Mul for f32 { type Output = Dimension; + /// Multiply a constant factor with a [`Dimension`]. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = 5.0 * Dimension::Points(2.0); + /// assert_eq!(result, Dimension::Points(10.0)); + /// ``` + /// + /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = 3.0 * Dimension::Undefined; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let lhs = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// let result = 3.0 * lhs; + /// let expected = Dimension::Calc( + /// CalcDimension::Mul( + /// Box::new( + /// Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ) + /// ), + /// 3.0 + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` fn mul(self, rhs: Dimension) -> Self::Output { match rhs { Dimension::Undefined => Dimension::Undefined, @@ -107,6 +323,61 @@ impl Mul for f32 { impl Div for Dimension { type Output = Dimension; + /// Divide a [`Dimension`] by a constant factor. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(10.0) / 2.0; + /// assert_eq!(result, Dimension::Points(5.0)); + /// ``` + /// + /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Undefined / 3.0; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let lhs = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// let result = lhs / 3.0; + /// let expected = Dimension::Calc( + /// CalcDimension::Div( + /// Box::new( + /// Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ) + /// ), + /// 3.0 + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` fn div(self, divisor: f32) -> Self::Output { match self { Dimension::Undefined => Dimension::Undefined, From aeb06df276f5eb697865ba0aa700ef0043e86d9d Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 16:47:51 +0200 Subject: [PATCH 09/14] Fix errors with style not being copy in tests --- src/flexbox.rs | 26 +++++++++++++------------- src/node.rs | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/flexbox.rs b/src/flexbox.rs index ca5bfe6d9..f8b1c2a2a 100644 --- a/src/flexbox.rs +++ b/src/flexbox.rs @@ -1820,25 +1820,25 @@ mod tests { let mut tree = Taffy::with_capacity(16); let style = FlexboxLayout::default(); - let node_id = tree.new_leaf(style).unwrap(); + let node_id = tree.new_leaf(style.clone()).unwrap(); let node_size = Size::NONE; let parent_size = Size::NONE; let constants = Taffy::compute_constants(&tree.nodes[node_id], node_size, parent_size); - assert!(constants.dir == style.flex_direction); - assert!(constants.is_row == style.flex_direction.is_row()); - assert!(constants.is_column == style.flex_direction.is_column()); - assert!(constants.is_wrap_reverse == (style.flex_wrap == FlexWrap::WrapReverse)); + assert!(constants.dir == style.clone().flex_direction); + assert!(constants.is_row == style.clone().flex_direction.is_row()); + assert!(constants.is_column == style.clone().flex_direction.is_column()); + assert!(constants.is_wrap_reverse == (style.clone().flex_wrap == FlexWrap::WrapReverse)); - let margin = style.margin.resolve_or_default(parent_size); + let margin = style.clone().margin.resolve_or_default(parent_size); assert_eq!(constants.margin, margin); - let border = style.border.resolve_or_default(parent_size); + let border = style.clone().border.resolve_or_default(parent_size); assert_eq!(constants.border, border); - let padding = style.padding.resolve_or_default(parent_size); + let padding = style.clone().padding.resolve_or_default(parent_size); // TODO: Replace with something less hardcoded? let padding_border = Rect { @@ -1868,15 +1868,15 @@ mod tests { let style: FlexboxLayout = FlexboxLayout { display: Flex, size: Size::from_points(50.0, 50.0), ..Default::default() }; - let grandchild_00 = taffy.new_leaf(style).unwrap(); + let grandchild_00 = taffy.new_leaf(style.clone()).unwrap(); - let grandchild_01 = taffy.new_leaf(style).unwrap(); + let grandchild_01 = taffy.new_leaf(style.clone()).unwrap(); - let grandchild_02 = taffy.new_leaf(style).unwrap(); + let grandchild_02 = taffy.new_leaf(style.clone()).unwrap(); - let child_00 = taffy.new_with_children(style, &[grandchild_00, grandchild_01]).unwrap(); + let child_00 = taffy.new_with_children(style.clone(), &[grandchild_00, grandchild_01]).unwrap(); - let child_01 = taffy.new_with_children(style, &[grandchild_02]).unwrap(); + let child_01 = taffy.new_with_children(style.clone(), &[grandchild_02]).unwrap(); let root = taffy .new_with_children( diff --git a/src/node.rs b/src/node.rs index e183f0220..d2dadd4bf 100644 --- a/src/node.rs +++ b/src/node.rs @@ -552,7 +552,7 @@ mod tests { let style = FlexboxLayout { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() }; - let node = taffy.new_leaf(style).unwrap(); + let node = taffy.new_leaf(style.clone()).unwrap(); let res = taffy.style(node); assert!(res.is_ok()); From 675623d34827883677eeb73d6a07a527ae0aceaa Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 16:54:34 +0200 Subject: [PATCH 10/14] Fix calculated dimensions breaking no-std --- src/resolve.rs | 4 +- src/style/dimension.rs | 328 +----------------------------------- src/style/dimension_ops.rs | 329 +++++++++++++++++++++++++++++++++++++ src/style/mod.rs | 4 + 4 files changed, 338 insertions(+), 327 deletions(-) create mode 100644 src/style/dimension_ops.rs diff --git a/src/resolve.rs b/src/resolve.rs index debec062d..9cca594a0 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -31,8 +31,10 @@ impl MaybeResolve> for Dimension { Dimension::Points(points) => Some(*points), // parent_dim * percent Dimension::Percent(percent) => context.map(|dim| dim * percent), - Dimension::Calc(calc) => calc.maybe_resolve(context), Dimension::Auto | Dimension::Undefined => None, + + #[cfg(feature = "std")] + Dimension::Calc(calc) => calc.maybe_resolve(context), } } } diff --git a/src/style/dimension.rs b/src/style/dimension.rs index 4766e3e12..b91596b8c 100644 --- a/src/style/dimension.rs +++ b/src/style/dimension.rs @@ -1,7 +1,6 @@ //! A unit of linear measurement. -use core::ops::{Add, Div, Mul, Sub}; - +#[cfg(feature = "std")] use super::CalcDimension; /// A unit of linear measurement @@ -50,6 +49,7 @@ pub enum Dimension { /// /// The actual result is then calculated when resolving the absolute values. /// See [`Dimension::maybe_resolve`]. + #[cfg(feature = "std")] Calc(CalcDimension), } @@ -65,327 +65,3 @@ impl Dimension { matches!(self, Dimension::Points(_) | Dimension::Percent(_)) } } - -impl Add for Dimension { - type Output = Dimension; - - /// Add two [`Dimension`]s together. - /// - /// If the result of the calculation can already be known, it is calculated immediately. - /// Otherwise, variants of [`Dimension::Calc`] are constructed. - /// - /// # Examples - /// - /// When the result can already be known, it is calculated immediately: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Points(13.0) + Dimension::Points(5.5); - /// assert_eq!(result, Dimension::Points(18.5)); - /// ``` - /// - /// If any of the operants is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Points(28.0) + Dimension::Undefined; - /// assert_eq!(result, Dimension::Undefined); - /// ``` - /// - /// The behavior is analogue for [`Dimension::Auto`]. - /// - /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # use taffy::style::CalcDimension; - /// # - /// let result = Dimension::Points(5.0) + Dimension::Percent(80.0); - /// let expected = Dimension::Calc( - /// CalcDimension::Add( - /// Box::new(Dimension::Points(5.0)), - /// Box::new(Dimension::Percent(80.0)) - /// ) - /// ); - /// assert_eq!(result, expected); - /// ``` - fn add(self, rhs: Dimension) -> Self::Output { - match (self, rhs) { - (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, - (Dimension::Auto, _) | (_, Dimension::Auto) => Dimension::Auto, - (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs + rhs), - (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs + rhs), - // Result can't be known in advance, defer calculation until resolving the actual values - (lhs, rhs) => Dimension::Calc(CalcDimension::Add(Box::new(lhs), Box::new(rhs))), - } - } -} - -impl Sub for Dimension { - type Output = Dimension; - - /// Subtract one [`Dimension`] from another. - /// - /// If the result of the calculation can already be known, it is calculated immediately. - /// Otherwise, variants of [`Dimension::Calc`] are constructed. - /// - /// # Examples - /// - /// When the result can already be known, it is calculated immediately: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Points(13.0) - Dimension::Points(5.5); - /// assert_eq!(result, Dimension::Points(7.5)); - /// ``` - /// - /// If any of the operants is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Points(28.0) - Dimension::Undefined; - /// assert_eq!(result, Dimension::Undefined); - /// ``` - /// - /// The behavior is analogue for [`Dimension::Auto`]. - /// - /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # use taffy::style::CalcDimension; - /// # - /// let result = Dimension::Percent(80.0) - Dimension::Points(5.0); - /// let expected = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ); - /// assert_eq!(result, expected); - /// ``` - fn sub(self, rhs: Dimension) -> Self::Output { - match (self, rhs) { - (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, - (Dimension::Auto, _) | (_, Dimension::Auto) => Dimension::Auto, - (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs - rhs), - (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs - rhs), - // Result can't be known in advance, defer calculation until resolving the actual values - (lhs, rhs) => Dimension::Calc(CalcDimension::Sub(Box::new(lhs), Box::new(rhs))), - } - } -} - -impl Mul for Dimension { - type Output = Dimension; - - /// Multiply a [`Dimension`] with a constant factor. - /// - /// If the result of the calculation can already be known, it is calculated immediately. - /// Otherwise, variants of [`Dimension::Calc`] are constructed. - /// - /// # Examples - /// - /// When the result can already be known, it is calculated immediately: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Points(2.0) * 5.0; - /// assert_eq!(result, Dimension::Points(10.0)); - /// ``` - /// - /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Undefined * 3.0; - /// assert_eq!(result, Dimension::Undefined); - /// ``` - /// - /// The behavior is analogue for [`Dimension::Auto`]. - /// - /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # use taffy::style::CalcDimension; - /// # - /// let lhs = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ); - /// let result = lhs * 3.0; - /// let expected = Dimension::Calc( - /// CalcDimension::Mul( - /// Box::new( - /// Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ) - /// ), - /// 3.0 - /// ) - /// ); - /// assert_eq!(result, expected); - /// ``` - fn mul(self, factor: f32) -> Self::Output { - match self { - Dimension::Undefined => Dimension::Undefined, - Dimension::Auto => Dimension::Auto, - Dimension::Points(lhs) => Dimension::Points(lhs * factor), - Dimension::Percent(lhs) => Dimension::Percent(lhs * factor), - // Result can't be known in advance, defer calculation until resolving the actual values - lhs => Dimension::Calc(CalcDimension::Mul(Box::new(lhs), factor)), - } - } -} - -impl Mul for f32 { - type Output = Dimension; - - /// Multiply a constant factor with a [`Dimension`]. - /// - /// If the result of the calculation can already be known, it is calculated immediately. - /// Otherwise, variants of [`Dimension::Calc`] are constructed. - /// - /// # Examples - /// - /// When the result can already be known, it is calculated immediately: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = 5.0 * Dimension::Points(2.0); - /// assert_eq!(result, Dimension::Points(10.0)); - /// ``` - /// - /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = 3.0 * Dimension::Undefined; - /// assert_eq!(result, Dimension::Undefined); - /// ``` - /// - /// The behavior is analogue for [`Dimension::Auto`]. - /// - /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # use taffy::style::CalcDimension; - /// # - /// let lhs = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ); - /// let result = 3.0 * lhs; - /// let expected = Dimension::Calc( - /// CalcDimension::Mul( - /// Box::new( - /// Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ) - /// ), - /// 3.0 - /// ) - /// ); - /// assert_eq!(result, expected); - /// ``` - fn mul(self, rhs: Dimension) -> Self::Output { - match rhs { - Dimension::Undefined => Dimension::Undefined, - Dimension::Auto => Dimension::Auto, - Dimension::Points(lhs) => Dimension::Points(lhs * self), - Dimension::Percent(lhs) => Dimension::Percent(lhs * self), - // Result can't be known in advance, defer calculation until resolving the actual values - rhs => Dimension::Calc(CalcDimension::Mul(Box::new(rhs), self)), - } - } -} - -impl Div for Dimension { - type Output = Dimension; - - /// Divide a [`Dimension`] by a constant factor. - /// - /// If the result of the calculation can already be known, it is calculated immediately. - /// Otherwise, variants of [`Dimension::Calc`] are constructed. - /// - /// # Examples - /// - /// When the result can already be known, it is calculated immediately: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Points(10.0) / 2.0; - /// assert_eq!(result, Dimension::Points(5.0)); - /// ``` - /// - /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # - /// let result = Dimension::Undefined / 3.0; - /// assert_eq!(result, Dimension::Undefined); - /// ``` - /// - /// The behavior is analogue for [`Dimension::Auto`]. - /// - /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: - /// - /// ``` - /// # use taffy::style::Dimension; - /// # use taffy::style::CalcDimension; - /// # - /// let lhs = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ); - /// let result = lhs / 3.0; - /// let expected = Dimension::Calc( - /// CalcDimension::Div( - /// Box::new( - /// Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) - /// ) - /// ) - /// ), - /// 3.0 - /// ) - /// ); - /// assert_eq!(result, expected); - /// ``` - fn div(self, divisor: f32) -> Self::Output { - match self { - Dimension::Undefined => Dimension::Undefined, - Dimension::Auto => Dimension::Auto, - Dimension::Points(lhs) => Dimension::Points(lhs / divisor), - Dimension::Percent(lhs) => Dimension::Percent(lhs / divisor), - // Result can't be known in advance, defer calculation until resolving the actual values - lhs => Dimension::Calc(CalcDimension::Div(Box::new(lhs), divisor)), - } - } -} diff --git a/src/style/dimension_ops.rs b/src/style/dimension_ops.rs new file mode 100644 index 000000000..7609e6263 --- /dev/null +++ b/src/style/dimension_ops.rs @@ -0,0 +1,329 @@ +//! Implementations for the standard operations `+`, `-`, `*` and `/` for [`Dimension`]. + +use super::CalcDimension; +use super::Dimension; +use core::ops::{Add, Div, Mul, Sub}; + +impl Add for Dimension { + type Output = Dimension; + + /// Add two [`Dimension`]s together. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(13.0) + Dimension::Points(5.5); + /// assert_eq!(result, Dimension::Points(18.5)); + /// ``` + /// + /// If any of the operants is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(28.0) + Dimension::Undefined; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let result = Dimension::Points(5.0) + Dimension::Percent(80.0); + /// let expected = Dimension::Calc( + /// CalcDimension::Add( + /// Box::new(Dimension::Points(5.0)), + /// Box::new(Dimension::Percent(80.0)) + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` + fn add(self, rhs: Dimension) -> Self::Output { + match (self, rhs) { + (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, + (Dimension::Auto, _) | (_, Dimension::Auto) => Dimension::Auto, + (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs + rhs), + (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs + rhs), + // Result can't be known in advance, defer calculation until resolving the actual values + (lhs, rhs) => Dimension::Calc(CalcDimension::Add(Box::new(lhs), Box::new(rhs))), + } + } +} + +impl Sub for Dimension { + type Output = Dimension; + + /// Subtract one [`Dimension`] from another. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(13.0) - Dimension::Points(5.5); + /// assert_eq!(result, Dimension::Points(7.5)); + /// ``` + /// + /// If any of the operants is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(28.0) - Dimension::Undefined; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let result = Dimension::Percent(80.0) - Dimension::Points(5.0); + /// let expected = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` + fn sub(self, rhs: Dimension) -> Self::Output { + match (self, rhs) { + (Dimension::Undefined, _) | (_, Dimension::Undefined) => Dimension::Undefined, + (Dimension::Auto, _) | (_, Dimension::Auto) => Dimension::Auto, + (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs - rhs), + (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs - rhs), + // Result can't be known in advance, defer calculation until resolving the actual values + (lhs, rhs) => Dimension::Calc(CalcDimension::Sub(Box::new(lhs), Box::new(rhs))), + } + } +} + +impl Mul for Dimension { + type Output = Dimension; + + /// Multiply a [`Dimension`] with a constant factor. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(2.0) * 5.0; + /// assert_eq!(result, Dimension::Points(10.0)); + /// ``` + /// + /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Undefined * 3.0; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let lhs = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// let result = lhs * 3.0; + /// let expected = Dimension::Calc( + /// CalcDimension::Mul( + /// Box::new( + /// Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ) + /// ), + /// 3.0 + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` + fn mul(self, factor: f32) -> Self::Output { + match self { + Dimension::Undefined => Dimension::Undefined, + Dimension::Auto => Dimension::Auto, + Dimension::Points(lhs) => Dimension::Points(lhs * factor), + Dimension::Percent(lhs) => Dimension::Percent(lhs * factor), + // Result can't be known in advance, defer calculation until resolving the actual values + lhs => Dimension::Calc(CalcDimension::Mul(Box::new(lhs), factor)), + } + } +} + +impl Mul for f32 { + type Output = Dimension; + + /// Multiply a constant factor with a [`Dimension`]. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = 5.0 * Dimension::Points(2.0); + /// assert_eq!(result, Dimension::Points(10.0)); + /// ``` + /// + /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = 3.0 * Dimension::Undefined; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let lhs = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// let result = 3.0 * lhs; + /// let expected = Dimension::Calc( + /// CalcDimension::Mul( + /// Box::new( + /// Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ) + /// ), + /// 3.0 + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` + fn mul(self, rhs: Dimension) -> Self::Output { + match rhs { + Dimension::Undefined => Dimension::Undefined, + Dimension::Auto => Dimension::Auto, + Dimension::Points(lhs) => Dimension::Points(lhs * self), + Dimension::Percent(lhs) => Dimension::Percent(lhs * self), + // Result can't be known in advance, defer calculation until resolving the actual values + rhs => Dimension::Calc(CalcDimension::Mul(Box::new(rhs), self)), + } + } +} + +impl Div for Dimension { + type Output = Dimension; + + /// Divide a [`Dimension`] by a constant factor. + /// + /// If the result of the calculation can already be known, it is calculated immediately. + /// Otherwise, variants of [`Dimension::Calc`] are constructed. + /// + /// # Examples + /// + /// When the result can already be known, it is calculated immediately: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Points(10.0) / 2.0; + /// assert_eq!(result, Dimension::Points(5.0)); + /// ``` + /// + /// If the value is [`Dimension::Undefined`], the result will be [`Dimension::Undefined`]: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # + /// let result = Dimension::Undefined / 3.0; + /// assert_eq!(result, Dimension::Undefined); + /// ``` + /// + /// The behavior is analogue for [`Dimension::Auto`]. + /// + /// If the result cannot be known beforehand, variants of [`Dimension::Calc`] will be constructed: + /// + /// ``` + /// # use taffy::style::Dimension; + /// # use taffy::style::CalcDimension; + /// # + /// let lhs = Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ); + /// let result = lhs / 3.0; + /// let expected = Dimension::Calc( + /// CalcDimension::Div( + /// Box::new( + /// Dimension::Calc( + /// CalcDimension::Sub( + /// Box::new(Dimension::Percent(80.0)), + /// Box::new(Dimension::Points(5.0)) + /// ) + /// ) + /// ), + /// 3.0 + /// ) + /// ); + /// assert_eq!(result, expected); + /// ``` + fn div(self, divisor: f32) -> Self::Output { + match self { + Dimension::Undefined => Dimension::Undefined, + Dimension::Auto => Dimension::Auto, + Dimension::Points(lhs) => Dimension::Points(lhs / divisor), + Dimension::Percent(lhs) => Dimension::Percent(lhs / divisor), + // Result can't be known in advance, defer calculation until resolving the actual values + lhs => Dimension::Calc(CalcDimension::Div(Box::new(lhs), divisor)), + } + } +} diff --git a/src/style/mod.rs b/src/style/mod.rs index 8242d93cf..dd513160a 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -1,10 +1,14 @@ //! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout +#[cfg(feature = "std")] mod calc_dimension; mod dimension; +#[cfg(feature = "std")] +mod dimension_ops; use crate::geometry::{Rect, Size}; +#[cfg(feature = "std")] pub use self::calc_dimension::CalcDimension; pub use self::dimension::Dimension; From fa28a28caf95c9cbba8a94f3d38f5375c92b6ac5 Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 17:02:24 +0200 Subject: [PATCH 11/14] Add value calculation to release notes --- RELEASES.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 3d8d8381e..b39d9deb3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,14 @@ # Release Notes +## Unreleased + +### Unreleased Added + +- `taffy::style::Dimension` now implements the `+`, `-`, `*` and `/` operators. + - If both sides of the calculation have the same type (e.g. points), the result is calculated immediately. + - If both sides have different types (e.g. adding points and percentage), the new `Dimension::Calc` variant is constructed. The result will be calculated when the absolute value is resolved. + - If any side is `Dimension::Undefined`, the result will be `Dimension::Undefined`. The same happens for `Dimension::Auto`. + ## 0.2.0 ### 0.2.0 Added @@ -14,7 +23,7 @@ ### 0.2.0 Changed - `Size.zero()` is now `Size::::ZERO` -- `Point.zero()` is now `Point::::ZERO` +- `Point.zero()` is now `Point::::ZERO` - renamed `taffy::node::Taffy.new_leaf()` -> `taffy::node::Taffy.new_leaf_with_measure()` - removed the public `Number` type; a more idiomatic `Option` is used instead - the associated public `MinMax` and `OrElse` traits have also been removed; these should never have been public From d6aeabf8f863a61c7a54f3d38c4d303c4aae754c Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 17:16:39 +0200 Subject: [PATCH 12/14] Improve documentation for CalcDimension --- src/style/calc_dimension.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/style/calc_dimension.rs b/src/style/calc_dimension.rs index 38580794f..e4d77e378 100644 --- a/src/style/calc_dimension.rs +++ b/src/style/calc_dimension.rs @@ -4,9 +4,13 @@ use crate::resolve::MaybeResolve; use super::Dimension; -/// A [`Dimension`] calculation. +/// An addition, subtraction, multiplication or division between [`Dimension`]s. /// /// The values are calulated when the point values are resolved. +/// +/// This type is needed, because not all calculations can be determined before resolving the actual values. +/// For example, when adding [`Dimension::Points`] and [`Dimension::Percent`] together, +/// the percentage first needs to be resolved to an absolute value to get the final result. #[derive(Clone, PartialEq, Debug)] pub enum CalcDimension { /// Add two [`Dimension`]s together. From d234d35b79a6d8a8efa74b4ebd281022628574ad Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 17:52:41 +0200 Subject: [PATCH 13/14] Don't clone Dimensions in FlexboxLayout methods --- src/flexbox.rs | 28 ++++++++++++------------- src/style/mod.rs | 54 ++++++++++++++++++++++++------------------------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/flexbox.rs b/src/flexbox.rs index f8b1c2a2a..fa4a07a7f 100644 --- a/src/flexbox.rs +++ b/src/flexbox.rs @@ -935,9 +935,9 @@ impl Taffy { .map(|child| { let child_style = &self.nodes[child.node].style; if child_style.align_self(&self.nodes[node].style) == AlignSelf::Baseline - && child_style.cross_margin_start(constants.dir) != Dimension::Auto - && child_style.cross_margin_end(constants.dir) != Dimension::Auto - && child_style.cross_size(constants.dir) == Dimension::Auto + && child_style.cross_margin_start(constants.dir) != &Dimension::Auto + && child_style.cross_margin_end(constants.dir) != &Dimension::Auto + && child_style.cross_size(constants.dir) == &Dimension::Auto { max_baseline - child.baseline + child.hypothetical_outer_size.cross(constants.dir) } else { @@ -999,9 +999,9 @@ impl Taffy { child.target_size.set_cross( constants.dir, if child_style.align_self(&self.nodes[node].style) == AlignSelf::Stretch - && child_style.cross_margin_start(constants.dir) != Dimension::Auto - && child_style.cross_margin_end(constants.dir) != Dimension::Auto - && child_style.cross_size(constants.dir) == Dimension::Auto + && child_style.cross_margin_start(constants.dir) != &Dimension::Auto + && child_style.cross_margin_end(constants.dir) != &Dimension::Auto + && child_style.cross_size(constants.dir) == &Dimension::Auto { (line_cross_size - child.margin.cross_axis_sum(constants.dir)) .maybe_max(child.min_size.cross(constants.dir)) @@ -1038,10 +1038,10 @@ impl Taffy { for child in line.items.iter_mut() { let child_style = &self.nodes[child.node].style; - if child_style.main_margin_start(constants.dir) == Dimension::Auto { + if child_style.main_margin_start(constants.dir) == &Dimension::Auto { num_auto_margins += 1; } - if child_style.main_margin_end(constants.dir) == Dimension::Auto { + if child_style.main_margin_end(constants.dir) == &Dimension::Auto { num_auto_margins += 1; } } @@ -1051,14 +1051,14 @@ impl Taffy { for child in line.items.iter_mut() { let child_style = &self.nodes[child.node].style; - if child_style.main_margin_start(constants.dir) == Dimension::Auto { + if child_style.main_margin_start(constants.dir) == &Dimension::Auto { if constants.is_row { child.margin.start = margin; } else { child.margin.top = margin; } } - if child_style.main_margin_end(constants.dir) == Dimension::Auto { + if child_style.main_margin_end(constants.dir) == &Dimension::Auto { if constants.is_row { child.margin.end = margin; } else { @@ -1144,8 +1144,8 @@ impl Taffy { let free_space = line_cross_size - child.outer_target_size.cross(constants.dir); let child_style = &self.nodes[child.node].style; - if child_style.cross_margin_start(constants.dir) == Dimension::Auto - && child_style.cross_margin_end(constants.dir) == Dimension::Auto + if child_style.cross_margin_start(constants.dir) == &Dimension::Auto + && child_style.cross_margin_end(constants.dir) == &Dimension::Auto { if constants.is_row { child.margin.top = free_space / 2.0; @@ -1154,13 +1154,13 @@ impl Taffy { child.margin.start = free_space / 2.0; child.margin.end = free_space / 2.0; } - } else if child_style.cross_margin_start(constants.dir) == Dimension::Auto { + } else if child_style.cross_margin_start(constants.dir) == &Dimension::Auto { if constants.is_row { child.margin.top = free_space; } else { child.margin.start = free_space; } - } else if child_style.cross_margin_end(constants.dir) == Dimension::Auto { + } else if child_style.cross_margin_end(constants.dir) == &Dimension::Auto { if constants.is_row { child.margin.bottom = free_space; } else { diff --git a/src/style/mod.rs b/src/style/mod.rs index dd513160a..c838ae277 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -429,83 +429,83 @@ impl Default for FlexboxLayout { impl FlexboxLayout { /// If the `direction` is row-oriented, the min width. Otherwise the min height - pub(crate) fn min_main_size(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn min_main_size(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.min_size.clone().width + &self.min_size.width } else { - self.min_size.clone().height + &self.min_size.height } } /// If the `direction` is row-oriented, the max width. Otherwise the max height - pub(crate) fn max_main_size(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn max_main_size(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.max_size.clone().width + &self.max_size.width } else { - self.max_size.clone().height + &self.max_size.height } } /// If the `direction` is row-oriented, the margin start. Otherwise the margin top - pub(crate) fn main_margin_start(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn main_margin_start(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.margin.clone().start + &self.margin.start } else { - self.margin.clone().top + &self.margin.top } } /// If the `direction` is row-oriented, the margin end. Otherwise the margin bottom - pub(crate) fn main_margin_end(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn main_margin_end(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.margin.clone().end + &self.margin.end } else { - self.margin.clone().bottom + &self.margin.bottom } } /// If the `direction` is row-oriented, the height. Otherwise the width - pub(crate) fn cross_size(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn cross_size(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.size.clone().height + &self.size.height } else { - self.size.clone().width + &self.size.width } } /// If the `direction` is row-oriented, the min height. Otherwise the min width - pub(crate) fn min_cross_size(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn min_cross_size(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.min_size.clone().height + &self.min_size.height } else { - self.min_size.clone().width + &self.min_size.width } } /// If the `direction` is row-oriented, the max height. Otherwise the max width - pub(crate) fn max_cross_size(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn max_cross_size(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.max_size.clone().height + &self.max_size.height } else { - self.max_size.clone().width + &self.max_size.width } } /// If the `direction` is row-oriented, the margin top. Otherwise the margin start - pub(crate) fn cross_margin_start(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn cross_margin_start(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.margin.clone().top + &self.margin.top } else { - self.margin.clone().start + &self.margin.start } } /// If the `direction` is row-oriented, the margin bottom. Otherwise the margin end - pub(crate) fn cross_margin_end(&self, direction: FlexDirection) -> Dimension { + pub(crate) fn cross_margin_end(&self, direction: FlexDirection) -> &Dimension { if direction.is_row() { - self.margin.clone().bottom + &self.margin.bottom } else { - self.margin.clone().end + &self.margin.end } } From b87f83d696c5525c7c51070c02fe78e5e8168c2c Mon Sep 17 00:00:00 2001 From: Tim Jentzsch Date: Wed, 12 Oct 2022 18:49:20 +0200 Subject: [PATCH 14/14] Box CalcDimension instead of operation paramters --- src/style/calc_dimension.rs | 8 +-- src/style/dimension.rs | 10 ++-- src/style/dimension_ops.rs | 104 +++++++++++++++++++++--------------- 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/src/style/calc_dimension.rs b/src/style/calc_dimension.rs index e4d77e378..061386415 100644 --- a/src/style/calc_dimension.rs +++ b/src/style/calc_dimension.rs @@ -14,16 +14,16 @@ use super::Dimension; #[derive(Clone, PartialEq, Debug)] pub enum CalcDimension { /// Add two [`Dimension`]s together. - Add(Box, Box), + Add(Dimension, Dimension), /// Subtract the right [`Dimension`] from the left one. - Sub(Box, Box), + Sub(Dimension, Dimension), /// Multiply a [`Dimension`] with a constant. - Mul(Box, f32), + Mul(Dimension, f32), /// Divide a [`Dimension`] by a constant. - Div(Box, f32), + Div(Dimension, f32), } impl MaybeResolve> for CalcDimension { diff --git a/src/style/dimension.rs b/src/style/dimension.rs index b91596b8c..0f6f7db52 100644 --- a/src/style/dimension.rs +++ b/src/style/dimension.rs @@ -39,9 +39,11 @@ pub enum Dimension { /// # /// let calc = Dimension::Points(10.0) + Dimension::Percent(50.0); /// let expected = Dimension::Calc( - /// CalcDimension::Add( - /// Box::new(Dimension::Points(10.0)), - /// Box::new(Dimension::Percent(50.0)) + /// Box::new( + /// CalcDimension::Add( + /// Dimension::Points(10.0), + /// Dimension::Percent(50.0) + /// ) /// ) /// ); /// assert_eq!(calc, expected); @@ -50,7 +52,7 @@ pub enum Dimension { /// The actual result is then calculated when resolving the absolute values. /// See [`Dimension::maybe_resolve`]. #[cfg(feature = "std")] - Calc(CalcDimension), + Calc(Box), } impl Default for Dimension { diff --git a/src/style/dimension_ops.rs b/src/style/dimension_ops.rs index 7609e6263..8b085bca5 100644 --- a/src/style/dimension_ops.rs +++ b/src/style/dimension_ops.rs @@ -42,9 +42,11 @@ impl Add for Dimension { /// # /// let result = Dimension::Points(5.0) + Dimension::Percent(80.0); /// let expected = Dimension::Calc( - /// CalcDimension::Add( - /// Box::new(Dimension::Points(5.0)), - /// Box::new(Dimension::Percent(80.0)) + /// Box::new( + /// CalcDimension::Add( + /// Dimension::Points(5.0), + /// Dimension::Percent(80.0) + /// ) /// ) /// ); /// assert_eq!(result, expected); @@ -56,7 +58,7 @@ impl Add for Dimension { (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs + rhs), (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs + rhs), // Result can't be known in advance, defer calculation until resolving the actual values - (lhs, rhs) => Dimension::Calc(CalcDimension::Add(Box::new(lhs), Box::new(rhs))), + (lhs, rhs) => Dimension::Calc(Box::new(CalcDimension::Add(lhs, rhs))), } } } @@ -99,9 +101,11 @@ impl Sub for Dimension { /// # /// let result = Dimension::Percent(80.0) - Dimension::Points(5.0); /// let expected = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) /// ); /// assert_eq!(result, expected); @@ -113,7 +117,7 @@ impl Sub for Dimension { (Dimension::Points(lhs), Dimension::Points(rhs)) => Dimension::Points(lhs - rhs), (Dimension::Percent(lhs), Dimension::Percent(rhs)) => Dimension::Percent(lhs - rhs), // Result can't be known in advance, defer calculation until resolving the actual values - (lhs, rhs) => Dimension::Calc(CalcDimension::Sub(Box::new(lhs), Box::new(rhs))), + (lhs, rhs) => Dimension::Calc(Box::new(CalcDimension::Sub(lhs, rhs))), } } } @@ -155,23 +159,27 @@ impl Mul for Dimension { /// # use taffy::style::CalcDimension; /// # /// let lhs = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) /// ); /// let result = lhs * 3.0; /// let expected = Dimension::Calc( - /// CalcDimension::Mul( - /// Box::new( + /// Box::new( + /// CalcDimension::Mul( /// Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) - /// ) - /// ), - /// 3.0 + /// ), + /// 3.0 + /// ) /// ) /// ); /// assert_eq!(result, expected); @@ -183,7 +191,7 @@ impl Mul for Dimension { Dimension::Points(lhs) => Dimension::Points(lhs * factor), Dimension::Percent(lhs) => Dimension::Percent(lhs * factor), // Result can't be known in advance, defer calculation until resolving the actual values - lhs => Dimension::Calc(CalcDimension::Mul(Box::new(lhs), factor)), + lhs => Dimension::Calc(Box::new(CalcDimension::Mul(lhs, factor))), } } } @@ -225,23 +233,27 @@ impl Mul for f32 { /// # use taffy::style::CalcDimension; /// # /// let lhs = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) /// ); /// let result = 3.0 * lhs; /// let expected = Dimension::Calc( - /// CalcDimension::Mul( - /// Box::new( + /// Box::new( + /// CalcDimension::Mul( /// Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) - /// ) - /// ), - /// 3.0 + /// ), + /// 3.0 + /// ) /// ) /// ); /// assert_eq!(result, expected); @@ -253,7 +265,7 @@ impl Mul for f32 { Dimension::Points(lhs) => Dimension::Points(lhs * self), Dimension::Percent(lhs) => Dimension::Percent(lhs * self), // Result can't be known in advance, defer calculation until resolving the actual values - rhs => Dimension::Calc(CalcDimension::Mul(Box::new(rhs), self)), + rhs => Dimension::Calc(Box::new(CalcDimension::Mul(rhs, self))), } } } @@ -295,23 +307,27 @@ impl Div for Dimension { /// # use taffy::style::CalcDimension; /// # /// let lhs = Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) /// ); /// let result = lhs / 3.0; /// let expected = Dimension::Calc( - /// CalcDimension::Div( - /// Box::new( + /// Box::new( + /// CalcDimension::Div( /// Dimension::Calc( - /// CalcDimension::Sub( - /// Box::new(Dimension::Percent(80.0)), - /// Box::new(Dimension::Points(5.0)) + /// Box::new( + /// CalcDimension::Sub( + /// Dimension::Percent(80.0), + /// Dimension::Points(5.0) + /// ) /// ) - /// ) - /// ), - /// 3.0 + /// ), + /// 3.0 + /// ) /// ) /// ); /// assert_eq!(result, expected); @@ -323,7 +339,7 @@ impl Div for Dimension { Dimension::Points(lhs) => Dimension::Points(lhs / divisor), Dimension::Percent(lhs) => Dimension::Percent(lhs / divisor), // Result can't be known in advance, defer calculation until resolving the actual values - lhs => Dimension::Calc(CalcDimension::Div(Box::new(lhs), divisor)), + lhs => Dimension::Calc(Box::new(CalcDimension::Div(lhs, divisor))), } } }