situwaition/lib.rs
1//! Situwaition
2//!
3//! <hr>
4//!
5//! This library makes it easy to wait for a situation (cutely named "situWAITion") to complete.
6//!
7//! Situwaition can be used in contexts with or without async runtimes, and generally does what you'd expect (tm):
8//!
9//! ```
10//! use situwaition::wait_for;
11//!
12//! fn main() -> Result<(), Box<dyn Error>> {
13//! let value = 0;
14//!
15//! let result: Result<&str> = wait_for(|| match value == 5 {
16//! true => Ok("done!"),
17//! false => {
18//! value += 1; // NOTE: incrementing like this only works in a single threaded context!
19//! Err("not yet")
20//! },
21//! });
22//! }
23//! ```
24//!
25//! The example above demonstrates the synchronous usage, but `tokio` and `async-std` and corresponding modules are available as well.
26
27use std::{result::Result, time::Duration};
28
29use derive_builder::Builder;
30use thiserror::Error;
31
32#[cfg(any(feature = "tokio", feature = "async-std"))]
33use async_trait::async_trait;
34
35pub mod runtime;
36pub mod sync;
37
38const DEFAULT_SITUWAITION_TIMEOUT_MS: u64 = 3_000;
39const DEFAULT_SITUWAITION_CHECK_INTERVAL_MS: u64 = 250;
40
41pub use sync::wait_for;
42
43/// The type of error that is thrown when
44#[derive(Debug, Error)]
45pub enum SituwaitionError<E> {
46 /// Timeout from repeated failure
47 #[error("failed repeatedly until the timeout: {0}")]
48 TimeoutError(E),
49
50 #[error("check fn run exceeded the timeout")]
51 CheckTimeoutError,
52
53 /// A single conditoin failure
54 #[error("condition check failed: {0}")]
55 ConditionFailed(E),
56
57 #[error("unexpected error: {0}")]
58 UnexpectedError(String),
59}
60
61/// Options for a given situwaition
62#[allow(dead_code)]
63#[derive(Debug, Clone, Builder)]
64pub struct SituwaitionOpts {
65 /// The maximum time to wait for a situwaition
66 pub timeout: Duration,
67
68 /// How often to check for a passing condition.
69 /// Note that in the synchronous case, this determines how quickly
70 /// you can return *before* a check actually completes (i.e. timing in 100ms when check_fn takes 500ms)
71 pub check_interval: Duration,
72
73 /// Time to wait after a check has been performed.
74 /// Use this to avoid running resource-intensive checks too frequently
75 pub check_cooldown: Option<Duration>,
76}
77
78impl Default for SituwaitionOpts {
79 fn default() -> Self {
80 SituwaitionOpts {
81 timeout: Duration::from_millis(DEFAULT_SITUWAITION_TIMEOUT_MS),
82 check_interval: Duration::from_millis(DEFAULT_SITUWAITION_CHECK_INTERVAL_MS),
83 check_cooldown: None,
84 }
85 }
86}
87
88/// The basic requirements of any situwaition
89pub trait SituwaitionBase {
90 type Result;
91 type Error;
92
93 /// Retrieve the options associated with this situwaition
94 fn options(&self) -> &SituwaitionOpts;
95
96 /// Change the options associated with this situwaition
97 fn set_options(
98 &mut self,
99 update_fn: impl Fn(&SituwaitionOpts) -> SituwaitionOpts,
100 ) -> Result<(), SituwaitionError<()>>;
101}
102
103/// Synchronously executed situwaitions
104pub trait SyncSituwaition: SituwaitionBase {
105 /// Execute the situwaition, and wait until it resolves
106 /// or fails with a timeout
107 fn exec(&mut self) -> Result<Self::Result, SituwaitionError<Self::Error>>;
108}
109
110/// This trait represents a "situwaition" that can be a"waited", with tokio.
111/// note that how the waiting is done can differ by platform
112#[cfg(feature = "tokio")]
113#[async_trait]
114pub trait TokioAsyncSituwaition: SituwaitionBase {
115 /// Execute the situwaition, and wait until it resolves
116 /// or fails with a timeout
117 async fn exec(&mut self) -> Result<Self::Result, SituwaitionError<Self::Error>>;
118}
119
120/// This trait represents a "situwaition" that can be a"waited", with async-std.
121/// note that how the waiting is done can differ by platform
122#[cfg(feature = "async-std")]
123#[async_trait]
124pub trait AsyncStdAsyncSituwaition: SituwaitionBase {
125 /// Execute the situwaition, and wait until it resolves
126 /// or fails with a timeout
127 async fn exec(&mut self) -> Result<Self::Result, SituwaitionError<Self::Error>>;
128}
129
130/// Errors that are thrown during waiter creation
131#[derive(Debug, Clone, Error)]
132pub enum WaiterCreationError {
133 #[error("invalid timeout: {0}")]
134 InvalidTimeout(String),
135
136 #[error("invalid interval: {0}")]
137 InvalidInterval(String),
138}