Skip to main content

nix_compat/wire/de/
collections.rs

1use std::{
2    collections::{BTreeMap, BTreeSet},
3    future::Future,
4};
5
6use super::{NixDeserialize, NixRead};
7
8#[allow(clippy::manual_async_fn)]
9impl<T> NixDeserialize for Vec<T>
10where
11    T: NixDeserialize + Send,
12{
13    fn try_deserialize<R>(
14        reader: &mut R,
15    ) -> impl Future<Output = Result<Option<Self>, R::Error>> + Send + '_
16    where
17        R: ?Sized + NixRead + Send,
18    {
19        async move {
20            if let Some(len) = reader.try_read_value::<usize>().await? {
21                let mut ret = Vec::with_capacity(len);
22                for _ in 0..len {
23                    ret.push(reader.read_value().await?);
24                }
25                Ok(Some(ret))
26            } else {
27                Ok(None)
28            }
29        }
30    }
31}
32
33#[allow(clippy::manual_async_fn)]
34impl<K, V> NixDeserialize for BTreeMap<K, V>
35where
36    K: NixDeserialize + Ord + Send,
37    V: NixDeserialize + Send,
38{
39    fn try_deserialize<R>(
40        reader: &mut R,
41    ) -> impl Future<Output = Result<Option<Self>, R::Error>> + Send + '_
42    where
43        R: ?Sized + NixRead + Send,
44    {
45        async move {
46            if let Some(len) = reader.try_read_value::<usize>().await? {
47                let mut ret = BTreeMap::new();
48                for _ in 0..len {
49                    let key = reader.read_value().await?;
50                    let value = reader.read_value().await?;
51                    ret.insert(key, value);
52                }
53                Ok(Some(ret))
54            } else {
55                Ok(None)
56            }
57        }
58    }
59}
60
61#[allow(clippy::manual_async_fn)]
62impl<T> NixDeserialize for BTreeSet<T>
63where
64    T: NixDeserialize + Ord + Send,
65{
66    fn try_deserialize<R>(
67        reader: &mut R,
68    ) -> impl Future<Output = Result<Option<Self>, R::Error>> + Send + '_
69    where
70        R: ?Sized + NixRead + Send,
71    {
72        async move {
73            if let Some(len) = reader.try_read_value::<usize>().await? {
74                let mut ret = BTreeSet::new();
75                for _ in 0..len {
76                    ret.insert(reader.read_value().await?);
77                }
78                Ok(Some(ret))
79            } else {
80                Ok(None)
81            }
82        }
83    }
84}
85
86#[cfg(test)]
87mod test {
88    use std::collections::BTreeMap;
89    use std::fmt;
90
91    use hex_literal::hex;
92    use rstest::rstest;
93    use tokio_test::io::Builder;
94
95    use crate::wire::de::{NixDeserialize, NixRead, NixReader};
96
97    #[rstest]
98    #[case::empty(vec![], &hex!("0000 0000 0000 0000"))]
99    #[case::one(vec![0x29], &hex!("0100 0000 0000 0000 2900 0000 0000 0000"))]
100    #[case::two(vec![0x7469, 10], &hex!("0200 0000 0000 0000 6974 0000 0000 0000 0A00 0000 0000 0000"))]
101    #[tokio::test]
102    async fn test_read_small_vec(#[case] expected: Vec<usize>, #[case] data: &[u8]) {
103        let mock = Builder::new().read(data).build();
104        let mut reader = NixReader::new(mock);
105        let actual: Vec<usize> = reader.read_value().await.unwrap();
106        assert_eq!(actual, expected);
107    }
108
109    fn empty_map() -> BTreeMap<usize, u64> {
110        BTreeMap::new()
111    }
112    macro_rules! map {
113        ($($key:expr => $value:expr),*) => {{
114            let mut ret = BTreeMap::new();
115            $(ret.insert($key, $value);)*
116            ret
117        }};
118    }
119
120    #[rstest]
121    #[case::empty(empty_map(), &hex!("0000 0000 0000 0000"))]
122    #[case::one(map![0x7469usize => 10u64], &hex!("0100 0000 0000 0000 6974 0000 0000 0000 0A00 0000 0000 0000"))]
123    #[tokio::test]
124    async fn test_read_small_btree_map<E>(#[case] expected: E, #[case] data: &[u8])
125    where
126        E: NixDeserialize + PartialEq + fmt::Debug,
127    {
128        let mock = Builder::new().read(data).build();
129        let mut reader = NixReader::new(mock);
130        let actual: E = reader.read_value().await.unwrap();
131        assert_eq!(actual, expected);
132    }
133}