Skip to main content

kevy_store/
list_read.rs

1//! `Store` list read commands (LLEN / LINDEX / LRANGE) — split from
2//! `list.rs` when the SegList arms pushed it against the 500-LOC cap.
3
4#[cfg(not(feature = "std"))]
5use crate::nostd_prelude::*;
6use crate::util::{norm_index, range_bounds};
7use crate::value::Value;
8use crate::{Store, StoreError};
9
10impl Store {
11    /// Element count. A missing key is 0, matching LLEN; a wrong-typed
12    /// key is an error.
13    pub fn llen(&mut self, key: &[u8]) -> Result<usize, StoreError> {
14        match self.live_entry(key) {
15            None => Ok(0),
16            Some(e) => match &e.value {
17                Value::List(l) => Ok(l.len()),
18                Value::SegList(l) => Ok(l.len()),
19                Value::SmallListInline(l) => Ok(l.len()),
20                _ => Err(StoreError::WrongType),
21            },
22        }
23    }
24
25    /// One element by index. Negative indices count from the back, as in
26    /// LINDEX; out of range is `Ok(None)` rather than an error.
27    pub fn lindex(&mut self, key: &[u8], idx: i64) -> Result<Option<Vec<u8>>, StoreError> {
28        match self.live_entry(key) {
29            None => Ok(None),
30            Some(e) => match &e.value {
31                Value::List(l) => Ok(norm_index(idx, l.len()).and_then(|i| l.get(i).cloned())),
32                Value::SegList(l) => Ok(norm_index(idx, l.len()).and_then(|i| l.get(i).cloned())),
33                Value::SmallListInline(l) => {
34                    let n = l.len();
35                    let Some(i) = norm_index(idx, n) else { return Ok(None) };
36                    Ok(l.iter().nth(i).map(<[u8]>::to_vec))
37                }
38                _ => Err(StoreError::WrongType),
39            },
40        }
41    }
42
43    /// A half-open-looking but INCLUSIVE range, as LRANGE defines it:
44    /// negative bounds count from the back, a start past the end is empty,
45    /// and an end past the last element is clamped rather than refused.
46    pub fn lrange(
47        &mut self,
48        key: &[u8],
49        start: i64,
50        stop: i64,
51    ) -> Result<Vec<Vec<u8>>, StoreError> {
52        match self.live_entry(key) {
53            None => Ok(Vec::new()),
54            Some(e) => match &e.value {
55                Value::List(l) => Ok(match range_bounds(start, stop, l.len()) {
56                    None => Vec::new(),
57                    Some((s, end)) => l.iter().skip(s).take(end - s + 1).cloned().collect(),
58                }),
59                // Seeks to the start segment instead of skip-walking
60                // elements — an LRANGE deep into a giant list stays
61                // O(segments + span).
62                Value::SegList(l) => Ok(match range_bounds(start, stop, l.len()) {
63                    None => Vec::new(),
64                    Some((s, end)) => l.iter_range(s, end - s + 1).cloned().collect(),
65                }),
66                Value::SmallListInline(l) => Ok(match range_bounds(start, stop, l.len()) {
67                    None => Vec::new(),
68                    Some((s, end)) => {
69                        l.iter().skip(s).take(end - s + 1).map(<[u8]>::to_vec).collect()
70                    }
71                }),
72                _ => Err(StoreError::WrongType),
73            },
74        }
75    }
76}