WIP

Nathan Sobo created

Change summary

crates/storybook/src/sketch.rs | 176 +++++++++++++++++++++++------------
1 file changed, 113 insertions(+), 63 deletions(-)

Detailed changes

crates/storybook/src/sketch.rs 🔗

@@ -15,9 +15,10 @@ impl AppContext {
         unimplemented!()
     }
 
-    pub fn open_window<E, S>(
+    pub fn open_window<S, E>(
         &self,
-        root_view: impl Fn(ViewContext<S>) -> View<S>,
+        state: S,
+        render: impl Fn(&mut S, &mut ViewContext<S>) -> View<E>,
     ) -> WindowHandle<S> {
         unimplemented!()
     }
@@ -56,7 +57,7 @@ pub struct ModelContext<'a, T> {
     entity_id: EntityId,
 }
 
-impl<'a, T> ModelContext<'a, T> {
+impl<'a, T: 'static> ModelContext<'a, T> {
     fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
         Self {
             app: Reference::Mutable(app),
@@ -72,13 +73,23 @@ impl<'a, T> ModelContext<'a, T> {
             entity_id,
         }
     }
+
+    fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
+        let mut entity = self.app.entities.remove(&self.entity_id).unwrap();
+        let result = update(entity.downcast_mut::<T>().unwrap(), self);
+        self.app.entities.insert(self.entity_id, Box::new(entity));
+        result
+    }
 }
 
 pub struct Window {
     id: WindowId,
 }
 
+#[derive(Deref, DerefMut)]
 pub struct WindowContext<'a, 'b> {
+    #[deref]
+    #[deref_mut]
     app: Reference<'a, AppContext>,
     window: Reference<'b, Window>,
 }
@@ -91,19 +102,29 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         }
     }
 
+    fn immutable(app: &'a AppContext, window: &'w Window) -> Self {
+        Self {
+            app: Reference::Immutable(app),
+            window: Reference::Immutable(window),
+        }
+    }
+
     fn app_context(&mut self) -> &mut AppContext {
         &mut *self.app
     }
 }
 
