105 lines
2.9 KiB
Rust

use std::env;
use syn::{spanned::Spanned, *};
macro_rules! syn_error {
($src:expr, $($fmt:expr),+) => {{
return Err(syn::Error::new($src.span(), format!($($fmt),*)));
}};
}
macro_rules! syn_assert {
($cond:expr, $src:expr, $($fmt:expr),+) => {{
if !$cond {
crate::utils::syn_error!($src, $($fmt),+);
}
}};
}
pub(crate) use {syn_assert, syn_error};
pub fn ffi_crate() -> Path {
match (
env::var("CARGO_PKG_NAME").ok(),
env::var("CARGO_TARGET_TMPDIR").ok(), // ignore tests/**/*.rs
) {
(Some(name), None) if name == "luaffi" => parse_quote!(crate),
_ => parse_quote!(::luaffi),
}
}
pub fn ty_name(ty: &Type) -> Result<&Ident> {
match ty {
Type::Path(path) => path.path.require_ident(),
_ => syn_error!(ty, "expected ident"),
}
}
pub fn pat_ident(pat: &Pat) -> Result<Ident> {
Ok(match pat {
Pat::Ident(ident) => match ident.subpat {
Some((_, ref subpat)) => syn_error!(subpat, "unexpected subpattern"),
None => ident.ident.clone(),
},
Pat::Wild(wild) => Ident::new("_", wild.span()),
_ => syn_error!(pat, "expected ident"),
})
}
pub fn is_unit(ty: &Type) -> bool {
if let Type::Tuple(tuple) = ty
&& tuple.elems.is_empty()
{
true
} else {
false
}
}
pub fn is_primitivelike(ty: &Type) -> bool {
match ty {
Type::Tuple(tuple) if tuple.elems.is_empty() => true, // unit type
Type::Reference(_) | Type::Ptr(_) => true,
Type::Paren(paren) => is_primitivelike(&paren.elem),
Type::Path(path) => {
if let Some(name) = path.path.get_ident() {
matches!(
format!("{name}").as_str(),
"bool"
| "u8"
| "u16"
| "u32"
| "u64"
| "usize"
| "i8"
| "i16"
| "i32"
| "i64"
| "isize"
| "f32"
| "f64"
| "char"
| "c_char"
| "c_schar"
| "c_uchar"
| "c_short"
| "c_ushort"
| "c_int"
| "c_uint"
| "c_long"
| "c_ulong"
| "c_longlong"
| "c_ulonglong"
| "c_float"
| "c_double"
| "c_size_t"
| "c_ssize_t"
| "c_ptrdiff_t"
)
} else {
false
}
}
_ => false,
}
}