Repository: cashapp/redwood
Pull request #399 (2022-09-27 22:43:18)

Renames Direction -> Orientation, Node -> FlexNode.


Patch:
diff --git a/redwood-flexbox-engine/build.gradle b/redwood-flexbox-engine/build.gradle
index 5dfea48d8..01029a2e3 100644
--- a/redwood-flexbox-engine/build.gradle
+++ b/redwood-flexbox-engine/build.gradle
@@ -20,7 +20,7 @@ spotless {
       // Apache 2-licensed files from Google.
       "src/commonMain/kotlin/app/cash/redwood/flexbox/FlexboxEngine.kt",
       "src/commonMain/kotlin/app/cash/redwood/flexbox/FlexLine.kt",
-      "src/commonMain/kotlin/app/cash/redwood/flexbox/Node.kt",
+      "src/commonMain/kotlin/app/cash/redwood/flexbox/FlexNode.kt",
       "src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxEngineTest.kt",
     )
   }
diff --git a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Direction.kt b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Direction.kt
deleted file mode 100644
index 1c03be998..000000000
--- a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Direction.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2022 Square, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package app.cash.redwood.flexbox
-
-internal fun FlexDirection.toDirection(): Direction {
-  if (this == FlexDirection.Row || this == FlexDirection.RowReverse) {
-    return Direction.Horizontal
-  } else {
-    return Direction.Vertical
-  }
-}
-
-/**
- * An interface to perform operations along the main/cross axis without knowledge
- * of the underlying [FlexDirection].
- */
-internal sealed interface Direction {
-  fun mainPaddingStart(padding: Spacing): Int
-  fun mainPaddingEnd(padding: Spacing): Int
-  fun crossPaddingStart(padding: Spacing): Int
-  fun crossPaddingEnd(padding: Spacing): Int
-
-  fun mainSize(node: Node): Int
-  fun crossSize(node: Node): Int
-  fun mainMeasuredSize(node: Node): Int
-  fun crossMeasuredSize(node: Node): Int
-
-  fun mainMarginStart(node: Node): Int
-  fun mainMarginEnd(node: Node): Int
-  fun crossMarginStart(node: Node): Int
-  fun crossMarginEnd(node: Node): Int
-
-  object Horizontal : Direction {
-    override fun mainPaddingStart(padding: Spacing) = padding.start
-    override fun mainPaddingEnd(padding: Spacing) = padding.end
-    override fun crossPaddingStart(padding: Spacing) = padding.top
-    override fun crossPaddingEnd(padding: Spacing) = padding.bottom
-    override fun mainSize(node: Node) = node.measurable.width
-    override fun crossSize(node: Node) = node.measurable.height
-    override fun mainMeasuredSize(node: Node) = node.measuredWidth
-    override fun crossMeasuredSize(node: Node) = node.measuredHeight
-    override fun mainMarginStart(node: Node) = node.margin.start
-    override fun mainMarginEnd(node: Node) = node.margin.end
-    override fun crossMarginStart(node: Node) = node.margin.top
-    override fun crossMarginEnd(node: Node) = node.margin.bottom
-  }
-
-  object Vertical : Direction {
-    override fun mainPaddingStart(padding: Spacing) = padding.top
-    override fun mainPaddingEnd(padding: Spacing) = padding.bottom
-    override fun crossPaddingStart(padding: Spacing) = padding.start
-    override fun crossPaddingEnd(padding: Spacing) = padding.end
-    override fun mainSize(node: Node) = node.measurable.height
-    override fun crossSize(node: Node) = node.measurable.width
-    override fun mainMeasuredSize(node: Node) = node.measuredHeight
-    override fun crossMeasuredSize(node: Node) = node.measuredWidth
-    override fun mainMarginStart(node: Node) = node.margin.top
-    override fun mainMarginEnd(node: Node) = node.margin.bottom
-    override fun crossMarginStart(node: Node) = node.margin.start
-    override fun crossMarginEnd(node: Node) = node.margin.end
-  }
-}
diff --git a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexLine.kt b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexLine.kt
index d08174bcd..38023ae24 100644
--- a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexLine.kt
+++ b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexLine.kt
@@ -80,14 +80,14 @@ internal class FlexLine {
   @JvmField var lastIndex = 0
 
   /**
-   * Set to true if any [Node]s in this line have [Node.flexGrow] attributes set
-   * (i.e. have a value other than [Node.DefaultFlexGrow]).
+   * Set to true if any [FlexNode]s in this line have [FlexNode.flexGrow] attributes set
+   * (i.e. have a value other than [FlexNode.DefaultFlexGrow]).
    */
   @JvmField var anyItemsHaveFlexGrow = false
 
   /**
-   * Set to true if any [Node]s in this line have [Node.flexShrink] attributes set
-   * (i.e. have a value other than [Node.UndefinedFlexShrink]).
+   * Set to true if any [FlexNode]s in this line have [FlexNode.flexShrink] attributes set
+   * (i.e. have a value other than [FlexNode.UndefinedFlexShrink]).
    */
   @JvmField var anyItemsHaveFlexShrink = false
 }
