polyfit 0.11.0

Because you don't need to be able to build a powerdrill to use one safely
Documentation
//! Unicode formatting utilities
use std::ops::Range;

use crate::value::Value;

/// Format a floating point number as a string
///
/// # Parameters
/// - `n`: The number to format
/// - `fixed_range`: An optional range specifying the values that will not be formatted in scientific notation
/// - `precision`: The number of decimal places to include
pub fn float<T: Value + std::fmt::LowerExp>(
    n: T,
    fixed_range: Option<Range<T>>,
    precision: usize,
) -> String {
    match fixed_range {
        Some(range) if range.contains(&n) => format!("{n:.precision$}"),
        _ => format!("{n:.precision$e}"),
    }
}

/// Convert a string into a superscript string, ignoring invalid characters
pub fn superscript(s: &str) -> String {
    s.chars().filter_map(to_superscript).collect()
}

/// Convert a string into a subscript string, ignoring invalid characters
pub fn subscript(s: &str) -> String {
    s.chars().filter_map(to_subscript).collect()
}

/// Greek symbols
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u64)]
pub enum Greek {
    /// α
    LowerAlpha = 'α' as u64,

    /// Α
    UpperAlpha = 'Α' as u64,

    /// β
    LowerBeta = 'β' as u64,

    /// Β
    UpperBeta = 'Β' as u64,

    /// γ
    LowerGamma = 'γ' as u64,

    /// Γ
    UpperGamma = 'Γ' as u64,

    /// δ
    LowerDelta = 'δ' as u64,

    /// Δ
    UpperDelta = 'Δ' as u64,

    /// ε
    LowerEpsilon = 'ε' as u64,

    /// Ε
    UpperEpsilon = 'Ε' as u64,

    /// ζ
    LowerZeta = 'ζ' as u64,

    /// Ζ
    UpperZeta = 'Ζ' as u64,
}
impl std::fmt::Display for Greek {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let c = char::from_u32(*self as u32).ok_or(std::fmt::Error)?;
        write!(f, "{c}")
    }
}

fn to_superscript(c: char) -> Option<char> {
    match c {
        '0' => Some(''),
        '1' => Some('¹'),
        '2' => Some('²'),
        '3' => Some('³'),
        '4' => Some(''),
        '5' => Some(''),
        '6' => Some(''),
        '7' => Some(''),
        '8' => Some(''),
        '9' => Some(''),
        '+' => Some(''),
        '-' => Some(''),
        '=' => Some(''),
        '(' => Some(''),
        ')' => Some(''),
        'a' | 'A' => Some(''),
        'b' | 'B' => Some(''),
        'c' | 'C' => Some(''),
        'd' | 'D' => Some(''),
        'e' | 'E' => Some(''),
        'f' | 'F' => Some(''),
        'g' | 'G' => Some(''),
        'h' | 'H' => Some('ʰ'),
        'i' | 'I' => Some(''),
        'j' | 'J' => Some('ʲ'),
        'k' | 'K' => Some(''),
        'l' | 'L' => Some('ˡ'),
        'm' | 'M' => Some(''),
        'n' | 'N' => Some(''),
        'o' | 'O' => Some(''),
        'p' | 'P' => Some(''),
        'r' | 'R' => Some('ʳ'),
        's' | 'S' => Some('ˢ'),
        't' | 'T' => Some(''),
        'u' | 'U' => Some(''),
        'v' | 'V' => Some(''),
        'w' | 'W' => Some('ʷ'),
        'x' | 'X' => Some('ˣ'),
        'y' | 'Y' => Some('ʸ'),
        'z' | 'Z' => Some(''),
        _ => None,
    }
}

fn to_subscript(c: char) -> Option<char> {
    match c {
        '0' => Some(''),
        '1' => Some(''),
        '2' => Some(''),
        '3' => Some(''),
        '4' => Some(''),
        '5' => Some(''),
        '6' => Some(''),
        '7' => Some(''),
        '8' => Some(''),
        '9' => Some(''),
        '+' => Some(''),
        '-' => Some(''),
        '=' => Some(''),
        '(' => Some(''),
        ')' => Some(''),
        'a' | 'A' => Some(''),
        'e' | 'E' => Some(''),
        'h' | 'H' => Some(''),
        'i' | 'I' => Some(''),
        'j' | 'J' => Some(''),
        'k' | 'K' => Some(''),
        'l' | 'L' => Some(''),
        'm' | 'M' => Some(''),
        'n' | 'N' => Some(''),
        'o' | 'O' => Some(''),
        'p' | 'P' => Some(''),
        'r' | 'R' => Some(''),
        's' | 'S' => Some(''),
        't' | 'T' => Some(''),
        'u' | 'U' => Some(''),
        'v' | 'V' => Some(''),
        'x' | 'X' => Some(''),
        _ => None,
    }
}