vdf_reader/entry/
table.rs

1use super::{Array, Entry};
2use crate::entry::{string_is_array, Statement, Value};
3use crate::error::UnknownError;
4use crate::event::{EntryEvent, GroupStartEvent, ValueContinuationEvent};
5use crate::{Event, Item, Reader, Result, VdfError};
6use serde::de::{DeserializeSeed, MapAccess};
7use serde::{Deserialize, Serialize, Serializer};
8use std::collections::hash_map;
9use std::collections::HashMap;
10use std::ops::{Deref, DerefMut};
11
12/// A table of entries.
13#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, Default)]
14#[serde(transparent)]
15pub struct Table(#[serde(serialize_with = "ordered_map")] HashMap<String, Entry>); // todo: switch to a map that maintains item order
16
17impl From<HashMap<String, Entry>> for Table {
18    fn from(value: HashMap<String, Entry>) -> Self {
19        Table(value)
20    }
21}
22
23fn ordered_map<S, K: Ord + Serialize, V: Serialize>(
24    value: &HashMap<K, V>,
25    serializer: S,
26) -> Result<S::Ok, S::Error>
27where
28    S: Serializer,
29{
30    use std::collections::BTreeMap;
31    let ordered: BTreeMap<_, _> = value.iter().collect();
32    ordered.serialize(serializer)
33}
34
35fn insert<K: Into<String>, V: Into<Entry>>(map: &mut HashMap<String, Entry>, key: K, value: V) {
36    let key = key.into();
37    let value = value.into();
38    let entry = map.entry(key);
39    match entry {
40        hash_map::Entry::Vacant(entry) => {
41            entry.insert(value);
42        }
43        hash_map::Entry::Occupied(mut entry) => match entry.get_mut() {
44            Entry::Array(ref mut array) => {
45                array.push(value);
46            }
47            _ => {
48                let (key, old_value) = entry.remove_entry();
49                let mut array = Array::from(old_value);
50                array.push(value);
51                map.insert(key, Entry::Array(array));
52            }
53        },
54    }
55}
56
57impl Table {
58    pub fn load_from_str(input: &str) -> Result<Table> {
59        let mut reader = Reader::from(input);
60        Self::load(&mut reader)
61    }
62
63    /// Load a table from the given `Reader`.
64    pub fn load(reader: &mut Reader) -> Result<Table> {
65        let mut map = HashMap::new();
66        let mut last_key = None;
67
68        while let Some(event) = reader.event() {
69            last_key = match event? {
70                Event::Entry(EntryEvent {
71                    key: Item::Item { content: key, .. },
72                    value,
73                    ..
74                }) => {
75                    let str = value.as_str();
76                    let key_clone = key.clone();
77                    if string_is_array(str) {
78                        insert(
79                            &mut map,
80                            key,
81                            Array::from_space_separated(str[1..str.len() - 1].trim()),
82                        )
83                    } else {
84                        insert(&mut map, key, Value::from(value.into_content()))
85                    }
86                    Some(key_clone)
87                }
88
89                Event::Entry(EntryEvent {
90                    key: Item::Statement { content: key, .. },
91                    value,
92                    ..
93                }) => {
94                    let key_clone = key.clone();
95                    insert(&mut map, key, Statement::from(value.into_content()));
96                    Some(key_clone)
97                }
98
99                Event::ValueContinuation(ValueContinuationEvent { value, .. }) => {
100                    if let Some(key) = last_key.as_ref() {
101                        if let Some(last_value) = map.get_mut(key.as_ref()) {
102                            last_value.push(Value::from(value.into_content()).into())?;
103                        }
104                    }
105                    last_key
106                }
107
108                Event::GroupStart(GroupStartEvent { name, .. }) => {
109                    insert(&mut map, name, Table::load(reader)?);
110                    None
111                }
112
113                Event::GroupEnd(_) => break,
114            }
115        }
116
117        Ok(Table(map))
118    }
119}
120
121impl IntoIterator for Table {
122    type Item = (String, Entry);
123    type IntoIter = hash_map::IntoIter<String, Entry>;
124
125    fn into_iter(self) -> Self::IntoIter {
126        self.0.into_iter()
127    }
128}
129
130impl From<Table> for Entry {
131    fn from(table: Table) -> Self {
132        Entry::Table(table)
133    }
134}
135
136impl From<Table> for HashMap<String, Entry> {
137    fn from(table: Table) -> Self {
138        table.0
139    }
140}
141
142impl Deref for Table {
143    type Target = HashMap<String, Entry>;
144
145    fn deref(&self) -> &Self::Target {
146        &self.0
147    }
148}
149
150impl DerefMut for Table {
151    fn deref_mut(&mut self) -> &mut Self::Target {
152        &mut self.0
153    }
154}
155
156pub(crate) struct TableSeq {
157    iter: hash_map::IntoIter<String, Entry>,
158    next_item: Option<Entry>,
159}
160
161impl TableSeq {
162    pub(crate) fn new(table: Table) -> Self {
163        TableSeq {
164            iter: table.0.into_iter(),
165            next_item: None,
166        }
167    }
168}
169
170impl<'de> MapAccess<'de> for TableSeq {
171    type Error = VdfError;
172
173    fn next_key_seed<K>(&mut self, seed: K) -> std::result::Result<Option<K::Value>, Self::Error>
174    where
175        K: DeserializeSeed<'de>,
176    {
177        let (key, value) = match self.iter.next() {
178            Some(pair) => pair,
179            None => {
180                return Ok(None);
181            }
182        };
183        self.next_item = Some(value);
184        seed.deserialize(Value::from(key)).map(Some)
185    }
186
187    fn next_value_seed<V>(&mut self, seed: V) -> std::result::Result<V::Value, Self::Error>
188    where
189        V: DeserializeSeed<'de>,
190    {
191        let item = match self.next_item.take() {
192            Some(item) => item,
193            None => return Err(UnknownError::from("double take value").into()),
194        };
195
196        seed.deserialize(item)
197    }
198}
199
200#[cfg(test)]
201#[track_caller]
202fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T {
203    r.map_err(miette::Error::from).unwrap()
204}
205
206#[test]
207fn test_serde_table() {
208    use maplit::hashmap;
209
210    let j = r#"{foo bar}"#;
211
212    assert_eq!(
213        Table(hashmap! {"foo".into() => Entry::Value("bar".into())}),
214        unwrap_err(crate::from_str(j))
215    );
216}