use std::collections::{btree_map::IntoValues, BTreeMap};
use serde::Deserializer;
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Metadata {
inner: BTreeMap<String, serde_json::Value>,
}
impl Metadata {
pub fn iter(&self) -> impl Iterator<Item = (&String, &serde_json::Value)> {
self.inner.iter()
}
pub fn insert<K, V>(&mut self, key: K, value: V)
where
K: Into<String>,
V: Into<serde_json::Value>,
{
self.inner.insert(key.into(), value.into());
}
pub fn get(&self, key: impl AsRef<str>) -> Option<&serde_json::Value> {
self.inner.get(key.as_ref())
}
pub fn into_values(self) -> IntoValues<String, serde_json::Value> {
self.inner.into_values()
}
}
impl<K, V> Extend<(K, V)> for Metadata
where
K: Into<String>,
V: Into<serde_json::Value>,
{
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
self.inner
.extend(iter.into_iter().map(|(k, v)| (k.into(), v.into())));
}
}
impl<K, V> From<Vec<(K, V)>> for Metadata
where
K: Into<String>,
V: Into<serde_json::Value>,
{
fn from(items: Vec<(K, V)>) -> Self {
let inner = items
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
Metadata { inner }
}
}
impl<'a, K, V> From<&'a [(K, V)]> for Metadata
where
K: Into<String> + Clone,
V: Into<serde_json::Value> + Clone,
{
fn from(items: &'a [(K, V)]) -> Self {
let inner = items
.iter()
.cloned()
.map(|(k, v)| (k.into(), v.into()))
.collect();
Metadata { inner }
}
}
impl<K: Ord, V, const N: usize> From<[(K, V); N]> for Metadata
where
K: Ord + Into<String>,
V: Into<serde_json::Value>,
{
fn from(mut arr: [(K, V); N]) -> Self {
if N == 0 {
return Metadata {
inner: BTreeMap::new(),
};
}
arr.sort_by(|a, b| a.0.cmp(&b.0));
let inner: BTreeMap<String, serde_json::Value> =
arr.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
Metadata { inner }
}
}
impl IntoIterator for Metadata {
type Item = (String, serde_json::Value);
type IntoIter = std::collections::btree_map::IntoIter<String, serde_json::Value>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'iter> IntoIterator for &'iter Metadata {
type Item = (&'iter String, &'iter serde_json::Value);
type IntoIter = std::collections::btree_map::Iter<'iter, String, serde_json::Value>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl<'de> serde::Deserialize<'de> for Metadata {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
BTreeMap::deserialize(deserializer).map(|inner| Metadata { inner })
}
}
impl serde::Serialize for Metadata {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.inner.serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_insert_and_get() {
let mut metadata = Metadata::default();
let key = "key";
let value = "value";
metadata.insert(key, "value");
assert_eq!(metadata.get(key).unwrap().as_str(), Some(value));
}
#[test]
fn test_iter() {
let mut metadata = Metadata::default();
metadata.insert("key1", json!("value1"));
metadata.insert("key2", json!("value2"));
let mut iter = metadata.iter();
assert_eq!(iter.next(), Some((&"key1".to_string(), &json!("value1"))));
assert_eq!(iter.next(), Some((&"key2".to_string(), &json!("value2"))));
assert_eq!(iter.next(), None);
}
#[test]
fn test_extend() {
let mut metadata = Metadata::default();
metadata.extend(vec![("key1", json!("value1")), ("key2", json!("value2"))]);
assert_eq!(metadata.get("key1"), Some(&json!("value1")));
assert_eq!(metadata.get("key2"), Some(&json!("value2")));
}
#[test]
fn test_from_vec() {
let metadata = Metadata::from(vec![("key1", json!("value1")), ("key2", json!("value2"))]);
assert_eq!(metadata.get("key1"), Some(&json!("value1")));
assert_eq!(metadata.get("key2"), Some(&json!("value2")));
}
#[test]
fn test_into_values() {
let mut metadata = Metadata::default();
metadata.insert("key1", json!("value1"));
metadata.insert("key2", json!("value2"));
let values: Vec<_> = metadata.into_values().collect();
assert_eq!(values, vec![json!("value1"), json!("value2")]);
}
}