Skip to main content

kevy_embedded/
modes.rs

1//! Named modes for [`crate::Store`] methods whose Redis command takes a
2//! flag: the method reads the way the command does.
3
4/// How the active TTL reaper runs.
5///
6/// ```
7/// use kevy_embedded::{Config, TtlReaperMode};
8///
9/// assert_eq!(Config::default().ttl_reaper, TtlReaperMode::Background);
10/// assert_eq!(Config::default().with_ttl_reaper_manual().ttl_reaper, TtlReaperMode::Manual);
11/// ```
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
13#[non_exhaustive]
14pub enum TtlReaperMode {
15    /// Spawn a background thread that ticks at the configured interval
16    /// (default 100 ms / 10 Hz, matching Redis's `hz=10`). Default.
17    ///
18    /// ```
19    /// use std::time::Duration;
20    /// use kevy_embedded::{Config, Store};
21    ///
22    /// let s = Store::open(Config::default())?;
23    /// s.set_with_ttl(b"k", b"v", Duration::from_millis(1))?;
24    /// // nobody calls tick(): the background thread reclaims the key
25    /// for _ in 0..500 {
26    ///     if s.info().expired_keys == 1 {
27    ///         break;
28    ///     }
29    ///     std::thread::sleep(Duration::from_millis(10));
30    /// }
31    /// assert_eq!(s.info().expired_keys, 1);
32    /// # Ok::<(), kevy_embedded::KevyError>(())
33    /// ```
34    #[default]
35    Background,
36    /// Caller-driven via [`crate::Store::tick`]. Required for WASM
37    /// targets (no threads) and single-threaded apps that don't want a
38    /// background worker.
39    ///
40    /// ```
41    /// use std::time::Duration;
42    /// use kevy_embedded::{Config, Store};
43    ///
44    /// let s = Store::open(Config::default().with_ttl_reaper_manual())?;
45    /// s.set_with_ttl(b"k", b"v", Duration::from_millis(1))?;
46    /// std::thread::sleep(Duration::from_millis(250));
47    /// assert_eq!(s.info().expired_keys, 0, "nothing reaps until the caller ticks");
48    /// for _ in 0..50 { s.tick(); }
49    /// assert_eq!(s.info().expired_keys, 1);
50    /// # Ok::<(), kevy_embedded::KevyError>(())
51    /// ```
52    Manual,
53}
54
55/// Whether `COPY` may overwrite an existing destination
56/// ([`crate::Store::copy`]).
57///
58/// ```
59/// use kevy_embedded::{Config, CopyMode, Store};
60///
61/// let s = Store::open(Config::default())?;
62/// s.set(b"src", b"new")?;
63/// s.set(b"dst", b"old")?;
64/// assert!(!s.copy(b"src", b"dst", CopyMode::IfAbsent)?);
65/// assert!(s.copy(b"src", b"dst", CopyMode::Replace)?);
66/// assert_eq!(s.get(b"dst")?.as_deref(), Some(&b"new"[..]));
67/// # Ok::<(), kevy_embedded::KevyError>(())
68/// ```
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
70#[non_exhaustive]
71pub enum CopyMode {
72    /// Copy only when the destination does not exist (`COPY` without
73    /// `REPLACE`).
74    ///
75    /// ```
76    /// use kevy_embedded::{Config, CopyMode, Store};
77    ///
78    /// let s = Store::open(Config::default())?;
79    /// s.set(b"src", b"v")?;
80    /// assert!(s.copy(b"src", b"fresh", CopyMode::IfAbsent)?, "an absent destination is written");
81    /// s.set(b"taken", b"old")?;
82    /// assert!(!s.copy(b"src", b"taken", CopyMode::IfAbsent)?);
83    /// assert_eq!(s.get(b"taken")?.as_deref(), Some(&b"old"[..]));
84    /// # Ok::<(), kevy_embedded::KevyError>(())
85    /// ```
86    #[default]
87    IfAbsent,
88    /// Overwrite an existing destination (`COPY … REPLACE`).
89    ///
90    /// ```
91    /// use kevy_embedded::{Config, CopyMode, Store};
92    ///
93    /// let s = Store::open(Config::default())?;
94    /// s.set(b"src", b"new")?;
95    /// s.set(b"dst", b"old")?;
96    /// assert!(s.copy(b"src", b"dst", CopyMode::Replace)?);
97    /// assert_eq!(s.get(b"dst")?.as_deref(), Some(&b"new"[..]));
98    /// # Ok::<(), kevy_embedded::KevyError>(())
99    /// ```
100    Replace,
101}
102
103/// Whether a text index records each token's position
104/// ([`crate::Store::idx_create_text`]).
105///
106/// Positions let a phrase query verify that its words are adjacent; they
107/// cost the positional side-channel's memory.
108///
109/// ```
110/// assert_eq!(kevy_embedded::TokenPositions::default(), kevy_embedded::TokenPositions::Omit);
111/// ```
112#[cfg(feature = "text")]
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
114#[non_exhaustive]
115pub enum TokenPositions {
116    /// Index terms only. Term queries work as usual; a multi-word phrase
117    /// query has no offsets to verify adjacency against and matches
118    /// nothing.
119    ///
120    /// ```
121    /// use kevy_embedded::{Config, Store, TokenPositions};
122    ///
123    /// let s = Store::open(Config::default())?;
124    /// s.idx_create_text(b"ft", b"doc:", &[(b"body", 1.0)], TokenPositions::Omit, &[])?;
125    /// s.hset(b"doc:1", &[(b"body", b"an engine written in rust")])?;
126    /// assert_eq!(s.idx_match(b"ft", b"rust engine", 10)?.len(), 1);
127    /// // no offsets were recorded, so no phrase can be verified
128    /// assert!(s.idx_match(b"ft", b"\"written in rust\"", 10)?.is_empty());
129    /// # Ok::<(), kevy_embedded::KevyError>(())
130    /// ```
131    #[default]
132    Omit,
133    /// Record token offsets, so phrase queries verify adjacency.
134    ///
135    /// ```
136    /// use kevy_embedded::{Config, Store, TokenPositions};
137    ///
138    /// let s = Store::open(Config::default())?;
139    /// s.idx_create_text(b"ft", b"doc:", &[(b"body", 1.0)], TokenPositions::Record, &[])?;
140    /// s.hset(b"doc:1", &[(b"body", b"an engine written in rust")])?;
141    /// assert!(s.idx_match(b"ft", b"\"rust engine\"", 10)?.is_empty(), "not adjacent");
142    /// assert_eq!(s.idx_match(b"ft", b"\"written in rust\"", 10)?.len(), 1);
143    /// # Ok::<(), kevy_embedded::KevyError>(())
144    /// ```
145    Record,
146}