#![allow(clippy::module_name_repetitions)]
use std::{hash, ptr::NonNull};
#[cfg(feature = "types")]
use crate::types::Type;
use crate::{mem::Slot, value::SmartString};
use super::{ByteVector, Pair, ValueTag, Vector};
#[derive(Debug)]
pub enum ValueKind<'a> {
Nil,
Bool(bool),
Char(char),
Integer(i64),
Float(f64),
Pair(bool, NonNull<Slot<Pair<'a>>>),
String(bool, NonNull<Slot<SmartString>>),
Symbol(bool, NonNull<Slot<Box<str>>>),
Bytevec(bool, NonNull<Slot<ByteVector>>),
Vector(bool, NonNull<Slot<Vector<'a>>>),
#[cfg(feature = "types")]
#[cfg_attr(docsrs, doc(cfg(feature = "types")))]
Type(bool, NonNull<Slot<Type>>),
}
impl<'a> ValueKind<'a> {
pub(super) const fn new_clone(&self) -> Self {
match self {
Self::Nil => Self::Nil,
Self::Bool(value) => Self::Bool(*value),
Self::Char(value) => Self::Char(*value),
Self::Integer(value) => Self::Integer(*value),
Self::Float(value) => Self::Float(*value),
Self::Pair(_, ptr) => Self::Pair(false, *ptr),
Self::String(_, ptr) => Self::String(false, *ptr),
Self::Symbol(_, ptr) => Self::Symbol(false, *ptr),
Self::Bytevec(_, ptr) => Self::Bytevec(false, *ptr),
Self::Vector(_, ptr) => Self::Vector(false, *ptr),
#[cfg(feature = "types")]
Self::Type(_, ptr) => Self::Type(false, *ptr),
}
}
}
impl<'a> hash::Hash for ValueKind<'a> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match self {
Self::Nil => ValueTag::Nil.hash(state),
Self::Bool(value) => {
ValueTag::Bool.hash(state);
value.hash(state);
}
Self::Char(value) => {
ValueTag::Char.hash(state);
value.hash(state);
}
Self::Integer(value) => {
ValueTag::Int.hash(state);
value.hash(state);
}
Self::Float(value) => {
ValueTag::Float.hash(state);
value.to_bits().hash(state);
}
Self::Pair(_, ptr) => {
ValueTag::Pair.hash(state);
ptr.hash(state);
}
Self::String(_, ptr) => {
ValueTag::String.hash(state);
ptr.hash(state);
}
Self::Symbol(_, ptr) => {
ValueTag::Symbol.hash(state);
ptr.hash(state);
}
Self::Bytevec(_, ptr) => {
ValueTag::Bytevec.hash(state);
ptr.hash(state);
}
Self::Vector(_, ptr) => {
ValueTag::Vector.hash(state);
ptr.hash(state);
}
#[cfg(feature = "types")]
Self::Type(_, ptr) => {
ValueTag::Type.hash(state);
ptr.hash(state);
}
}
}
}
impl<'a> PartialEq for ValueKind<'a> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Nil, Self::Nil) => true,
(Self::Bool(a), Self::Bool(b)) => *a == *b,
(Self::Char(a), Self::Char(b)) => *a == *b,
(Self::Integer(a), Self::Integer(b)) => *a == *b,
(Self::Float(a), Self::Float(b)) => {
if a.is_nan() && b.is_nan() {
true
} else {
*a == *b
}
}
(Self::Pair(_, a), Self::Pair(_, b)) => {
if a == b {
true
} else {
let a = unsafe { a.as_ref() };
let b = unsafe { b.as_ref() };
a == b
}
}
(Self::String(_, a), Self::String(_, b)) => {
if a == b {
true
} else {
let a = unsafe { a.as_ref() };
let b = unsafe { b.as_ref() };
a == b
}
}
(Self::Symbol(_, a), Self::Symbol(_, b)) => {
if a == b {
true
} else {
let a = unsafe { a.as_ref() };
let b = unsafe { b.as_ref() };
a == b
}
}
(Self::Bytevec(_, a), Self::Bytevec(_, b)) => {
if a == b {
true
} else {
let a = unsafe { a.as_ref() };
let b = unsafe { b.as_ref() };
a == b
}
}
(Self::Vector(_, a), Self::Vector(_, b)) => {
if a == b {
true
} else {
let a = unsafe { a.as_ref() };
let b = unsafe { b.as_ref() };
a == b
}
}
#[cfg(feature = "types")]
(Self::Type(_, a), Self::Type(_, b)) => {
if a == b {
true
} else {
let a = unsafe { a.as_ref() };
let b = unsafe { b.as_ref() };
a == b
}
}
_ => false,
}
}
}