axion_data/series/
list.rs1use crate::dtype::DataType;
2use crate::error::{AxionError, AxionResult};
3use super::core::Series;
4use super::interface::SeriesTrait;
5use std::any::Any;
6use std::cmp::Ordering;
7use std::fmt::{self, Debug, Display};
8
9#[derive(Clone)]
21pub struct ListSeries {
22 name: String,
23 data: Vec<Option<Box<dyn SeriesTrait>>>,
25 inner_dtype: DataType,
27}
28
29impl ListSeries {
30 pub fn new(name: String, data: Vec<Option<Box<dyn SeriesTrait>>>, inner_dtype: DataType) -> Self {
38 ListSeries { name, data, inner_dtype }
39 }
40
41 pub fn get_inner_series(&self, index: usize) -> Option<&dyn SeriesTrait> {
51 self.data.get(index).and_then(|opt_box| opt_box.as_deref())
52 }
53}
54
55impl SeriesTrait for ListSeries {
57 fn name(&self) -> &str {
58 &self.name
59 }
60
61 fn dtype(&self) -> DataType {
62 DataType::List(Box::new(self.inner_dtype.clone()))
64 }
65
66 fn len(&self) -> usize {
67 self.data.len()
68 }
69
70 fn is_empty(&self) -> bool {
71 self.data.is_empty()
72 }
73
74 fn as_any(&self) -> &dyn Any {
75 self
76 }
77
78 fn as_any_mut(&mut self) -> &mut dyn Any {
79 self
80 }
81
82 fn clone_box(&self) -> Box<dyn SeriesTrait> {
83 Box::new(self.clone())
85 }
86
87 fn get_str(&self, index: usize) -> Option<String> {
89 self.data.get(index).and_then(|opt_box| {
90 opt_box.as_ref().map(|inner_series| {
91 if inner_series.is_empty() {
94 return "[]".to_string();
95 }
96
97 let max_elements_to_show = 5; let mut elements_str = Vec::with_capacity(max_elements_to_show);
100 for i in 0..std::cmp::min(inner_series.len(), max_elements_to_show) {
101 elements_str.push(inner_series.get_str(i).unwrap_or_else(|| "null".to_string()));
103 }
104
105 let mut result = format!("[{}", elements_str.join(", "));
107
108 if inner_series.len() > max_elements_to_show {
110 result.push_str(", ...");
111 }
112 result.push(']');
113 result
114 })
115 })
116 }
117
118 fn slice(&self, start: usize, length: usize) -> Box<dyn SeriesTrait> {
120 let end = std::cmp::min(start + length, self.len());
121 let start = std::cmp::min(start, end);
122 let sliced_data = self.data[start..end].to_vec(); Box::new(ListSeries::new(self.name.clone(), sliced_data, self.inner_dtype.clone()))
124 }
125
126 fn filter(&self, mask: &Series<bool>) -> AxionResult<Box<dyn SeriesTrait>> {
128 if mask.len() != self.len() {
129 return Err(AxionError::MismatchedLengths {
130 expected: self.len(),
131 found: mask.len(),
132 name: format!("filter mask for list series '{}'", self.name),
133 });
134 }
135 let mut new_data = Vec::with_capacity(self.len());
136 for (opt_val, opt_mask) in self.data.iter().zip(mask.data_internal().iter()) {
137 if let Some(true) = opt_mask {
138 new_data.push(opt_val.clone());
139 }
140 }
141 Ok(Box::new(ListSeries::new(self.name.clone(), new_data, self.inner_dtype.clone())))
142 }
143
144 fn take_indices(&self, indices: &[usize]) -> AxionResult<Box<dyn SeriesTrait>> {
146 let mut new_data = Vec::with_capacity(indices.len());
147 for &idx in indices {
148 let opt_val = self.data.get(idx)
149 .ok_or_else(|| AxionError::IndexOutOfBounds(idx, self.len()))?
150 .clone();
151 new_data.push(opt_val);
152 }
153 Ok(Box::new(ListSeries::new(self.name.clone(), new_data, self.inner_dtype.clone())))
154 }
155
156 fn take_indices_option(&self, indices: &[Option<usize>]) -> AxionResult<Box<dyn SeriesTrait>> {
157 let mut new_data = Vec::with_capacity(indices.len());
158 for opt_idx in indices {
159 match opt_idx {
160 Some(idx) => {
161 let opt_val = self.data.get(*idx)
163 .ok_or_else(|| AxionError::IndexOutOfBounds(*idx, self.len()))?
164 .clone();
165 new_data.push(opt_val);
166 }
167 None => {
168 new_data.push(None);
170 }
171 }
172 }
173 Ok(Box::new(ListSeries::new(self.name.clone(), new_data, self.inner_dtype.clone())))
174 }
175
176 fn rename(&mut self, new_name: &str) {
177 self.name = new_name.to_string();
178 }
179
180 fn series_equal(&self, other: &dyn SeriesTrait) -> bool {
182 if let Some(other_list) = other.as_any().downcast_ref::<ListSeries>() {
184 if self.inner_dtype != other_list.inner_dtype {
186 return false;
187 }
188 if self.len() != other_list.len() {
190 return false;
191 }
192 self.data.iter().zip(other_list.data.iter()).all(|(self_opt_box, other_opt_box)| {
194 match (self_opt_box, other_opt_box) {
195 (None, None) => true,
197 (Some(self_inner_series), Some(other_inner_series)) => {
199 self_inner_series.series_equal(&**other_inner_series)
201 }
202 _ => false,
204 }
205 })
206 } else {
207 false
209 }
210 }
211
212 fn compare_row(&self, _a_idx: usize, _b_idx: usize) -> Ordering {
213 Ordering::Equal
216 }
218
219 fn get_as_f64(&self, index: usize) -> AxionResult<Option<f64>> {
220 let _index = index; Ok(None)
222 }
223
224 fn is_null_at(&self, index: usize) -> bool {
225 self.data.get(index).map_or(true, |opt_val_ref| opt_val_ref.is_none())
229 }
230}
231
232impl Debug for ListSeries {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 f.debug_struct("ListSeries")
236 .field("name", &self.name)
237 .field("dtype", &self.dtype()) .field("len", &self.len())
239 .field("data_head", &self.data.iter().take(5).collect::<Vec<_>>()) .finish()
241 }
242}
243
244impl Display for ListSeries {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 writeln!(f, "ListSeries: '{}' [{:?}]", self.name, self.dtype())?;
247 for (i, opt_val) in self.data.iter().take(10).enumerate() {
248 write!(f, "{}: ", i)?;
249 match opt_val {
250 Some(val) => writeln!(f, "{:?}", val)?, None => writeln!(f, "null")?,
252 }
253 }
254 if self.len() > 10 {
255 writeln!(f, "... ({} more)", self.len() - 10)?;
256 }
257 Ok(())
258 }
259}
260
261pub fn new_list_series(name: String, data: Vec<Box<dyn SeriesTrait>>) -> AxionResult<ListSeries> {
279 let inner_dtype = data.first()
280 .map(|s| s.dtype())
281 .unwrap_or(DataType::Null);
282
283 for series in data.iter().skip(1) {
284 if series.dtype() != inner_dtype {
285 return Err(AxionError::Other(format!(
286 "List series '{}' expects inner type {:?} but found {:?}",
287 name, inner_dtype, series.dtype()
288 )));
289 }
290 }
291
292 let data_opts = data.into_iter().map(Some).collect();
293
294 Ok(ListSeries::new(name, data_opts, inner_dtype))
295}