gpui: Make entities no longer implement Element (they go through AnyElement now) (#48217)

Piotr Osiewicz created

This reduces e.g. agent_ui's LLVM lines from 1.95m to 1.7m ( -> 56009 ->
50899).
git_ui: 1.02 -> 0.917m (30700 functions -> 27496)


Overall, anything that implements `Render` should benefit. OTOH `editor`
does not, because it has a custom `Element` impl.
Release Notes:

- N/A

Change summary

crates/editor/src/editor_tests.rs |  2 
crates/editor/src/test.rs         |  6 ++-
crates/gpui/src/element.rs        | 39 +++++++++++++++------
crates/gpui/src/elements/list.rs  | 10 +++--
crates/gpui/src/view.rs           | 57 +-------------------------------
5 files changed, 40 insertions(+), 74 deletions(-)

Detailed changes

crates/editor/src/editor_tests.rs 🔗

@@ -30563,7 +30563,7 @@ fn test_editor_rendering_when_positioned_above_viewport(cx: &mut TestAppContext)
     cx.draw(
         gpui::point(px(0.), px(-10000.)),
         gpui::size(px(500.), px(3000.)),
-        |_, _| editor.clone(),
+        |_, _| editor.clone().into_any_element(),
     );
 
     // If we get here without hanging, the test passes

crates/editor/src/test.rs 🔗

