use std::char;
use std::cmp::{Ordering, PartialOrd};
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::iter::{once};
use std::num::{FpCategory};
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use super::class::{Class, Obj};
use super::code::{Coro, GFn};
use super::collections::{Arr, DequeOps, Str, Tab};
use super::engine::{RFn, RData, stock_syms::*, Sym};
use super::error::{GResult};
use super::gc::Root;
use super::iter::{GIter};
#[derive(Clone)]
pub enum Val {
Nil,
Int(i32),
Flo(f32),
Char(char),
Bool(bool),
Sym(Sym),
Arr(Root<Arr>),
Str(Root<Str>),
Tab(Root<Tab>),
GIter(Root<GIter>),
Obj(Root<Obj>),
Class(Root<Class>),
GFn(Root<GFn>),
Coro(Root<Coro>),
RData(Root<RData>),
RFn(Root<RFn>),
}
impl Default for Val {
fn default() -> Val {
Val::Nil
}
}
macro_rules! impl_val {
($(($variant:ident, $type:ty, $type_name:literal, $a_type_name:literal, $is_type:ident,
$unwrap_type:ident)),+) => (
impl Val {
pub fn type_name(&self) -> &'static str {
match *self {
Val::Nil => "nil",
$(Val::$variant(_) => $type_name),+
}
}
pub fn a_type_name(&self) -> &'static str {
match *self {
Val::Nil => "a nil",
$(Val::$variant(_) => $a_type_name),+
}
}
}
impl Val {
$(
#[inline]
pub fn $is_type(&self) -> bool {
match *self {
Val::$variant(_) => true,
_ => false
}
}
#[inline]
pub fn $unwrap_type(self) -> $type {
match self {
Val::$variant(inner) => inner,
_ => panic!("attempted to unwrap {} Val as {}", self.a_type_name(),
$a_type_name)
}
}
)+
}
);
}
impl_val!(
(Int, i32, "int", "an int", is_int, unwrap_int),
(Flo, f32, "flo", "a flo", is_flo, unwrap_flo),
(Char, char, "char", "a char", is_char, unwrap_char),
(Bool, bool, "bool", "a bool", is_bool, unwrap_bool),
(Sym, Sym, "sym", "a sym", is_sym, unwrap_sym),
(Arr, Root<Arr>, "arr", "an arr", is_arr, unwrap_arr),
(Str, Root<Str>, "str", "a str", is_str, unwrap_str),
(Tab, Root<Tab>, "tab", "a tab", is_tab, unwrap_tab),
(GIter, Root<GIter>, "iter", "an iter", is_giter, unwrap_giter),
(Obj, Root<Obj>, "obj", "a obj", is_obj, unwrap_obj),
(Class, Root<Class>, "class", "a class", is_class, unwrap_class),
(GFn, Root<GFn>, "fn", "a fn", is_gfn, unwrap_gfn),
(Coro, Root<Coro>, "coro", "a coro", is_coro, unwrap_coro),
(RData, Root<RData>, "rdata", "an rdata", is_rdata, unwrap_rdata),
(RFn, Root<RFn>, "rfn", "an rfn", is_rfn, unwrap_rfn)
);
impl Val {
pub fn is_nil(&self) -> bool {
match *self {
Val::Nil => true,
_ => false
}
}
pub fn is_truthy(&self) -> bool {
match *self {
Val::Nil | Val::Bool(false) => false,
_ => true
}
}
pub fn is_falsy(&self) -> bool {
match *self {
Val::Nil | Val::Bool(false) => true,
_ => false
}
}
pub fn is_num(&self) -> bool {
matches!(*self, Val::Int(_) | Val::Flo(_))
}
pub fn is_deque(&self) -> bool {
matches!(*self, Val::Arr(_) | Val::Str(_))
}
pub fn is_callable(&self) -> bool {
matches!(*self, Val::GFn(_) | Val::RFn(_) | Val::Class(_))
}
pub fn is_expander(&self) -> bool {
matches!(*self, Val::GFn(_) | Val::RFn(_))
}
pub fn is_iterable(&self) -> bool {
matches!(*self, Val::Arr(_) | Val::Str(_) | Val::Tab(_) | Val::GIter(_) | Val::Coro(_))
}
pub fn shallow_clone(&self) -> GResult<Val> {
Ok(match *self {
Val::Nil => Val::Nil,
Val::Int(i) => Val::Int(i),
Val::Flo(f) => Val::Flo(f),
Val::Char(c) => Val::Char(c),
Val::Bool(b) => Val::Bool(b),
Val::Sym(s) => Val::Sym(s),
Val::Arr(ref arr) => Val::Arr(arr.shallow_clone()),
Val::Str(ref st) => Val::Str(st.shallow_clone()),
Val::Tab(ref tab) => Val::Tab(tab.shallow_clone()),
Val::GIter(ref giter) => Val::GIter(giter.shallow_clone()),
Val::Obj(ref root) => {
let val: Option<Val> = root.call_if_present(OP_CLONE_SYM, &())?;
match val {
Some(val) => val,
None => Val::Obj(root.clone())
}
}
Val::Class(ref root) => Val::Class(root.clone()),
Val::GFn(ref root) => Val::GFn(root.clone()),
Val::Coro(ref root) => Val::Coro(root.clone()),
Val::RData(ref root) => {
let val: Option<Val> = root.call_if_present(OP_CLONE_SYM, &())?;
match val {
Some(val) => val,
None => Val::RData(root.clone())
}
}
Val::RFn(ref root) => Val::RFn(root.clone()),
})
}
pub fn deep_clone(&self) -> GResult<Val> {
Ok(match *self {
Val::Nil => Val::Nil,
Val::Int(i) => Val::Int(i),
Val::Flo(f) => Val::Flo(f),
Val::Char(c) => Val::Char(c),
Val::Bool(b) => Val::Bool(b),
Val::Sym(s) => Val::Sym(s),
Val::Arr(ref arr) => Val::Arr(arr.deep_clone()?),
Val::Str(ref st) => Val::Str(st.shallow_clone()),
Val::Tab(ref tab) => Val::Tab(tab.deep_clone()?),
Val::GIter(ref giter) => Val::GIter(giter.shallow_clone()),
Val::Obj(ref root) => {
let mut val: Option<Val> = root.call_if_present(OP_DEEP_CLONE_SYM, &())?;
if val.is_none() {
val = root.call_if_present(OP_CLONE_SYM, &())?;
}
match val {
Some(val) => val,
None => Val::Obj(root.clone())
}
}
Val::Class(ref root) => Val::Class(root.clone()),
Val::GFn(ref root) => Val::GFn(root.clone()),
Val::Coro(ref root) => Val::Coro(root.clone()),
Val::RData(ref root) => {
let mut val: Option<Val> = root.call_if_present(OP_DEEP_CLONE_SYM, &())?;
if val.is_none() {
val = root.call_if_present(OP_CLONE_SYM, &())?;
}
match val {
Some(val) => val,
None => Val::RData(root.clone())
}
}
Val::RFn(ref root) => Val::RFn(root.clone())
})
}
pub fn freeze(&self) {
match *self {
Val::Arr(ref arr) => arr.freeze(),
Val::Str(ref st) => st.freeze(),
Val::Tab(ref tab) => tab.freeze(),
Val::Obj(ref obj) => obj.freeze(),
Val::Nil | Val::Int(_) | Val::Flo(_) | Val::Char(_) |
Val::Bool(_) | Val::Sym(_) | Val::GIter(_) | Val::RFn(_) |
Val::Class(_) | Val::GFn(_) | Val::Coro(_) | Val::RData(_) => ()
}
}
pub fn deep_freeze(&self) {
match *self {
Val::Arr(ref arr) => arr.deep_freeze(),
Val::Tab(ref tab) => tab.deep_freeze(),
Val::Str(ref st) => st.freeze(),
Val::Obj(ref obj) => {
obj.freeze()
}
Val::Nil | Val::Int(_) | Val::Flo(_) | Val::Char(_) |
Val::Bool(_) | Val::Sym(_) | Val::GIter(_) | Val::RFn(_) |
Val::Class(_) | Val::GFn(_) | Val::Coro(_) | Val::RData(_) => ()
}
}
pub(crate) fn is_deep_frozen(&self) -> bool {
match *self {
Val::Arr(ref arr) => arr.is_deep_frozen(),
Val::Str(ref st) => st.is_frozen(),
Val::Tab(ref tab) => tab.is_deep_frozen(),
Val::Nil | Val::Int(_) | Val::Flo(_) |
Val::Char(_) | Val::Bool(_) | Val::Sym(_) => true,
Val::Obj(_) | Val::RFn(_) | Val::Class(_) | Val::GIter(_) |
Val::GFn(_) | Val::Coro(_) | Val::RData(_) => unreachable!()
}
}
}
#[derive(Clone, Copy)]
pub enum Num {
Int(i32),
Flo(f32)
}
impl Num {
pub fn is_int(self) -> bool {
if let Num::Int(_) = self { true } else { false }
}
pub fn is_flo(self) -> bool {
if let Num::Flo(_) = self { true } else { false }
}
pub fn unwrap_int(self) -> i32 {
if let Num::Int(i) = self { i } else { panic!() }
}
pub fn unwrap_flo(self) -> f32 {
if let Num::Flo(f) = self { f } else { panic!() }
}
pub fn into_f32(self) -> f32 {
match self {
Num::Int(i) => i as f32,
Num::Flo(f) => f
}
}
pub fn abs(self) -> Num {
match self {
Num::Int(i) => Num::Int(i.wrapping_abs()),
Num::Flo(f) => Num::Flo(f.abs())
}
}
pub fn div_euclid(self, other: Num) -> Num {
match (self, other) {
(Num::Int(left), Num::Int(right)) => Num::Int(left.div_euclid(right)),
(Num::Flo(left), Num::Int(right)) => Num::Flo(left.div_euclid(right as f32)),
(Num::Int(left), Num::Flo(right)) => Num::Flo((left as f32).div_euclid(right)),
(Num::Flo(left), Num::Flo(right)) => Num::Flo(left.div_euclid(right))
}
}
pub fn wrapping_div_euclid(self, other: Num) -> Num {
match (self, other) {
(Num::Int(left), Num::Int(right)) => Num::Int(left.wrapping_div_euclid(right)),
(Num::Flo(left), Num::Int(right)) => Num::Flo(left.div_euclid(right as f32)),
(Num::Int(left), Num::Flo(right)) => Num::Flo((left as f32).div_euclid(right)),
(Num::Flo(left), Num::Flo(right)) => Num::Flo(left.div_euclid(right))
}
}
pub fn rem_euclid(self, other: Num) -> Num {
match (self, other) {
(Num::Int(left), Num::Int(right)) => Num::Int(left.rem_euclid(right)),
(Num::Flo(left), Num::Int(right)) => Num::Flo(left.rem_euclid(right as f32)),
(Num::Int(left), Num::Flo(right)) => Num::Flo((left as f32).rem_euclid(right)),
(Num::Flo(left), Num::Flo(right)) => Num::Flo(left.rem_euclid(right))
}
}
pub fn wrapping_rem_euclid(self, other: Num) -> Num {
match (self, other) {
(Num::Int(left), Num::Int(right)) => Num::Int(left.wrapping_rem_euclid(right)),
(Num::Flo(left), Num::Int(right)) => Num::Flo(left.rem_euclid(right as f32)),
(Num::Int(left), Num::Flo(right)) => Num::Flo((left as f32).rem_euclid(right)),
(Num::Flo(left), Num::Flo(right)) => Num::Flo(left.rem_euclid(right))
}
}
}
#[inline]
pub(crate) fn float_total_eq(a: f32, b: f32) -> bool {
(a.is_nan() && b.is_nan()) || a == b
}
pub(crate) fn float_total_cmp(a: f32, b: f32) -> Ordering {
match (a.is_nan(), b.is_nan()) {
(true, true) => Ordering::Equal,
(true, false) => Ordering::Greater,
(false, true) => Ordering::Less,
(false, false) => a.partial_cmp(&b).unwrap()
}
}
impl Default for Num {
fn default() -> Num {
Num::Int(0)
}
}
impl Debug for Num {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
match *self {
Num::Int(ref i) => Debug::fmt(i, formatter),
Num::Flo(ref f) => Debug::fmt(f, formatter),
}
}
}
impl Display for Num {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
match *self {
Num::Int(ref i) => Display::fmt(i, formatter),
Num::Flo(ref f) => Display::fmt(f, formatter),
}
}
}
impl PartialEq<Num> for Num {
fn eq(&self, other: &Num) -> bool {
match (*self, *other) {
(Num::Int(i0), Num::Int(i1)) => i0 == i1,
(Num::Int(i0), Num::Flo(f1)) => float_total_eq(i0 as f32, f1),
(Num::Flo(f0), Num::Int(i1)) => float_total_eq(f0, i1 as f32),
(Num::Flo(f0), Num::Flo(f1)) => float_total_eq(f0, f1)
}
}
}
impl Eq for Num { }
impl PartialEq<i32> for Num {
fn eq(&self, other: &i32) -> bool {
self.eq(&Num::Int(*other))
}
}
impl PartialEq<Num> for i32 {
fn eq(&self, other: &Num) -> bool {
Num::Int(*self).eq(other)
}
}
impl PartialEq<f32> for Num {
fn eq(&self, other: &f32) -> bool {
self.eq(&Num::Flo(*other))
}
}
impl PartialEq<Num> for f32 {
fn eq(&self, other: &Num) -> bool {
Num::Flo(*self).eq(other)
}
}
impl PartialOrd<Num> for Num {
fn partial_cmp(&self, other: &Num) -> Option<Ordering> {
match (*self, *other) {
(Num::Int(i0), Num::Int(i1)) => Some(i0.cmp(&i1)),
(Num::Int(i0), Num::Flo(f1)) => Some(float_total_cmp(i0 as f32, f1)),
(Num::Flo(f0), Num::Int(i1)) => Some(float_total_cmp(f0, i1 as f32)),
(Num::Flo(f0), Num::Flo(f1)) => Some(float_total_cmp(f0, f1))
}
}
}
impl Ord for Num {
fn cmp(&self, other: &Num) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialOrd<i32> for Num {
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
self.partial_cmp(&Num::Int(*other))
}
}
impl PartialOrd<Num> for i32 {
fn partial_cmp(&self, other: &Num) -> Option<Ordering> {
Num::Int(*self).partial_cmp(other)
}
}
impl PartialOrd<f32> for Num {
fn partial_cmp(&self, other: &f32) -> Option<Ordering> {
self.partial_cmp(&Num::Flo(*other))
}
}
impl PartialOrd<Num> for f32 {
fn partial_cmp(&self, other: &Num) -> Option<Ordering> {
Num::Flo(*self).partial_cmp(other)
}
}
impl Add for Num {
type Output = Num;
fn add(self, rhs: Num) -> Num {
match (self, rhs) {
(Num::Int(i0), Num::Int(i1)) => Num::Int(i0.wrapping_add(i1)),
(Num::Int(i0), Num::Flo(f1)) => Num::Flo(i0 as f32 + f1),
(Num::Flo(f0), Num::Int(i1)) => Num::Flo(f0 + i1 as f32),
(Num::Flo(f0), Num::Flo(f1)) => Num::Flo(f0 + f1)
}
}
}
impl Sub for Num {
type Output = Num;
fn sub(self, rhs: Num) -> Num {
match (self, rhs) {
(Num::Int(i0), Num::Int(i1)) => Num::Int(i0.wrapping_sub(i1)),
(Num::Int(i0), Num::Flo(f1)) => Num::Flo(i0 as f32 - f1),
(Num::Flo(f0), Num::Int(i1)) => Num::Flo(f0 - i1 as f32),
(Num::Flo(f0), Num::Flo(f1)) => Num::Flo(f0 - f1)
}
}
}
impl Mul for Num {
type Output = Num;
fn mul(self, rhs: Num) -> Num {
match (self, rhs) {
(Num::Int(i0), Num::Int(i1)) => Num::Int(i0.wrapping_mul(i1)),
(Num::Int(i0), Num::Flo(f1)) => Num::Flo(i0 as f32 * f1),
(Num::Flo(f0), Num::Int(i1)) => Num::Flo(f0 * i1 as f32),
(Num::Flo(f0), Num::Flo(f1)) => Num::Flo(f0 * f1)
}
}
}
impl Div for Num {
type Output = Num;
fn div(self, rhs: Num) -> Num {
match (self, rhs) {
(Num::Int(i0), Num::Int(i1)) => Num::Int(i0.wrapping_div(i1)),
(Num::Int(i0), Num::Flo(f1)) => Num::Flo(i0 as f32 / f1),
(Num::Flo(f0), Num::Int(i1)) => Num::Flo(f0 / i1 as f32),
(Num::Flo(f0), Num::Flo(f1)) => Num::Flo(f0 / f1)
}
}
}
impl Rem for Num {
type Output = Num;
fn rem(self, rhs: Num) -> Num {
match (self, rhs) {
(Num::Int(i0), Num::Int(i1)) => Num::Int(i0.wrapping_rem(i1)),
(Num::Int(i0), Num::Flo(f1)) => Num::Flo(i0 as f32 % f1),
(Num::Flo(f0), Num::Int(i1)) => Num::Flo(f0 % i1 as f32),
(Num::Flo(f0), Num::Flo(f1)) => Num::Flo(f0 % f1)
}
}
}
impl Neg for Num {
type Output = Num;
fn neg(self) -> Num {
match self {
Num::Int(i) => Num::Int(i.wrapping_neg()),
Num::Flo(f) => Num::Flo(-f)
}
}
}
impl Val {
#[inline]
pub fn num_eq(&self, other: &Val) -> Option<bool> {
match (self, other) {
(&Val::Int(i0), &Val::Int(i1)) => Some(i0 == i1),
(&Val::Flo(f0), &Val::Int(i1)) => Some(float_total_eq(f0, i1 as f32)),
(&Val::Char(c0), &Val::Int(i1)) => Some(c0 as u32 as i32 == i1),
(&Val::Int(i0), &Val::Flo(f1)) => Some(float_total_eq(i0 as f32, f1)),
(&Val::Flo(f0), &Val::Flo(f1)) => Some(float_total_eq(f0, f1)),
(&Val::Char(c0), &Val::Flo(f1)) => Some(float_total_eq(c0 as u32 as f32, f1)),
(&Val::Int(i0), &Val::Char(c1)) => Some(i0 == c1 as u32 as i32),
(&Val::Flo(f0), &Val::Char(c1)) => Some(float_total_eq(f0, c1 as u32 as f32)),
(&Val::Char(c0), &Val::Char(c1)) => Some(c0 == c1),
_ => None
}
}
pub fn same(&self, other: &Val) -> bool {
match (self, other) {
(&Val::Nil, &Val::Nil) => true,
(&Val::Int(_), &Val::Int(_)) => self.num_eq(other).unwrap(),
(&Val::Int(_), &Val::Flo(_)) => self.num_eq(other).unwrap(),
(&Val::Int(_), &Val::Char(_)) => self.num_eq(other).unwrap(),
(&Val::Flo(_), &Val::Int(_)) => self.num_eq(other).unwrap(),
(&Val::Flo(_), &Val::Flo(_)) => self.num_eq(other).unwrap(),
(&Val::Flo(_), &Val::Char(_)) => self.num_eq(other).unwrap(),
(&Val::Char(_), &Val::Int(_)) => self.num_eq(other).unwrap(),
(&Val::Char(_), &Val::Flo(_)) => self.num_eq(other).unwrap(),
(&Val::Char(_), &Val::Char(_)) => self.num_eq(other).unwrap(),
(&Val::Bool(b0), &Val::Bool(b1)) => b0 == b1,
(&Val::Sym(s0), &Val::Sym(s1)) => s0 == s1,
(&Val::Arr(ref root0), &Val::Arr(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::Str(ref root0), &Val::Str(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::Tab(ref root0), &Val::Tab(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::GIter(ref root0), &Val::GIter(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::Obj(ref root0), &Val::Obj(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::Class(ref root0), &Val::Class(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::GFn(ref root0), &Val::GFn(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::Coro(ref root0), &Val::Coro(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::RData(ref root0), &Val::RData(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::RFn(ref root0), &Val::RFn(ref root1)) => Root::ptr_eq(root0, root1),
_ => false
}
}
pub fn keys_eqv(&self, other: &Val) -> bool {
match (self, other) {
(&Val::Int(_), &Val::Flo(_)) => false,
(&Val::Int(_), &Val::Char(_)) => false,
(&Val::Flo(_), &Val::Int(_)) => false,
(&Val::Flo(_), &Val::Char(_)) => false,
(&Val::Char(_), &Val::Int(_)) => false,
(&Val::Char(_), &Val::Flo(_)) => false,
(&Val::Flo(f0), &Val::Flo(f1)) => {
match (f0.classify(), f1.classify()) {
(FpCategory::Nan, FpCategory::Nan) => true,
_ => f0 == f1
}
}
(&Val::Tab(ref root0), &Val::Tab(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::Obj(ref root0), &Val::Obj(ref root1)) => Root::ptr_eq(root0, root1),
(&Val::RData(ref root0), &Val::RData(ref root1)) => Root::ptr_eq(root0, root1),
_ => self.eq(other)
}
}
pub(crate) fn literal_eq(&self, other: &Val) -> bool {
match (self, other) {
(&Val::Tab(_), &Val::Tab(_)) => self.eq(other),
(&Val::Flo(f0), &Val::Flo(f1)) if f0 == 0.0 && f1 == 0.0 => false,
_ => self.keys_eqv(other)
}
}
pub fn try_eq(&self, other: &Val) -> GResult<bool> {
match (self, other) {
(&Val::Arr(ref a0), &Val::Arr(ref a1)) => a0.try_eq(a1),
(&Val::Str(ref s0), &Val::Str(ref s1)) => Ok(**s0 == **s1),
(&Val::Tab(ref t0), &Val::Tab(ref t1)) => t0.try_eq(t1),
(&Val::Obj(ref o0), &Val::Obj(ref o1)) => o0.try_eq(o1),
(&Val::RData(ref r0), &Val::RData(ref r1)) => r0.try_eq(r1),
_ => Ok(self.same(other))
}
}
}
impl PartialEq<Val> for Val {
fn eq(&self, other: &Val) -> bool {
match (self, other) {
(&Val::Arr(_), &Val::Arr(_)) => self.try_eq(other).unwrap(),
(&Val::Str(_), &Val::Str(_)) => self.try_eq(other).unwrap(),
(&Val::Tab(_), &Val::Tab(_)) => self.try_eq(other).unwrap(),
(&Val::Obj(_), &Val::Obj(_)) => self.try_eq(other).unwrap(),
(&Val::RData(_), &Val::RData(_)) => self.try_eq(other).unwrap(),
_ => self.same(other)
}
}
}
impl Eq for Val { }
impl PartialOrd<Val> for Val {
fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
match (self, other) {
(&Val::Int(i0), &Val::Int(i1)) => Some(i0.cmp(&i1)),
(&Val::Flo(f0), &Val::Int(i1)) => Some(float_total_cmp(f0, i1 as f32)),
(&Val::Int(i0), &Val::Flo(f1)) => Some(float_total_cmp(i0 as f32, f1)),
(&Val::Flo(f0), &Val::Flo(f1)) => Some(float_total_cmp(f0, f1)),
(&Val::Char(c0), &Val::Int(i1)) => Some((c0 as i32).cmp(&i1)),
(&Val::Char(c0), &Val::Flo(f1)) => Some(float_total_cmp(c0 as u32 as f32, f1)),
(&Val::Int(i0), &Val::Char(c1)) => Some(i0.cmp(&(c1 as i32))),
(&Val::Flo(f0), &Val::Char(c1)) => Some(float_total_cmp(f0, c1 as u32 as f32)),
(&Val::Char(c0), &Val::Char(c1)) => Some(c0.cmp(&c1)),
(&Val::Char(c0), &Val::Sym(s1)) => Some(once(c0).cmp(s1.name().chars())),
(&Val::Char(c0), &Val::Str(ref s1)) => Some(once(c0).cmp(s1.iter())),
(&Val::Str(ref s0), &Val::Char(c1)) => Some(s0.iter().cmp(once(c1))),
(&Val::Str(ref s0), &Val::Sym(s1)) => Some(s0.iter().cmp(s1.name().chars())),
(&Val::Str(ref s0), &Val::Str(ref s1)) => Some(s0.cmp(s1)),
(&Val::Sym(s0), &Val::Str(ref s1)) => Some(s0.name().chars().cmp(s1.iter())),
(&Val::Sym(s0), &Val::Char(c1)) => Some(s0.name().chars().cmp(once(c1))),
(&Val::Sym(s0), &Val::Sym(s1)) => Some(s0.cmp(&s1)),
(&Val::Arr(ref a0), &Val::Arr(ref a1)) => a0.partial_cmp(a1),
_ => None
}
}
}
#[doc(hidden)]
#[derive(Clone)]
pub struct Hashable(pub Val);
impl PartialEq<Hashable> for Hashable {
fn eq(&self, other: &Hashable) -> bool {
self.0.keys_eqv(&other.0)
}
}
impl Eq for Hashable { }
impl Hash for Hashable {
fn hash<H: Hasher>(&self, state: &mut H) {
match self.0 {
Val::Nil => 0u8.hash(state),
Val::Int(i) => i.hash(state),
Val::Flo(f) => {
match f.classify() {
FpCategory::Zero => 0u8.hash(state),
FpCategory::Infinite => {
if f > 0.0 { 1u8.hash(state) } else { 2u8.hash(state) }
}
FpCategory::Nan => 3u8.hash(state),
FpCategory::Normal | FpCategory::Subnormal => {
f.to_bits().hash(state)
}
}
}
Val::Bool(b) => b.hash(state),
Val::Char(c) => c.hash(state),
Val::Sym(s) => s.hash(state),
Val::Arr(ref arr) => (**arr).hash(state),
Val::Str(ref st) => (**st).hash(state),
Val::Tab(ref root) => (&**root as *const _ as usize).hash(state),
Val::GIter(ref root) => (&**root as *const _ as usize).hash(state),
Val::Obj(ref root) => (&**root as *const _ as usize).hash(state),
Val::Class(ref root) => (&**root as *const _ as usize).hash(state),
Val::GFn(ref root) => (&**root as *const _ as usize).hash(state),
Val::Coro(ref root) => (&**root as *const _ as usize).hash(state),
Val::RData(ref root) => (&**root as *const _ as usize).hash(state),
Val::RFn(ref root) => (&**root as *const _ as usize).hash(state)
}
}
}