1- use std:: {
2- collections:: HashMap ,
3- env,
4- fmt:: Write as FmtWrite ,
5- fs:: { read_dir, File } ,
6- io:: { Read , Write } ,
7- path:: Path ,
8- } ;
1+ use proc_macro2:: Literal ;
2+ use quote:: { format_ident, quote} ;
3+ use std:: { collections:: HashMap , env, fs, path:: Path } ;
94
105fn main ( ) {
116 println ! ( "cargo::rustc-check-cfg=cfg(font_awesome_out_dir)" ) ;
@@ -22,70 +17,91 @@ fn capitalize_first_letter(s: &str) -> String {
2217}
2318
2419fn write_fontawesome_sprite ( ) {
20+ let mut match_arms = vec ! [ ] ;
2521 let mut types = HashMap :: new ( ) ;
26- let dest_path = Path :: new ( & env:: var ( "OUT_DIR" ) . unwrap ( ) ) . join ( "fontawesome.rs" ) ;
27- let mut dest_file = File :: create ( dest_path) . unwrap ( ) ;
28- dest_file
29- . write_all ( b"const fn fontawesome_svg(dir:&str,file:&str)->&'static str{match(dir.as_bytes(),file.as_bytes()){" )
30- . expect ( "fontawesome fn write" ) ;
22+
3123 for ( dirname, trait_name) in & [
3224 ( "brands" , "Brands" ) ,
3325 ( "regular" , "Regular" ) ,
3426 ( "solid" , "Solid" ) ,
3527 ] {
36- let dir = read_dir ( Path :: new ( "fontawesome-free-6.2.0-desktop/svgs" ) . join ( dirname) ) . unwrap ( ) ;
37- let mut data = String :: new ( ) ;
28+ let dir =
29+ fs:: read_dir ( Path :: new ( "fontawesome-free-6.2.0-desktop/svgs" ) . join ( dirname) ) . unwrap ( ) ;
30+
3831 for file in dir {
3932 let file = file. expect ( "fontawesome directory access" ) ;
33+ let data = fs:: read_to_string ( file. path ( ) ) . expect ( "fontawesome file read" ) ;
34+
4035 let filename = file
4136 . file_name ( )
4237 . into_string ( )
43- . expect ( "fontawesome filenames are unicode" ) ;
44- let mut file = File :: open ( file. path ( ) ) . expect ( "fontawesome file access" ) ;
45- data. clear ( ) ;
46- file. read_to_string ( & mut data)
47- . expect ( "fontawesome file read" ) ;
48- // if this assert goes off, add more hashes here and in the format! below
49- assert ! ( !data. contains( "###" ) , "file {filename} breaks raw string" ) ;
50- let filename = filename. replace ( ".svg" , "" ) ;
51- dest_file
52- . write_all (
53- format ! ( r####"(b"{dirname}",b"{filename}")=>r#"{data}"#,"#### ) . as_bytes ( ) ,
54- )
55- . expect ( "write fontawesome file" ) ;
38+ . expect ( "fontawesome filenames are unicode" )
39+ . replace ( ".svg" , "" ) ;
40+
41+ let dirname_literal = Literal :: byte_string ( dirname. as_bytes ( ) ) ;
42+ let filename_literal = Literal :: byte_string ( filename. as_bytes ( ) ) ;
43+ match_arms. push ( quote ! {
44+ ( #dirname_literal, #filename_literal) => #data,
45+ } ) ;
46+
5647 types
5748 . entry ( filename)
5849 . or_insert_with ( || ( data. clone ( ) , Vec :: with_capacity ( 3 ) ) )
5950 . 1
6051 . push ( trait_name) ;
6152 }
6253 }
63- dest_file
64- . write_all ( b"_=>\" \" }} pub mod icons { use super::{IconStr, Regular, Brands, Solid};" )
65- . expect ( "fontawesome fn write" ) ;
54+
55+ let mut types_output = vec ! [ ] ;
6656
6757 for ( icon, ( data, kinds) ) in types {
6858 let mut type_name = "Icon" . to_string ( ) ;
6959 type_name. extend ( icon. split ( '-' ) . map ( capitalize_first_letter) ) ;
70- let kinds = kinds. iter ( ) . fold ( String :: new ( ) , |mut acc, k| {
71- let _ = writeln ! ( acc, "impl {k} for {type_name} {{}}" ) ;
72- acc
60+ let type_name = format_ident ! ( "{}" , type_name) ;
61+
62+ let kind_impls: Vec < _ > = kinds
63+ . iter ( )
64+ . map ( |k| {
65+ let k = format_ident ! ( "{}" , k) ;
66+ quote ! {
67+ impl #k for #type_name { }
68+ }
69+ } )
70+ . collect ( ) ;
71+
72+ types_output. push ( quote ! {
73+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
74+ pub struct #type_name;
75+
76+ impl IconStr for #type_name {
77+ fn icon_name( & self ) -> & ' static str { #icon }
78+ fn icon_str( & self ) -> & ' static str { #data }
79+ }
80+
81+ #( #kind_impls) *
7382 } ) ;
74- dest_file
75- . write_all (
76- format ! (
77- "\n #[derive(Debug, Clone, Copy, PartialEq, Eq)]
78- pub struct {type_name};
79- impl IconStr for {type_name} {{
80- fn icon_name(&self) -> &'static str {{ r#\" {icon}\" # }}
81- fn icon_str(&self) -> &'static str {{ r#\" {data}\" # }}
82- }}
83- {kinds}"
84- )
85- . as_bytes ( ) ,
86- )
87- . expect ( "write fontawesome file types" ) ;
8883 }
8984
90- dest_file. write_all ( b"}" ) . expect ( "fontawesome fn write" ) ;
85+ let token_stream = quote ! {
86+ const fn fontawesome_svg( dir: & str , file: & str ) -> & ' static str {
87+ // we are using byte literals to match because they can be evaluated in a
88+ // `const` context, and `str` cannot.
89+ match ( dir. as_bytes( ) , file. as_bytes( ) ) {
90+ #( #match_arms) *
91+ _=> ""
92+ }
93+ }
94+
95+ pub mod icons {
96+ use super :: { IconStr , Regular , Brands , Solid } ;
97+
98+ #( #types_output) *
99+ }
100+ } ;
101+
102+ let dest_path = Path :: new ( & env:: var ( "OUT_DIR" ) . unwrap ( ) ) . join ( "fontawesome.rs" ) ;
103+
104+ let output = prettyplease:: unparse ( & syn:: parse2 ( token_stream) . unwrap ( ) ) ;
105+
106+ fs:: write ( & dest_path, output. as_bytes ( ) ) . expect ( "fontawesome output write" ) ;
91107}
0 commit comments