1use std::{
4 collections::HashMap,
5 sync::{
6 Arc,
7 atomic::{AtomicU64, Ordering},
8 },
9};
10
11use gpui::SharedString;
12
13static GENERATIONS: AtomicU64 = AtomicU64::new(1);
14
15#[derive(Clone, Debug, Default)]
22pub struct Data(Arc<Table>);
23
24#[derive(Clone, Debug, Default)]
25struct Table {
26 fields: Vec<(SharedString, Column)>,
27 len: usize,
28 generation: u64,
29}
30
31#[derive(Clone, Debug)]
32pub enum Column {
33 Number(Arc<[f64]>),
36 Text(Text),
37}
38
39#[derive(Clone, Debug)]
42pub struct Text {
43 pub codes: Arc<[u32]>,
44 pub names: Arc<[SharedString]>,
45}
46
47impl Text {
48 pub fn get(&self, row: usize) -> &SharedString {
49 &self.names[self.codes[row] as usize]
50 }
51}
52
53impl<S: Into<SharedString>> FromIterator<S> for Text {
54 fn from_iter<I: IntoIterator<Item = S>>(values: I) -> Self {
55 let mut index = HashMap::new();
56 let mut names = Vec::new();
57 let codes = values
58 .into_iter()
59 .map(|value| {
60 let value = value.into();
61 *index.entry(value.clone()).or_insert_with(|| {
62 names.push(value);
63 names.len() as u32 - 1
64 })
65 })
66 .collect();
67 Self {
68 codes,
69 names: names.into(),
70 }
71 }
72}
73
74impl Column {
75 pub fn len(&self) -> usize {
76 match self {
77 Self::Number(values) => values.len(),
78 Self::Text(text) => text.codes.len(),
79 }
80 }
81
82 pub fn is_empty(&self) -> bool {
83 self.len() == 0
84 }
85}
86
87impl Data {
88 pub fn new() -> Self {
89 Self::default()
90 }
91
92 pub fn with(mut self, field: impl Into<SharedString>, column: Column) -> Self {
98 let field = field.into();
99 let table = Arc::make_mut(&mut self.0);
100 if let Some((name, other)) = table.fields.iter().find(|(name, _)| *name != field) {
101 assert_eq!(
102 column.len(),
103 other.len(),
104 "column `{field}` is not as long as `{name}`"
105 );
106 }
107 table.len = column.len();
108 match table.fields.iter_mut().find(|(name, _)| *name == field) {
109 Some((_, slot)) => *slot = column,
110 None => table.fields.push((field, column)),
111 }
112 table.generation = GENERATIONS.fetch_add(1, Ordering::Relaxed);
113 self
114 }
115
116 pub fn number(self, field: impl Into<SharedString>, values: impl Into<Arc<[f64]>>) -> Self {
117 self.with(field, Column::Number(values.into()))
118 }
119
120 pub fn text<S: Into<SharedString>>(
121 self,
122 field: impl Into<SharedString>,
123 values: impl IntoIterator<Item = S>,
124 ) -> Self {
125 self.with(field, Column::Text(values.into_iter().collect()))
126 }
127
128 pub fn column(&self, field: &str) -> Option<&Column> {
129 self.0
130 .fields
131 .iter()
132 .find(|(name, _)| name == field)
133 .map(|(_, column)| column)
134 }
135
136 pub fn fields(&self) -> impl Iterator<Item = (&SharedString, &Column)> {
138 self.0.fields.iter().map(|(name, column)| (name, column))
139 }
140
141 pub fn len(&self) -> usize {
143 self.0.len
144 }
145
146 pub fn is_empty(&self) -> bool {
147 self.0.len == 0
148 }
149
150 pub fn generation(&self) -> u64 {
152 self.0.generation
153 }
154}