-impl<'app, 'win> WindowContext<'app, 'win> {
+impl<'a, 'w> WindowContext<'a, 'w> {
     fn add_entity<T: 'static>(
         &mut self,
-        build_entity: impl FnOnce(&mut ViewContext<'_, 'app, 'win, T>) -> T,
+        build_entity: impl FnOnce(&mut ViewContext<'_, '_, T>) -> T,
     ) -> Handle<T> {
         let id = EntityId::new(&mut self.app_context().entity_count);
-        let mut cx = ViewContext::mutable(self, id);
-        let entity = build_entity(&mut cx);
+        let entity = build_entity(&mut ViewContext::mutable(
+            &mut *self.app,
+            &mut *self.window,
+            id,
+        ));
         self.app.entities.insert(id, Box::new(entity));
         Handle {
             id,
@@ -119,7 +140,7 @@ impl<'app, 'win> WindowContext<'app, 'win> {
         let mut entity = self.app.entities.remove(&handle.id).unwrap();
         let result = update(
             entity.downcast_mut().unwrap(),
-            &mut ViewContext::mutable(self, handle.id),
+            &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
         );
         self.app.entities.insert(handle.id, entity);
         result
@@ -139,26 +160,36 @@ impl<'app, 'win> WindowContext<'app, 'win> {
 }
 
 #[derive(Deref, DerefMut)]
-pub struct ViewContext<'parent, 'app, 'win, T> {
+pub struct ViewContext<'a, 'w, T> {
     #[deref]
     #[deref_mut]
-    window_cx: Reference<'parent, WindowContext<'app, 'win>>,
+    window_cx: WindowContext<'a, 'w>,
     entity_type: PhantomData<T>,
     entity_id: EntityId,
 }
 
-impl<'cx, 'app: 'cx, 'win: 'cx, V> ViewContext<'cx, 'app, 'win, V> {
-    fn mutable(window_cx: &'cx mut WindowContext<'app, 'win>, entity_id: EntityId) -> Self {
+impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> {
+    fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
+        let mut entity = self.window_cx.app.entities.remove(&self.entity_id).unwrap();
+        let result = update(entity.downcast_mut::<T>().unwrap(), self);
+        self.window_cx
+            .app
+            .entities
+            .insert(self.entity_id, Box::new(entity));
+        result
+    }
+
+    fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
         Self {
-            window_cx: Reference::Mutable(window_cx),
+            window_cx: WindowContext::mutable(app, window),
             entity_id,
             entity_type: PhantomData,
         }
     }
 
-    fn immutable(window_cx: &'cx WindowContext<'app, 'win>, entity_id: EntityId) -> Self {
+    fn immutable(app: &'a AppContext, window: &'w Window, entity_id: EntityId) -> Self {
         Self {
-            window_cx: Reference::Immutable(window_cx),
+            window_cx: WindowContext::immutable(app, window),
             entity_id,
             entity_type: PhantomData,
         }
@@ -192,28 +223,23 @@ impl EntityId {
     }
 }
 
-pub struct Handle<T> {
-    id: EntityId,
-    entity_type: PhantomData<T>,
-}
-
 trait Context {
-    type EntityContext<'cx, 'app, 'win, T: 'static>;
+    type EntityContext<'a, 'w, T: 'static>;
 
-    fn update_entity<'a, 'app, 'win, T: 'static, R>(
-        &'a mut self,
+    fn update_entity<T: 'static, R>(
+        &mut self,
         handle: &Handle<T>,
-        update: impl for<'cx> FnOnce(&mut T, &mut Self::EntityContext<'cx, 'app, 'win, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
     ) -> R;
 }
 
 impl Context for AppContext {
-    type EntityContext<'cx, 'app, 'win, T: 'static> = ModelContext<'cx, T>;
+    type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, T>;
 
-    fn update_entity<'a, 'app, 'win, T: 'static, R>(
-        &'a mut self,
+    fn update_entity<T: 'static, R>(
+        &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, 'app, 'win, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
     ) -> R {
         let mut entity = self
             .entities
@@ -227,31 +253,40 @@ impl Context for AppContext {
     }
 }
 
-// impl<'app, 'win> Context for WindowContext<'app, 'win> {
-//     type EntityContext<'cx, 'app, 'win, T: 'static> = ModelContext<'cx, T>;
+impl Context for WindowContext<'_, '_> {
+    type EntityContext<'a, 'w, T: 'static> = ViewContext<'a, 'w, T>;
 
-//     fn update_entity<'a, 'app, 'win, T: 'static, R>(
-//         &'a mut self,
-//         handle: &Handle<T>,
-//         update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, 'app, 'win, T>) -> R,
-//     ) -> R {
-//         let mut entity = self
-//             .entities
-//             .remove(&handle.id)
-//             .unwrap()
-//             .downcast::<T>()
-//             .unwrap();
-//         let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
-//         self.entities.insert(handle.id, Box::new(entity));
-//         result
-//     }
-// }
+    fn update_entity<T: 'static, R>(
+        &mut self,
+        handle: &Handle<T>,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+    ) -> R {
+        let mut entity = self
+            .app
+            .entities
+            .remove(&handle.id)
+            .unwrap()
+            .downcast::<T>()
+            .unwrap();
+        let result = update(
+            &mut *entity,
+            &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
+        );
+        self.entities.insert(handle.id, Box::new(entity));
+        result
+    }
+}
+
+pub struct Handle<T> {
+    id: EntityId,
+    entity_type: PhantomData<T>,
+}
 
 impl<T: 'static> Handle<T> {
-    fn update<'app, 'win, C: Context, R>(
+    fn update<C: Context, R>(
         &self,
         cx: &mut C,
-        update: impl FnOnce(&mut T, &mut C::EntityContext<'_, 'app, 'win, T>) -> R,
+        update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
     ) -> R {
         cx.update_entity(self, update)
     }
@@ -352,41 +387,53 @@ impl<S> AnyElement<S> {
 }
 
 pub trait IntoAnyElement<S> {
-    fn into_any_element(self) -> AnyElement<S>;
+    fn into_any(self) -> AnyElement<S>;
 }
 
 impl<E: Element> IntoAnyElement<E::State> for E {
-    fn into_any_element(self) -> AnyElement<E::State> {
+    fn into_any(self) -> AnyElement<E::State> {
         AnyElement(Box::new(RenderedElement::new(self)))
     }
 }
 
 impl<S> IntoAnyElement<S> for AnyElement<S> {
-    fn into_any_element(self) -> AnyElement<S> {
+    fn into_any(self) -> AnyElement<S> {
         self
     }
 }
 
-pub struct View<S> {
-    render: Rc<dyn Fn(&mut WindowContext) -> AnyElement<S>>,
+pub struct View<E> {
+    render: Rc<dyn Fn(&mut WindowContext) -> E>,
 }
 
-impl<S> View<S> {
-    fn render(&self, cx: &mut WindowContext) -> AnyElement<S> {
+impl<E> View<E> {
+    fn render(&self, cx: &mut WindowContext) -> E {
         (self.render)(cx)
     }
 }
 
-pub fn view<ParentState, ChildState: 'static>(
-    state: Handle<ChildState>,
-    render: impl 'static + Fn(&mut ChildState, &mut ViewContext<ChildState>) -> AnyElement<ParentState>,
-) -> View<ParentState> {
+pub fn view<S: 'static, E: Element<State = S>>(
+    state: Handle<S>,
+    render: impl 'static + Fn(&mut S, &mut ViewContext<S>) -> E,
+) -> View<E> {
     View {
-        // render: Rc::new(move |cx| state.update(cx, |state, cx| render(state, cx))),
-        render: todo!(),
+        render: Rc::new(move |cx| state.update(cx, |state, cx| render(state, cx))),
     }
 }
 
+trait ViewObject<S> {
+    fn render(cx: &mut WindowContext) -> AnyElement<S>;
+}
+
+impl<S: 'static, E: Element<State = S>> ViewObject<S> for View<E> {
+    fn render<V>(&mut self, cx: &mut WindowContext) -> AnyElement<V> {
+        let element = (self.render)(cx);
+        AnyElement(Box::new(RenderedElement::new(element)))
+    }
+}
+
+pub struct AnyView(Box<dyn ViewObject<S>);
+
 pub struct Div<S>(PhantomData<S>);
 
 impl<S: 'static> Element for Div<S> {
@@ -423,7 +470,7 @@ pub fn div<S>() -> Div<S> {
 }
 
 pub struct Workspace {
-    left_panel: View<Self>,
+    left_panel: AnyView,
 }
 
 fn workspace(
@@ -471,7 +518,10 @@ mod tests {
     #[test]
     fn test() {
         let mut cx = AppContext::new();
-        // let collab_panel = cx.add_entity(|cx| CollabPanel::new(cx));
+        let collab_panel = cx.open_window(|cx| {
+            let panel = cx.add_entity(|cx| CollabPanel::new(cx));
+            view(panel, |panel, cx| div().into_any())
+        });
 
         // let
         // let mut workspace = Workspace {