use super::{FRAME_SIZE, FRAME_WIDTH};
use crate::{
bc::BytecodeValue,
result::{RoarError, RoarResult},
runtime_value_impl,
};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum RuntimeValue {
I64(RuntimeI64Value),
F64(RuntimeF64Value),
}
impl RuntimeValue {
pub fn f64_splat(value: f64) -> RuntimeValue {
RuntimeValue::F64(RuntimeF64Value::splat(value))
}
pub fn i64_splat(value: i64) -> RuntimeValue {
RuntimeValue::I64(RuntimeI64Value::splat(value))
}
pub fn f64_new(value: [f64; FRAME_SIZE]) -> RuntimeValue {
RuntimeValue::F64(RuntimeF64Value::new(value))
}
pub fn i64_new(value: [i64; FRAME_SIZE]) -> RuntimeValue {
RuntimeValue::I64(RuntimeI64Value::new(value))
}
}
impl From<BytecodeValue> for RuntimeValue {
fn from(value: BytecodeValue) -> Self {
match value {
BytecodeValue::F64(v) => RuntimeValue::F64(RuntimeF64Value::splat(v)),
BytecodeValue::I64(v) => RuntimeValue::I64(RuntimeI64Value::splat(v)),
}
}
}
impl From<RuntimeI64Value> for RuntimeValue {
fn from(value: RuntimeI64Value) -> Self {
Self::I64(value)
}
}
impl RuntimeValue {
pub fn as_i64(self) -> RoarResult<RuntimeI64Value> {
match self {
RuntimeValue::F64(_) => Err(RoarError::UnmatchedTypeUnwrap),
RuntimeValue::I64(runtime_i64_value) => Ok(runtime_i64_value),
}
}
}
impl From<RuntimeF64Value> for RuntimeValue {
fn from(value: RuntimeF64Value) -> Self {
Self::F64(value)
}
}
impl RuntimeValue {
pub fn as_f64(self) -> RoarResult<RuntimeF64Value> {
match self {
RuntimeValue::I64(_) => Err(RoarError::UnmatchedTypeUnwrap),
RuntimeValue::F64(runtime_f64_value) => Ok(runtime_f64_value),
}
}
}
impl std::ops::Shl for RuntimeI64Value {
type Output = RuntimeI64Value;
fn shl(mut self, rhs: Self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] <<= rhs[i]
}
self
}
}
impl std::ops::ShlAssign for RuntimeI64Value {
fn shl_assign(&mut self, rhs: Self) {
*self = *self << rhs;
}
}
impl std::ops::Shr for RuntimeI64Value {
type Output = RuntimeI64Value;
fn shr(mut self, rhs: Self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] >>= rhs[i]
}
self
}
}
impl std::ops::ShrAssign for RuntimeI64Value {
fn shr_assign(&mut self, rhs: Self) {
*self = *self >> rhs;
}
}
impl RuntimeF64Value {
pub fn powi(mut self, pow: RuntimeI64Value) -> Self {
for i in 0..FRAME_SIZE {
self[i] = self[i].powi(pow[i] as i32)
}
self
}
pub fn powf(mut self, pow: RuntimeF64Value) -> Self {
for i in 0..FRAME_SIZE {
self[i] = self[i].powf(pow[i])
}
self
}
}
impl RuntimeI64Value {
pub fn pow(mut self, pow: Self) -> Self {
for i in 0..FRAME_SIZE {
self[i] = self[i].pow(pow[i] as u32)
}
self
}
}
runtime_value_impl!(RuntimeI64Value, i64);
runtime_value_impl!(RuntimeF64Value, f64);
#[macro_export]
macro_rules! runtime_value_impl {
($name:ident, $t:ty) => {
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct $name([$t; FRAME_SIZE]);
impl $name {
pub fn new(value: [$t; FRAME_SIZE]) -> Self {
Self(value)
}
pub fn splat(value: $t) -> Self {
Self([value; FRAME_SIZE])
}
}
impl std::ops::Index<usize> for $name {
type Output = $t;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl std::ops::IndexMut<usize> for $name {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl std::ops::Add for $name {
type Output = $name;
fn add(mut self, rhs: Self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] += rhs[i]
}
self
}
}
impl std::ops::AddAssign for $name {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl std::ops::Mul for $name {
type Output = $name;
fn mul(mut self, rhs: Self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] *= rhs[i]
}
self
}
}
impl std::ops::MulAssign for $name {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl std::ops::Sub for $name {
type Output = $name;
fn sub(mut self, rhs: Self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] -= rhs[i]
}
self
}
}
impl std::ops::SubAssign for $name {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl std::ops::Div for $name {
type Output = $name;
fn div(mut self, rhs: Self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] /= rhs[i]
}
self
}
}
impl std::ops::DivAssign for $name {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl std::ops::Neg for $name {
type Output = $name;
fn neg(mut self) -> Self::Output {
for i in 0..FRAME_SIZE {
self[i] = -self[i];
}
self
}
}
impl Default for $name {
fn default() -> Self {
Self([Default::default(); FRAME_SIZE])
}
}
impl $name {
pub fn new_with_fn(mut f: impl FnMut(usize, usize) -> $t) -> Self {
let mut value = [Default::default(); FRAME_SIZE];
for y in 0..FRAME_WIDTH {
for x in 0..FRAME_WIDTH {
value[y * FRAME_WIDTH + x] = f(x, y);
}
}
Self(value)
}
pub fn unanymous_val(&self) -> crate::result::RoarResult<$t> {
let val = self[0];
for i in 0..FRAME_SIZE {
if self[i] != val {
return Err(crate::result::RoarError::ValueNotUnanymous);
}
}
Ok(val)
}
pub fn arr(&self) -> [$t; FRAME_SIZE] {
self.0
}
}
impl $name {
pub fn min(mut self, other: Self) -> Self {
for i in 0..FRAME_SIZE {
self[i] = self[i].min(other[i]);
}
self
}
pub fn max(mut self, other: Self) -> Self {
for i in 0..FRAME_SIZE {
self[i] = self[i].max(other[i]);
}
self
}
}
};
}