roar 0.1.0

A toolkit for procedural world generation (with a focus on voxel games)
Documentation
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
            }
        }
    };
}