From d98aa6e6f6bd9b8957da221fe920e93dace94bee Mon Sep 17 00:00:00 2001 From: Adoo Date: Tue, 11 Jun 2024 12:26:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(core):=20=F0=9F=8E=B8=20support=20query=20?= =?UTF-8?q?`WriteRef`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 + core/src/builtin_widgets/focus_node.rs | 4 +- core/src/builtin_widgets/mix_builtin.rs | 27 +-- core/src/context/build_ctx.rs | 12 +- core/src/context/widget_ctx.rs | 4 +- core/src/data_widget.rs | 53 ++--- core/src/events/dispatcher.rs | 11 +- core/src/events/focus_mgr.rs | 34 ++-- core/src/lib.rs | 3 + core/src/pipe.rs | 117 ++++++----- core/src/query.rs | 259 ++++++++++++++++++++++++ core/src/render_helper.rs | 22 +- core/src/state.rs | 82 +------- core/src/state/map_state.rs | 6 +- core/src/state/splitted_state.rs | 2 +- core/src/state/state_cell.rs | 59 ++++-- core/src/state/stateful.rs | 4 +- core/src/widget.rs | 114 +---------- core/src/widget_tree/widget_id.rs | 61 +++--- core/src/window.rs | 17 +- widgets/src/input.rs | 2 +- 21 files changed, 499 insertions(+), 398 deletions(-) create mode 100644 core/src/query.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 417238f45..65b18248a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he ## [@Unreleased] - @ReleaseDate +### Features + +- **core**: Added support to query a `WriteRef` from a state, enabling users to modify the state after attaching it to a widget. (#pr @M-Adoo) + ### Changed - **core**: Render widgets no longer need to implement the `Query` trait. Data can only be queried if it's a state or wrapped with `Queryable`. (#pr @M-Adoo) diff --git a/core/src/builtin_widgets/focus_node.rs b/core/src/builtin_widgets/focus_node.rs index 4b5db7652..8995c02f4 100644 --- a/core/src/builtin_widgets/focus_node.rs +++ b/core/src/builtin_widgets/focus_node.rs @@ -69,13 +69,11 @@ mod tests { let id = tree.content_root(); let node = id.get(&tree.arena).unwrap(); let mut cnt = 0; - node.query_type_inside_first(|b: &MixBuiltin| { + node.query_all_iter::().for_each(|b| { if b.contain_flag(BuiltinFlags::Focus) { cnt += 1; } - true }); - assert_eq!(cnt, 1); } } diff --git a/core/src/builtin_widgets/mix_builtin.rs b/core/src/builtin_widgets/mix_builtin.rs index 879aee914..a1a6349c5 100644 --- a/core/src/builtin_widgets/mix_builtin.rs +++ b/core/src/builtin_widgets/mix_builtin.rs @@ -349,28 +349,31 @@ fn life_fn_once_to_fn_mut( impl ComposeChild for MixBuiltin { type Child = Widget; #[inline] - fn compose_child(this: impl StateWriter, child: Self::Child) -> impl WidgetBuilder { + fn compose_child( + this: impl StateWriter, mut child: Self::Child, + ) -> impl WidgetBuilder { move |ctx: &BuildCtx| match this.try_into_value() { Ok(this) => { let mut this = Some(this); - child + if let Some(m) = child .id() .assert_get(&ctx.tree.borrow().arena) - .query_most_outside(|m: &MixBuiltin| { - let this = this.take().unwrap(); - if !m.contain_flag(BuiltinFlags::Focus) && this.contain_flag(BuiltinFlags::Focus) { - this.callbacks_for_focus_node(); - } - m.merge(this) - }); + .query_ref::() + { + let this = unsafe { this.take().unwrap_unchecked() }; + if !m.contain_flag(BuiltinFlags::Focus) && this.contain_flag(BuiltinFlags::Focus) { + this.callbacks_for_focus_node(); + } + m.merge(this); + } + // We do not use an else branch here, due to the borrow conflict of the `ctx`. if let Some(this) = this { if this.contain_flag(BuiltinFlags::Focus) { this.callbacks_for_focus_node(); } - child.attach_data(Queryable(this), ctx) - } else { - child + child = child.attach_data(Queryable(this), ctx); } + child } Err(this) => { if this.read().contain_flag(BuiltinFlags::Focus) { diff --git a/core/src/context/build_ctx.rs b/core/src/context/build_ctx.rs index 44a15dc2d..0f9580673 100644 --- a/core/src/context/build_ctx.rs +++ b/core/src/context/build_ctx.rs @@ -123,11 +123,13 @@ impl<'a> BuildCtx<'a> { let arena = &self.tree.borrow().arena; p.ancestors(arena).any(|p| { - p.assert_get(arena) - .query_type_inside_first(|t: &Sc| { - themes.push(t.clone()); - matches!(t.deref(), Theme::Inherit(_)) - }); + for t in p.assert_get(arena).query_all_iter::>() { + themes.push(t.clone()); + if matches!(&**t, Theme::Full(_)) { + break; + } + } + matches!(themes.last().map(Sc::deref), Some(Theme::Full(_))) }); themes diff --git a/core/src/context/widget_ctx.rs b/core/src/context/widget_ctx.rs index 5293c795e..afaad8547 100644 --- a/core/src/context/widget_ctx.rs +++ b/core/src/context/widget_ctx.rs @@ -72,7 +72,6 @@ pub trait WidgetCtx { pub(crate) trait WidgetCtxImpl { fn id(&self) -> WidgetId; - // todo: return sc instead of rc fn current_wnd(&self) -> Rc; #[inline] @@ -201,7 +200,8 @@ impl WidgetCtx for T { ) -> Option { self.with_tree(|tree| { id.assert_get(&tree.arena) - .query_most_outside(callback) + .query_ref::() + .map(|r| callback(&r)) }) } diff --git a/core/src/data_widget.rs b/core/src/data_widget.rs index 4d26dcca4..6da88e370 100644 --- a/core/src/data_widget.rs +++ b/core/src/data_widget.rs @@ -47,7 +47,7 @@ impl Widget { /// /// User can query the state or its value type. pub fn try_unwrap_state_and_attach( - self, data: impl StateReader, ctx: &BuildCtx, + self, data: impl StateWriter, ctx: &BuildCtx, ) -> Widget { match data.try_into_value() { Ok(data) => self.attach_data(Queryable(data), ctx), @@ -70,37 +70,32 @@ impl RenderProxy for DataAttacher { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self.render.as_ref() } + fn proxy(&self) -> Self::Target<'_> { self.render.as_ref() } } impl Query for DataAttacher { - fn query_inside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.render.query_inside_first(type_id, callback) - && self.data.query_inside_first(type_id, callback) + fn query_all(&self, type_id: TypeId) -> smallvec::SmallVec<[QueryHandle; 1]> { + let mut types = self.render.query_all(type_id); + types.extend(self.data.query_all(type_id)); + types } - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.data.query_outside_first(type_id, callback) - && self.render.query_outside_first(type_id, callback) + fn query(&self, type_id: TypeId) -> Option { + self + .data + .query(type_id) + .or_else(|| self.render.query(type_id)) } } impl Query for AnonymousAttacher { - fn query_inside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.render.query_inside_first(type_id, callback) + #[inline] + fn query_all(&self, type_id: TypeId) -> smallvec::SmallVec<[QueryHandle; 1]> { + self.render.query_all(type_id) } - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.render.query_outside_first(type_id, callback) - } + #[inline] + fn query(&self, type_id: TypeId) -> Option { self.render.query(type_id) } } impl RenderProxy for AnonymousAttacher { @@ -110,21 +105,15 @@ impl RenderProxy for AnonymousAttacher { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self.render.as_ref() } + fn proxy(&self) -> Self::Target<'_> { self.render.as_ref() } } impl Query for Queryable { - #[inline] - fn query_inside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.query_outside_first(type_id, callback) + fn query_all(&self, type_id: TypeId) -> smallvec::SmallVec<[QueryHandle; 1]> { + self.query(type_id).into_iter().collect() } - #[inline] - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - if type_id == TypeId::of::() { callback(&self.0) } else { true } + fn query(&self, type_id: TypeId) -> Option { + (type_id == self.0.type_id()).then(|| QueryHandle::new(&self.0)) } } diff --git a/core/src/events/dispatcher.rs b/core/src/events/dispatcher.rs index 6cb0d89fc..318d949d5 100644 --- a/core/src/events/dispatcher.rs +++ b/core/src/events/dispatcher.rs @@ -159,14 +159,9 @@ impl Dispatcher { let nearest_focus = self.pointer_down_uid.and_then(|wid| { wid.ancestors(&tree.arena).find(|id| { - let mut is_focus_node = false; - if let Some(w) = id.get(&tree.arena) { - w.query_type_outside_first(|m: &MixBuiltin| { - is_focus_node |= m.contain_flag(BuiltinFlags::Focus); - !is_focus_node - }); - } - is_focus_node + id.get(&tree.arena) + .and_then(|w| w.query_ref::()) + .map_or(false, |m| m.contain_flag(BuiltinFlags::Focus)) }) }); if let Some(focus_id) = nearest_focus { diff --git a/core/src/events/focus_mgr.rs b/core/src/events/focus_mgr.rs index 45c6e5e14..c6a9e179f 100644 --- a/core/src/events/focus_mgr.rs +++ b/core/src/events/focus_mgr.rs @@ -339,16 +339,11 @@ impl FocusManager { .find_map(|wid| self.node_ids.get(&wid).copied())?; self.scope_list(node_id).find(|id| { - let mut has_ignore = false; - self.get(*id).and_then(|n| n.wid).map(|wid| { - wid - .get(arena)? - .query_most_inside(|s: &FocusScope| { - has_ignore = s.skip_descendants; - !has_ignore - }) - }); - has_ignore + self + .get(*id) + .and_then(|n| n.wid) + .and_then(|wid| wid.get(arena)?.query_ref::()) + .map_or(false, |s| s.skip_descendants) }) } @@ -357,21 +352,22 @@ impl FocusManager { let tree = wnd.widget_tree.borrow(); scope_id .and_then(|id| id.get(&tree.arena)) - .and_then(|r| r.query_most_inside(|s: &FocusScope| s.clone())) + .and_then(|r| r.query_ref::().map(|s| s.clone())) .unwrap_or_default() } fn tab_index(&self, node_id: NodeId) -> i16 { let wnd = self.window(); - let get_index = || { - let wid = self.get(node_id)?.wid?; - let tree = wnd.widget_tree.borrow(); - let r = wid.get(&tree.arena)?; - r.query_most_outside(|s: &MixBuiltin| s.get_tab_index()) - }; - - get_index().unwrap_or(0) + self + .get(node_id) + .and_then(|n| n.wid) + .and_then(|wid| { + let tree = wnd.widget_tree.borrow(); + let m = wid.get(&tree.arena)?.query_ref::()?; + Some(m.get_tab_index()) + }) + .unwrap_or_default() } fn insert_node(&mut self, parent: NodeId, node_id: NodeId, wid: WidgetId, arena: &TreeArena) { diff --git a/core/src/lib.rs b/core/src/lib.rs index ae912af68..643513d91 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -22,6 +22,7 @@ pub mod widget_children; pub mod window; pub use rxrust; pub mod overlay; +pub mod query; pub mod prelude { pub use log; @@ -34,6 +35,7 @@ pub mod prelude { pub use ribir_text::*; #[doc(hidden)] pub use rxrust::prelude::*; + pub use smallvec; #[doc(no_inline)] pub use crate::builtin_widgets::*; @@ -61,6 +63,7 @@ pub mod prelude { pub use crate::window::Window; pub use crate::{ animation::*, + query::*, ticker::{Duration, Instant}, }; } diff --git a/core/src/pipe.rs b/core/src/pipe.rs index 6faf7a202..3c886499f 100644 --- a/core/src/pipe.rs +++ b/core/src/pipe.rs @@ -662,34 +662,42 @@ fn update_children_key_status(old: WidgetId, new: WidgetId, ctx: &BuildCtx) { match (o_first == o_last, n_first == n_last) { (true, true) => update_key_status_single(o_first, n_first, ctx), (true, false) => { - inspect_key(o_first, ctx, |old_key| { + if let Some(old_key) = ctx + .assert_get(o_first) + .query_ref::>() + { let o_key = old_key.key(); new.children(tree).any(|n| { - inspect_key(n, ctx, |new_key| { + if let Some(new_key) = ctx.assert_get(n).query_ref::>() { let same_key = o_key == new_key.key(); if same_key { - update_key_states(old_key, o_first, new_key, n, ctx); + update_key_states(&**old_key, o_first, &**new_key, n, ctx); } same_key - }) - .unwrap_or(false) + } else { + false + } }); - }); + } } (false, true) => { - inspect_key(n_first, ctx, |new_key| { + if let Some(new_key) = ctx + .assert_get(n_first) + .query_ref::>() + { let n_key = new_key.key(); old.children(tree).any(|o| { - inspect_key(o, ctx, |old_key| { + if let Some(old_key) = ctx.assert_get(o).query_ref::>() { let same_key = old_key.key() == n_key; if same_key { - update_key_states(old_key, o, new_key, n_first, ctx); + update_key_states(&**old_key, o, &**new_key, n_first, ctx); } same_key - }) - .unwrap_or(false) - }) - }); + } else { + false + } + }); + } } (false, false) => update_key_state_multi(old.children(tree), new.children(tree), ctx), } @@ -698,13 +706,13 @@ fn update_children_key_status(old: WidgetId, new: WidgetId, ctx: &BuildCtx) { } fn update_key_status_single(old: WidgetId, new: WidgetId, ctx: &BuildCtx) { - inspect_key(old, ctx, |old_key| { - inspect_key(new, ctx, |new_key| { + if let Some(old_key) = ctx.assert_get(old).query_ref::>() { + if let Some(new_key) = ctx.assert_get(new).query_ref::>() { if old_key.key() == new_key.key() { - update_key_states(old_key, old, new_key, new, ctx) + update_key_states(&**old_key, old, &**new_key, new, ctx); } - }) - }); + } + } } fn update_key_state_multi( @@ -712,28 +720,24 @@ fn update_key_state_multi( ) { let mut old_key_list = ahash::HashMap::default(); for o in old { - inspect_key(o, ctx, |old_key: &dyn AnyKey| { + if let Some(old_key) = ctx.assert_get(o).query_ref::>() { old_key_list.insert(old_key.key(), o); - }); + } } if !old_key_list.is_empty() { for n in new { - inspect_key(n, ctx, |new_key| { + if let Some(new_key) = ctx.assert_get(n).query_ref::>() { if let Some(o) = old_key_list.get(&new_key.key()).copied() { - inspect_key(o, ctx, |old_key| update_key_states(old_key, o, new_key, n, ctx)); + if let Some(old_key) = ctx.assert_get(o).query_ref::>() { + update_key_states(&**old_key, o, &**new_key, n, ctx); + } } - }); + } } } } -fn inspect_key(id: WidgetId, ctx: &BuildCtx, mut cb: impl FnMut(&dyn AnyKey) -> R) -> Option { - ctx - .assert_get(id) - .query_most_outside::, _>(|key_widget| cb(key_widget.deref())) -} - fn update_key_states( old_key: &dyn AnyKey, old: WidgetId, new_key: &dyn AnyKey, new: WidgetId, ctx: &BuildCtx, ) { @@ -978,25 +982,29 @@ fn set_pos_of_multi(widgets: &[WidgetId], ctx: &BuildCtx) { widgets.iter().enumerate().for_each(|(pos, wid)| { wid .assert_get(arena) - .query_type_outside_first(|info: &DynInfo| { - info.set_pos_of_multi(pos); - true - }); + .query_all_iter::() + .for_each(|info| info.set_pos_of_multi(pos)) }); } fn query_info_outside_until( id: WidgetId, to: &Sc, ctx: &BuildCtx, mut cb: impl FnMut(&DynInfo), ) { - id.assert_get(&ctx.tree.borrow().arena) - .query_type_outside_first(|info: &DynInfo| { - cb(info); - - info - .as_any() - .downcast_ref::>() - .map_or(true, |info| !Sc::ptr_eq(info, to)) - }); + for info in id + .assert_get(&ctx.tree.borrow().arena) + .query_all_iter::() + .rev() + { + cb(&info); + + if info + .as_any() + .downcast_ref::>() + .map_or(false, |info| Sc::ptr_eq(info, to)) + { + break; + } + } } fn pipe_priority_value(info: &Sc, handle: BuildCtxHandle) -> i64 @@ -1018,24 +1026,23 @@ where } impl Query for PipeNode { - fn query_inside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { + fn query_all(&self, type_id: TypeId) -> smallvec::SmallVec<[QueryHandle; 1]> { let p = self.as_ref(); - if !p.data.query_inside_first(type_id, callback) { - return false; + let mut types = p.data.query_all(type_id); + if type_id == TypeId::of::() { + types.push(QueryHandle::new(&p.dyn_info)); } - if type_id == TypeId::of::() { callback(&p.dyn_info) } else { true } + + types } - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { + fn query(&self, type_id: TypeId) -> Option { let p = self.as_ref(); - if type_id == TypeId::of::() && !callback(&p.dyn_info) { - return false; + if type_id == TypeId::of::() { + Some(QueryHandle::new(&p.dyn_info)) + } else { + p.data.query(type_id) } - p.data.query_outside_first(type_id, callback) } } @@ -1046,7 +1053,7 @@ impl RenderProxy for PipeNode { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { &*self.as_ref().data } + fn proxy(&self) -> Self::Target<'_> { &*self.as_ref().data } } #[cfg(test)] diff --git a/core/src/query.rs b/core/src/query.rs new file mode 100644 index 000000000..eae31c338 --- /dev/null +++ b/core/src/query.rs @@ -0,0 +1,259 @@ +use std::any::{Any, TypeId}; + +use smallvec::SmallVec; + +use crate::state::{ + MapReader, MapWriterAsReader, ReadRef, Reader, StateReader, StateWriter, WriteRef, +}; + +/// A type can composed by many types, this trait help us to query the type and +/// the inner type by its type id, and call the callback one by one with a `& +/// dyn Any` of the target type. You can control if you want to continue query +/// by return `true` or `false` in the callback. +pub trait Query: Any { + /// Queries all types that match the provided type id, returning their handles + /// in an inside-to-outside order. + fn query_all(&self, type_id: TypeId) -> SmallVec<[QueryHandle; 1]>; + + /// Queries the type that matches the provided type id, returning its handle. + /// This method always returns the outermost type. + fn query(&self, type_id: TypeId) -> Option; +} + +/// A dynamic handle to a query result of a data, so we can use it in a trait +/// object. +pub struct QueryHandle<'a>(InnerHandle<'a>); + +/// A reference to a query result of a data, it's similar to `&T`. +pub struct QueryRef<'a, T> { + pub(crate) type_ref: &'a T, + pub(crate) _data: Option>, +} + +impl<'a> QueryHandle<'a> { + pub fn new(r: &'a dyn Any) -> Self { QueryHandle(InnerHandle::Ref(r)) } + + /// Downcast the to type `T` and returns a reference to it, + /// return `None` if the type not match + pub fn downcast_ref(&self) -> Option<&T> { + match self.0 { + InnerHandle::Ref(r) => r.downcast_ref::(), + InnerHandle::Owned(ref o) => query_downcast_ref(o.as_ref()), + } + } + + /// Attempts to downcast to type `T` and returns a mutable reference + /// to it. If the types do not match, it returns `None`. + /// + /// This method can only return a mutable reference if the handle points + /// to a `WriteRef`. This is because in Ribir, the final tree is immutable by + /// default. Any modifications to the tree can only be made through the + /// `WriteRef` of the `StateWriter`. + pub fn downcast_mut(&mut self) -> Option<&mut T> { + let InnerHandle::Owned(ref mut o) = self.0 else { + return None; + }; + (o.query_type() == TypeId::of::>()).then(|| { + // SAFETY: the creater guarantees that the query type is `WriteRef`, + unsafe { &mut **(o.as_mut() as *mut dyn QueryResult as *mut WriteRef<'a, T>) } + }) + } + + pub(crate) fn owned(o: Box) -> Self { QueryHandle(InnerHandle::Owned(o)) } + + pub fn into_ref(self) -> Option> { + match self.0 { + InnerHandle::Ref(r) if r.type_id() == TypeId::of::() => { + Some(QueryRef { type_ref: r.downcast_ref::().unwrap(), _data: None }) + } + InnerHandle::Owned(o) => { + let r = query_downcast_ref(o.as_ref()); + // hold the _data to keep the data alive + r.map(|r| QueryRef { type_ref: r, _data: Some(o) }) + } + _ => None, + } + } + + pub fn into_mut(self) -> Option> { + let InnerHandle::Owned(o) = self.0 else { + return None; + }; + (o.query_type() == TypeId::of::>()).then(|| { + // SAFETY: the creater guarantees that the query type is `WriteRef`, + let w_r = unsafe { + let ptr = Box::into_raw(o); + Box::from_raw(ptr as *mut WriteRef<'a, T>) + }; + *w_r + }) + } +} + +fn query_downcast_ref<'a, T: Any>(q: &(dyn QueryResult + 'a)) -> Option<&'a T> { + let q_type = q.query_type(); + if q_type == TypeId::of::() { + // SAFETY: the creater guarantees that the query type is `T`, + let t = unsafe { &*(q as *const dyn QueryResult as *const T) }; + Some(t) + } else if q_type == TypeId::of::>() { + // SAFETY: the creater guarantees that the query type is `WriteRef`, + let wr = unsafe { &*(q as *const dyn QueryResult as *const WriteRef<'a, T>) }; + Some(wr) + } else if q_type == TypeId::of::>() { + // SAFETY: the creater guarantees that the query type is `WriteRef`, + let rr = unsafe { &*(q as *const dyn QueryResult as *const ReadRef<'a, T>) }; + Some(rr) + } else { + None + } +} +enum InnerHandle<'a> { + Ref(&'a dyn Any), + Owned(Box), +} + +pub(crate) trait QueryResult { + fn query_type(&self) -> TypeId; +} + +impl<'a> QueryResult for &'a dyn Any { + fn query_type(&self) -> TypeId { Any::type_id(*self) } +} + +impl<'a, T: Any> QueryResult for WriteRef<'a, T> { + fn query_type(&self) -> TypeId { TypeId::of::>() } +} + +impl<'a, T: Any> QueryResult for ReadRef<'a, T> { + fn query_type(&self) -> TypeId { TypeId::of::>() } +} + +impl<'a, T> std::ops::Deref for QueryRef<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { self.type_ref } +} + +impl Query for T +where + T::Value: 'static + Sized, +{ + fn query_all(&self, type_id: TypeId) -> smallvec::SmallVec<[QueryHandle; 1]> { + // The value of the writer and the writer itself cannot be queried + // at the same time. + self.query(type_id).into_iter().collect() + } + + fn query(&self, type_id: TypeId) -> Option { + if type_id == TypeId::of::() { + Some(QueryHandle::owned(Box::new(self.write()))) + } else if type_id == self.type_id() { + Some(QueryHandle::new(self)) + } else { + None + } + } +} + +macro_rules! impl_query_for_reader { + () => { + // The value of the reader and the reader itself cannot be queried + // at the same time. + fn query_all(&self, type_id: TypeId) -> SmallVec<[QueryHandle; 1]> { + self.query(type_id).into_iter().collect() + } + + fn query(&self, type_id: TypeId) -> Option { + if type_id == TypeId::of::() { + Some(QueryHandle::owned(Box::new(self.read()))) + } else if type_id == self.type_id() { + Some(QueryHandle::new(self)) + } else { + None + } + } + }; +} + +impl Query for MapReader +where + Self: StateReader, + V: Any, +{ + impl_query_for_reader!(); +} + +impl Query for MapWriterAsReader +where + Self: StateReader, + V: Any, +{ + impl_query_for_reader!(); +} + +impl Query for Reader { + impl_query_for_reader!(); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + data_widget::Queryable, + reset_test_env, + state::{PartData, State, StateReader, StateWriter}, + }; + + #[test] + fn query_ref() { + reset_test_env!(); + + struct X; + let x = Queryable(X); + let mut h = x.query(TypeId::of::()).unwrap(); + assert!(h.downcast_ref::().is_some()); + assert!(h.downcast_mut::().is_none()); + assert!(h.into_ref::().is_some()); + let h = x.query(TypeId::of::()).unwrap(); + assert!(h.into_mut::().is_none()); + } + + #[test] + fn query_state() { + reset_test_env!(); + + let x = State::value(0i32); + let mut h = x.query(TypeId::of::()).unwrap(); + assert!(h.downcast_ref::().is_some()); + assert!(h.downcast_mut::().is_some()); + assert!(h.into_mut::().is_some()); + } + + #[test] + fn query_split_state() { + reset_test_env!(); + + struct X { + a: i32, + _b: i32, + } + + let x = State::value(X { a: 0, _b: 1 }); + let y = x.split_writer(|x| PartData::from_ref_mut(&mut x.a)); + let mut h = y.query(TypeId::of::()).unwrap(); + assert!(h.downcast_ref::().is_some()); + assert!(h.downcast_mut::().is_some()); + } + + #[test] + fn query_reader_only() { + reset_test_env!(); + + let x = State::value(0i32).clone_reader(); + let mut h = x.query(TypeId::of::()).unwrap(); + assert!(h.downcast_ref::().is_some()); + assert!(h.downcast_mut::().is_none()); + assert!(h.into_mut::().is_none()); + } +} diff --git a/core/src/render_helper.rs b/core/src/render_helper.rs index 1b86b1b48..770f238af 100644 --- a/core/src/render_helper.rs +++ b/core/src/render_helper.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use ribir_algo::Sc; -use state_cell::{StateCell, ValueRef}; +use state_cell::{ReadRef, StateCell}; use crate::prelude::*; @@ -11,22 +11,24 @@ pub trait RenderProxy { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r>; + fn proxy(&self) -> Self::Target<'_>; } pub(crate) struct PureRender(pub R); impl Query for PureRender { - fn query_inside_first(&self, _: TypeId, _: &mut dyn FnMut(&dyn Any) -> bool) -> bool { true } + fn query_all(&self, _: TypeId) -> smallvec::SmallVec<[QueryHandle; 1]> { + smallvec::SmallVec::new() + } - fn query_outside_first(&self, _: TypeId, _: &mut dyn FnMut(&dyn Any) -> bool) -> bool { true } + fn query(&self, _: TypeId) -> Option { None } } impl RenderProxy for PureRender { type R = R; type Target<'r> =&'r R where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { &self.0 } + fn proxy(&self) -> Self::Target<'_> { &self.0 } } impl Render for T { @@ -55,17 +57,17 @@ impl RenderProxy for RefCell { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self.borrow() } + fn proxy(&self) -> Self::Target<'_> { self.borrow() } } impl RenderProxy for StateCell { type R = R; - type Target<'r> = ValueRef<'r, R> + type Target<'r> = ReadRef<'r, R> where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self.read() } + fn proxy(&self) -> Self::Target<'_> { self.read() } } impl RenderProxy for Sc { @@ -75,7 +77,7 @@ impl RenderProxy for Sc { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self } + fn proxy(&self) -> Self::Target<'_> { self } } impl RenderProxy for Resource { @@ -85,5 +87,5 @@ impl RenderProxy for Resource { where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self } + fn proxy(&self) -> Self::Target<'_> { self } } diff --git a/core/src/state.rs b/core/src/state.rs index 72a65fc64..0a75b414a 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -15,8 +15,8 @@ pub use map_state::*; pub use prior_op::*; use rxrust::ops::box_it::{BoxOp, CloneableBoxOp}; pub use splitted_state::*; -pub use state_cell::PartData; -use state_cell::{StateCell, ValueMutRef, ValueRef}; +pub use state_cell::{PartData, ReadRef}; +use state_cell::{StateCell, ValueMutRef}; pub use stateful::*; pub use watcher::*; @@ -148,10 +148,6 @@ pub trait StateWriter: StateWatcher { } } -/// Wraps a borrowed reference to a value in a state. -/// A wrapper type for an immutably borrowed value from a `StateReader`. -pub struct ReadRef<'a, V>(ValueRef<'a, V>); - pub struct WriteRef<'a, V> { value: ValueMutRef<'a, V>, control: &'a dyn WriterControl, @@ -180,7 +176,7 @@ impl StateReader for State { fn read(&self) -> ReadRef { match self.inner_ref() { - InnerState::Data(w) => ReadRef::new(w.read()), + InnerState::Data(w) => w.read(), InnerState::Stateful(w) => w.read(), } } @@ -266,51 +262,14 @@ impl State { } } -impl<'a, V> ReadRef<'a, V> { - pub(crate) fn new(r: ValueRef<'a, V>) -> ReadRef<'a, V> { ReadRef(r) } - - /// Make a new `ReadRef` by mapping the value of the current `ReadRef`. - pub fn map(mut r: ReadRef<'a, V>, f: impl FnOnce(&V) -> PartData) -> ReadRef<'a, U> { - ReadRef(ValueRef { value: f(&mut r.0.value), borrow: r.0.borrow }) - } - - /// Split the current `ReadRef` into two `ReadRef`s by mapping the value to - /// two parts. - pub fn map_split( - orig: ReadRef<'a, V>, f: impl FnOnce(&V) -> (PartData, PartData), - ) -> (ReadRef<'a, U>, ReadRef<'a, W>) { - let (a, b) = f(&*orig); - let borrow = orig.0.borrow.clone(); - - (ReadRef(ValueRef { value: a, borrow: borrow.clone() }), ReadRef(ValueRef { value: b, borrow })) - } - - pub(crate) fn mut_as_ref_map( - orig: ReadRef<'a, V>, f: impl FnOnce(&mut V) -> PartData, - ) -> ReadRef<'a, U> { - let ValueRef { value, borrow } = orig.0; - let value = match value { - PartData::PartRef(mut ptr) => unsafe { - // Safety: This method is used to map a state to a part of it. Although a `&mut - // T` is passed to the closure, it is the user's responsibility to - // ensure that the closure does not modify the state. - f(ptr.as_mut()) - }, - PartData::PartData(mut data) => f(&mut data), - }; - - ReadRef(ValueRef { value, borrow }) - } -} - impl<'a, V> WriteRef<'a, V> { pub fn map(mut orig: WriteRef<'a, V>, part_map: M) -> WriteRef<'a, U> where M: Fn(&mut V) -> PartData, { - let value = part_map(&mut orig.value); + let inner = part_map(&mut orig.value); let borrow = orig.value.borrow.clone(); - let value = ValueMutRef { value, borrow }; + let value = ValueMutRef { inner, borrow }; WriteRef { value, modified: false, modify_scope: orig.modify_scope, control: orig.control } } @@ -324,8 +283,8 @@ impl<'a, V> WriteRef<'a, V> { let WriteRef { control, modify_scope, modified, .. } = orig; let (a, b) = f(&mut *orig.value); let borrow = orig.value.borrow.clone(); - let a = ValueMutRef { value: a, borrow: borrow.clone() }; - let b = ValueMutRef { value: b, borrow }; + let a = ValueMutRef { inner: a, borrow: borrow.clone() }; + let b = ValueMutRef { inner: b, borrow }; ( WriteRef { value: a, modified, modify_scope, control }, WriteRef { value: b, modified, modify_scope, control }, @@ -339,14 +298,6 @@ impl<'a, V> WriteRef<'a, V> { pub fn forget_modifies(&mut self) -> bool { std::mem::replace(&mut self.modified, false) } } -impl<'a, W> Deref for ReadRef<'a, W> { - type Target = W; - - #[track_caller] - #[inline] - fn deref(&self) -> &Self::Target { &self.0 } -} - impl<'a, W> Deref for WriteRef<'a, W> { type Target = W; #[track_caller] @@ -451,25 +402,6 @@ impl MultiParent for State { } } -impl Query for T -where - T::Value: 'static + Sized, -{ - #[inline] - fn query_inside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.query_outside_first(type_id, callback) - } - - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - let any: &T::Value = &self.read(); - if type_id == any.type_id() { callback(any) } else { true } - } -} - macro_rules! impl_compose_builder { ($name:ident) => { impl ComposeBuilder for $name diff --git a/core/src/state/map_state.rs b/core/src/state/map_state.rs index b54441d3b..10a5dbe60 100644 --- a/core/src/state/map_state.rs +++ b/core/src/state/map_state.rs @@ -176,7 +176,7 @@ where Self: 'r; #[inline] - fn proxy<'r>(&'r self) -> Self::Target<'r> { self.read() } + fn proxy(&self) -> Self::Target<'_> { self.read() } } impl RenderProxy for MapWriterAsReader @@ -188,11 +188,11 @@ where type R = V; type Target<'r> = ReadRef<'r, V> - + where Self: 'r; - fn proxy<'r>(&'r self) -> Self::Target<'r> { self.read() } + fn proxy(&self) -> Self::Target<'_> { self.read() } } impl RenderBuilder for MapWriter diff --git a/core/src/state/splitted_state.rs b/core/src/state/splitted_state.rs index ec841e1fc..d54416d56 100644 --- a/core/src/state/splitted_state.rs +++ b/core/src/state/splitted_state.rs @@ -153,7 +153,7 @@ where orig.modify_scope.remove(ModifyScope::FRAMEWORK); orig.modified = true; let value = - ValueMutRef { value: (self.splitter)(&mut orig.value), borrow: orig.value.borrow.clone() }; + ValueMutRef { inner: (self.splitter)(&mut orig.value), borrow: orig.value.borrow.clone() }; WriteRef { value, modified: false, modify_scope, control: self } } diff --git a/core/src/state/state_cell.rs b/core/src/state/state_cell.rs index 0a5c3f934..ce3caa87a 100644 --- a/core/src/state/state_cell.rs +++ b/core/src/state/state_cell.rs @@ -33,7 +33,7 @@ impl StateCell { } #[track_caller] - pub(crate) fn read(&self) -> ValueRef { + pub(crate) fn read(&self) -> ReadRef { let borrow = &self.borrow_flag; let b = borrow.get().wrapping_add(1); borrow.set(b); @@ -57,8 +57,8 @@ impl StateCell { // SAFETY: `BorrowRef` ensures that there is only immutable access // to the value while borrowed. - let value = PartData::PartRef(unsafe { NonNull::new_unchecked(self.data.get()) }); - ValueRef { value, borrow: BorrowRef { borrow } } + let inner = PartData::PartRef(unsafe { NonNull::new_unchecked(self.data.get()) }); + ReadRef { inner, borrow: BorrowRef { borrow } } } pub(crate) fn write(&self) -> ValueMutRef<'_, W> { @@ -84,8 +84,8 @@ impl StateCell { borrow.set(UNUSED - 1); let v_ref = BorrowRefMut { borrow }; - let value = PartData::PartRef(unsafe { NonNull::new_unchecked(self.data.get()) }); - ValueMutRef { value, borrow: v_ref } + let inner = PartData::PartRef(unsafe { NonNull::new_unchecked(self.data.get()) }); + ValueMutRef { inner, borrow: v_ref } } pub(crate) fn is_unused(&self) -> bool { self.borrow_flag.get() == UNUSED } @@ -114,13 +114,13 @@ impl PartData { /// Caller should ensure that the data is not a copy. pub fn from_data(ptr_data: T) -> Self { PartData::PartData(ptr_data) } } -pub(crate) struct ValueRef<'a, T> { - pub(crate) value: PartData, +pub struct ReadRef<'a, T> { + pub(crate) inner: PartData, pub(crate) borrow: BorrowRef<'a>, } pub(crate) struct ValueMutRef<'a, T> { - pub(crate) value: PartData, + pub(crate) inner: PartData, pub(crate) borrow: BorrowRefMut<'a>, } @@ -201,19 +201,54 @@ impl BorrowRef<'_> { } } -impl<'a, T> Deref for ValueRef<'a, T> { +impl<'a, V> ReadRef<'a, V> { + /// Make a new `ReadRef` by mapping the value of the current `ReadRef`. + pub fn map(mut r: ReadRef<'a, V>, f: impl FnOnce(&V) -> PartData) -> ReadRef<'a, U> { + ReadRef { inner: f(&mut r.inner), borrow: r.borrow } + } + + /// Split the current `ReadRef` into two `ReadRef`s by mapping the value to + /// two parts. + pub fn map_split( + orig: ReadRef<'a, V>, f: impl FnOnce(&V) -> (PartData, PartData), + ) -> (ReadRef<'a, U>, ReadRef<'a, W>) { + let (a, b) = f(&*orig); + let borrow = orig.borrow.clone(); + + (ReadRef { inner: a, borrow: borrow.clone() }, ReadRef { inner: b, borrow }) + } + + pub(crate) fn mut_as_ref_map( + orig: ReadRef<'a, V>, f: impl FnOnce(&mut V) -> PartData, + ) -> ReadRef<'a, U> { + let ReadRef { inner: value, borrow } = orig; + let value = match value { + PartData::PartRef(mut ptr) => unsafe { + // Safety: This method is used to map a state to a part of it. Although a `&mut + // T` is passed to the closure, it is the user's responsibility to + // ensure that the closure does not modify the state. + f(ptr.as_mut()) + }, + PartData::PartData(mut data) => f(&mut data), + }; + + ReadRef { inner: value, borrow } + } +} + +impl<'a, T> Deref for ReadRef<'a, T> { type Target = T; #[inline] - fn deref(&self) -> &Self::Target { &self.value } + fn deref(&self) -> &Self::Target { &self.inner } } impl<'a, T> Deref for ValueMutRef<'a, T> { type Target = T; #[inline] - fn deref(&self) -> &Self::Target { &self.value } + fn deref(&self) -> &Self::Target { &self.inner } } impl<'a, T> DerefMut for ValueMutRef<'a, T> { #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } diff --git a/core/src/state/stateful.rs b/core/src/state/stateful.rs index b1d2afeca..9d6c34d13 100644 --- a/core/src/state/stateful.rs +++ b/core/src/state/stateful.rs @@ -51,7 +51,7 @@ impl StateReader for Stateful { type Reader = Reader; #[inline] - fn read(&self) -> ReadRef { ReadRef::new(self.data.read()) } + fn read(&self) -> ReadRef { self.data.read() } #[inline] fn clone_reader(&self) -> Self::Reader { Reader(self.data.clone()) } @@ -105,7 +105,7 @@ impl StateReader for Reader { type Reader = Self; #[inline] - fn read(&self) -> ReadRef { ReadRef::new(self.0.read()) } + fn read(&self) -> ReadRef { self.0.read() } #[inline] fn clone_reader(&self) -> Self { Reader(self.0.clone()) } diff --git a/core/src/widget.rs b/core/src/widget.rs index b4bc5eb8d..5d9ef102d 100644 --- a/core/src/widget.rs +++ b/core/src/widget.rs @@ -1,12 +1,11 @@ +use std::convert::Infallible; #[doc(hidden)] pub use std::{ any::{Any, TypeId}, marker::PhantomData, ops::Deref, }; -use std::{cell::RefCell, convert::Infallible}; -use ribir_algo::Sc; use rxrust::ops::box_it::CloneableBoxOp; use widget_id::RenderQueryable; @@ -66,22 +65,6 @@ pub type BoxedWidget = Box FnOnce(&'a BuildCtx<'b>) -> Widget>; /// widget. pub struct GenWidget(Box FnMut(&'a BuildCtx<'b>) -> Widget>); -/// A type can composed by many types, this trait help us to query the type and -/// the inner type by its type id, and call the callback one by one with a `& -/// dyn Any` of the target type. You can control if you want to continue query -/// by return `true` or `false` in the callback. -pub trait Query: Any { - /// Query the type in a inside first order, and apply the callback to it. - /// return what the callback return, hint if the query should continue. - fn query_inside_first(&self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool) - -> bool; - /// Query the type in a outside first order, and apply the callback to it, - /// return what the callback return, hint if the query should continue. - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool; -} - /// Trait to build a indirect widget into widget tree with `BuildCtx` in the /// build phase. You should not implement this trait directly, framework will /// auto implement this. @@ -205,36 +188,6 @@ impl Widget + 'static> From for GenWidget { fn from(f: F) -> Self { Self::new(f) } } -/// query self and proxy to the inner object. -macro_rules! impl_proxy_and_self_query { - ($($t:tt)*) => { - fn query_inside_first( - &self, - type_id: TypeId, - callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - if !self.$($t)*.query_inside_first(type_id, callback) { - return false - } - - type_id != self.type_id() || callback(self) - } - - fn query_outside_first( - &self, - type_id: TypeId, - callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - if type_id == self.type_id() && !callback(self) { - return false - } - self.$($t)*.query_outside_first(type_id, callback) - } - } -} - -pub(crate) use impl_proxy_and_self_query; - impl ComposeBuilder for C { #[inline] fn build(self, ctx: &BuildCtx) -> Widget { Compose::compose(State::value(self)).build(ctx) } @@ -251,20 +204,6 @@ impl> + 'static, C> ComposeChildBuilder for W } } -impl Query for Resource { - impl_proxy_and_self_query!(deref()); -} -impl Query for Sc { - impl_proxy_and_self_query!(deref()); -} -impl Query for RefCell { - impl_proxy_and_self_query!(borrow()); -} - -impl Query for StateCell { - impl_proxy_and_self_query!(read()); -} - pub(crate) fn hit_test_impl(ctx: &HitTestCtx, pos: Point) -> bool { ctx .box_rect() @@ -317,8 +256,6 @@ pub(crate) use multi_build_replace_impl; pub(crate) use multi_build_replace_impl_include_self; pub(crate) use repeat_and_replace; -use self::state_cell::StateCell; - impl Drop for Widget { fn drop(&mut self) { log::warn!("widget allocated but never used: {:?}", self.id); @@ -327,52 +264,3 @@ impl Drop for Widget { .with_ctx(|ctx| ctx.tree.borrow_mut().remove_subtree(self.id)); } } - -#[cfg(test)] -mod tests { - use super::*; - - struct X; - - impl Query for X { - fn query_inside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - if type_id == TypeId::of::() { callback(self) } else { true } - } - - fn query_outside_first( - &self, type_id: TypeId, callback: &mut dyn FnMut(&dyn Any) -> bool, - ) -> bool { - self.query_inside_first(type_id, callback) - } - } - - macro_rules! impl_wrap_test { - ($name:ident) => { - paste::paste! { - #[test] - fn [<$name:lower _support_query>]() { - let warp = $name::new(X); - let x_tid = X.type_id(); - let w_tid = warp.type_id(); - let mut hit = 0; - - let mut hit_fn = |_: &dyn Any| { - hit += 1; - true - }; - - warp.query_inside_first(x_tid, &mut hit_fn); - warp.query_outside_first(x_tid, &mut hit_fn); - warp.query_inside_first(w_tid, &mut hit_fn); - warp.query_outside_first(w_tid, &mut hit_fn); - assert_eq!(hit, 4); - } - } - }; - } - impl_wrap_test!(Sc); - impl_wrap_test!(RefCell); - impl_wrap_test!(Resource); -} diff --git a/core/src/widget_tree/widget_id.rs b/core/src/widget_tree/widget_id.rs index 04616ac99..582e4e028 100644 --- a/core/src/widget_tree/widget_id.rs +++ b/core/src/widget_tree/widget_id.rs @@ -2,11 +2,11 @@ use std::any::{Any, TypeId}; use indextree::{Arena, Node, NodeId}; -use super::WidgetTree; +use super::{Query, QueryHandle, QueryRef, WidgetTree, WriteRef}; use crate::{ context::{PaintingCtx, WidgetCtx}, data_widget::{AnonymousAttacher, DataAttacher}, - widget::{Query, Render}, + widget::Render, window::DelayEvent, }; @@ -219,51 +219,36 @@ pub(crate) fn new_node(arena: &mut TreeArena, node: Box) -> } impl<'a> dyn RenderQueryable + 'a { - #[inline] - pub fn query_type_inside_first(&self, mut callback: impl FnMut(&T) -> bool) -> bool { + /// Return a iterator of all reference of type `T` in this node. + pub fn query_all_iter(&self) -> impl DoubleEndedIterator> { self - .query_inside_first(TypeId::of::(), &mut |a| a.downcast_ref().map_or(true, &mut callback)) + .query_all(TypeId::of::()) + .into_iter() + .filter_map(QueryHandle::into_ref) } - #[inline] - pub fn query_type_outside_first(&self, mut callback: impl FnMut(&T) -> bool) -> bool { + /// Return a iterator of all mutable reference of type `T` in this node. + pub fn query_all_iter_write(&self) -> impl DoubleEndedIterator> { self - .query_outside_first(TypeId::of::(), &mut |a| a.downcast_ref().map_or(true, &mut callback)) + .query_all(TypeId::of::()) + .into_iter() + .filter_map(QueryHandle::into_mut) } - /// Query the most inside type match `T`, and apply the callback to it, return - /// what the callback return. - pub fn query_most_inside(&self, callback: impl FnOnce(&T) -> R) -> Option { - let mut callback = Some(callback); - let mut res = None; - self.query_type_inside_first(|a| { - let cb = callback.take().expect("should only call once"); - res = Some(cb(a)); - false - }); - res + /// Query the outermost of reference of type `T` in this node. + pub fn query_write(&self) -> Option> { + self + .query(TypeId::of::()) + .and_then(QueryHandle::into_mut) } - /// Query the most outside type match `T`, and apply the callback to it, - /// return what the callback return. - pub fn query_most_outside(&self, callback: impl FnOnce(&T) -> R) -> Option { - let mut callback = Some(callback); - let mut res = None; - self.query_type_outside_first(|a| { - let cb = callback.take().expect("should only call once"); - res = Some(cb(a)); - false - }); - res + /// Query the outermost of reference of type `T` in this node. + pub fn query_ref(&self) -> Option> { + self + .query(TypeId::of::()) + .and_then(QueryHandle::into_ref) } /// return if this object contain type `T` - pub fn contain_type(&self) -> bool { - let mut hit = false; - self.query_type_outside_first(|_: &T| { - hit = true; - false - }); - hit - } + pub fn contain_type(&self) -> bool { self.query(TypeId::of::()).is_some() } } diff --git a/core/src/window.rs b/core/src/window.rs index a876ff0a4..0c5252d46 100644 --- a/core/src/window.rs +++ b/core/src/window.rs @@ -340,8 +340,8 @@ impl Window { let tree = self.widget_tree.borrow(); let drop_conditional = wid .assert_get(&self.widget_tree.borrow().arena) - .query_most_outside(|d: &KeepAlive| !d.keep_alive) - .unwrap_or(true); + .query_ref::() + .map_or(true, |d| !d.keep_alive); let parent_dropped = parent.map_or(false, |p| { p.is_dropped(&tree.arena) || p.ancestors(&tree.arena).last() != Some(tree.root()) }); @@ -547,12 +547,12 @@ impl Window { // no way to mut access the inner data of node or destroy the node. let tree = unsafe { &*(&*self.widget_tree.borrow() as *const WidgetTree) }; id.assert_get(&tree.arena) - .query_type_inside_first(|m: &MixBuiltin| { + .query_all_iter::() + .for_each(|m| { if m.contain_flag(e.flags()) { m.dispatch(e); } - true - }); + }) } fn top_down_emit(&self, e: &mut Event, bottom: WidgetId, up: Option) { @@ -564,7 +564,9 @@ impl Window { path.iter().rev().all(|id| { id.assert_get(&tree.arena) - .query_type_outside_first(|m: &MixBuiltin| { + .query_all_iter::() + .rev() + .all(|m| { if m.contain_flag(e.flags()) { e.set_current_target(*id); m.dispatch(e); @@ -585,7 +587,8 @@ impl Window { .take_while(|id| Some(*id) != up) .all(|id| { id.assert_get(&tree.arena) - .query_type_inside_first(|m: &MixBuiltin| { + .query_all_iter::() + .all(|m| { if m.contain_flag(e.flags()) { e.set_current_target(id); m.dispatch(e); diff --git a/widgets/src/input.rs b/widgets/src/input.rs index 2f8c7d404..e34d7d4f9 100644 --- a/widgets/src/input.rs +++ b/widgets/src/input.rs @@ -359,7 +359,7 @@ where let placeholder = @ { placeholder.map(move |holder| @Text { visible: pipe!(SelectableText::text(&*$this).is_empty()), - text: pipe!((*$holder).0.clone()), + text: pipe!($holder.0.clone()), }) };