Float fabricFloatFromYogaOptionalFloat(YGFloatOptional value) {
  if (value.isUndefined()) {
    return kFloatUndefined;
  }

  return fabricFloatFromYogaFloat(value.getValue());
}
std::string stringFromYogaStyleOptionalFloat(YGFloatOptional value) {
  if (value.isUndefined()) {
    return "undefined";
  }

  return folly::to<std::string>(fabricFloatFromYogaFloat(value.getValue()));
}
YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
  YogaLayoutableShadowNode *shadowNodeRawPtr = (YogaLayoutableShadowNode *)yogaNode->getContext();
  assert(shadowNodeRawPtr);

  Size minimumSize = Size {0, 0};
  Size maximumSize = Size {kFloatMax, kFloatMax};

  switch (widthMode) {
    case YGMeasureModeUndefined:
      break;
    case YGMeasureModeExactly:
      minimumSize.width = fabricFloatFromYogaFloat(width);
      maximumSize.width = fabricFloatFromYogaFloat(width);
      break;
    case YGMeasureModeAtMost:
      maximumSize.width = fabricFloatFromYogaFloat(width);
      break;
  }

  switch (heightMode) {
    case YGMeasureModeUndefined:
      break;
    case YGMeasureModeExactly:
      minimumSize.height = fabricFloatFromYogaFloat(height);
      maximumSize.height = fabricFloatFromYogaFloat(height);
      break;
    case YGMeasureModeAtMost:
      maximumSize.height = fabricFloatFromYogaFloat(height);
      break;
  }

  Size size = shadowNodeRawPtr->measure(LayoutConstraints {minimumSize, maximumSize});

  return YGSize {
    yogaFloatFromFabricFloat(size.width),
    yogaFloatFromFabricFloat(size.height)
  };
}
LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) {
  LayoutMetrics layoutMetrics;

  YGLayout layout = yogaNode.getLayout();

  layoutMetrics.frame = Rect {
    Point {
      fabricFloatFromYogaFloat(layout.position[YGEdgeLeft]),
      fabricFloatFromYogaFloat(layout.position[YGEdgeTop])
    },
    Size {
      fabricFloatFromYogaFloat(layout.dimensions[YGDimensionWidth]),
      fabricFloatFromYogaFloat(layout.dimensions[YGDimensionHeight])
    }
  };

  layoutMetrics.borderWidth = EdgeInsets {
    fabricFloatFromYogaFloat(layout.border[YGEdgeLeft]),
    fabricFloatFromYogaFloat(layout.border[YGEdgeTop]),
    fabricFloatFromYogaFloat(layout.border[YGEdgeRight]),
    fabricFloatFromYogaFloat(layout.border[YGEdgeBottom])
  };

  layoutMetrics.contentInsets = EdgeInsets {
    fabricFloatFromYogaFloat(layout.border[YGEdgeLeft] + layout.padding[YGEdgeLeft]),
    fabricFloatFromYogaFloat(layout.border[YGEdgeTop] + layout.padding[YGEdgeTop]),
    fabricFloatFromYogaFloat(layout.border[YGEdgeRight] + layout.padding[YGEdgeRight]),
    fabricFloatFromYogaFloat(layout.border[YGEdgeBottom] + layout.padding[YGEdgeBottom])
  };

  layoutMetrics.displayType =
    yogaNode.getStyle().display == YGDisplayNone ? DisplayType::None : DisplayType::Flex;

  layoutMetrics.layoutDirection =
    layout.direction == YGDirectionRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight;

  return layoutMetrics;
}