euv_ui/hook/debounced_value/impl.rs
1use super::*;
2
3impl<T: Clone + PartialEq + Default + 'static> DebouncedValue<T> {
4 /// Schedules `next` to become the emitted value. The
5 /// commit happens on the next `tick` call at or after
6 /// `now + delay_ms`.
7 ///
8 /// Calling `set` repeatedly within `delay_ms` of each
9 /// other means only the last value wins — that's the
10 /// "debounce" contract.
11 ///
12 /// # Arguments
13 ///
14 /// - `T: Clone + PartialEq + Default + 'static` - A generic type parameter.
15 /// - `Instant` - A monotonic instant in time (`Instant`).
16 pub fn set(&self, next: T, now: Instant) {
17 self.get_state().set(DebounceState::Pending(now, next));
18 }
19
20 /// Drives the state machine forward.
21 ///
22 /// - If the state is `Idle`, this is a no-op.
23 /// - If the state is `Pending(set_at, value)`, this
24 /// emits `value` (writing it to the `value` signal)
25 /// iff `now - set_at >= delay_ms`. Otherwise the
26 /// pending value is preserved and the call returns
27 /// `false`.
28 ///
29 /// Returns `true` when a pending value was emitted,
30 /// `false` otherwise.
31 ///
32 /// # Arguments
33 ///
34 /// - `Instant` - A monotonic instant in time (`Instant`).
35 ///
36 /// # Returns
37 ///
38 /// - `bool` - A boolean.
39 pub fn tick(&self, now: Instant) -> bool {
40 match self.get_state().get() {
41 DebounceState::Idle => false,
42 DebounceState::Pending(set_at, _) => {
43 if now.duration_since(set_at).as_millis() >= u128::from(self.delay_ms) {
44 let pending: T = match self.get_state().get() {
45 DebounceState::Pending(_, value) => value,
46 DebounceState::Idle => unreachable!(),
47 };
48 self.get_value().set(pending);
49 self.get_state().set(DebounceState::Idle);
50 true
51 } else {
52 false
53 }
54 }
55 }
56 }
57
58 /// Cancels any pending value without emitting it.
59 /// The emitted value is left untouched.
60 pub fn cancel(&self) {
61 self.get_state().set(DebounceState::Idle);
62 }
63
64 /// Returns the currently emitted value as a snapshot.
65 ///
66 /// # Returns
67 ///
68 /// - `T` - The current value (or a snapshot thereof).
69 pub fn get(&self) -> T {
70 self.get_value().get()
71 }
72
73 /// Returns `true` when a value is waiting to be
74 /// emitted.
75 ///
76 /// # Returns
77 ///
78 /// - `bool` - `true` when a value is waiting to be emitted.
79 pub fn is_pending(&self) -> bool {
80 matches!(self.get_state().get(), DebounceState::Pending(_, _))
81 }
82}
83
84impl<T: Clone + PartialEq + Debug + Default + 'static> Display for DebouncedValue<T> {
85 /// Formats the [`DebouncedValue`] via the supplied formatter.
86 ///
87 /// # Arguments
88 ///
89 /// - `&mut Formatter<'_>` - The formatter receiving the formatted output.
90 ///
91 /// # Returns
92 ///
93 /// - `FmtResult` - Result of the formatting operation.
94 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
95 let pending: &DebounceState<T> = &self.get_state().get();
96 match pending {
97 DebounceState::Idle => {
98 write!(formatter, "DebouncedValue({:?})", self.get_value().get())
99 }
100 DebounceState::Pending(_, value) => {
101 write!(formatter, "DebouncedValue(pending={value:?})")
102 }
103 }
104 }
105}