use std::cmp::Ordering;
use super::{PAYLOAD_SHIFT, TAG_MASK};
use crate::value::{BoolMut, Destructured, DestructuredMut, DestructuredRef, IValue, ValueType};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(usize)]
pub(crate) enum Constant {
Null = 1,
False = 2,
True = 3,
}
pub(crate) struct ConstantRepr;
impl ConstantRepr {
const fn encode(c: Constant) -> usize {
let bits = (c as usize) << PAYLOAD_SHIFT;
debug_assert!(
bits & TAG_MASK == 0,
"inline constant must leave the tag bits clear"
);
bits
}
fn decode(bits: usize) -> Constant {
let discriminant = (bits >> PAYLOAD_SHIFT) & 0b11;
debug_assert!(
(1..=3).contains(&discriminant),
"only the three constants are ever encoded"
);
if discriminant == Constant::Null as usize {
Constant::Null
} else if discriminant == Constant::False as usize {
Constant::False
} else {
Constant::True
}
}
}
pub(crate) const NULL: usize = ConstantRepr::encode(Constant::Null);
pub(crate) const FALSE: usize = ConstantRepr::encode(Constant::False);
pub(crate) const TRUE: usize = ConstantRepr::encode(Constant::True);
impl super::InlineValue for ConstantRepr {
fn value_type(&self, v: &IValue) -> ValueType {
match Self::decode(v.usize_()) {
Constant::Null => ValueType::Null,
Constant::False | Constant::True => ValueType::Bool,
}
}
unsafe fn partial_cmp(&self, a: &IValue, b: &IValue) -> Option<Ordering> {
Some(Self::decode(a.usize_()).cmp(&Self::decode(b.usize_())))
}
unsafe fn debug(&self, v: &IValue, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match Self::decode(v.usize_()) {
Constant::Null => "null",
Constant::False => "false",
Constant::True => "true",
})
}
fn destructure(&self, v: IValue) -> Destructured {
match Self::decode(v.usize_()) {
Constant::Null => Destructured::Null,
Constant::False => Destructured::Bool(false),
Constant::True => Destructured::Bool(true),
}
}
unsafe fn destructure_ref<'a>(&self, v: &'a IValue) -> DestructuredRef<'a> {
match Self::decode(v.usize_()) {
Constant::Null => DestructuredRef::Null,
Constant::False => DestructuredRef::Bool(false),
Constant::True => DestructuredRef::Bool(true),
}
}
unsafe fn destructure_mut<'a>(&self, v: &'a mut IValue) -> DestructuredMut<'a> {
match Self::decode(v.usize_()) {
Constant::Null => DestructuredMut::Null,
Constant::False | Constant::True => DestructuredMut::Bool(BoolMut(v)),
}
}
}