use std::{
cmp::Ordering,
fmt::{self, Display},
hash::Hasher,
};
use gazebo::any::AnyLifetime;
use serde::Serialize;
use crate::{
collections::{StarlarkHashValue, StarlarkHasher},
values::{
basic::StarlarkValueBasic, AllocFrozenValue, AllocValue, FrozenHeap, FrozenValue, Heap,
StarlarkValue, UnpackValue, Value, ValueError,
},
};
pub const BOOL_TYPE: &str = "bool";
#[derive(AnyLifetime, Debug, Serialize)]
#[serde(transparent)]
pub(crate) struct StarlarkBool(pub(crate) bool);
impl Display for StarlarkBool {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 {
write!(f, "True")
} else {
write!(f, "False")
}
}
}
impl<'v> AllocValue<'v> for bool {
fn alloc_value(self, _heap: &'v Heap) -> Value<'v> {
Value::new_bool(self)
}
}
impl AllocFrozenValue for bool {
fn alloc_frozen_value(self, _heap: &FrozenHeap) -> FrozenValue {
FrozenValue::new_bool(self)
}
}
impl UnpackValue<'_> for bool {
fn expected() -> String {
"bool".to_owned()
}
fn unpack_value(value: Value) -> Option<Self> {
value.unpack_bool()
}
}
impl StarlarkValue<'_> for StarlarkBool {
starlark_type!(BOOL_TYPE);
fn is_special() -> bool
where
Self: Sized,
{
true
}
fn collect_repr(&self, s: &mut String) {
if self.0 {
s.push_str("True")
} else {
s.push_str("False")
}
}
fn to_int(&self) -> anyhow::Result<i32> {
Ok(if self.0 { 1 } else { 0 })
}
fn to_bool(&self) -> bool {
self.0
}
fn write_hash(&self, hasher: &mut StarlarkHasher) -> anyhow::Result<()> {
hasher.write_u8(if self.0 { 1 } else { 0 });
Ok(())
}
fn equals(&self, other: Value) -> anyhow::Result<bool> {
debug_assert!(!matches!(other.unpack_bool(), Some(other) if other == self.0));
Ok(false)
}
fn compare(&self, other: Value) -> anyhow::Result<Ordering> {
if let Some(other) = other.unpack_bool() {
Ok(self.0.cmp(&other))
} else {
ValueError::unsupported_with(self, "<>", other)
}
}
}
impl<'v> StarlarkValueBasic<'v> for StarlarkBool {
fn get_hash(&self) -> StarlarkHashValue {
StarlarkHashValue::new_unchecked(if self.0 { 0xa4acba08 } else { 0x71e8ba71 })
}
}