use proc_macro::TokenStream;
use quote::quote;
const WIT_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/wit");
#[proc_macro_attribute]
pub fn redis_subscriber(_attr: TokenStream, item: TokenStream) -> TokenStream {
let func = syn::parse_macro_input!(item as syn::ItemFn);
let func_name = &func.sig.ident;
if func.sig.asyncness.is_none() {
return syn::Error::new_spanned(
func.sig.fn_token,
"the `#[redis_subscriber]` function must be `async`",
)
.to_compile_error()
.into();
}
quote!(
#func
mod __spin_redis {
mod preamble {
#![allow(missing_docs)]
::spin_sdk::wit_bindgen::generate!({
world: "spin-sdk-macro-redis-trigger",
path: #WIT_PATH,
runtime_path: "::spin_sdk::wit_bindgen::rt",
generate_all,
});
pub struct Spin;
export!(Spin);
}
impl self::preamble::exports::spin::redis::inbound_redis::Guest for preamble::Spin {
async fn handle_message(msg: self::preamble::exports::spin::redis::inbound_redis::Payload) -> Result<(), self::preamble::spin::redis::redis::Error> {
match super::#func_name(msg.try_into().expect("cannot convert from Spin Redis payload")).await {
Ok(()) => Ok(()),
Err(e) => {
eprintln!("{}", e);
Err(self::preamble::spin::redis::redis::Error::Other(e.to_string()))
},
}
}
}
}
)
.into()
}
#[proc_macro_attribute]
pub fn http_service(_attr: TokenStream, item: TokenStream) -> TokenStream {
let func = syn::parse_macro_input!(item as syn::ItemFn);
if func.sig.asyncness.is_none() {
return syn::Error::new_spanned(
func.sig.fn_token,
"the `#[http_service]` function must be `async`",
)
.to_compile_error()
.into();
}
let func_name = &func.sig.ident;
quote!(
#func
mod __spin_wasip3_http {
use ::spin_sdk::http::IntoResponse;
struct Spin;
::spin_sdk::wasip3::http::service::export!(Spin);
impl ::spin_sdk::wasip3::exports::http::handler::Guest for self::Spin {
async fn handle(request: ::spin_sdk::wasip3::http::types::Request) -> Result<::spin_sdk::wasip3::http::types::Response, ::spin_sdk::wasip3::http::types::ErrorCode> {
let request = <::spin_sdk::http::Request as ::spin_sdk::http::FromRequest>::from_request(request)?;
::spin_sdk::http::IntoResponse::into_response(super::#func_name(request).await)
}
}
}
)
.into()
}
#[proc_macro]
pub fn dependencies(item: TokenStream) -> TokenStream {
if !item.is_empty() {
return syn::Error::new(
proc_macro2::Span::call_site(),
"the `dependencies!` macro does not take any arguments",
)
.to_compile_error()
.into();
}
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let wit_path = std::path::Path::new(&manifest_dir).join("spin-dependencies.wit");
if !wit_path.exists() {
return TokenStream::new();
}
let wit_path_str = wit_path.to_str().expect("path is not valid UTF-8");
quote!(
::spin_sdk::wit_bindgen::generate!({
path: #wit_path_str,
world: "root",
runtime_path: "::spin_sdk::wit_bindgen::rt",
generate_all,
});
)
.into()
}