swiftide_core/
metadata.rs

1//! Metadata is a key-value store for indexation nodes
2//!
3//! Typically metadata is used to extract or generate additional information about the node
4//!
5//! Internally it uses a `BTreeMap` to store the key-value pairs, to ensure the data is sorted.
6use std::collections::{btree_map::IntoValues, BTreeMap};
7
8use serde::Deserializer;
9
10use crate::util::debug_long_utf8;
11
12#[derive(Clone, Default, PartialEq, Eq)]
13pub struct Metadata {
14    inner: BTreeMap<String, serde_json::Value>,
15}
16
17impl std::fmt::Debug for Metadata {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        f.debug_map()
20            .entries(
21                self.inner
22                    .iter()
23                    .map(|(k, v): (&String, &serde_json::Value)| {
24                        let fvalue = v.as_str().map_or_else(
25                            || debug_long_utf8(v.to_string(), 100),
26                            ToString::to_string,
27                        );
28
29                        (k, fvalue)
30                    }),
31            )
32            .finish()
33    }
34}
35
36impl Metadata {
37    pub fn iter(&self) -> impl Iterator<Item = (&String, &serde_json::Value)> {
38        self.inner.iter()
39    }
40
41    pub fn insert<K, V>(&mut self, key: K, value: V)
42    where
43        K: Into<String>,
44        V: Into<serde_json::Value>,
45    {
46        self.inner.insert(key.into(), value.into());
47    }
48
49    pub fn get(&self, key: impl AsRef<str>) -> Option<&serde_json::Value> {
50        self.inner.get(key.as_ref())
51    }
52
53    pub fn into_values(self) -> IntoValues<String, serde_json::Value> {
54        self.inner.into_values()
55    }
56
57    pub fn is_empty(&self) -> bool {
58        self.inner.is_empty()
59    }
60}
61
62impl<K, V> Extend<(K, V)> for Metadata
63where
64    K: Into<String>,
65    V: Into<serde_json::Value>,
66{
67    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
68        self.inner
69            .extend(iter.into_iter().map(|(k, v)| (k.into(), v.into())));
70    }
71}
72
73impl<K, V> From<Vec<(K, V)>> for Metadata
74where
75    K: Into<String>,
76    V: Into<serde_json::Value>,
77{
78    fn from(items: Vec<(K, V)>) -> Self {
79        let inner = items
80            .into_iter()
81            .map(|(k, v)| (k.into(), v.into()))
82            .collect();
83        Metadata { inner }
84    }
85}
86
87impl<K, V> From<(K, V)> for Metadata
88where
89    K: Into<String>,
90    V: Into<serde_json::Value>,
91{
92    fn from(items: (K, V)) -> Self {
93        let sliced: [(K, V); 1] = [items];
94        let inner = sliced
95            .into_iter()
96            .map(|(k, v)| (k.into(), v.into()))
97            .collect();
98        Metadata { inner }
99    }
100}
101
102impl<'a, K, V> From<&'a [(K, V)]> for Metadata
103where
104    K: Into<String> + Clone,
105    V: Into<serde_json::Value> + Clone,
106{
107    fn from(items: &'a [(K, V)]) -> Self {
108        let inner = items
109            .iter()
110            .cloned()
111            .map(|(k, v)| (k.into(), v.into()))
112            .collect();
113        Metadata { inner }
114    }
115}
116
117impl<K: Ord, V, const N: usize> From<[(K, V); N]> for Metadata
118where
119    K: Ord + Into<String>,
120    V: Into<serde_json::Value>,
121{
122    fn from(mut arr: [(K, V); N]) -> Self {
123        if N == 0 {
124            return Metadata {
125                inner: BTreeMap::new(),
126            };
127        }
128        arr.sort_by(|a, b| a.0.cmp(&b.0));
129        let inner: BTreeMap<String, serde_json::Value> =
130            arr.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
131        Metadata { inner }
132    }
133}
134
135impl IntoIterator for Metadata {
136    type Item = (String, serde_json::Value);
137    type IntoIter = std::collections::btree_map::IntoIter<String, serde_json::Value>;
138    fn into_iter(self) -> Self::IntoIter {
139        self.inner.into_iter()
140    }
141}
142
143impl<'iter> IntoIterator for &'iter Metadata {
144    type Item = (&'iter String, &'iter serde_json::Value);
145    type IntoIter = std::collections::btree_map::Iter<'iter, String, serde_json::Value>;
146    fn into_iter(self) -> Self::IntoIter {
147        self.inner.iter()
148    }
149}
150
151impl<'de> serde::Deserialize<'de> for Metadata {
152    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
153        BTreeMap::deserialize(deserializer).map(|inner| Metadata { inner })
154    }
155}
156
157impl serde::Serialize for Metadata {
158    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
159        self.inner.serialize(serializer)
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use serde_json::json;
167
168    #[test]
169    fn test_insert_and_get() {
170        let mut metadata = Metadata::default();
171        let key = "key";
172        let value = "value";
173        metadata.insert(key, "value");
174
175        assert_eq!(metadata.get(key).unwrap().as_str(), Some(value));
176    }
177
178    #[test]
179    fn test_iter() {
180        let mut metadata = Metadata::default();
181        metadata.insert("key1", json!("value1"));
182        metadata.insert("key2", json!("value2"));
183
184        let mut iter = metadata.iter();
185        assert_eq!(iter.next(), Some((&"key1".to_string(), &json!("value1"))));
186        assert_eq!(iter.next(), Some((&"key2".to_string(), &json!("value2"))));
187        assert_eq!(iter.next(), None);
188    }
189
190    #[test]
191    fn test_extend() {
192        let mut metadata = Metadata::default();
193        metadata.extend(vec![("key1", json!("value1")), ("key2", json!("value2"))]);
194
195        assert_eq!(metadata.get("key1"), Some(&json!("value1")));
196        assert_eq!(metadata.get("key2"), Some(&json!("value2")));
197    }
198
199    #[test]
200    fn test_from_vec() {
201        let metadata = Metadata::from(vec![("key1", json!("value1")), ("key2", json!("value2"))]);
202
203        assert_eq!(metadata.get("key1"), Some(&json!("value1")));
204        assert_eq!(metadata.get("key2"), Some(&json!("value2")));
205    }
206
207    #[test]
208    fn test_into_values() {
209        let mut metadata = Metadata::default();
210        metadata.insert("key1", json!("value1"));
211        metadata.insert("key2", json!("value2"));
212
213        let values: Vec<_> = metadata.into_values().collect();
214        assert_eq!(values, vec![json!("value1"), json!("value2")]);
215    }
216}