use bincode;
use blake3::Hash;
use hashbrown::HashMap;
use log::info;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::{json, Value};
use specs::{Component, VecStorage};
#[derive(Debug, Default, Component, Serialize, Deserialize, Clone)]
#[storage(VecStorage)]
pub struct MetadataComp {
pub map: HashMap<String, Value>,
#[serde(skip_serializing)]
#[serde(skip_deserializing)]
cache_hash: Option<Hash>,
#[serde(skip_serializing)]
#[serde(skip_deserializing)]
cached_json: Option<String>,
}
impl MetadataComp {
pub fn new() -> Self {
Self::default()
}
pub fn from_map(map: HashMap<String, Value>) -> Self {
Self {
map,
cache_hash: None,
cached_json: None,
}
}
pub fn set<T: Component + Serialize>(&mut self, component: &str, data: &T) {
let value = json!(data);
self.map.insert(component.to_owned(), value);
self.cached_json = None;
}
pub fn get<T: Component + DeserializeOwned>(&self, component: &str) -> Option<T> {
if let Some(component) = self.map.get(component) {
return Some(serde_json::from_value(component.to_owned()).unwrap());
}
None
}
fn calculate_hash(&self) -> Hash {
let bytes = bincode::serialize(&self.map).unwrap_or_default();
blake3::hash(&bytes)
}
pub fn to_cached_str(&mut self) -> (String, bool) {
let current_hash = self.calculate_hash();
let mut updated = false;
if let Some(cache_hash) = self.cache_hash {
if cache_hash != current_hash {
updated = true;
self.cache_hash = Some(current_hash);
self.cached_json = None;
}
} else {
updated = true;
self.cache_hash = Some(current_hash);
self.cached_json = None;
}
if !updated && self.cached_json.is_some() {
return (self.cached_json.clone().unwrap(), updated);
}
let json_str = self.to_string();
self.cached_json = Some(json_str.clone());
(json_str, updated)
}
pub fn to_string(&self) -> String {
serde_json::to_string(&self.map).unwrap()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn reset(&mut self) {
self.map.clear();
}
}