use crate::reverse_path::ReversePath;
use crate::serialization_helpers::SArc;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::sync::Arc;
pub mod path_fragment;
pub use path_fragment::*;
pub mod reverse_path;
pub use reverse_path::*;
pub type EffectPath = ReversePath<PathFragment>;
#[derive(Debug)]
pub enum EffectDBError {
SerializationError(serde_json::Error),
}
impl From<serde_json::Error> for EffectDBError {
fn from(e: serde_json::Error) -> Self {
EffectDBError::SerializationError(e)
}
}
pub trait EffectDB {
fn get_value<'a>(
&'a self,
at: &Arc<EffectPath>,
) -> Box<dyn Iterator<Item = (&'a Arc<String>, &'a serde_json::Value)> + 'a>;
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct MapEffectDB {
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
effects: BTreeMap<SArc<EffectPath>, BTreeMap<SArc<String>, serde_json::Value>>,
#[serde(skip, default)]
empty: BTreeMap<SArc<String>, serde_json::Value>,
}
pub struct EditableMapEffectDB {
pub effects: BTreeMap<SArc<EffectPath>, BTreeMap<SArc<String>, serde_json::Value>>,
pub empty: BTreeMap<SArc<String>, serde_json::Value>,
}
impl From<MapEffectDB> for EditableMapEffectDB {
fn from(MapEffectDB { effects, empty }: MapEffectDB) -> Self {
Self { effects, empty }
}
}
impl From<EditableMapEffectDB> for MapEffectDB {
fn from(EditableMapEffectDB { effects, empty }: EditableMapEffectDB) -> Self {
Self { effects, empty }
}
}
impl MapEffectDB {
pub fn skip_serializing(&self) -> bool {
self.effects.is_empty()
}
}
impl EffectDB for MapEffectDB {
fn get_value<'a>(
&'a self,
at: &Arc<EffectPath>,
) -> Box<dyn Iterator<Item = (&'a Arc<String>, &'a serde_json::Value)> + 'a> {
let r: &BTreeMap<_, _> = self.effects.get(&SArc(at.clone())).unwrap_or(&self.empty);
Box::new(r.iter().map(|(a, b)| (&a.0, b)))
}
}
#[cfg(test)]
mod test {
use super::*;
use std::convert::{TryFrom, TryInto};
#[test]
fn test_string() {
let v: Vec<PathFragment> = vec![
"hello".try_into().unwrap(),
"#123".try_into().unwrap(),
PathFragment::FinishFn,
];
let r = EffectPath::try_from(v).unwrap();
assert_eq!(String::from(r.clone()), "hello/#123/@finish_fn");
assert_eq!(Ok(r), EffectPath::try_from("hello/#123/@finish_fn"));
}
#[test]
fn test_serde() {
let v: Vec<PathFragment> = vec![
"hello".try_into().unwrap(),
PathFragment::Branch(100),
PathFragment::FinishFn,
];
let r = EffectPath::try_from(v).unwrap();
assert_eq!(
serde_json::to_string(&r).unwrap(),
"\"hello/#100/@finish_fn\""
);
assert_eq!(
Ok(r),
serde_json::from_str("\"hello/#100/@finish_fn\"").map_err(|_| ())
);
}
}