gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 497HTML 254C 19JavaScript 81329 Definiciones

Make the core algorithms be allocation free

a40abe4bd9bd4a3eb0e6d80afa84924e4076f52a · por David Flemström · (hace 6 años) · padre 6e9ad8ea3 · ver el árbol en este commit

Delta semántico · 24

src/algo.rs

src/forest.rs

src/lib.rs

src/node.rs

4 archivos · +157 −191

diff --git a/src/algo.rs b/src/algo.rs
index cb902d15f..caa0094d9 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -1,13 +1,10 @@
-#[cfg(not(feature = "std"))]
-use alloc::{boxed::Box, vec, vec::Vec};
-
-use core::any::Any;
 use core::f32;
 
 use crate::forest::{Forest, NodeData};
 use crate::id::NodeId;
 use crate::result;
 use crate::style::*;
+use crate::sys;
 
 use crate::number::Number::*;
 use crate::number::*;
@@ -50,14 +47,14 @@ struct FlexItem {
     offset_cross: f32,
 }
 
-struct FlexLine {
-    items: Vec<FlexItem>,
+struct FlexLine<'a> {
+    items: &'a mut [FlexItem],
     cross_size: f32,
     offset_cross: f32,
 }
 
 impl Forest {
-    pub(crate) fn compute(&mut self, root: NodeId, size: Size<Number>) -> Result<(), Box<dyn Any>> {
+    pub(crate) fn compute(&mut self, root: NodeId, size: Size<Number>) {
         let style = self.nodes[root].style;
         let has_root_min_max = style.min_size.width.is_defined()
             || style.min_size.height.is_defined()
@@ -70,7 +67,7 @@ impl Forest {
                 Size { width: style.size.width.resolve(size.width), height: style.size.height.resolve(size.height) },
                 size,
                 false,
-            )?;
+            );
 
             self.compute_internal(
                 root,
@@ -90,14 +87,14 @@ impl Forest {
                 },
                 size,
                 true,
-            )?
+            )
         } else {
             self.compute_internal(
                 root,
                 Size { width: style.size.width.resolve(size.width), height: style.size.height.resolve(size.height) },
                 size,
                 true,
-            )?
+            )
         };
 
         self.nodes[root].layout = result::Layout {
@@ -107,10 +104,15 @@ impl Forest {
         };
 
         Self::round_layout(&mut self.nodes, &self.children, root, 0.0, 0.0);
-        Ok(())
     }
 
-    fn round_layout(nodes: &mut Vec<NodeData>, children: &[Vec<NodeId>], root: NodeId, abs_x: f32, abs_y: f32) {
+    fn round_layout(
+        nodes: &mut [NodeData],
+        children: &[sys::ChildrenVec<NodeId>],
+        root: NodeId,
+        abs_x: f32,
+        abs_y: f32,
+    ) {
         let layout = &mut nodes[root].layout;
         let abs_x = abs_x + layout.location.x;
         let abs_y = abs_y + layout.location.y;
@@ -131,7 +133,7 @@ impl Forest {
         node_size: Size<Number>,
         parent_size: Size<Number>,
         perform_layout: bool,
-    ) -> Result<ComputeResult, Box<dyn Any>> {
+    ) -> ComputeResult {
         self.nodes[node].is_dirty = false;
 
         // First we check if we have a result for the given input
@@ -150,11 +152,11 @@ impl Forest {
                 };
 
                 if width_compatible && height_compatible {
-                    return Ok(cache.result.clone());
+                    return cache.result.clone();
                 }
 
                 if cache.node_size == node_size && cache.parent_size == parent_size {
-                    return Ok(cache.result.clone());
+                    return cache.result.clone();
                 }
             }
         }
@@ -189,22 +191,22 @@ 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 Ok(ComputeResult { size: node_size.map(|s| s.or_else(0.0)) });
+                return ComputeResult { size: node_size.map(|s| s.or_else(0.0)) };
             }
 
             if let Some(ref measure) = self.nodes[node].measure {
-                let result = ComputeResult { size: measure(node_size)? };
+                let result = ComputeResult { size: measure(node_size) };
                 self.nodes[node].layout_cache =
                     Some(result::Cache { node_size, parent_size, perform_layout, result: result.clone() });
-                return Ok(result);
+                return result;
             }
 
-            return Ok(ComputeResult {
+            return ComputeResult {
                 size: Size {
                     width: node_size.width.or_else(0.0) + padding_border.horizontal(),
                     height: node_size.height.or_else(0.0) + padding_border.vertical(),
                 },
-            });
+            };
         }
 
         // 9.2. Line Length Determination
