Skip to main content

rustauth_core/options/
storage.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use crate::error::RustAuthError;
5
6pub type SecondaryStorageFuture<'a, T> =
7    Pin<Box<dyn Future<Output = Result<T, RustAuthError>> + Send + 'a>>;
8
9/// Async key-value storage for plugin data that can live outside the primary database.
10pub trait SecondaryStorage: Send + Sync + 'static {
11    fn get<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, Option<String>>;
12
13    /// `ttl_seconds == Some(0)` means the value is already expired: implementations
14    /// must remove any existing key and must not store `value` without expiry.
15    fn set<'a>(
16        &'a self,
17        key: &'a str,
18        value: String,
19        ttl_seconds: Option<u64>,
20    ) -> SecondaryStorageFuture<'a, ()>;
21
22    /// Store `value` only when `key` is absent.
23    ///
24    /// Returns `Ok(true)` when the key was created, or `Ok(false)` when it already existed.
25    /// `ttl_seconds == Some(0)` means the value is already expired: implementations must
26    /// not create or delete the key and must return `Ok(false)`.
27    fn set_if_not_exists<'a>(
28        &'a self,
29        key: &'a str,
30        value: String,
31        ttl_seconds: Option<u64>,
32    ) -> SecondaryStorageFuture<'a, bool>;
33
34    fn delete<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, ()>;
35
36    /// Atomically remove and return the stored value when present.
37    fn take<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, Option<String>>;
38
39    /// Atomically replace the key only when the currently stored value matches
40    /// `expected`. `expected == None` means the key must be absent.
41    ///
42    /// Implementations must perform the comparison and replacement as a single
43    /// backend operation. A `get` followed by `set` is not sufficient for
44    /// shared or multi-process storage because concurrent writers can lose
45    /// updates between the read and write.
46    ///
47    /// Returns `Ok(true)` when the replacement was applied.
48    fn compare_and_set<'a>(
49        &'a self,
50        key: &'a str,
51        expected: Option<String>,
52        value: String,
53        ttl_seconds: Option<u64>,
54    ) -> SecondaryStorageFuture<'a, bool>;
55
56    /// Atomically delete the key only when the currently stored value matches
57    /// `expected`. `expected == None` means the key must already be absent and
58    /// therefore no deletion is performed.
59    ///
60    /// Implementations must perform the comparison and deletion as a single
61    /// backend operation. A `get` followed by `delete` is not sufficient for
62    /// shared or multi-process storage because concurrent writers can race the
63    /// deletion.
64    fn delete_if_value<'a>(
65        &'a self,
66        key: &'a str,
67        expected: Option<String>,
68    ) -> SecondaryStorageFuture<'a, bool>;
69}