jsonld_syntax/
nullable.rs1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
5#[error("nullable value was null")]
6pub struct NullError;
7
8#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
16pub enum Nullable<T> {
17 Null,
19
20 Some(T),
22}
23
24impl<T> Nullable<T> {
25 #[inline(always)]
27 pub fn is_null(&self) -> bool {
28 matches!(self, Nullable::Null)
29 }
30
31 #[inline(always)]
33 pub fn is_some(&self) -> bool {
34 matches!(self, Nullable::Some(_))
35 }
36
37 #[inline(always)]
43 pub fn try_unwrap(self) -> Result<T, NullError> {
44 match self {
45 Nullable::Some(t) => Ok(t),
46 Nullable::Null => Err(NullError),
47 }
48 }
49
50 #[inline(always)]
52 pub fn as_ref(&self) -> Nullable<&T> {
53 match self {
54 Nullable::Null => Nullable::Null,
55 Nullable::Some(t) => Nullable::Some(t),
56 }
57 }
58
59 pub fn as_deref(&self) -> Nullable<&T::Target>
62 where
63 T: std::ops::Deref,
64 {
65 match self {
66 Self::Null => Nullable::Null,
67 Self::Some(t) => Nullable::Some(t),
68 }
69 }
70
71 #[inline(always)]
73 pub fn option(self) -> Option<T> {
74 match self {
75 Nullable::Null => None,
76 Nullable::Some(t) => Some(t),
77 }
78 }
79
80 #[inline(always)]
82 pub fn map<F, U>(self, f: F) -> Nullable<U>
83 where
84 F: FnOnce(T) -> U,
85 {
86 match self {
87 Nullable::Null => Nullable::Null,
88 Nullable::Some(t) => Nullable::Some(f(t)),
89 }
90 }
91
92 pub fn cast<U>(self) -> Nullable<U>
94 where
95 T: Into<U>,
96 {
97 match self {
98 Self::Null => Nullable::Null,
99 Self::Some(t) => Nullable::Some(t.into()),
100 }
101 }
102
103 pub fn unwrap_or(self, default: T) -> T {
105 match self {
106 Self::Null => default,
107 Self::Some(t) => t,
108 }
109 }
110
111 pub fn unwrap_or_default(self) -> T
113 where
114 T: Default,
115 {
116 match self {
117 Self::Null => T::default(),
118 Self::Some(t) => t,
119 }
120 }
121}
122
123impl<T> From<T> for Nullable<T> {
124 fn from(value: T) -> Self {
125 Self::Some(value)
126 }
127}
128
129impl<T> From<Option<T>> for Nullable<T> {
130 fn from(value: Option<T>) -> Self {
131 match value {
132 Some(t) => Self::Some(t),
133 None => Self::Null,
134 }
135 }
136}
137
138impl<T: Clone> Nullable<&T> {
139 #[inline(always)]
141 #[must_use]
142 pub fn cloned(&self) -> Nullable<T> {
143 match self {
144 Nullable::Null => Nullable::Null,
145 Nullable::Some(t) => Nullable::Some((*t).clone()),
146 }
147 }
148}
149
150impl<T: fmt::Display> fmt::Display for Nullable<T> {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 match self {
153 Self::Null => write!(f, "null"),
154 Self::Some(v) => v.fmt(f),
155 }
156 }
157}
158
159impl<T: contextual::DisplayWithContext<V>, V> contextual::DisplayWithContext<V> for Nullable<T> {
160 fn fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
161 match self {
162 Self::Null => write!(f, "null"),
163 Self::Some(v) => v.fmt_with(vocabulary, f),
164 }
165 }
166}
167
168#[cfg(feature = "serde")]
169impl<T: serde::Serialize> serde::Serialize for Nullable<T> {
170 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171 where
172 S: serde::Serializer,
173 {
174 match self {
175 Self::Null => serializer.serialize_none(),
176 Self::Some(t) => serializer.serialize_some(t),
177 }
178 }
179}
180
181#[cfg(feature = "serde")]
182impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Nullable<T> {
183 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
184 where
185 D: serde::Deserializer<'de>,
186 {
187 Ok(Option::<T>::deserialize(deserializer)?.into())
188 }
189}
190
191#[cfg(feature = "serde")]
192impl<T> Nullable<T> {
193 pub fn optional<'de, D>(deserializer: D) -> Result<Option<Self>, D::Error>
205 where
206 T: serde::Deserialize<'de>,
207 D: serde::Deserializer<'de>,
208 {
209 use serde::Deserialize;
210 Ok(Some(Option::<T>::deserialize(deserializer)?.into()))
211 }
212}