badgelib 0.4.0

A library for generating badges in Rust
Documentation
use std::fs;
use std::path::Path;

use rayon::prelude::*;
use rusttype::{Font, Scale, point};

fn calc_width(font: &Font<'_>, text: &str, size: f32) -> f32 {
  font
    .layout(text, Scale { x: size * 1.15, y: size }, point(0.0, 0.0))
    .map(|glyph| glyph.position().x + glyph.unpositioned().h_metrics().advance_width)
    .last()
    .unwrap_or(0.0)
}

fn generate_widths(font_path: &Path) -> Result<String, String> {
  let font_data = fs::read(font_path)
    .map_err(|error| format!("failed to read {}: {error}", font_path.display()))?;
  let font = Font::try_from_vec(font_data)
    .ok_or_else(|| format!("failed to parse font data from {}", font_path.display()))?;
  let size = 110.0;
  let widths = (0..2u32.pow(13))
    .into_par_iter()
    .map(|codepoint| {
      if codepoint <= 32 || codepoint == 127 {
        0.0
      } else {
        let character = char::from_u32(codepoint).expect("width-table codepoint must be valid");
        calc_width(&font, &character.to_string(), size)
      }
    })
    .collect::<Vec<_>>();
  Ok(format!("pub(crate) static WIDTHS: [f32; 8192] = {widths:?};"))
}

fn run() -> Result<(), String> {
  let root = Path::new(env!("CARGO_MANIFEST_DIR"));
  let output = root.join("src/_width.rs");
  let body = generate_widths(&root.join("vendor/DejaVuSans.ttf"))?;
  let code = format!("// This file is generated by scripts/update-widths.rs\n{body}\n");
  fs::write(&output, code)
    .map_err(|error| format!("failed to write {}: {error}", output.display()))?;
  println!("Generated 8,192 font widths");
  Ok(())
}

fn main() {
  if let Err(error) = run() {
    eprintln!("Font-width update failed: {error}");
    std::process::exit(1);
  }
}