# bouncing
Async debouncer for Rust/Tokio with cancellation support, max wait limits, and event hooks.
## Quick Start
```rust
use bouncing::Debouncer;
use std::time::Duration;
use tokio_util::sync::CancellationToken;
let cancel_token = CancellationToken::new();
let debouncer = Debouncer::new(Duration::from_millis(100), cancel_token.clone(), "my_task");
// Rapid calls - only the last one executes after 100ms of quiet
// check token.cancelled() for graceful shutdown
}).await;
```
## API
### Debouncer
Core debouncer - pass a new closure each call.
```rust
let debouncer = Debouncer::new(duration, cancel_token, "name")
.with_task_timeout(Duration::from_secs(5)) // abort timeout after cancel
.with_max_wait(Duration::from_secs(30)) // force execution after max wait
.with_event_handler(|event| { /* ... */ });
Trait-based - implement `DebouncedTask` on your type.
```rust
use bouncing::{DebouncedTask, TaskDebouncer};
struct MyTask { /* state */ }
impl DebouncedTask for MyTask {
async fn execute(&self, token: CancellationToken) {
// your work
}
}
let debouncer = TaskDebouncer::new(Duration::from_millis(100), cancel_token, "name", MyTask {});
debouncer.debounce().await;
```
## Cancellation
All task closures receive a `CancellationToken`. Check it for graceful shutdown:
```rust
_ = token.cancelled() => { /* cleanup */ }
_ = do_work() => {}
}
}).await;
```
**Exit states:**
- `Normal` - task completed
- `Cancelled` - task responded to cancellation
- `Aborted` - task didn't exit within timeout, was force-aborted
- `NotStarted` - timer cancelled before task started
## Max Wait
Prevents starvation when events fire continuously:
```rust
let debouncer = Debouncer::new(Duration::from_millis(100), token, "name")
.with_max_wait(Duration::from_secs(5)); // force run after 5s of continuous debouncing
```
## Events
Hook into lifecycle events:
```rust
use bouncing::DebounceEvent;
let debouncer = Debouncer::new(duration, token, "name")
.with_event_handler(|event| match event {
DebounceEvent::Debounced { instant, first_debounce_at, debounce_ends_at } => {}
DebounceEvent::Started { instant } => {}
DebounceEvent::Ended { instant, exit_status } => {}
});
```
## Builder Methods
All three debouncer types support:
- `with_task_timeout(Duration)` - time to wait for graceful exit before abort
- `with_max_wait(Duration)` - max time to debounce before forcing execution
- `with_event_handler(Fn)` - lifecycle event callback
- `stop()` - cancel current task and timer