plantuml_server_client_rs/metadata/
include.rs

1use anyhow::Result;
2use derive_getters::Getters;
3use normalize_path::NormalizePath;
4use serde::{Deserialize, Serialize};
5use std::collections::BTreeMap;
6use std::path::PathBuf;
7use typed_builder::TypedBuilder;
8
9/// A metadata about files collected for includes
10#[derive(Deserialize, Serialize, Clone, Debug)]
11pub struct IncludesMetadata(
12    #[serde(with = "btreemap_vec_with")] BTreeMap<PathBuf, Vec<IncludesMetadataItem>>,
13);
14
15/// A metadata about file collected for includes
16///
17/// * `path` - The path constructed from `base_path` and `relative_path`
18/// * `normalize_path` - The normalized `path`
19/// * `base_path` - The path of the file from which to include
20/// * `relative_path` - The relative path from the source file to include
21/// * `index` - The specified index to include
22/// * `id` - The specified id to include
23#[derive(Deserialize, Serialize, TypedBuilder, Getters, Clone, Debug)]
24#[builder(mutators(
25    pub fn path(&mut self, path: PathBuf){
26        self.normalized_path = path.normalize();
27        self.path = path
28    }
29))]
30pub struct IncludesMetadataItem {
31    #[builder(via_mutators)]
32    path: PathBuf,
33    #[builder(via_mutators)]
34    normalized_path: PathBuf,
35    base_path: PathBuf,
36    relative_path: PathBuf,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    index: Option<usize>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    id: Option<String>,
41}
42
43impl IncludesMetadata {
44    /// Returns `true` if the metadata has a length of 0.
45    pub fn is_empty(&self) -> bool {
46        self.0.is_empty()
47    }
48
49    /// Returns the number of elements in the metadata.
50    pub fn len(&self) -> usize {
51        self.0.len()
52    }
53
54    /// Returns an iterator over the metadata item.
55    pub fn iter(&self) -> impl std::iter::Iterator<Item = (&PathBuf, &Vec<IncludesMetadataItem>)> {
56        self.0.iter()
57    }
58
59    /// Returns a flatten iterator over the metadata item.
60    pub fn flat_iter(&self) -> impl std::iter::Iterator<Item = (&PathBuf, &IncludesMetadataItem)> {
61        self.0
62            .iter()
63            .flat_map(|(k, v)| v.iter().map(move |x| (k, x)))
64    }
65}
66
67impl From<BTreeMap<PathBuf, Vec<IncludesMetadataItem>>> for IncludesMetadata {
68    fn from(inner: BTreeMap<PathBuf, Vec<IncludesMetadataItem>>) -> Self {
69        Self(inner)
70    }
71}
72
73impl btreemap_vec_with::Key for IncludesMetadataItem {
74    type Key = PathBuf;
75    fn key(&self) -> Self::Key {
76        self.path.normalize()
77    }
78}
79
80mod btreemap_vec_with {
81    use super::*;
82
83    use serde::ser::SerializeSeq;
84    use serde::{Deserializer, Serializer};
85
86    pub trait Key {
87        type Key;
88        fn key(&self) -> Self::Key;
89    }
90
91    pub fn deserialize<'de, D, K, V>(deserializer: D) -> Result<BTreeMap<K, Vec<V>>, D::Error>
92    where
93        D: Deserializer<'de>,
94        K: Ord,
95        V: Deserialize<'de> + Key<Key = K>,
96    {
97        let v = Vec::<V>::deserialize(deserializer)?;
98        let mut map = BTreeMap::new();
99        for item in v {
100            map.entry(item.key()).or_insert(vec![]).push(item);
101        }
102        Ok(map)
103    }
104
105    pub fn serialize<S, K, V>(map: &BTreeMap<K, Vec<V>>, serializer: S) -> Result<S::Ok, S::Error>
106    where
107        S: Serializer,
108        V: Serialize,
109    {
110        let len = map.values().flatten().collect::<Vec<_>>().len();
111        let mut seq = serializer.serialize_seq(Some(len))?;
112        for element in map.values().flatten() {
113            seq.serialize_element(element)?;
114        }
115        seq.end()
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_serialize_btreemap_values() -> anyhow::Result<()> {
125        #[derive(Serialize)]
126        struct TestStruct {
127            #[serde(with = "btreemap_vec_with")]
128            map: BTreeMap<usize, Vec<String>>,
129        }
130
131        let testdata = TestStruct {
132            map: BTreeMap::from([
133                (1, (0..1).map(|_| "1".into()).collect()),
134                (2, (0..2).map(|_| "2".into()).collect()),
135                (3, (0..3).map(|_| "3".into()).collect()),
136                (4, (0..4).map(|_| "4".into()).collect()),
137            ]),
138        };
139
140        let serialized = serde_json::to_string(&testdata)?;
141        let mut deserialized = serde_json::from_str::<serde_json::Value>(&serialized)?
142            .get("map")
143            .map(|x| serde_json::from_value::<Vec<String>>(x.clone()))
144            .unwrap()?;
145        deserialized.sort();
146        assert_eq!(
147            deserialized,
148            ["1", "2", "2", "3", "3", "3", "4", "4", "4", "4"]
149        );
150
151        Ok(())
152    }
153}