use core::fmt;
use std::sync::Arc;
#[cfg(feature = "data-csv")]
pub mod csv;
#[cfg(feature = "data-polars")]
pub mod polars;
#[cfg(feature = "time")]
use crate::time::{DateTime, TimeDelta};
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub enum SampleRef<'a> {
#[default]
Null,
Num(f64),
Cat(&'a str),
#[cfg(feature = "time")]
Time(DateTime),
#[cfg(feature = "time")]
TimeDelta(TimeDelta),
}
impl SampleRef<'_> {
pub fn is_null(&self) -> bool {
matches!(self, SampleRef::Null)
}
pub fn as_num(&self) -> Option<f64> {
match self {
SampleRef::Num(v) => Some(*v),
_ => None,
}
}
pub fn as_cat(&self) -> Option<&str> {
match self {
SampleRef::Cat(v) => Some(v),
_ => None,
}
}
#[cfg(feature = "time")]
pub fn as_time(&self) -> Option<DateTime> {
match self {
SampleRef::Time(v) => Some(*v),
_ => None,
}
}
#[cfg(feature = "time")]
pub fn as_time_delta(&self) -> Option<TimeDelta> {
match self {
SampleRef::TimeDelta(v) => Some(*v),
_ => None,
}
}
pub fn to_sample(&self) -> Sample {
match self {
SampleRef::Null => Sample::Null,
SampleRef::Num(v) => Sample::Num(*v),
SampleRef::Cat(v) => Sample::Cat(v.to_string()),
#[cfg(feature = "time")]
SampleRef::Time(v) => Sample::Time(*v),
#[cfg(feature = "time")]
SampleRef::TimeDelta(v) => Sample::TimeDelta(*v),
}
}
}
impl std::cmp::Eq for SampleRef<'_> {}
impl From<f64> for SampleRef<'_> {
fn from(val: f64) -> Self {
if val.is_finite() {
SampleRef::Num(val)
} else {
SampleRef::Num(val)
}
}
}
impl From<Option<f64>> for SampleRef<'_> {
fn from(val: Option<f64>) -> Self {
match val {
Some(v) => v.into(),
None => SampleRef::Null,
}
}
}
impl From<i64> for SampleRef<'_> {
fn from(val: i64) -> Self {
SampleRef::Num(val as f64)
}
}
impl From<Option<i64>> for SampleRef<'_> {
fn from(val: Option<i64>) -> Self {
match val {
Some(v) => SampleRef::Num(v as f64),
None => SampleRef::Null,
}
}
}
impl<'a> From<&'a str> for SampleRef<'a> {
fn from(val: &'a str) -> Self {
SampleRef::Cat(val)
}
}
impl<'a> From<Option<&'a str>> for SampleRef<'a> {
fn from(val: Option<&'a str>) -> Self {
match val {
Some(val) => SampleRef::Cat(val),
None => SampleRef::Null,
}
}
}
#[cfg(feature = "time")]
impl From<DateTime> for SampleRef<'_> {
fn from(val: DateTime) -> Self {
SampleRef::Time(val)
}
}
#[cfg(feature = "time")]
impl From<Option<DateTime>> for SampleRef<'_> {
fn from(val: Option<DateTime>) -> Self {
match val {
Some(v) => SampleRef::Time(v),
None => SampleRef::Null,
}
}
}
#[cfg(feature = "time")]
impl From<TimeDelta> for SampleRef<'_> {
fn from(val: TimeDelta) -> Self {
SampleRef::TimeDelta(val)
}
}
#[cfg(feature = "time")]
impl From<Option<TimeDelta>> for SampleRef<'_> {
fn from(val: Option<TimeDelta>) -> Self {
match val {
Some(v) => SampleRef::TimeDelta(v),
None => SampleRef::Null,
}
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub enum Sample {
#[default]
Null,
Num(f64),
Cat(String),
#[cfg(feature = "time")]
Time(DateTime),
#[cfg(feature = "time")]
TimeDelta(TimeDelta),
}
impl Sample {
pub fn is_null(&self) -> bool {
matches!(self, Sample::Null)
}
pub fn as_num(&self) -> Option<f64> {
match self {
Sample::Num(v) => Some(*v),
_ => None,
}
}
pub fn as_cat(&self) -> Option<&str> {
match self {
Sample::Cat(v) => Some(v),
_ => None,
}
}
#[cfg(feature = "time")]
pub fn as_time(&self) -> Option<DateTime> {
match self {
Sample::Time(v) => Some(*v),
_ => None,
}
}
#[cfg(feature = "time")]
pub fn as_time_delta(&self) -> Option<TimeDelta> {
match self {
Sample::TimeDelta(v) => Some(*v),
_ => None,
}
}
pub fn as_ref(&self) -> SampleRef<'_> {
match self {
Sample::Null => SampleRef::Null,
Sample::Num(v) => SampleRef::Num(*v),
Sample::Cat(v) => SampleRef::Cat(v.as_str()),
#[cfg(feature = "time")]
Sample::Time(v) => SampleRef::Time(*v),
#[cfg(feature = "time")]
Sample::TimeDelta(v) => SampleRef::TimeDelta(*v),
}
}
}
impl<'a> From<SampleRef<'a>> for Sample {
fn from(sample: SampleRef<'a>) -> Self {
sample.to_sample()
}
}
impl std::cmp::Eq for Sample {}
impl From<f64> for Sample {
fn from(val: f64) -> Self {
if val.is_finite() {
Sample::Num(val)
} else {
Sample::Num(val)
}
}
}
impl From<Option<f64>> for Sample {
fn from(val: Option<f64>) -> Self {
match val {
Some(v) => v.into(),
None => Sample::Null,
}
}
}
impl From<i64> for Sample {
fn from(val: i64) -> Self {
Sample::Num(val as f64)
}
}
impl From<Option<i64>> for Sample {
fn from(val: Option<i64>) -> Self {
match val {
Some(v) => Sample::Num(v as f64),
None => Sample::Null,
}
}
}
impl<'a> From<&'a str> for Sample {
fn from(val: &'a str) -> Self {
Sample::Cat(val.to_string())
}
}
impl From<String> for Sample {
fn from(val: String) -> Self {
Sample::Cat(val)
}
}
impl From<Option<String>> for Sample {
fn from(val: Option<String>) -> Self {
match val {
Some(val) => Sample::Cat(val),
None => Sample::Null,
}
}
}
#[cfg(feature = "time")]
impl From<DateTime> for Sample {
fn from(val: DateTime) -> Self {
Sample::Time(val)
}
}
#[cfg(feature = "time")]
impl From<Option<DateTime>> for Sample {
fn from(val: Option<DateTime>) -> Self {
match val {
Some(v) => Sample::Time(v),
None => Sample::Null,
}
}
}
#[cfg(feature = "time")]
impl From<TimeDelta> for Sample {
fn from(val: TimeDelta) -> Self {
Sample::TimeDelta(val)
}
}
#[cfg(feature = "time")]
impl From<Option<TimeDelta>> for Sample {
fn from(val: Option<TimeDelta>) -> Self {
match val {
Some(v) => Sample::TimeDelta(v),
None => Sample::Null,
}
}
}
pub trait Column: std::fmt::Debug {
fn len(&self) -> usize;
fn len_some(&self) -> usize;
fn sample_iter(&self) -> Box<dyn Iterator<Item = SampleRef<'_>> + '_> {
#[cfg(feature = "time")]
if let Some(iter) = self.as_time_iter() {
return Box::new(iter.map(SampleRef::from));
} else if let Some(iter) = self.as_time_delta_iter() {
return Box::new(iter.map(SampleRef::from));
}
if let Some(iter) = self.as_i64_iter() {
Box::new(iter.map(SampleRef::from))
} else if let Some(iter) = self.as_f64_iter() {
Box::new(iter.map(SampleRef::from))
} else {
Box::new(self.as_str_iter().unwrap().map(SampleRef::from))
}
}
fn boxed_copy(&self) -> Box<dyn Column> {
if let Some(col) = self.f64() {
let mut vec = Vec::with_capacity(col.len());
for v in col.f64_iter() {
vec.push(v.unwrap_or(f64::NAN));
}
return Box::new(vec);
} else if let Some(col) = self.i64() {
return Box::new(col.i64_iter().collect::<Vec<_>>());
} else if let Some(col) = self.str() {
return Box::new(
col.str_iter()
.map(|s| s.map(|s| s.to_string()))
.collect::<Vec<_>>(),
);
}
#[cfg(feature = "time")]
if let Some(col) = self.time() {
return Box::new(col.time_iter().collect::<Vec<_>>());
} else if let Some(col) = self.time_delta() {
return Box::new(col.time_delta_iter().collect::<Vec<_>>());
}
panic!("Cannot box copy column: no known type");
}
fn f64(&self) -> Option<&dyn F64Column> {
None
}
fn i64(&self) -> Option<&dyn I64Column> {
None
}
fn str(&self) -> Option<&dyn StrColumn> {
None
}
#[cfg(feature = "time")]
fn time(&self) -> Option<&dyn TimeColumn> {
None
}
#[cfg(feature = "time")]
fn time_delta(&self) -> Option<&dyn TimeDeltaColumn> {
None
}
fn as_f64_iter(&self) -> Option<Box<dyn Iterator<Item = Option<f64>> + '_>> {
self.f64().map(|c| c.f64_iter())
}
fn as_i64_iter(&self) -> Option<Box<dyn Iterator<Item = Option<i64>> + '_>> {
self.i64().map(|c| c.i64_iter())
}
fn as_str_iter(&self) -> Option<Box<dyn Iterator<Item = Option<&str>> + '_>> {
self.str().map(|c| c.str_iter())
}
#[cfg(feature = "time")]
fn as_time_iter(&self) -> Option<Box<dyn Iterator<Item = Option<DateTime>> + '_>> {
self.time().map(|c| c.time_iter())
}
#[cfg(feature = "time")]
fn as_time_delta_iter(&self) -> Option<Box<dyn Iterator<Item = Option<TimeDelta>> + '_>> {
self.time_delta().map(|c| c.time_delta_iter())
}
}
pub trait F64Column: std::fmt::Debug {
fn len(&self) -> usize;
fn len_some(&self) -> usize {
self.f64_iter().filter(|v| v.is_some()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_>;
fn minmax(&self) -> Option<(f64, f64)> {
let mut res: Option<(f64, f64)> = None;
for v in self.f64_iter() {
match (v, res) {
(None, _) => continue,
(Some(v), Some((min, max))) => {
res = Some((min.min(v), max.max(v)));
}
(Some(v), None) => {
res = Some((v, v));
}
}
}
res
}
}
pub trait I64Column: std::fmt::Debug {
fn len(&self) -> usize;
fn len_some(&self) -> usize {
self.i64_iter().filter(|v| v.is_some()).count()
}
fn i64_iter(&self) -> Box<dyn Iterator<Item = Option<i64>> + '_>;
fn minmax(&self) -> Option<(i64, i64)> {
let mut res: Option<(i64, i64)> = None;
for v in self.i64_iter() {
match (v, res) {
(None, _) => continue,
(Some(v), Some((min, max))) => {
res = Some((min.min(v), max.max(v)));
}
(Some(v), None) => {
res = Some((v, v));
}
}
}
res
}
}
pub trait StrColumn: std::fmt::Debug {
fn len(&self) -> usize;
fn len_some(&self) -> usize {
self.str_iter().filter(|v| v.is_some()).count()
}
fn str_iter(&self) -> Box<dyn Iterator<Item = Option<&str>> + '_>;
}
#[cfg(feature = "time")]
pub trait TimeColumn: std::fmt::Debug {
fn len(&self) -> usize;
fn len_some(&self) -> usize {
self.time_iter().filter(|v| v.is_some()).count()
}
fn time_iter(&self) -> Box<dyn Iterator<Item = Option<DateTime>> + '_>;
fn minmax(&self) -> Option<(DateTime, DateTime)> {
let mut res: Option<(DateTime, DateTime)> = None;
for v in self.time_iter() {
match (v, res) {
(None, _) => continue,
(Some(v), Some((min, max))) => {
res = Some((min.min(v), max.max(v)));
}
(Some(v), None) => {
res = Some((v, v));
}
}
}
res
}
}
#[cfg(feature = "time")]
pub trait TimeDeltaColumn: std::fmt::Debug {
fn len(&self) -> usize;
fn len_some(&self) -> usize {
self.time_delta_iter().filter(|v| v.is_some()).count()
}
fn time_delta_iter(&self) -> Box<dyn Iterator<Item = Option<TimeDelta>> + '_>;
fn minmax(&self) -> Option<(TimeDelta, TimeDelta)> {
let mut res: Option<(TimeDelta, TimeDelta)> = None;
for v in self.time_delta_iter() {
match (v, res) {
(None, _) => continue,
(Some(v), Some((min, max))) => {
res = Some((min.min(v), max.max(v)));
}
(Some(v), None) => {
res = Some((v, v));
}
}
}
res
}
}
pub trait Source: fmt::Debug {
fn names(&self) -> Vec<&str>;
fn column(&self, name: &str) -> Option<&dyn Column>;
fn copy(&self) -> Arc<dyn Source> {
let names = self.names();
let mut new_source = NamedOwnedColumns::new();
for name in names {
if let Some(col) = self.column(name) {
new_source.add_column(name, col.boxed_copy());
}
}
Arc::new(new_source)
}
}
impl Source for () {
fn names(&self) -> Vec<&str> {
Vec::new()
}
fn column(&self, _name: &str) -> Option<&dyn Column> {
None
}
fn copy(&self) -> Arc<dyn Source> {
Arc::new(())
}
}
impl Source for Arc<dyn Source> {
fn names(&self) -> Vec<&str> {
self.as_ref().names()
}
fn column(&self, name: &str) -> Option<&dyn Column> {
self.as_ref().column(name)
}
fn copy(&self) -> Arc<dyn Source> {
self.as_ref().copy()
}
}
#[derive(Debug, Clone, Copy)]
pub struct FCol<'a>(pub &'a [f64]);
impl F64Column for FCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.iter().filter(|v| v.is_finite()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(
self.0
.iter()
.copied()
.map(|f| if f.is_finite() { Some(f) } else { None }),
)
}
}
impl Column for FCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.iter().filter(|v| v.is_finite()).count()
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.0.to_vec())
}
}
#[derive(Debug, Clone, Copy)]
pub struct ICol<'a>(pub &'a [i64]);
impl I64Column for ICol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn i64_iter(&self) -> Box<dyn Iterator<Item = Option<i64>> + '_> {
Box::new(self.0.iter().copied().map(Some))
}
}
impl F64Column for ICol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.0.iter().map(|i| *i as f64).map(Some))
}
}
impl Column for ICol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn i64(&self) -> Option<&dyn I64Column> {
Some(self)
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.0.to_vec())
}
}
#[derive(Debug)]
pub struct SCol<'a, T>(pub &'a [T]);
impl<T> StrColumn for SCol<'_, T>
where
T: AsRef<str> + std::fmt::Debug,
{
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn str_iter(&self) -> Box<dyn Iterator<Item = Option<&str>> + '_> {
Box::new(self.0.iter().map(|s| Some(s.as_ref())))
}
}
impl<T> Column for SCol<'_, T>
where
T: AsRef<str> + std::fmt::Debug,
{
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn str(&self) -> Option<&dyn StrColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(
self.0
.iter()
.map(|s| s.as_ref().to_string())
.collect::<Vec<_>>(),
)
}
}
#[cfg(feature = "time")]
#[derive(Debug)]
pub struct TCol<'a>(pub &'a [DateTime]);
#[cfg(feature = "time")]
impl TimeColumn for TCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn time_iter(&self) -> Box<dyn Iterator<Item = Option<DateTime>> + '_> {
Box::new(self.0.iter().copied().map(Some))
}
}
#[cfg(feature = "time")]
impl F64Column for TCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.0.iter().map(|dt| dt.timestamp()).map(Some))
}
}
#[cfg(feature = "time")]
impl Column for TCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn time(&self) -> Option<&dyn TimeColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.0.to_vec())
}
}
#[cfg(feature = "time")]
#[derive(Debug)]
pub struct TdCol<'a>(pub &'a [TimeDelta]);
#[cfg(feature = "time")]
impl TimeDeltaColumn for TdCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn time_delta_iter(&self) -> Box<dyn Iterator<Item = Option<TimeDelta>> + '_> {
Box::new(self.0.iter().copied().map(Some))
}
}
#[cfg(feature = "time")]
impl F64Column for TdCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.0.iter().map(|dt| dt.seconds()).map(Some))
}
}
#[cfg(feature = "time")]
impl Column for TdCol<'_> {
fn len(&self) -> usize {
self.0.len()
}
fn len_some(&self) -> usize {
self.0.len()
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn time_delta(&self) -> Option<&dyn TimeDeltaColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.0.to_vec())
}
}
impl F64Column for Vec<f64> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_finite()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(
self.as_slice()
.iter()
.copied()
.map(|f| if f.is_finite() { Some(f) } else { None }),
)
}
}
impl Column for Vec<f64> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_finite()).count()
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
impl F64Column for Vec<f32> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_finite()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(
self.as_slice()
.iter()
.copied()
.map(|f| if f.is_finite() { Some(f as f64) } else { None }),
)
}
}
impl Column for Vec<f32> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_finite()).count()
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
impl F64Column for Vec<Option<i64>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.as_slice().iter().copied().map(|v| v.map(|v| v as f64)))
}
}
impl I64Column for Vec<Option<i64>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn i64_iter(&self) -> Box<dyn Iterator<Item = Option<i64>> + '_> {
Box::new(self.as_slice().iter().copied())
}
}
impl Column for Vec<Option<i64>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn i64(&self) -> Option<&dyn I64Column> {
Some(self)
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
impl F64Column for Vec<i64> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.as_slice().iter().copied().map(|v| Some(v as f64)))
}
}
impl I64Column for Vec<i64> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn i64_iter(&self) -> Box<dyn Iterator<Item = Option<i64>> + '_> {
Box::new(self.as_slice().iter().copied().map(Some))
}
}
impl Column for Vec<i64> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn i64(&self) -> Option<&dyn I64Column> {
Some(self)
}
fn f64(&self) -> Option<&dyn F64Column> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
impl StrColumn for Vec<Option<String>> {
fn len(&self) -> usize {
self.len()
}
fn str_iter(&self) -> Box<dyn Iterator<Item = Option<&str>> + '_> {
Box::new(self.as_slice().iter().map(|s| s.as_deref()))
}
}
impl Column for Vec<Option<String>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn str(&self) -> Option<&dyn StrColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
impl StrColumn for Vec<String> {
fn len(&self) -> usize {
self.len()
}
fn str_iter(&self) -> Box<dyn Iterator<Item = Option<&str>> + '_> {
Box::new(self.as_slice().iter().map(|s| Some(s.as_str())))
}
}
impl Column for Vec<String> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn str(&self) -> Option<&dyn StrColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
impl StrColumn for Vec<Option<&str>> {
fn len(&self) -> usize {
self.len()
}
fn str_iter(&self) -> Box<dyn Iterator<Item = Option<&str>> + '_> {
Box::new(self.as_slice().iter().map(|s| *s))
}
}
impl Column for Vec<Option<&str>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn str(&self) -> Option<&dyn StrColumn> {
Some(self)
}
}
impl StrColumn for Vec<&str> {
fn len(&self) -> usize {
self.len()
}
fn str_iter(&self) -> Box<dyn Iterator<Item = Option<&str>> + '_> {
Box::new(self.as_slice().iter().map(|s| Some(*s)))
}
}
impl Column for Vec<&str> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn str(&self) -> Option<&dyn StrColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.iter().map(|s| s.to_string()).collect::<Vec<_>>())
}
}
#[cfg(feature = "time")]
impl TimeColumn for Vec<DateTime> {
fn len(&self) -> usize {
self.len()
}
fn time_iter(&self) -> Box<dyn Iterator<Item = Option<DateTime>> + '_> {
Box::new(self.as_slice().iter().map(|v| Some(*v)))
}
}
#[cfg(feature = "time")]
impl F64Column for Vec<DateTime> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.as_slice().iter().map(|v| Some(v.timestamp())))
}
}
#[cfg(feature = "time")]
impl Column for Vec<DateTime> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn time(&self) -> Option<&dyn TimeColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
#[cfg(feature = "time")]
impl TimeColumn for Vec<Option<DateTime>> {
fn len(&self) -> usize {
self.len()
}
fn time_iter(&self) -> Box<dyn Iterator<Item = Option<DateTime>> + '_> {
Box::new(self.as_slice().iter().copied())
}
}
#[cfg(feature = "time")]
impl F64Column for Vec<Option<DateTime>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(
self.as_slice()
.iter()
.copied()
.map(|v| v.map(|v| v.timestamp())),
)
}
}
#[cfg(feature = "time")]
impl Column for Vec<Option<DateTime>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn time(&self) -> Option<&dyn TimeColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
#[cfg(feature = "time")]
impl TimeDeltaColumn for Vec<TimeDelta> {
fn len(&self) -> usize {
self.len()
}
fn time_delta_iter(&self) -> Box<dyn Iterator<Item = Option<TimeDelta>> + '_> {
Box::new(self.as_slice().iter().map(|v| Some(*v)))
}
}
#[cfg(feature = "time")]
impl F64Column for Vec<TimeDelta> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(self.as_slice().iter().map(|v| Some(v.seconds())))
}
}
#[cfg(feature = "time")]
impl Column for Vec<TimeDelta> {
#[cfg(feature = "time")]
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.len()
}
fn time_delta(&self) -> Option<&dyn TimeDeltaColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
#[cfg(feature = "time")]
impl TimeDeltaColumn for Vec<Option<TimeDelta>> {
fn len(&self) -> usize {
self.len()
}
fn time_delta_iter(&self) -> Box<dyn Iterator<Item = Option<TimeDelta>> + '_> {
Box::new(self.as_slice().iter().copied())
}
}
#[cfg(feature = "time")]
impl F64Column for Vec<Option<TimeDelta>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn f64_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(
self.as_slice()
.iter()
.copied()
.map(|v| v.map(|v| v.seconds())),
)
}
}
#[cfg(feature = "time")]
impl Column for Vec<Option<TimeDelta>> {
fn len(&self) -> usize {
self.len()
}
fn len_some(&self) -> usize {
self.as_slice().iter().filter(|v| v.is_some()).count()
}
fn time_delta(&self) -> Option<&dyn TimeDeltaColumn> {
Some(self)
}
fn boxed_copy(&self) -> Box<dyn Column> {
Box::new(self.clone())
}
}
#[derive(Debug)]
pub struct NamedOwnedColumns {
names: Vec<String>,
columns: Vec<Box<dyn Column>>,
}
impl NamedOwnedColumns {
pub fn new() -> Self {
Self {
names: Vec::new(),
columns: Vec::new(),
}
}
pub fn add_column(&mut self, name: &str, col: Box<dyn Column>) {
let position = self.names.as_slice().iter().position(|n| n == name);
if let Some(pos) = position {
self.columns[pos] = col;
return;
}
self.names.push(name.to_string());
self.columns.push(col);
}
}
impl Source for NamedOwnedColumns {
fn names(&self) -> Vec<&str> {
self.names.iter().map(|s| s.as_str()).collect()
}
fn column(&self, name: &str) -> Option<&dyn Column> {
let Some(idx) = self.names.as_slice().iter().position(|k| k == name) else {
return None;
};
self.columns.get(idx).map(|c| c.as_ref() as &dyn Column)
}
fn copy(&self) -> Arc<dyn Source> {
let mut new_source = NamedOwnedColumns::new();
for (name, col) in self.names.iter().zip(self.columns.iter()) {
new_source.add_column(name, col.boxed_copy());
}
Arc::new(new_source)
}
}
#[derive(Debug)]
pub struct NamedColumns<'a> {
names: Vec<String>,
columns: Vec<&'a dyn Column>,
}
impl<'a> NamedColumns<'a> {
pub fn new() -> Self {
Self {
names: Vec::new(),
columns: Vec::new(),
}
}
pub fn add_column(&mut self, name: &str, col: &'a dyn Column) {
let position = self.names.iter().position(|n| n == name);
if let Some(pos) = position {
self.columns[pos] = col;
return;
}
self.names.push(name.to_string());
self.columns.push(col);
}
}
impl<'a> Source for NamedColumns<'a> {
fn names(&self) -> Vec<&str> {
self.names.iter().map(|s| s.as_str()).collect()
}
fn column(&self, name: &str) -> Option<&dyn Column> {
let Some(idx) = self.names.as_slice().iter().position(|k| k == name) else {
return None;
};
self.columns.get(idx).map(|c| *c as &dyn Column)
}
fn copy(&self) -> Arc<dyn Source> {
let mut new_source = NamedOwnedColumns::new();
for (name, col) in self.names.iter().zip(self.columns.iter()) {
new_source.add_column(name, col.boxed_copy());
}
Arc::new(new_source)
}
}
#[derive(Debug, Clone)]
pub enum VecColumn {
F64(Vec<f64>),
I64(Vec<Option<i64>>),
Str(Vec<Option<String>>),
#[cfg(feature = "time")]
Time(Vec<Option<DateTime>>),
#[cfg(feature = "time")]
TimeDelta(Vec<Option<TimeDelta>>),
}
impl From<Vec<f64>> for VecColumn {
fn from(v: Vec<f64>) -> Self {
VecColumn::F64(v)
}
}
impl From<Vec<Option<i64>>> for VecColumn {
fn from(v: Vec<Option<i64>>) -> Self {
VecColumn::I64(v)
}
}
impl From<Vec<Option<String>>> for VecColumn {
fn from(v: Vec<Option<String>>) -> Self {
VecColumn::Str(v)
}
}
impl From<Vec<i64>> for VecColumn {
fn from(v: Vec<i64>) -> Self {
let v: Vec<Option<i64>> = v.into_iter().map(Some).collect();
VecColumn::I64(v)
}
}
impl From<Vec<String>> for VecColumn {
fn from(v: Vec<String>) -> Self {
let v: Vec<Option<String>> = v.into_iter().map(Some).collect();
VecColumn::Str(v)
}
}
impl Column for VecColumn {
fn len(&self) -> usize {
match self {
VecColumn::F64(v) => v.len(),
VecColumn::I64(v) => v.len(),
VecColumn::Str(v) => v.len(),
#[cfg(feature = "time")]
VecColumn::Time(v) => v.len(),
#[cfg(feature = "time")]
VecColumn::TimeDelta(v) => v.len(),
}
}
fn len_some(&self) -> usize {
match self {
VecColumn::F64(v) => <dyn F64Column>::len_some(v),
VecColumn::I64(v) => <dyn I64Column>::len_some(v),
VecColumn::Str(v) => <dyn StrColumn>::len_some(v),
#[cfg(feature = "time")]
VecColumn::Time(v) => <dyn TimeColumn>::len_some(v),
#[cfg(feature = "time")]
VecColumn::TimeDelta(v) => <dyn TimeDeltaColumn>::len_some(v),
}
}
fn sample_iter(&self) -> Box<dyn Iterator<Item = SampleRef<'_>> + '_> {
match self {
VecColumn::F64(v) => Box::new(v.iter().map(|v| (*v).into())),
VecColumn::I64(v) => Box::new(v.iter().map(|v| (*v).into())),
VecColumn::Str(v) => Box::new(v.iter().map(|v| match v {
Some(s) => SampleRef::Cat(s.as_str()),
None => SampleRef::Null,
})),
#[cfg(feature = "time")]
VecColumn::Time(v) => Box::new(v.iter().map(|v| (*v).into())),
#[cfg(feature = "time")]
VecColumn::TimeDelta(v) => Box::new(v.iter().map(|v| (*v).into())),
}
}
fn f64(&self) -> Option<&dyn F64Column> {
match self {
VecColumn::F64(v) => Some(v),
VecColumn::I64(v) => Some(v),
_ => None,
}
}
fn i64(&self) -> Option<&dyn I64Column> {
match self {
VecColumn::I64(v) => Some(v),
_ => None,
}
}
fn str(&self) -> Option<&dyn StrColumn> {
match self {
VecColumn::Str(v) => Some(v),
_ => None,
}
}
#[cfg(feature = "time")]
fn time(&self) -> Option<&dyn TimeColumn> {
match self {
VecColumn::Time(v) => Some(v),
_ => None,
}
}
#[cfg(feature = "time")]
fn time_delta(&self) -> Option<&dyn TimeDeltaColumn> {
match self {
VecColumn::TimeDelta(v) => Some(v),
_ => None,
}
}
fn boxed_copy(&self) -> Box<dyn Column> {
match self {
VecColumn::F64(v) => Box::new(v.clone()),
VecColumn::I64(v) => Box::new(v.clone()),
VecColumn::Str(v) => Box::new(v.clone()),
#[cfg(feature = "time")]
VecColumn::Time(v) => Box::new(v.clone()),
#[cfg(feature = "time")]
VecColumn::TimeDelta(v) => Box::new(v.clone()),
}
}
}
#[derive(Clone)]
pub struct TableSource {
heads: Vec<String>,
columns: Vec<VecColumn>,
len: usize,
}
impl TableSource {
pub fn new() -> Self {
Self {
heads: Vec::new(),
columns: Vec::new(),
len: 0,
}
}
pub fn heads(&self) -> &[String] {
&self.heads
}
pub fn add_column(&mut self, name: &str, col: VecColumn) {
self.len = self.len.max(col.len());
self.heads.push(name.to_string());
self.columns.push(col);
for col in &mut self.columns {
while col.len() < self.len {
match col {
VecColumn::F64(vec) => vec.push(f64::NAN),
VecColumn::I64(vec) => vec.push(None),
VecColumn::Str(vec) => vec.push(None),
#[cfg(feature = "time")]
VecColumn::Time(vec) => vec.push(None),
#[cfg(feature = "time")]
VecColumn::TimeDelta(vec) => vec.push(None),
}
}
}
}
pub fn with_column(mut self, name: &str, col: VecColumn) -> Self {
self.add_column(name, col);
self
}
pub fn with_f64_column(mut self, name: &str, col: Vec<f64>) -> Self {
self.add_column(name, VecColumn::F64(col));
self
}
pub fn with_i64_column(mut self, name: &str, col: Vec<Option<i64>>) -> Self {
self.add_column(name, VecColumn::I64(col));
self
}
pub fn with_str_column(mut self, name: &str, col: Vec<Option<String>>) -> Self {
self.add_column(name, VecColumn::Str(col));
self
}
#[cfg(feature = "time")]
pub fn with_time_column(mut self, name: &str, col: Vec<Option<DateTime>>) -> Self {
self.add_column(name, VecColumn::Time(col));
self
}
#[cfg(feature = "time")]
pub fn with_time_delta_column(mut self, name: &str, col: Vec<Option<TimeDelta>>) -> Self {
self.add_column(name, VecColumn::TimeDelta(col));
self
}
pub fn len(&self) -> usize {
self.len
}
}
impl Source for TableSource {
fn names(&self) -> Vec<&str> {
self.heads.iter().map(|s| s.as_str()).collect()
}
fn column(&self, name: &str) -> Option<&dyn Column> {
let Some(idx) = self.heads.as_slice().iter().position(|k| k == name) else {
return None;
};
self.columns.get(idx).map(|c| c as &dyn Column)
}
fn copy(&self) -> Arc<dyn Source> {
Arc::new(self.clone())
}
}
impl std::fmt::Debug for TableSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let rows = self.len();
let cols = self.heads.len();
let (col_indices, show_ellipsis) = if cols > 8 {
let mut idxs = (0..4).collect::<Vec<_>>();
idxs.extend((cols - 4)..cols);
(idxs, true)
} else {
((0..cols).collect::<Vec<_>>(), false)
};
fn cell_string(col: &VecColumn, row: usize) -> String {
match col {
VecColumn::F64(v) => {
let val = v.get(row).copied();
match val {
Some(x) if x.is_finite() => format!("{:.6}", x),
_ => "(null)".to_string(),
}
}
VecColumn::I64(v) => match v.get(row).copied().flatten() {
Some(x) => format!("{}", x),
None => "(null)".to_string(),
},
VecColumn::Str(v) => match v.get(row) {
Some(Some(s)) => s.clone(),
_ => "(null)".to_string(),
},
#[cfg(feature = "time")]
VecColumn::Time(v) => match v.get(row) {
Some(Some(t)) => format!("{}", t),
_ => "(null)".to_string(),
},
#[cfg(feature = "time")]
VecColumn::TimeDelta(v) => match v.get(row) {
Some(Some(t)) => format!("{}", t),
_ => "(null)".to_string(),
},
}
}
let mut col_widths: Vec<usize> = col_indices.iter().map(|&i| self.heads[i].len()).collect();
let row_indices: Vec<usize> = if rows <= 10 {
(0..rows).collect()
} else {
(0..5).chain((rows - 5)..rows).collect()
};
for (col_pos, &col_idx) in col_indices.iter().enumerate() {
col_widths[col_pos] = col_widths[col_pos].max(self.heads[col_idx].len());
for &row in &row_indices {
let cell = cell_string(&self.columns[col_idx], row);
col_widths[col_pos] = col_widths[col_pos].max(cell.len());
}
}
let ellipsis_width = 6;
writeln!(f, "VecSource: {} rows x {} columns", rows, cols)?;
for (col_pos, &i) in col_indices.iter().enumerate() {
write!(
f,
"| {:^width$} ",
&self.heads[i],
width = col_widths[col_pos]
)?;
}
if show_ellipsis {
write!(f, "| {:^width$} ", "...", width = ellipsis_width)?;
}
writeln!(f, "|")?;
for (col_pos, _) in col_indices.iter().enumerate() {
write!(f, "|{:=^width$}", "", width = col_widths[col_pos] + 2)?;
}
if show_ellipsis {
write!(f, "|{:=^width$}", "", width = ellipsis_width + 2)?;
}
writeln!(f, "|")?;
let print_row = |f: &mut std::fmt::Formatter<'_>, row: usize| -> std::fmt::Result {
for (col_pos, &i) in col_indices.iter().enumerate() {
let cell = cell_string(&self.columns[i], row);
write!(f, "| {:>width$} ", cell, width = col_widths[col_pos])?;
}
if show_ellipsis {
write!(f, "| {:^width$} ", "...", width = ellipsis_width)?;
}
writeln!(f, "|")
};
if rows <= 10 {
for row in 0..rows {
print_row(f, row)?;
}
} else {
for row in 0..5 {
print_row(f, row)?;
}
for (col_pos, _) in col_indices.iter().enumerate() {
write!(f, "| {:^width$} ", "...", width = col_widths[col_pos])?;
}
if show_ellipsis {
write!(f, "| {:^width$} ", "...", width = ellipsis_width)?;
}
writeln!(f, "|")?;
for row in (rows - 5)..rows {
print_row(f, row)?;
}
}
Ok(())
}
}