use std::collections::{HashMap, HashSet};
use serde::{Serialize, Deserialize};
use serde_with::{serde_as, MapPreventDuplicates, SetPreventDuplicates};
use crate::util::*;
#[serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Suitability)]
#[serde(deny_unknown_fields)]
pub struct Map<T> {
#[serde_as(as = "MapPreventDuplicates<_, _>")]
pub map: HashMap<String, T>,
#[serde(default = "Option::default", skip_serializing_if = "Option::is_none")]
pub if_none: Option<Box<T>>,
#[serde(default = "Option::default", skip_serializing_if = "Option::is_none")]
pub r#else: Option<Box<T>>
}
impl<T> Map<T> {
pub fn with_capacity(capacity: usize) -> Self {
Map {
map : HashMap::with_capacity(capacity),
if_none: None,
r#else : None
}
}
pub fn get<U: AsRef<str>>(&self, key: Option<U>) -> Option<&T> {
match key {
Some(key) => self.map.get(key.as_ref()),
None => self.if_none.as_deref()
}.or(self.r#else.as_deref())
}
}
impl<T> Default for Map<T> {
fn default() -> Self {
Self {
map : Default::default(),
if_none: Default::default(),
r#else : Default::default()
}
}
}
#[serde_as]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Suitability)]
pub struct MapDiff<T> {
#[serde_as(as = "MapPreventDuplicates<_, _>")]
#[serde(default, bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
pub insert: HashMap<String, T>,
#[serde_as(as = "SetPreventDuplicates<_>")]
#[serde(default)]
pub remove: HashSet<String>
}
impl<T> MapDiff<T> {
pub fn apply_once(self, to: &mut Map<T>) {
to.map.extend(self.insert);
to.map.retain(|k, _| !self.remove.contains(k));
}
}
impl<T: Clone> MapDiff<T> {
pub fn apply_multiple(&self, to: &mut Map<T>) {
to.map.extend(self.insert.iter().map(|(k, v)| (k.clone(), v.clone())));
to.map.retain(|k, _| !self.remove.contains(k));
}
}
impl<T, const N: usize> From<[(String, T); N]> for Map<T> {
fn from(value: [(String, T); N]) -> Self {
Self {
map: value.into(),
if_none: None,
r#else: None
}
}
}
impl<T, const N: usize> From<[(Option<String>, T); N]> for Map<T> {
fn from(value: [(Option<String>, T); N]) -> Self {
let mut ret = Self {
map: HashMap::with_capacity(N),
if_none: None,
r#else: None
};
for (k, v) in value {
match k {
Some(k) => {ret.map.insert(k, v);},
None => ret.if_none = Some(Box::new(v))
}
}
ret
}
}
impl<T> From<HashMap<String, T>> for Map<T> {
fn from(value: HashMap<String, T>) -> Self {
Self {
map: value,
if_none: None,
r#else: None
}
}
}
impl<T> From<HashMap<Option<String>, T>> for Map<T> {
fn from(value: HashMap<Option<String>, T>) -> Self {
let mut ret = Self {
map: HashMap::with_capacity(value.len()),
if_none: None,
r#else: None
};
for (k, v) in value {
match k {
Some(k) => {ret.map.insert(k, v);},
None => ret.if_none = Some(Box::new(v))
}
}
ret
}
}
impl<T> FromIterator<(String, T)> for Map<T> {
fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Self {
Self {
map: iter.into_iter().collect(),
if_none: None,
r#else: None
}
}
}
impl<T> FromIterator<(Option<String>, T)> for Map<T> {
fn from_iter<I: IntoIterator<Item = (Option<String>, T)>>(iter: I) -> Self {
let iter = iter.into_iter();
let size_hint = iter.size_hint();
let mut ret = Self {
map: HashMap::with_capacity(size_hint.1.unwrap_or(size_hint.0)),
if_none: None,
r#else: None
};
for (k, v) in iter {
match k {
Some(k) => {ret.map.insert(k, v);},
None => ret.if_none = Some(Box::new(v))
}
}
ret
}
}