diff --git a/markup-proc-macro/Cargo.toml b/markup-proc-macro/Cargo.toml index 7a39e27..af288a9 100644 --- a/markup-proc-macro/Cargo.toml +++ b/markup-proc-macro/Cargo.toml @@ -16,3 +16,9 @@ proc-macro = true proc-macro2 = "1.0.3" quote = "1.0.2" syn = { version = "1.0.5", features = ["extra-traits", "full"] } +sha2 = { version = "0.8", optional = true } +dirs = { version = "2.0.2", optional = true } +version = { version = "3.0.0", optional = true } + +[features] +caching = ["sha2", "dirs", "version"] diff --git a/markup-proc-macro/src/caching.rs b/markup-proc-macro/src/caching.rs new file mode 100644 index 0000000..22fc9d9 --- /dev/null +++ b/markup-proc-macro/src/caching.rs @@ -0,0 +1,35 @@ +use proc_macro::TokenStream; + +#[cfg(not(feature = "caching"))] +pub fn cached(tokens: TokenStream, f: impl FnOnce(TokenStream) -> TokenStream) -> TokenStream { + f(tokens) +} + +#[cfg(feature = "caching")] +pub fn cached(tokens: TokenStream, f: impl FnOnce(TokenStream) -> TokenStream) -> TokenStream { + use sha2::{Digest, Sha256}; + use std::fs; + + let dir = dirs::cache_dir().unwrap().join("markup-rs"); + let _ = fs::create_dir(&dir); + let dir = dir.join(version::version!().to_string()); + let _ = fs::create_dir(&dir); + + let input = tokens.to_string(); + let mut hasher = Sha256::new(); + hasher.input(input); + let hash = hasher.result(); + let path = dir.join(format!("{:x}", hash)); + + if let Ok(cached) = fs::read_to_string(&path) { + if let Ok(cached) = cached.parse() { + return cached; + } + } + + let output = f(tokens); + if fs::write(&path, output.to_string()).is_err() { + eprintln!("warning: cannot write to cache dir"); + } + output +} diff --git a/markup-proc-macro/src/lib.rs b/markup-proc-macro/src/lib.rs index 045c574..24562ea 100644 --- a/markup-proc-macro/src/lib.rs +++ b/markup-proc-macro/src/lib.rs @@ -2,11 +2,16 @@ extern crate proc_macro; mod ast; +mod caching; mod generate; mod parse; +use proc_macro::TokenStream; + #[proc_macro] -pub fn define(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { - let structs = syn::parse_macro_input!(tokens as parse::Many).0; - quote::quote!( #(#structs)* ).into() +pub fn define(tokens: TokenStream) -> TokenStream { + caching::cached(tokens, |tokens| { + let structs = syn::parse_macro_input!(tokens as parse::Many).0; + quote::quote!( #(#structs)* ).into() + }) } diff --git a/markup/Cargo.toml b/markup/Cargo.toml index 9865719..9511ee4 100644 --- a/markup/Cargo.toml +++ b/markup/Cargo.toml @@ -14,3 +14,6 @@ categories = ["template-engine"] [dependencies] markup-proc-macro = { path = "../markup-proc-macro", version = "0.4.0" } + +[features] +caching = ["markup-proc-macro/caching"]