Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion witchcraft-server-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,49 @@ use syn::{Error, ItemFn};
/// witchcraft_server::init(inner_main)
/// }
/// ```
///
/// Async functions are also supported:
///
/// ```ignore
/// use conjure_error::Error;
/// use witchcraft_server::config::install::InstallConfig;
/// use witchcraft_server::config::runtime::RuntimeConfig;
/// use witchcraft_server::Witchcraft;
/// use refreshable::Refreshable;
///
/// #[witchcraft_server::main]
/// async fn main(
/// install: InstallConfig,
/// runtime: Refreshable<RuntimeConfig, Error>,
/// wc: &mut Witchcraft,
/// ) -> Result<(), Error> {
/// // initialization code...
/// Ok(())
/// }
/// ```
///
/// Expands to:
///
/// ```ignore
/// use conjure_error::Error;
/// use witchcraft_server::config::install::InstallConfig;
/// use witchcraft_server::config::runtime::RuntimeConfig;
/// use witchcraft_server::Witchcraft;
/// use refreshable::Refreshable;
///
/// fn main() {
/// async fn inner_main(
/// install: InstallConfig,
/// runtime: Refreshable<RuntimeConfig, Error>,
/// wc: &mut Witchcraft,
/// ) -> Result<(), Error> {
/// // initialization code...
/// Ok(())
/// }
///
/// witchcraft_server::init_async(inner_main)
/// }
/// ```
#[proc_macro_attribute]
pub fn main(args: TokenStream, input: TokenStream) -> TokenStream {
if !args.is_empty() {
Expand All @@ -84,11 +127,16 @@ pub fn main(args: TokenStream, input: TokenStream) -> TokenStream {
let vis = &function.vis;
let name = &function.sig.ident;

let init = match function.sig.asyncness {
Some(_) => quote!(init_async),
None => quote!(init),
};

quote! {
#vis fn #name() {
#function

witchcraft_server::init(#name)
witchcraft_server::#init(#name)
}
}
.into()
Expand Down
62 changes: 60 additions & 2 deletions witchcraft-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,20 @@
//!
//! The entrypoint of a Witchcraft server is an initialization function annotated with `#[witchcraft_server::main]`:
//!
//! ```ignore
//! ```no_run
//! use conjure_error::Error;
//! use refreshable::Refreshable;
//! use witchcraft_server::Witchcraft;
//! use witchcraft_server::config::install::InstallConfig;
//! use witchcraft_server::config::runtime::RuntimeConfig;
//!
//! #[witchcraft_server::main]
//! fn main(
//! install: InstallConfig,
//! runtime: Refreshable<RuntimeConfig>,
//! runtime: Refreshable<RuntimeConfig, Error>,
//! wc: &mut Witchcraft,
//! ) -> Result<(), Error> {
//! # #[cfg(any())]
//! wc.api(CustomApiEndpoints::new(CustomApiResource));
//!
//! Ok(())
Expand All @@ -38,6 +40,28 @@
//! The function is provided with the server's install and runtime configuration, as well as the [`Witchcraft`] object
//! which can be used to configure the server. Once the initialization function returns, the server will start.
//!
//! Async init functions are also supported:
//!
//! ```no_run
//! use conjure_error::Error;
//! use refreshable::Refreshable;
//! use witchcraft_server::Witchcraft;
//! use witchcraft_server::config::install::InstallConfig;
//! use witchcraft_server::config::runtime::RuntimeConfig;
//!
//! #[witchcraft_server::main]
//! async fn main(
//! install: InstallConfig,
//! runtime: Refreshable<RuntimeConfig, Error>,
//! wc: &mut Witchcraft,
//! ) -> Result<(), Error> {
//! # #[cfg(any())]
//! wc.api(CustomApiEndpoints::new(CustomApiResource));
//!
//! Ok(())
//! }
//! ```
//!
//! ## Note
//!
//! The initialization function is expected to return quickly - any long-running work required should happen in the
Expand Down Expand Up @@ -374,6 +398,18 @@ where
init_with_configs(init, configs::load_install::<I>, configs::load_runtime::<R>)
}

/// Initializes a Witchcraft server.
///
/// This is equivalent to [`init`], except that it takes an asynchronous init function.
pub fn init_async<I, R, F>(init_async: F)
where
I: AsRef<InstallConfig> + DeserializeOwned,
R: AsRef<RuntimeConfig> + DeserializeOwned + PartialEq + 'static + Sync + Send,
F: AsyncFnOnce(I, Refreshable<R, Error>, &mut Witchcraft) -> Result<(), Error>,
{
init(|install, runtime, wc| wc.handle.clone().block_on(init_async(install, runtime, wc)))
}

/// Initializes a Witchcraft server with custom config loaders.
///
/// `init` is invoked with the install and runtime configs from the provided loaders as well as the [`Witchcraft`]
Expand Down Expand Up @@ -401,6 +437,28 @@ where
process::exit(ret);
}

/// Initializes a Witchcraft server with custom config loaders.
///
/// This is equivalent to [`init_with_configs`] except that it takes an asynchrnous init function.
pub fn init_with_configs_async<I, R, F, LI, LR>(init_async: F, load_install: LI, load_runtime: LR)
where
I: AsRef<InstallConfig> + DeserializeOwned,
R: AsRef<RuntimeConfig> + DeserializeOwned + PartialEq + 'static + Sync + Send,
F: AsyncFnOnce(I, Refreshable<R, Error>, &mut Witchcraft) -> Result<(), Error>,
LI: FnOnce() -> Result<I, Error>,
LR: FnOnce(&Handle, &Arc<AtomicBool>) -> Result<Refreshable<R, Error>, Error>,
{
init_with_configs(
|install, runtime, wc| {
wc.handle()
.clone()
.block_on(init_async(install, runtime, wc))
},
load_install,
load_runtime,
);
}

fn init_inner<I, R, F, LI, LR>(
init: F,
load_install: LI,
Expand Down