Skip to content

Commit

Permalink
Add crate attribute to hot_module proc-macro
Browse files Browse the repository at this point in the history
Make it possible for users to specify what crate name is inside
the generated module code.

This allow usage with aliases crate name
and re-export hot-lib-reloader-rs from another crate
  • Loading branch information
izissise committed Feb 3, 2023
1 parent 8abc03d commit efdde61
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 13 deletions.
21 changes: 21 additions & 0 deletions macro/src/hot_module/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) struct HotModuleAttribute {
pub(crate) lib_name: syn::Expr,
pub(crate) lib_dir: syn::Expr,
pub(crate) file_watch_debounce_ms: syn::LitInt,
pub(crate) crate_name: syn::Path,
}

// Parses something like `#[hot(name = "lib")]`.
Expand All @@ -14,6 +15,7 @@ impl syn::parse::Parse for HotModuleAttribute {
let mut lib_name = None;
let mut lib_dir = None;
let mut file_watch_debounce_ms = None;
let mut crate_name = None;

let args = Punctuated::<syn::Expr, token::Comma>::parse_separated_nonempty(stream)?;

Expand Down Expand Up @@ -49,6 +51,19 @@ impl syn::parse::Parse for HotModuleAttribute {
continue;
}

expr if expr_is_ident(&left, "crate") => {
let span = expr.span().clone();
let s = match match expr {
syn::Expr::Lit(syn::ExprLit { lit, .. }) => lit,
_ => return Err(Error::new(left.span(), "unexpected expression type")),
} {
syn::Lit::Str(s) => s,
_ => return Err(Error::new(span, "unexpected expression type")),
};
crate_name = Some(s.parse::<syn::Path>().clone()?);
continue;
}

_ => return Err(Error::new(left.span(), "unexpected attribute name")),
},

Expand Down Expand Up @@ -82,10 +97,16 @@ impl syn::parse::Parse for HotModuleAttribute {
Some(file_watch_debounce_ms) => file_watch_debounce_ms,
};

let crate_name = match crate_name {
None => syn::parse_quote! { ::hot_lib_reloader },
Some(crate_name) => crate_name,
};

Ok(HotModuleAttribute {
lib_name,
lib_dir,
file_watch_debounce_ms,
crate_name,
})
}
}
19 changes: 10 additions & 9 deletions macro/src/hot_module/code_gen.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use proc_macro2::Span;
use syn::{token, Expr, FnArg, ItemFn, LitByteStr, LitStr, Result, VisPublic, Visibility};
use syn::{token, Expr, Path, FnArg, ItemFn, LitByteStr, LitStr, Result, VisPublic, Visibility};
use syn::{ForeignItemFn, LitInt};

