Detailed changes
@@ -3,31 +3,41 @@ use crate::{
WindowContext, WindowHandle, WindowId,
};
use anyhow::{anyhow, Result};
+use async_task::Runnable;
+use futures::Future;
+use parking_lot::RwLock;
use slotmap::SlotMap;
-use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc, sync::Arc};
+use std::{
+ any::Any,
+ marker::PhantomData,
+ sync::{Arc, Weak},
+};
#[derive(Clone)]
-pub struct App(Rc<RefCell<AppContext>>);
+pub struct App(Arc<RwLock<AppContext<()>>>);
+
+pub struct MainThread;
impl App {
pub fn new() -> Self {
- Self(Rc::new(RefCell::new(AppContext::new(current_platform()))))
+ Self(Arc::new(RwLock::new(AppContext::new(current_platform()))))
}
pub fn run<F>(self, on_finish_launching: F)
where
- F: 'static + FnOnce(&mut AppContext),
+ F: 'static + FnOnce(&mut AppContext<MainThread>),
{
- let platform = self.0.borrow().platform().clone();
platform.run(Box::new(move || {
- let mut cx = self.0.borrow_mut();
+ let mut cx = self.0.write();
on_finish_launching(&mut *cx);
}));
}
}
-pub struct AppContext {
- platform: Rc<dyn Platform>,
+pub struct AppContext<Thread = ()> {
+ this: Weak<RwLock<AppContext>>,
+ thread: PhantomData<Thread>,
+ platform: Box<dyn Platform>,
text_system: Arc<TextSystem>,
pub(crate) unit_entity_id: EntityId,
pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any>>>,
@@ -36,13 +46,40 @@ pub struct AppContext {
pub(crate) layout_id_buffer: Vec<LayoutId>,
}
-impl AppContext {
- pub fn new(platform: Rc<dyn Platform>) -> Self {
+impl AppContext<()> {
+ pub fn run_on_main<F: 'static, T: 'static>(
+ &self,
+ to_call: F,
+ ) -> Result<T, impl Future<Output = T>>
+ where
+ F: Fn(&mut AppContext<MainThread>) -> T + Send + Sync,
+ {
+ let dispatcher = self.platform().dispatcher();
+ if dispatcher.is_main_thread() {
+ } else {
+ let future = async move {
+ // let cx = unsafe { };
+ };
+ let schedule = move |runnable: Runnable| dispatcher.run_on_main_thread(runnable);
+
+ let (runnable, task) = async_task::spawn_local();
+ runnable.schedule();
+ }
+
+ let (runnable, task) = async_task::spawn_local(future, schedule);
+ runnable.schedule();
+ task
+ }
+}
+
+impl<Thread> AppContext<Thread> {
+ pub fn new(platform: Arc<dyn Platform>) -> Self {
let text_system = Arc::new(TextSystem::new(platform.text_system()));
let mut entities = SlotMap::with_key();
let unit_entity_id = entities.insert(Some(Box::new(()) as Box<dyn Any>));
AppContext {
+ thread: PhantomData,
platform,
text_system,
unit_entity_id,
@@ -54,11 +91,7 @@ impl AppContext {
#[cfg(any(test, feature = "test"))]
pub fn test() -> Self {
- Self::new(Rc::new(super::TestPlatform::new()))
- }
-
- pub fn platform(&self) -> &Rc<dyn Platform> {
- &self.platform
+ Self::new(Arc::new(super::TestPlatform::new()))
}
pub fn text_system(&self) -> &Arc<TextSystem> {
@@ -105,8 +138,14 @@ impl AppContext {
}
}
-impl Context for AppContext {
- type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, T>;
+impl AppContext<MainThread> {
+ pub fn platform(&self) -> &dyn Platform {
+ self.platform.as_ref()
+ }
+}
+
+impl<Thread: 'static> Context for AppContext<Thread> {
+ type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, Thread, T>;
fn entity<T: 'static>(
&mut self,
@@ -139,14 +178,14 @@ impl Context for AppContext {
}
}
-pub struct ModelContext<'a, T> {
- app: Reference<'a, AppContext>,
+pub struct ModelContext<'a, Thread: 'static, T> {
+ app: Reference<'a, AppContext<Thread>>,
entity_type: PhantomData<T>,
entity_id: EntityId,
}
-impl<'a, T: 'static> ModelContext<'a, T> {
- pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
+impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> {
+ pub(crate) fn mutable(app: &'a mut AppContext<Thread>, entity_id: EntityId) -> Self {
Self {
app: Reference::Mutable(app),
entity_type: PhantomData,
@@ -154,7 +193,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
}
}
- fn immutable(app: &'a AppContext, entity_id: EntityId) -> Self {
+ fn immutable(app: &'a AppContext<Thread>, entity_id: EntityId) -> Self {
Self {
app: Reference::Immutable(app),
entity_type: PhantomData,
@@ -180,9 +219,8 @@ impl<'a, T: 'static> ModelContext<'a, T> {
}
}
-impl<'a, T: 'static> Context for ModelContext<'a, T> {
- type EntityContext<'b, 'c, U: 'static> = ModelContext<'b, U>;
-
+impl<'a, Thread, T: 'static> Context for ModelContext<'a, Thread, T> {
+ type EntityContext<'b, 'c, U: 'static> = ModelContext<'b, Thread, U>;
fn entity<U: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
@@ -1,4 +1,4 @@
-use super::{Handle, Layout, LayoutId, Pixels, Point, Result, ViewContext};
+use super::{Layout, LayoutId, Pixels, Point, Result, ViewContext};
pub(crate) use smallvec::SmallVec;
use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
@@ -36,12 +36,12 @@ pub use mac::*;
pub use test::*;
#[cfg(target_os = "macos")]
-pub(crate) fn current_platform() -> Rc<dyn Platform> {
+pub(crate) fn current_platform() -> Arc<dyn Platform> {
Rc::new(MacPlatform::new())
}
pub trait Platform {
- fn executor(&self) -> Rc<ForegroundExecutor>;
+ fn dispatcher(&self) -> Arc<dyn PlatformDispatcher>;
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
fn run(&self, on_finish_launching: Box<dyn FnOnce()>);
@@ -0,0 +1,143 @@
+use crate::{
+ AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext,
+ WindowContext,
+};
+use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
+
+pub struct View<S, P> {
+ state: Handle<S>,
+ render: Rc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S>>,
+ parent_state_type: PhantomData<P>,
+}
+
+impl<S, P> Clone for View<S, P> {
+ fn clone(&self) -> Self {
+ Self {
+ state: self.state.clone(),
+ render: self.render.clone(),
+ parent_state_type: PhantomData,
+ }
+ }
+}
+
+pub type RootView<S> = View<S, ()>;
+
+pub fn view<S: 'static, P: 'static, E: Element<State = S>>(
+ state: Handle<S>,
+ render: impl 'static + Fn(&mut S, &mut ViewContext<S>) -> E,
+) -> View<S, P> {
+ View {
+ state,
+ render: Rc::new(move |state, cx| render(state, cx).into_any()),
+ parent_state_type: PhantomData,
+ }
+}
+
+impl<S: 'static, P: 'static> View<S, P> {
+ pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
+ AnyView {
+ view: Rc::new(RefCell::new(self)),
+ parent_state_type: PhantomData,
+ }
+ }
+}
+
+impl<S: 'static, P: 'static> Element for View<S, P> {
+ type State = P;
+ type FrameState = AnyElement<S>;
+
+ fn layout(
+ &mut self,
+ _: &mut Self::State,
+ cx: &mut ViewContext<Self::State>,
+ ) -> Result<(LayoutId, Self::FrameState)> {
+ self.state.update(cx, |state, cx| {
+ let mut element = (self.render)(state, cx);
+ let layout_id = element.layout(state, cx)?;
+ Ok((layout_id, element))
+ })
+ }
+
+ fn paint(
+ &mut self,
+ layout: Layout,
+ _: &mut Self::State,
+ element: &mut Self::FrameState,
+ cx: &mut ViewContext<Self::State>,
+ ) -> Result<()> {
+ self.state
+ .update(cx, |state, cx| element.paint(state, None, cx))
+ }
+}
+
+trait ViewObject {
+ fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
+ fn paint(
+ &mut self,
+ layout: Layout,
+ element: &mut dyn Any,
+ cx: &mut WindowContext,
+ ) -> Result<()>;
+}
+
+impl<S: 'static, P> ViewObject for View<S, P> {
+ fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
+ self.state.update(cx, |state, cx| {
+ let mut element = (self.render)(state, cx);
+ let layout_id = element.layout(state, cx)?;
+ let element = Box::new(element) as Box<dyn Any>;
+ Ok((layout_id, element))
+ })
+ }
+
+ fn paint(
+ &mut self,
+ layout: Layout,
+ element: &mut dyn Any,
+ cx: &mut WindowContext,
+ ) -> Result<()> {
+ self.state.update(cx, |state, cx| {
+ element
+ .downcast_mut::<AnyElement<S>>()
+ .unwrap()
+ .paint(state, None, cx)
+ })
+ }
+}
+
+pub struct AnyView<S> {
+ view: Rc<RefCell<dyn ViewObject>>,
+ parent_state_type: PhantomData<S>,
+}
+
+impl<S: 'static> Element for AnyView<S> {
+ type State = S;
+ type FrameState = Box<dyn Any>;
+
+ fn layout(
+ &mut self,
+ _: &mut Self::State,
+ cx: &mut ViewContext<Self::State>,
+ ) -> Result<(LayoutId, Self::FrameState)> {
+ self.view.borrow_mut().layout(cx)
+ }
+
+ fn paint(
+ &mut self,
+ layout: Layout,
+ _: &mut Self::State,
+ element: &mut Self::FrameState,
+ cx: &mut ViewContext<Self::State>,
+ ) -> Result<()> {
+ self.view.borrow_mut().paint(layout, element, cx)
+ }
+}
+
+impl<S> Clone for AnyView<S> {
+ fn clone(&self) -> Self {
+ Self {
+ view: self.view.clone(),
+ parent_state_type: PhantomData,
+ }
+ }
+}
@@ -1,4 +1,6 @@
-use crate::{AvailableSpace, PlatformWindow, Point, Size, Style, TextStyle, TextStyleRefinement};
+use crate::{
+ AvailableSpace, Bg, PlatformWindow, Point, Size, Style, TextStyle, TextStyleRefinement,
+};
use super::{
px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference,
@@ -45,7 +47,7 @@ pub struct WindowContext<'a, 'b> {
}
impl<'a, 'w> WindowContext<'a, 'w> {
- pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
+ pub(crate) fn mutable(app: &'a mut AppContext<Bg>, window: &'w mut Window) -> Self {
Self {
app: Reference::Mutable(app),
window: Reference::Mutable(window),