160 lines
4.4 KiB
Rust
160 lines
4.4 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() => return true, // unit type
|
|
Type::Reference(_) | Type::Ptr(_) => return true,
|
|
Type::Paren(paren) => return is_primitivelike(&paren.elem),
|
|
Type::Path(path) => {
|
|
if let Some(name) = path.path.get_ident() {
|
|
return matches!(
|
|
name.to_string().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"
|
|
);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum StringLike {
|
|
SliceU8,
|
|
Str,
|
|
BStr,
|
|
}
|
|
|
|
pub fn is_stringlike(ty: &Type) -> Option<StringLike> {
|
|
if let Type::Reference(ty) = ty
|
|
&& ty.mutability.is_none()
|
|
&& ty.lifetime.is_none()
|
|
{
|
|
match *ty.elem {
|
|
Type::Slice(ref slice) => {
|
|
// match &[u8]
|
|
if let Type::Path(ref path) = *slice.elem
|
|
&& let Some(name) = path.path.get_ident()
|
|
&& name == "u8"
|
|
{
|
|
return Some(StringLike::SliceU8);
|
|
}
|
|
}
|
|
Type::Path(ref path) => {
|
|
// match &str or &BStr
|
|
if let Some(name) = path.path.get_ident() {
|
|
match name.to_string().as_str() {
|
|
"str" => return Some(StringLike::Str),
|
|
"BStr" => return Some(StringLike::BStr),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
pub fn is_optionlike(ty: &Type) -> Option<&Type> {
|
|
if let Type::Path(path) = ty
|
|
&& path.path.leading_colon.is_none()
|
|
&& path.path.segments.len() == 1
|
|
&& let Some(segment) = path.path.segments.get(0)
|
|
&& segment.ident == "Option"
|
|
&& let PathArguments::AngleBracketed(ref angle) = segment.arguments
|
|
&& angle.args.len() == 1
|
|
&& let Some(GenericArgument::Type(ty)) = angle.args.get(0)
|
|
{
|
|
Some(ty)
|
|
} else {
|
|
None
|
|
}
|
|
}
|