typst_library/foundations/
auto.rs1use std::fmt::{self, Debug, Formatter};
2
3use ecow::EcoString;
4
5use crate::diag::HintedStrResult;
6use crate::foundations::{
7 CastInfo, Fold, FromValue, IntoValue, Reflect, Repr, Resolve, StyleChain, Type,
8 Value, ty,
9};
10
11#[ty(cast, name = "auto")]
20#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
21pub struct AutoValue;
22
23impl IntoValue for AutoValue {
24 fn into_value(self) -> Value {
25 Value::Auto
26 }
27}
28
29impl FromValue for AutoValue {
30 fn from_value(value: Value) -> HintedStrResult<Self> {
31 match value {
32 Value::Auto => Ok(Self),
33 _ => Err(Self::error(&value)),
34 }
35 }
36}
37
38impl Reflect for AutoValue {
39 fn input() -> CastInfo {
40 CastInfo::Type(Type::of::<Self>())
41 }
42
43 fn output() -> CastInfo {
44 CastInfo::Type(Type::of::<Self>())
45 }
46
47 fn castable(value: &Value) -> bool {
48 matches!(value, Value::Auto)
49 }
50}
51
52impl Debug for AutoValue {
53 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
54 f.write_str("Auto")
55 }
56}
57
58impl Repr for AutoValue {
59 fn repr(&self) -> EcoString {
60 "auto".into()
61 }
62}
63
64#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
66pub enum Smart<T> {
67 Auto,
69 Custom(T),
71}
72
73impl<T> Smart<T> {
74 pub fn is_auto(&self) -> bool {
76 matches!(self, Self::Auto)
77 }
78
79 pub fn is_custom(&self) -> bool {
81 matches!(self, Self::Custom(_))
82 }
83
84 pub fn is_custom_and<F>(self, f: F) -> bool
86 where
87 F: Fn(T) -> bool,
88 {
89 match self {
90 Self::Auto => false,
91 Self::Custom(x) => f(x),
92 }
93 }
94
95 pub fn as_ref(&self) -> Smart<&T> {
97 match self {
98 Smart::Auto => Smart::Auto,
99 Smart::Custom(v) => Smart::Custom(v),
100 }
101 }
102
103 pub fn custom(self) -> Option<T> {
109 match self {
110 Self::Auto => None,
111 Self::Custom(x) => Some(x),
112 }
113 }
114
115 pub fn map<F, U>(self, f: F) -> Smart<U>
117 where
118 F: FnOnce(T) -> U,
119 {
120 match self {
121 Self::Auto => Smart::Auto,
122 Self::Custom(x) => Smart::Custom(f(x)),
123 }
124 }
125
126 pub fn map_or<F, U>(self, default: U, f: F) -> U
129 where
130 F: FnOnce(T) -> U,
131 {
132 match self {
133 Self::Auto => default,
134 Self::Custom(x) => f(x),
135 }
136 }
137
138 pub fn or(self, other: Smart<T>) -> Self {
140 match self {
141 Self::Custom(x) => Self::Custom(x),
142 Self::Auto => other,
143 }
144 }
145
146 pub fn or_else<F>(self, f: F) -> Self
149 where
150 F: FnOnce() -> Self,
151 {
152 match self {
153 Self::Custom(x) => Self::Custom(x),
154 Self::Auto => f(),
155 }
156 }
157
158 pub fn and_then<F, U>(self, f: F) -> Smart<U>
161 where
162 F: FnOnce(T) -> Smart<U>,
163 {
164 match self {
165 Smart::Auto => Smart::Auto,
166 Smart::Custom(x) => f(x),
167 }
168 }
169
170 pub fn unwrap_or(self, default: T) -> T {
172 match self {
173 Self::Auto => default,
174 Self::Custom(x) => x,
175 }
176 }
177
178 pub fn unwrap_or_else<F>(self, f: F) -> T
180 where
181 F: FnOnce() -> T,
182 {
183 match self {
184 Self::Auto => f(),
185 Self::Custom(x) => x,
186 }
187 }
188
189 pub fn unwrap_or_default(self) -> T
191 where
192 T: Default,
193 {
194 #[allow(clippy::unwrap_or_default)]
196 self.unwrap_or_else(T::default)
197 }
198}
199
200impl<T> Smart<Smart<T>> {
201 pub fn flatten(self) -> Smart<T> {
203 match self {
204 Smart::Custom(Smart::Auto) | Smart::Auto => Smart::Auto,
205 Smart::Custom(Smart::Custom(v)) => Smart::Custom(v),
206 }
207 }
208}
209
210impl<T> Default for Smart<T> {
211 fn default() -> Self {
212 Self::Auto
213 }
214}
215
216impl<T> From<Option<T>> for Smart<T> {
217 fn from(value: Option<T>) -> Self {
218 match value {
219 Some(v) => Smart::Custom(v),
220 None => Smart::Auto,
221 }
222 }
223}
224
225impl<T: Reflect> Reflect for Smart<T> {
226 fn input() -> CastInfo {
227 T::input() + AutoValue::input()
228 }
229
230 fn output() -> CastInfo {
231 T::output() + AutoValue::output()
232 }
233
234 fn castable(value: &Value) -> bool {
235 AutoValue::castable(value) || T::castable(value)
236 }
237}
238
239impl<T: IntoValue> IntoValue for Smart<T> {
240 fn into_value(self) -> Value {
241 match self {
242 Smart::Custom(v) => v.into_value(),
243 Smart::Auto => Value::Auto,
244 }
245 }
246}
247
248impl<T: FromValue> FromValue for Smart<T> {
249 fn from_value(value: Value) -> HintedStrResult<Self> {
250 match value {
251 Value::Auto => Ok(Self::Auto),
252 v if T::castable(&v) => Ok(Self::Custom(T::from_value(v)?)),
253 _ => Err(Self::error(&value)),
254 }
255 }
256}
257
258impl<T: Resolve> Resolve for Smart<T> {
259 type Output = Smart<T::Output>;
260
261 fn resolve(self, styles: StyleChain) -> Self::Output {
262 self.map(|v| v.resolve(styles))
263 }
264}
265
266impl<T: Fold> Fold for Smart<T> {
267 fn fold(self, outer: Self) -> Self {
268 use Smart::Custom;
269 match (self, outer) {
270 (Custom(inner), Custom(outer)) => Custom(inner.fold(outer)),
271 (inner, _) => inner,
274 }
275 }
276}