Skip to main content

ormdb_proto/
value.rs

1//! Runtime value types for protocol messages.
2
3use rkyv::{Archive, Deserialize, Serialize};
4use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
5
6/// A runtime value that can be serialized over the wire.
7///
8/// This enum represents all possible values that can be passed in queries,
9/// mutations, and results. It maps to the scalar types defined in the catalog.
10///
11/// Note: Arrays are typed (e.g., BoolArray, Int32Array) to avoid recursive
12/// type issues with rkyv serialization.
13#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
14pub enum Value {
15    /// Null value.
16    Null,
17    /// Boolean value.
18    Bool(bool),
19    /// 32-bit signed integer.
20    Int32(i32),
21    /// 64-bit signed integer.
22    Int64(i64),
23    /// 32-bit floating point.
24    Float32(f32),
25    /// 64-bit floating point.
26    Float64(f64),
27    /// UTF-8 string.
28    String(String),
29    /// Binary data.
30    Bytes(Vec<u8>),
31    /// Timestamp as microseconds since Unix epoch.
32    Timestamp(i64),
33    /// UUID as 16 bytes.
34    Uuid([u8; 16]),
35    /// Array of booleans.
36    BoolArray(Vec<bool>),
37    /// Array of 32-bit integers.
38    Int32Array(Vec<i32>),
39    /// Array of 64-bit integers.
40    Int64Array(Vec<i64>),
41    /// Array of 32-bit floats.
42    Float32Array(Vec<f32>),
43    /// Array of 64-bit floats.
44    Float64Array(Vec<f64>),
45    /// Array of strings.
46    StringArray(Vec<String>),
47    /// Array of UUIDs.
48    UuidArray(Vec<[u8; 16]>),
49}
50
51impl Value {
52    /// Check if this value is null.
53    pub fn is_null(&self) -> bool {
54        matches!(self, Value::Null)
55    }
56
57    /// Check if this value is an array type.
58    pub fn is_array(&self) -> bool {
59        matches!(
60            self,
61            Value::BoolArray(_)
62                | Value::Int32Array(_)
63                | Value::Int64Array(_)
64                | Value::Float32Array(_)
65                | Value::Float64Array(_)
66                | Value::StringArray(_)
67                | Value::UuidArray(_)
68        )
69    }
70
71    /// Try to get as bool.
72    pub fn as_bool(&self) -> Option<bool> {
73        match self {
74            Value::Bool(b) => Some(*b),
75            _ => None,
76        }
77    }
78
79    /// Try to get as i32.
80    pub fn as_i32(&self) -> Option<i32> {
81        match self {
82            Value::Int32(i) => Some(*i),
83            _ => None,
84        }
85    }
86
87    /// Try to get as i64.
88    pub fn as_i64(&self) -> Option<i64> {
89        match self {
90            Value::Int64(i) => Some(*i),
91            Value::Int32(i) => Some(*i as i64),
92            _ => None,
93        }
94    }
95
96    /// Try to get as f32.
97    pub fn as_f32(&self) -> Option<f32> {
98        match self {
99            Value::Float32(f) => Some(*f),
100            _ => None,
101        }
102    }
103
104    /// Try to get as f64.
105    pub fn as_f64(&self) -> Option<f64> {
106        match self {
107            Value::Float64(f) => Some(*f),
108            Value::Float32(f) => Some(*f as f64),
109            _ => None,
110        }
111    }
112
113    /// Try to get as string reference.
114    pub fn as_str(&self) -> Option<&str> {
115        match self {
116            Value::String(s) => Some(s),
117            _ => None,
118        }
119    }
120
121    /// Try to get as bytes reference.
122    pub fn as_bytes(&self) -> Option<&[u8]> {
123        match self {
124            Value::Bytes(b) => Some(b),
125            _ => None,
126        }
127    }
128
129    /// Try to get as timestamp.
130    pub fn as_timestamp(&self) -> Option<i64> {
131        match self {
132            Value::Timestamp(t) => Some(*t),
133            _ => None,
134        }
135    }
136
137    /// Try to get as UUID.
138    pub fn as_uuid(&self) -> Option<&[u8; 16]> {
139        match self {
140            Value::Uuid(u) => Some(u),
141            _ => None,
142        }
143    }
144}
145
146// Conversion implementations
147impl From<bool> for Value {
148    fn from(v: bool) -> Self {
149        Value::Bool(v)
150    }
151}
152
153impl From<i32> for Value {
154    fn from(v: i32) -> Self {
155        Value::Int32(v)
156    }
157}
158
159impl From<i64> for Value {
160    fn from(v: i64) -> Self {
161        Value::Int64(v)
162    }
163}
164
165impl From<f32> for Value {
166    fn from(v: f32) -> Self {
167        Value::Float32(v)
168    }
169}
170
171impl From<f64> for Value {
172    fn from(v: f64) -> Self {
173        Value::Float64(v)
174    }
175}
176
177impl From<String> for Value {
178    fn from(v: String) -> Self {
179        Value::String(v)
180    }
181}
182
183impl From<&str> for Value {
184    fn from(v: &str) -> Self {
185        Value::String(v.to_string())
186    }
187}
188
189impl From<Vec<u8>> for Value {
190    fn from(v: Vec<u8>) -> Self {
191        Value::Bytes(v)
192    }
193}
194
195impl From<[u8; 16]> for Value {
196    fn from(v: [u8; 16]) -> Self {
197        Value::Uuid(v)
198    }
199}
200
201impl From<Vec<bool>> for Value {
202    fn from(v: Vec<bool>) -> Self {
203        Value::BoolArray(v)
204    }
205}
206
207impl From<Vec<i32>> for Value {
208    fn from(v: Vec<i32>) -> Self {
209        Value::Int32Array(v)
210    }
211}
212
213impl From<Vec<i64>> for Value {
214    fn from(v: Vec<i64>) -> Self {
215        Value::Int64Array(v)
216    }
217}
218
219impl From<Vec<String>> for Value {
220    fn from(v: Vec<String>) -> Self {
221        Value::StringArray(v)
222    }
223}
224
225impl<T: Into<Value>> From<Option<T>> for Value {
226    fn from(v: Option<T>) -> Self {
227        match v {
228            Some(val) => val.into(),
229            None => Value::Null,
230        }
231    }
232}
233
234#[cfg(test)]
235mod tests {
236    use super::*;
237
238    #[test]
239    fn test_value_accessors() {
240        assert!(Value::Null.is_null());
241        assert!(!Value::Bool(true).is_null());
242
243        assert_eq!(Value::Bool(true).as_bool(), Some(true));
244        assert_eq!(Value::Int32(42).as_i32(), Some(42));
245        assert_eq!(Value::Int64(100).as_i64(), Some(100));
246        assert_eq!(Value::Int32(42).as_i64(), Some(42)); // Widening conversion
247
248        assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
249        assert_eq!(Value::Bytes(vec![1, 2, 3]).as_bytes(), Some(&[1, 2, 3][..]));
250    }
251
252    #[test]
253    fn test_value_conversions() {
254        let v: Value = true.into();
255        assert_eq!(v, Value::Bool(true));
256
257        let v: Value = 42i32.into();
258        assert_eq!(v, Value::Int32(42));
259
260        let v: Value = "hello".into();
261        assert_eq!(v, Value::String("hello".into()));
262
263        let v: Value = None::<i32>.into();
264        assert_eq!(v, Value::Null);
265
266        let v: Value = Some(42i32).into();
267        assert_eq!(v, Value::Int32(42));
268    }
269
270    #[test]
271    fn test_array_values() {
272        let v: Value = vec![1i32, 2, 3].into();
273        assert!(v.is_array());
274        assert_eq!(v, Value::Int32Array(vec![1, 2, 3]));
275
276        let v: Value = vec!["a".to_string(), "b".to_string()].into();
277        assert!(v.is_array());
278    }
279
280    #[test]
281    fn test_value_serialization_roundtrip() {
282        let values = vec![
283            Value::Null,
284            Value::Bool(true),
285            Value::Int32(-42),
286            Value::Int64(i64::MAX),
287            Value::Float32(3.14),
288            Value::Float64(std::f64::consts::PI),
289            Value::String("hello world".into()),
290            Value::Bytes(vec![0, 1, 2, 255]),
291            Value::Timestamp(1704067200_000_000), // 2024-01-01 00:00:00 UTC
292            Value::Uuid([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
293            Value::Int32Array(vec![1, 2, 3]),
294            Value::StringArray(vec!["a".into(), "b".into()]),
295        ];
296
297        for value in values {
298            let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&value).unwrap();
299            let archived = rkyv::access::<ArchivedValue, rkyv::rancor::Error>(&bytes).unwrap();
300            let deserialized: Value =
301                rkyv::deserialize::<Value, rkyv::rancor::Error>(archived).unwrap();
302            assert_eq!(value, deserialized);
303        }
304    }
305}