use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use crate::dtype::DType;
use crate::expr::stats::precision::Precision::Exact;
use crate::expr::stats::precision::Precision::Inexact;
use crate::scalar::Scalar;
use crate::scalar::ScalarValue;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Precision<T> {
Exact(T),
Inexact(T),
}
impl<T> Precision<Option<T>> {
pub fn transpose(self) -> Option<Precision<T>> {
match self {
Exact(Some(x)) => Some(Exact(x)),
Inexact(Some(x)) => Some(Inexact(x)),
Exact(None) | Inexact(None) => None,
}
}
}
impl<T> Precision<T>
where
T: Copy,
{
pub fn to_inexact(&self) -> Self {
match self {
Exact(v) => Exact(*v),
Inexact(v) => Inexact(*v),
}
}
}
impl<T> Precision<T> {
pub fn exact<S: Into<T>>(s: S) -> Precision<T> {
Exact(s.into())
}
pub fn inexact<S: Into<T>>(s: S) -> Precision<T> {
Inexact(s.into())
}
pub fn as_ref(&self) -> Precision<&T> {
match self {
Exact(val) => Exact(val),
Inexact(val) => Inexact(val),
}
}
pub fn into_inexact(self) -> Self {
match self {
Exact(val) => Inexact(val),
Inexact(_) => self,
}
}
pub fn as_exact(self) -> Option<T> {
match self {
Exact(val) => Some(val),
_ => None,
}
}
pub fn as_inexact(self) -> Option<T> {
match self {
Inexact(val) => Some(val),
_ => None,
}
}
pub fn is_exact(&self) -> bool {
matches!(self, Exact(_))
}
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Precision<U> {
match self {
Exact(value) => Exact(f(value)),
Inexact(value) => Inexact(f(value)),
}
}
pub fn zip<U>(self, other: Precision<U>) -> Precision<(T, U)> {
match (self, other) {
(Exact(lhs), Exact(rhs)) => Exact((lhs, rhs)),
(Inexact(lhs), Exact(rhs))
| (Exact(lhs), Inexact(rhs))
| (Inexact(lhs), Inexact(rhs)) => Inexact((lhs, rhs)),
}
}
pub fn try_map<U, F: FnOnce(T) -> VortexResult<U>>(self, f: F) -> VortexResult<Precision<U>> {
let precision = match self {
Exact(value) => Exact(f(value)?),
Inexact(value) => Inexact(f(value)?),
};
Ok(precision)
}
pub fn into_inner(self) -> T {
match self {
Exact(val) | Inexact(val) => val,
}
}
}
impl<T: Display> Display for Precision<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Exact(v) => {
write!(f, "{v}")
}
Inexact(v) => {
write!(f, "~{v}")
}
}
}
}
impl<T: PartialEq> PartialEq<T> for Precision<T> {
fn eq(&self, other: &T) -> bool {
match self {
Exact(v) => v == other,
_ => false,
}
}
}
impl Precision<ScalarValue> {
pub fn into_scalar(self, dtype: DType) -> Precision<Scalar> {
self.map(|v| {
Scalar::try_new(dtype, Some(v)).vortex_expect("`Precision<ScalarValue>` was invalid")
})
}
}
impl Precision<&ScalarValue> {
pub fn into_scalar(self, dtype: DType) -> Precision<Scalar> {
self.map(|v| {
Scalar::try_new(dtype, Some(v.clone()))
.vortex_expect("`Precision<ScalarValue>` was invalid")
})
}
}