diff --git a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Node.kt b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexNode.kt
similarity index 99%
rename from redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Node.kt
rename to redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexNode.kt
index b931c64b7..2f4dc3ad1 100644
--- a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Node.kt
+++ b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexNode.kt
@@ -18,7 +18,7 @@ package app.cash.redwood.flexbox
 /**
  * A node with properties that can be measured and laid out inside a flexbox.
  */
-public class Node(
+public class FlexNode(
 
   /**
    * True if this item is visible and should be laid out.
diff --git a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexboxEngine.kt b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexboxEngine.kt
index ac0c29b8f..e988237a5 100644
--- a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexboxEngine.kt
+++ b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/FlexboxEngine.kt
@@ -17,10 +17,10 @@
 
 package app.cash.redwood.flexbox
 
+import app.cash.redwood.flexbox.FlexNode.Companion.DefaultFlexBasisPercent
+import app.cash.redwood.flexbox.FlexNode.Companion.DefaultFlexGrow
+import app.cash.redwood.flexbox.FlexNode.Companion.UndefinedFlexShrink
 import app.cash.redwood.flexbox.Measurable.Companion.MatchParent
-import app.cash.redwood.flexbox.Node.Companion.DefaultFlexBasisPercent
-import app.cash.redwood.flexbox.Node.Companion.DefaultFlexGrow
-import app.cash.redwood.flexbox.Node.Companion.UndefinedFlexShrink
 import kotlin.math.roundToInt
 
 /**
@@ -66,7 +66,7 @@ public class FlexboxEngine {
   /**
    * Returns the nodes contained in the flexbox.
    */
-  public val nodes: MutableList<Node> = ObservableMutableList(
+  public val nodes: MutableList<FlexNode> = ObservableMutableList(
     onChange = { indexToReorderedIndex = null },
   )
 
@@ -76,7 +76,7 @@ public class FlexboxEngine {
   internal var flexLines = listOf<FlexLine>()
 
   /**
-   * Holds the reordered indices after [Node.order] has been taken into account.
+   * Holds the reordered indices after [FlexNode.order] has been taken into account.
    */
   private var indexToReorderedIndex: IntArray? = null
 
@@ -179,7 +179,7 @@ public class FlexboxEngine {
     fromIndex: Int,
     toIndex: Int,
   ): List<FlexLine> {
-    val direction = flexDirection.toDirection()
+    val orientation = flexDirection.toOrientation()
     val mainMode = mainMeasureSpec.mode
     val mainSize = mainMeasureSpec.size
     val flexLines = mutableListOf<FlexLine>()
@@ -193,7 +193,7 @@ public class FlexboxEngine {
     var indexInFlexLine = 0
     var flexLine = FlexLine()
     flexLine.firstIndex = fromIndex
-    flexLine.mainSize = direction.mainPaddingStart(padding) + direction.mainPaddingEnd(padding)
+    flexLine.mainSize = orientation.mainPaddingStart(padding) + orientation.mainPaddingEnd(padding)
     val childCount = nodes.size
     for (i in fromIndex until childCount) {
       val child = getReorderedChildAt(i)
@@ -213,7 +213,7 @@ public class FlexboxEngine {
       if (child.alignSelf == AlignSelf.Stretch) {
         flexLine.indicesAlignSelfStretch += i
       }
-      var childMainSize = direction.mainSize(child)
+      var childMainSize = orientation.mainSize(child)
       if (child.flexBasisPercent != DefaultFlexBasisPercent && mainMode == MeasureSpecMode.Exactly) {
         childMainSize = (mainSize * child.flexBasisPercent).roundToInt()
         // Use the dimension from the layout if the mainMode is not
@@ -222,32 +222,32 @@ public class FlexboxEngine {
       }
       var childMainMeasureSpec: MeasureSpec
       var childCrossMeasureSpec: MeasureSpec
-      if (direction == Direction.Horizontal) {
+      if (orientation == Orientation.Horizontal) {
         childMainMeasureSpec = MeasureSpec.getChildMeasureSpec(
           spec = mainMeasureSpec,
-          padding = direction.mainPaddingStart(padding) + direction.mainPaddingEnd(padding) +
-            direction.mainMarginStart(child) + direction.mainMarginEnd(child),
+          padding = orientation.mainPaddingStart(padding) + orientation.mainPaddingEnd(padding) +
+            orientation.mainMarginStart(child) + orientation.mainMarginEnd(child),
           childDimension = childMainSize,
         )
         childCrossMeasureSpec = MeasureSpec.getChildMeasureSpec(
           spec = crossMeasureSpec,
-          padding = direction.crossPaddingStart(padding) + direction.crossPaddingEnd(padding) +
-            direction.crossMarginStart(child) + direction.crossMarginEnd(child) + sumCrossSize,
-          childDimension = direction.crossSize(child),
+          padding = orientation.crossPaddingStart(padding) + orientation.crossPaddingEnd(padding) +
+            orientation.crossMarginStart(child) + orientation.crossMarginEnd(child) + sumCrossSize,
+          childDimension = orientation.crossSize(child),
         )
         child.applyMeasure(childMainMeasureSpec, childCrossMeasureSpec)
         updateMeasureCache(i, childMainMeasureSpec, childCrossMeasureSpec, child)
       } else {
         childCrossMeasureSpec = MeasureSpec.getChildMeasureSpec(
           spec = crossMeasureSpec,
-          padding = direction.crossPaddingStart(padding) + direction.crossPaddingEnd(padding) +
-            direction.crossMarginStart(child) + direction.crossMarginEnd(child) + sumCrossSize,
-          childDimension = direction.crossSize(child),
+          padding = orientation.crossPaddingStart(padding) + orientation.crossPaddingEnd(padding) +
+            orientation.crossMarginStart(child) + orientation.crossMarginEnd(child) + sumCrossSize,
+          childDimension = orientation.crossSize(child),
         )
         childMainMeasureSpec = MeasureSpec.getChildMeasureSpec(
           spec = mainMeasureSpec,
-          padding = direction.mainPaddingStart(padding) + direction.mainPaddingEnd(padding) +
-            direction.mainMarginStart(child) + direction.mainMarginEnd(child),
+          padding = orientation.mainPaddingStart(padding) + orientation.mainPaddingEnd(padding) +
+            orientation.mainMarginStart(child) + orientation.mainMarginEnd(child),
           childDimension = childMainSize,
         )
         child.applyMeasure(childCrossMeasureSpec, childMainMeasureSpec)
@@ -264,7 +264,7 @@ public class FlexboxEngine {
           mode = mainMode,
           maxSize = mainSize,
           currentLength = flexLine.mainSize,
-          childLength = direction.mainMeasuredSize(child) + direction.mainMarginStart(child) + direction.mainMarginEnd(child),
+          childLength = orientation.mainMeasuredSize(child) + orientation.mainMarginStart(child) + orientation.mainMarginEnd(child),
           flexItem = child,
           flexLinesSize = flexLines.size,
         )
@@ -274,7 +274,7 @@ public class FlexboxEngine {
           sumCrossSize += flexLine.crossSize
         }
         val measurable = child.measurable
-        if (direction == Direction.Horizontal) {
+        if (orientation == Orientation.Horizontal) {
           val height = measurable.height
           if (height == MatchParent) {
             // This case takes care of the corner case where the cross size of the
@@ -313,7 +313,7 @@ public class FlexboxEngine {
         }
         flexLine = FlexLine()
         flexLine.itemCount = 1
-        flexLine.mainSize = direction.mainPaddingStart(padding) + direction.mainPaddingEnd(padding)
+        flexLine.mainSize = orientation.mainPaddingStart(padding) + orientation.mainPaddingEnd(padding)
         flexLine.firstIndex = i
         indexInFlexLine = 0
         largestSizeInCross = Int.MIN_VALUE
@@ -326,18 +326,18 @@ public class FlexboxEngine {
       if (indexToFlexLine != null) {
         indexToFlexLine!![i] = flexLines.size
       }
-      flexLine.mainSize += direction.mainMeasuredSize(child) + direction.mainMarginStart(child) + direction.mainMarginEnd(child)
+      flexLine.mainSize += orientation.mainMeasuredSize(child) + orientation.mainMarginStart(child) + orientation.mainMarginEnd(child)
       flexLine.totalFlexGrow += child.flexGrow
       flexLine.totalFlexShrink += child.flexShrink
       largestSizeInCross = maxOf(
         largestSizeInCross,
-        direction.crossMeasuredSize(child) + direction.crossMarginStart(child) + direction.crossMarginEnd(child)
+        orientation.crossMeasuredSize(child) + orientation.crossMarginStart(child) + orientation.crossMarginEnd(child)
       )
       // Temporarily set the cross axis length as the largest child in the flexLine
       // Expand along the cross axis depending on the alignContent property if needed
       // later
       flexLine.crossSize = maxOf(flexLine.crossSize, largestSizeInCross)
-      if (direction == Direction.Horizontal) {
+      if (orientation == Orientation.Horizontal) {
         if (flexWrap != FlexWrap.WrapReverse) {
           flexLine.maxBaseline = maxOf(
             flexLine.maxBaseline,
@@ -397,7 +397,7 @@ public class FlexboxEngine {
     maxSize: Int,
     currentLength: Int,
     childLength: Int,
-    flexItem: Node,
+    flexItem: FlexNode,
     flexLinesSize: Int,
   ): Boolean {
     if (flexWrap == FlexWrap.NoWrap) {
@@ -435,10 +435,10 @@ public class FlexboxEngine {
   }
 
   /**
-   * Remeasures the node if its [Node.measuredWidth] or [Node.measuredHeight] violate the
+   * Remeasures the node if its [FlexNode.measuredWidth] or [FlexNode.measuredHeight] violate the
    * minimum/maximum size constraints imposed by its min/max attributes.
    */
-  private fun measureWithConstraints(node: Node, index: Int) {
+  private fun measureWithConstraints(node: FlexNode, index: Int) {
     var needsMeasure = false
     var childWidth = node.measuredWidth
     var childHeight = node.measuredHeight
@@ -559,7 +559,7 @@ public class FlexboxEngine {
   }
 
   /**
-   * Expand the flex items along the main axis based on the individual [Node.flexGrow] attribute.
+   * Expand the flex items along the main axis based on the individual [FlexNode.flexGrow] attribute.
    *
    * @param widthMeasureSpec the horizontal space requirements as imposed by the parent
    * @param heightMeasureSpec the vertical space requirements as imposed by the parent
@@ -745,7 +745,7 @@ public class FlexboxEngine {
   }
 
   /**
-   * Shrink the flex items along the main axis based on the individual [Node.flexShrink] attribute.
+   * Shrink the flex items along the main axis based on the individual [FlexNode.flexShrink] attribute.
    *
    * @param widthMeasureSpec the horizontal space requirements as imposed by the parent
    * @param heightMeasureSpec the vertical space requirements as imposed by the parent
@@ -930,7 +930,7 @@ public class FlexboxEngine {
 
   private fun getChildWidthMeasureSpecInternal(
     widthMeasureSpec: MeasureSpec,
-    flexItem: Node,
+    flexItem: FlexNode,
     padding: Int,
   ): MeasureSpec {
     val measurable = flexItem.measurable
@@ -953,7 +953,7 @@ public class FlexboxEngine {
 
   private fun getChildHeightMeasureSpecInternal(
     heightMeasureSpec: MeasureSpec,
-    flexItem: Node,
+    flexItem: FlexNode,
     padding: Int,
   ): MeasureSpec {
     val measurable = flexItem.measurable
@@ -1148,7 +1148,7 @@ public class FlexboxEngine {
 
   /**
    * Expand the node if the [FlexboxEngine.alignItems] attribute is set to
-   * [AlignItems.Stretch] or [Node.alignSelf] is set as [AlignItems.Stretch].
+   * [AlignItems.Stretch] or [FlexNode.alignSelf] is set as [AlignItems.Stretch].
    *
    * @param fromIndex the index from which value, stretch is calculated
    */
@@ -1224,7 +1224,7 @@ public class FlexboxEngine {
   /**
    * Expand the node vertically to the size of the [crossSize] (considering [node]'s margins).
    */
-  private fun stretchViewVertically(node: Node, crossSize: Int, index: Int) {
+  private fun stretchViewVertically(node: FlexNode, crossSize: Int, index: Int) {
     val measurable = node.measurable
     val newHeight = (crossSize - node.margin.top - node.margin.bottom)
       .coerceIn(measurable.minHeight, measurable.maxHeight)
@@ -1247,7 +1247,7 @@ public class FlexboxEngine {
   /**
    * Expand the node horizontally to the size of the crossSize (considering [node]'s margins).
    */
-  private fun stretchViewHorizontally(node: Node, crossSize: Int, index: Int) {
+  private fun stretchViewHorizontally(node: FlexNode, crossSize: Int, index: Int) {
     val measurable = node.measurable
     val newWidth = (crossSize - node.margin.start - node.margin.end)
       .coerceIn(measurable.minWidth, measurable.maxWidth)
@@ -1272,7 +1272,7 @@ public class FlexboxEngine {
    * ([FlexboxEngine.flexDirection] is either [FlexDirection.Row] or [FlexDirection.RowReverse]).
    */
   private fun layoutSingleChildHorizontal(
-    node: Node,
+    node: FlexNode,
     flexLine: FlexLine,
     left: Int,
     top: Int,
@@ -1342,7 +1342,7 @@ public class FlexboxEngine {
    * ([FlexboxEngine.flexDirection] is either [FlexDirection.Column] or [FlexDirection.ColumnReverse]).
    */
   private fun layoutSingleChildVertical(
-    node: Node,
+    node: FlexNode,
     flexLine: FlexLine,
     isRtl: Boolean,
     left: Int,
@@ -1405,7 +1405,7 @@ public class FlexboxEngine {
     index: Int,
     widthMeasureSpec: MeasureSpec,
     heightMeasureSpec: MeasureSpec,
-    node: Node,
+    node: FlexNode,
   ) {
     measureSpecCache?.let { cache ->
       cache[index] = packLong(widthMeasureSpec.value, heightMeasureSpec.value)
@@ -1870,9 +1870,9 @@ public class FlexboxEngine {
   }
 
   /**
-   * Returns a node, which is reordered by taking into account [Node.order].
+   * Returns a node, which is reordered by taking into account [FlexNode.order].
    */
-  private fun getReorderedChildAt(index: Int): Node? {
+  private fun getReorderedChildAt(index: Int): FlexNode? {
     if (indexToReorderedIndex == null) {
       val sorted = nodes.withIndex().sortedWith(compareBy({ -it.value.order }, { it.index }))
       val indexes = IntArray(sorted.size)
@@ -1885,10 +1885,10 @@ public class FlexboxEngine {
   }
 
   /**
-   * Call [Measurable.measure] and update [Node.measuredWidth] and [Node.measuredHeight] with the
+   * Call [Measurable.measure] and update [FlexNode.measuredWidth] and [FlexNode.measuredHeight] with the
    * result.
    */
-  private fun Node.applyMeasure(widthSpec: MeasureSpec, heightSpec: MeasureSpec) {
+  private fun FlexNode.applyMeasure(widthSpec: MeasureSpec, heightSpec: MeasureSpec) {
     val size = measurable.measure(widthSpec, heightSpec)
     this.measuredWidth = size.width
     this.measuredHeight = size.height
diff --git a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Orientation.kt b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Orientation.kt
new file mode 100644
index 000000000..4d12e8d1c
--- /dev/null
+++ b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/Orientation.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package app.cash.redwood.flexbox
+
+internal fun FlexDirection.toOrientation(): Orientation {
+  if (this == FlexDirection.Row || this == FlexDirection.RowReverse) {
+    return Orientation.Horizontal
+  } else {
+    return Orientation.Vertical
+  }
+}
+
+/**
+ * An interface to perform operations along the main/cross axis without knowledge
+ * of the underlying [FlexDirection].
+ */
+internal sealed interface Orientation {
+  fun mainPaddingStart(padding: Spacing): Int
+  fun mainPaddingEnd(padding: Spacing): Int
+  fun crossPaddingStart(padding: Spacing): Int
+  fun crossPaddingEnd(padding: Spacing): Int
+
+  fun mainSize(node: FlexNode): Int
+  fun crossSize(node: FlexNode): Int
+  fun mainMeasuredSize(node: FlexNode): Int
+  fun crossMeasuredSize(node: FlexNode): Int
+
+  fun mainMarginStart(node: FlexNode): Int
+  fun mainMarginEnd(node: FlexNode): Int
+  fun crossMarginStart(node: FlexNode): Int
+  fun crossMarginEnd(node: FlexNode): Int
+
+  object Horizontal : Orientation {
+    override fun mainPaddingStart(padding: Spacing) = padding.start
+    override fun mainPaddingEnd(padding: Spacing) = padding.end
+    override fun crossPaddingStart(padding: Spacing) = padding.top
+    override fun crossPaddingEnd(padding: Spacing) = padding.bottom
+    override fun mainSize(node: FlexNode) = node.measurable.width
+    override fun crossSize(node: FlexNode) = node.measurable.height
+    override fun mainMeasuredSize(node: FlexNode) = node.measuredWidth
+    override fun crossMeasuredSize(node: FlexNode) = node.measuredHeight
+    override fun mainMarginStart(node: FlexNode) = node.margin.start
+    override fun mainMarginEnd(node: FlexNode) = node.margin.end
+    override fun crossMarginStart(node: FlexNode) = node.margin.top
+    override fun crossMarginEnd(node: FlexNode) = node.margin.bottom
+  }
+
+  object Vertical : Orientation {
+    override fun mainPaddingStart(padding: Spacing) = padding.top
+    override fun mainPaddingEnd(padding: Spacing) = padding.bottom
+    override fun crossPaddingStart(padding: Spacing) = padding.start
+    override fun crossPaddingEnd(padding: Spacing) = padding.end
+    override fun mainSize(node: FlexNode) = node.measurable.height
+    override fun crossSize(node: FlexNode) = node.measurable.width
+    override fun mainMeasuredSize(node: FlexNode) = node.measuredHeight
+    override fun crossMeasuredSize(node: FlexNode) = node.measuredWidth
+    override fun mainMarginStart(node: FlexNode) = node.margin.top
+    override fun mainMarginEnd(node: FlexNode) = node.margin.bottom
+    override fun crossMarginStart(node: FlexNode) = node.margin.start
+    override fun crossMarginEnd(node: FlexNode) = node.margin.end
+  }
+}
diff --git a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/utils.kt b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/utils.kt
index 24d1918cf..2f33e710e 100644
--- a/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/utils.kt
+++ b/redwood-flexbox-engine/src/commonMain/kotlin/app/cash/redwood/flexbox/utils.kt
@@ -32,7 +32,7 @@ internal fun unpackHigher(value: Long): Int {
 
 /** Convenience function to use named arguments. */
 @Suppress("EXTENSION_FUNCTION_SHADOWED_BY_MEMBER_PROPERTY_WITH_INVOKE")
-internal inline fun Node.layout(left: Int, top: Int, right: Int, bottom: Int) {
+internal inline fun FlexNode.layout(left: Int, top: Int, right: Int, bottom: Int) {
   layout(left, top, right, bottom)
 }
 


Test patch:
diff --git a/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxEngineTest.kt b/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxEngineTest.kt
index beb15eea1..ecbe504cb 100644
--- a/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxEngineTest.kt
+++ b/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxEngineTest.kt
@@ -31,10 +31,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testCalculateHorizontalFlexLines() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100))
-    val node2 = Node(measurable = BoxMeasurable(200, 100))
-    val node3 = Node(measurable = BoxMeasurable(300, 100))
-    val node4 = Node(measurable = BoxMeasurable(400, 100))
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(200, 100))
+    val node3 = FlexNode(measurable = BoxMeasurable(300, 100))
+    val node4 = FlexNode(measurable = BoxMeasurable(400, 100))
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -73,10 +73,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testCalculateVerticalFlexLines() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100))
-    val node2 = Node(measurable = BoxMeasurable(100, 200))
-    val node3 = Node(measurable = BoxMeasurable(100, 300))
-    val node4 = Node(measurable = BoxMeasurable(100, 400))
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(100, 200))
+    val node3 = FlexNode(measurable = BoxMeasurable(100, 300))
+    val node4 = FlexNode(measurable = BoxMeasurable(100, 400))
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -116,10 +116,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineMainSize_direction_row_flexGrowSet() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100))
-    val node2 = Node(measurable = BoxMeasurable(200, 100), flexGrow = 1.0f)
-    val node3 = Node(measurable = BoxMeasurable(300, 100))
-    val node4 = Node(measurable = BoxMeasurable(400, 100), flexGrow = 2.0f)
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(200, 100), flexGrow = 1.0f)
+    val node3 = FlexNode(measurable = BoxMeasurable(300, 100))
+    val node4 = FlexNode(measurable = BoxMeasurable(400, 100), flexGrow = 2.0f)
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -145,10 +145,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineMainSize_direction_column_flexGrowSet() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100))
-    val node2 = Node(measurable = BoxMeasurable(100, 200), flexGrow = 1.0f)
-    val node3 = Node(measurable = BoxMeasurable(100, 300))
-    val node4 = Node(measurable = BoxMeasurable(100, 400), flexGrow = 2.0f)
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(100, 200), flexGrow = 1.0f)
+    val node3 = FlexNode(measurable = BoxMeasurable(100, 300))
+    val node4 = FlexNode(measurable = BoxMeasurable(100, 400), flexGrow = 2.0f)
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -174,10 +174,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineMainSize_direction_row_flexShrinkSet() {
-    val node1 = Node(measurable = BoxMeasurable(200, 100))
-    val node2 = Node(measurable = BoxMeasurable(200, 100))
-    val node3 = Node(measurable = BoxMeasurable(200, 100))
-    val node4 = Node(measurable = BoxMeasurable(200, 100))
+    val node1 = FlexNode(measurable = BoxMeasurable(200, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(200, 100))
+    val node3 = FlexNode(measurable = BoxMeasurable(200, 100))
+    val node4 = FlexNode(measurable = BoxMeasurable(200, 100))
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -203,10 +203,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineMainSize_direction_column_flexShrinkSet() {
-    val node1 = Node(measurable = BoxMeasurable(100, 200))
-    val node2 = Node(measurable = BoxMeasurable(100, 200))
-    val node3 = Node(measurable = BoxMeasurable(100, 200))
-    val node4 = Node(measurable = BoxMeasurable(100, 200))
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 200))
+    val node2 = FlexNode(measurable = BoxMeasurable(100, 200))
+    val node3 = FlexNode(measurable = BoxMeasurable(100, 200))
+    val node4 = FlexNode(measurable = BoxMeasurable(100, 200))
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -232,8 +232,8 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineMainSize_directionRow_fixedSizeViewAndShrinkable_doNotExceedMaxMainSize() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100), flexShrink = 0f)
-    val node2 = Node(measurable = BoxMeasurable(2000, 2000)) // simulate a very long text view
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100), flexShrink = 0f)
+    val node2 = FlexNode(measurable = BoxMeasurable(2000, 2000)) // simulate a very long text view
     engine.nodes += node1
     engine.nodes += node2
     engine.flexWrap = FlexWrap.NoWrap
@@ -250,9 +250,9 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineMainSize_directionRow_twoFixedSizeViewsAndShrinkable_doNotExceedMaxMainSize() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100), flexShrink = 0f)
-    val node2 = Node(measurable = BoxMeasurable(2000, 2000)) // simulate a very long text view
-    val node3 = Node(measurable = BoxMeasurable(100, 100), flexShrink = 0f)
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100), flexShrink = 0f)
+    val node2 = FlexNode(measurable = BoxMeasurable(2000, 2000)) // simulate a very long text view
+    val node3 = FlexNode(measurable = BoxMeasurable(100, 100), flexShrink = 0f)
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -271,10 +271,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineCrossSize_direction_row_alignContent_stretch() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100))
-    val node2 = Node(measurable = BoxMeasurable(200, 100))
-    val node3 = Node(measurable = BoxMeasurable(300, 100))
-    val node4 = Node(measurable = BoxMeasurable(400, 100))
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(200, 100))
+    val node3 = FlexNode(measurable = BoxMeasurable(300, 100))
+    val node4 = FlexNode(measurable = BoxMeasurable(400, 100))
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -300,10 +300,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testDetermineCrossSize_direction_column_alignContent_stretch() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100))
-    val node2 = Node(measurable = BoxMeasurable(100, 200))
-    val node3 = Node(measurable = BoxMeasurable(100, 300))
-    val node4 = Node(measurable = BoxMeasurable(100, 400))
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100))
+    val node2 = FlexNode(measurable = BoxMeasurable(100, 200))
+    val node3 = FlexNode(measurable = BoxMeasurable(100, 300))
+    val node4 = FlexNode(measurable = BoxMeasurable(100, 400))
     engine.nodes += node1
     engine.nodes += node2
     engine.nodes += node3
@@ -365,10 +365,10 @@ class FlexboxEngineTest {
 
   @Test
   fun testFlexLine_anyItemsHaveFlexGrow() {
-    val node1 = Node(measurable = BoxMeasurable(100, 100), flexGrow = 1.0f)
-    val node2 = Node(measurable = BoxMeasurable(100, 200))
-    val node3 = Node(measurable = BoxMeasurable(100, 300))
-    val node4 = Node(measurable = BoxMeasurable(100, 400), flexGrow = 2.0f)
+    val node1 = FlexNode(measurable = BoxMeasurable(100, 100), flexGrow = 1.0f)
+    val node2 = FlexNode(measurable = BoxMeasurable(100, 200))
+    val node3 = FlexNode(measurable = BoxMeasurable(100, 300))
+    val node4 = FlexNode(measurable = BoxMeasurable(100, 400), flexGrow = 2.0f)
     engine.apply {
       nodes += node1
       nodes += node2
diff --git a/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxTest.kt b/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxTest.kt
index 5465c9205..539ebc096 100644
--- a/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxTest.kt
+++ b/redwood-flexbox-engine/src/commonTest/kotlin/app/cash/redwood/flexbox/FlexboxTest.kt
@@ -115,7 +115,7 @@ class FlexboxTest {
     val widgets = imdbTop4.map { StringWidget(it) }
     val engine = FlexboxEngine().apply {
       flexDirection = Row
-      nodes += widgets.map { it.toNode(Node(flexBasisPercent = 0f)) }
+      nodes += widgets.map { it.toNode(FlexNode(flexBasisPercent = 0f)) }
       justifyContent = JustifyContent.Center
     }
 
@@ -156,7 +156,7 @@ class FlexboxTest {
     return canvas.toString()
   }
 
-  private fun StringWidget.toNode(node: Node = Node()): Node {
+  private fun StringWidget.toNode(node: FlexNode = FlexNode()): FlexNode {
     return node.apply {
       this.measurable = this@toNode
       this.layout = this@toNode::layout