commit 5fde3277a1a795adf3fd5e91b212b33eb7886244
parent d19e4b1d2bb8300b22f0c6c032c6aeb6cd7f9156
Author: William Casarin <jb55@jb55.com>
Date: Thu, 6 Mar 2025 15:10:47 -0800
notedeck: add debouncer util
I wanted this separate from the timed serializer so I could use it for
other things
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
3 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/crates/notedeck/src/debouncer.rs b/crates/notedeck/src/debouncer.rs
@@ -0,0 +1,35 @@
+use std::time::{Duration, Instant};
+
+/// A simple debouncer that tracks when an action was last performed
+/// and determines if enough time has passed to perform it again.
+#[derive(Debug)]
+pub struct Debouncer {
+ delay: Duration,
+ last_action: Instant,
+}
+
+impl Debouncer {
+ /// Creates a new Debouncer with the specified delay
+ pub fn new(delay: Duration) -> Self {
+ Self {
+ delay,
+ last_action: Instant::now() - delay, // Start ready to act
+ }
+ }
+
+ /// Sets a new delay value and returns self for method chaining
+ pub fn with_delay(mut self, delay: Duration) -> Self {
+ self.delay = delay;
+ self
+ }
+
+ /// Checks if enough time has passed since the last action
+ pub fn should_act(&self) -> bool {
+ self.last_action.elapsed() >= self.delay
+ }
+
+ /// Marks an action as performed, updating the timestamp
+ pub fn bounce(&mut self) {
+ self.last_action = Instant::now();
+ }
+}
diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs
@@ -2,6 +2,7 @@ mod accounts;
mod app;
mod args;
mod context;
+pub mod debouncer;
mod error;
pub mod filter;
pub mod fonts;
diff --git a/crates/notedeck/src/timed_serializer.rs b/crates/notedeck/src/timed_serializer.rs
@@ -1,14 +1,13 @@
-use std::time::{Duration, Instant};
-
+use crate::debouncer::Debouncer;
use crate::{storage, DataPath, DataPathType, Directory};
use serde::{Deserialize, Serialize};
-use tracing::info;
+use std::time::Duration;
+use tracing::info; // Adjust this import path as needed
pub struct TimedSerializer<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> {
directory: Directory,
file_name: String,
- delay: Duration,
- last_saved: Instant,
+ debouncer: Debouncer,
saved_item: Option<T>,
}
@@ -16,28 +15,24 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize
pub fn new(path: &DataPath, path_type: DataPathType, file_name: String) -> Self {
let directory = Directory::new(path.path(path_type));
let delay = Duration::from_millis(1000);
+ let debouncer = Debouncer::new(delay);
Self {
directory,
file_name,
- delay,
- last_saved: Instant::now() - delay,
+ debouncer,
saved_item: None,
}
}
pub fn with_delay(mut self, delay: Duration) -> Self {
- self.delay = delay;
+ self.debouncer = self.debouncer.with_delay(delay);
self
}
- fn should_save(&self) -> bool {
- self.last_saved.elapsed() >= self.delay
- }
-
// returns whether successful
pub fn try_save(&mut self, cur_item: T) -> bool {
- if self.should_save() {
+ if self.debouncer.should_act() {
if let Some(saved_item) = self.saved_item {
if saved_item != cur_item {
return self.save(cur_item);
@@ -53,7 +48,6 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize
if self.saved_item.is_some() {
return self.saved_item;
}
-
if let Ok(file_contents) = self.directory.get_file(self.file_name.clone()) {
if let Ok(item) = serde_json::from_str::<T>(&file_contents) {
return Some(item);
@@ -61,7 +55,6 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize
} else {
info!("Could not find file {}", self.file_name);
}
-
None
}
@@ -75,12 +68,11 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize
.is_ok()
{
info!("wrote item {}", serialized_item);
- self.last_saved = Instant::now();
+ self.debouncer.bounce();
self.saved_item = Some(cur_item);
return true;
}
}
-
false
}
}