diff options
Diffstat (limited to 'crates/typst-library/src/foundations/none.rs')
| -rw-r--r-- | crates/typst-library/src/foundations/none.rs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/crates/typst-library/src/foundations/none.rs b/crates/typst-library/src/foundations/none.rs new file mode 100644 index 00000000..d376c0c5 --- /dev/null +++ b/crates/typst-library/src/foundations/none.rs @@ -0,0 +1,114 @@ +use std::fmt::{self, Debug, Formatter}; + +use ecow::EcoString; +use serde::{Serialize, Serializer}; + +use crate::diag::HintedStrResult; +use crate::foundations::{ + cast, ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value, +}; + +/// A value that indicates the absence of any other value. +/// +/// The none type has exactly one value: `{none}`. +/// +/// When inserted into the document, it is not visible. This is also the value +/// that is produced by empty code blocks. It can be +/// [joined]($scripting/#blocks) with any value, yielding the other value. +/// +/// # Example +/// ```example +/// Not visible: #none +/// ``` +#[ty(cast, name = "none")] +#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct NoneValue; + +impl Reflect for NoneValue { + fn input() -> CastInfo { + CastInfo::Type(Type::of::<Self>()) + } + + fn output() -> CastInfo { + CastInfo::Type(Type::of::<Self>()) + } + + fn castable(value: &Value) -> bool { + matches!(value, Value::None) + } +} + +impl IntoValue for NoneValue { + fn into_value(self) -> Value { + Value::None + } +} + +impl FromValue for NoneValue { + fn from_value(value: Value) -> HintedStrResult<Self> { + match value { + Value::None => Ok(Self), + _ => Err(Self::error(&value)), + } + } +} + +impl Debug for NoneValue { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.pad("None") + } +} + +impl Repr for NoneValue { + fn repr(&self) -> EcoString { + "none".into() + } +} + +impl Serialize for NoneValue { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_none() + } +} + +cast! { + (), + self => Value::None, + _: NoneValue => (), +} + +impl<T: Reflect> Reflect for Option<T> { + fn input() -> CastInfo { + T::input() + NoneValue::input() + } + + fn output() -> CastInfo { + T::output() + NoneValue::output() + } + + fn castable(value: &Value) -> bool { + NoneValue::castable(value) || T::castable(value) + } +} + +impl<T: IntoValue> IntoValue for Option<T> { + fn into_value(self) -> Value { + match self { + Some(v) => v.into_value(), + None => Value::None, + } + } +} + +impl<T: FromValue> FromValue for Option<T> { + fn from_value(value: Value) -> HintedStrResult<Self> { + match value { + Value::None => Ok(None), + v if T::castable(&v) => Ok(Some(T::from_value(v)?)), + _ => Err(Self::error(&value)), + } + } +} |
