use std::hash::Hasher;
use derive_more::Display;
use gazebo::{any::AnyLifetime, prelude::*};
use serde::{Serialize, Serializer};
use crate::{
collections::{StarlarkHashValue, StarlarkHasher},
values::{
basic::StarlarkValueBasic, AllocFrozenValue, AllocValue, FrozenHeap, FrozenValue, Heap,
StarlarkValue, UnpackValue, Value,
},
};
#[derive(Debug, Clone, Dupe, AnyLifetime, Display)]
#[display(fmt = "None")]
pub struct NoneType;
impl NoneType {
pub const TYPE: &'static str = "NoneType";
}
impl<'v> StarlarkValue<'v> for NoneType {
starlark_type!(NoneType::TYPE);
fn is_special() -> bool
where
Self: Sized,
{
true
}
fn equals(&self, other: Value) -> anyhow::Result<bool> {
debug_assert!(!other.is_none());
Ok(false)
}
fn to_bool(&self) -> bool {
false
}
fn write_hash(&self, hasher: &mut StarlarkHasher) -> anyhow::Result<()> {
hasher.write_u64(9_223_380_832_852_120_682);
Ok(())
}
}
impl<'v> StarlarkValueBasic<'v> for NoneType {
fn get_hash(&self) -> StarlarkHashValue {
StarlarkHashValue::new_unchecked(0xf9c2263d)
}
}
impl<'v> AllocValue<'v> for NoneType {
fn alloc_value(self, _heap: &'v Heap) -> Value<'v> {
Value::new_none()
}
}
impl Serialize for NoneType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_none()
}
}
impl AllocFrozenValue for NoneType {
fn alloc_frozen_value(self, _heap: &FrozenHeap) -> FrozenValue {
FrozenValue::new_none()
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Dupe)]
pub enum NoneOr<T> {
None,
Other(T),
}
impl<T> NoneOr<T> {
pub fn into_option(self) -> Option<T> {
match self {
Self::None => None,
Self::Other(x) => Some(x),
}
}
pub fn is_none(&self) -> bool {
matches!(self, NoneOr::None)
}
}
impl<'v, T: UnpackValue<'v>> UnpackValue<'v> for NoneOr<T> {
fn expected() -> String {
format!("None or {}", T::expected())
}
fn unpack_value(value: Value<'v>) -> Option<Self> {
if value.is_none() {
Some(NoneOr::None)
} else {
T::unpack_value(value).map(NoneOr::Other)
}
}
}