typst_utils/
lib.rs

1//! Utilities for Typst.
2
3pub mod fat;
4
5#[macro_use]
6mod macros;
7mod bitset;
8mod deferred;
9mod duration;
10mod hash;
11mod listset;
12mod pico;
13mod round;
14mod scalar;
15
16pub use self::bitset::{BitSet, SmallBitSet};
17pub use self::deferred::Deferred;
18pub use self::duration::format_duration;
19pub use self::hash::{HashLock, LazyHash, ManuallyHash};
20pub use self::listset::ListSet;
21pub use self::pico::{PicoStr, ResolvedPicoStr};
22pub use self::round::{round_int_with_precision, round_with_precision};
23pub use self::scalar::Scalar;
24
25#[doc(hidden)]
26pub use once_cell;
27
28use std::fmt::{Debug, Display, Formatter};
29use std::hash::Hash;
30use std::iter::{Chain, Flatten, Rev};
31use std::num::{NonZeroU32, NonZeroUsize};
32use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub};
33use std::sync::Arc;
34
35use siphasher::sip128::{Hasher128, SipHasher13};
36use unicode_math_class::MathClass;
37
38/// Turn a closure into a struct implementing [`Debug`].
39pub fn debug<F>(f: F) -> impl Debug
40where
41    F: Fn(&mut Formatter) -> std::fmt::Result,
42{
43    struct Wrapper<F>(F);
44
45    impl<F> Debug for Wrapper<F>
46    where
47        F: Fn(&mut Formatter) -> std::fmt::Result,
48    {
49        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50            self.0(f)
51        }
52    }
53
54    Wrapper(f)
55}
56
57/// Turn a closure into a struct implementing [`Display`].
58pub fn display<F>(f: F) -> impl Display
59where
60    F: Fn(&mut Formatter) -> std::fmt::Result,
61{
62    struct Wrapper<F>(F);
63
64    impl<F> Display for Wrapper<F>
65    where
66        F: Fn(&mut Formatter) -> std::fmt::Result,
67    {
68        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
69            self.0(f)
70        }
71    }
72
73    Wrapper(f)
74}
75
76/// Calculate a 128-bit siphash of a value.
77pub fn hash128<T: Hash + ?Sized>(value: &T) -> u128 {
78    let mut state = SipHasher13::new();
79    value.hash(&mut state);
80    state.finish128().as_u128()
81}
82
83/// An extra constant for [`NonZeroUsize`].
84pub trait NonZeroExt {
85    /// The number `1`.
86    const ONE: Self;
87}
88
89impl NonZeroExt for NonZeroUsize {
90    const ONE: Self = Self::new(1).unwrap();
91}
92
93impl NonZeroExt for NonZeroU32 {
94    const ONE: Self = Self::new(1).unwrap();
95}
96
97/// Extra methods for [`Arc`].
98pub trait ArcExt<T> {
99    /// Takes the inner value if there is exactly one strong reference and
100    /// clones it otherwise.
101    fn take(self) -> T;
102}
103
104impl<T: Clone> ArcExt<T> for Arc<T> {
105    fn take(self) -> T {
106        match Arc::try_unwrap(self) {
107            Ok(v) => v,
108            Err(rc) => (*rc).clone(),
109        }
110    }
111}
112
113/// Extra methods for [`Option`].
114pub trait OptionExt<T> {
115    /// Maps an `Option<T>` to `U` by applying a function to a contained value
116    /// (if `Some`) or returns a default (if `None`).
117    fn map_or_default<U: Default, F>(self, f: F) -> U
118    where
119        F: FnOnce(T) -> U;
120}
121
122impl<T> OptionExt<T> for Option<T> {
123    fn map_or_default<U: Default, F>(self, f: F) -> U
124    where
125        F: FnOnce(T) -> U,
126    {
127        match self {
128            Some(x) => f(x),
129            None => U::default(),
130        }
131    }
132}
133
134/// Extra methods for [`[T]`](slice).
135pub trait SliceExt<T> {
136    /// Returns a slice with all matching elements from the start of the slice
137    /// removed.
138    fn trim_start_matches<F>(&self, f: F) -> &[T]
139    where
140        F: FnMut(&T) -> bool;
141
142    /// Returns a slice with all matching elements from the end of the slice
143    /// removed.
144    fn trim_end_matches<F>(&self, f: F) -> &[T]
145    where
146        F: FnMut(&T) -> bool;
147
148    /// Split a slice into consecutive runs with the same key and yield for
149    /// each such run the key and the slice of elements with that key.
150    fn group_by_key<K, F>(&self, f: F) -> GroupByKey<'_, T, F>
151    where
152        F: FnMut(&T) -> K,
153        K: PartialEq;
154
155    /// Computes two indices which split a slice into three parts.
156    ///
157    /// - A prefix which matches `f`
158    /// - An inner portion
159    /// - A suffix which matches `f` and does not overlap with the prefix
160    ///
161    /// If all elements match `f`, the prefix becomes `self` and the suffix
162    /// will be empty.
163    ///
164    /// Returns the indices at which the inner portion and the suffix start.
165    fn split_prefix_suffix<F>(&self, f: F) -> (usize, usize)
166    where
167        F: FnMut(&T) -> bool;
168}
169
170impl<T> SliceExt<T> for [T] {
171    fn trim_start_matches<F>(&self, mut f: F) -> &[T]
172    where
173        F: FnMut(&T) -> bool,
174    {
175        let len = self.len();
176        let mut i = 0;
177        while i < len && f(&self[i]) {
178            i += 1;
179        }
180        &self[i..]
181    }
182
183    fn trim_end_matches<F>(&self, mut f: F) -> &[T]
184    where
185        F: FnMut(&T) -> bool,
186    {
187        let mut i = self.len();
188        while i > 0 && f(&self[i - 1]) {
189            i -= 1;
190        }
191        &self[..i]
192    }
193
194    fn group_by_key<K, F>(&self, f: F) -> GroupByKey<'_, T, F> {
195        GroupByKey { slice: self, f }
196    }
197
198    fn split_prefix_suffix<F>(&self, mut f: F) -> (usize, usize)
199    where
200        F: FnMut(&T) -> bool,
201    {
202        let start = self.iter().position(|v| !f(v)).unwrap_or(self.len());
203        let end = self
204            .iter()
205            .skip(start)
206            .rposition(|v| !f(v))
207            .map_or(start, |i| start + i + 1);
208        (start, end)
209    }
210}
211
212/// This struct is created by [`SliceExt::group_by_key`].
213pub struct GroupByKey<'a, T, F> {
214    slice: &'a [T],
215    f: F,
216}
217
218impl<'a, T, K, F> Iterator for GroupByKey<'a, T, F>
219where
220    F: FnMut(&T) -> K,
221    K: PartialEq,
222{
223    type Item = (K, &'a [T]);
224
225    fn next(&mut self) -> Option<Self::Item> {
226        let mut iter = self.slice.iter();
227        let key = (self.f)(iter.next()?);
228        let count = 1 + iter.take_while(|t| (self.f)(t) == key).count();
229        let (head, tail) = self.slice.split_at(count);
230        self.slice = tail;
231        Some((key, head))
232    }
233}
234
235/// Adapter for reversing iterators conditionally.
236pub trait MaybeReverseIter {
237    type RevIfIter;
238
239    /// Reverse this iterator (apply .rev()) based on some condition.
240    fn rev_if(self, condition: bool) -> Self::RevIfIter
241    where
242        Self: Sized;
243}
244
245impl<I: Iterator + DoubleEndedIterator> MaybeReverseIter for I {
246    type RevIfIter =
247        Chain<Flatten<std::option::IntoIter<I>>, Flatten<std::option::IntoIter<Rev<I>>>>;
248
249    fn rev_if(self, condition: bool) -> Self::RevIfIter
250    where
251        Self: Sized,
252    {
253        let (maybe_self_iter, maybe_rev_iter) =
254            if condition { (None, Some(self.rev())) } else { (Some(self), None) };
255
256        maybe_self_iter
257            .into_iter()
258            .flatten()
259            .chain(maybe_rev_iter.into_iter().flatten())
260    }
261}
262
263/// Check if the [`Option`]-wrapped L is same to R.
264pub fn option_eq<L, R>(left: Option<L>, other: R) -> bool
265where
266    L: PartialEq<R>,
267{
268    left.is_some_and(|v| v == other)
269}
270
271/// A container around a static reference that is cheap to clone and hash.
272#[derive(Debug)]
273pub struct Static<T: 'static>(pub &'static T);
274
275impl<T> Deref for Static<T> {
276    type Target = T;
277
278    fn deref(&self) -> &Self::Target {
279        self.0
280    }
281}
282
283impl<T> Copy for Static<T> {}
284
285impl<T> Clone for Static<T> {
286    fn clone(&self) -> Self {
287        *self
288    }
289}
290
291impl<T> Eq for Static<T> {}
292
293impl<T> PartialEq for Static<T> {
294    fn eq(&self, other: &Self) -> bool {
295        std::ptr::eq(self.0, other.0)
296    }
297}
298
299impl<T> Hash for Static<T> {
300    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
301        state.write_usize(self.0 as *const _ as _);
302    }
303}
304
305/// Generic access to a structure's components.
306pub trait Get<Index> {
307    /// The structure's component type.
308    type Component;
309
310    /// Borrow the component for the specified index.
311    fn get_ref(&self, index: Index) -> &Self::Component;
312
313    /// Borrow the component for the specified index mutably.
314    fn get_mut(&mut self, index: Index) -> &mut Self::Component;
315
316    /// Convenience method for getting a copy of a component.
317    fn get(self, index: Index) -> Self::Component
318    where
319        Self: Sized,
320        Self::Component: Copy,
321    {
322        *self.get_ref(index)
323    }
324
325    /// Convenience method for setting a component.
326    fn set(&mut self, index: Index, component: Self::Component) {
327        *self.get_mut(index) = component;
328    }
329
330    /// Builder-style method for setting a component.
331    fn with(mut self, index: Index, component: Self::Component) -> Self
332    where
333        Self: Sized,
334    {
335        self.set(index, component);
336        self
337    }
338}
339
340/// A numeric type.
341pub trait Numeric:
342    Sized
343    + Debug
344    + Copy
345    + PartialEq
346    + Neg<Output = Self>
347    + Add<Output = Self>
348    + Sub<Output = Self>
349    + Mul<f64, Output = Self>
350    + Div<f64, Output = Self>
351{
352    /// The identity element for addition.
353    fn zero() -> Self;
354
355    /// Whether `self` is zero.
356    fn is_zero(self) -> bool {
357        self == Self::zero()
358    }
359
360    /// Whether `self` consists only of finite parts.
361    fn is_finite(self) -> bool;
362}
363
364/// Returns the default math class of a character in Typst, if it has one.
365///
366/// This is determined by the Unicode math class, with some manual overrides.
367pub fn default_math_class(c: char) -> Option<MathClass> {
368    match c {
369        // Better spacing.
370        // https://github.com/typst/typst/commit/2e039cb052fcb768027053cbf02ce396f6d7a6be
371        ':' => Some(MathClass::Relation),
372
373        // Better spacing when used alongside + PLUS SIGN.
374        // https://github.com/typst/typst/pull/1726
375        '⋯' | '⋱' | '⋰' | '⋮' => Some(MathClass::Normal),
376
377        // Better spacing.
378        // https://github.com/typst/typst/pull/1855
379        '.' | '/' => Some(MathClass::Normal),
380
381        // ⊥ UP TACK should not be a relation, contrary to ⟂ PERPENDICULAR.
382        // https://github.com/typst/typst/pull/5714
383        '\u{22A5}' => Some(MathClass::Normal),
384
385        // Used as a binary connector in linear logic, where it is referred to
386        // as "par".
387        // https://github.com/typst/typst/issues/5764
388        '⅋' => Some(MathClass::Binary),
389
390        // Those overrides should become the default in the next revision of
391        // MathClass.txt.
392        // https://github.com/typst/typst/issues/5764#issuecomment-2632435247
393        '⎰' | '⟅' => Some(MathClass::Opening),
394        '⎱' | '⟆' => Some(MathClass::Closing),
395
396        // Both ∨ and ⟑ are classified as Binary.
397        // https://github.com/typst/typst/issues/5764
398        '⟇' => Some(MathClass::Binary),
399
400        // Arabic comma.
401        // https://github.com/latex3/unicode-math/pull/633#issuecomment-2028936135
402        '،' => Some(MathClass::Punctuation),
403
404        c => unicode_math_class::class(c),
405    }
406}
407
408/// Automatically calls a deferred function when the returned handle is dropped.
409pub fn defer<T, F: FnOnce(&mut T)>(
410    thing: &mut T,
411    deferred: F,
412) -> impl DerefMut<Target = T> {
413    pub struct DeferHandle<'a, T, F: FnOnce(&mut T)> {
414        thing: &'a mut T,
415        deferred: Option<F>,
416    }
417
418    impl<'a, T, F: FnOnce(&mut T)> Drop for DeferHandle<'a, T, F> {
419        fn drop(&mut self) {
420            std::mem::take(&mut self.deferred).expect("deferred function")(self.thing);
421        }
422    }
423
424    impl<T, F: FnOnce(&mut T)> std::ops::Deref for DeferHandle<'_, T, F> {
425        type Target = T;
426
427        fn deref(&self) -> &Self::Target {
428            self.thing
429        }
430    }
431
432    impl<T, F: FnOnce(&mut T)> std::ops::DerefMut for DeferHandle<'_, T, F> {
433        fn deref_mut(&mut self) -> &mut Self::Target {
434            self.thing
435        }
436    }
437
438    DeferHandle { thing, deferred: Some(deferred) }
439}