pub mod fat;
#[macro_use]
mod macros;
mod bitset;
mod deferred;
mod duration;
mod hash;
mod listset;
mod pico;
mod protected;
mod round;
mod scalar;
#[path = "version.rs"]
mod version_;
pub use self::bitset::{BitSet, SmallBitSet};
pub use self::deferred::Deferred;
pub use self::duration::format_duration;
pub use self::hash::{HashLock, LazyHash, ManuallyHash, hash128};
pub use self::listset::ListSet;
pub use self::pico::{PicoStr, ResolvedPicoStr};
pub use self::protected::Protected;
pub use self::round::{round_int_with_precision, round_with_precision};
pub use self::scalar::Scalar;
pub use self::version_::{TypstVersion, display_commit, version};
#[doc(hidden)]
pub use once_cell;
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::iter::{Chain, Flatten, Rev};
use std::num::{NonZeroU32, NonZeroUsize};
use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub};
use smallvec::SmallVec;
use unicode_math_class::MathClass;
pub fn debug<F>(f: F) -> impl Debug
where
F: Fn(&mut Formatter) -> std::fmt::Result,
{
struct Wrapper<F>(F);
impl<F> Debug for Wrapper<F>
where
F: Fn(&mut Formatter) -> std::fmt::Result,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0(f)
}
}
Wrapper(f)
}
pub fn display<F>(f: F) -> impl Display
where
F: Fn(&mut Formatter) -> std::fmt::Result,
{
struct Wrapper<F>(F);
impl<F> Display for Wrapper<F>
where
F: Fn(&mut Formatter) -> std::fmt::Result,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0(f)
}
}
Wrapper(f)
}
pub trait NonZeroExt {
const ONE: Self;
}
impl NonZeroExt for NonZeroUsize {
const ONE: Self = Self::new(1).unwrap();
}
impl NonZeroExt for NonZeroU32 {
const ONE: Self = Self::new(1).unwrap();
}
pub trait OptionExt<T> {
fn map_or_default<U: Default, F>(self, f: F) -> U
where
F: FnOnce(T) -> U;
}
impl<T> OptionExt<T> for Option<T> {
fn map_or_default<U: Default, F>(self, f: F) -> U
where
F: FnOnce(T) -> U,
{
match self {
Some(x) => f(x),
None => U::default(),
}
}
}
pub trait SliceExt<T> {
fn trim_start_matches<F>(&self, f: F) -> &[T]
where
F: FnMut(&T) -> bool;
fn trim_end_matches<F>(&self, f: F) -> &[T]
where
F: FnMut(&T) -> bool;
fn group_by_key<K, F>(&self, f: F) -> GroupByKey<'_, T, F>
where
F: FnMut(&T) -> K,
K: PartialEq;
fn split_prefix_suffix<F>(&self, f: F) -> (usize, usize)
where
F: FnMut(&T) -> bool;
}
impl<T> SliceExt<T> for [T] {
fn trim_start_matches<F>(&self, mut f: F) -> &[T]
where
F: FnMut(&T) -> bool,
{
let len = self.len();
let mut i = 0;
while i < len && f(&self[i]) {
i += 1;
}
&self[i..]
}
fn trim_end_matches<F>(&self, mut f: F) -> &[T]
where
F: FnMut(&T) -> bool,
{
let mut i = self.len();
while i > 0 && f(&self[i - 1]) {
i -= 1;
}
&self[..i]
}
fn group_by_key<K, F>(&self, f: F) -> GroupByKey<'_, T, F> {
GroupByKey { slice: self, f }
}
fn split_prefix_suffix<F>(&self, mut f: F) -> (usize, usize)
where
F: FnMut(&T) -> bool,
{
let start = self.iter().position(|v| !f(v)).unwrap_or(self.len());
let end = self
.iter()
.skip(start)
.rposition(|v| !f(v))
.map_or(start, |i| start + i + 1);
(start, end)
}
}
pub trait Rdedup {
type Item;
fn rdedup_by_key<K, F>(&mut self, key: F)
where
F: Fn(&mut Self::Item) -> K,
K: PartialEq<K>;
}
impl<T: Copy, const N: usize> Rdedup for SmallVec<[T; N]> {
type Item = T;
fn rdedup_by_key<K, F>(&mut self, mut key: F)
where
T: Copy,
K: PartialEq<K>,
F: FnMut(&mut T) -> K,
{
let mut k = 0;
for i in 1..self.len() {
if key(&mut self[i]) != key(&mut self[k]) {
k += 1;
}
if k < i {
self[k] = self[i];
}
}
self.truncate(k + 1);
}
}
pub struct GroupByKey<'a, T, F> {
slice: &'a [T],
f: F,
}
impl<'a, T, K, F> Iterator for GroupByKey<'a, T, F>
where
F: FnMut(&T) -> K,
K: PartialEq,
{
type Item = (K, &'a [T]);
fn next(&mut self) -> Option<Self::Item> {
let mut iter = self.slice.iter();
let key = (self.f)(iter.next()?);
let count = 1 + iter.take_while(|t| (self.f)(t) == key).count();
let (head, tail) = self.slice.split_at(count);
self.slice = tail;
Some((key, head))
}
}
pub trait MaybeReverseIter {
type RevIfIter;
fn rev_if(self, condition: bool) -> Self::RevIfIter
where
Self: Sized;
}
impl<I: Iterator + DoubleEndedIterator> MaybeReverseIter for I {
type RevIfIter =
Chain<Flatten<std::option::IntoIter<I>>, Flatten<std::option::IntoIter<Rev<I>>>>;
fn rev_if(self, condition: bool) -> Self::RevIfIter
where
Self: Sized,
{
let (maybe_self_iter, maybe_rev_iter) =
if condition { (None, Some(self.rev())) } else { (Some(self), None) };
maybe_self_iter
.into_iter()
.flatten()
.chain(maybe_rev_iter.into_iter().flatten())
}
}
pub fn option_eq<L, R>(left: Option<L>, other: R) -> bool
where
L: PartialEq<R>,
{
left.is_some_and(|v| v == other)
}
#[derive(Debug)]
pub struct Static<T: 'static>(pub &'static T);
impl<T> Deref for Static<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<T> Copy for Static<T> {}
impl<T> Clone for Static<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Eq for Static<T> {}
impl<T> PartialEq for Static<T> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.0, other.0)
}
}
impl<T> Hash for Static<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_usize(self.0 as *const _ as _);
}
}
pub trait Get<Index> {
type Component;
fn get_ref(&self, index: Index) -> &Self::Component;
fn get_mut(&mut self, index: Index) -> &mut Self::Component;
fn get(self, index: Index) -> Self::Component
where
Self: Sized,
Self::Component: Copy,
{
*self.get_ref(index)
}
fn set(&mut self, index: Index, component: Self::Component) {
*self.get_mut(index) = component;
}
fn with(mut self, index: Index, component: Self::Component) -> Self
where
Self: Sized,
{
self.set(index, component);
self
}
}
pub trait Numeric:
Sized
+ Debug
+ Copy
+ PartialEq
+ Neg<Output = Self>
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<f64, Output = Self>
+ Div<f64, Output = Self>
{
fn zero() -> Self;
fn is_zero(self) -> bool {
self == Self::zero()
}
fn is_finite(self) -> bool;
}
pub trait NumericLength: Numeric {}
pub fn default_math_class(c: char) -> Option<MathClass> {
match c {
':' => Some(MathClass::Relation),
'⋯' | '⋱' | '⋰' | '⋮' => Some(MathClass::Normal),
'.' | '/' => Some(MathClass::Normal),
'\u{22A5}' => Some(MathClass::Normal),
'â…‹' => Some(MathClass::Binary),
'⎰' | '⟅' => Some(MathClass::Opening),
'⎱' | '⟆' => Some(MathClass::Closing),
'⟇' => Some(MathClass::Binary),
'،' => Some(MathClass::Punctuation),
c => unicode_math_class::class(c),
}
}
pub fn defer<T, F: FnOnce(&mut T)>(
thing: &mut T,
deferred: F,
) -> impl DerefMut<Target = T> {
pub struct DeferHandle<'a, T, F: FnOnce(&mut T)> {
thing: &'a mut T,
deferred: Option<F>,
}
impl<'a, T, F: FnOnce(&mut T)> Drop for DeferHandle<'a, T, F> {
fn drop(&mut self) {
std::mem::take(&mut self.deferred).expect("deferred function")(self.thing);
}
}
impl<T, F: FnOnce(&mut T)> std::ops::Deref for DeferHandle<'_, T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.thing
}
}
impl<T, F: FnOnce(&mut T)> std::ops::DerefMut for DeferHandle<'_, T, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.thing
}
}
DeferHandle { thing, deferred: Some(deferred) }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct DefSite {
pub path: &'static str,
pub key: &'static str,
}
#[macro_export]
macro_rules! display_possible_values {
($ty:ty) => {
impl std::fmt::Display for $ty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_possible_value()
.expect("no values are skipped")
.get_name()
.fmt(f)
}
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rdedup() {
#[track_caller]
fn test(given: &[(char, i32)], expected: &[(char, i32)]) {
let mut vec: SmallVec<[(char, i32); 2]> = given.into();
vec.rdedup_by_key(|&mut (c, _)| c);
assert_eq!(vec.as_slice(), expected);
}
test(&[], &[]);
test(&[('a', 1), ('a', 2), ('a', 3), ('b', 2)], &[('a', 3), ('b', 2)]);
test(&[('b', 2), ('c', 3), ('c', 4)], &[('b', 2), ('c', 4)]);
test(
&[('a', 1), ('b', 1), ('c', 1), ('c', 2), ('d', 1)],
&[('a', 1), ('b', 1), ('c', 2), ('d', 1)],
);
}
}