Skip to main content

git_ark/
store.rs

1use anyhow::{anyhow, Result};
2use std::collections::BTreeMap;
3use std::sync::Mutex;
4
5pub trait ObjectStore {
6    fn put(&self, key: &str, body: &[u8]) -> Result<()>;
7    fn get(&self, key: &str) -> Result<Vec<u8>>;
8    fn list(&self, prefix: &str) -> Result<Vec<String>>;
9}
10
11#[derive(Default)]
12pub struct InMemoryStore {
13    inner: Mutex<BTreeMap<String, Vec<u8>>>,
14}
15
16impl InMemoryStore {
17    pub fn new() -> Self {
18        Self::default()
19    }
20}
21
22impl ObjectStore for InMemoryStore {
23    fn put(&self, key: &str, body: &[u8]) -> Result<()> {
24        self.inner
25            .lock()
26            .unwrap()
27            .insert(key.to_string(), body.to_vec());
28        Ok(())
29    }
30    fn get(&self, key: &str) -> Result<Vec<u8>> {
31        self.inner
32            .lock()
33            .unwrap()
34            .get(key)
35            .cloned()
36            .ok_or_else(|| anyhow!("no such object: {key}"))
37    }
38    fn list(&self, prefix: &str) -> Result<Vec<String>> {
39        Ok(self
40            .inner
41            .lock()
42            .unwrap()
43            .keys()
44            .filter(|k| k.starts_with(prefix))
45            .cloned()
46            .collect())
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn put_get_list() {
56        let s = InMemoryStore::new();
57        s.put("git-ark/x/latest.age", b"a").unwrap();
58        s.put("git-ark/x/history/2026.age", b"b").unwrap();
59        assert_eq!(s.get("git-ark/x/latest.age").unwrap(), b"a");
60        let mut listed = s.list("git-ark/x/history/").unwrap();
61        listed.sort();
62        assert_eq!(listed, vec!["git-ark/x/history/2026.age".to_string()]);
63    }
64
65    #[test]
66    fn get_missing_errs() {
67        let s = InMemoryStore::new();
68        assert!(s.get("nope").is_err());
69    }
70}