summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/foundations/none.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-10-27 19:04:55 +0100
committerGitHub <noreply@github.com>2024-10-27 18:04:55 +0000
commitbe7cfc85d08c545abfac08098b7b33b4bd71f37e (patch)
treef4137fa2aaa57babae1f7603a9b2ed7e688f43d8 /crates/typst-library/src/foundations/none.rs
parentb8034a343831e8609aec2ec81eb7eeda57aa5d81 (diff)
Split out four new crates (#5302)
Diffstat (limited to 'crates/typst-library/src/foundations/none.rs')
-rw-r--r--crates/typst-library/src/foundations/none.rs114
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)),
+ }
+ }
+}