Skip to content

Commit 34e4434

Browse files
authored
Merge pull request #818 from xStrom/bloom_docs
Add documentation, e.g. around bloom usage.
2 parents bb2d147 + 1f177a0 commit 34e4434

File tree

8 files changed

+129
-76
lines changed

8 files changed

+129
-76
lines changed

druid-shell/src/common_util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl<F: FnOnce(&dyn Any) + Send> IdleCallback for F {
5555
///
5656
/// This can be used safely from multiple threads.
5757
///
58-
/// The counter will overflow if `next()` iscalled 2^64 - 2 times.
58+
/// The counter will overflow if `next()` is called 2^64 - 2 times.
5959
/// If this is possible for your application, and reuse would be undesirable,
6060
/// use something else.
6161
pub struct Counter(AtomicU64);

druid/src/bloom.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,12 @@ impl<T: ?Sized + Hash> Bloom<T> {
7171
self.entry_count += 1;
7272
}
7373

74-
/// Return whether an item exists in the filter.
74+
/// Returns `true` if the item may have been added to the filter.
7575
///
7676
/// This can return false positives, but never false negatives.
77-
pub fn contains(&self, item: &T) -> bool {
77+
/// Thus `true` means that the item may have been added - or not,
78+
/// while `false` means that the item has definitely not been added.
79+
pub fn may_contain(&self, item: &T) -> bool {
7880
let mask = self.make_bit_mask(item);
7981
self.bits & mask == mask
8082
}
@@ -134,11 +136,11 @@ mod tests {
134136
let mut bloom = Bloom::default();
135137
for i in 0..100 {
136138
bloom.add(&i);
137-
assert!(bloom.contains(&i));
139+
assert!(bloom.may_contain(&i));
138140
}
139141
bloom.clear();
140142
for i in 0..100 {
141-
assert!(!bloom.contains(&i));
143+
assert!(!bloom.may_contain(&i));
142144
}
143145
}
144146

@@ -147,18 +149,18 @@ mod tests {
147149
let mut bloom1 = Bloom::default();
148150
bloom1.add(&0);
149151
bloom1.add(&1);
150-
assert!(!bloom1.contains(&2));
151-
assert!(!bloom1.contains(&3));
152+
assert!(!bloom1.may_contain(&2));
153+
assert!(!bloom1.may_contain(&3));
152154
let mut bloom2 = Bloom::default();
153155
bloom2.add(&2);
154156
bloom2.add(&3);
155-
assert!(!bloom2.contains(&0));
156-
assert!(!bloom2.contains(&1));
157+
assert!(!bloom2.may_contain(&0));
158+
assert!(!bloom2.may_contain(&1));
157159

158160
let bloom3 = bloom1.union(bloom2);
159-
assert!(bloom3.contains(&0));
160-
assert!(bloom3.contains(&1));
161-
assert!(bloom3.contains(&2));
162-
assert!(bloom3.contains(&3));
161+
assert!(bloom3.may_contain(&0));
162+
assert!(bloom3.may_contain(&1));
163+
assert!(bloom3.may_contain(&2));
164+
assert!(bloom3.may_contain(&3));
163165
}
164166
}

druid/src/contexts.rs

+66-25
Original file line numberDiff line numberDiff line change
@@ -240,49 +240,62 @@ impl<'a> EventCtx<'a> {
240240

241241
/// The focus status of a widget.
242242
///
243+
/// Returns `true` if this specific widget is focused.
244+
/// To check if any descendants are focused use [`has_focus`].
245+
///
243246
/// Focus means that the widget receives keyboard events.
244247
///
245248
/// A widget can request focus using the [`request_focus`] method.
246-
/// This will generally result in a separate event propagation of
247-
/// a `FocusChanged` method, including sending `false` to the previous
248-
/// widget that held focus.
249+
/// It's also possible to register for automatic focus via [`register_for_focus`].
249250
///
250-
/// Only one leaf widget at a time has focus. However, in a container
251-
/// hierarchy, all ancestors of that leaf widget are also invoked with
252-
/// `FocusChanged(true)`.
251+
/// If a widget gains or loses focus it will get a [`LifeCycle::FocusChanged`] event.
253252
///
254-
/// Discussion question: is "is_focused" a better name?
253+
/// Only one widget at a time is focused. However due to the way events are routed,
254+
/// all ancestors of that widget will also receive keyboard events.
255255
///
256256
/// [`request_focus`]: struct.EventCtx.html#method.request_focus
257+
/// [`register_for_focus`]: struct.LifeCycleCtx.html#method.register_for_focus
258+
/// [`LifeCycle::FocusChanged`]: enum.LifeCycle.html#variant.FocusChanged
259+
/// [`has_focus`]: struct.EventCtx.html#method.has_focus
260+
pub fn is_focused(&self) -> bool {
261+
self.focus_widget == Some(self.widget_id())
262+
}
263+
264+
/// The (tree) focus status of a widget.
265+
///
266+
/// Returns `true` if either this specific widget or any one of its descendants is focused.
267+
/// To check if only this specific widget is focused use [`is_focused`].
268+
///
269+
/// See [`is_focused`] for more information about focus.
270+
///
271+
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
257272
pub fn has_focus(&self) -> bool {
273+
// The bloom filter we're checking can return false positives.
258274
let is_child = self
259275
.focus_widget
260-
.map(|id| self.base_state.children.contains(&id))
276+
.map(|id| self.base_state.children.may_contain(&id))
261277
.unwrap_or(false);
262278
is_child || self.focus_widget == Some(self.widget_id())
263279
}
264280

265-
/// The (leaf) focus status of a widget. See [`has_focus`].
266-
///
267-
/// [`has_focus`]: struct.EventCtx.html#method.has_focus
268-
pub fn is_focused(&self) -> bool {
269-
self.focus_widget == Some(self.widget_id())
270-
}
271-
272281
/// Request keyboard focus.
273282
///
274-
/// See [`has_focus`] for more information.
283+
/// See [`is_focused`] for more information about focus.
275284
///
276-
/// [`has_focus`]: struct.EventCtx.html#method.has_focus
285+
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
277286
pub fn request_focus(&mut self) {
278287
self.base_state.request_focus = Some(FocusChange::Focus(self.widget_id()));
279288
}
280289

281290
/// Transfer focus to the next focusable widget.
282291
///
283292
/// This should only be called by a widget that currently has focus.
293+
///
294+
/// See [`is_focused`] for more information about focus.
295+
///
296+
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
284297
pub fn focus_next(&mut self) {
285-
if self.focus_widget == Some(self.widget_id()) {
298+
if self.is_focused() {
286299
self.base_state.request_focus = Some(FocusChange::Next);
287300
} else {
288301
log::warn!("focus_next can only be called by the currently focused widget");
@@ -292,8 +305,12 @@ impl<'a> EventCtx<'a> {
292305
/// Transfer focus to the previous focusable widget.
293306
///
294307
/// This should only be called by a widget that currently has focus.
308+
///
309+
/// See [`is_focused`] for more information about focus.
310+
///
311+
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
295312
pub fn focus_prev(&mut self) {
296-
if self.focus_widget == Some(self.widget_id()) {
313+
if self.is_focused() {
297314
self.base_state.request_focus = Some(FocusChange::Previous);
298315
} else {
299316
log::warn!("focus_prev can only be called by the currently focused widget");
@@ -303,8 +320,12 @@ impl<'a> EventCtx<'a> {
303320
/// Give up focus.
304321
///
305322
/// This should only be called by a widget that currently has focus.
323+
///
324+
/// See [`is_focused`] for more information about focus.
325+
///
326+
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
306327
pub fn resign_focus(&mut self) {
307-
if self.focus_widget == Some(self.widget_id()) {
328+
if self.is_focused() {
308329
self.base_state.request_focus = Some(FocusChange::Resign);
309330
} else {
310331
log::warn!("resign_focus can only be called by the currently focused widget");
@@ -414,6 +435,13 @@ impl<'a> LifeCycleCtx<'a> {
414435
}
415436

416437
/// Register this widget to be eligile to accept focus automatically.
438+
///
439+
/// This should only be called in response to a [`LifeCycle::WidgetAdded`] event.
440+
///
441+
/// See [`EventCtx::is_focused`] for more information about focus.
442+
///
443+
/// [`LifeCycle::WidgetAdded`]: enum.Lifecycle.html#variant.WidgetAdded
444+
/// [`EventCtx::is_focused`]: struct.EventCtx.html#method.is_focused
417445
pub fn register_for_focus(&mut self) {
418446
self.base_state.focus_chain.push(self.widget_id());
419447
}
@@ -557,20 +585,33 @@ impl<'a, 'b: 'a> PaintCtx<'a, 'b> {
557585
self.base_state.size()
558586
}
559587

560-
/// Query the focus state of the widget.
588+
/// The focus status of a widget.
589+
///
590+
/// Returns `true` if this specific widget is focused.
591+
/// To check if any descendants are focused use [`has_focus`].
592+
///
593+
/// See [`EventCtx::is_focused`] for more information about focus.
561594
///
562-
/// This is true only if this widget has focus.
595+
/// [`has_focus`]: #method.has_focus
596+
/// [`EventCtx::is_focused`]: struct.EventCtx.html#method.is_focused
563597
pub fn is_focused(&self) -> bool {
564598
self.focus_widget == Some(self.widget_id())
565599
}
566600

567-
/// The focus status of a widget.
601+
/// The (tree) focus status of a widget.
602+
///
603+
/// Returns `true` if either this specific widget or any one of its descendants is focused.
604+
/// To check if only this specific widget is focused use [`is_focused`].
605+
///
606+
/// See [`EventCtx::is_focused`] for more information about focus.
568607
///
569-
/// See [`has_focus`](struct.EventCtx.html#method.has_focus).
608+
/// [`is_focused`]: #method.is_focused
609+
/// [`EventCtx::is_focused`]: struct.EventCtx.html#method.is_focused
570610
pub fn has_focus(&self) -> bool {
611+
// The bloom filter we're checking can return false positives.
571612
let is_child = self
572613
.focus_widget
573-
.map(|id| self.base_state.children.contains(&id))
614+
.map(|id| self.base_state.children.may_contain(&id))
574615
.unwrap_or(false);
575616
is_child || self.focus_widget == Some(self.widget_id())
576617
}

druid/src/core.rs

+19-15
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
369369
let mut child_ctx = EventCtx {
370370
cursor: ctx.cursor,
371371
command_queue: ctx.command_queue,
372-
window: &ctx.window,
372+
window: ctx.window,
373373
window_id: ctx.window_id,
374374
base_state: &mut self.state,
375375
had_active,
@@ -446,7 +446,9 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
446446
Target::Window(_) => Event::Command(cmd.clone()),
447447
Target::Widget(id) if *id == child_ctx.widget_id() => Event::Command(cmd.clone()),
448448
Target::Widget(id) => {
449-
recurse = child_ctx.base_state.children.contains(id);
449+
// Recurse when the target widget could be our descendant.
450+
// The bloom filter we're checking can return false positives.
451+
recurse = child_ctx.base_state.children.may_contain(id);
450452
Event::TargetedCommand(*target, cmd.clone())
451453
}
452454
Target::Global => panic!("Target::Global should be converted before WidgetPod"),
@@ -496,7 +498,6 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
496498
self.state.children.clear();
497499
self.state.focus_chain.clear();
498500
}
499-
500501
self.state.children_changed
501502
}
502503
}
@@ -517,8 +518,10 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
517518
self.inner.lifecycle(ctx, &event, data, env);
518519
false
519520
} else {
520-
old.map(|id| self.state.children.contains(&id))
521-
.or_else(|| new.map(|id| self.state.children.contains(&id)))
521+
// Recurse when the target widgets could be our descendants.
522+
// The bloom filter we're checking can return false positives.
523+
old.map(|id| self.state.children.may_contain(&id))
524+
.or_else(|| new.map(|id| self.state.children.may_contain(&id)))
522525
.unwrap_or(false)
523526
}
524527
}
@@ -532,7 +535,9 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
532535
state_cell.set(self.state.clone());
533536
false
534537
} else {
535-
self.state.children.contains(&widget)
538+
// Recurse when the target widget could be our descendant.
539+
// The bloom filter we're checking can return false positives.
540+
self.state.children.may_contain(&widget)
536541
}
537542
}
538543
#[cfg(test)]
@@ -542,13 +547,12 @@ impl<T: Data, W: Widget<T>> WidgetPod<T, W> {
542547
}
543548
};
544549

545-
let mut child_ctx = LifeCycleCtx {
546-
command_queue: ctx.command_queue,
547-
base_state: &mut self.state,
548-
window_id: ctx.window_id,
549-
};
550-
551550
if recurse {
551+
let mut child_ctx = LifeCycleCtx {
552+
command_queue: ctx.command_queue,
553+
base_state: &mut self.state,
554+
window_id: ctx.window_id,
555+
};
552556
self.inner.lifecycle(&mut child_ctx, event, data, env);
553557
}
554558

@@ -691,9 +695,9 @@ mod tests {
691695
let env = Env::default();
692696

693697
widget.lifecycle(&mut ctx, &LifeCycle::WidgetAdded, &None, &env);
694-
assert!(ctx.base_state.children.contains(&ID_1));
695-
assert!(ctx.base_state.children.contains(&ID_2));
696-
assert!(ctx.base_state.children.contains(&ID_3));
698+
assert!(ctx.base_state.children.may_contain(&ID_1));
699+
assert!(ctx.base_state.children.may_contain(&ID_2));
700+
assert!(ctx.base_state.children.may_contain(&ID_3));
697701
assert_eq!(ctx.base_state.children.entry_count(), 7);
698702
}
699703
}

druid/src/event.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,13 @@ pub enum LifeCycle {
186186
},
187187
/// Called when the focus status changes.
188188
///
189-
/// This will always be called immediately after an event where a widget
190-
/// has requested focus.
189+
/// This will always be called immediately after a new widget gains focus.
190+
/// The newly focused widget will receive this with `true` and the widget
191+
/// that lost focus will receive this with `false`.
191192
///
192-
/// See [`has_focus`](struct.EventCtx.html#method.has_focus) for
193-
/// discussion about the focus status.
193+
/// See [`EventCtx::is_focused`] for more information about focus.
194+
///
195+
/// [`EventCtx::is_focused`]: struct.EventCtx.html#method.is_focused
194196
FocusChanged(bool),
195197
/// Testing only: request the `BaseState` of a specific widget.
196198
///

druid/src/tests/mod.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,13 @@ fn child_tracking() {
275275
harness.send_initial_events();
276276
let root = harness.get_state(id_4);
277277
assert_eq!(root.children.entry_count(), 3);
278-
assert!(root.children.contains(&id_1));
279-
assert!(root.children.contains(&id_2));
280-
assert!(root.children.contains(&id_3));
278+
assert!(root.children.may_contain(&id_1));
279+
assert!(root.children.may_contain(&id_2));
280+
assert!(root.children.may_contain(&id_3));
281281

282282
let split = harness.get_state(id_3);
283-
assert!(split.children.contains(&id_1));
284-
assert!(split.children.contains(&id_2));
283+
assert!(split.children.may_contain(&id_1));
284+
assert!(split.children.may_contain(&id_2));
285285
assert_eq!(split.children.entry_count(), 2);
286286
});
287287
}
@@ -302,18 +302,18 @@ fn register_after_adding_child() {
302302
Harness::create(String::new(), widget, |harness| {
303303
harness.send_initial_events();
304304

305-
assert!(harness.get_state(id_5).children.contains(&id_6));
306-
assert!(harness.get_state(id_5).children.contains(&id_1));
307-
assert!(harness.get_state(id_5).children.contains(&id_4));
305+
assert!(harness.get_state(id_5).children.may_contain(&id_6));
306+
assert!(harness.get_state(id_5).children.may_contain(&id_1));
307+
assert!(harness.get_state(id_5).children.may_contain(&id_4));
308308
assert_eq!(harness.get_state(id_5).children.entry_count(), 3);
309309

310310
harness.submit_command(REPLACE_CHILD, None);
311311

312-
assert!(harness.get_state(id_5).children.contains(&id_6));
313-
assert!(harness.get_state(id_5).children.contains(&id_4));
314-
assert!(harness.get_state(id_5).children.contains(&id_7));
315-
assert!(harness.get_state(id_5).children.contains(&id_2));
316-
assert!(harness.get_state(id_5).children.contains(&id_3));
312+
assert!(harness.get_state(id_5).children.may_contain(&id_6));
313+
assert!(harness.get_state(id_5).children.may_contain(&id_4));
314+
assert!(harness.get_state(id_5).children.may_contain(&id_7));
315+
assert!(harness.get_state(id_5).children.may_contain(&id_2));
316+
assert!(harness.get_state(id_5).children.may_contain(&id_3));
317317
assert_eq!(harness.get_state(id_5).children.entry_count(), 5);
318318
})
319319
}

0 commit comments

Comments
 (0)