use std::fmt::Display;
use crate::{Error, TulispObject, TulispValue};
#[derive(Debug, Clone, Copy)]
pub enum Number {
Int(i64),
Float(f64),
}
impl Default for Number {
fn default() -> Self {
Number::Int(0)
}
}
impl From<i64> for Number {
fn from(value: i64) -> Self {
Number::Int(value)
}
}
impl From<f64> for Number {
fn from(value: f64) -> Self {
Number::Float(value)
}
}
impl TryFrom<TulispObject> for Number {
type Error = Error;
fn try_from(value: TulispObject) -> Result<Self, Self::Error> {
match &value.inner_ref().0 {
TulispValue::Number { value } => Ok(*value),
_ => Err(Error::type_mismatch(format!(
"Expected number, got: {}",
value
))),
}
}
}
impl From<Number> for TulispObject {
fn from(value: Number) -> Self {
match value {
Number::Int(v) => v.into(),
Number::Float(v) => v.into(),
}
}
}
impl Display for Number {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Number::Int(v) => write!(f, "{}", v),
Number::Float(v) => write!(f, "{}", v),
}
}
}
impl std::ops::Add for Number {
type Output = Number;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Number::Int(l), Number::Int(r)) => Number::Int(l + r),
(Number::Int(l), Number::Float(r)) => Number::Float(l as f64 + r),
(Number::Float(l), Number::Int(r)) => Number::Float(l + r as f64),
(Number::Float(l), Number::Float(r)) => Number::Float(l + r),
}
}
}
impl std::ops::Add<i64> for Number {
type Output = Number;
fn add(self, rhs: i64) -> Self::Output {
match self {
Number::Int(l) => Number::Int(l + rhs),
Number::Float(l) => Number::Float(l + rhs as f64),
}
}
}
impl std::ops::Add<f64> for Number {
type Output = Number;
fn add(self, rhs: f64) -> Self::Output {
match self {
Number::Int(l) => Number::Float(l as f64 + rhs),
Number::Float(l) => Number::Float(l + rhs),
}
}
}
impl std::ops::Sub for Number {
type Output = Number;
fn sub(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Number::Int(l), Number::Int(r)) => Number::Int(l - r),
(Number::Int(l), Number::Float(r)) => Number::Float(l as f64 - r),
(Number::Float(l), Number::Int(r)) => Number::Float(l - r as f64),
(Number::Float(l), Number::Float(r)) => Number::Float(l - r),
}
}
}
impl std::ops::Sub<i64> for Number {
type Output = Number;
fn sub(self, rhs: i64) -> Self::Output {
match self {
Number::Int(l) => Number::Int(l - rhs),
Number::Float(l) => Number::Float(l - rhs as f64),
}
}
}
impl std::ops::Sub<f64> for Number {
type Output = Number;
fn sub(self, rhs: f64) -> Self::Output {
match self {
Number::Int(l) => Number::Float(l as f64 - rhs),
Number::Float(l) => Number::Float(l - rhs),
}
}
}
impl std::ops::Mul for Number {
type Output = Number;
fn mul(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Number::Int(l), Number::Int(r)) => Number::Int(l * r),
(Number::Int(l), Number::Float(r)) => Number::Float(l as f64 * r),
(Number::Float(l), Number::Int(r)) => Number::Float(l * r as f64),
(Number::Float(l), Number::Float(r)) => Number::Float(l * r),
}
}
}
impl std::ops::Mul<i64> for Number {
type Output = Number;
fn mul(self, rhs: i64) -> Self::Output {
match self {
Number::Int(l) => Number::Int(l * rhs),
Number::Float(l) => Number::Float(l * rhs as f64),
}
}
}
impl std::ops::Mul<f64> for Number {
type Output = Number;
fn mul(self, rhs: f64) -> Self::Output {
match self {
Number::Int(l) => Number::Float(l as f64 * rhs),
Number::Float(l) => Number::Float(l * rhs),
}
}
}
impl std::ops::Div for Number {
type Output = Number;
fn div(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Number::Int(l), Number::Int(r)) => Number::Float(l as f64 / r as f64),
(Number::Int(l), Number::Float(r)) => Number::Float(l as f64 / r),
(Number::Float(l), Number::Int(r)) => Number::Float(l / r as f64),
(Number::Float(l), Number::Float(r)) => Number::Float(l / r),
}
}
}
impl std::ops::Div<i64> for Number {
type Output = Number;
fn div(self, rhs: i64) -> Self::Output {
match self {
Number::Int(l) => Number::Float(l as f64 / rhs as f64),
Number::Float(l) => Number::Float(l / rhs as f64),
}
}
}
impl std::ops::Div<f64> for Number {
type Output = Number;
fn div(self, rhs: f64) -> Self::Output {
match self {
Number::Int(l) => Number::Float(l as f64 / rhs),
Number::Float(l) => Number::Float(l / rhs),
}
}
}
impl std::ops::Rem for Number {
type Output = Number;
fn rem(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Number::Int(l), Number::Int(r)) => Number::Int(l % r),
(Number::Int(l), Number::Float(r)) => Number::Float(l as f64 % r),
(Number::Float(l), Number::Int(r)) => Number::Float(l % r as f64),
(Number::Float(l), Number::Float(r)) => Number::Float(l % r),
}
}
}
impl std::ops::Rem<i64> for Number {
type Output = Number;
fn rem(self, rhs: i64) -> Self::Output {
match self {
Number::Int(l) => Number::Int(l % rhs),
Number::Float(l) => Number::Float(l % rhs as f64),
}
}
}
impl std::ops::Rem<f64> for Number {
type Output = Number;
fn rem(self, rhs: f64) -> Self::Output {
match self {
Number::Int(l) => Number::Float(l as f64 % rhs),
Number::Float(l) => Number::Float(l % rhs),
}
}
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Number::Int(l), Number::Int(r)) => l == r,
(Number::Int(l), Number::Float(r)) => (*l as f64) == *r,
(Number::Float(l), Number::Int(r)) => *l == (*r as f64),
(Number::Float(l), Number::Float(r)) => l == r,
}
}
}
impl PartialEq<i64> for Number {
fn eq(&self, other: &i64) -> bool {
match self {
Number::Int(l) => l == other,
Number::Float(l) => *l == (*other as f64),
}
}
}
impl PartialEq<f64> for Number {
fn eq(&self, other: &f64) -> bool {
match self {
Number::Int(l) => (*l as f64) == *other,
Number::Float(l) => l == other,
}
}
}
impl PartialOrd for Number {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
(Number::Int(l), Number::Int(r)) => l.partial_cmp(r),
(Number::Int(l), Number::Float(r)) => (*l as f64).partial_cmp(r),
(Number::Float(l), Number::Int(r)) => l.partial_cmp(&(*r as f64)),
(Number::Float(l), Number::Float(r)) => l.partial_cmp(r),
}
}
}
impl PartialOrd<i64> for Number {
fn partial_cmp(&self, other: &i64) -> Option<std::cmp::Ordering> {
match self {
Number::Int(l) => l.partial_cmp(other),
Number::Float(l) => l.partial_cmp(&(*other as f64)),
}
}
}
impl PartialOrd<f64> for Number {
fn partial_cmp(&self, other: &f64) -> Option<std::cmp::Ordering> {
match self {
Number::Int(l) => (*l as f64).partial_cmp(other),
Number::Float(l) => l.partial_cmp(other),
}
}
}