diff --git a/crates/font-awesome-as-a-crate/build.rs b/crates/font-awesome-as-a-crate/build.rs index 7634058c0..0a811a09e 100644 --- a/crates/font-awesome-as-a-crate/build.rs +++ b/crates/font-awesome-as-a-crate/build.rs @@ -1,5 +1,7 @@ use std::{ + collections::HashMap, env, + fmt::Write as FmtWrite, fs::{read_dir, File}, io::{Read, Write}, path::Path, @@ -11,13 +13,26 @@ fn main() { write_fontawesome_sprite(); } +fn capitalize_first_letter(s: &str) -> String { + let mut c = s.chars(); + match c.next() { + None => String::new(), + Some(f) => f.to_uppercase().chain(c).collect(), + } +} + fn write_fontawesome_sprite() { + let mut types = HashMap::new(); let dest_path = Path::new(&env::var("OUT_DIR").unwrap()).join("fontawesome.rs"); let mut dest_file = File::create(dest_path).unwrap(); dest_file .write_all(b"const fn fontawesome_svg(dir:&str,file:&str)->&'static str{match(dir.as_bytes(),file.as_bytes()){") .expect("fontawesome fn write"); - for dirname in &["brands", "regular", "solid"] { + for (dirname, trait_name) in &[ + ("brands", "Brands"), + ("regular", "Regular"), + ("solid", "Solid"), + ] { let dir = read_dir(Path::new("fontawesome-free-6.2.0-desktop/svgs").join(dirname)).unwrap(); let mut data = String::new(); for file in dir { @@ -32,20 +47,45 @@ fn write_fontawesome_sprite() { .expect("fontawesome file read"); // if this assert goes off, add more hashes here and in the format! below assert!(!data.contains("###"), "file {filename} breaks raw string"); + let filename = filename.replace(".svg", ""); dest_file .write_all( - format!( - r####"(b"{dirname}",b"{filename}")=>r#"{data}"#,"####, - data = data, - dirname = dirname, - filename = filename.replace(".svg", ""), - ) - .as_bytes(), + format!(r####"(b"{dirname}",b"{filename}")=>r#"{data}"#,"####).as_bytes(), ) .expect("write fontawesome file"); + types + .entry(filename) + .or_insert_with(|| (data.clone(), Vec::with_capacity(3))) + .1 + .push(trait_name); } } dest_file - .write_all(b"_=>\"\"}}") + .write_all(b"_=>\"\"}} pub mod icons { use super::{IconStr, Regular, Brands, Solid};") .expect("fontawesome fn write"); + + for (icon, (data, kinds)) in types { + let mut type_name = "Icon".to_string(); + type_name.extend(icon.split('-').map(capitalize_first_letter)); + let kinds = kinds.iter().fold(String::new(), |mut acc, k| { + let _ = writeln!(acc, "impl {k} for {type_name} {{}}"); + acc + }); + dest_file + .write_all( + format!( + "\n#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct {type_name}; +impl IconStr for {type_name} {{ + fn icon_name(&self) -> &'static str {{ r#\"{icon}\"# }} + fn icon_str(&self) -> &'static str {{ r#\"{data}\"# }} +}} +{kinds}" + ) + .as_bytes(), + ) + .expect("write fontawesome file types"); + } + + dest_file.write_all(b"}").expect("fontawesome fn write"); } diff --git a/crates/font-awesome-as-a-crate/src/lib.rs b/crates/font-awesome-as-a-crate/src/lib.rs index 16c0297dd..4afab7d18 100644 --- a/crates/font-awesome-as-a-crate/src/lib.rs +++ b/crates/font-awesome-as-a-crate/src/lib.rs @@ -87,6 +87,29 @@ pub const fn svg(type_: Type, name: &str) -> Result<&'static str, NameError> { Ok(svg) } +pub trait IconStr { + /// Name of the icon, like "triangle-exclamation". + fn icon_name(&self) -> &'static str; + /// The SVG content of the icon. + fn icon_str(&self) -> &'static str; +} + +pub trait Brands: IconStr { + fn get_type() -> Type { + Type::Brands + } +} +pub trait Regular: IconStr { + fn get_type() -> Type { + Type::Regular + } +} +pub trait Solid: IconStr { + fn get_type() -> Type { + Type::Solid + } +} + #[cfg(test)] mod tests { const fn usable_as_const_() {