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
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106pub struct WireTable {
107 pub ipc_bytes: Vec<u8>,
109 pub type_name: Option<String>,
111 pub schema_id: Option<u32>,
113 pub row_count: usize,
115 pub column_count: usize,
117}
118
119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
121pub enum WireColumn {
122 Numbers(Vec<f64>),
124
125 Integers(Vec<i64>),
127
128 Booleans(Vec<bool>),
130
131 Strings(Vec<String>),
133
134 Objects(Vec<WireValue>),
136}
137
138impl WireValue {
139 pub fn null() -> Self {
141 WireValue::Null
142 }
143
144 pub fn is_null(&self) -> bool {
146 matches!(self, WireValue::Null)
147 }
148
149 pub fn as_number(&self) -> Option<f64> {
151 match self {
152 WireValue::Number(n) => Some(*n),
153 WireValue::Integer(i) => Some(*i as f64),
154 WireValue::I8(v) => Some(*v as f64),
155 WireValue::U8(v) => Some(*v as f64),
156 WireValue::I16(v) => Some(*v as f64),
157 WireValue::U16(v) => Some(*v as f64),
158 WireValue::I32(v) => Some(*v as f64),
159 WireValue::U32(v) => Some(*v as f64),
160 WireValue::I64(_)
163 | WireValue::U64(_)
164 | WireValue::Isize(_)
165 | WireValue::Usize(_)
166 | WireValue::Ptr(_) => None,
167 WireValue::F32(v) => Some(*v as f64),
168 _ => None,
169 }
170 }
171
172 pub fn as_str(&self) -> Option<&str> {
174 match self {
175 WireValue::String(s) => Some(s),
176 _ => None,
177 }
178 }
179
180 pub fn as_bool(&self) -> Option<bool> {
182 match self {
183 WireValue::Bool(b) => Some(*b),
184 _ => None,
185 }
186 }
187
188 pub fn type_name(&self) -> &'static str {
190 match self {
191 WireValue::Null => "Null",
192 WireValue::Bool(_) => "Bool",
193 WireValue::Number(_) => "Number",
194 WireValue::Integer(_) => "Integer",
195 WireValue::I8(_) => "i8",
196 WireValue::U8(_) => "u8",
197 WireValue::I16(_) => "i16",
198 WireValue::U16(_) => "u16",
199 WireValue::I32(_) => "i32",
200 WireValue::U32(_) => "u32",
201 WireValue::I64(_) => "i64",
202 WireValue::U64(_) => "u64",
203 WireValue::Isize(_) => "isize",
204 WireValue::Usize(_) => "usize",
205 WireValue::Ptr(_) => "ptr",
206 WireValue::F32(_) => "f32",
207 WireValue::String(_) => "String",
208 WireValue::Timestamp(_) => "Timestamp",
209 WireValue::Duration { .. } => "Duration",
210 WireValue::Array(_) => "Array",
211 WireValue::Object(_) => "Object",
212 WireValue::Table(_) => "Table",
213 WireValue::Result { .. } => "Result",
214 WireValue::Range { .. } => "Range",
215 WireValue::FunctionRef { .. } => "Function",
216 WireValue::PrintResult(_) => "PrintResult",
217 }
218 }
219}
220
221impl WireTable {
222 pub fn empty() -> Self {
224 WireTable {
225 ipc_bytes: Vec::new(),
226 type_name: None,
227 schema_id: None,
228 row_count: 0,
229 column_count: 0,
230 }
231 }
232}
233
234impl WireColumn {
235 pub fn len(&self) -> usize {
237 match self {
238 WireColumn::Numbers(v) => v.len(),
239 WireColumn::Integers(v) => v.len(),
240 WireColumn::Booleans(v) => v.len(),
241 WireColumn::Strings(v) => v.len(),
242 WireColumn::Objects(v) => v.len(),
243 }
244 }
245
246 pub fn is_empty(&self) -> bool {
248 self.len() == 0
249 }
250
251 pub fn element_type(&self) -> &'static str {
253 match self {
254 WireColumn::Numbers(_) => "Number",
255 WireColumn::Integers(_) => "Integer",
256 WireColumn::Booleans(_) => "Bool",
257 WireColumn::Strings(_) => "String",
258 WireColumn::Objects(_) => "Object",
259 }
260 }
261}
262
263impl From<bool> for WireValue {
265 fn from(b: bool) -> Self {
266 WireValue::Bool(b)
267 }
268}
269
270impl From<f64> for WireValue {
271 fn from(n: f64) -> Self {
272 WireValue::Number(n)
273 }
274}
275
276impl From<i64> for WireValue {
277 fn from(n: i64) -> Self {
278 WireValue::Integer(n)
279 }
280}
281
282impl From<u64> for WireValue {
283 fn from(n: u64) -> Self {
284 WireValue::U64(n)
285 }
286}
287
288impl From<i32> for WireValue {
289 fn from(n: i32) -> Self {
290 WireValue::I32(n)
291 }
292}
293
294impl From<u32> for WireValue {
295 fn from(n: u32) -> Self {
296 WireValue::U32(n)
297 }
298}
299
300impl From<i16> for WireValue {
301 fn from(n: i16) -> Self {
302 WireValue::I16(n)
303 }
304}
305
306impl From<u16> for WireValue {
307 fn from(n: u16) -> Self {
308 WireValue::U16(n)
309 }
310}
311
312impl From<i8> for WireValue {
313 fn from(n: i8) -> Self {
314 WireValue::I8(n)
315 }
316}
317
318impl From<u8> for WireValue {
319 fn from(n: u8) -> Self {
320 WireValue::U8(n)
321 }
322}
323
324impl From<f32> for WireValue {
325 fn from(n: f32) -> Self {
326 WireValue::F32(n)
327 }
328}
329
330impl From<String> for WireValue {
331 fn from(s: String) -> Self {
332 WireValue::String(s)
333 }
334}
335
336impl From<&str> for WireValue {
337 fn from(s: &str) -> Self {
338 WireValue::String(s.to_string())
339 }
340}
341
342impl<T: Into<WireValue>> From<Vec<T>> for WireValue {
343 fn from(v: Vec<T>) -> Self {
344 WireValue::Array(v.into_iter().map(Into::into).collect())
345 }
346}
347
348impl<T: Into<WireValue>> From<Option<T>> for WireValue {
349 fn from(opt: Option<T>) -> Self {
350 match opt {
351 Some(v) => v.into(),
352 None => WireValue::Null,
353 }
354 }
355}
356
357impl From<serde_json::Value> for WireValue {
363 fn from(json: serde_json::Value) -> Self {
364 match json {
365 serde_json::Value::Null => WireValue::Null,
366 serde_json::Value::Bool(b) => WireValue::Bool(b),
367 serde_json::Value::Number(n) => {
368 if let Some(i) = n.as_i64() {
369 WireValue::Integer(i)
370 } else if let Some(u) = n.as_u64() {
371 WireValue::U64(u)
372 } else if let Some(f) = n.as_f64() {
373 WireValue::Number(f)
374 } else {
375 WireValue::Null
376 }
377 }
378 serde_json::Value::String(s) => WireValue::String(s),
379 serde_json::Value::Array(arr) => {
380 WireValue::Array(arr.into_iter().map(WireValue::from).collect())
381 }
382 serde_json::Value::Object(obj) => {
383 let map: BTreeMap<String, WireValue> = obj
385 .into_iter()
386 .map(|(k, v)| (k, WireValue::from(v)))
387 .collect();
388 WireValue::Object(map)
389 }
390 }
391 }
392}
393
394impl From<&serde_json::Value> for WireValue {
395 fn from(json: &serde_json::Value) -> Self {
396 WireValue::from(json.clone())
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403
404 #[test]
405 fn test_wire_value_type_names() {
406 assert_eq!(WireValue::Null.type_name(), "Null");
407 assert_eq!(WireValue::Bool(true).type_name(), "Bool");
408 assert_eq!(WireValue::Number(1.0).type_name(), "Number");
409 assert_eq!(WireValue::String("test".into()).type_name(), "String");
410 }
411
412 #[test]
413 fn test_wire_value_conversions() {
414 let v: WireValue = 42.0.into();
415 assert_eq!(v.as_number(), Some(42.0));
416
417 let v = WireValue::I64(42);
418 assert_eq!(v.as_number(), None, "i64 should not coerce to number");
419
420 let v: WireValue = "hello".into();
421 assert_eq!(v.as_str(), Some("hello"));
422
423 let v: WireValue = true.into();
424 assert_eq!(v.as_bool(), Some(true));
425 }
426
427 #[test]
428 fn test_wire_series_empty() {
429 let series = WireTable::empty();
430 assert_eq!(series.row_count, 0);
431 assert_eq!(series.column_count, 0);
432 assert!(series.ipc_bytes.is_empty());
433 }
434
435 #[test]
436 fn test_json_to_wire_conversion() {
437 let json = serde_json::json!(null);
439 let wire = WireValue::from(json);
440 assert!(wire.is_null());
441
442 let json = serde_json::json!(true);
444 let wire = WireValue::from(json);
445 assert_eq!(wire.as_bool(), Some(true));
446
447 let json = serde_json::json!(42);
449 let wire = WireValue::from(json);
450 assert!(matches!(wire, WireValue::Integer(42)));
451
452 let json = serde_json::json!(3.14);
454 let wire = WireValue::from(json);
455 assert!(matches!(wire, WireValue::Number(n) if (n - 3.14).abs() < 0.001));
456
457 let json = serde_json::json!("hello");
459 let wire = WireValue::from(json);
460 assert_eq!(wire.as_str(), Some("hello"));
461
462 let json = serde_json::json!([1, 2, 3]);
464 let wire = WireValue::from(json);
465 assert!(matches!(wire, WireValue::Array(arr) if arr.len() == 3));
466
467 let json = serde_json::json!({"x": 10, "y": 20});
469 let wire = WireValue::from(json);
470 if let WireValue::Object(map) = wire {
471 assert_eq!(map.len(), 2);
472 } else {
473 panic!("Expected Object");
474 }
475 }
476}