Async experimentation

This commit imports some of the infrastructure from the idiopath_async branch. It should still be considered experimental.
This commit is contained in:
Raph Levien 2022-05-24 15:32:11 -07:00
parent c0f725d972
commit b1e57b02d2
6 changed files with 88 additions and 7 deletions

View File

@ -8,3 +8,5 @@ edition = "2021"
[dependencies]
"druid-shell" = { path = "../druid-shell" }
bitflags = "1.3.2"
futures-task = "0.3"
tokio = { version = "1", features = ["full"] }

View File

@ -18,7 +18,8 @@ fn app_logic(_: &mut ()) -> impl View<()> {
scroll_view(list(1000, 20.0, |i| format!("{}", i)))
}
pub fn main() {
#[tokio::main]
async fn main() {
let app = App::new((), app_logic);
AppLauncher::new(app).run();
}

View File

@ -12,10 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::{Arc, Mutex};
use druid_shell::kurbo::Size;
use druid_shell::piet::{Color, Piet, RenderContext};
use druid_shell::WindowHandle;
use crate::event::AsyncWake;
use crate::id::IdPath;
use crate::widget::{CxState, EventCx, LayoutCx, PaintCx, Pod, UpdateCx, WidgetState};
use crate::{
event::Event,
@ -36,8 +40,12 @@ pub struct App<T, V: View<T>, F: FnMut(&mut T) -> V> {
root_pod: Option<Pod>,
size: Size,
cx: Cx,
wake_queue: WakeQueue,
}
#[derive(Clone, Default)]
pub struct WakeQueue(Arc<Mutex<Vec<IdPath>>>);
const BG_COLOR: Color = Color::rgb8(0x27, 0x28, 0x22);
impl<T, V: View<T>, F: FnMut(&mut T) -> V> App<T, V, F>
@ -45,7 +53,8 @@ where
V::Element: Widget + 'static,
{
pub fn new(data: T, app_logic: F) -> Self {
let cx = Cx::new();
let wake_queue = Default::default();
let cx = Cx::new(&wake_queue);
App {
data,
app_logic,
@ -58,6 +67,7 @@ where
root_state: Default::default(),
size: Default::default(),
cx,
wake_queue,
}
}
@ -76,7 +86,7 @@ where
pub fn connect(&mut self, window_handle: WindowHandle) {
self.window_handle = window_handle.clone();
// This will be needed for wiring up async but is a stub for now.
//self.cx.set_handle(window_handle.get_idle_handle());
self.cx.set_handle(window_handle.get_idle_handle());
}
pub fn size(&mut self, size: Size) {
@ -154,4 +164,25 @@ where
}
self.view = Some(view);
}
pub fn wake_async(&mut self) {
for id_path in self.wake_queue.take() {
self.events.push(Event::new(id_path, AsyncWake));
}
self.run_app_logic();
}
}
impl WakeQueue {
// Returns true if the queue was empty.
pub fn push_wake(&self, id_path: IdPath) -> bool {
let mut queue = self.0.lock().unwrap();
let was_empty = queue.is_empty();
queue.push(id_path);
was_empty
}
pub fn take(&self) -> Vec<IdPath> {
std::mem::replace(&mut self.0.lock().unwrap(), Vec::new())
}
}

View File

@ -15,8 +15,8 @@
use std::any::Any;
use druid_shell::{
kurbo::Size, Application, Cursor, HotKey, Menu, MouseEvent, Region, SysMods, WinHandler,
WindowBuilder, WindowHandle,
kurbo::Size, Application, Cursor, HotKey, IdleToken, Menu, MouseEvent, Region, SysMods,
WinHandler, WindowBuilder, WindowHandle,
};
use crate::{app::App, widget::RawEvent, View, Widget};
@ -135,6 +135,12 @@ where
Application::global().quit()
}
fn idle(&mut self, _token: IdleToken) {
self.app.wake_async();
// TODO: wire up invalidation through widget hierarchy
self.handle.invalidate();
}
fn as_any(&mut self) -> &mut dyn Any {
self
}

View File

@ -38,6 +38,8 @@ pub enum EventResult<A> {
Stale,
}
pub struct AsyncWake;
impl<A> EventResult<A> {
#[allow(unused)]
pub fn map<B>(self, f: impl FnOnce(A) -> B) -> EventResult<B> {

View File

@ -23,9 +23,13 @@ pub mod text;
pub mod use_state;
pub mod vstack;
use std::any::Any;
use std::{any::Any, sync::Arc};
use druid_shell::{IdleHandle, IdleToken};
use futures_task::{ArcWake, Waker};
use crate::{
app::WakeQueue,
event::EventResult,
id::{Id, IdPath},
widget::Widget,
@ -84,12 +88,35 @@ pub trait View<T, A = ()> {
#[derive(Clone)]
pub struct Cx {
id_path: IdPath,
idle_handle: Option<IdleHandle>,
wake_queue: WakeQueue,
}
struct MyWaker {
id_path: IdPath,
idle_handle: IdleHandle,
wake_queue: WakeQueue,
}
impl ArcWake for MyWaker {
fn wake_by_ref(arc_self: &Arc<Self>) {
println!("path = {:?}", arc_self.id_path);
if arc_self.wake_queue.push_wake(arc_self.id_path.clone()) {
// The clone shouldn't be needed; schedule_idle should be &self I think
arc_self
.idle_handle
.clone()
.schedule_idle(IdleToken::new(42));
}
}
}
impl Cx {
pub fn new() -> Self {
pub fn new(wake_queue: &WakeQueue) -> Self {
Cx {
id_path: Vec::new(),
idle_handle: None,
wake_queue: wake_queue.clone(),
}
}
@ -129,4 +156,16 @@ impl Cx {
self.pop();
(id, result)
}
pub(crate) fn set_handle(&mut self, idle_handle: Option<IdleHandle>) {
self.idle_handle = idle_handle;
}
pub fn waker(&self) -> Waker {
futures_task::waker(Arc::new(MyWaker {
id_path: self.id_path.clone(),
idle_handle: self.idle_handle.as_ref().unwrap().clone(),
wake_queue: self.wake_queue.clone(),
}))
}
}