use std::fmt;
use ha_ndarray::*;
use safecast::CastInto;
use tc_error::*;
use tc_value::Number;
pub enum Block {
F32(ArrayAccess<f32>),
F64(ArrayAccess<f64>),
I16(ArrayAccess<i16>),
I32(ArrayAccess<i32>),
I64(ArrayAccess<i64>),
U8(ArrayAccess<u8>),
U16(ArrayAccess<u16>),
U32(ArrayAccess<u32>),
U64(ArrayAccess<u64>),
}
macro_rules! block_dispatch {
($this:ident, $var:ident, $call:expr) => {
match $this {
Block::F32($var) => $call,
Block::F64($var) => $call,
Block::I16($var) => $call,
Block::I32($var) => $call,
Block::I64($var) => $call,
Block::U8($var) => $call,
Block::U16($var) => $call,
Block::U32($var) => $call,
Block::U64($var) => $call,
}
};
}
macro_rules! block_cmp {
($self:ident, $other:ident, $this:ident, $that:ident, $call:expr) => {
match ($self, $other) {
(Self::F32($this), Self::F32($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::F64($this), Self::F64($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::I16($this), Self::I16($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::I32($this), Self::I32($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::I64($this), Self::I64($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::U8($this), Self::U8($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::U16($this), Self::U16($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::U32($this), Self::U32($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(Self::U64($this), Self::U64($that)) => {
$call.map(ArrayAccess::from).map_err(TCError::from)
}
(this, that) => Err(bad_request!("cannot compare {this:?} with {that:?}")),
}
};
}
impl Block {
pub fn cast<T: CType>(self) -> TCResult<ArrayAccess<T>> {
block_dispatch!(
self,
this,
this.cast().map(ArrayAccess::from).map_err(TCError::from)
)
}
pub fn and(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.and(that))
}
pub fn and_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.and_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn not(self) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.not().map(ArrayAccess::from).map_err(TCError::from)
)
}
pub fn or(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.or(that))
}
pub fn or_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.or_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn xor(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.xor(that))
}
pub fn xor_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.xor_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn eq(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.eq(that))
}
pub fn eq_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.eq_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn gt(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.gt(that))
}
pub fn gt_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.gt_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn ge(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.ge(that))
}
pub fn ge_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.ge_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn lt(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.lt(that))
}
pub fn lt_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.lt_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn le(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.le(that))
}
pub fn le_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.le_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
pub fn ne(self, other: Self) -> TCResult<ArrayAccess<u8>> {
block_cmp!(self, other, this, that, this.ne(that))
}
pub fn ne_scalar(self, other: Number) -> TCResult<ArrayAccess<u8>> {
block_dispatch!(
self,
this,
this.ne_scalar(other.cast_into())
.map(ArrayAccess::from)
.map_err(TCError::from)
)
}
}
macro_rules! block_from {
($t:ty, $var:ident) => {
impl From<ArrayAccess<$t>> for Block {
fn from(array: ArrayAccess<$t>) -> Self {
Self::$var(array)
}
}
};
}
block_from!(f32, F32);
block_from!(f64, F64);
block_from!(i16, I16);
block_from!(i32, I32);
block_from!(i64, I64);
block_from!(u8, U8);
block_from!(u16, U16);
block_from!(u32, U32);
block_from!(u64, U64);
impl fmt::Debug for Block {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::F32(this) => this.fmt(f),
Self::F64(this) => this.fmt(f),
Self::I16(this) => this.fmt(f),
Self::I32(this) => this.fmt(f),
Self::I64(this) => this.fmt(f),
Self::U8(this) => this.fmt(f),
Self::U16(this) => this.fmt(f),
Self::U32(this) => this.fmt(f),
Self::U64(this) => this.fmt(f),
}
}
}