use std::{
fmt::{Display, Formatter},
sync::Arc,
};
use crate::{Bitmask, DatetimeArray, MaskedArray};
use crate::{
enums::{error::MinarrowError, shape_dim::ShapeDim},
traits::{concatenate::Concatenate, shape::Shape},
};
#[repr(C, align(64))]
#[derive(PartialEq, Clone, Debug, Default)]
pub enum TemporalArray {
Datetime32(Arc<DatetimeArray<i32>>), Datetime64(Arc<DatetimeArray<i64>>),
#[default]
Null, }
impl TemporalArray {
#[inline]
pub fn len(&self) -> usize {
match self {
TemporalArray::Datetime32(arr) => arr.len(),
TemporalArray::Datetime64(arr) => arr.len(),
TemporalArray::Null => 0,
}
}
#[inline]
pub fn null_mask(&self) -> Option<&Bitmask> {
match self {
TemporalArray::Datetime32(arr) => arr.null_mask.as_ref(),
TemporalArray::Datetime64(arr) => arr.null_mask.as_ref(),
TemporalArray::Null => None,
}
}
pub fn append_array(&mut self, other: &Self) {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => {
Arc::make_mut(a).append_array(b)
}
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => {
Arc::make_mut(a).append_array(b)
}
(TemporalArray::Null, TemporalArray::Null) => (),
(lhs, rhs) => panic!("Cannot append {:?} into {:?}", rhs, lhs),
}
}
pub fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => Arc::make_mut(a).append_range(b, offset, len),
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => Arc::make_mut(a).append_range(b, offset, len),
(TemporalArray::Null, TemporalArray::Null) => Ok(()),
(lhs, rhs) => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some(format!("Cannot append_range {:?} into {:?}", rhs, lhs)),
}),
}
}
pub fn insert_rows(&mut self, index: usize, other: &Self) -> Result<(), MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => {
Arc::make_mut(a).insert_rows(index, b)
}
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => {
Arc::make_mut(a).insert_rows(index, b)
}
(TemporalArray::Null, TemporalArray::Null) => Ok(()),
(lhs, rhs) => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some(format!(
"Cannot insert {} into {}: incompatible types",
temporal_variant_name(rhs),
temporal_variant_name(lhs)
)),
}),
}
}
pub fn split(self, index: usize) -> Result<(Self, Self), MinarrowError> {
use std::sync::Arc;
match self {
TemporalArray::Datetime32(a) => {
let (left, right) = Arc::try_unwrap(a)
.unwrap_or_else(|arc| (*arc).clone())
.split(index)?;
Ok((
TemporalArray::Datetime32(Arc::new(left)),
TemporalArray::Datetime32(Arc::new(right)),
))
}
TemporalArray::Datetime64(a) => {
let (left, right) = Arc::try_unwrap(a)
.unwrap_or_else(|arc| (*arc).clone())
.split(index)?;
Ok((
TemporalArray::Datetime64(Arc::new(left)),
TemporalArray::Datetime64(Arc::new(right)),
))
}
TemporalArray::Null => Err(MinarrowError::IndexError(
"Cannot split Null array".to_string(),
)),
}
}
pub fn dt32_ref(&self) -> Result<&DatetimeArray<i32>, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => Ok(arr),
TemporalArray::Datetime64(_) => Err(MinarrowError::TypeError {
from: "Datetime64",
to: "DatetimeArray<i32>",
message: None,
}),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
pub fn dt64_ref(&self) -> Result<&DatetimeArray<i64>, MinarrowError> {
match self {
TemporalArray::Datetime64(arr) => Ok(arr),
TemporalArray::Datetime32(_) => Err(MinarrowError::TypeError {
from: "Datetime32",
to: "DatetimeArray<i64>",
message: None,
}),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
pub fn dt32(self) -> Result<DatetimeArray<i32>, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => match Arc::try_unwrap(arr) {
Ok(inner) => Ok(inner),
Err(shared) => Ok((*shared).clone()),
},
TemporalArray::Datetime64(arr) => Ok(DatetimeArray::<i32>::try_from(&*arr)?),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
pub fn dt64(self) -> Result<DatetimeArray<i64>, MinarrowError> {
match self {
TemporalArray::Datetime64(arr) => match Arc::try_unwrap(arr) {
Ok(inner) => Ok(inner),
Err(shared) => Ok((*shared).clone()),
},
TemporalArray::Datetime32(arr) => Ok(DatetimeArray::<i64>::from(&*arr)),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
}
impl Shape for TemporalArray {
fn shape(&self) -> ShapeDim {
ShapeDim::Rank1(self.len())
}
}
impl Concatenate for TemporalArray {
fn concat(self, other: Self) -> Result<Self, MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => {
let a = Arc::try_unwrap(a).unwrap_or_else(|arc| (*arc).clone());
let b = Arc::try_unwrap(b).unwrap_or_else(|arc| (*arc).clone());
Ok(TemporalArray::Datetime32(Arc::new(a.concat(b)?)))
}
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => {
let a = Arc::try_unwrap(a).unwrap_or_else(|arc| (*arc).clone());
let b = Arc::try_unwrap(b).unwrap_or_else(|arc| (*arc).clone());
Ok(TemporalArray::Datetime64(Arc::new(a.concat(b)?)))
}
(TemporalArray::Null, TemporalArray::Null) => Ok(TemporalArray::Null),
(lhs, rhs) => Err(MinarrowError::IncompatibleTypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some(format!(
"Cannot concatenate mismatched TemporalArray variants: {:?} and {:?}",
temporal_variant_name(&lhs),
temporal_variant_name(&rhs)
)),
}),
}
}
}
#[cfg(feature = "datetime_ops")]
use crate::DatetimeOps;
#[cfg(feature = "datetime_ops")]
use crate::enums::time_units::TimeUnit;
#[cfg(feature = "datetime_ops")]
use time::Duration;
#[cfg(feature = "datetime_ops")]
use crate::structs::variants::{boolean::BooleanArray, integer::IntegerArray};
#[cfg(feature = "datetime_ops")]
impl DatetimeOps for TemporalArray {
fn year(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.year(),
TemporalArray::Datetime64(arr) => arr.year(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn month(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.month(),
TemporalArray::Datetime64(arr) => arr.month(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn day(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.day(),
TemporalArray::Datetime64(arr) => arr.day(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn hour(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.hour(),
TemporalArray::Datetime64(arr) => arr.hour(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn minute(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.minute(),
TemporalArray::Datetime64(arr) => arr.minute(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn second(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.second(),
TemporalArray::Datetime64(arr) => arr.second(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn weekday(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.weekday(),
TemporalArray::Datetime64(arr) => arr.weekday(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn day_of_year(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.day_of_year(),
TemporalArray::Datetime64(arr) => arr.day_of_year(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn iso_week(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.iso_week(),
TemporalArray::Datetime64(arr) => arr.iso_week(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn quarter(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.quarter(),
TemporalArray::Datetime64(arr) => arr.quarter(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn week_of_year(&self) -> IntegerArray<i32> {
match self {
TemporalArray::Datetime32(arr) => arr.week_of_year(),
TemporalArray::Datetime64(arr) => arr.week_of_year(),
TemporalArray::Null => IntegerArray::default(),
}
}
fn is_leap_year(&self) -> BooleanArray<()> {
match self {
TemporalArray::Datetime32(arr) => arr.is_leap_year(),
TemporalArray::Datetime64(arr) => arr.is_leap_year(),
TemporalArray::Null => BooleanArray::default(),
}
}
fn add_duration(&self, duration: Duration) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => Ok(TemporalArray::Datetime32(Arc::new(
arr.add_duration(duration)?,
))),
TemporalArray::Datetime64(arr) => Ok(TemporalArray::Datetime64(Arc::new(
arr.add_duration(duration)?,
))),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
fn sub_duration(&self, duration: Duration) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => Ok(TemporalArray::Datetime32(Arc::new(
arr.sub_duration(duration)?,
))),
TemporalArray::Datetime64(arr) => Ok(TemporalArray::Datetime64(Arc::new(
arr.sub_duration(duration)?,
))),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
fn add_days(&self, days: i64) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => {
Ok(TemporalArray::Datetime32(Arc::new(arr.add_days(days)?)))
}
TemporalArray::Datetime64(arr) => {
Ok(TemporalArray::Datetime64(Arc::new(arr.add_days(days)?)))
}
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
fn add_months(&self, months: i32) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => {
Ok(TemporalArray::Datetime32(Arc::new(arr.add_months(months)?)))
}
TemporalArray::Datetime64(arr) => {
Ok(TemporalArray::Datetime64(Arc::new(arr.add_months(months)?)))
}
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
fn add_years(&self, years: i32) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => {
Ok(TemporalArray::Datetime32(Arc::new(arr.add_years(years)?)))
}
TemporalArray::Datetime64(arr) => {
Ok(TemporalArray::Datetime64(Arc::new(arr.add_years(years)?)))
}
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
fn diff(&self, other: &Self, unit: TimeUnit) -> Result<IntegerArray<i64>, MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.diff(b, unit),
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.diff(b, unit),
(TemporalArray::Null, _) | (_, TemporalArray::Null) => {
Err(MinarrowError::NullError { message: None })
}
_ => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some("Mismatched temporal variants".to_string()),
}),
}
}
fn abs_diff(&self, other: &Self, unit: TimeUnit) -> Result<IntegerArray<i64>, MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.abs_diff(b, unit),
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.abs_diff(b, unit),
(TemporalArray::Null, _) | (_, TemporalArray::Null) => {
Err(MinarrowError::NullError { message: None })
}
_ => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some("Mismatched temporal variants".to_string()),
}),
}
}
fn is_before(&self, other: &Self) -> Result<BooleanArray<()>, MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.is_before(b),
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.is_before(b),
(TemporalArray::Null, _) | (_, TemporalArray::Null) => {
Err(MinarrowError::NullError { message: None })
}
_ => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some("Mismatched temporal variants".to_string()),
}),
}
}
fn is_after(&self, other: &Self) -> Result<BooleanArray<()>, MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => a.is_after(b),
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => a.is_after(b),
(TemporalArray::Null, _) | (_, TemporalArray::Null) => {
Err(MinarrowError::NullError { message: None })
}
_ => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some("Mismatched temporal variants".to_string()),
}),
}
}
fn between(&self, start: &Self, end: &Self) -> Result<BooleanArray<()>, MinarrowError> {
match (self, start, end) {
(
TemporalArray::Datetime32(a),
TemporalArray::Datetime32(s),
TemporalArray::Datetime32(e),
) => a.between(s, e),
(
TemporalArray::Datetime64(a),
TemporalArray::Datetime64(s),
TemporalArray::Datetime64(e),
) => a.between(s, e),
(TemporalArray::Null, _, _)
| (_, TemporalArray::Null, _)
| (_, _, TemporalArray::Null) => Err(MinarrowError::NullError { message: None }),
_ => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some("Mismatched temporal variants".to_string()),
}),
}
}
fn truncate(&self, unit: &str) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => {
Ok(TemporalArray::Datetime32(Arc::new(arr.truncate(unit)?)))
}
TemporalArray::Datetime64(arr) => {
Ok(TemporalArray::Datetime64(Arc::new(arr.truncate(unit)?)))
}
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
fn us(&self) -> Self {
match self {
TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.us())),
TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.us())),
TemporalArray::Null => TemporalArray::Null,
}
}
fn ms(&self) -> Self {
match self {
TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.ms())),
TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.ms())),
TemporalArray::Null => TemporalArray::Null,
}
}
fn sec(&self) -> Self {
match self {
TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.sec())),
TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.sec())),
TemporalArray::Null => TemporalArray::Null,
}
}
fn min(&self) -> Self {
match self {
TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.min())),
TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.min())),
TemporalArray::Null => TemporalArray::Null,
}
}
fn hr(&self) -> Self {
match self {
TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.hr())),
TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.hr())),
TemporalArray::Null => TemporalArray::Null,
}
}
fn week(&self) -> Self {
match self {
TemporalArray::Datetime32(arr) => TemporalArray::Datetime32(Arc::new(arr.week())),
TemporalArray::Datetime64(arr) => TemporalArray::Datetime64(Arc::new(arr.week())),
TemporalArray::Null => TemporalArray::Null,
}
}
fn cast_time_unit(&self, new_unit: TimeUnit) -> Result<Self, MinarrowError> {
match self {
TemporalArray::Datetime32(arr) => Ok(TemporalArray::Datetime32(Arc::new(
arr.cast_time_unit(new_unit)?,
))),
TemporalArray::Datetime64(arr) => Ok(TemporalArray::Datetime64(Arc::new(
arr.cast_time_unit(new_unit)?,
))),
TemporalArray::Null => Err(MinarrowError::NullError { message: None }),
}
}
}
fn temporal_variant_name(arr: &TemporalArray) -> &'static str {
match arr {
TemporalArray::Datetime32(_) => "Datetime32",
TemporalArray::Datetime64(_) => "Datetime64",
TemporalArray::Null => "Null",
}
}
impl Display for TemporalArray {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
TemporalArray::Datetime32(arr) => {
write_temporal_array_with_header(f, "Datetime32", arr.as_ref())
}
TemporalArray::Datetime64(arr) => {
write_temporal_array_with_header(f, "Datetime64", arr.as_ref())
}
TemporalArray::Null => writeln!(f, "TemporalArray::Null [0 values]"),
}
}
}
fn write_temporal_array_with_header<T>(
f: &mut Formatter<'_>,
dtype: &str,
arr: &(impl MaskedArray<CopyType = T> + Display + ?Sized),
) -> std::fmt::Result {
writeln!(
f,
"TemporalArray [{dtype}] [{} values] (null count: {})",
arr.len(),
arr.null_count()
)?;
Display::fmt(arr, f)
}