static_file_http_server_macros/
lib.rs1extern crate proc_macro;
2
3use proc_macro::{TokenStream, TokenTree};
4use std::{env, fmt::Display, fs, path::PathBuf};
5
6fn git_sbp_url(sub_uri: &impl ToString) -> String {
7 format!(
8 "https://raw.githubusercontent.com/devraymondsh/static-file-http-server/v{}/single-binary-producer/{}",
9 env::var("CARGO_PKG_VERSION").unwrap(),
10 sub_uri.to_string()
11 )
12}
13fn download_from_repo(sub_uri: &(impl ToString + Display)) -> String {
14 String::from_utf8_lossy(
15 &reqwest::blocking::get(git_sbp_url(sub_uri))
16 .unwrap()
17 .bytes()
18 .unwrap(),
19 )
20 .to_string()
21}
22
23const MAIN_RS_ORIGINAL_PATH: &str = concat!(
24 env!("CARGO_MANIFEST_DIR"),
25 "/../single-binary-producer/src/main.rs"
26);
27const CARGO_TOML_ORIGINAL_PATH: &str = concat!(
28 env!("CARGO_MANIFEST_DIR"),
29 "/../single-binary-producer/Cargo.toml"
30);
31
32fn get_main_rs_path() -> String {
33 if PathBuf::from(MAIN_RS_ORIGINAL_PATH).exists() {
34 let main_rs_contents = fs::read_to_string(MAIN_RS_ORIGINAL_PATH).unwrap();
35 main_rs_contents
36 } else {
37 download_from_repo(&"src/main.rs")
38 }
39}
40fn get_cargo_toml_path() -> String {
41 if PathBuf::from(CARGO_TOML_ORIGINAL_PATH).exists() {
42 let cargo_toml_contents = fs::read_to_string(CARGO_TOML_ORIGINAL_PATH).unwrap();
43 cargo_toml_contents
44 } else {
45 download_from_repo(&"Cargo.toml")
46 }
47}
48fn quote(name: impl ToString, contents: impl ToString) -> TokenStream {
49 format!(
50 "const {}: &str = r#\"{}\"#;",
51 name.to_string(),
52 contents.to_string()
53 )
54 .parse()
55 .unwrap()
56}
57
58fn parse_input(input: TokenStream) -> String {
59 match &input.into_iter().collect::<Vec<_>>()[0] {
60 TokenTree::Literal(lit) => {
61 let mut repr = lit.to_string();
62 if !repr.starts_with('"') || !repr.ends_with('"') {
63 panic!("This macro only accepts a single, non-empty string argument")
64 }
65
66 repr.remove(0);
67 repr.pop();
68
69 repr
70 }
71 _ => panic!("This macro only accepts a single, non-empty string argument"),
72 }
73}
74
75#[proc_macro]
76pub fn get_sbp_main_rs(input: TokenStream) -> TokenStream {
77 let contents = get_main_rs_path();
78 let name = parse_input(input);
79
80 quote(name, contents)
81}
82
83#[proc_macro]
84pub fn get_sbp_cargo_toml(input: TokenStream) -> TokenStream {
85 let contents = get_cargo_toml_path();
86 let name = parse_input(input);
87
88 quote(name, contents)
89}