Remove use of replace_with crate for managing element lifecycles

Max Brunsfeld and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

Cargo.lock           |  7 -----
gpui/Cargo.toml      |  1 
gpui/src/elements.rs | 60 +++++++++++++++++++++++++--------------------
3 files changed, 33 insertions(+), 35 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2172,7 +2172,6 @@ dependencies = [
  "png 0.16.8",
  "postage",
  "rand 0.8.3",
- "replace_with",
  "resvg",
  "seahash",
  "serde 1.0.125",
@@ -3927,12 +3926,6 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "replace_with"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690"
-
 [[package]]
 name = "resvg"
 version = "0.14.0"

gpui/Cargo.toml 🔗

@@ -19,7 +19,6 @@ pathfinder_color = "0.5"
 pathfinder_geometry = "0.5"
 postage = { version = "0.4.1", features = ["futures-traits"] }
 rand = "0.8.3"
-replace_with = "0.1.7"
 resvg = "0.14"
 seahash = "4.1"
 serde = { version = "1.0.125", features = ["derive"] }

gpui/src/elements.rs 🔗

@@ -34,8 +34,7 @@ use crate::{
 };
 use core::panic;
 use json::ToJson;
-use replace_with::replace_with_or_abort;
-use std::{any::Any, borrow::Cow};
+use std::{any::Any, borrow::Cow, mem};
 
 trait AnyElement {
     fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
@@ -115,6 +114,7 @@ pub trait Element {
 }
 
 pub enum Lifecycle<T: Element> {
+    Empty,
     Init {
         element: T,
     },
@@ -139,8 +139,9 @@ pub struct ElementBox {
 
 impl<T: Element> AnyElement for Lifecycle<T> {
     fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
-        let mut result = None;
-        replace_with_or_abort(self, |me| match me {
+        let result;
+        *self = match mem::take(self) {
+            Lifecycle::Empty => unreachable!(),
             Lifecycle::Init { mut element }
             | Lifecycle::PostLayout { mut element, .. }
             | Lifecycle::PostPaint { mut element, .. } => {
@@ -148,7 +149,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                 debug_assert!(size.x().is_finite());
                 debug_assert!(size.y().is_finite());
 
-                result = Some(size);
+                result = size;
                 Lifecycle::PostLayout {
                     element,
                     constraint,
@@ -156,8 +157,8 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                     layout,
                 }
             }
-        });
-        result.unwrap()
+        };
+        result
     }
 
     fn after_layout(&mut self, cx: &mut AfterLayoutContext) {
@@ -175,27 +176,25 @@ impl<T: Element> AnyElement for Lifecycle<T> {
     }
 
     fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
-        replace_with_or_abort(self, |me| {
-            if let Lifecycle::PostLayout {
-                mut element,
+        *self = if let Lifecycle::PostLayout {
+            mut element,
+            constraint,
+            size,
+            mut layout,
+        } = mem::take(self)
+        {
+            let bounds = RectF::new(origin, size);
+            let paint = element.paint(bounds, &mut layout, cx);
+            Lifecycle::PostPaint {
+                element,
                 constraint,
-                size,
-                mut layout,
-            } = me
-            {
-                let bounds = RectF::new(origin, size);
-                let paint = element.paint(bounds, &mut layout, cx);
-                Lifecycle::PostPaint {
-                    element,
-                    constraint,
-                    bounds,
-                    layout,
-                    paint,
-                }
-            } else {
-                panic!("invalid element lifecycle state");
+                bounds,
+                layout,
+                paint,
             }
-        });
+        } else {
+            panic!("invalid element lifecycle state");
+        };
     }
 
     fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
@@ -215,7 +214,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
 
     fn size(&self) -> Vector2F {
         match self {
-            Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
+            Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
             Lifecycle::PostLayout { size, .. } => *size,
             Lifecycle::PostPaint { bounds, .. } => bounds.size(),
         }
@@ -223,6 +222,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
 
     fn metadata(&self) -> Option<&dyn Any> {
         match self {
+            Lifecycle::Empty => unreachable!(),
             Lifecycle::Init { element }
             | Lifecycle::PostLayout { element, .. }
             | Lifecycle::PostPaint { element, .. } => element.metadata(),
@@ -257,6 +257,12 @@ impl<T: Element> AnyElement for Lifecycle<T> {
     }
 }
 
+impl<T: Element> Default for Lifecycle<T> {
+    fn default() -> Self {
+        Self::Empty
+    }
+}
+
 impl ElementBox {
     pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
         self.element.layout(constraint, cx)