use crate::util::ident_from_pat;
Expand All @@ -8,13 +8,14 @@ pub(crate) fn generate_lib_loader_items(
lib_dir: &Expr,
lib_name: &Expr,
file_watch_debounce_ms: &LitInt,
crate_name: &Path,
span: Span,
) -> Result<proc_macro2::TokenStream> {
let result = quote::quote_spanned! {span=>
static mut LIB_CHANGE_NOTIFIER: Option<::std::sync::Arc<::std::sync::RwLock<::hot_lib_reloader::LibReloadNotifier>>> = None;
static mut LIB_CHANGE_NOTIFIER: Option<::std::sync::Arc<::std::sync::RwLock<#crate_name::LibReloadNotifier>>> = None;
static LIB_CHANGE_NOTIFIER_INIT: ::std::sync::Once = ::std::sync::Once::new();

fn __lib_notifier() -> ::std::sync::Arc<::std::sync::RwLock<::hot_lib_reloader::LibReloadNotifier>> {
fn __lib_notifier() -> ::std::sync::Arc<::std::sync::RwLock<#crate_name::LibReloadNotifier>> {
LIB_CHANGE_NOTIFIER_INIT.call_once(|| {
let notifier = ::std::sync::Arc::new(::std::sync::RwLock::new(Default::default()));
// Safety: guarded by Once, will only be called one time.
Expand All @@ -28,7 +29,7 @@ pub(crate) fn generate_lib_loader_items(
unsafe { LIB_CHANGE_NOTIFIER.as_ref().cloned().unwrap() }
}

fn __lib_loader_subscription() -> ::hot_lib_reloader::LibReloadObserver {
fn __lib_loader_subscription() -> #crate_name::LibReloadObserver {
// Make sure that LIB_LOADER_INIT ran and the change messages are
// live, otherwise we would not get lib updates if none of the hot
// functions are called.
Expand All @@ -39,17 +40,17 @@ pub(crate) fn generate_lib_loader_items(
.subscribe()
}

static mut LIB_LOADER: Option<::std::sync::Arc<::std::sync::RwLock<::hot_lib_reloader::LibReloader>>> = None;
static mut LIB_LOADER: Option<::std::sync::Arc<::std::sync::RwLock<#crate_name::LibReloader>>> = None;
static LIB_LOADER_INIT: ::std::sync::Once = ::std::sync::Once::new();

// version counter that counts the reloads
static VERSION: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
// for simple queries
static WAS_UPDATED: ::std::sync::atomic::AtomicBool = ::std::sync::atomic::AtomicBool::new(false);

fn __lib_loader() -> ::std::sync::Arc<::std::sync::RwLock<::hot_lib_reloader::LibReloader>> {
fn __lib_loader() -> ::std::sync::Arc<::std::sync::RwLock<#crate_name::LibReloader>> {
LIB_LOADER_INIT.call_once(|| {
let mut lib_loader = ::hot_lib_reloader::LibReloader::new(#lib_dir, #lib_name, Some(::std::time::Duration::from_millis(#file_watch_debounce_ms)))
let mut lib_loader = #crate_name::LibReloader::new(#lib_dir, #lib_name, Some(::std::time::Duration::from_millis(#file_watch_debounce_ms)))
.expect("failed to create hot reload loader");

let change_rx = lib_loader.subscribe_to_file_changes();
Expand All @@ -72,14 +73,14 @@ pub(crate) fn generate_lib_loader_items(
if let Ok(mut lib_loader) = lib_loader_for_update.try_write() {
if let Some(first_lock_attempt) = first_lock_attempt {
let duration: ::std::time::Duration = first_lock_attempt - ::std::time::Instant::now();
::hot_lib_reloader::LibReloader::log_info(&format!("...got write lock after {}ms!", duration.as_millis()));
#crate_name::LibReloader::log_info(&format!("...got write lock after {}ms!", duration.as_millis()));
}
let _ = !lib_loader.update().expect("hot lib update()");
break;
}
if first_lock_attempt.is_none() {
first_lock_attempt = Some(::std::time::Instant::now());
::hot_lib_reloader::LibReloader::log_info("trying to get a write lock...");
#crate_name::LibReloader::log_info("trying to get a write lock...");
}
::std::thread::sleep(::std::time::Duration::from_millis(1));
}
Expand Down
3 changes: 2 additions & 1 deletion macro/src/hot_module/module_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,14 @@ impl quote::ToTokens for HotModule {
lib_name,
lib_dir,
file_watch_debounce_ms,
crate_name,
} = match hot_module_args {
None => panic!("Expected to have macro attributes"),
Some(attributes) => attributes,
};

let lib_loader =
generate_lib_loader_items(lib_dir, lib_name, file_watch_debounce_ms, tokens.span())
generate_lib_loader_items(lib_dir, lib_name, file_watch_debounce_ms, crate_name, tokens.span())
.expect("error generating hot lib loader helpers");

let module_def = quote::quote! {
Expand Down
8 changes: 5 additions & 3 deletions tests/lib-loader-test.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod common;

#[hot_lib_reloader::hot_module(dylib = "lib_for_testing", file_watch_debounce = 50)]
use hot_lib_reloader as hlibr_crate_alias;

#[hlibr_crate_alias::hot_module(dylib = "lib_for_testing", file_watch_debounce = 50, crate = "super::hlibr_crate_alias")]
mod hot_lib {
hot_functions_from_file!("tests/lib_for_testing/src/lib.rs");

#[lib_change_subscription]
pub fn subscribe() -> hot_lib_reloader::LibReloadObserver {}
pub fn subscribe() -> super::hlibr_crate_alias::LibReloadObserver {}

#[lib_version]
pub fn version() -> usize {}
Expand Down Expand Up @@ -57,7 +59,7 @@ fn test() {
// wait for reload to be completed
lib_observer.wait_for_reload();

// make rue lib is new
// make sure lib is new
let n = hot_lib::do_more_stuff(Box::new(hot_lib::do_stuff));
assert_eq!(n, 7);
assert_eq!(hot_lib::version(), 1);
Expand Down

0 comments on commit efdde61

Please sign in to comment.