pub mod memory;
pub mod sets;
pub mod yaml;
use std::ops::{Deref, DerefMut};
use serde::de::DeserializeOwned;
use serde::Serialize;
pub use self::memory::MemStorage;
pub use self::yaml::YamlStorage;
pub trait StorageReadGuard<'a, T: Sized>: Deref<Target = T> {}
pub trait StorageWriteGuard<'a, T: Sized>: DerefMut<Target = T> {}
pub trait Storage {
type S;
fn read<'a>(&'a self) -> Box<dyn StorageReadGuard<'a, Self::S, Target = Self::S> + 'a>;
fn write<'a>(&'a mut self) -> Box<dyn StorageWriteGuard<'a, Self::S, Target = Self::S> + 'a>;
}
pub fn get_storage<'a, T: Sized + Serialize + DeserializeOwned + 'a, F: Fn() -> T>(
location: &str,
default: F,
) -> Result<Box<dyn Storage<S = T> + 'a>, String> {
if location.ends_with(".yaml") {
Ok(Box::new(
YamlStorage::new(location, default).map_err(|err| format!("{}: {}", err, location))?,
) as Box<dyn Storage<S = T>>)
} else if location == "memory" {
Ok(
Box::new(MemStorage::new(default).map_err(|err| format!("{}: {}", err, location))?)
as Box<dyn Storage<S = T>>,
)
} else {
Err(format!("Unknown state location type: {}", location))
}
}
#[cfg(test)]
mod tests {
use super::YamlStorage;
use super::*;
use tempdir::TempDir;
#[test]
fn test_read_guard() {
let temp_dir = TempDir::new("test_read_guard").unwrap();
let mut temp_dir_path = temp_dir.path().to_path_buf();
temp_dir_path.push("circuits.yaml");
let filename = temp_dir_path.to_str().unwrap().to_string();
let storage = YamlStorage::new(filename.clone(), || 1).unwrap();
let val = storage.read();
let other = storage.read();
assert_eq!(**val, 1);
assert_eq!(**other, 1);
}
#[test]
fn test_disk_persistence() {
let temp_dir = TempDir::new("test_disk_persistence").unwrap();
let mut temp_dir_path = temp_dir.path().to_path_buf();
temp_dir_path.push("circuits.yaml");
let filename = temp_dir_path.to_str().unwrap().to_string();
{
let mut storage = YamlStorage::new(&filename[..], || 0).unwrap();
let mut val = storage.write();
**val = 5;
assert_eq!(**val, 5);
}
let storage = YamlStorage::new(&filename[..], || 0).unwrap();
let val = storage.read();
assert_eq!(**val, 5);
}
#[test]
fn test_truncation() {
let temp_dir = TempDir::new("test_truncation").unwrap();
let mut temp_dir_path = temp_dir.path().to_path_buf();
temp_dir_path.push("circuits.yaml");
let filename = temp_dir_path.to_str().unwrap().to_string();
{
let storage = YamlStorage::new(&filename[..], || 500).unwrap();
let val = storage.read();
assert_eq!(**val, 500);
}
{
let mut storage = YamlStorage::new(&filename[..], || 0).unwrap();
let mut val = storage.write();
assert_eq!(**val, 500);
**val = 2;
assert_eq!(**val, 2);
}
let storage = YamlStorage::new(&filename[..], || 0).unwrap();
let val = storage.read();
assert_eq!(**val, 2);
}
#[test]
fn test_write_guard() {
let temp_dir = TempDir::new("test_write_guard").unwrap();
let mut temp_dir_path = temp_dir.path().to_path_buf();
temp_dir_path.push("circuits.yaml");
let filename = temp_dir_path.to_str().unwrap().to_string();
{
let mut storage = YamlStorage::new(&filename[..], || 1).unwrap();
let mut val = storage.write();
assert_eq!(**val, 1);
**val = 5;
assert_eq!(**val, 5);
}
{
let mut storage = YamlStorage::new(&filename[..], || 1).unwrap();
let mut val = storage.write();
assert_eq!(**val, 5);
**val = 64;
assert_eq!(**val, 64);
}
}
#[test]
fn test_get_storage() {
let temp_dir = TempDir::new("test_get_storage").unwrap();
let mut temp_dir_path = temp_dir.path().to_path_buf();
temp_dir_path.push("circuits.yaml");
let filename = temp_dir_path.to_str().unwrap().to_string();
let mem = get_storage("memory", || 1).unwrap();
let mut yaml = get_storage(&format!("{}.yaml", filename), || 1).unwrap();
assert_eq!(**mem.read(), 1);
{
let mut val = yaml.write();
**val = 128;
}
assert_eq!(**yaml.read(), 128);
if let Ok(_) = get_storage("not_yaml.file", || 1) {
panic!("get_storage did not fail when given a bad file type");
}
}
}