kittycad_execution_plan_traits/
containers.rs

1//! Impl Value for various container types, if the inner type implements Value.
2
3use std::collections::HashSet;
4
5use crate::{MemoryError, Primitive, Value};
6const NONE: &str = "None";
7const SOME: &str = "Some";
8
9/// Use the standard enum convention (a string for the variant tag, then all fields of the variant)
10impl<T> Value for Option<T>
11where
12    T: Value,
13{
14    fn into_parts(self) -> Vec<Primitive> {
15        match self {
16            Some(v) => {
17                let mut parts = Vec::new();
18                parts.push(SOME.to_owned().into());
19                parts.extend(v.into_parts());
20                parts
21            }
22            None => vec![NONE.to_owned().into()],
23        }
24    }
25
26    fn from_parts<I>(values: &mut I) -> Result<(Self, usize), MemoryError>
27    where
28        I: Iterator<Item = Option<Primitive>>,
29    {
30        let variant: String = values
31            .next()
32            .flatten()
33            .ok_or(MemoryError::MemoryWrongSize)?
34            .try_into()?;
35        match variant.as_str() {
36            NONE => Ok((None, 1)),
37            SOME => {
38                let (val, count) = T::from_parts(values)?;
39                Ok((Some(val), count + 1))
40            }
41            other => Err(MemoryError::InvalidEnumVariant {
42                expected_type: "option".to_owned(),
43                actual: other.to_owned(),
44                valid_variants: vec![NONE, SOME],
45            }),
46        }
47    }
48}
49
50/// Store the vec's length as the first primitive, then lay out all elements.
51impl<T> Value for Vec<T>
52where
53    T: Value,
54{
55    fn into_parts(self) -> Vec<Primitive> {
56        let mut parts: Vec<Primitive> = Vec::with_capacity(self.len() + 1);
57        parts.push(self.len().into());
58        parts.extend(self.into_iter().flat_map(|part| part.into_parts()));
59        parts
60    }
61
62    fn from_parts<I>(values: &mut I) -> Result<(Self, usize), MemoryError>
63    where
64        I: Iterator<Item = Option<Primitive>>,
65    {
66        // Read the length of the vec -- how many elements does it have?
67        let n: usize = values
68            .next()
69            .flatten()
70            .ok_or(MemoryError::MemoryWrongSize)?
71            .try_into()?;
72        // Read `n` elements from the parts.
73        (0..n).try_fold((Vec::with_capacity(n), 1), |(mut elems, count), _i| {
74            // Read another element, update the elements and the total primitive count.
75            let (next, next_count) = T::from_parts(values)?;
76            elems.push(next);
77            Ok((elems, count + next_count))
78        })
79    }
80}
81
82/// Store the HashMap's length as the first primitive, then lay out all elements.
83impl<T> Value for HashSet<T>
84where
85    T: Value + Eq + std::hash::Hash,
86{
87    fn into_parts(self) -> Vec<Primitive> {
88        let mut parts: Vec<Primitive> = Vec::with_capacity(self.len() + 1);
89        parts.push(self.len().into());
90        parts.extend(self.into_iter().flat_map(|part| part.into_parts()));
91        parts
92    }
93
94    fn from_parts<I>(values: &mut I) -> Result<(Self, usize), MemoryError>
95    where
96        I: Iterator<Item = Option<Primitive>>,
97    {
98        // Vec and HashSet use the same layout, so just read a vec.
99        Vec::from_parts(values)
100            // Then convert the vec into a hashmap.
101            .map(|(v, count)| (v.into_iter().collect(), count))
102    }
103}
104
105/// `Box<T>` is laid out identically to an unboxed `T`.
106impl<T> Value for Box<T>
107where
108    T: Value,
109{
110    fn into_parts(self) -> Vec<Primitive> {
111        (*self).into_parts()
112    }
113
114    fn from_parts<I>(values: &mut I) -> Result<(Self, usize), MemoryError>
115    where
116        I: Iterator<Item = Option<Primitive>>,
117    {
118        T::from_parts(values).map(|(x, i)| (Box::new(x), i))
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_name() {
128        let h: HashSet<uuid::Uuid> = HashSet::new();
129        fn assert_set_of_uuid_impls_value<T>(_t: T)
130        where
131            T: Value,
132        {
133        }
134        assert_set_of_uuid_impls_value(h)
135    }
136}