tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definitions

Replace Number type with a simpler Option<f32> (#144)

* Update RELEASES.md

* Implement extension traits for Option<f32>

* Replace usages of Number with Option<f32>

* Rename module from number.rs to math.rs

* Note removal of associated traits

* Make behavior of maybe_sub consistent

* Thanks clippy!

* dead_code XD

* Update math operations to be consistent with previous impl

* Reduce churn in PR

* Follow line length calculation spec correctly

* Fix undefined math logic for MaybeMath trait

b1ea6794519524c818057af327f78c09ff379453 · by Alice Cecile · (4 years ago) · parent ab22fd7f9 · browse the tree at this commit

Semantic delta · 94

examples/basic.rs

  • body changed fn main

examples/nested.rs

  • body changed fn main

src/flexbox.rs

src/forest.rs

src/geometry.rs

src/layout.rs

  • signature changed def Cache

src/lib.rs

src/math.rs

src/node.rs

src/number.rs

src/style.rs

tests/measure.rs

tests/relayout.rs

tests/root_constraints.rs

tests/simple_child.rs

17 files · +310 −436

diff --git a/RELEASES.md b/RELEASES.md
index fc4ed9d04..d8d05efe5 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -8,6 +8,8 @@
 
 ### 0.2.0 Changed
 
+- removed the public `Number` type; a more idiomatic `Option<f32>` is used instead
+  - the associated public `MinMax` and `OrElse` traits have also been removed; these should never have been public
 - `Sprawl::remove` now returns a `Result<usize, Error>`, to indicate if the operation was sucessful, and if it was, which ID was invalidated.
 - renamed `taffy::forest::Forest.new-node(..)` `taffy::forest::Forest.new_with_children(..)`
 - renamed `taffy::node::Taffy.new-node(..)` -> `taffy::node::Taffy.new_with_children(..)`
@@ -19,6 +21,7 @@
 
 - fixed rounding of fractional values to follow latest Chrome - values are now rounded the same regardless of their position
 - fixed computing free space when using both `flex-grow` and a minimum size
+- padding is now only subtracted when determining the available space if the node size is unspecified, following [section 9.2.2 of the flexbox spec](https://www.w3.org/TR/css-flexbox-1/#line-sizing)
 
 ### 0.2.0 Removed
 
diff --git a/examples/basic.rs b/examples/basic.rs
index 751477ee9..ba1f7f29b 100644
--- a/examples/basic.rs
+++ b/examples/basic.rs
@@ -17,7 +17,7 @@ fn main() -> Result<(), taffy::error::InvalidNode> {
         &[child],
     )?;
 
-    taffy.compute_layout(node, Size { height: Number::Defined(100.0), width: Number::Defined(100.0) })?;
+    taffy.compute_layout(node, Size { height: Some(100.0), width: Some(100.0) })?;
 
     // or just use undefined for 100 x 100
     // taffy.compute_layout(node, Size::undefined())?;
diff --git a/examples/nested.rs b/examples/nested.rs
index 53fb7e491..2abf98213 100644
--- a/examples/nested.rs
+++ b/examples/nested.rs
@@ -47,7 +47,7 @@ fn main() -> Result<(), taffy::error::InvalidNode> {
         &[div1, div2],
     )?;
 
-    taffy.compute_layout(container, Size { height: Number::Defined(100.0), width: Number::Defined(100.0) })?;
+    taffy.compute_layout(container, Size { height: Some(100.0), width: Some(100.0) })?;
 
     println!("node: {:#?}", taffy.layout(container)?);
 
diff --git a/src/flexbox.rs b/src/flexbox.rs
index fd4041d27..1314996fa 100644
--- a/src/flexbox.rs
+++ b/src/flexbox.rs
@@ -3,13 +3,11 @@
 //! Note that some minor steps appear to be missing: see https://github.com/DioxusLabs/taffy/issues for more information.
 use core::f32;
 
-use crate::flexbox::Number::{Defined, Undefined};
 use crate::forest::{Forest, NodeData};
 use crate::geometry::{Point, Rect, Size};
 use crate::layout::{Cache, Layout};
+use crate::math::MaybeMath;
 use crate::node::{MeasureFunc, NodeId};
-use crate::number::{MinMax, OrElse};
-use crate::prelude::Number;
 use crate::style::{AlignContent, AlignSelf, Dimension, Display, FlexWrap, JustifyContent, PositionType};
 use crate::style::{FlexDirection, FlexboxLayout};
 use crate::sys::{abs, round, ChildrenVec, Vec};
@@ -20,14 +18,14 @@ struct FlexItem {
     node: NodeId,
 
     /// The base size of this item
-    size: Size<Number>,
+    size: Size<Option<f32>>,
     /// The minimum allowable size of this item
-    min_size: Size<Number>,
+    min_size: Size<Option<f32>>,
     /// The maximum allowable size of this item
-    max_size: Size<Number>,
+    max_size: Size<Option<f32>>,
 
     /// The final offset of this item
-    position: Rect<Number>,
+    position: Rect<Option<f32>>,
     /// The margin of this item
     margin: Rect<f32>,
     /// The padding of this item
@@ -97,7 +95,7 @@ struct AlgoConstants {
     padding_border: Rect<f32>,
 
     /// The size of the internal node
-    node_inner_size: Size<Number>,
+    node_inner_size: Size<Option<f32>>,
     /// The size of the surrounding container
     container_size: Size<f32>,
     /// The size of the internal container
@@ -106,7 +104,7 @@ struct AlgoConstants {
 
 impl Forest {
     /// Computes the layout of this [`Forest`] according to the flexbox algorithm
-    pub(crate) fn compute(&mut self, root: NodeId, size: Size<Number>) {
+    pub(crate) fn compute(&mut self, root: NodeId, size: Size<Option<f32>>) {
         let style = self.nodes[root].style;
         let has_root_min_max = style.min_size.width.is_defined()
             || style.min_size.height.is_defined()
@@ -174,23 +172,23 @@ impl Forest {
     fn compute_from_cache(
         &mut self,
         node: NodeId,
-        node_size: Size<Number>,
-        parent_size: Size<Number>,
+        node_size: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
         perform_layout: bool,
         main_size: bool,
     ) -> Option<Size<f32>> {
         if let Some(ref cache) = self.cache(node, main_size) {
             if cache.perform_layout || !perform_layout {
-                let width_compatible = if let Number::Defined(width) = node_size.width {
+                let width_compatible = if let Some(width) = node_size.width {
                     abs(width - cache.size.width) < f32::EPSILON
                 } else {
-                    cache.node_size.width.is_undefined()
+                    cache.node_size.width.is_none()
                 };
 
-                let height_compatible = if let Number::Defined(height) = node_size.height {
+                let height_compatible = if let Some(height) = node_size.height {
                     abs(height - cache.size.height) < f32::EPSILON
                 } else {
-                    cache.node_size.height.is_undefined()
+                    cache.node_size.height.is_none()
                 };
 
                 if width_compatible && height_compatible {
@@ -208,15 +206,20 @@ impl Forest {
 
     /// Compute constants that can be reused during the flexbox algorithm.
     #[inline]
-    fn compute_constants(&self, node: NodeId, node_size: Size<Number>, parent_size: Size<Number>) -> AlgoConstants {
+    fn compute_constants(
+        &self,
+        node: NodeId,
+        node_size: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+    ) -> AlgoConstants {
         let dir = self.nodes[node].style.flex_direction;
         let is_row = dir.is_row();
         let is_column = dir.is_column();
         let is_wrap_reverse = self.nodes[node].style.flex_wrap == FlexWrap::WrapReverse;
 
-        let margin = self.nodes[node].style.margin.map(|n| n.resolve(parent_size.width).or_else(0.0));
-        let padding = self.nodes[node].style.padding.map(|n| n.resolve(parent_size.width).or_else(0.0));
-        let border = self.nodes[node].style.border.map(|n| n.resolve(parent_size.width).or_else(0.0));
+        let margin = self.nodes[node].style.margin.map(|n| n.resolve(parent_size.width).unwrap_or(0.0));
+        let padding = self.nodes[node].style.padding.map(|n| n.resolve(parent_size.width).unwrap_or(0.0));
+        let border = self.nodes[node].style.border.map(|n| n.resolve(parent_size.width).unwrap_or(0.0));
 
         let padding_border = Rect {
             start: padding.start + border.start,
@@ -226,8 +229,8 @@ impl Forest {
         };
 
         let node_inner_size = Size {
-            width: node_size.width - padding_border.horizontal_axis_sum(),
-            height: node_size.height - padding_border.vertical_axis_sum(),
+            width: node_size.width.maybe_sub(padding_border.horizontal_axis_sum()),
+            height: node_size.height.maybe_sub(padding_border.vertical_axis_sum()),
         };
 
         let container_size = Size::zero();
@@ -266,9 +269,9 @@ impl Forest {
                 max_size: child_style.max_size.resolve(constants.node_inner_size),
 
                 position: child_style.position.zip_size(constants.node_inner_size, |p, s| p.resolve(s)),
-                margin: child_style.margin.map(|m| m.resolve(constants.node_inner_size.width).or_else(0.0)),
-                padding: child_style.padding.map(|p| p.resolve(constants.node_inner_size.width).or_else(0.0)),
-                border: child_style.border.map(|b| b.resolve(constants.node_inner_size.width).or_else(0.0)),
+                margin: child_style.margin.map(|m| m.resolve(constants.node_inner_size.width).unwrap_or(0.0)),
+                padding: child_style.padding.map(|p| p.resolve(constants.node_inner_size.width).unwrap_or(0.0)),
+                border: child_style.border.map(|b| b.resolve(constants.node_inner_size.width).unwrap_or(0.0)),
 
                 flex_basis: 0.0,
                 inner_flex_basis: 0.0,
@@ -300,16 +303,27 @@ impl Forest {
     #[inline]
     #[must_use]
     fn determine_available_space(
-        node_size: Size<Number>,
-        parent_size: Size<Number>,
+        node_size: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
         constants: &AlgoConstants,
-    ) -> Size<Number> {
-        Size {
-            width: node_size.width.or_else(parent_size.width - constants.margin.horizontal_axis_sum())
-                - constants.padding_border.horizontal_axis_sum(),
-            height: node_size.height.or_else(parent_size.height - constants.margin.vertical_axis_sum())
-                - constants.padding_border.vertical_axis_sum(),
-        }
+    ) -> Size<Option<f32>> {
+        let width = match node_size.width {
+            Some(node_width) => Some(node_width),
+            None => parent_size
+                .width
+                .maybe_sub(constants.margin.horizontal_axis_sum())
+                .maybe_sub(constants.padding_border.horizontal_axis_sum()),
+        };
+
+        let height = match node_size.height {
+            Some(node_height) => Some(node_height),
+            None => parent_size
+                .height
+                .maybe_sub(constants.margin.vertical_axis_sum())
+                .maybe_sub(constants.padding_border.vertical_axis_sum()),
+        };
+
+        Size { width, height }
     }
 
     /// Determine the flex base size and hypothetical main size of each item.
@@ -343,9 +357,9 @@ impl Forest {
     fn determine_flex_base_size(
         &mut self,
         node: NodeId,
-        node_size: Size<Number>,
+        node_size: Size<Option<f32>>,
         constants: &AlgoConstants,
-        available_space: Size<Number>,
+        available_space: Size<Option<f32>>,
         flex_items: &mut Vec<FlexItem>,
     ) {
         // TODO - this does not follow spec. See the TODOs below
@@ -355,8 +369,8 @@ impl Forest {
             // A. If the item has a definite used flex basis, that’s the flex base size.
 
             let flex_basis = child_style.flex_basis.resolve(constants.node_inner_size.main(constants.dir));
-            if flex_basis.is_defined() {
-                child.flex_basis = flex_basis.or_else(0.0);
+            if flex_basis.is_some() {
+                child.flex_basis = flex_basis.unwrap_or(0.0);
                 continue;
             };
 
@@ -365,8 +379,8 @@ impl Forest {
             //    then the flex base size is calculated from its inner
             //    cross size and the flex item’s intrinsic aspect ratio.
 
-            if let Defined(ratio) = child_style.aspect_ratio {
-                if let Defined(cross) = node_size.cross(constants.dir) {
+            if let Some(ratio) = child_style.aspect_ratio {
+                if let Some(cross) = node_size.cross(constants.dir) {
                     if child_style.flex_basis == Dimension::Auto {
                         child.flex_basis = cross * ratio;
                         continue;
@@ -397,7 +411,7 @@ impl Forest {
             //    is auto and not definite, in this calculation use fit-content as the
             //    flex item’s cross size. The flex base size is the item’s resulting main size.
 
-            let width: Number = if !child.size.width.is_defined()
+            let width: Option<f32> = if child.size.width.is_none()
                 && child_style.align_self(&self.nodes[node].style) == AlignSelf::Stretch
                 && constants.is_column
             {
@@ -406,7 +420,7 @@ impl Forest {
                 child.size.width
             };
 
-            let height: Number = if !child.size.height.is_defined()
+            let height: Option<f32> = if child.size.height.is_none()
                 && child_style.align_self(&self.nodes[node].style) == AlignSelf::Stretch
                 && constants.is_row
             {
@@ -483,7 +497,7 @@ impl Forest {
         &self,
         node: NodeId,
         constants: &AlgoConstants,
-        available_space: Size<Number>,
+        available_space: Size<Option<f32>>,
         flex_items: &'a mut Vec<FlexItem>,
     ) -> Vec<FlexLine<'a>> {
         let mut lines = crate::sys::new_vec_with_capacity(1);
@@ -500,7 +514,7 @@ impl Forest {
                     .enumerate()
                     .find(|&(idx, child)| {
                         line_length += child.hypothetical_outer_size.main(constants.dir);
-                        if let Defined(main) = available_space.main(constants.dir) {
+                        if let Some(main) = available_space.main(constants.dir) {
                             line_length > main && idx != 0
                         } else {
                             false
@@ -526,7 +540,7 @@ impl Forest {
         &mut self,
         line: &mut FlexLine,
         constants: &AlgoConstants,
-        available_space: Size<Number>,
+        available_space: Size<Option<f32>>,
     ) {
         // 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
         //    items on the line. If the sum is less than the flex container’s inner main size,
@@ -535,7 +549,7 @@ impl Forest {
 
         let used_flex_factor: f32 =
             line.items.iter().map(|child| child.hypothetical_outer_size.main(constants.dir)).sum();
-        let growing = used_flex_factor < constants.node_inner_size.main(constants.dir).or_else(0.0);
+        let growing = used_flex_factor < constants.node_inner_size.main(constants.dir).unwrap_or(0.0);
         let shrinking = !growing;
 
         // 2. Size inflexible items. Freeze, setting its target main size to its hypothetical main size
@@ -548,7 +562,7 @@ impl Forest {
         for child in line.items.iter_mut() {
             // TODO - This is not found by reading the spec. Maybe this can be done in some other place
             // instead. This was found by trail and error fixing tests to align with webkit output.
-            if constants.node_inner_size.main(constants.dir).is_undefined() && constants.is_row {
+            if constants.node_inner_size.main(constants.dir).is_none() && constants.is_row {
                 child.target_size.set_main(
                     constants.dir,
                     self.compute_preliminary(
@@ -599,7 +613,7 @@ impl Forest {
             })
             .sum();
 
-        let initial_free_space = (constants.node_inner_size.main(constants.dir) - used_space).or_else(0.0);
+        let initial_free_space = constants.node_inner_size.main(constants.dir).maybe_sub(used_space).unwrap_or(0.0);
 
         // 4. Loop
 
@@ -636,12 +650,12 @@ impl Forest {
 
             let free_space = if growing && sum_flex_grow < 1.0 {
                 (initial_free_space * sum_flex_grow)
-                    .maybe_min(constants.node_inner_size.main(constants.dir) - used_space)
+                    .maybe_min(constants.node_inner_size.main(constants.dir).maybe_sub(used_space))
             } else if shrinking && sum_flex_shrink < 1.0 {
                 (initial_free_space * sum_flex_shrink)
-                    .maybe_max(constants.node_inner_size.main(constants.dir) - used_space)
+                    .maybe_max(constants.node_inner_size.main(constants.dir).maybe_sub(used_space))
             } else {
-                (constants.node_inner_size.main(constants.dir) - used_space).or_else(0.0)
+                (constants.node_inner_size.main(constants.dir).maybe_sub(used_space)).unwrap_or(0.0)
             };
 
             // c. Distribute free space proportional to the flex factors.
@@ -697,7 +711,7 @@ impl Forest {
 
             let total_violation = unfrozen.iter_mut().fold(0.0, |acc, child| -> f32 {
                 // TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
-                // The following logic was developed not from the spec but by trail and error looking into how
+                // The following logic was developed not from the spec but by trial and error looking into how
                 // webkit handled various scenarios. Can probably be solved better by passing in
                 // min-content max-content constraints from the top. Need to figure out correct thing to do here as
                 // just piling on more conditionals.
@@ -755,7 +769,7 @@ impl Forest {
         &mut self,
         line: &mut FlexLine,
         constants: &AlgoConstants,
-        available_space: Size<Number>,
+        available_space: Size<Option<f32>>,
     ) {
         for child in line.items.iter_mut() {
             let child_cross = child
@@ -804,7 +818,7 @@ impl Forest {
     fn calculate_children_base_lines(
         &mut self,
         node: NodeId,
-        node_size: Size<Number>,
+        node_size: Size<Option<f32>>,
         flex_lines: &mut [FlexLine],
         constants: &AlgoConstants,
     ) {
@@ -884,12 +898,13 @@ impl Forest {
         &mut self,
         flex_lines: &mut [FlexLine],
         node: NodeId,
-        node_size: Size<Number>,
+        node_size: Size<Option<f32>>,
         constants: &AlgoConstants,
     ) {
-        if flex_lines.len() == 1 && node_size.cross(constants.dir).is_defined() {
+        if flex_lines.len() == 1 && node_size.cross(constants.dir).is_some() {
             flex_lines[0].cross_size =
-                (node_size.cross(constants.dir) - constants.padding_border.cross_axis_sum(constants.dir)).or_else(0.0);
+                (node_size.cross(constants.dir).maybe_sub(constants.padding_border.cross_axis_sum(constants.dir)))
+                    .unwrap_or(0.0);
         } else {
             for line in flex_lines.iter_mut() {
                 //    1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose
@@ -937,14 +952,14 @@ impl Forest {
         &mut self,
         flex_lines: &mut [FlexLine],
         node: NodeId,
-        node_size: Size<Number>,
+        node_size: Size<Option<f32>>,
         constants: &AlgoConstants,
     ) {
-        if self.nodes[node].style.align_content == AlignContent::Stretch && node_size.cross(constants.dir).is_defined()
-        {
+        if self.nodes[node].style.align_content == AlignContent::Stretch && node_size.cross(constants.dir).is_some() {
             let total_cross: f32 = flex_lines.iter().map(|line| line.cross_size).sum();
             let inner_cross =
-                (node_size.cross(constants.dir) - constants.padding_border.cross_axis_sum(constants.dir)).or_else(0.0);
+                (node_size.cross(constants.dir).maybe_sub(constants.padding_border.cross_axis_sum(constants.dir)))
+                    .unwrap_or(0.0);
 
             if total_cross < inner_cross {
                 let remaining = inner_cross - total_cross;
@@ -1236,7 +1251,7 @@ impl Forest {
     #[must_use]
     fn determine_container_cross_size(
         flex_lines: &mut [FlexLine],
-        node_size: Size<Number>,
+        node_size: Size<Option<f32>>,
         constants: &mut AlgoConstants,
     ) -> f32 {
         let total_cross_size: f32 = flex_lines.iter().map(|line| line.cross_size).sum();
@@ -1245,7 +1260,7 @@ impl Forest {
             constants.dir,
             node_size
                 .cross(constants.dir)
-                .or_else(total_cross_size + constants.padding_border.cross_axis_sum(constants.dir)),
+                .unwrap_or(total_cross_size + constants.padding_border.cross_axis_sum(constants.dir)),
         );
 
         constants.inner_container_size.set_cross(
@@ -1343,15 +1358,15 @@ impl Forest {
                 let offset_main = total_offset_main
                     + child.offset_main
                     + child.margin.main_start(constants.dir)
-                    + (child.position.main_start(constants.dir).or_else(0.0)
-                        - child.position.main_end(constants.dir).or_else(0.0));
+                    + (child.position.main_start(constants.dir).unwrap_or(0.0)
+                        - child.position.main_end(constants.dir).unwrap_or(0.0));
 
                 let offset_cross = total_offset_cross
                     + child.offset_cross
                     + line_offset_cross
                     + child.margin.cross_start(constants.dir)
-                    + (child.position.cross_start(constants.dir).or_else(0.0)
-                        - child.position.cross_end(constants.dir).or_else(0.0));
+                    + (child.position.cross_start(constants.dir).unwrap_or(0.0)
+                        - child.position.cross_end(constants.dir).unwrap_or(0.0));
 
                 self.nodes[child.node].layout = Layout {
                     order: self.children[node].iter().position(|n| *n == child.node).unwrap() as u32,
@@ -1400,41 +1415,48 @@ impl Forest {
 
             let child_style = self.nodes[child].style;
 
-            let start =
-                child_style.position.start.resolve(container_width) + child_style.margin.start.resolve(container_width);
-            let end =
-                child_style.position.end.resolve(container_width) + child_style.margin.end.resolve(container_width);
-            let top =
-                child_style.position.top.resolve(container_height) + child_style.margin.top.resolve(container_height);
-            let bottom = child_style.position.bottom.resolve(container_height)
-                + child_style.margin.bottom.resolve(container_height);
+            // X-axis
+            let child_position_start = child_style.position.start.resolve(container_width);
+            let child_margin_start = child_style.margin.start.resolve(container_width);
+            let start = child_position_start.maybe_add(child_margin_start);
+
+            let child_position_end = child_style.position.end.resolve(container_width);
+            let child_margin_end = child_style.margin.end.resolve(container_width);
+            let end = child_position_end.maybe_add(child_margin_end);
+
+            // Y-axis
+            let child_position_top = child_style.position.top.resolve(container_height);
+            let child_margin_top = child_style.margin.top.resolve(container_height);
+            let top = child_position_top.maybe_add(child_margin_top);
+
+            let child_position_bottom = child_style.position.bottom.resolve(container_height);
+            let child_margin_bottom = child_style.margin.bottom.resolve(container_height);
+            let bottom = child_position_bottom.maybe_add(child_margin_bottom);
 
             let (start_main, end_main) = if constants.is_row { (start, end) } else { (top, bottom) };
             let (start_cross, end_cross) = if constants.is_row { (top, bottom) } else { (start, end) };
 
-            let width = child_style
+            let mut width = child_style
                 .size
                 .width
                 .resolve(container_width)
                 .maybe_max(child_style.min_size.width.resolve(container_width))
-                .maybe_min(child_style.max_size.width.resolve(container_width))
-                .or_else(if start.is_defined() && end.is_defined() {
-                    container_width - start - end
-                } else {
-                    Undefined
-                });
+                .maybe_min(child_style.max_size.width.resolve(container_width));
+
+            if width.is_none() && start.is_some() && end.is_some() {
+                width = container_width.maybe_sub(start).maybe_sub(end);
+            }
 
-            let height = child_style
+            let mut height: Option<f32> = child_style
                 .size
                 .height
                 .resolve(container_height)
                 .maybe_max(child_style.min_size.height.resolve(container_height))
-                .maybe_min(child_style.max_size.height.resolve(container_height))
-                .or_else(if top.is_defined() && bottom.is_defined() {
-                    container_height - top - bottom
-                } else {
-                    Undefined
-                });
+                .maybe_min(child_style.max_size.height.resolve(container_height));
+
+            if height.is_none() && top.is_some() && bottom.is_some() {
+                height = container_height.maybe_sub(top).maybe_sub(bottom);
+            }
 
             let preliminary_size = self.compute_preliminary(
                 child,
@@ -1468,10 +1490,10 @@ impl Forest {
                             .resolve(constants.node_inner_size.cross(constants.dir)),
                     );
 
-            let offset_main = if start_main.is_defined() {
-                start_main.or_else(0.0) + constants.border.main_start(constants.dir)
-            } else if end_main.is_defined() {
-                free_main_space - end_main.or_else(0.0) - constants.border.main_end(constants.dir)
+            let offset_main = if start_main.is_some() {
+                start_main.unwrap_or(0.0) + constants.border.main_start(constants.dir)
+            } else if end_main.is_some() {
+                free_main_space - end_main.unwrap_or(0.0) - constants.border.main_end(constants.dir)
             } else {
                 match self.nodes[node].style.justify_content {
                     JustifyContent::SpaceBetween | JustifyContent::FlexStart => {
@@ -1484,10 +1506,10 @@ impl Forest {
                 }
             };
 
-            let offset_cross = if start_cross.is_defined() {
-                start_cross.or_else(0.0) + constants.border.cross_start(constants.dir)
-            } else if end_cross.is_defined() {
-                free_cross_space - end_cross.or_else(0.0) - constants.border.cross_end(constants.dir)
+            let offset_cross = if start_cross.is_some() {
+                start_cross.unwrap_or(0.0) + constants.border.cross_start(constants.dir)
+            } else if end_cross.is_some() {
+                free_cross_space - end_cross.unwrap_or(0.0) - constants.border.cross_end(constants.dir)
             } else {
                 match child_style.align_self(&self.nodes[node].style) {
                     AlignSelf::Auto => 0.0, // Should never happen
@@ -1532,8 +1554,8 @@ impl Forest {
     fn compute_preliminary(
         &mut self,
         node: NodeId,
-        node_size: Size<Number>,
-        parent_size: Size<Number>,
+        node_size: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
         perform_layout: bool,
         main_size: bool,
     ) -> Size<f32> {
@@ -1549,8 +1571,8 @@ impl Forest {
 
         // If this is a leaf node we can skip a lot of this function in some cases
         if self.children[node].is_empty() {
-            if node_size.width.is_defined() && node_size.height.is_defined() {
-                return node_size.map(|s| s.or_else(0.0));
+            if node_size.width.is_some() && node_size.height.is_some() {
+                return node_size.map(|s| s.unwrap_or(0.0));
             }
 
             if let Some(ref measure) = self.nodes[node].measure {
@@ -1565,8 +1587,8 @@ impl Forest {
             }
 
             return Size {
-                width: node_size.width.or_else(0.0) + constants.padding_border.horizontal_axis_sum(),
-                height: node_size.height.or_else(0.0) + constants.padding_border.vertical_axis_sum(),
+                width: node_size.width.unwrap_or(0.0) + constants.padding_border.horizontal_axis_sum(),
+                height: node_size.height.unwrap_or(0.0) + constants.padding_border.vertical_axis_sum(),
             };
         }
 
@@ -1604,7 +1626,7 @@ impl Forest {
         // Not part of the spec from what i can see but seems correct
         constants.container_size.set_main(
             constants.dir,
-            node_size.main(constants.dir).or_else({
+            node_size.main(constants.dir).unwrap_or({
                 let longest_line = flex_lines.iter().fold(f32::MIN, |acc, line| {
                     let length: f32 = line.items.iter().map(|item| item.outer_target_size.main(constants.dir)).sum();
                     acc.max(length)
@@ -1612,7 +1634,7 @@ impl Forest {
 
                 let size = longest_line + constants.padding_border.main_axis_sum(constants.dir);
                 match available_space.main(constants.dir) {
-                    Defined(val) if flex_lines.len() > 1 && size < val => val,
+                    Some(val) if flex_lines.len() > 1 && size < val => val,
                     _ => size,
                 }
             }),
diff --git a/src/forest.rs b/src/forest.rs
index f7f711fb5..8f7b0d095 100644
--- a/src/forest.rs
+++ b/src/forest.rs
@@ -4,7 +4,6 @@
 use crate::geometry::Size;
 use crate::layout::{Cache, Layout};
 use crate::node::{MeasureFunc, NodeId};
-use crate::number::Number;
 use crate::style::FlexboxLayout;
 use crate::sys::{new_vec_with_capacity, ChildrenVec, ParentsVec, Vec};
 
@@ -14,7 +13,7 @@ use crate::sys::{new_vec_with_capacity, ChildrenVec, ParentsVec, Vec};
 pub(crate) struct NodeData {
     /// The layout strategy used by this node
     pub(crate) style: FlexboxLayout,
-    /// The mapping from the Size<Number> (in units) to Size<f32> (in points) for this node
+    /// The mapping from the Size<Option<f32>> (in real units) to Size<f32> (in points) for this node
     pub(crate) measure: Option<MeasureFunc>,
     /// The results of the layout computation
     pub(crate) layout: Layout,
@@ -236,7 +235,7 @@ impl Forest {
     }
 
     /// Computes the layout of the `node` and its children
-    pub(crate) fn compute_layout(&mut self, node: NodeId, size: Size<Number>) {
+    pub(crate) fn compute_layout(&mut self, node: NodeId, size: Size<Option<f32>>) {
         // TODO: It's not clear why this method is distinct
         self.compute(node, size)
     }
diff --git a/src/geometry.rs b/src/geometry.rs
index 55555948c..e043ec180 100644
--- a/src/geometry.rs
+++ b/src/geometry.rs
@@ -1,9 +1,7 @@
 //! Geometric primitives useful for layout
 
-use core::ops::Add;
-
-use crate::number::Number;
 use crate::style::{Dimension, FlexDirection};
+use core::ops::Add;
 
 /// An axis-aligned UI rectangle
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -162,10 +160,10 @@ pub struct Size<T> {
 }
 
 impl Size<()> {
-    /// Generates a `Size<Number>` with undefined width and height
+    /// Generates a `Size<Option<f32>>` with undefined width and height
     #[must_use]
-    pub fn undefined() -> Size<Number> {
-        Size { width: Number::Undefined, height: Number::Undefined }
+    pub fn undefined() -> Size<Option<f32>> {
+        Size { width: None, height: None }
     }
 }
 
@@ -235,7 +233,7 @@ impl Size<f32> {
 
 impl Size<Dimension> {
     /// Converts any `parent`-relative values for size into an absolute size
-    pub(crate) fn resolve(&self, parent: Size<Number>) -> Size<Number> {
+    pub(crate) fn resolve(&self, parent: Size<Option<f32>>) -> Size<Option<f32>> {
         Size { width: self.width.resolve(parent.width), height: self.height.resolve(parent.height) }
     }
 }
diff --git a/src/layout.rs b/src/layout.rs
index dd465f7ff..cbf323a90 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1,7 +1,6 @@
 //! Final and cached data structures that represent the high-level UI layout
 
 use crate::geometry::{Point, Size};
-use crate::number::Number;
 
 /// The final result of a layout algorithm for a single [`Node`](crate::node::Node).
 #[derive(Copy, Debug, Clone)]
@@ -29,9 +28,9 @@ impl Layout {
 #[derive(Debug, Clone)]
 pub(crate) struct Cache {
     /// The initial cached size of the node itself
-    pub(crate) node_size: Size<Number>,
+    pub(crate) node_size: Size<Option<f32>>,
     /// The initial cached size of the parent's node
-    pub(crate) parent_size: Size<Number>,
+    pub(crate) parent_size: Size<Option<f32>>,
     /// Whether or not layout should be recomputed
     pub(crate) perform_layout: bool,
 
diff --git a/src/lib.rs b/src/lib.rs
index b10b07041..ba8e64eec 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,8 +14,8 @@ extern crate serde;
 pub mod error;
 pub mod geometry;
 pub mod layout;
+pub mod math;
 pub mod node;
-pub mod number;
 pub mod prelude;
 pub mod style;
 
diff --git a/src/math.rs b/src/math.rs
new file mode 100644
index 000000000..2d99ab827
--- /dev/null
+++ b/src/math.rs
@@ -0,0 +1,123 @@
+//! Contains numberical helper traits and functions
+
+/// A trait to conveniently calculate minimums and maximums when some data may not be defined
+///
+/// If the left-hand value is [`None`], these operations return [`None`].
+/// If the right-hand value is [`None`], it is treated as zero.
+pub(crate) trait MaybeMath<In, Out> {
+    /// Returns the minimum of `self` and `rhs`
+    fn maybe_min(self, rhs: In) -> Out;
+
+    /// Returns the maximum of `self` and `rhs`
+    fn maybe_max(self, rhs: In) -> Out;
+
+    /// Adds `self` and `rhs`.
+    fn maybe_add(self, rhs: In) -> Out;
+
+    /// Subracts rhs from `self`, treating [`None`] values as default
+    fn maybe_sub(self, rhs: In) -> Out;
+}
+
+impl MaybeMath<Option<f32>, Option<f32>> for Option<f32> {
+    fn maybe_min(self, rhs: Option<f32>) -> Option<f32> {
+        match (self, rhs) {
+            (Some(l), Some(r)) => Some(l.min(r)),
+            (Some(_l), None) => self,
+            (None, Some(_r)) => None,
+            (None, None) => None,
+        }
+    }
+
+    fn maybe_max(self, rhs: Option<f32>) -> Option<f32> {
+        match (self, rhs) {
+            (Some(l), Some(r)) => Some(l.max(r)),
+            (Some(_l), None) => self,
+            (None, Some(_r)) => None,
+            (None, None) => None,
+        }
+    }
+
+    fn maybe_add(self, rhs: Option<f32>) -> Option<f32> {
+        match (self, rhs) {
+            (Some(l), Some(r)) => Some(l + r),
+            (Some(_l), None) => self,
+            (None, Some(_r)) => None,
+            (None, None) => None,
+        }
+    }
+
+    fn maybe_sub(self, rhs: Option<f32>) -> Option<f32> {
+        match (self, rhs) {
+            (Some(l), Some(r)) => Some(l - r),
+            (Some(_l), None) => self,
+            (None, Some(_r)) => None,
+            (None, None) => None,
+        }
+    }
+}
+
+impl MaybeMath<f32, Option<f32>> for Option<f32> {
+    // The logic here is subtle and critical;
+    // explicit match statements make it more clear what's going on
+    #[allow(clippy::manual_map)]
+    fn maybe_min(self, rhs: f32) -> Option<f32> {
+        match self {
+            Some(val) => Some(val.min(rhs)),
+            None => None,
+        }
+    }
+
+    #[allow(clippy::manual_map)]
+    fn maybe_max(self, rhs: f32) -> Option<f32> {
+        match self {
+            Some(val) => Some(val.max(rhs)),
+            None => None,
+        }
+    }
+
+    #[allow(clippy::manual_map)]
+    fn maybe_add(self, rhs: f32) -> Option<f32> {
+        match self {
+            Some(val) => Some(val + rhs),
+            None => None,
+        }
+    }
+
+    #[allow(clippy::manual_map)]
+    fn maybe_sub(self, rhs: f32) -> Option<f32> {
+        match self {
+            Some(val) => Some(val - rhs),
+            None => None,
+        }
+    }
+}
+
+impl MaybeMath<Option<f32>, f32> for f32 {
+    fn maybe_min(self, rhs: Option<f32>) -> f32 {
+        match rhs {
+            Some(val) => self.min(val),
+            None => self,
+        }
+    }
+
+    fn maybe_max(self, rhs: Option<f32>) -> f32 {
+        match rhs {
+            Some(val) => self.max(val),
+            None => self,
+        }
+    }
+
+    fn maybe_add(self, rhs: Option<f32>) -> f32 {
+        match rhs {
+            Some(val) => self + val,
+            None => self,
+        }
+    }
+
+    fn maybe_sub(self, rhs: Option<f32>) -> f32 {
+        match rhs {
+            Some(val) => self - val,
+            None => self,
+        }
+    }
+}
diff --git a/src/node.rs b/src/node.rs
index ee56bc770..d92ea10cf 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -5,20 +5,19 @@ use crate::error;
 use crate::forest::Forest;
 use crate::geometry::Size;
 use crate::layout::Layout;
-use crate::number::Number;
 use crate::style::FlexboxLayout;
 #[cfg(any(feature = "std", feature = "alloc"))]
 use crate::sys::Box;
 use crate::sys::{new_map_with_capacity, ChildrenVec, Map, Vec};
 use core::sync::atomic::{AtomicUsize, Ordering};
 
-/// A function that can be applied to a `Size<Number>` to obtain a `Size<f32>`
+/// A function that can be applied to a `Size<Option<f32>>` to obtain a `Size<f32>`
 pub enum MeasureFunc {
     /// Stores an unboxed function
-    Raw(fn(Size<Number>) -> Size<f32>),
+    Raw(fn(Size<Option<f32>>) -> Size<f32>),
     /// Stores a boxed function
     #[cfg(any(feature = "std", feature = "alloc"))]
-    Boxed(Box<dyn Fn(Size<Number>) -> Size<f32>>),
+    Boxed(Box<dyn Fn(Size<Option<f32>>) -> Size<f32>>),
 }
 
 /// Global taffy instance id allocator.
@@ -288,7 +287,7 @@ impl Taffy {
     }
 
     /// Updates the stored layout of the provided `node` and its children
-    pub fn compute_layout(&mut self, node: Node, size: Size<Number>) -> Result<(), error::InvalidNode> {
+    pub fn compute_layout(&mut self, node: Node, size: Size<Option<f32>>) -> Result<(), error::InvalidNode> {
         let id = self.find_node(node)?;
         self.forest.compute_layout(id, size);
         Ok(())
diff --git a/src/number.rs b/src/number.rs
deleted file mode 100644
index 48dd11ea7..000000000
--- a/src/number.rs
+++ /dev/null
@@ -1,227 +0,0 @@
-//! Contains the [`Number`] type and associated methods
-
-use core::ops::{Add, Div, Mul, Sub};
-
-/// A [`f32`] that may be undefined
-///
-/// NOTE: this should *really* be an [`Option<f32>`],
-/// but we're optimizing for backwards compatibility for now.
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub enum Number {
-    /// Pretend this is [`Some(f32)`]
-    ///
-    /// WARNING: the contained value may be NaN
-    Defined(f32),
-    /// Pretend this is [`None`]
-    Undefined,
-}
-
-/// An extension method used for [`Number`]
-pub trait OrElse<T> {
-    /// Returns the contained value if it is defined, otherwise returns `other`
-    fn or_else(self, other: T) -> T;
-}
-
-impl Default for Number {
-    fn default() -> Self {
-        Self::Undefined
-    }
-}
-
-impl OrElse<f32> for Number {
-    fn or_else(self, other: f32) -> f32 {
-        match self {
-            Number::Defined(val) => val,
-            Number::Undefined => other,
-        }
-    }
-}
-
-impl OrElse<Self> for Number {
-    fn or_else(self, other: Self) -> Self {
-        match self {
-            Number::Defined(_) => self,
-            Number::Undefined => other,
-        }
-    }
-}
-
-impl Number {
-    /// Is the number defined?
-    pub fn is_defined(self) -> bool {
-        match self {
-            Number::Defined(_) => true,
-            Number::Undefined => false,
-        }
-    }
-
-    /// Is the number undefined?
-    pub fn is_undefined(self) -> bool {
-        match self {
-            Number::Defined(_) => false,
-            Number::Undefined => true,
-        }
-    }
-}
-
-/// An extension trait for [`Number`]
-pub trait MinMax<In, Out> {
-    /// Returns the minimum of self and rhs
-    ///
-    /// If either either value is invalid, returns the other value.
-    fn maybe_min(self, rhs: In) -> Out;
-    /// Returns the maximum of self and rhs
-    ///
-    /// If either either value is invalid, returns the other value.
-    fn maybe_max(self, rhs: In) -> Out;
-}
-
-impl MinMax<Self, Self> for Number {
-    fn maybe_min(self, rhs: Self) -> Self {
-        match (self, rhs) {
-            (Number::Defined(l), Number::Defined(r)) => Number::Defined(l.min(r)),
-            (Number::Defined(_), _) => self,
-            _ => Number::Undefined,
-        }
-    }
-
-    fn maybe_max(self, rhs: Self) -> Self {
-        match (self, rhs) {
-            (Number::Defined(l), Number::Defined(r)) => Number::Defined(l.max(r)),
-            (Number::Defined(_), _) => self,
-            _ => Number::Undefined,
-        }
-    }
-}
-
-impl MinMax<f32, Number> for Number {
-    fn maybe_min(self, rhs: f32) -> Self {
-        match self {
-            Number::Defined(val) => Number::Defined(val.min(rhs)),
-            Number::Undefined => Number::Undefined,
-        }
-    }
-
-    fn maybe_max(self, rhs: f32) -> Self {
-        match self {
-            Number::Defined(val) => Number::Defined(val.max(rhs)),
-            Number::Undefined => Number::Undefined,
-        }
-    }
-}
-
-impl MinMax<Number, f32> for f32 {
-    fn maybe_min(self, rhs: Number) -> f32 {
-        match rhs {
-            Number::Defined(val) => self.min(val),
-            Number::Undefined => self,
-        }
-    }
-
-    fn maybe_max(self, rhs: Number) -> f32 {
-        match rhs {
-            Number::Defined(val) => self.max(val),
-            Number::Undefined => self,
-        }
-    }
-}
-
-impl From<f32> for Number {
-    #[must_use]
-    fn from(v: f32) -> Self {
-        Self::Defined(v)
-    }
-}
-
-impl Add<f32> for Number {
-    type Output = Number;
-
-    fn add(self, rhs: f32) -> Self {
-        match self {
-            Number::Defined(val) => Number::Defined(val + rhs),
-            Number::Undefined => Number::Undefined,
-        }
-    }
-}
-
-impl Add<Number> for Number {
-    type Output = Number;
-
-    fn add(self, rhs: Self) -> Self {
-        match (self, rhs) {
-            (Number::Defined(l), Number::Defined(r)) => Number::Defined(l + r),
-            (Number::Defined(_), _) => self,
-            _ => Number::Undefined,
-        }
-    }
-}
-
-impl Sub<f32> for Number {
-    type Output = Number;
-
-    fn sub(self, rhs: f32) -> Self {
-        match self {
-            Number::Defined(val) => Number::Defined(val - rhs),
-            Number::Undefined => Number::Undefined,
-        }
-    }
-}
-
-impl Sub<Number> for Number {
-    type Output = Number;
-
-    fn sub(self, rhs: Self) -> Self {
-        match (self, rhs) {
-            (Number::Defined(l), Number::Defined(r)) => Number::Defined(l - r),
-            (Number::Defined(_), _) => self,
-            _ => Number::Undefined,
-        }
-    }
-}
-
-impl Mul<f32> for Number {
-    type Output = Number;
-
-    fn mul(self, rhs: f32) -> Self {
-        match self {
-            Number::Defined(val) => Number::Defined(val * rhs),
-            Number::Undefined => Number::Undefined,
-        }
-    }
-}
-
-impl Mul<Number> for Number {
-    type Output = Number;
-
-    fn mul(self, rhs: Self) -> Self {
-        match (self, rhs) {
-            (Number::Defined(l), Number::Defined(r)) => Number::Defined(l * r),
-            (Number::Defined(_), _) => self,
-            _ => Number::Undefined,
-        }
-    }
-}
-
-impl Div<f32> for Number {
-    type Output = Number;
-
-    fn div(self, rhs: f32) -> Self {
-        match self {
-            Number::Defined(val) => Number::Defined(val / rhs),
-            Number::Undefined => Number::Undefined,
-        }
-    }
-}
-
-impl Div<Number> for Number {
-    type Output = Number;
-
-    fn div(self, rhs: Self) -> Self {
-        match (self, rhs) {
-            (Number::Defined(l), Number::Defined(r)) => Number::Defined(l / r),
-            (Number::Defined(_), _) => self,
-            _ => Number::Undefined,
-        }
-    }
-}
diff --git a/src/prelude.rs b/src/prelude.rs
index 107baab24..0cbe7df3b 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -4,7 +4,6 @@ pub use crate::{
     geometry::{Rect, Size},
     layout::Layout,
     node::{Node, Taffy},
-    number::Number,
     style::{
         AlignContent, AlignItems, AlignSelf, Dimension, Display, FlexDirection, FlexWrap, FlexboxLayout,
         JustifyContent, PositionType,
diff --git a/src/style.rs b/src/style.rs
index ee54620f3..22f5a03f7 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -1,7 +1,6 @@
 //! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout
 
 use crate::geometry::{Rect, Size};
-use crate::number::Number;
 
 /// How [`Nodes`](crate::node::Node) are aligned relative to the cross axis
 ///
@@ -272,11 +271,12 @@ impl Default for Dimension {
 
 impl Dimension {
     /// Converts the given [`Dimension`] into a concrete value of points
-    pub(crate) fn resolve(self, parent_dim: Number) -> Number {
+    pub(crate) fn resolve(self, parent_dim: Option<f32>) -> Option<f32> {
         match self {
-            Dimension::Points(points) => Number::Defined(points),
-            Dimension::Percent(percent) => parent_dim * percent,
-            _ => Number::Undefined,
+            Dimension::Points(points) => Some(points),
+            // parent_dim * percent
+            Dimension::Percent(percent) => parent_dim.map(|dim| dim * percent),
+            _ => None,
         }
     }
 
@@ -360,7 +360,7 @@ pub struct FlexboxLayout {
     /// Sets the preferred aspect ratio for the item
     ///
     /// The ratio is calculated as width divided by height.
-    pub aspect_ratio: Number,
+    pub aspect_ratio: Option<f32>,
 }
 
 impl Default for FlexboxLayout {
diff --git a/tests/measure.rs b/tests/measure.rs
index 25eccc8b3..1dfea23b6 100644
--- a/tests/measure.rs
+++ b/tests/measure.rs
@@ -1,7 +1,6 @@
 #[cfg(test)]
 mod measure {
     use taffy::node::MeasureFunc;
-    use taffy::number::OrElse;
 
     #[test]
     fn measure_root() {
@@ -10,8 +9,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -30,8 +29,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -53,8 +52,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -85,8 +84,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -135,8 +134,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { flex_grow: 1.0, ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(10.0),
-                    height: constraint.height.or_else(50.0),
+                    width: constraint.width.unwrap_or(10.0),
+                    height: constraint.height.unwrap_or(50.0),
                 }),
             )
             .unwrap();
@@ -178,8 +177,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(50.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(50.0),
                 }),
             )
             .unwrap();
@@ -220,8 +219,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { flex_grow: 1.0, ..Default::default() },
                 MeasureFunc::Raw(|constraint| {
-                    let width = constraint.width.or_else(10.0);
-                    let height = constraint.height.or_else(width * 2.0);
+                    let width = constraint.width.unwrap_or(10.0);
+                    let height = constraint.height.unwrap_or(width * 2.0);
                     taffy::geometry::Size { width, height }
                 }),
             )
@@ -266,8 +265,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| {
-                    let width = constraint.width.or_else(100.0);
-                    let height = constraint.height.or_else(width * 2.0);
+                    let width = constraint.width.unwrap_or(100.0);
+                    let height = constraint.height.unwrap_or(width * 2.0);
                     taffy::geometry::Size { width, height }
                 }),
             )
@@ -298,8 +297,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| {
-                    let height = constraint.height.or_else(50.0);
-                    let width = constraint.width.or_else(height);
+                    let height = constraint.height.unwrap_or(50.0);
+                    let width = constraint.width.unwrap_or(height);
                     taffy::geometry::Size { width, height }
                 }),
             )
@@ -334,8 +333,8 @@ mod measure {
                     ..Default::default()
                 },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -357,8 +356,8 @@ mod measure {
                     ..Default::default()
                 },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -392,8 +391,8 @@ mod measure {
                     ..Default::default()
                 },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(100.0),
-                    height: constraint.height.or_else(100.0),
+                    width: constraint.width.unwrap_or(100.0),
+                    height: constraint.height.unwrap_or(100.0),
                 }),
             )
             .unwrap();
@@ -426,8 +425,8 @@ mod measure {
             .new_leaf(
                 taffy::style::FlexboxLayout { ..Default::default() },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(50.0),
-                    height: constraint.height.or_else(50.0),
+                    width: constraint.width.unwrap_or(50.0),
+                    height: constraint.height.unwrap_or(50.0),
                 }),
             )
             .unwrap();
@@ -461,8 +460,8 @@ mod measure {
                     ..Default::default()
                 },
                 MeasureFunc::Raw(|constraint| taffy::geometry::Size {
-                    width: constraint.width.or_else(50.0),
-                    height: constraint.height.or_else(50.0),
+                    width: constraint.width.unwrap_or(50.0),
+                    height: constraint.height.unwrap_or(50.0),
                 }),
             )
             .unwrap();
@@ -528,8 +527,8 @@ mod measure {
                 MeasureFunc::Raw(|constraint| {
                     NUM_MEASURES.fetch_add(1, atomic::Ordering::Relaxed);
                     taffy::geometry::Size {
-                        width: constraint.width.or_else(50.0),
-                        height: constraint.height.or_else(50.0),
+                        width: constraint.width.unwrap_or(50.0),
+                        height: constraint.height.unwrap_or(50.0),
                     }
                 }),
             )
diff --git a/tests/relayout.rs b/tests/relayout.rs
index 14fdaf7de..6b4df7767 100644
--- a/tests/relayout.rs
+++ b/tests/relayout.rs
@@ -33,29 +33,13 @@ fn relayout() {
         )
         .unwrap();
     println!("0:");
-    taffy
-        .compute_layout(
-            node,
-            taffy::geometry::Size {
-                width: taffy::prelude::Number::Defined(100f32),
-                height: taffy::prelude::Number::Defined(100f32),
-            },
-        )
-        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size { width: Some(100f32), height: Some(100f32) }).unwrap();
     let initial = taffy.layout(node).unwrap().location;
     let initial0 = taffy.layout(node0).unwrap().location;
     let initial1 = taffy.layout(node1).unwrap().location;
     for i in 1..10 {
         println!("\n\n{i}:");
-        taffy
-            .compute_layout(
-                node,
-                taffy::geometry::Size {
-                    width: taffy::prelude::Number::Defined(100f32),
-                    height: taffy::prelude::Number::Defined(100f32),
-                },
-            )
-            .unwrap();
+        taffy.compute_layout(node, taffy::geometry::Size { width: Some(100f32), height: Some(100f32) }).unwrap();
         assert_eq!(taffy.layout(node).unwrap().location, initial);
         assert_eq!(taffy.layout(node0).unwrap().location, initial0);
         assert_eq!(taffy.layout(node1).unwrap().location, initial1);
diff --git a/tests/root_constraints.rs b/tests/root_constraints.rs
index 1362db202..bc2ee1f86 100644
--- a/tests/root_constraints.rs
+++ b/tests/root_constraints.rs
@@ -1,6 +1,5 @@
 #[cfg(test)]
 mod root_constraints {
-    use taffy::number::*;
 
     #[test]
     fn root_with_percentage_size() {
@@ -18,12 +17,7 @@ mod root_constraints {
             )
             .unwrap();
 
-        taffy
-            .compute_layout(
-                node,
-                taffy::geometry::Size { width: Number::Defined(100.0), height: Number::Defined(200.0) },
-            )
-            .unwrap();
+        taffy.compute_layout(node, taffy::geometry::Size { width: Some(100.0), height: Some(200.0) }).unwrap();
         let layout = taffy.layout(node).unwrap();
 
         assert_eq!(layout.size.width, 100.0);
@@ -35,12 +29,7 @@ mod root_constraints {
         let mut taffy = taffy::node::Taffy::new();
         let node = taffy.new_with_children(taffy::style::FlexboxLayout { ..Default::default() }, &[]).unwrap();
 
-        taffy
-            .compute_layout(
-                node,
-                taffy::geometry::Size { width: Number::Defined(100.0), height: Number::Defined(100.0) },
-            )
-            .unwrap();
+        taffy.compute_layout(node, taffy::geometry::Size { width: Some(100.0), height: Some(100.0) }).unwrap();
         let layout = taffy.layout(node).unwrap();
 
         assert_eq!(layout.size.width, 0.0);
@@ -63,12 +52,7 @@ mod root_constraints {
             )
             .unwrap();
 
-        taffy
-            .compute_layout(
-                node,
-                taffy::geometry::Size { width: Number::Defined(100.0), height: Number::Defined(100.0) },
-            )
-            .unwrap();
+        taffy.compute_layout(node, taffy::geometry::Size { width: Some(100.0), height: Some(100.0) }).unwrap();
         let layout = taffy.layout(node).unwrap();
 
         assert_eq!(layout.size.width, 200.0);
diff --git a/tests/simple_child.rs b/tests/simple_child.rs
index 6bb727355..61a4f9fb9 100644
--- a/tests/simple_child.rs
+++ b/tests/simple_child.rs
@@ -60,15 +60,7 @@ fn simple_child() {
             &[node0, node1],
         )
         .unwrap();
-    taffy
-        .compute_layout(
-            node,
-            taffy::geometry::Size {
-                width: taffy::prelude::Number::Defined(100f32),
-                height: taffy::prelude::Number::Defined(100f32),
-            },
-        )
-        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size { width: Some(100.), height: Some(100.) }).unwrap();
     assert_eq!(taffy.layout(node).unwrap().location, Point { x: 0.0, y: 0.0 });
     assert_eq!(taffy.layout(node0).unwrap().location, Point { x: 0.0, y: 0.0 });
     assert_eq!(taffy.layout(node1).unwrap().location, Point { x: 10.0, y: 0.0 });