readsight 1.0.1

Multilingual readability library — 86 languages, 17 formulas, TeX-based syllable counting via the Frank M. Liang algorithm.
Documentation
//! Formula layer: the 17 readability formulas, shared helpers, and registry.

use std::collections::BTreeMap;

use crate::language::Language;
use crate::text::TextStatistics;

pub mod grade_level;
pub mod helper;
pub mod impls;
pub mod registry;

pub use grade_level::GradeLevelInterpretation;
pub use helper::TextStatisticsHelper;
pub use registry::FormulaRegistry;

/// Round `x` to `places` decimal places using half-away-from-zero rounding
/// (matching PHP's `round`).
pub fn round_to(x: f64, places: i32) -> f64 {
    let f = 10f64.powi(places);
    (x * f).round() / f
}

/// Clamp a grade level to `[lo, hi]` after rounding to 1 decimal place.
pub fn grade_clamp(score: f64, lo: f64, hi: f64) -> f64 {
    round_to(score, 1).clamp(lo, hi)
}

/// The result of evaluating a formula.
#[derive(Debug, Clone, PartialEq)]
pub struct FormulaResult {
    /// Formula identifier (e.g. `"gunning_fog"`).
    pub formula_name: String,
    /// Language code the result was computed for.
    pub language_code: String,
    /// The (rounded) score.
    pub score: f64,
    /// Optional grade level, when the formula produces one.
    pub grade_level: Option<f64>,
    /// Human-readable interpretation band.
    pub interpretation: String,
    /// Debug inputs (integers stored as `f64`).
    pub inputs: BTreeMap<String, f64>,
}

/// A readability formula.
pub trait Formula {
    /// Formula identifier.
    fn name(&self) -> &'static str;
    /// Human-readable description.
    fn description(&self) -> &'static str;
    /// Language codes this formula supports; `["*"]` means all.
    fn supported_languages(&self) -> &'static [&'static str];
    /// Evaluate the formula over `stats` for `language`.
    fn calculate(&self, stats: &TextStatistics, language: &Language) -> FormulaResult;
}

/// Convenience builder for the `inputs` map.
pub(crate) fn inputs(pairs: &[(&str, f64)]) -> BTreeMap<String, f64> {
    pairs.iter().map(|(k, v)| (k.to_string(), *v)).collect()
}