kittycad_execution_plan_traits/
primitive.rs

1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4use crate::{impl_value_on_primitive_ish, Address, MemoryError, Value};
5
6/// A value stored in KCEP program memory.
7#[derive(PartialEq, Clone, Serialize, Deserialize)]
8pub enum Primitive {
9    /// UTF-8 text
10    String(String),
11    /// Various number kinds
12    NumericValue(NumericPrimitive),
13    /// UUID
14    Uuid(Uuid),
15    /// Raw binary
16    Bytes(Vec<u8>),
17    /// True or false
18    Bool(bool),
19    /// List metadata.
20    ListHeader(ListHeader),
21    /// Object metadata.
22    ObjectHeader(ObjectHeader),
23    /// An optional value which was not given.
24    Nil,
25    /// Address in KCEP memory.
26    Address(Address),
27}
28
29impl std::fmt::Debug for Primitive {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        match self {
32            Primitive::String(s) => write!(f, r#""{s}""#),
33            Primitive::NumericValue(NumericPrimitive::Float(x)) => x.fmt(f),
34            Primitive::NumericValue(NumericPrimitive::Integer(x)) => x.fmt(f),
35            Primitive::NumericValue(NumericPrimitive::UInteger(x)) => write!(f, "{x} (uint)"),
36            Primitive::Uuid(u) => write!(f, "{u}"),
37            Primitive::Bytes(_) => write!(f, "Binary"),
38            Primitive::Bool(b) => write!(f, "{b}"),
39            Primitive::ListHeader(ListHeader { count, size }) => write!(f, "List header (count {count}, size {size})"),
40            Primitive::ObjectHeader(ObjectHeader { properties, size }) => {
41                write!(f, "Object header (props {properties:?}, size {size})")
42            }
43            Primitive::Nil => write!(f, "Nil"),
44            Primitive::Address(a) => write!(f, "Addr({})", a.0),
45        }
46    }
47}
48
49/// List metadata.
50/// A KCEP list is a layout for variable-length lists whose elements may be different types,
51/// and are identified by a uint index.
52#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize, Debug)]
53pub struct ListHeader {
54    /// How many elements are in the list?
55    pub count: usize,
56    /// How many addresses does the list take up in total?
57    pub size: usize,
58}
59
60/// Object metadata.
61/// A KCEP object is a layout for objects whose elements may be different types,
62/// and are identified by a string key.
63#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
64pub struct ObjectHeader {
65    /// What properties does the object have, and in what order are they laid out?
66    pub properties: Vec<String>,
67    /// What is the total size of this object
68    pub size: usize,
69}
70
71impl From<bool> for Primitive {
72    fn from(value: bool) -> Self {
73        Self::Bool(value)
74    }
75}
76
77impl From<Uuid> for Primitive {
78    fn from(u: Uuid) -> Self {
79        Self::Uuid(u)
80    }
81}
82
83impl From<String> for Primitive {
84    fn from(value: String) -> Self {
85        Self::String(value)
86    }
87}
88
89impl From<f32> for Primitive {
90    fn from(value: f32) -> Self {
91        Self::NumericValue(NumericPrimitive::Float(value as f64))
92    }
93}
94
95impl From<f64> for Primitive {
96    fn from(value: f64) -> Self {
97        Self::NumericValue(NumericPrimitive::Float(value))
98    }
99}
100
101impl From<Vec<u8>> for Primitive {
102    fn from(value: Vec<u8>) -> Self {
103        Self::Bytes(value)
104    }
105}
106
107impl From<ListHeader> for Primitive {
108    fn from(value: ListHeader) -> Self {
109        Self::ListHeader(value)
110    }
111}
112
113impl From<ObjectHeader> for Primitive {
114    fn from(value: ObjectHeader) -> Self {
115        Self::ObjectHeader(value)
116    }
117}
118
119impl From<Address> for Primitive {
120    fn from(value: Address) -> Self {
121        Self::Address(value)
122    }
123}
124
125impl TryFrom<Primitive> for String {
126    type Error = MemoryError;
127
128    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
129        if let Primitive::String(s) = value {
130            Ok(s)
131        } else {
132            Err(MemoryError::MemoryWrongType {
133                expected: "string",
134                actual: format!("{value:?}"),
135            })
136        }
137    }
138}
139
140impl TryFrom<Primitive> for Uuid {
141    type Error = MemoryError;
142
143    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
144        if let Primitive::Uuid(u) = value {
145            Ok(u)
146        } else {
147            Err(MemoryError::MemoryWrongType {
148                expected: "uuid",
149                actual: format!("{value:?}"),
150            })
151        }
152    }
153}
154
155impl TryFrom<Primitive> for f64 {
156    type Error = MemoryError;
157
158    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
159        if let Primitive::NumericValue(NumericPrimitive::Float(x)) = value {
160            Ok(x)
161        } else {
162            Err(MemoryError::MemoryWrongType {
163                expected: "float",
164                actual: format!("{value:?}"),
165            })
166        }
167    }
168}
169
170impl TryFrom<Primitive> for f32 {
171    type Error = MemoryError;
172
173    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
174        f64::try_from(value).map(|x| x as f32)
175    }
176}
177
178impl TryFrom<Primitive> for Vec<u8> {
179    type Error = MemoryError;
180
181    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
182        if let Primitive::Bytes(x) = value {
183            Ok(x)
184        } else {
185            Err(MemoryError::MemoryWrongType {
186                expected: "bytes",
187                actual: format!("{value:?}"),
188            })
189        }
190    }
191}
192
193impl TryFrom<Primitive> for bool {
194    type Error = MemoryError;
195
196    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
197        if let Primitive::Bool(x) = value {
198            Ok(x)
199        } else {
200            Err(MemoryError::MemoryWrongType {
201                expected: "bool",
202                actual: format!("{value:?}"),
203            })
204        }
205    }
206}
207
208impl TryFrom<Primitive> for Address {
209    type Error = MemoryError;
210
211    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
212        if let Primitive::Address(x) = value {
213            Ok(x)
214        } else {
215            Err(MemoryError::MemoryWrongType {
216                expected: "address",
217                actual: format!("{value:?}"),
218            })
219        }
220    }
221}
222
223impl TryFrom<Primitive> for usize {
224    type Error = MemoryError;
225
226    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
227        if let Primitive::NumericValue(NumericPrimitive::UInteger(x)) = value {
228            Ok(x)
229        } else {
230            Err(MemoryError::MemoryWrongType {
231                expected: "usize",
232                actual: format!("{value:?}"),
233            })
234        }
235    }
236}
237
238impl TryFrom<Primitive> for u32 {
239    type Error = MemoryError;
240
241    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
242        if let Primitive::NumericValue(NumericPrimitive::UInteger(x)) = value {
243            Ok(x.try_into().map_err(|_| MemoryError::MemoryWrongType {
244                expected: "u32",
245                actual: x.to_string(),
246            })?)
247        } else {
248            Err(MemoryError::MemoryWrongType {
249                expected: "u32",
250                actual: format!("{value:?}"),
251            })
252        }
253    }
254}
255
256impl TryFrom<Primitive> for ListHeader {
257    type Error = MemoryError;
258
259    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
260        if let Primitive::ListHeader(x) = value {
261            Ok(x)
262        } else {
263            Err(MemoryError::MemoryWrongType {
264                expected: "ListHeader",
265                actual: format!("{value:?}"),
266            })
267        }
268    }
269}
270
271impl TryFrom<Primitive> for ObjectHeader {
272    type Error = MemoryError;
273
274    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
275        if let Primitive::ObjectHeader(x) = value {
276            Ok(x)
277        } else {
278            Err(MemoryError::MemoryWrongType {
279                expected: "ObjectHeader",
280                actual: format!("{value:?}"),
281            })
282        }
283    }
284}
285
286impl TryFrom<Primitive> for i64 {
287    type Error = MemoryError;
288
289    fn try_from(value: Primitive) -> Result<Self, Self::Error> {
290        if let Primitive::NumericValue(NumericPrimitive::Integer(x)) = value {
291            Ok(x)
292        } else {
293            Err(MemoryError::MemoryWrongType {
294                expected: "i64",
295                actual: format!("{value:?}"),
296            })
297        }
298    }
299}
300
301impl From<usize> for Primitive {
302    fn from(value: usize) -> Self {
303        Self::NumericValue(NumericPrimitive::UInteger(value))
304    }
305}
306
307impl From<u32> for Primitive {
308    fn from(value: u32) -> Self {
309        Self::NumericValue(NumericPrimitive::UInteger(value as usize))
310    }
311}
312
313impl From<i64> for Primitive {
314    fn from(value: i64) -> Self {
315        Self::NumericValue(NumericPrimitive::Integer(value))
316    }
317}
318
319/// Various kinds of number.
320#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
321pub enum NumericPrimitive {
322    /// Unsigned integer
323    UInteger(usize),
324    /// Signed integer
325    Integer(i64),
326    /// Floating point
327    Float(f64),
328}
329
330impl crate::Value for Primitive {
331    fn into_parts(self) -> Vec<Primitive> {
332        vec![self]
333    }
334
335    fn from_parts<I>(values: &mut I) -> Result<(Self, usize), MemoryError>
336    where
337        I: Iterator<Item = Option<Primitive>>,
338    {
339        values
340            .next()
341            .and_then(|v| v.to_owned())
342            .ok_or(MemoryError::MemoryWrongSize)
343            .map(|prim| (prim, 1))
344    }
345}
346
347impl From<NumericPrimitive> for f64 {
348    fn from(value: NumericPrimitive) -> Self {
349        match value {
350            NumericPrimitive::UInteger(x) => x as f64,
351            NumericPrimitive::Integer(x) => x as f64,
352            NumericPrimitive::Float(x) => x,
353        }
354    }
355}
356
357impl_value_on_primitive_ish!(Value, f32);
358impl_value_on_primitive_ish!(Value, f64);
359impl_value_on_primitive_ish!(Value, bool);
360impl_value_on_primitive_ish!(Value, String);
361impl_value_on_primitive_ish!(Value, Uuid);
362type VecU8 = Vec<u8>;
363impl_value_on_primitive_ish!(Value, VecU8);
364impl_value_on_primitive_ish!(Value, usize);
365impl_value_on_primitive_ish!(Value, u32);
366impl_value_on_primitive_ish!(Value, i64);