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