Skip to main content

typst_library/foundations/
none.rs

1use std::fmt::{self, Debug, Formatter};
2
3use ecow::EcoString;
4use serde::{Serialize, Serializer};
5
6use crate::diag::HintedStrResult;
7use crate::foundations::{
8    CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value, cast, ty,
9};
10
11/// A value that indicates the absence of any other value.
12///
13/// The none type has exactly one value: `{none}`.
14///
15/// When inserted into the document, it is not visible. This is also the value
16/// that is produced by empty code blocks. It can be
17/// @reference:scripting:blocks[joined] with any value, yielding the other
18/// value.
19///
20/// = Example <example>
21/// ```example
22/// Not visible: #none
23/// ```
24#[ty(cast, name = "none")]
25#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
26pub struct NoneValue;
27
28impl Reflect for NoneValue {
29    fn input() -> CastInfo {
30        CastInfo::Type(Type::of::<Self>())
31    }
32
33    fn output() -> CastInfo {
34        CastInfo::Type(Type::of::<Self>())
35    }
36
37    fn castable(value: &Value) -> bool {
38        matches!(value, Value::None)
39    }
40}
41
42impl IntoValue for NoneValue {
43    fn into_value(self) -> Value {
44        Value::None
45    }
46}
47
48impl FromValue for NoneValue {
49    fn from_value(value: Value) -> HintedStrResult<Self> {
50        match value {
51            Value::None => Ok(Self),
52            _ => Err(Self::error(&value)),
53        }
54    }
55}
56
57impl Debug for NoneValue {
58    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59        f.pad("None")
60    }
61}
62
63impl Repr for NoneValue {
64    fn repr(&self) -> EcoString {
65        "none".into()
66    }
67}
68
69impl Serialize for NoneValue {
70    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71    where
72        S: Serializer,
73    {
74        serializer.serialize_none()
75    }
76}
77
78cast! {
79    (),
80    self => Value::None,
81    _: NoneValue => (),
82}
83
84impl<T: Reflect> Reflect for Option<T> {
85    fn input() -> CastInfo {
86        T::input() + NoneValue::input()
87    }
88
89    fn output() -> CastInfo {
90        T::output() + NoneValue::output()
91    }
92
93    fn castable(value: &Value) -> bool {
94        NoneValue::castable(value) || T::castable(value)
95    }
96}
97
98impl<T: IntoValue> IntoValue for Option<T> {
99    fn into_value(self) -> Value {
100        match self {
101            Some(v) => v.into_value(),
102            None => Value::None,
103        }
104    }
105}
106
107impl<T: FromValue> FromValue for Option<T> {
108    fn from_value(value: Value) -> HintedStrResult<Self> {
109        match value {
110            Value::None => Ok(None),
111            v if T::castable(&v) => Ok(Some(T::from_value(v)?)),
112            _ => Err(Self::error(&value)),
113        }
114    }
115}
116
117impl<T: Repr> Repr for Option<T> {
118    fn repr(&self) -> EcoString {
119        match self {
120            Some(r) => r.repr(),
121            None => NoneValue.repr(),
122        }
123    }
124}