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    pub fn llen(&mut self, key: &[u8]) -> Result<usize, StoreError> {
12        match self.live_entry(key) {
13            None => Ok(0),
14            Some(e) => match &e.value {
15                Value::List(l) => Ok(l.len()),
16                Value::SegList(l) => Ok(l.len()),
17                Value::SmallListInline(l) => Ok(l.len()),
18                _ => Err(StoreError::WrongType),
19            },
20        }
21    }
22
23    pub fn lindex(&mut self, key: &[u8], idx: i64) -> Result<Option<Vec<u8>>, StoreError> {
24        match self.live_entry(key) {
25            None => Ok(None),
26            Some(e) => match &e.value {
27                Value::List(l) => Ok(norm_index(idx, l.len()).and_then(|i| l.get(i).cloned())),
28                Value::SegList(l) => {
29                    Ok(norm_index(idx, l.len()).and_then(|i| l.get(i).cloned()))
30                }
31                Value::SmallListInline(l) => {
32                    let n = l.len();
33                    let Some(i) = norm_index(idx, n) else { return Ok(None) };
34                    Ok(l.iter().nth(i).map(<[u8]>::to_vec))
35                }
36                _ => Err(StoreError::WrongType),
37            },
38        }
39    }
40
41    pub fn lrange(
42        &mut self,
43        key: &[u8],
44        start: i64,
45        stop: i64,
46    ) -> Result<Vec<Vec<u8>>, StoreError> {
47        match self.live_entry(key) {
48            None => Ok(Vec::new()),
49            Some(e) => match &e.value {
50                Value::List(l) => Ok(match range_bounds(start, stop, l.len()) {
51                    None => Vec::new(),
52                    Some((s, end)) => l.iter().skip(s).take(end - s + 1).cloned().collect(),
53                }),
54                // Seeks to the start segment instead of skip-walking
55                // elements — an LRANGE deep into a giant list stays
56                // O(segments + span).
57                Value::SegList(l) => Ok(match range_bounds(start, stop, l.len()) {
58                    None => Vec::new(),
59                    Some((s, end)) => l.iter_range(s, end - s + 1).cloned().collect(),
60                }),
61                Value::SmallListInline(l) => Ok(match range_bounds(start, stop, l.len()) {
62                    None => Vec::new(),
63                    Some((s, end)) => l
64                        .iter()
65                        .skip(s)
66                        .take(end - s + 1)
67                        .map(<[u8]>::to_vec)
68                        .collect(),
69                }),
70                _ => Err(StoreError::WrongType),
71            },
72        }
73    }
74}