use proc_macro::TokenStream;
use proc_macro_error2::abort_call_site;
use proc_macro_error2::proc_macro_error;
use syn::{parse_macro_input, ItemFn, ItemMod};
#[cfg(feature = "runtime")]
use syn::ReturnType;
use crate::utils::{fn_macro, is_module, lock_macro, mod_macro};
mod env;
#[cfg(feature = "executable")]
mod executable;
mod file;
#[cfg(feature = "http")]
mod http;
#[cfg(feature = "icmp")]
mod icmp;
#[cfg(feature = "resource")]
mod resource;
#[cfg(feature = "runtime")]
mod runtime;
mod socket;
#[cfg(feature = "timezone")]
mod timezone;
#[cfg(feature = "user")]
mod user;
mod utils;
#[proc_macro_attribute]
#[proc_macro_error]
pub fn env(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
env::check_env_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
env::check_env_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_env(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_env(attr: TokenStream, stream: TokenStream) -> TokenStream {
env::runtime_env(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn no_env(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
env::check_no_env_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
env::check_no_env_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_no_env(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_no_env(attr: TokenStream, stream: TokenStream) -> TokenStream {
env::runtime_no_env(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn file(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
file::check_file_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
file::check_file_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_file(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_file(attr: TokenStream, stream: TokenStream) -> TokenStream {
file::runtime_file(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn path(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
file::check_path_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
file::check_path_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_path(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_path(attr: TokenStream, stream: TokenStream) -> TokenStream {
file::runtime_path(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "http")]
pub fn http(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
http::check_http_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
http::check_http_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_http(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "http"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_http(attr: TokenStream, stream: TokenStream) -> TokenStream {
http::runtime_http(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "http")]
pub fn https(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
http::check_https_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
http::check_https_condition,
)
}
}
#[cfg(all(not(feature = "runtime"), feature = "http"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_https(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "http"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_https(attr: TokenStream, stream: TokenStream) -> TokenStream {
http::runtime_https(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "icmp")]
pub fn icmp(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
icmp::check_icmp_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
icmp::check_icmp_condition,
)
}
}
#[cfg(all(not(feature = "runtime"), feature = "icmp"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_icmp(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "icmp"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStream {
icmp::runtime_icmp(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn tcp(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
socket::check_tcp_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
socket::check_tcp_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_tcp(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_tcp(attr: TokenStream, stream: TokenStream) -> TokenStream {
socket::runtime_tcp(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(all(feature = "user"))]
pub fn root(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
user::check_root_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
user::check_root_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_root(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "user"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_root(attr: TokenStream, stream: TokenStream) -> TokenStream {
user::runtime_root(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(all(feature = "user"))]
pub fn group(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
user::check_group_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
user::check_group_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_group(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "user"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_group(attr: TokenStream, stream: TokenStream) -> TokenStream {
user::runtime_group(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(all(feature = "user", not(target_os = "windows")))]
pub fn user(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
user::check_user_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
user::check_user_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_user(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "user"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_user(attr: TokenStream, stream: TokenStream) -> TokenStream {
user::runtime_user(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "resource")]
pub fn mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
resource::check_mem_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
resource::check_mem_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
resource::runtime_mem(attr, stream)
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_free_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_free_mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
resource::runtime_free_mem(attr, stream)
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_available_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_available_mem(attr: TokenStream, stream: TokenStream) -> TokenStream {
resource::runtime_available_mem(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "resource")]
pub fn swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
resource::check_swap_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
resource::check_swap_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_swap(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
let swap_limitation_str = attr.to_string().replace(' ', "");
if byte_unit::Byte::parse_str(&swap_limitation_str, true).is_err() {
abort_call_site!("swap size description is not correct")
}
let ItemFn {
attrs,
vis,
sig,
block,
} = parse_macro_input!(stream as ItemFn);
let syn::Signature { ident, .. } = sig.clone();
let check_ident = syn::Ident::new(&format!("_check_{ident}"), proc_macro2::Span::call_site());
let check_fn = match (&sig.asyncness, &sig.output) {
(Some(_), ReturnType::Default) => quote::quote! {
async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
let sys = test_with::sysinfo::System::new_with_specifics(
test_with::sysinfo::RefreshKind::nothing().with_memory(test_with::sysinfo::MemoryRefreshKind::nothing().with_swap()),
);
let swap_size = match test_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) {
Ok(b) => b,
Err(_) => panic!("system swap size can not get"),
};
let swap_size_limitation = test_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct");
if swap_size >= swap_size_limitation {
#ident().await;
Ok(test_with::Completion::Completed)
} else {
Ok(test_with::Completion::ignored_with(format!("because the swap less than {}", #swap_limitation_str)))
}
}
},
(Some(_), ReturnType::Type(_, _)) => quote::quote! {
async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
let sys = test_with::sysinfo::System::new_with_specifics(
test_with::sysinfo::RefreshKind::nothing().with_memory(test_with::sysinfo::MemoryRefreshKind::nothing().with_swap()),
);
let swap_size = match test_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) {
Ok(b) => b,
Err(_) => panic!("system swap size can not get"),
};
let swap_size_limitation = test_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct");
if swap_size >= swap_size_limitation {
if let Err(e) = #ident().await {
Err(format!("{e:?}").into())
} else {
Ok(test_with::Completion::Completed)
}
} else {
Ok(test_with::Completion::ignored_with(format!("because the swap less than {}", #swap_limitation_str)))
}
}
},
(None, _) => quote::quote! {
fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
let sys = test_with::sysinfo::System::new_with_specifics(
test_with::sysinfo::RefreshKind::nothing().with_memory(test_with::sysinfo::MemoryRefreshKind::nothing().with_swap()),
);
let swap_size = match test_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) {
Ok(b) => b,
Err(_) => panic!("system swap size can not get"),
};
let swap_size_limitation = test_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct");
if swap_size >= swap_size_limitation {
#ident();
Ok(test_with::Completion::Completed)
} else {
Ok(test_with::Completion::ignored_with(format!("because the swap less than {}", #swap_limitation_str)))
}
}
},
};
quote::quote! {
#check_fn
#(#attrs)*
#vis #sig #block
}
.into()
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_free_swap(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_free_swap(attr: TokenStream, stream: TokenStream) -> TokenStream {
resource::runtime_free_swap(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "resource")]
pub fn cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
resource::check_cpu_core_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
resource::check_cpu_core_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_cpu_core(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
resource::runtime_cpu_core(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "resource")]
pub fn phy_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
resource::check_cpu_core_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
resource::check_phy_core_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_phy_cpu_core(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "resource"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_phy_cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream {
resource::runtime_phy_cpu_core(attr, stream)
}
#[proc_macro_attribute]
#[proc_macro_error]
#[cfg(feature = "executable")]
pub fn executable(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
executable::check_executable_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
executable::check_executable_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_executable(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "executable"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_executable(attr: TokenStream, stream: TokenStream) -> TokenStream {
executable::runtime_executable(attr, stream)
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_ignore_if(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_ignore_if(attr: TokenStream, stream: TokenStream) -> TokenStream {
let ignore_function = syn::Ident::new(
&attr.to_string().replace(' ', ""),
proc_macro2::Span::call_site(),
);
let ItemFn {
attrs,
vis,
sig,
block,
} = parse_macro_input!(stream as ItemFn);
let syn::Signature { ident, .. } = sig.clone();
let check_ident = syn::Ident::new(&format!("_check_{ident}"), proc_macro2::Span::call_site());
let check_fn = match (&sig.asyncness, &sig.output) {
(Some(_), ReturnType::Default) => quote::quote! {
async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
if let Some(msg) = #ignore_function() {
Ok(test_with::Completion::ignored_with(msg))
} else {
#ident().await;
Ok(test_with::Completion::Completed)
}
}
},
(Some(_), ReturnType::Type(_, _)) => quote::quote! {
async fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
if let Some(msg) = #ignore_function() {
Ok(test_with::Completion::ignored_with(msg))
} else {
if let Err(e) = #ident().await {
Err(format!("{e:?}").into())
} else {
Ok(test_with::Completion::Completed)
}
}
}
},
(None, _) => quote::quote! {
fn #check_ident() -> Result<test_with::Completion, test_with::Failed> {
if let Some(msg) = #ignore_function() {
Ok(test_with::Completion::ignored_with(msg))
} else {
#ident();
Ok(test_with::Completion::Completed)
}
}
},
};
quote::quote! {
#check_fn
#(#attrs)*
#vis #sig #block
}
.into()
}
#[proc_macro_attribute]
#[proc_macro_error]
pub fn lock(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
abort_call_site!("#[test_with::lock] only works with fn")
} else {
lock_macro(attr, parse_macro_input!(stream as ItemFn))
}
}
#[cfg(feature = "timezone")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn timezone(attr: TokenStream, stream: TokenStream) -> TokenStream {
if is_module(&stream) {
mod_macro(
attr,
parse_macro_input!(stream as ItemMod),
timezone::check_tz_condition,
)
} else {
fn_macro(
attr,
parse_macro_input!(stream as ItemFn),
timezone::check_tz_condition,
)
}
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_timezone(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
abort_call_site!("should be used with runtime feature")
}
#[cfg(all(feature = "runtime", feature = "timezone"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn runtime_timezone(attr: TokenStream, stream: TokenStream) -> TokenStream {
timezone::runtime_timezone(attr, stream)
}
#[cfg(not(feature = "runtime"))]
#[proc_macro]
pub fn runner(_input: TokenStream) -> TokenStream {
abort_call_site!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro]
pub fn runner(input: TokenStream) -> TokenStream {
runtime::runner(input)
}
#[cfg(not(feature = "runtime"))]
#[proc_macro]
pub fn tokio_runner(_input: TokenStream) -> TokenStream {
abort_call_site!("should be used with `runtime` feature")
}
#[cfg(feature = "runtime")]
#[proc_macro]
pub fn tokio_runner(input: TokenStream) -> TokenStream {
runtime::tokio_runner(input)
}
#[cfg(not(feature = "runtime"))]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn module(_attr: TokenStream, _stream: TokenStream) -> TokenStream {
panic!("should be used with runtime feature")
}
#[cfg(feature = "runtime")]
#[proc_macro_attribute]
#[proc_macro_error]
pub fn module(attr: TokenStream, stream: TokenStream) -> TokenStream {
runtime::module(attr, stream)
}