use crate::{Error, NoCodec, Path, Reader, Record, Value, Writer};
#[derive(Debug, Default)]
pub struct MemoryStore {
root: Value,
}
impl MemoryStore {
pub fn new() -> Self {
Self { root: Value::Null }
}
pub fn with_root(root: Value) -> Self {
Self { root }
}
pub fn root(&self) -> &Value {
&self.root
}
}
impl Reader for MemoryStore {
fn read(&mut self, from: &Path) -> Result<Option<Record>, Error> {
if from.is_empty() && self.root.is_null() {
return Ok(None);
}
Ok(self.root.get(from).cloned().map(Record::parsed))
}
fn read_children(&mut self, from: &Path) -> Result<Option<Vec<String>>, Error> {
if from.is_empty() && self.root.is_null() {
return Ok(None);
}
Ok(self.root.get(from).map(|v| match v {
Value::Map(map) => map.keys().cloned().collect(),
Value::Array(arr) => (0..arr.len()).map(|i| i.to_string()).collect(),
_ => Vec::new(),
}))
}
}
impl Writer for MemoryStore {
fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error> {
let value = data.into_value(&NoCodec)?;
if value.is_null() {
if to.is_empty() {
self.root = Value::Null;
} else {
self.root.remove(to)?;
}
return Ok(to.clone());
}
if to.is_empty() {
self.root = value;
return Ok(to.clone());
}
if self.root.is_null() {
self.root = Value::map();
}
self.root.set(to, value)?;
Ok(to.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::path;
#[test]
fn deep_write_creates_intermediates() {
let mut store = MemoryStore::new();
store
.write(&path!("a/b/c"), Record::parsed(Value::from(1i64)))
.unwrap();
assert!(store.read(&path!("a")).unwrap().is_some());
assert!(store.read(&path!("a/b")).unwrap().is_some());
assert_eq!(
store.read(&path!("a/b/c")).unwrap().unwrap().as_value(),
Some(&Value::Integer(1))
);
}
#[test]
fn null_deletes_subtree_component_wise() {
let mut store = MemoryStore::new();
store
.write(
&path!("accounts/personal"),
Record::parsed(Value::from(1i64)),
)
.unwrap();
store
.write(&path!("accounts_other"), Record::parsed(Value::from(2i64)))
.unwrap();
store
.write(&path!("accounts"), Record::parsed(Value::Null))
.unwrap();
assert!(store.read(&path!("accounts")).unwrap().is_none());
assert!(store.read(&path!("accounts/personal")).unwrap().is_none());
assert!(store.read(&path!("accounts_other")).unwrap().is_some());
}
#[test]
fn map_write_replaces_subtree() {
let mut store = MemoryStore::new();
store
.write(&path!("cfg/old"), Record::parsed(Value::from("stale")))
.unwrap();
let mut new_state = std::collections::BTreeMap::new();
new_state.insert("fresh".to_string(), Value::from("new"));
store
.write(&path!("cfg"), Record::parsed(Value::Map(new_state)))
.unwrap();
assert!(store.read(&path!("cfg/old")).unwrap().is_none());
assert!(store.read(&path!("cfg/fresh")).unwrap().is_some());
}
#[test]
fn empty_store_reads_none_at_root() {
let mut store = MemoryStore::new();
assert!(store.read(&path!("")).unwrap().is_none());
assert!(store.read_children(&path!("")).unwrap().is_none());
}
#[test]
fn root_write_and_clear() {
let mut store = MemoryStore::new();
store
.write(&path!(""), Record::parsed(Value::from("everything")))
.unwrap();
assert!(store.read(&path!("")).unwrap().is_some());
store
.write(&path!(""), Record::parsed(Value::Null))
.unwrap();
assert!(store.read(&path!("")).unwrap().is_none());
}
#[test]
fn read_children_overridden() {
let mut store = MemoryStore::new();
store
.write(&path!("m/a"), Record::parsed(Value::from(1i64)))
.unwrap();
store
.write(&path!("m/b"), Record::parsed(Value::from(2i64)))
.unwrap();
assert_eq!(
store.read_children(&path!("m")).unwrap(),
Some(vec!["a".to_string(), "b".to_string()])
);
assert_eq!(store.read_children(&path!("m/a")).unwrap(), Some(vec![]));
assert_eq!(store.read_children(&path!("missing")).unwrap(), None);
}
}