@@ -19,7 +19,7 @@ use gpui::{
 use multi_buffer::{MultiBufferOffset, ToPoint};
 use pretty_assertions::assert_eq;
 use project::{Project, project_settings::DiagnosticSeverity};
-use ui::{App, BorrowAppContext, px};
+use ui::{App, BorrowAppContext, IntoElement, px};
 use util::test::{generate_marked_text, marked_text_offsets, marked_text_ranges};
 
 #[cfg(test)]
@@ -193,7 +193,9 @@ pub fn editor_content_with_blocks_and_size(
     cx: &mut VisualTestContext,
 ) -> String {
     cx.simulate_resize(draw_size);
-    cx.draw(gpui::Point::default(), draw_size, |_, _| editor.clone());
+    cx.draw(gpui::Point::default(), draw_size, |_, _| {
+        editor.clone().into_any_element()
+    });
     let (snapshot, mut lines, blocks) = editor.update_in(cx, |editor, window, cx| {
         let snapshot = editor.snapshot(window, cx);
         let text = editor.display_text(cx);

crates/gpui/src/element.rs 🔗

@@ -33,8 +33,8 @@
 
 use crate::{
     App, ArenaBox, AvailableSpace, Bounds, Context, DispatchNodeId, ElementId, FocusHandle,
-    InspectorElementId, LayoutId, Pixels, Point, Size, Style, Window, util::FluentBuilder,
-    window::with_element_arena,
+    InspectorElementId, LayoutId, Pixels, Point, SharedString, Size, Style, Window,
+    util::FluentBuilder, window::with_element_arena,
 };
 use derive_more::{Deref, DerefMut};
 use std::{
@@ -197,8 +197,27 @@ impl<C: RenderOnce> Component<C> {
     }
 }
 
+fn prepaint_component(
+    (element, name): &mut (AnyElement, &'static str),
+    window: &mut Window,
+    cx: &mut App,
+) {
+    window.with_id(ElementId::Name(SharedString::new_static(name)), |window| {
+        element.prepaint(window, cx);
+    })
+}
+
+fn paint_component(
+    (element, name): &mut (AnyElement, &'static str),
+    window: &mut Window,
+    cx: &mut App,
+) {
+    window.with_id(ElementId::Name(SharedString::new_static(name)), |window| {
+        element.paint(window, cx);
+    })
+}
 impl<C: RenderOnce> Element for Component<C> {
-    type RequestLayoutState = AnyElement;
+    type RequestLayoutState = (AnyElement, &'static str);
     type PrepaintState = ();
 
     fn id(&self) -> Option<ElementId> {
@@ -229,7 +248,7 @@ impl<C: RenderOnce> Element for Component<C> {
                 .into_any_element();
 
             let layout_id = element.request_layout(window, cx);
-            (layout_id, element)
+            (layout_id, (element, type_name::<C>()))
         })
     }
 
@@ -238,13 +257,11 @@ impl<C: RenderOnce> Element for Component<C> {
         _id: Option<&GlobalElementId>,
         _inspector_id: Option<&InspectorElementId>,
         _: Bounds<Pixels>,
-        element: &mut AnyElement,
+        state: &mut Self::RequestLayoutState,
         window: &mut Window,
         cx: &mut App,
     ) {
-        window.with_id(ElementId::Name(type_name::<C>().into()), |window| {
-            element.prepaint(window, cx);
-        })
+        prepaint_component(state, window, cx);
     }
 
     fn paint(
@@ -252,14 +269,12 @@ impl<C: RenderOnce> Element for Component<C> {
         _id: Option<&GlobalElementId>,
         _inspector_id: Option<&InspectorElementId>,
         _: Bounds<Pixels>,
-        element: &mut Self::RequestLayoutState,
+        state: &mut Self::RequestLayoutState,
         _: &mut Self::PrepaintState,
         window: &mut Window,
         cx: &mut App,
     ) {
-        window.with_id(ElementId::Name(type_name::<C>().into()), |window| {
-            element.paint(window, cx);
-        })
+        paint_component(state, window, cx);
     }
 }
 

crates/gpui/src/elements/list.rs 🔗

@@ -1285,7 +1285,7 @@ mod test {
 
         // Paint
         cx.draw(point(px(0.), px(0.)), size(px(100.), px(20.)), |_, cx| {
-            cx.new(|_| TestView(state.clone()))
+            cx.new(|_| TestView(state.clone())).into_any_element()
         });
 
         // Reset
@@ -1322,7 +1322,7 @@ mod test {
 
         // Paint
         cx.draw(point(px(0.), px(0.)), size(px(100.), px(100.)), |_, cx| {
-            cx.new(|_| TestView(state.clone()))
+            cx.new(|_| TestView(state.clone())).into_any_element()
         });
 
         // Test positive distance: start at item 1, move down 30px
@@ -1391,7 +1391,7 @@ mod test {
         });
 
         cx.draw(point(px(0.), px(0.)), size(px(100.), px(200.)), |_, _| {
-            view.clone()
+            view.clone().into_any_element()
         });
 
         let offset = state.logical_scroll_top();
@@ -1405,7 +1405,9 @@ mod test {
         item_height.set(50);
         state.remeasure();
 
-        cx.draw(point(px(0.), px(0.)), size(px(100.), px(200.)), |_, _| view);
+        cx.draw(point(px(0.), px(0.)), size(px(100.), px(200.)), |_, _| {
+            view.into_any_element()
+        });
 
         let offset = state.logical_scroll_top();
         assert_eq!(offset.item_ix, 2);

crates/gpui/src/view.rs 🔗

@@ -25,59 +25,6 @@ struct ViewCacheKey {
     text_style: TextStyle,
 }
 
-impl<V: Render> Element for Entity<V> {
-    type RequestLayoutState = AnyElement;
-    type PrepaintState = ();
-
-    fn id(&self) -> Option<ElementId> {
-        Some(ElementId::View(self.entity_id()))
-    }
-
-    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
-        None
-    }
-
-    fn request_layout(
-        &mut self,
-        _id: Option<&GlobalElementId>,
-        _inspector_id: Option<&InspectorElementId>,
-        window: &mut Window,
-        cx: &mut App,
-    ) -> (LayoutId, Self::RequestLayoutState) {
-        let mut element = self.update(cx, |view, cx| view.render(window, cx).into_any_element());
-        let layout_id = window.with_rendered_view(self.entity_id(), |window| {
-            element.request_layout(window, cx)
-        });
-        (layout_id, element)
-    }
-
-    fn prepaint(
-        &mut self,
-        _id: Option<&GlobalElementId>,
-        _inspector_id: Option<&InspectorElementId>,
-        _: Bounds<Pixels>,
-        element: &mut Self::RequestLayoutState,
-        window: &mut Window,
-        cx: &mut App,
-    ) {
-        window.set_view_id(self.entity_id());
-        window.with_rendered_view(self.entity_id(), |window| element.prepaint(window, cx));
-    }
-
-    fn paint(
-        &mut self,
-        _id: Option<&GlobalElementId>,
-        _inspector_id: Option<&InspectorElementId>,
-        _: Bounds<Pixels>,
-        element: &mut Self::RequestLayoutState,
-        _: &mut Self::PrepaintState,
-        window: &mut Window,
-        cx: &mut App,
-    ) {
-        window.with_rendered_view(self.entity_id(), |window| element.paint(window, cx));
-    }
-}
-
 /// A dynamically-typed handle to a view, which can be downcast to a [Entity] for a specific type.
 #[derive(Clone, Debug)]
 pub struct AnyView {
@@ -294,10 +241,10 @@ impl Element for AnyView {
 }
 
 impl<V: 'static + Render> IntoElement for Entity<V> {
-    type Element = Entity<V>;
+    type Element = AnyView;
 
     fn into_element(self) -> Self::Element {
-        self
+        self.into()
     }
 }