@@ -224,7 +226,7 @@ impl Forest {
             height: node_size.height.or_else(parent_size.height - margin.vertical()) - padding_border.vertical(),
         };
 
-        let mut flex_items: Vec<FlexItem> = self.children[node]
+        let mut flex_items: sys::Vec<FlexItem> = self.children[node]
             .iter()
             .map(|child| (child, &self.nodes[*child].style))
             .filter(|(_, style)| style.position_type != PositionType::Absolute)
@@ -275,7 +277,7 @@ impl Forest {
 
         // TODO - this does not follow spec. See commented out code below
         // 3. Determine the flex base size and hypothetical main size of each item:
-        flex_items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
+        for child in &mut flex_items {
             let child_style = self.nodes[child.node].style;
 
             // A. If the item has a definite used flex basis, that’s the flex base size.
@@ -283,7 +285,7 @@ impl Forest {
             let flex_basis = child_style.flex_basis.resolve(node_inner_size.main(dir));
             if flex_basis.is_defined() {
                 child.flex_basis = flex_basis.or_else(0.0);
-                return Ok(());
+                continue;
             };
 
             // B. If the flex item has an intrinsic aspect ratio,
@@ -295,7 +297,7 @@ impl Forest {
                 if let Defined(cross) = node_size.cross(dir) {
                     if child_style.flex_basis == Dimension::Auto {
                         child.flex_basis = cross * ratio;
-                        return Ok(());
+                        continue;
                     }
                 }
             }
@@ -350,19 +352,17 @@ impl Forest {
                     },
                     available_space,
                     false,
-                )?
+                )
                 .size
                 .main(dir)
                 .maybe_max(child.min_size.main(dir))
                 .maybe_min(child.max_size.main(dir));
-
-            Ok(())
-        })?;
+        }
 
         // The hypothetical main size is the item’s flex base size clamped according to its
         // used min and max main sizes (and flooring the content box size at zero).
 
-        flex_items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
+        for child in &mut flex_items {
             child.inner_flex_basis = child.flex_basis - child.padding.main(dir) - child.border.main(dir);
 
             // TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
@@ -370,7 +370,7 @@ impl Forest {
             // webkit handled various scenarios. Can probably be solved better by passing in
             // min-content max-content constraints from the top
             let min_main = self
-                .compute_internal(child.node, Size { width: Undefined, height: Undefined }, available_space, false)?
+                .compute_internal(child.node, Size { width: Undefined, height: Undefined }, available_space, false)
                 .size
                 .main(dir)
                 .maybe_max(child.min_size.main(dir))
@@ -384,9 +384,7 @@ impl Forest {
             child
                 .hypothetical_outer_size
                 .set_main(dir, child.hypothetical_inner_size.main(dir) + child.margin.main(dir));
-
-            Ok(())
-        })?;
+        }
 
         // 9.3. Main Size Determination
 
