1use std::cmp::Ordering;
4
5use ecow::eco_format;
6use typst_utils::Numeric;
7
8use crate::diag::{HintedStrResult, StrResult, bail};
9use crate::foundations::{
10 Datetime, IntoValue, Regex, Repr, SymbolElem, Value, format_str,
11};
12use crate::layout::{Alignment, Length, Rel};
13use crate::text::TextElem;
14use crate::visualize::Stroke;
15
16macro_rules! mismatch {
18 ($fmt:expr, $($value:expr),* $(,)?) => {
19 return Err(eco_format!($fmt, $($value.ty()),*).into())
20 };
21}
22
23pub fn join(lhs: Value, rhs: Value) -> StrResult<Value> {
25 use Value::*;
26 Ok(match (lhs, rhs) {
27 (a, None) => a,
28 (None, b) => b,
29 (Symbol(a), Symbol(b)) => Str(format_str!("{a}{b}")),
30 (Str(a), Str(b)) => Str(a + b),
31 (Str(a), Symbol(b)) => Str(format_str!("{a}{b}")),
32 (Symbol(a), Str(b)) => Str(format_str!("{a}{b}")),
33 (Bytes(a), Bytes(b)) => Bytes(a + b),
34 (Content(a), Content(b)) => Content(a + b),
35 (Content(a), Symbol(b)) => Content(a + SymbolElem::packed(b.get())),
36 (Content(a), Str(b)) => Content(a + TextElem::packed(b)),
37 (Str(a), Content(b)) => Content(TextElem::packed(a) + b),
38 (Symbol(a), Content(b)) => Content(SymbolElem::packed(a.get()) + b),
39 (Array(a), Array(b)) => Array(a + b),
40 (Dict(a), Dict(b)) => Dict(a + b),
41 (Args(a), Args(b)) => Args(a + b),
42 (a, b) => mismatch!("cannot join {} with {}", a, b),
43 })
44}
45
46pub fn pos(value: Value) -> HintedStrResult<Value> {
48 use Value::*;
49 Ok(match value {
50 Int(v) => Int(v),
51 Float(v) => Float(v),
52 Decimal(v) => Decimal(v),
53 Length(v) => Length(v),
54 Angle(v) => Angle(v),
55 Ratio(v) => Ratio(v),
56 Relative(v) => Relative(v),
57 Fraction(v) => Fraction(v),
58 Symbol(_) | Str(_) | Bytes(_) | Content(_) | Array(_) | Dict(_) | Datetime(_) => {
59 mismatch!("cannot apply unary '+' to {}", value)
60 }
61 Dyn(d) => {
62 if d.is::<Alignment>() {
63 mismatch!("cannot apply unary '+' to {}", d)
64 } else {
65 mismatch!("cannot apply '+' to {}", d)
66 }
67 }
68 v => mismatch!("cannot apply '+' to {}", v),
69 })
70}
71
72pub fn neg(value: Value) -> HintedStrResult<Value> {
74 use Value::*;
75 Ok(match value {
76 Int(v) => Int(v.checked_neg().ok_or_else(too_large)?),
77 Float(v) => Float(-v),
78 Decimal(v) => Decimal(-v),
79 Length(v) => Length(-v),
80 Angle(v) => Angle(-v),
81 Ratio(v) => Ratio(-v),
82 Relative(v) => Relative(-v),
83 Fraction(v) => Fraction(-v),
84 Duration(v) => Duration(-v),
85 Datetime(_) => mismatch!("cannot apply unary '-' to {}", value),
86 v => mismatch!("cannot apply '-' to {}", v),
87 })
88}
89
90pub fn add(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
92 use Value::*;
93 Ok(match (lhs, rhs) {
94 (a, None) => a,
95 (None, b) => b,
96
97 (Int(a), Int(b)) => Int(a.checked_add(b).ok_or_else(too_large)?),
98 (Int(a), Float(b)) => Float(a as f64 + b),
99 (Float(a), Int(b)) => Float(a + b as f64),
100 (Float(a), Float(b)) => Float(a + b),
101
102 (Decimal(a), Decimal(b)) => Decimal(a.checked_add(b).ok_or_else(too_large)?),
103 (Decimal(a), Int(b)) => Decimal(
104 a.checked_add(crate::foundations::Decimal::from(b))
105 .ok_or_else(too_large)?,
106 ),
107 (Int(a), Decimal(b)) => Decimal(
108 crate::foundations::Decimal::from(a)
109 .checked_add(b)
110 .ok_or_else(too_large)?,
111 ),
112
113 (Angle(a), Angle(b)) => Angle(a + b),
114
115 (Length(a), Length(b)) => Length(a + b),
116 (Length(a), Ratio(b)) => Relative(b + a),
117 (Length(a), Relative(b)) => Relative(b + a),
118
119 (Ratio(a), Length(b)) => Relative(a + b),
120 (Ratio(a), Ratio(b)) => Ratio(a + b),
121 (Ratio(a), Relative(b)) => Relative(b + a),
122
123 (Relative(a), Length(b)) => Relative(a + b),
124 (Relative(a), Ratio(b)) => Relative(a + b),
125 (Relative(a), Relative(b)) => Relative(a + b),
126
127 (Fraction(a), Fraction(b)) => Fraction(a + b),
128
129 (Symbol(a), Symbol(b)) => Str(format_str!("{a}{b}")),
130 (Str(a), Str(b)) => Str(a + b),
131 (Str(a), Symbol(b)) => Str(format_str!("{a}{b}")),
132 (Symbol(a), Str(b)) => Str(format_str!("{a}{b}")),
133 (Bytes(a), Bytes(b)) => Bytes(a + b),
134 (Content(a), Content(b)) => Content(a + b),
135 (Content(a), Symbol(b)) => Content(a + SymbolElem::packed(b.get())),
136 (Content(a), Str(b)) => Content(a + TextElem::packed(b)),
137 (Str(a), Content(b)) => Content(TextElem::packed(a) + b),
138 (Symbol(a), Content(b)) => Content(SymbolElem::packed(a.get()) + b),
139
140 (Array(a), Array(b)) => Array(a + b),
141 (Dict(a), Dict(b)) => Dict(a + b),
142 (Args(a), Args(b)) => Args(a + b),
143
144 (Color(color), Length(thickness)) | (Length(thickness), Color(color)) => {
145 Stroke::from_pair(color, thickness).into_value()
146 }
147 (Gradient(gradient), Length(thickness))
148 | (Length(thickness), Gradient(gradient)) => {
149 Stroke::from_pair(gradient, thickness).into_value()
150 }
151 (Tiling(tiling), Length(thickness)) | (Length(thickness), Tiling(tiling)) => {
152 Stroke::from_pair(tiling, thickness).into_value()
153 }
154
155 (Duration(a), Duration(b)) => Duration(a + b),
156 (Datetime(a), Duration(b)) => Datetime(a + b),
157 (Duration(a), Datetime(b)) => Datetime(b + a),
158
159 (Dyn(a), Dyn(b)) => {
160 if let (Some(&a), Some(&b)) =
162 (a.downcast::<Alignment>(), b.downcast::<Alignment>())
163 {
164 return Ok((a + b)?.into_value());
165 }
166
167 mismatch!("cannot add {} and {}", a, b);
168 }
169
170 (a, b) => mismatch!("cannot add {} and {}", a, b),
171 })
172}
173
174pub fn sub(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
176 use Value::*;
177 Ok(match (lhs, rhs) {
178 (Int(a), Int(b)) => Int(a.checked_sub(b).ok_or_else(too_large)?),
179 (Int(a), Float(b)) => Float(a as f64 - b),
180 (Float(a), Int(b)) => Float(a - b as f64),
181 (Float(a), Float(b)) => Float(a - b),
182
183 (Decimal(a), Decimal(b)) => Decimal(a.checked_sub(b).ok_or_else(too_large)?),
184 (Decimal(a), Int(b)) => Decimal(
185 a.checked_sub(crate::foundations::Decimal::from(b))
186 .ok_or_else(too_large)?,
187 ),
188 (Int(a), Decimal(b)) => Decimal(
189 crate::foundations::Decimal::from(a)
190 .checked_sub(b)
191 .ok_or_else(too_large)?,
192 ),
193
194 (Angle(a), Angle(b)) => Angle(a - b),
195
196 (Length(a), Length(b)) => Length(a - b),
197 (Length(a), Ratio(b)) => Relative(-b + a),
198 (Length(a), Relative(b)) => Relative(-b + a),
199
200 (Ratio(a), Length(b)) => Relative(a + -b),
201 (Ratio(a), Ratio(b)) => Ratio(a - b),
202 (Ratio(a), Relative(b)) => Relative(-b + a),
203
204 (Relative(a), Length(b)) => Relative(a + -b),
205 (Relative(a), Ratio(b)) => Relative(a + -b),
206 (Relative(a), Relative(b)) => Relative(a - b),
207
208 (Fraction(a), Fraction(b)) => Fraction(a - b),
209
210 (Duration(a), Duration(b)) => Duration(a - b),
211 (Datetime(a), Duration(b)) => Datetime(a - b),
212 (Datetime(a), Datetime(b)) => Duration((a - b)?),
213
214 (a, b) => mismatch!("cannot subtract {1} from {0}", a, b),
215 })
216}
217
218pub fn mul(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
220 use Value::*;
221 Ok(match (lhs, rhs) {
222 (Int(a), Int(b)) => Int(a.checked_mul(b).ok_or_else(too_large)?),
223 (Int(a), Float(b)) => Float(a as f64 * b),
224 (Float(a), Int(b)) => Float(a * b as f64),
225 (Float(a), Float(b)) => Float(a * b),
226
227 (Decimal(a), Decimal(b)) => Decimal(a.checked_mul(b).ok_or_else(too_large)?),
228 (Decimal(a), Int(b)) => Decimal(
229 a.checked_mul(crate::foundations::Decimal::from(b))
230 .ok_or_else(too_large)?,
231 ),
232 (Int(a), Decimal(b)) => Decimal(
233 crate::foundations::Decimal::from(a)
234 .checked_mul(b)
235 .ok_or_else(too_large)?,
236 ),
237
238 (Length(a), Int(b)) => Length(a * b as f64),
239 (Length(a), Float(b)) => Length(a * b),
240 (Length(a), Ratio(b)) => Length(a * b.get()),
241 (Int(a), Length(b)) => Length(b * a as f64),
242 (Float(a), Length(b)) => Length(b * a),
243 (Ratio(a), Length(b)) => Length(b * a.get()),
244
245 (Angle(a), Int(b)) => Angle(a * b as f64),
246 (Angle(a), Float(b)) => Angle(a * b),
247 (Angle(a), Ratio(b)) => Angle(a * b.get()),
248 (Int(a), Angle(b)) => Angle(a as f64 * b),
249 (Float(a), Angle(b)) => Angle(a * b),
250 (Ratio(a), Angle(b)) => Angle(a.get() * b),
251
252 (Ratio(a), Ratio(b)) => Ratio(a * b),
253 (Ratio(a), Int(b)) => Ratio(a * b as f64),
254 (Ratio(a), Float(b)) => Ratio(a * b),
255 (Int(a), Ratio(b)) => Ratio(a as f64 * b),
256 (Float(a), Ratio(b)) => Ratio(a * b),
257
258 (Relative(a), Int(b)) => Relative(a * b as f64),
259 (Relative(a), Float(b)) => Relative(a * b),
260 (Relative(a), Ratio(b)) => Relative(a * b.get()),
261 (Int(a), Relative(b)) => Relative(a as f64 * b),
262 (Float(a), Relative(b)) => Relative(a * b),
263 (Ratio(a), Relative(b)) => Relative(a.get() * b),
264
265 (Fraction(a), Int(b)) => Fraction(a * b as f64),
266 (Fraction(a), Float(b)) => Fraction(a * b),
267 (Fraction(a), Ratio(b)) => Fraction(a * b.get()),
268 (Int(a), Fraction(b)) => Fraction(a as f64 * b),
269 (Float(a), Fraction(b)) => Fraction(a * b),
270 (Ratio(a), Fraction(b)) => Fraction(a.get() * b),
271
272 (Str(a), Int(b)) => Str(a.repeat(Value::Int(b).cast()?)?),
273 (Int(a), Str(b)) => Str(b.repeat(Value::Int(a).cast()?)?),
274 (Array(a), Int(b)) => Array(a.repeat(Value::Int(b).cast()?)?),
275 (Int(a), Array(b)) => Array(b.repeat(Value::Int(a).cast()?)?),
276 (Content(a), b @ Int(_)) => Content(a.repeat(b.cast()?)),
277 (a @ Int(_), Content(b)) => Content(b.repeat(a.cast()?)),
278
279 (Int(a), Duration(b)) => Duration(b * (a as f64)),
280 (Float(a), Duration(b)) => Duration(b * a),
281 (Duration(a), Int(b)) => Duration(a * (b as f64)),
282 (Duration(a), Float(b)) => Duration(a * b),
283
284 (a, b) => mismatch!("cannot multiply {} with {}", a, b),
285 })
286}
287
288pub fn div(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
290 use Value::*;
291 if is_zero(&rhs) {
292 bail!("cannot divide by zero");
293 }
294
295 Ok(match (lhs, rhs) {
296 (Int(a), Int(b)) => Float(a as f64 / b as f64),
297 (Int(a), Float(b)) => Float(a as f64 / b),
298 (Float(a), Int(b)) => Float(a / b as f64),
299 (Float(a), Float(b)) => Float(a / b),
300
301 (Decimal(a), Decimal(b)) => Decimal(a.checked_div(b).ok_or_else(too_large)?),
302 (Decimal(a), Int(b)) => Decimal(
303 a.checked_div(crate::foundations::Decimal::from(b))
304 .ok_or_else(too_large)?,
305 ),
306 (Int(a), Decimal(b)) => Decimal(
307 crate::foundations::Decimal::from(a)
308 .checked_div(b)
309 .ok_or_else(too_large)?,
310 ),
311
312 (Length(a), Int(b)) => Length(a / b as f64),
313 (Length(a), Float(b)) => Length(a / b),
314 (Length(a), Length(b)) => Float(try_div_length(a, b)?),
315 (Length(a), Relative(b)) if b.rel.is_zero() => Float(try_div_length(a, b.abs)?),
316
317 (Angle(a), Int(b)) => Angle(a / b as f64),
318 (Angle(a), Float(b)) => Angle(a / b),
319 (Angle(a), Angle(b)) => Float(a / b),
320
321 (Ratio(a), Int(b)) => Ratio(a / b as f64),
322 (Ratio(a), Float(b)) => Ratio(a / b),
323 (Ratio(a), Ratio(b)) => Float(a / b),
324 (Ratio(a), Relative(b)) if b.abs.is_zero() => Float(a / b.rel),
325
326 (Relative(a), Int(b)) => Relative(a / b as f64),
327 (Relative(a), Float(b)) => Relative(a / b),
328 (Relative(a), Length(b)) if a.rel.is_zero() => Float(try_div_length(a.abs, b)?),
329 (Relative(a), Ratio(b)) if a.abs.is_zero() => Float(a.rel / b),
330 (Relative(a), Relative(b)) => Float(try_div_relative(a, b)?),
331
332 (Fraction(a), Int(b)) => Fraction(a / b as f64),
333 (Fraction(a), Float(b)) => Fraction(a / b),
334 (Fraction(a), Fraction(b)) => Float(a / b),
335
336 (Duration(a), Int(b)) => Duration(a / (b as f64)),
337 (Duration(a), Float(b)) => Duration(a / b),
338 (Duration(a), Duration(b)) => Float(a / b),
339
340 (a, b) => mismatch!("cannot divide {} by {}", a, b),
341 })
342}
343
344fn is_zero(v: &Value) -> bool {
346 use Value::*;
347 match *v {
348 Int(v) => v == 0,
349 Float(v) => v == 0.0,
350 Decimal(v) => v.is_zero(),
351 Length(v) => v.is_zero(),
352 Angle(v) => v.is_zero(),
353 Ratio(v) => v.is_zero(),
354 Relative(v) => v.is_zero(),
355 Fraction(v) => v.is_zero(),
356 Duration(v) => v.is_zero(),
357 _ => false,
358 }
359}
360
361fn try_div_length(a: Length, b: Length) -> StrResult<f64> {
363 a.try_div(b).ok_or_else(|| "cannot divide these two lengths".into())
364}
365
366fn try_div_relative(a: Rel<Length>, b: Rel<Length>) -> StrResult<f64> {
368 a.try_div(b)
369 .ok_or_else(|| "cannot divide these two relative lengths".into())
370}
371
372pub fn not(value: Value) -> HintedStrResult<Value> {
374 match value {
375 Value::Bool(b) => Ok(Value::Bool(!b)),
376 v => mismatch!("cannot apply 'not' to {}", v),
377 }
378}
379
380pub fn and(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
382 match (lhs, rhs) {
383 (Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a && b)),
384 (a, b) => mismatch!("cannot apply 'and' to {} and {}", a, b),
385 }
386}
387
388pub fn or(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
390 match (lhs, rhs) {
391 (Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a || b)),
392 (a, b) => mismatch!("cannot apply 'or' to {} and {}", a, b),
393 }
394}
395
396pub fn eq(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
398 Ok(Value::Bool(equal(&lhs, &rhs)))
399}
400
401pub fn neq(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
403 Ok(Value::Bool(!equal(&lhs, &rhs)))
404}
405
406macro_rules! comparison {
407 ($name:ident, $op:tt, $($pat:tt)*) => {
408 pub fn $name(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
410 let ordering = compare(&lhs, &rhs)?;
411 Ok(Value::Bool(matches!(ordering, $($pat)*)))
412 }
413 };
414}
415
416comparison!(lt, "<", Ordering::Less);
417comparison!(leq, "<=", Ordering::Less | Ordering::Equal);
418comparison!(gt, ">", Ordering::Greater);
419comparison!(geq, ">=", Ordering::Greater | Ordering::Equal);
420
421pub fn equal(lhs: &Value, rhs: &Value) -> bool {
423 use Value::*;
424 match (lhs, rhs) {
425 (None, None) => true,
427 (Auto, Auto) => true,
428 (Bool(a), Bool(b)) => a == b,
429 (Int(a), Int(b)) => a == b,
430 (Float(a), Float(b)) => a == b,
431 (Decimal(a), Decimal(b)) => a == b,
432 (Length(a), Length(b)) => a == b,
433 (Angle(a), Angle(b)) => a == b,
434 (Ratio(a), Ratio(b)) => a == b,
435 (Relative(a), Relative(b)) => a == b,
436 (Fraction(a), Fraction(b)) => a == b,
437 (Color(a), Color(b)) => a == b,
438 (Symbol(a), Symbol(b)) => a == b,
439 (Version(a), Version(b)) => a == b,
440 (Str(a), Str(b)) => a == b,
441 (Bytes(a), Bytes(b)) => a == b,
442 (Label(a), Label(b)) => a == b,
443 (Content(a), Content(b)) => a == b,
444 (Array(a), Array(b)) => a == b,
445 (Dict(a), Dict(b)) => a == b,
446 (Func(a), Func(b)) => a == b,
447 (Args(a), Args(b)) => a == b,
448 (Type(a), Type(b)) => a == b,
449 (Module(a), Module(b)) => a == b,
450 (Datetime(a), Datetime(b)) => a == b,
451 (Duration(a), Duration(b)) => a == b,
452 (Dyn(a), Dyn(b)) => a == b,
453
454 (&Int(i), &Float(f)) | (&Float(f), &Int(i)) => i as f64 == f,
456 (&Int(i), &Decimal(d)) | (&Decimal(d), &Int(i)) => {
457 crate::foundations::Decimal::from(i) == d
458 }
459 (&Length(len), &Relative(rel)) | (&Relative(rel), &Length(len)) => {
460 len == rel.abs && rel.rel.is_zero()
461 }
462 (&Ratio(rat), &Relative(rel)) | (&Relative(rel), &Ratio(rat)) => {
463 rat == rel.rel && rel.abs.is_zero()
464 }
465
466 _ => false,
467 }
468}
469
470pub fn compare(lhs: &Value, rhs: &Value) -> StrResult<Ordering> {
472 use Value::*;
473 Ok(match (lhs, rhs) {
474 (Bool(a), Bool(b)) => a.cmp(b),
475 (Int(a), Int(b)) => a.cmp(b),
476 (Float(a), Float(b)) => try_cmp_values(a, b)?,
477 (Decimal(a), Decimal(b)) => a.cmp(b),
478 (Length(a), Length(b)) => try_cmp_values(a, b)?,
479 (Angle(a), Angle(b)) => a.cmp(b),
480 (Ratio(a), Ratio(b)) => a.cmp(b),
481 (Relative(a), Relative(b)) => try_cmp_values(a, b)?,
482 (Fraction(a), Fraction(b)) => a.cmp(b),
483 (Version(a), Version(b)) => a.cmp(b),
484 (Str(a), Str(b)) => a.cmp(b),
485
486 (Int(a), Float(b)) => try_cmp_values(&(*a as f64), b)?,
488 (Float(a), Int(b)) => try_cmp_values(a, &(*b as f64))?,
489 (Int(a), Decimal(b)) => crate::foundations::Decimal::from(*a).cmp(b),
490 (Decimal(a), Int(b)) => a.cmp(&crate::foundations::Decimal::from(*b)),
491 (Length(a), Relative(b)) if b.rel.is_zero() => try_cmp_values(a, &b.abs)?,
492 (Ratio(a), Relative(b)) if b.abs.is_zero() => a.cmp(&b.rel),
493 (Relative(a), Length(b)) if a.rel.is_zero() => try_cmp_values(&a.abs, b)?,
494 (Relative(a), Ratio(b)) if a.abs.is_zero() => a.rel.cmp(b),
495
496 (Duration(a), Duration(b)) => a.cmp(b),
497 (Datetime(a), Datetime(b)) => try_cmp_datetimes(a, b)?,
498 (Array(a), Array(b)) => try_cmp_arrays(a.as_slice(), b.as_slice())?,
499
500 _ => mismatch!("cannot compare {} and {}", lhs, rhs),
501 })
502}
503
504fn try_cmp_values<T: PartialOrd + Repr>(a: &T, b: &T) -> StrResult<Ordering> {
506 a.partial_cmp(b)
507 .ok_or_else(|| eco_format!("cannot compare {} with {}", a.repr(), b.repr()))
508}
509
510fn try_cmp_datetimes(a: &Datetime, b: &Datetime) -> StrResult<Ordering> {
512 a.partial_cmp(b)
513 .ok_or_else(|| eco_format!("cannot compare {} and {}", a.kind(), b.kind()))
514}
515
516fn try_cmp_arrays(a: &[Value], b: &[Value]) -> StrResult<Ordering> {
518 a.iter()
519 .zip(b.iter())
520 .find_map(|(first, second)| {
521 match compare(first, second) {
522 Ok(Ordering::Equal) => None,
524 result => Some(result),
527 }
528 })
529 .unwrap_or_else(|| {
530 Ok(a.len().cmp(&b.len()))
533 })
534}
535
536pub fn in_(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
538 if let Some(b) = contains(&lhs, &rhs) {
539 Ok(Value::Bool(b))
540 } else {
541 mismatch!("cannot apply 'in' to {} and {}", lhs, rhs)
542 }
543}
544
545pub fn not_in(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
547 if let Some(b) = contains(&lhs, &rhs) {
548 Ok(Value::Bool(!b))
549 } else {
550 mismatch!("cannot apply 'not in' to {} and {}", lhs, rhs)
551 }
552}
553
554pub fn contains(lhs: &Value, rhs: &Value) -> Option<bool> {
556 use Value::*;
557 match (lhs, rhs) {
558 (Str(a), Str(b)) => Some(b.as_str().contains(a.as_str())),
559 (Dyn(a), Str(b)) => a.downcast::<Regex>().map(|regex| regex.is_match(b)),
560 (Str(a), Dict(b)) => Some(b.contains(a)),
561 (Str(a), Module(b)) => Some(b.scope().get(a).is_some()),
562 (a, Array(b)) => Some(b.contains(a.clone())),
563
564 _ => Option::None,
565 }
566}
567
568#[cold]
569fn too_large() -> &'static str {
570 "value is too large"
571}