use crate::arr;
use crate::error::OverError;
use crate::obj;
use crate::parse::format::Format;
use crate::tup;
use crate::types::Type;
use crate::{OverResult, INDENT_STEP};
use num_bigint::BigInt;
use num_rational::BigRational;
use num_traits::ToPrimitive;
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Int(BigInt),
Frac(BigRational),
Char(char),
Str(String),
Arr(arr::Arr),
Tup(tup::Tup),
Obj(obj::Obj),
}
macro_rules! get_fn {
( $doc:expr, $name:tt, $type:ty, $variant:ident ) => {
#[doc=$doc]
pub fn $name(&self) -> OverResult<$type> {
if let Value::$variant(ref inner) = *self {
Ok(inner.clone())
} else {
Err(OverError::TypeMismatch(Type::$variant, self.get_type()))
}
}
}
}
impl Value {
pub fn is_null(&self) -> bool {
if let Value::Null = *self {
true
} else {
false
}
}
pub fn get_type(&self) -> Type {
use self::Value::*;
match *self {
Null => Type::Null,
Bool(_) => Type::Bool,
Int(_) => Type::Int,
Frac(_) => Type::Frac,
Char(_) => Type::Char,
Str(_) => Type::Str,
Arr(ref arr) => Type::Arr(Box::new(arr.inner_type())),
Tup(ref tup) => Type::Tup(tup.inner_type_vec()),
Obj(_) => Type::Obj,
}
}
get_fn!(
"Returns the `bool` contained in this `Value`. \
Returns an error if this `Value` is not `Bool`.",
get_bool,
bool,
Bool
);
get_fn!(
"Returns the `BigInt` contained in this `Value`. \
Returns an error if this `Value` is not `Int`.",
get_int,
BigInt,
Int
);
pub fn get_frac(&self) -> OverResult<BigRational> {
match *self {
Value::Frac(ref inner) => Ok(inner.clone()),
Value::Int(ref inner) => Ok(frac!(inner.clone(), 1)),
_ => Err(OverError::TypeMismatch(Type::Frac, self.get_type())),
}
}
get_fn!(
"Returns the `char` contained in this `Value`. \
Returns an error if this `Value` is not `Char`.",
get_char,
char,
Char
);
get_fn!(
"Returns the `String` contained in this `Value`. \
Returns an error if this `Value` is not `Str`.",
get_str,
String,
Str
);
get_fn!(
"Returns the `Obj` contained in this `Value`. \
Returns an error if this `Value` is not `Obj`.",
get_obj,
obj::Obj,
Obj
);
pub fn get_arr(&self) -> OverResult<arr::Arr> {
if let Value::Arr(ref inner) = *self {
Ok(inner.clone())
} else {
Err(OverError::TypeMismatch(
Type::Arr(Box::new(Type::Any)),
self.get_type(),
))
}
}
pub fn get_tup(&self) -> OverResult<tup::Tup> {
if let Value::Tup(ref inner) = *self {
Ok(inner.clone())
} else {
Err(OverError::TypeMismatch(Type::Tup(vec![]), self.get_type()))
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.format(true, INDENT_STEP))
}
}
macro_rules! impl_eq {
($valtype:ident, $type:ty) => {
impl PartialEq<$type> for Value {
fn eq(&self, other: &$type) -> bool {
match *self {
Value::$valtype(ref value) => value == other,
_ => false,
}
}
}
impl PartialEq<Value> for $type {
fn eq(&self, other: &Value) -> bool {
match *other {
Value::$valtype(ref value) => value == self,
_ => false,
}
}
}
};
}
impl_eq!(Bool, bool);
impl_eq!(Int, BigInt);
impl_eq!(Frac, BigRational);
impl_eq!(Char, char);
impl_eq!(Arr, arr::Arr);
impl_eq!(Tup, tup::Tup);
impl_eq!(Obj, obj::Obj);
impl<'a> PartialEq<&'a str> for Value {
fn eq(&self, other: &&str) -> bool {
match *self {
Value::Str(ref value) => value == &other.replace("\r\n", "\n"),
_ => false,
}
}
}
impl<'a> PartialEq<Value> for &'a str {
fn eq(&self, other: &Value) -> bool {
match *other {
Value::Str(ref value) => value == &self.replace("\r\n", "\n"),
_ => false,
}
}
}
impl PartialEq<String> for Value {
fn eq(&self, other: &String) -> bool {
&other.as_str() == self
}
}
impl PartialEq<Value> for String {
fn eq(&self, other: &Value) -> bool {
&self.as_str() == other
}
}
macro_rules! impl_eq_int {
($type:ty, $fn:tt) => {
impl PartialEq<$type> for Value {
fn eq(&self, other: &$type) -> bool {
match *self {
Value::Int(ref value) => match value.$fn() {
Some(value) => value == *other,
None => false,
},
_ => false,
}
}
}
impl PartialEq<Value> for $type {
fn eq(&self, other: &Value) -> bool {
match *other {
Value::Int(ref value) => match value.$fn() {
Some(value) => value == *self,
None => false,
},
_ => false,
}
}
}
};
}
impl_eq_int!(usize, to_usize);
impl_eq_int!(u8, to_u8);
impl_eq_int!(u16, to_u16);
impl_eq_int!(u32, to_u32);
impl_eq_int!(u64, to_u64);
impl_eq_int!(i8, to_i8);
impl_eq_int!(i16, to_i16);
impl_eq_int!(i32, to_i32);
impl_eq_int!(i64, to_i64);
macro_rules! impl_from {
($type:ty, $fn:tt) => {
impl From<$type> for Value {
fn from(inner: $type) -> Self {
Value::$fn(inner.into())
}
}
};
}
impl_from!(bool, Bool);
impl_from!(usize, Int);
impl_from!(u8, Int);
impl_from!(u16, Int);
impl_from!(u32, Int);
impl_from!(u64, Int);
impl_from!(i8, Int);
impl_from!(i16, Int);
impl_from!(i32, Int);
impl_from!(i64, Int);
impl_from!(BigInt, Int);
impl_from!(BigRational, Frac);
impl_from!(char, Char);
impl_from!(String, Str);
impl<'a> From<&'a str> for Value {
fn from(inner: &str) -> Self {
Value::Str(inner.into())
}
}
impl_from!(arr::Arr, Arr);
impl_from!(tup::Tup, Tup);
impl_from!(obj::Obj, Obj);