yolol-devices 0.3.3

Starbase game's yolol devices library
Documentation
mod int;
mod string;

use std::convert::TryFrom;
use std::convert::TryInto;
use std::fmt::Display;
use std::ops::Add;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Rem;
use std::ops::Sub;

use enum_dispatch::enum_dispatch;

pub use self::int::YololInt;
pub use self::string::YololString;

#[enum_dispatch]
pub trait ValueTrait {
    fn post_inc(&mut self) -> YololValue;
    fn pre_inc(&mut self) -> YololValue;
    fn post_dec(&mut self) -> Option<YololValue>;
    fn pre_dec(&mut self) -> Option<YololValue>;
    fn fac(&self) -> Option<YololValue>;
    fn abs(&self) -> Option<YololValue>;
    fn sqrt(&self) -> Option<YololValue>;
    fn sin(&self) -> Option<YololValue>;
    fn asin(&self) -> Option<YololValue>;
    fn cos(&self) -> Option<YololValue>;
    fn acos(&self) -> Option<YololValue>;
    fn tan(&self) -> Option<YololValue>;
    fn atan(&self) -> Option<YololValue>;
    fn pow(&self, e: &YololValue) -> Option<YololValue>;
    fn not(&self) -> YololValue;
}

#[enum_dispatch(ValueTrait)]
#[derive(Debug, Clone)]
pub enum YololValue {
    String(YololString),
    Int(YololInt),
}

impl Default for YololValue {
    fn default() -> Self {
        YololValue::Int(YololInt::default())
    }
}

impl YololValue {
    fn is_string(&self) -> bool {
        match self {
            YololValue::String(_) => true,
            YololValue::Int(_) => false,
        }
    }
}

impl From<&YololValue> for bool {
    fn from(v: &YololValue) -> Self {
        match v {
            YololValue::String(v) => v.into(),
            YololValue::Int(v) => v.into(),
        }
    }
}

impl From<&str> for YololValue {
    fn from(v: &str) -> Self {
        Self::String(v.into())
    }
}

impl From<i64> for YololValue {
    fn from(v: i64) -> Self {
        Self::Int(v.into())
    }
}

impl From<f64> for YololValue {
    fn from(v: f64) -> Self {
        Self::Int(v.into())
    }
}

impl From<bool> for YololValue {
    fn from(v: bool) -> Self {
        Self::Int(v.into())
    }
}

impl TryFrom<&YololValue> for YololInt {
    type Error = ();

    fn try_from(value: &YololValue) -> Result<Self, Self::Error> {
        if let YololValue::Int(v) = value {
            Ok(*v)
        } else {
            Err(())
        }
    }
}

impl TryFrom<&YololValue> for YololString {
    type Error = ();

    fn try_from(value: &YololValue) -> Result<Self, Self::Error> {
        if let YololValue::String(v) = value {
            Ok(v.clone())
        } else {
            Err(())
        }
    }
}

impl YololValue {
    pub fn or(&self, rhs: &Self) -> Self {
        YololInt::from(self.into() || rhs.into()).into()
    }

    pub fn and(&self, rhs: &Self) -> Self {
        YololInt::from(self.into() && rhs.into()).into()
    }
}

impl Mul for &YololValue {
    type Output = Option<YololValue>;

    fn mul(self, rhs: Self) -> Self::Output {
        if let YololValue::Int(lhs) = self {
            if let YololValue::Int(rhs) = rhs {
                return Some((lhs * rhs).into());
            }
        }
        None
    }
}

impl Div for &YololValue {
    type Output = Option<YololValue>;

    fn div(self, rhs: Self) -> Self::Output {
        if let YololValue::Int(lhs) = self {
            if let YololValue::Int(rhs) = rhs {
                return Some((lhs / rhs)?.into());
            }
        }
        None
    }
}

impl Rem for &YololValue {
    type Output = Option<YololValue>;

    fn rem(self, rhs: Self) -> Self::Output {
        if let YololValue::Int(lhs) = self {
            if let YololValue::Int(rhs) = rhs {
                if rhs != &0.into() {
                    return Some((lhs % rhs)?.into());
                }
            }
        }
        None
    }
}

impl Add for &YololValue {
    type Output = YololValue;

    fn add(self, rhs: Self) -> Self::Output {
        if self.is_string() || rhs.is_string() {
            let a: YololString = {
                if self.is_string() {
                    self.try_into().unwrap()
                } else {
                    let a: &YololInt = &self.try_into().unwrap();
                    a.into()
                }
            };
            let b: YololString = {
                if rhs.is_string() {
                    rhs.try_into().unwrap()
                } else {
                    let b: &YololInt = &rhs.try_into().unwrap();
                    b.into()
                }
            };
            (a + b).into()
        } else {
            let a: YololInt = self.try_into().unwrap();
            let b: YololInt = rhs.try_into().unwrap();
            (&a + &b).into()
        }
    }
}

impl Sub for &YololValue {
    type Output = Option<YololValue>;

    fn sub(self, rhs: Self) -> Self::Output {
        if self.is_string() || rhs.is_string() {
            let a: YololString = {
                if self.is_string() {
                    self.try_into().unwrap()
                } else {
                    let a: &YololInt = &self.try_into().unwrap();
                    a.into()
                }
            };
            let b: YololString = {
                if rhs.is_string() {
                    rhs.try_into().unwrap()
                } else {
                    let b: &YololInt = &rhs.try_into().unwrap();
                    b.into()
                }
            };
            Some((a - b)?.into())
        } else {
            let a: YololInt = self.try_into().unwrap();
            let b: YololInt = rhs.try_into().unwrap();
            Some((&a - &b).into())
        }
    }
}

impl PartialEq for YololValue {
    fn eq(&self, rhs: &Self) -> bool {
        if self.is_string() && rhs.is_string() {
            let a: YololString = self.clone().try_into().unwrap();
            let b: YololString = rhs.clone().try_into().unwrap();
            return a.eq(&b);
        } else if !self.is_string() && !rhs.is_string() {
            let a: YololInt = self.clone().try_into().unwrap();
            let b: YololInt = rhs.clone().try_into().unwrap();
            return a.eq(&b);
        }
        false
    }
}

impl PartialOrd for YololValue {
    fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> {
        if self.is_string() || rhs.is_string() {
            let a: YololString = {
                if self.is_string() {
                    self.clone().try_into().unwrap()
                } else {
                    let a: &YololInt = &self.try_into().unwrap();
                    a.into()
                }
            };
            let b: YololString = {
                if rhs.is_string() {
                    rhs.try_into().unwrap()
                } else {
                    let b: &YololInt = &rhs.clone().try_into().unwrap();
                    b.into()
                }
            };
            a.partial_cmp(&b)
        } else {
            let a: YololInt = self.clone().try_into().unwrap();
            let b: YololInt = rhs.clone().try_into().unwrap();
            a.partial_cmp(&b)
        }
    }
}

impl Display for YololValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            YololValue::String(v) => write!(f, "{}", v),
            YololValue::Int(v) => write!(f, "{}", v),
        }
    }
}