pub(crate) fn estimate_text_width(text: &str, font_size: f64) -> f64 {
let mut narrow_chars = 0;
let mut uppercase_chars = 0;
let mut other_chars = 0;
for c in text.chars() {
if matches!(
c,
'.' | ',' | ':' | ';' | '!' | 'i' | 'j' | 'l' | '-' | '|' | '1' | 't' | 'f' | 'r'
) {
narrow_chars += 1;
} else if c.is_ascii_uppercase() {
uppercase_chars += 1;
} else {
other_chars += 1;
}
}
(narrow_chars as f64 * 0.3 + uppercase_chars as f64 * 0.65 + other_chars as f64 * 0.55)
* font_size
}
use ahash::AHashMap;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
pub trait IntoParallelizable {
type Item;
#[cfg(feature = "parallel")]
type Iter: ParallelIterator<Item = Self::Item>;
#[cfg(not(feature = "parallel"))]
type Iter: Iterator<Item = Self::Item>;
fn maybe_into_par_iter(self) -> Self::Iter;
}
pub trait Parallelizable {
type Item;
#[cfg(feature = "parallel")]
type Iter: ParallelIterator<Item = Self::Item>;
#[cfg(not(feature = "parallel"))]
type Iter: Iterator<Item = Self::Item>;
fn maybe_par_iter(self) -> Self::Iter;
}
impl<'a, T: Sync + Send + 'a> Parallelizable for &'a Vec<T> {
type Item = &'a T;
#[cfg(feature = "parallel")]
type Iter = rayon::slice::Iter<'a, T>;
#[cfg(not(feature = "parallel"))]
type Iter = std::slice::Iter<'a, T>;
fn maybe_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.par_iter()
}
#[cfg(not(feature = "parallel"))]
{
self.iter()
}
}
}
impl<'a, T: Sync + Send + 'a> Parallelizable for &'a [T] {
type Item = &'a T;
#[cfg(feature = "parallel")]
type Iter = rayon::slice::Iter<'a, T>;
#[cfg(not(feature = "parallel"))]
type Iter = std::slice::Iter<'a, T>;
fn maybe_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.par_iter()
}
#[cfg(not(feature = "parallel"))]
{
self.iter()
}
}
}
impl<'a, T: Sync + Send + 'a> Parallelizable for &'a mut Vec<T> {
type Item = &'a mut T;
#[cfg(feature = "parallel")]
type Iter = rayon::slice::IterMut<'a, T>;
#[cfg(not(feature = "parallel"))]
type Iter = std::slice::IterMut<'a, T>;
fn maybe_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.par_iter_mut()
}
#[cfg(not(feature = "parallel"))]
{
self.iter_mut()
}
}
}
impl<'a, K: Sync + Send + 'a, V: Sync + Send + 'a> Parallelizable for &'a AHashMap<K, V> {
type Item = (&'a K, &'a V);
#[cfg(feature = "parallel")]
type Iter = rayon::collections::hash_map::Iter<'a, K, V>;
#[cfg(not(feature = "parallel"))]
type Iter = std::collections::hash_map::Iter<'a, K, V>;
fn maybe_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.par_iter()
}
#[cfg(not(feature = "parallel"))]
{
self.iter()
}
}
}
impl<'a, K: Sync + Send + 'a, V: Sync + Send + 'a> Parallelizable for &'a mut AHashMap<K, V> {
type Item = (&'a K, &'a mut V);
#[cfg(feature = "parallel")]
type Iter = rayon::collections::hash_map::IterMut<'a, K, V>;
#[cfg(not(feature = "parallel"))]
type Iter = std::collections::hash_map::IterMut<'a, K, V>;
fn maybe_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.par_iter_mut()
}
#[cfg(not(feature = "parallel"))]
{
self.iter_mut()
}
}
}
impl<T: Send + Sync> IntoParallelizable for Vec<T> {
type Item = T;
#[cfg(feature = "parallel")]
type Iter = rayon::vec::IntoIter<T>;
#[cfg(not(feature = "parallel"))]
type Iter = std::vec::IntoIter<T>;
fn maybe_into_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.into_par_iter()
}
#[cfg(not(feature = "parallel"))]
{
self.into_iter()
}
}
}
impl IntoParallelizable for std::ops::Range<usize> {
type Item = usize;
#[cfg(feature = "parallel")]
type Iter = rayon::range::Iter<usize>;
#[cfg(not(feature = "parallel"))]
type Iter = std::ops::Range<usize>;
fn maybe_into_par_iter(self) -> Self::Iter {
#[cfg(feature = "parallel")]
{
self.into_par_iter()
}
#[cfg(not(feature = "parallel"))]
{
self.into_iter()
}
}
}