@@ -405,30 +403,34 @@ impl Forest {
         //      Note that the "collect as many" line will collect zero-sized flex items onto
         //      the end of the previous line even if the last non-zero item exactly "filled up" the line.
 
-        let mut flex_lines = {
-            let mut lines: Vec<FlexLine> = vec![];
-            let mut line_length = 0.0;
+        let mut flex_lines: sys::Vec<_> = {
+            let mut lines = sys::new_vec_with_capacity(1);
 
             if self.nodes[node].style.flex_wrap == FlexWrap::NoWrap {
-                lines.push(FlexLine { items: flex_items, cross_size: 0.0, offset_cross: 0.0 });
+                lines.push(FlexLine { items: flex_items.as_mut_slice(), cross_size: 0.0, offset_cross: 0.0 });
             } else {
-                let mut line = FlexLine { items: vec![], cross_size: 0.0, offset_cross: 0.0 };
-
-                for child in flex_items {
-                    line_length += child.hypothetical_outer_size.main(dir);
-
-                    if let Defined(main) = available_space.main(dir) {
-                        if line_length > main && !line.items.is_empty() {
-                            line_length = child.hypothetical_outer_size.main(dir);
-                            lines.push(line);
-                            line = FlexLine { items: vec![], cross_size: 0.0, offset_cross: 0.0 };
-                        }
-                    }
+                let mut flex_items = &mut flex_items[..];
+
+                while !flex_items.is_empty() {
+                    let mut line_length = 0.0;
+                    let index = flex_items
+                        .iter()
+                        .enumerate()
+                        .find(|&(idx, ref child)| {
+                            line_length += child.hypothetical_outer_size.main(dir);
+                            if let Defined(main) = available_space.main(dir) {
+                                line_length > main && idx != 0
+                            } else {
+                                false
+                            }
+                        })
+                        .map(|(idx, _)| idx)
+                        .unwrap_or(flex_items.len());
 
-                    line.items.push(child);
+                    let (items, rest) = flex_items.split_at_mut(index);
+                    lines.push(FlexLine { items, cross_size: 0.0, offset_cross: 0.0 });
+                    flex_items = rest;
                 }
-
-                lines.push(line);
             }
 
             lines
@@ -439,7 +441,7 @@ impl Forest {
         //
         // 9.7. Resolving Flexible Lengths
 
-        flex_lines.iter_mut().try_for_each(|line| -> Result<(), Box<dyn Any>> {
+        for line in &mut flex_lines {
             // 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,
             //    use the flex grow factor for the rest of this algorithm; otherwise, use the
@@ -456,7 +458,7 @@ impl Forest {
             //    - If using the flex shrink factor: any item that has a flex base size
             //      smaller than its hypothetical main size
 
-            line.items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
+            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 node_inner_size.main(dir).is_undefined() && is_row {
@@ -474,7 +476,7 @@ impl Forest {
                             },
                             available_space,
                             false,
-                        )?
+                        )
                         .size
                         .main(dir)
                         .maybe_max(child.min_size.main(dir))
@@ -496,9 +498,7 @@ impl Forest {
                 {
                     child.frozen = true;
                 }
-
-                Ok(())
-            })?;
+            }
 
             // 3. Calculate initial free space. Sum the outer sizes of all items on the line,
             //    and subtract this from the flex container’s inner main size. For frozen items,
@@ -520,18 +520,7 @@ impl Forest {
                 // a. Check for flexible items. If all the flex items on the line are frozen,
                 //    free space has been distributed; exit this loop.
 
-                let mut frozen: Vec<&mut FlexItem> = vec![];
-                let mut unfrozen: Vec<&mut FlexItem> = vec![];
-
-                line.items.iter_mut().for_each(|child| {
-                    if child.frozen {
-                        frozen.push(child);
-                    } else {
-                        unfrozen.push(child);
-                    }
-                });
-
-                if unfrozen.is_empty() {
+                if line.items.iter().all(|child| child.frozen) {
                     break;
                 }
 
@@ -541,13 +530,18 @@ impl Forest {
                 //    value is less than the magnitude of the remaining free space, use this
                 //    as the remaining free space.
 
-                let used_space: f32 = Iterator::chain(frozen.iter(), unfrozen.iter())
+                let used_space: f32 = line
+                    .items
+                    .iter()
                     .map(|child| {
                         child.margin.main(dir)
                             + if child.frozen { child.target_size.main(dir) } else { child.flex_basis }
                     })
                     .sum();
 
+                let mut unfrozen: sys::Vec<&mut FlexItem> =
+                    line.items.iter_mut().filter(|child| !child.frozen).collect();
+
                 let (sum_flex_grow, sum_flex_shrink): (f32, f32) =
                     unfrozen.iter().fold((0.0, 0.0), |(flex_grow, flex_shrink), item| {
                         let style = &self.nodes[item.node].style;
@@ -583,13 +577,13 @@ impl Forest {
 
                 if free_space.is_normal() {
                     if growing && sum_flex_grow > 0.0 {
-                        unfrozen.iter_mut().for_each(|child| {
+                        for child in &mut unfrozen {
                             child.target_size.set_main(
                                 dir,
                                 child.flex_basis
                                     + free_space * (self.nodes[child.node].style.flex_grow / sum_flex_grow),
                             );
-                        });
+                        }
                     } else if shrinking && sum_flex_shrink > 0.0 {
                         let sum_scaled_shrink_factor: f32 = unfrozen
                             .iter()
@@ -597,14 +591,14 @@ impl Forest {
                             .sum();
 
                         if sum_scaled_shrink_factor > 0.0 {
-                            unfrozen.iter_mut().for_each(|child| {
+                            for child in &mut unfrozen {
                                 let scaled_shrink_factor =
                                     child.inner_flex_basis * self.nodes[child.node].style.flex_shrink;
                                 child.target_size.set_main(
                                     dir,
                                     child.flex_basis + free_space * (scaled_shrink_factor / sum_scaled_shrink_factor),
                                 )
-                            });
+                            }
                         }
                     }
                 }
@@ -614,7 +608,7 @@ impl Forest {
                 //    item’s target main size was made smaller by this, it’s a max violation.
                 //    If the item’s target main size was made larger by this, it’s a min violation.
 
-                let total_violation = unfrozen.iter_mut().try_fold(0.0, |acc, child| -> Result<f32, Box<dyn Any>> {
+                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
                     // webkit handled various scenarios. Can probably be solved better by passing in
@@ -626,7 +620,7 @@ impl Forest {
                             Size { width: Undefined, height: Undefined },
                             available_space,
                             false,
-                        )?
+                        )
                         .size
                         .width
                         .maybe_min(child.size.width)
@@ -642,8 +636,8 @@ impl Forest {
                     child.target_size.set_main(dir, clamped);
                     child.outer_target_size.set_main(dir, child.target_size.main(dir) + child.margin.main(dir));
 
-                    Ok(acc + child.violation)
-                })?;
+                    acc + child.violation
+                });
 
                 // e. Freeze over-flexed items. The total violation is the sum of the adjustments
                 //    from the previous step ∑(clamped size - unclamped size). If the total violation is:
@@ -654,17 +648,17 @@ impl Forest {
                 //    - Negative
                 //        Freeze all the items with max violations.
 
-                unfrozen.iter_mut().for_each(|child| match total_violation {
-                    v if v > 0.0 => child.frozen = child.violation > 0.0,
-                    v if v < 0.0 => child.frozen = child.violation < 0.0,
-                    _ => child.frozen = true,
-                })
+                for child in &mut unfrozen {
+                    match total_violation {
+                        v if v > 0.0 => child.frozen = child.violation > 0.0,
+                        v if v < 0.0 => child.frozen = child.violation < 0.0,
+                        _ => child.frozen = true,
+                    }
+                }
 
                 // f. Return to the start of this loop.
             }
-
-            Ok(())
-        })?;
+        }
 
         // Not part of the spec from what i can see but seems correct
         container_size.set_main(
@@ -690,8 +684,8 @@ impl Forest {
         // 7. Determine the hypothetical cross size of each item by performing layout with the
         //    used main size and the available space, treating auto as fit-content.
 
-        flex_lines.iter_mut().try_for_each(|line| {
-            line.items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
+        for line in &mut flex_lines {
+            for child in line.items.iter_mut() {
                 let child_cross =
                     child.size.cross(dir).maybe_max(child.min_size.cross(dir)).maybe_min(child.max_size.cross(dir));
 
@@ -708,7 +702,7 @@ impl Forest {
                             height: if is_row { available_space.height } else { container_size.main(dir).to_number() },
                         },
                         false,
-                    )?
+                    )
                     .size
                     .cross(dir)
                     .maybe_max(child.min_size.cross(dir))
@@ -718,10 +712,8 @@ impl Forest {
                 child
                     .hypothetical_outer_size
                     .set_cross(dir, child.hypothetical_inner_size.cross(dir) + child.margin.cross(dir));
-
-                Ok(())
-            })
-        })?;
+            }
+        }
 
         // TODO - probably should move this somewhere else as it doesn't make a ton of sense here but we need it below
         // TODO - This is expensive and should only be done if we really require a baseline. aka, make it lazy
@@ -736,8 +728,8 @@ impl Forest {
         };
 
         if has_baseline_child {
-            flex_lines.iter_mut().try_for_each(|line| {
-                line.items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
+            for line in &mut flex_lines {
+                for child in line.items.iter_mut() {
                     let result = self.compute_internal(
                         child.node,
                         Size {
@@ -757,7 +749,7 @@ impl Forest {
                             height: if is_row { node_size.height } else { container_size.height.to_number() },
                         },
                         true,
-                    )?;
+                    );
 
                     child.baseline = calc_baseline(
                         self,
@@ -768,10 +760,8 @@ impl Forest {
                             location: Point { x: 0.0, y: 0.0 },
                         },
                     );
-
-                    Ok(())
-                })
-            })?;
+                }
+            }
         }
 
         // 8. Calculate the cross size of each flex line.
@@ -785,7 +775,7 @@ impl Forest {
         if flex_lines.len() == 1 && node_size.cross(dir).is_defined() {
             flex_lines[0].cross_size = (node_size.cross(dir) - padding_border.cross(dir)).or_else(0.0);
         } else {
-            flex_lines.iter_mut().for_each(|line| {
+            for line in &mut flex_lines {
                 //    1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose
                 //       align-self is baseline, and whose cross-axis margins are both non-auto. Find the
                 //       largest of the distances between each item’s baseline and its hypothetical outer
@@ -815,7 +805,7 @@ impl Forest {
                         }
                     })
                     .fold(0.0, |acc, x| acc.max(x));
-            });
+            }
         }
 
         // 9. Handle 'align-content: stretch'. If the flex container has a definite cross size,
@@ -862,10 +852,10 @@ impl Forest {
         //     Note that this step does not affect the main size of the flex item, even if it has an
         //     intrinsic aspect ratio.
 
-        flex_lines.iter_mut().for_each(|line| {
+        for line in &mut flex_lines {
             let line_cross_size = line.cross_size;
 
-            line.items.iter_mut().for_each(|child| {
+            for child in line.items.iter_mut() {
                 let child_style = &self.nodes[child.node].style;
                 child.target_size.set_cross(
                     dir,
@@ -883,8 +873,8 @@ impl Forest {
                 );
 
                 child.outer_target_size.set_cross(dir, child.target_size.cross(dir) + child.margin.cross(dir));
-            });
-        });
+            }
+        }
 
         // 9.5. Main-Axis Alignment
 
@@ -894,12 +884,12 @@ impl Forest {
         //        set all auto margins to zero.
         //     2. Align the items along the main-axis per justify-content.
 
-        flex_lines.iter_mut().for_each(|line| {
+        for line in &mut flex_lines {
             let used_space: f32 = line.items.iter().map(|child| child.outer_target_size.main(dir)).sum();
             let free_space = inner_container_size.main(dir) - used_space;
             let mut num_auto_margins = 0;
 
-            line.items.iter_mut().for_each(|child| {
+            for child in line.items.iter_mut() {
                 let child_style = &self.nodes[child.node].style;
                 if child_style.main_margin_start(dir) == Dimension::Auto {
                     num_auto_margins += 1;
@@ -907,12 +897,12 @@ impl Forest {
                 if child_style.main_margin_end(dir) == Dimension::Auto {
                     num_auto_margins += 1;
                 }
-            });
+            }
 
             if free_space > 0.0 && num_auto_margins > 0 {
                 let margin = free_space / num_auto_margins as f32;
 
-                line.items.iter_mut().for_each(|child| {
+                for child in line.items.iter_mut() {
                     let child_style = &self.nodes[child.node].style;
                     if child_style.main_margin_start(dir) == Dimension::Auto {
                         if is_row {
@@ -928,7 +918,7 @@ impl Forest {
                             child.margin.bottom = margin;
                         }
                     }
-                });
+                }
             } else {
                 let num_items = line.items.len();
                 let layout_reverse = dir.is_reverse();
@@ -982,7 +972,7 @@ impl Forest {
                     line.items.iter_mut().enumerate().for_each(justify_item);
                 }
             }
-        });
+        }
 
         // 9.6. Cross-Axis Alignment
 
@@ -994,11 +984,11 @@ impl Forest {
         //       is auto, set it to zero. Set the opposite margin so that the outer cross size of the
         //       item equals the cross size of its flex line.
 
-        flex_lines.iter_mut().for_each(|line| {
+        for line in &mut flex_lines {
             let line_cross_size = line.cross_size;
             let max_baseline: f32 = line.items.iter_mut().map(|child| child.baseline).fold(0.0, |acc, x| acc.max(x));
 
-            line.items.iter_mut().for_each(|child| {
+            for child in line.items.iter_mut() {
                 let free_space = line_cross_size - child.outer_target_size.cross(dir);
                 let child_style = &self.nodes[child.node].style;
 
@@ -1067,8 +1057,8 @@ impl Forest {
                         }
                     };
                 }
-            });
-        });
+            }
+        }
 
         // 15. Determine the flex container’s used cross size:
         //     - If the cross size property is a definite size, use that, clamped by the used
@@ -1086,7 +1076,7 @@ impl Forest {
             let result = ComputeResult { size: container_size };
             self.nodes[node].layout_cache =
                 Some(result::Cache { node_size, parent_size, perform_layout, result: result.clone() });
-            return Ok(result);
+            return result;
         }
 
         // 16. Align all flex lines per align-content.
@@ -1145,21 +1135,19 @@ impl Forest {
 
         // Do a final layout pass and gather the resulting layouts
         {
-            let mut lines: Vec<Vec<result::Layout>> = vec![];
             let mut total_offset_cross = padding_border.cross_start(dir);
 
-            let layout_line = |line: &mut FlexLine| -> Result<(), Box<dyn Any>> {
-                let mut children: Vec<result::Layout> = vec![];
+            let layout_line = |line: &mut FlexLine| {
                 let mut total_offset_main = padding_border.main_start(dir);
                 let line_offset_cross = line.offset_cross;
 
-                let layout_item = |child: &mut FlexItem| -> Result<(), Box<dyn Any>> {
+                let layout_item = |child: &mut FlexItem| {
                     let result = self.compute_internal(
                         child.node,
                         child.target_size.map(|s| s.to_number()),
                         container_size.map(|s| s.to_number()),
                         true,
-                    )?;
+                    );
 
                     let offset_main = total_offset_main
                         + child.offset_main
@@ -1182,31 +1170,21 @@ impl Forest {
                     };
 
                     total_offset_main += child.offset_main + child.margin.main(dir) + result.size.main(dir);
-
-                    Ok(())
                 };
 
                 if dir.is_reverse() {
-                    line.items.iter_mut().rev().try_for_each(layout_item)?;
+                    line.items.iter_mut().rev().for_each(layout_item);
                 } else {
-                    line.items.iter_mut().try_for_each(layout_item)?;
+                    line.items.iter_mut().for_each(layout_item);
                 }
 
                 total_offset_cross += line_offset_cross + line.cross_size;
-
-                if dir.is_reverse() {
-                    children.reverse();
-                }
-
-                lines.push(children);
-
-                Ok(())
             };
 
             if is_wrap_reverse {
-                flex_lines.iter_mut().rev().try_for_each(layout_line)?;
+                flex_lines.iter_mut().rev().for_each(layout_line);
             } else {
-                flex_lines.iter_mut().try_for_each(layout_line)?;
+                flex_lines.iter_mut().for_each(layout_line);
             }
         }
 
@@ -1218,7 +1196,7 @@ impl Forest {
                 .cloned()
                 .enumerate()
                 .filter(|(_, child)| self.nodes[*child].style.position_type == PositionType::Absolute)
-                .collect::<Vec<_>>();
+                .collect::<sys::Vec<_>>();
 
             for (order, child) in candidates {
                 let container_width = container_size.width.to_number();
@@ -1267,7 +1245,7 @@ impl Forest {
                     Size { width, height },
                     Size { width: container_width, height: container_height },
                     true,
-                )?;
+                );
 
                 let free_main_space = container_size.main(dir)
                     - result
@@ -1341,7 +1319,7 @@ impl Forest {
             }
         }
 
-        fn hidden_layout(nodes: &mut Vec<NodeData>, children: &[Vec<NodeId>], node: NodeId, order: u32) {
+        fn hidden_layout(nodes: &mut [NodeData], children: &[sys::ChildrenVec<NodeId>], node: NodeId, order: u32) {
             nodes[node].layout =
                 result::Layout { order, size: Size { width: 0.0, height: 0.0 }, location: Point { x: 0.0, y: 0.0 } };
 
@@ -1359,6 +1337,7 @@ impl Forest {
         let result = ComputeResult { size: container_size };
         self.nodes[node].layout_cache =
             Some(result::Cache { node_size, parent_size, perform_layout, result: result.clone() });
-        Ok(result)
+
+        result
     }
 }
diff --git a/src/forest.rs b/src/forest.rs
index fd5e542d8..f6d1d2779 100644
--- a/src/forest.rs
+++ b/src/forest.rs
@@ -1,17 +1,13 @@
 //! Forest - ECS like datastructure for storing node trees.
 //!
 //! Backing datastructure for `Stretch` structs.
-
-#[cfg(not(feature = "std"))]
-use alloc::vec::Vec;
-
 use crate::geometry::Size;
 use crate::id::NodeId;
 use crate::node::MeasureFunc;
 use crate::number::Number;
 use crate::result::{Cache, Layout};
 use crate::style::Style;
-use crate::Error;
+use crate::sys;
 
 pub(crate) struct NodeData {
     pub(crate) style: Style,
@@ -32,36 +28,36 @@ impl NodeData {
 }
 
 pub(crate) struct Forest {
-    pub(crate) nodes: Vec<NodeData>,
-    pub(crate) children: Vec<Vec<NodeId>>,
-    pub(crate) parents: Vec<Vec<NodeId>>,
+    pub(crate) nodes: sys::Vec<NodeData>,
+    pub(crate) children: sys::Vec<sys::ChildrenVec<NodeId>>,
+    pub(crate) parents: sys::Vec<sys::ParentsVec<NodeId>>,
 }
 
 impl Forest {
     pub fn with_capacity(capacity: usize) -> Self {
         Forest {
-            nodes: Vec::with_capacity(capacity),
-            children: Vec::with_capacity(capacity),
-            parents: Vec::with_capacity(capacity),
+            nodes: sys::new_vec_with_capacity(capacity),
+            children: sys::new_vec_with_capacity(capacity),
+            parents: sys::new_vec_with_capacity(capacity),
         }
     }
 
     pub fn new_leaf(&mut self, style: Style, measure: MeasureFunc) -> NodeId {
         let id = self.nodes.len();
         self.nodes.push(NodeData::new_leaf(style, measure));
-        self.children.push(Vec::with_capacity(0));
-        self.parents.push(Vec::with_capacity(1));
+        self.children.push(sys::new_vec_with_capacity(0));
+        self.parents.push(sys::new_vec_with_capacity(1));
         id
     }
 
-    pub fn new_node(&mut self, style: Style, children: Vec<NodeId>) -> NodeId {
+    pub fn new_node(&mut self, style: Style, children: sys::ChildrenVec<NodeId>) -> NodeId {
         let id = self.nodes.len();
         for child in &children {
             self.parents[*child].push(id);
         }
         self.nodes.push(NodeData::new(style));
         self.children.push(children);
-        self.parents.push(Vec::with_capacity(1));
+        self.parents.push(sys::new_vec_with_capacity(1));
         id
     }
 
@@ -159,7 +155,7 @@ impl Forest {
     }
 
     pub fn mark_dirty(&mut self, node: NodeId) {
-        fn mark_dirty_impl(nodes: &mut Vec<NodeData>, parents: &[Vec<NodeId>], node_id: NodeId) {
+        fn mark_dirty_impl(nodes: &mut sys::Vec<NodeData>, parents: &[sys::ParentsVec<NodeId>], node_id: NodeId) {
             let node = &mut nodes[node_id];
             node.layout_cache = None;
             node.is_dirty = true;
@@ -172,7 +168,7 @@ impl Forest {
         mark_dirty_impl(&mut self.nodes, &self.parents, node);
     }
 
-    pub fn compute_layout(&mut self, node: NodeId, size: Size<Number>) -> Result<(), Error> {
-        self.compute(node, size).map_err(|err| Error::Measure(err))
+    pub fn compute_layout(&mut self, node: NodeId, size: Size<Number>) {
+        self.compute(node, size)
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 226ce569e..5ecab2f1c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,9 +1,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
-#[cfg(not(feature = "std"))]
-extern crate alloc;
 
-#[cfg(not(feature = "std"))]
-use alloc::boxed::Box;
+#[cfg(all(not(feature = "std"), feature = "alloc"))]
+extern crate alloc;
 
 #[macro_use]
 extern crate lazy_static;
@@ -23,14 +21,12 @@ mod forest;
 mod id;
 
 mod sys;
-pub use crate::node::Stretch;
 
-use core::any::Any;
+pub use crate::node::Stretch;
 
 #[derive(Debug)]
 pub enum Error {
     InvalidNode(node::Node),
-    Measure(Box<dyn Any>),
 }
 
 #[cfg(feature = "std")]
@@ -38,7 +34,6 @@ impl std::fmt::Display for Error {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         match *self {
             Error::InvalidNode(ref node) => write!(f, "Invalid node {:?}", node),
-            Error::Measure(_) => write!(f, "Error during measurement"),
         }
     }
 }
@@ -48,7 +43,6 @@ impl std::error::Error for Error {
     fn description(&self) -> &str {
         match *self {
             Error::InvalidNode(_) => "The node is not part of the stretch instance",
-            Error::Measure(_) => "Error occurred inside a measurement function",
         }
     }
 }
diff --git a/src/node.rs b/src/node.rs
index 7f3693712..566de55c4 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -1,11 +1,3 @@
-#[cfg(not(feature = "std"))]
-use alloc::{boxed::Box, vec::Vec};
-#[cfg(not(feature = "std"))]
-use hashbrown::HashMap;
-#[cfg(feature = "std")]
-use std::collections::HashMap;
-
-use core::any::Any;
 use core::ops::Drop;
 
 use crate::forest::Forest;
@@ -14,9 +6,10 @@ use crate::id::{self, NodeId};
 use crate::number::Number;
 use crate::result::Layout;
 use crate::style::*;
+use crate::sys;
 use crate::Error;
 
-pub type MeasureFunc = Box<dyn Fn(Size<Number>) -> Result<Size<f32>, Box<dyn Any>>>;
+pub type MeasureFunc = fn(Size<Number>) -> Size<f32>;
 
 lazy_static! {
     /// Global stretch instance id allocator.
@@ -24,6 +17,7 @@ lazy_static! {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(not(any(feature = "std", feature = "alloc")), derive(hash32_derive::Hash32))]
 pub struct Node {
     instance: id::Id,
     local: id::Id,
@@ -32,8 +26,8 @@ pub struct Node {
 pub struct Stretch {
     id: id::Id,
     nodes: id::Allocator,
-    nodes_to_ids: HashMap<Node, NodeId>,
-    ids_to_nodes: HashMap<NodeId, Node>,
+    nodes_to_ids: crate::sys::Map<Node, NodeId>,
+    ids_to_nodes: crate::sys::Map<NodeId, Node>,
     forest: Forest,
 }
 
@@ -52,8 +46,8 @@ impl Stretch {
         Stretch {
             id: INSTANCE_ALLOCATOR.allocate(),
             nodes: id::Allocator::new(),
-            nodes_to_ids: HashMap::with_capacity(capacity),
-            ids_to_nodes: HashMap::with_capacity(capacity),
+            nodes_to_ids: crate::sys::new_map_with_capacity(capacity),
+            ids_to_nodes: crate::sys::new_map_with_capacity(capacity),
             forest: Forest::with_capacity(capacity),
         }
     }
@@ -64,8 +58,8 @@ impl Stretch {
     }
 
     fn add_node(&mut self, node: Node, id: NodeId) {
-        self.nodes_to_ids.insert(node, id);
-        self.ids_to_nodes.insert(id, node);
+        let _ = self.nodes_to_ids.insert(node, id);
+        let _ = self.ids_to_nodes.insert(id, node);
     }
 
     // Find node in the forest.
@@ -83,9 +77,10 @@ impl Stretch {
         Ok(node)
     }
 
-    pub fn new_node(&mut self, style: Style, children: Vec<Node>) -> Result<Node, Error> {
+    pub fn new_node(&mut self, style: Style, children: &[Node]) -> Result<Node, Error> {
         let node = self.allocate_node();
-        let children = children.iter().map(|child| self.find_node(*child)).collect::<Result<Vec<_>, Error>>()?;
+        let children =
+            children.iter().map(|child| self.find_node(*child)).collect::<Result<sys::ChildrenVec<_>, Error>>()?;
         let id = self.forest.new_node(style, children);
         self.add_node(node, id);
         Ok(node)
@@ -112,8 +107,8 @@ impl Stretch {
 
         if let Some(new_id) = self.forest.swap_remove(id) {
             let new = self.ids_to_nodes.remove(&new_id).unwrap();
-            self.nodes_to_ids.insert(new, id);
-            self.ids_to_nodes.insert(id, new);
+            let _ = self.nodes_to_ids.insert(new, id);
+            let _ = self.ids_to_nodes.insert(id, new);
         }
     }
 
@@ -132,9 +127,10 @@ impl Stretch {
         Ok(())
     }
 
-    pub fn set_children(&mut self, node: Node, children: Vec<Node>) -> Result<(), Error> {
+    pub fn set_children(&mut self, node: Node, children: &[Node]) -> Result<(), Error> {
         let node_id = self.find_node(node)?;
-        let children_id = children.iter().map(|child| self.find_node(*child)).collect::<Result<Vec<_>, _>>()?;
+        let children_id =
+            children.iter().map(|child| self.find_node(*child)).collect::<Result<sys::ChildrenVec<_>, _>>()?;
 
         // Remove node as parent from all its current children.
         for child in &self.forest.children[node_id] {
@@ -181,7 +177,7 @@ impl Stretch {
         Ok(self.ids_to_nodes[&old_child])
     }
 
-    pub fn children(&self, node: Node) -> Result<Vec<Node>, Error> {
+    pub fn children(&self, node: Node) -> Result<sys::Vec<Node>, Error> {
         let id = self.find_node(node)?;
         Ok(self.forest.children[id].iter().map(|child| self.ids_to_nodes[child]).collect())
     }
@@ -226,7 +222,8 @@ impl Stretch {
 
     pub fn compute_layout(&mut self, node: Node, size: Size<Number>) -> Result<(), Error> {
         let id = self.find_node(node)?;
-        self.forest.compute_layout(id, size)
+        self.forest.compute_layout(id, size);
+        Ok(())
     }
 }