1use serde::{Deserialize, Serialize};
8use std::collections::BTreeMap;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum DurationUnit {
14 Nanoseconds,
15 Microseconds,
16 Milliseconds,
17 Seconds,
18 Minutes,
19 Hours,
20 Days,
21 Weeks,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub enum WireValue {
30 Null,
32
33 Bool(bool),
35
36 Number(f64),
38
39 Integer(i64),
41
42 I8(i8),
44 U8(u8),
46 I16(i16),
48 U16(u16),
50 I32(i32),
52 U32(u32),
54 I64(i64),
56 U64(u64),
58 Isize(i64),
60 Usize(u64),
62 Ptr(u64),
64 F32(f32),
66
67 String(String),
69
70 Timestamp(i64),
72
73 Duration { value: f64, unit: DurationUnit },
75
76 Array(Vec<WireValue>),
78
79 Object(BTreeMap<String, WireValue>),
81
82 Table(WireTable),
84
85 Result { ok: bool, value: Box<WireValue> },
87
88 Range {
90 start: Option<Box<WireValue>>,
91 end: Option<Box<WireValue>>,
92 inclusive: bool,
93 },
94
95 FunctionRef { name: String },
97
98 PrintResult(crate::print_result::WirePrintResult),
100
101 Content(shape_value::content::ContentNode),
103}
104
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
109pub struct WireTable {
110 pub ipc_bytes: Vec<u8>,
112 pub type_name: Option<String>,
114 pub schema_id: Option<u32>,
116 pub row_count: usize,
118 pub column_count: usize,
120}
121
122#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
124pub enum WireColumn {
125 Numbers(Vec<f64>),
127
128 Integers(Vec<i64>),
130
131 Booleans(Vec<bool>),
133
134 Strings(Vec<String>),
136
137 Objects(Vec<WireValue>),
139}
140
141impl WireValue {
142 pub fn null() -> Self {
144 WireValue::Null
145 }
146
147 pub fn is_null(&self) -> bool {
149 matches!(self, WireValue::Null)
150 }
151
152 pub fn as_number(&self) -> Option<f64> {
154 match self {
155 WireValue::Number(n) => Some(*n),
156 WireValue::Integer(i) => Some(*i as f64),
157 WireValue::I8(v) => Some(*v as f64),
158 WireValue::U8(v) => Some(*v as f64),
159 WireValue::I16(v) => Some(*v as f64),
160 WireValue::U16(v) => Some(*v as f64),
161 WireValue::I32(v) => Some(*v as f64),
162 WireValue::U32(v) => Some(*v as f64),
163 WireValue::I64(_)
166 | WireValue::U64(_)
167 | WireValue::Isize(_)
168 | WireValue::Usize(_)
169 | WireValue::Ptr(_) => None,
170 WireValue::F32(v) => Some(*v as f64),
171 _ => None,
172 }
173 }
174
175 pub fn as_str(&self) -> Option<&str> {
177 match self {
178 WireValue::String(s) => Some(s),
179 _ => None,
180 }
181 }
182
183 pub fn as_bool(&self) -> Option<bool> {
185 match self {
186 WireValue::Bool(b) => Some(*b),
187 _ => None,
188 }
189 }
190
191 pub fn type_name(&self) -> &'static str {
193 match self {
194 WireValue::Null => "Null",
195 WireValue::Bool(_) => "Bool",
196 WireValue::Number(_) => "Number",
197 WireValue::Integer(_) => "Integer",
198 WireValue::I8(_) => "i8",
199 WireValue::U8(_) => "u8",
200 WireValue::I16(_) => "i16",
201 WireValue::U16(_) => "u16",
202 WireValue::I32(_) => "i32",
203 WireValue::U32(_) => "u32",
204 WireValue::I64(_) => "i64",
205 WireValue::U64(_) => "u64",
206 WireValue::Isize(_) => "isize",
207 WireValue::Usize(_) => "usize",
208 WireValue::Ptr(_) => "ptr",
209 WireValue::F32(_) => "f32",
210 WireValue::String(_) => "String",
211 WireValue::Timestamp(_) => "Timestamp",
212 WireValue::Duration { .. } => "Duration",
213 WireValue::Array(_) => "Array",
214 WireValue::Object(_) => "Object",
215 WireValue::Table(_) => "Table",
216 WireValue::Result { .. } => "Result",
217 WireValue::Range { .. } => "Range",
218 WireValue::FunctionRef { .. } => "Function",
219 WireValue::PrintResult(_) => "PrintResult",
220 WireValue::Content(_) => "Content",
221 }
222 }
223}
224
225impl WireTable {
226 pub fn empty() -> Self {
228 WireTable {
229 ipc_bytes: Vec::new(),
230 type_name: None,
231 schema_id: None,
232 row_count: 0,
233 column_count: 0,
234 }
235 }
236}
237
238impl WireColumn {
239 pub fn len(&self) -> usize {
241 match self {
242 WireColumn::Numbers(v) => v.len(),
243 WireColumn::Integers(v) => v.len(),
244 WireColumn::Booleans(v) => v.len(),
245 WireColumn::Strings(v) => v.len(),
246 WireColumn::Objects(v) => v.len(),
247 }
248 }
249
250 pub fn is_empty(&self) -> bool {
252 self.len() == 0
253 }
254
255 pub fn element_type(&self) -> &'static str {
257 match self {
258 WireColumn::Numbers(_) => "Number",
259 WireColumn::Integers(_) => "Integer",
260 WireColumn::Booleans(_) => "Bool",
261 WireColumn::Strings(_) => "String",
262 WireColumn::Objects(_) => "Object",
263 }
264 }
265}
266
267impl From<bool> for WireValue {
269 fn from(b: bool) -> Self {
270 WireValue::Bool(b)
271 }
272}
273
274impl From<f64> for WireValue {
275 fn from(n: f64) -> Self {
276 WireValue::Number(n)
277 }
278}
279
280impl From<i64> for WireValue {
281 fn from(n: i64) -> Self {
282 WireValue::Integer(n)
283 }
284}
285
286impl From<u64> for WireValue {
287 fn from(n: u64) -> Self {
288 WireValue::U64(n)
289 }
290}
291
292impl From<i32> for WireValue {
293 fn from(n: i32) -> Self {
294 WireValue::I32(n)
295 }
296}
297
298impl From<u32> for WireValue {
299 fn from(n: u32) -> Self {
300 WireValue::U32(n)
301 }
302}
303
304impl From<i16> for WireValue {
305 fn from(n: i16) -> Self {
306 WireValue::I16(n)
307 }
308}
309
310impl From<u16> for WireValue {
311 fn from(n: u16) -> Self {
312 WireValue::U16(n)
313 }
314}
315
316impl From<i8> for WireValue {
317 fn from(n: i8) -> Self {
318 WireValue::I8(n)
319 }
320}
321
322impl From<u8> for WireValue {
323 fn from(n: u8) -> Self {
324 WireValue::U8(n)
325 }
326}
327
328impl From<f32> for WireValue {
329 fn from(n: f32) -> Self {
330 WireValue::F32(n)
331 }
332}
333
334impl From<String> for WireValue {
335 fn from(s: String) -> Self {
336 WireValue::String(s)
337 }
338}
339
340impl From<&str> for WireValue {
341 fn from(s: &str) -> Self {
342 WireValue::String(s.to_string())
343 }
344}
345
346impl<T: Into<WireValue>> From<Vec<T>> for WireValue {
347 fn from(v: Vec<T>) -> Self {
348 WireValue::Array(v.into_iter().map(Into::into).collect())
349 }
350}
351
352impl<T: Into<WireValue>> From<Option<T>> for WireValue {
353 fn from(opt: Option<T>) -> Self {
354 match opt {
355 Some(v) => v.into(),
356 None => WireValue::Null,
357 }
358 }
359}
360
361impl From<serde_json::Value> for WireValue {
367 fn from(json: serde_json::Value) -> Self {
368 match json {
369 serde_json::Value::Null => WireValue::Null,
370 serde_json::Value::Bool(b) => WireValue::Bool(b),
371 serde_json::Value::Number(n) => {
372 if let Some(i) = n.as_i64() {
373 WireValue::Integer(i)
374 } else if let Some(u) = n.as_u64() {
375 WireValue::U64(u)
376 } else if let Some(f) = n.as_f64() {
377 WireValue::Number(f)
378 } else {
379 WireValue::Null
380 }
381 }
382 serde_json::Value::String(s) => WireValue::String(s),
383 serde_json::Value::Array(arr) => {
384 WireValue::Array(arr.into_iter().map(WireValue::from).collect())
385 }
386 serde_json::Value::Object(obj) => {
387 let map: BTreeMap<String, WireValue> = obj
389 .into_iter()
390 .map(|(k, v)| (k, WireValue::from(v)))
391 .collect();
392 WireValue::Object(map)
393 }
394 }
395 }
396}
397
398impl From<&serde_json::Value> for WireValue {
399 fn from(json: &serde_json::Value) -> Self {
400 WireValue::from(json.clone())
401 }
402}
403
404#[cfg(test)]
405mod tests {
406 use super::*;
407
408 #[test]
409 fn test_wire_value_type_names() {
410 assert_eq!(WireValue::Null.type_name(), "Null");
411 assert_eq!(WireValue::Bool(true).type_name(), "Bool");
412 assert_eq!(WireValue::Number(1.0).type_name(), "Number");
413 assert_eq!(WireValue::String("test".into()).type_name(), "String");
414 }
415
416 #[test]
417 fn test_wire_value_conversions() {
418 let v: WireValue = 42.0.into();
419 assert_eq!(v.as_number(), Some(42.0));
420
421 let v = WireValue::I64(42);
422 assert_eq!(v.as_number(), None, "i64 should not coerce to number");
423
424 let v: WireValue = "hello".into();
425 assert_eq!(v.as_str(), Some("hello"));
426
427 let v: WireValue = true.into();
428 assert_eq!(v.as_bool(), Some(true));
429 }
430
431 #[test]
432 fn test_wire_series_empty() {
433 let series = WireTable::empty();
434 assert_eq!(series.row_count, 0);
435 assert_eq!(series.column_count, 0);
436 assert!(series.ipc_bytes.is_empty());
437 }
438
439 #[test]
440 fn test_json_to_wire_conversion() {
441 let json = serde_json::json!(null);
443 let wire = WireValue::from(json);
444 assert!(wire.is_null());
445
446 let json = serde_json::json!(true);
448 let wire = WireValue::from(json);
449 assert_eq!(wire.as_bool(), Some(true));
450
451 let json = serde_json::json!(42);
453 let wire = WireValue::from(json);
454 assert!(matches!(wire, WireValue::Integer(42)));
455
456 let json = serde_json::json!(3.14);
458 let wire = WireValue::from(json);
459 assert!(matches!(wire, WireValue::Number(n) if (n - 3.14).abs() < 0.001));
460
461 let json = serde_json::json!("hello");
463 let wire = WireValue::from(json);
464 assert_eq!(wire.as_str(), Some("hello"));
465
466 let json = serde_json::json!([1, 2, 3]);
468 let wire = WireValue::from(json);
469 assert!(matches!(wire, WireValue::Array(arr) if arr.len() == 3));
470
471 let json = serde_json::json!({"x": 10, "y": 20});
473 let wire = WireValue::from(json);
474 if let WireValue::Object(map) = wire {
475 assert_eq!(map.len(), 2);
476 } else {
477 panic!("Expected Object");
478 }
479 }
480}