1use crate::{
2 models::{ColumnMeta, ColumnType},
3 CCDBError, CCDBResult,
4};
5use itertools::izip;
6use memchr::memchr;
7use std::{collections::HashMap, sync::Arc};
8
9#[derive(Debug, Clone)]
11pub enum Column {
12 Int(Vec<i32>),
14 UInt(Vec<u32>),
16 Long(Vec<i64>),
18 ULong(Vec<u64>),
20 Double(Vec<f64>),
22 Bool(Vec<bool>),
24 String(Vec<String>),
26}
27
28impl Column {
29 #[must_use]
31 pub fn len(&self) -> usize {
32 match self {
33 Self::Int(v) => v.len(),
34 Self::UInt(v) => v.len(),
35 Self::Long(v) => v.len(),
36 Self::ULong(v) => v.len(),
37 Self::Double(v) => v.len(),
38 Self::Bool(v) => v.len(),
39 Self::String(v) => v.len(),
40 }
41 }
42
43 #[must_use]
45 pub fn is_empty(&self) -> bool {
46 match self {
47 Self::Int(v) => v.is_empty(),
48 Self::UInt(v) => v.is_empty(),
49 Self::Long(v) => v.is_empty(),
50 Self::ULong(v) => v.is_empty(),
51 Self::Double(v) => v.is_empty(),
52 Self::Bool(v) => v.is_empty(),
53 Self::String(v) => v.is_empty(),
54 }
55 }
56
57 #[must_use]
59 pub fn row(&self, row: usize) -> Value<'_> {
60 match self {
61 Self::Int(v) => Value::Int(&v[row]),
62 Self::UInt(v) => Value::UInt(&v[row]),
63 Self::Long(v) => Value::Long(&v[row]),
64 Self::ULong(v) => Value::ULong(&v[row]),
65 Self::Double(v) => Value::Double(&v[row]),
66 Self::Bool(v) => Value::Bool(&v[row]),
67 Self::String(v) => Value::String(&v[row]),
68 }
69 }
70
71 #[must_use]
73 pub fn int(&self) -> Option<Vec<i32>> {
74 match self {
75 Self::Int(v) => Some(v.clone()),
76 _ => None,
77 }
78 }
79 #[must_use]
81 pub fn uint(&self) -> Option<Vec<u32>> {
82 match self {
83 Self::UInt(v) => Some(v.clone()),
84 _ => None,
85 }
86 }
87 #[must_use]
89 pub fn long(&self) -> Option<Vec<i64>> {
90 match self {
91 Self::Long(v) => Some(v.clone()),
92 _ => None,
93 }
94 }
95 #[must_use]
97 pub fn ulong(&self) -> Option<Vec<u64>> {
98 match self {
99 Self::ULong(v) => Some(v.clone()),
100 _ => None,
101 }
102 }
103 #[must_use]
105 pub fn double(&self) -> Option<Vec<f64>> {
106 match self {
107 Self::Double(v) => Some(v.clone()),
108 _ => None,
109 }
110 }
111 #[must_use]
113 pub fn bool(&self) -> Option<Vec<bool>> {
114 match self {
115 Self::Bool(v) => Some(v.clone()),
116 _ => None,
117 }
118 }
119 #[must_use]
121 pub fn string(&self) -> Option<Vec<String>> {
122 match self {
123 Self::String(v) => Some(v.clone()),
124 _ => None,
125 }
126 }
127}
128
129#[derive(Debug, Copy, Clone)]
131pub enum Value<'a> {
132 Int(&'a i32),
134 UInt(&'a u32),
136 Long(&'a i64),
138 ULong(&'a u64),
140 Double(&'a f64),
142 Bool(&'a bool),
144 String(&'a str),
146}
147impl<'a> Value<'a> {
148 #[must_use]
150 pub fn as_int(self) -> Option<i32> {
151 if let Value::Int(v) = self {
152 Some(*v)
153 } else {
154 None
155 }
156 }
157
158 #[must_use]
160 pub fn as_uint(self) -> Option<u32> {
161 if let Value::UInt(v) = self {
162 Some(*v)
163 } else {
164 None
165 }
166 }
167
168 #[must_use]
170 pub fn as_long(self) -> Option<i64> {
171 if let Value::Long(v) = self {
172 Some(*v)
173 } else {
174 None
175 }
176 }
177
178 #[must_use]
180 pub fn as_ulong(self) -> Option<u64> {
181 if let Value::ULong(v) = self {
182 Some(*v)
183 } else {
184 None
185 }
186 }
187
188 #[must_use]
190 pub fn as_double(self) -> Option<f64> {
191 if let Value::Double(v) = self {
192 Some(*v)
193 } else {
194 None
195 }
196 }
197
198 #[must_use]
200 pub fn as_bool(self) -> Option<bool> {
201 if let Value::Bool(v) = self {
202 Some(*v)
203 } else {
204 None
205 }
206 }
207
208 #[must_use]
210 pub fn as_str(self) -> Option<&'a str> {
211 if let Value::String(v) = self {
212 Some(v)
213 } else {
214 None
215 }
216 }
217}
218
219#[derive(Debug, Clone, Copy)]
221pub struct RowView<'a> {
222 row: usize,
223 columns: &'a [Column],
224 column_names: &'a [String],
225 column_indices: &'a HashMap<String, usize>,
226 column_types: &'a [ColumnType],
227}
228impl<'a> RowView<'a> {
229 #[must_use]
231 pub fn value(&self, column: usize) -> Option<Value<'a>> {
232 self.columns.get(column).map(|col| col.row(self.row))
233 }
234
235 #[must_use]
237 pub fn named_value(&self, name: &str) -> Option<Value<'a>> {
238 self.column_indices
239 .get(name)
240 .and_then(|&idx| self.value(idx))
241 }
242
243 #[must_use]
245 pub fn int(&self, column: usize) -> Option<i32> {
246 self.value(column)?.as_int()
247 }
248 #[must_use]
250 pub fn uint(&self, column: usize) -> Option<u32> {
251 self.value(column)?.as_uint()
252 }
253 #[must_use]
255 pub fn long(&self, column: usize) -> Option<i64> {
256 self.value(column)?.as_long()
257 }
258 #[must_use]
260 pub fn ulong(&self, column: usize) -> Option<u64> {
261 self.value(column)?.as_ulong()
262 }
263 #[must_use]
265 pub fn double(&self, column: usize) -> Option<f64> {
266 self.value(column)?.as_double()
267 }
268 #[must_use]
270 pub fn string(&self, column: usize) -> Option<&'a str> {
271 self.value(column)?.as_str()
272 }
273 #[must_use]
275 pub fn bool(&self, column: usize) -> Option<bool> {
276 self.value(column)?.as_bool()
277 }
278
279 #[must_use]
281 pub fn named_int(&self, name: &str) -> Option<i32> {
282 self.named_value(name)?.as_int()
283 }
284 #[must_use]
286 pub fn named_uint(&self, name: &str) -> Option<u32> {
287 self.named_value(name)?.as_uint()
288 }
289 #[must_use]
291 pub fn named_long(&self, name: &str) -> Option<i64> {
292 self.named_value(name)?.as_long()
293 }
294 #[must_use]
296 pub fn named_ulong(&self, name: &str) -> Option<u64> {
297 self.named_value(name)?.as_ulong()
298 }
299 #[must_use]
301 pub fn named_double(&self, name: &str) -> Option<f64> {
302 self.named_value(name)?.as_double()
303 }
304 #[must_use]
306 pub fn named_string(&self, name: &str) -> Option<&'a str> {
307 self.named_value(name)?.as_str()
308 }
309 #[must_use]
311 pub fn named_bool(&self, name: &str) -> Option<bool> {
312 self.named_value(name)?.as_bool()
313 }
314
315 pub fn iter_columns(&self) -> impl Iterator<Item = (&'a str, ColumnType, Value<'a>)> + '_ {
317 izip!(
318 self.column_names.iter(),
319 self.column_types.iter(),
320 self.columns.iter()
321 )
322 .map(move |(name, column_type, col)| (name.as_str(), *column_type, col.row(self.row)))
323 }
324
325 #[must_use]
327 pub fn contains(&self, name: &str) -> bool {
328 self.column_indices.contains_key(name)
329 }
330
331 #[must_use]
333 pub fn n_columns(&self) -> usize {
334 self.columns.len()
335 }
336
337 #[must_use]
339 pub fn column_types(&self) -> &'a [ColumnType] {
340 self.column_types
341 }
342}
343
344#[derive(Debug, Clone)]
346pub struct ColumnDef {
347 pub index: usize,
349 pub name: String,
351 pub column_type: ColumnType,
353}
354
355#[derive(Debug, Clone)]
357pub struct ColumnLayout {
358 columns: Vec<ColumnMeta>,
359 column_names: Vec<String>,
360 column_indices: HashMap<String, usize>,
361 column_types: Vec<ColumnType>,
362}
363
364impl ColumnLayout {
365 #[must_use]
367 pub fn new(mut columns: Vec<ColumnMeta>) -> Self {
368 columns.sort_unstable_by_key(|c| c.order);
369 let column_names: Vec<String> = columns
370 .iter()
371 .enumerate()
372 .map(|(i, c)| {
373 if c.name.is_empty() {
374 i.to_string()
375 } else {
376 c.name.clone()
377 }
378 })
379 .collect();
380 let column_types: Vec<ColumnType> = columns.iter().map(|c| c.column_type).collect();
381 let column_indices: HashMap<String, usize> = column_names
382 .iter()
383 .enumerate()
384 .map(|(idx, name)| (name.clone(), idx))
385 .collect();
386 Self {
387 columns,
388 column_names,
389 column_indices,
390 column_types,
391 }
392 }
393
394 #[must_use]
396 pub fn columns(&self) -> &[ColumnMeta] {
397 &self.columns
398 }
399
400 #[must_use]
402 pub fn column_names(&self) -> &[String] {
403 &self.column_names
404 }
405
406 #[must_use]
408 pub fn column_indices(&self) -> &HashMap<String, usize> {
409 &self.column_indices
410 }
411
412 #[must_use]
414 pub fn column_types(&self) -> &[ColumnType] {
415 &self.column_types
416 }
417
418 #[must_use]
420 pub fn column_count(&self) -> usize {
421 self.columns.len()
422 }
423}
424
425#[derive(Debug, Clone)]
427pub struct Data {
428 n_rows: usize,
429 layout: Arc<ColumnLayout>,
430 columns: Vec<Column>,
431}
432
433impl Data {
434 pub fn from_vault(vault: &str, layout: Arc<ColumnLayout>, n_rows: usize) -> CCDBResult<Self> {
442 let n_columns = layout.column_count();
443 let expected_cells = n_rows * n_columns;
444 let column_types = layout.column_types();
445 let mut column_vecs: Vec<Column> = column_types
446 .iter()
447 .map(|t| match t {
448 ColumnType::Int => Column::Int(Vec::with_capacity(n_rows)),
449 ColumnType::UInt => Column::UInt(Vec::with_capacity(n_rows)),
450 ColumnType::Long => Column::Long(Vec::with_capacity(n_rows)),
451 ColumnType::ULong => Column::ULong(Vec::with_capacity(n_rows)),
452 ColumnType::Double => Column::Double(Vec::with_capacity(n_rows)),
453 ColumnType::String => Column::String(Vec::with_capacity(n_rows)),
454 ColumnType::Bool => Column::Bool(Vec::with_capacity(n_rows)),
455 })
456 .collect();
457 let mut raw_iter = VaultFieldIter::new(vault);
458 for idx in 0..expected_cells {
459 let Some(raw) = raw_iter.next() else {
460 return Err(CCDBError::ColumnCountMismatch {
461 expected: expected_cells,
462 found: idx,
463 });
464 };
465 let row = idx / n_columns;
466 let col = idx % n_columns;
467 let column_type = column_types[col];
468
469 match (&mut column_vecs[col], column_type) {
470 (Column::Int(vec), ColumnType::Int) => {
471 vec.push(raw.parse().map_err(|_| CCDBError::ParseError {
472 column: col,
473 row,
474 column_type,
475 text: raw.to_string(),
476 })?);
477 }
478 (Column::UInt(vec), ColumnType::UInt) => {
479 vec.push(raw.parse().map_err(|_| CCDBError::ParseError {
480 column: col,
481 row,
482 column_type,
483 text: raw.to_string(),
484 })?);
485 }
486 (Column::Long(vec), ColumnType::Long) => {
487 vec.push(raw.parse().map_err(|_| CCDBError::ParseError {
488 column: col,
489 row,
490 column_type,
491 text: raw.to_string(),
492 })?);
493 }
494 (Column::ULong(vec), ColumnType::ULong) => {
495 vec.push(raw.parse().map_err(|_| CCDBError::ParseError {
496 column: col,
497 row,
498 column_type,
499 text: raw.to_string(),
500 })?);
501 }
502 (Column::Double(vec), ColumnType::Double) => {
503 vec.push(raw.parse().map_err(|_| CCDBError::ParseError {
504 column: col,
505 row,
506 column_type,
507 text: raw.to_string(),
508 })?);
509 }
510 (Column::String(vec), ColumnType::String) => {
511 let decoded = raw.replace("&delimeter", "|");
512 vec.push(decoded);
513 }
514 (Column::Bool(vec), ColumnType::Bool) => {
515 vec.push(parse_bool(raw));
516 }
517 _ => unreachable!("column type mismatch"),
518 }
519 }
520 if raw_iter.next().is_some() {
521 let found = expected_cells + 1 + raw_iter.count();
522 return Err(CCDBError::ColumnCountMismatch {
523 expected: expected_cells,
524 found,
525 });
526 }
527 Ok(Data {
528 n_rows,
529 layout,
530 columns: column_vecs,
531 })
532 }
533
534 #[must_use]
536 pub fn n_rows(&self) -> usize {
537 self.n_rows
538 }
539 #[must_use]
541 pub fn n_columns(&self) -> usize {
542 self.layout.column_count()
543 }
544 #[must_use]
546 pub fn column_names(&self) -> &[String] {
547 self.layout.column_names()
548 }
549
550 #[must_use]
552 pub fn column_types(&self) -> &[ColumnType] {
553 self.layout.column_types()
554 }
555
556 #[must_use]
558 pub fn column(&self, idx: usize) -> Option<&Column> {
559 self.columns.get(idx)
560 }
561
562 #[must_use]
564 pub fn named_column(&self, name: &str) -> Option<&Column> {
565 self.layout
566 .column_indices()
567 .get(name)
568 .and_then(|idx| self.columns.get(*idx))
569 }
570
571 #[must_use]
573 pub fn column_clone(&self, idx: usize) -> Option<Column> {
574 self.columns.get(idx).cloned()
575 }
576
577 #[must_use]
579 pub fn named_column_clone(&self, name: &str) -> Option<Column> {
580 self.layout
581 .column_indices()
582 .get(name)
583 .and_then(|idx| self.columns.get(*idx))
584 .cloned()
585 }
586
587 #[must_use]
589 pub fn value(&self, column: usize, row: usize) -> Option<Value<'_>> {
590 if row >= self.n_rows || column >= self.layout.column_count() {
591 return None;
592 }
593 match self.columns.get(column)? {
594 Column::Int(v) => Some(Value::Int(&v[row])),
595 Column::UInt(v) => Some(Value::UInt(&v[row])),
596 Column::Long(v) => Some(Value::Long(&v[row])),
597 Column::ULong(v) => Some(Value::ULong(&v[row])),
598 Column::Double(v) => Some(Value::Double(&v[row])),
599 Column::Bool(v) => Some(Value::Bool(&v[row])),
600 Column::String(v) => Some(Value::String(&v[row])),
601 }
602 }
603 #[must_use]
605 pub fn named_int(&self, name: &str, row: usize) -> Option<i32> {
606 self.named_column(name)?.row(row).as_int()
607 }
608 #[must_use]
610 pub fn named_uint(&self, name: &str, row: usize) -> Option<u32> {
611 self.named_column(name)?.row(row).as_uint()
612 }
613 #[must_use]
615 pub fn named_long(&self, name: &str, row: usize) -> Option<i64> {
616 self.named_column(name)?.row(row).as_long()
617 }
618 #[must_use]
620 pub fn named_ulong(&self, name: &str, row: usize) -> Option<u64> {
621 self.named_column(name)?.row(row).as_ulong()
622 }
623 #[must_use]
625 pub fn named_double(&self, name: &str, row: usize) -> Option<f64> {
626 self.named_column(name)?.row(row).as_double()
627 }
628 #[must_use]
630 pub fn named_string(&self, name: &str, row: usize) -> Option<&str> {
631 self.named_column(name)?.row(row).as_str()
632 }
633 #[must_use]
635 pub fn named_bool(&self, name: &str, row: usize) -> Option<bool> {
636 self.named_column(name)?.row(row).as_bool()
637 }
638
639 #[must_use]
641 pub fn int(&self, column: usize, row: usize) -> Option<i32> {
642 self.value(column, row)?.as_int()
643 }
644 #[must_use]
646 pub fn uint(&self, column: usize, row: usize) -> Option<u32> {
647 self.value(column, row)?.as_uint()
648 }
649 #[must_use]
651 pub fn long(&self, column: usize, row: usize) -> Option<i64> {
652 self.value(column, row)?.as_long()
653 }
654 #[must_use]
656 pub fn ulong(&self, column: usize, row: usize) -> Option<u64> {
657 self.value(column, row)?.as_ulong()
658 }
659 #[must_use]
661 pub fn double(&self, column: usize, row: usize) -> Option<f64> {
662 self.value(column, row)?.as_double()
663 }
664 #[must_use]
666 pub fn string(&self, column: usize, row: usize) -> Option<&str> {
667 self.value(column, row)?.as_str()
668 }
669 #[must_use]
671 pub fn bool(&self, column: usize, row: usize) -> Option<bool> {
672 self.value(column, row)?.as_bool()
673 }
674
675 pub fn row(&self, row: usize) -> CCDBResult<RowView<'_>> {
681 if row >= self.n_rows {
682 return Err(CCDBError::RowOutOfBounds {
683 requested: row,
684 n_rows: self.n_rows,
685 });
686 }
687 let layout = self.layout.as_ref();
688 Ok(RowView {
689 row,
690 columns: &self.columns,
691 column_names: layout.column_names(),
692 column_indices: layout.column_indices(),
693 column_types: layout.column_types(),
694 })
695 }
696
697 pub fn iter_rows(&self) -> impl Iterator<Item = RowView<'_>> {
699 let layout = self.layout.as_ref();
700 let columns = &self.columns;
701 let column_names = layout.column_names();
702 let column_indices = layout.column_indices();
703 let column_types = layout.column_types();
704 (0..self.n_rows).map(move |row| RowView {
705 row,
706 columns,
707 column_names,
708 column_indices,
709 column_types,
710 })
711 }
712
713 pub fn iter_columns(&self) -> impl Iterator<Item = (&String, &ColumnType, &Column)> {
715 izip!(
716 self.layout.column_names().iter(),
717 self.layout.column_types().iter(),
718 self.columns.iter()
719 )
720 }
721
722 #[must_use]
724 pub fn contains(&self, name: &str) -> bool {
725 self.layout.column_indices().contains_key(name)
726 }
727}
728
729struct VaultFieldIter<'a> {
730 input: &'a str,
731 cursor: usize,
732 finished: bool,
733}
734
735impl<'a> VaultFieldIter<'a> {
736 fn new(input: &'a str) -> Self {
737 Self {
738 input,
739 cursor: 0,
740 finished: false,
741 }
742 }
743}
744
745impl<'a> Iterator for VaultFieldIter<'a> {
746 type Item = &'a str;
747
748 fn next(&mut self) -> Option<Self::Item> {
749 if self.finished {
750 return None;
751 }
752 if self.cursor > self.input.len() {
753 self.finished = true;
754 return Some("");
755 }
756 if self.cursor == self.input.len() {
757 self.finished = true;
758 return Some("");
759 }
760 let bytes = self.input.as_bytes();
761 if let Some(pos) = memchr(b'|', &bytes[self.cursor..]) {
762 let start = self.cursor;
763 let end = start + pos;
764 self.cursor = end + 1;
765 Some(&self.input[start..end])
766 } else {
767 self.finished = true;
768 let start = self.cursor;
769 Some(&self.input[start..])
770 }
771 }
772}
773
774fn parse_bool(s: &str) -> bool {
775 if s == "true" {
776 return true;
777 }
778 if s == "false" {
779 return false;
780 }
781 s.parse::<i32>().unwrap_or(0) != 0
782}