perspective_client/virtual_server/
data.rs1use std::error::Error;
14use std::ops::{Deref, DerefMut};
15
16use indexmap::IndexMap;
17use serde::Serialize;
18
19use crate::config::Scalar;
20
21#[derive(Debug, Serialize)]
26#[serde(untagged)]
27pub enum VirtualDataColumn {
28 Boolean(Vec<Option<bool>>),
29 String(Vec<Option<String>>),
30 Float(Vec<Option<f64>>),
31 Integer(Vec<Option<i32>>),
32 Datetime(Vec<Option<i64>>),
33 IntegerIndex(Vec<Option<Vec<i32>>>),
34 RowPath(Vec<Vec<Scalar>>),
35}
36
37#[derive(Debug, Serialize)]
42#[serde(untagged)]
43pub enum VirtualDataCell {
44 Boolean(Option<bool>),
45 String(Option<String>),
46 Float(Option<f64>),
47 Integer(Option<i32>),
48 Datetime(Option<i64>),
49 IntegerIndex(Option<Vec<i32>>),
50 RowPath(Vec<Scalar>),
51}
52
53impl VirtualDataColumn {
54 pub fn is_empty(&self) -> bool {
56 match self {
57 VirtualDataColumn::Boolean(v) => v.is_empty(),
58 VirtualDataColumn::String(v) => v.is_empty(),
59 VirtualDataColumn::Float(v) => v.is_empty(),
60 VirtualDataColumn::Integer(v) => v.is_empty(),
61 VirtualDataColumn::Datetime(v) => v.is_empty(),
62 VirtualDataColumn::IntegerIndex(v) => v.is_empty(),
63 VirtualDataColumn::RowPath(v) => v.is_empty(),
64 }
65 }
66
67 pub fn len(&self) -> usize {
69 match self {
70 VirtualDataColumn::Boolean(v) => v.len(),
71 VirtualDataColumn::String(v) => v.len(),
72 VirtualDataColumn::Float(v) => v.len(),
73 VirtualDataColumn::Integer(v) => v.len(),
74 VirtualDataColumn::Datetime(v) => v.len(),
75 VirtualDataColumn::IntegerIndex(v) => v.len(),
76 VirtualDataColumn::RowPath(v) => v.len(),
77 }
78 }
79}
80
81pub trait SetVirtualDataColumn {
87 fn write_to(self, col: &mut VirtualDataColumn) -> Result<(), &'static str>;
91
92 fn new_column() -> VirtualDataColumn;
94
95 fn to_scalar(self) -> Scalar;
97}
98
99macro_rules! template_psp {
100 ($t:ty, $u:ident, $v:ident, $w:ty) => {
101 impl SetVirtualDataColumn for Option<$t> {
102 fn write_to(self, col: &mut VirtualDataColumn) -> Result<(), &'static str> {
103 if let VirtualDataColumn::$u(x) = col {
104 x.push(self);
105 Ok(())
106 } else {
107 Err("Bad type")
108 }
109 }
110
111 fn new_column() -> VirtualDataColumn {
112 VirtualDataColumn::$u(vec![])
113 }
114
115 fn to_scalar(self) -> Scalar {
116 if let Some(x) = self {
117 Scalar::$v(x as $w)
118 } else {
119 Scalar::Null
120 }
121 }
122 }
123 };
124}
125
126template_psp!(String, String, String, String);
127template_psp!(f64, Float, Float, f64);
128template_psp!(i32, Integer, Float, f64);
129template_psp!(i64, Datetime, Float, f64);
130template_psp!(bool, Boolean, Bool, bool);
131
132#[derive(Debug, Default, Serialize)]
137pub struct VirtualDataSlice(IndexMap<String, VirtualDataColumn>);
138
139impl Deref for VirtualDataSlice {
140 type Target = IndexMap<String, VirtualDataColumn>;
141
142 fn deref(&self) -> &Self::Target {
143 &self.0
144 }
145}
146
147impl DerefMut for VirtualDataSlice {
148 fn deref_mut(&mut self) -> &mut Self::Target {
149 &mut self.0
150 }
151}
152
153impl VirtualDataSlice {
154 pub(super) fn to_rows(&self) -> Vec<IndexMap<String, VirtualDataCell>> {
155 let num_rows = self.values().next().map(|x| x.len()).unwrap_or(0);
156 (0..num_rows)
157 .map(|row_idx| {
158 self.iter()
159 .map(|(col_name, col_data)| {
160 let row_value = match col_data {
161 VirtualDataColumn::Boolean(v) => VirtualDataCell::Boolean(v[row_idx]),
162 VirtualDataColumn::String(v) => {
163 VirtualDataCell::String(v[row_idx].clone())
164 },
165 VirtualDataColumn::Float(v) => VirtualDataCell::Float(v[row_idx]),
166 VirtualDataColumn::Integer(v) => VirtualDataCell::Integer(v[row_idx]),
167 VirtualDataColumn::Datetime(v) => VirtualDataCell::Datetime(v[row_idx]),
168 VirtualDataColumn::IntegerIndex(v) => {
169 VirtualDataCell::IntegerIndex(v[row_idx].clone())
170 },
171 VirtualDataColumn::RowPath(v) => {
172 VirtualDataCell::RowPath(v[row_idx].clone())
173 },
174 };
175 (col_name.clone(), row_value)
176 })
177 .collect()
178 })
179 .collect()
180 }
181
182 pub fn set_col<T: SetVirtualDataColumn>(
190 &mut self,
191 name: &str,
192 group_by_index: Option<usize>,
193 index: usize,
194 value: T,
195 ) -> Result<(), Box<dyn Error>> {
196 if group_by_index.is_some() {
197 if !self.contains_key("__ROW_PATH__") {
198 self.insert(
199 "__ROW_PATH__".to_owned(),
200 VirtualDataColumn::RowPath(vec![]),
201 );
202 }
203
204 let Some(VirtualDataColumn::RowPath(col)) = self.get_mut("__ROW_PATH__") else {
205 return Err("__ROW_PATH__ column has unexpected type".into());
206 };
207
208 if let Some(row) = col.get_mut(index) {
209 let scalar = value.to_scalar();
210 row.push(scalar);
211 } else {
212 while col.len() < index {
213 col.push(vec![])
214 }
215
216 let scalar = value.to_scalar();
217 col.push(vec![scalar]);
218 }
219
220 Ok(())
221 } else {
222 if !self.contains_key(name) {
223 self.insert(name.to_owned(), T::new_column());
224 }
225
226 let col = self
227 .get_mut(name)
228 .ok_or_else(|| format!("Column '{}' not found after insertion", name))?;
229
230 Ok(value.write_to(col)?)
231 }
232 }
233}