Implement string parameter specialisation
This commit is contained in:
parent
681dd332ab
commit
98100d02fa
@ -485,12 +485,17 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn param_str(&mut self, name: impl Display) -> &mut Self {
|
pub fn param_str(
|
||||||
// fast-path for &str and &[u8]-like parameters
|
&mut self,
|
||||||
|
name: impl Display,
|
||||||
|
allow_nil: bool,
|
||||||
|
check_utf8: bool,
|
||||||
|
) -> &mut Self {
|
||||||
|
// fast-path for &[u8] and &str-like parameters
|
||||||
//
|
//
|
||||||
// this passes one lua `string` argument as two C `const uint8_t *ptr` and `uintptr_t len`
|
// this passes one lua `string` argument as two C `const uint8_t *ptr` and `uintptr_t len`
|
||||||
// arguments, bypassing the slower generic `&[u8]: FromFfi` path which constructs a
|
// arguments, bypassing the slower generic `&[u8]: FromFfi` path which constructs a
|
||||||
// temporary cdata to pass the string and its length in one argument
|
// temporary cdata to pass the string and its length in one argument.
|
||||||
let Self {
|
let Self {
|
||||||
lparams,
|
lparams,
|
||||||
cparams,
|
cparams,
|
||||||
@ -499,22 +504,26 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
|||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let param_ptr = <*const u8>::cdecl("ptr");
|
let param_ptr = <*const u8>::cdecl(&name);
|
||||||
let param_len = usize::cdecl("len");
|
let param_len = usize::cdecl(format!("{name}_len"));
|
||||||
|
|
||||||
(!lparams.is_empty()).then(|| lparams.push_str(", "));
|
(!lparams.is_empty()).then(|| lparams.push_str(", "));
|
||||||
(!cparams.is_empty()).then(|| cparams.push_str(", "));
|
(!cparams.is_empty()).then(|| cparams.push_str(", "));
|
||||||
(!cargs.is_empty()).then(|| cargs.push_str(", "));
|
(!cargs.is_empty()).then(|| cargs.push_str(", "));
|
||||||
|
|
||||||
write!(lparams, "{name}").unwrap();
|
write!(lparams, "{name}").unwrap();
|
||||||
write!(cparams, "{param_ptr}, {param_len}",).unwrap();
|
write!(cparams, "{param_ptr}, {param_len}").unwrap();
|
||||||
write!(cargs, "{name}, __{name}_len").unwrap();
|
write!(cargs, "{name}, __{name}_len").unwrap();
|
||||||
write!(prelude, "local __{name}_len = 0; ").unwrap();
|
write!(prelude, "local __{name}_len = 0; if {name} ~= nil then ").unwrap();
|
||||||
write!(
|
write!(prelude, r#"assert(type({name}) == "string", "string expected in argument '{name}', got " .. type({name})); "#).unwrap();
|
||||||
prelude,
|
write!(prelude, r#"__{name}_len = #{name}; "#).unwrap();
|
||||||
r#"if {name} ~= nil then assert(type({name}) == "string", "string expected in argument '{name}', got " .. type({name})); __{name}_len = #{name}; end; "#
|
if check_utf8 {
|
||||||
)
|
write!(prelude, r#"assert(__C.{IS_UTF8_FN}({name}, __{name}_len), "argument '{name}' must be a valid utf-8 string"); "#).unwrap();
|
||||||
.unwrap();
|
}
|
||||||
|
if !allow_nil {
|
||||||
|
write!(prelude, r#"else return error("string expected in argument '{name}', got " .. type({name})); "#).unwrap();
|
||||||
|
}
|
||||||
|
write!(prelude, r#"end; "#).unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,21 +558,21 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
|||||||
if T::Into::ty() == TypeType::Void {
|
if T::Into::ty() == TypeType::Void {
|
||||||
write!(lua, "__C.{func}({cargs}); {postlude}end").unwrap();
|
write!(lua, "__C.{func}({cargs}); {postlude}end").unwrap();
|
||||||
} else {
|
} else {
|
||||||
let check = T::postlude("__res");
|
let check = T::postlude("__ret");
|
||||||
write!(lua, "local __res = __C.{func}({cargs}); ").unwrap();
|
write!(lua, "local __ret = __C.{func}({cargs}); ").unwrap();
|
||||||
write!(lua, "{check}{postlude}return __res; end").unwrap();
|
write!(lua, "{check}{postlude}return __ret; end").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(cdef, "{};", T::Into::cdecl(display!("{func}({cparams})"))).unwrap();
|
writeln!(cdef, "{};", T::Into::cdecl(display!("{func}({cparams})"))).unwrap();
|
||||||
}
|
}
|
||||||
FfiReturnConvention::ByOutParam => {
|
FfiReturnConvention::ByOutParam => {
|
||||||
let ct = T::Into::name();
|
let ct = T::Into::name();
|
||||||
let check = T::postlude("__res");
|
let check = T::postlude("__out");
|
||||||
write!(lua, "local __res = __new(__ct.{ct}); __C.{func}(__res").unwrap();
|
write!(lua, "local __out = __new(__ct.{ct}); __C.{func}(__out").unwrap();
|
||||||
if !cargs.is_empty() {
|
if !cargs.is_empty() {
|
||||||
write!(lua, ", {cargs}").unwrap();
|
write!(lua, ", {cargs}").unwrap();
|
||||||
}
|
}
|
||||||
write!(lua, "); {check}{postlude}return __res; end").unwrap();
|
write!(lua, "); {check}{postlude}return __out; end").unwrap();
|
||||||
write!(cdef, "void {func}({}", <*mut T::Into>::cdecl("out")).unwrap();
|
write!(cdef, "void {func}({}", <*mut T::Into>::cdecl("out")).unwrap();
|
||||||
if !cparams.is_empty() {
|
if !cparams.is_empty() {
|
||||||
write!(cdef, ", {cparams}").unwrap();
|
write!(cdef, ", {cparams}").unwrap();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
ffi_crate, is_primitivelike, is_unit, pat_ident, syn_assert, syn_error, ty_name,
|
StringLike, ffi_crate, is_optionlike, is_primitivelike, is_stringlike, is_unit, pat_ident,
|
||||||
|
syn_assert, syn_error, ty_name,
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{ToTokens, format_ident, quote, quote_spanned};
|
use quote::{ToTokens, format_ident, quote, quote_spanned};
|
||||||
@ -29,12 +30,27 @@ pub fn transform(mut imp: ItemImpl) -> Result<TokenStream> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Registry {
|
||||||
|
ty: Ident,
|
||||||
|
shims: Vec<ImplItemFn>,
|
||||||
|
build: Vec<TokenStream>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registry {
|
||||||
|
fn new(ty: Ident) -> Self {
|
||||||
|
Self {
|
||||||
|
ty,
|
||||||
|
shims: vec![],
|
||||||
|
build: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let ty = imp.self_ty.clone();
|
let ty = imp.self_ty.clone();
|
||||||
let ty_name = ty_name(&ty)?;
|
let ty_name = ty_name(&ty)?;
|
||||||
let mut ffi_funcs = FfiRegistry::new(ty_name.clone());
|
let mut registry = Registry::new(ty_name.clone());
|
||||||
let mut lua_funcs = LuaRegistry::new(ty_name.clone());
|
|
||||||
let mut mms = HashSet::new();
|
let mut mms = HashSet::new();
|
||||||
let mut lua_drop = None;
|
let mut lua_drop = None;
|
||||||
|
|
||||||
@ -47,7 +63,7 @@ fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ffi_function(&mut ffi_funcs, &func)?;
|
add_ffi_function(&mut registry, &func)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for func in get_lua_functions(imp)? {
|
for func in get_lua_functions(imp)? {
|
||||||
@ -59,37 +75,32 @@ fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if func.attrs.metamethod == Some(Metamethod::Gc) {
|
if let Some(Metamethod::Gc) = func.attrs.metamethod {
|
||||||
lua_drop = Some(func);
|
lua_drop = Some(func);
|
||||||
} else {
|
} else {
|
||||||
add_lua_function(&mut lua_funcs, &func)?;
|
add_lua_function(&mut registry, &func)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mms.contains(&Metamethod::New) {
|
if !mms.contains(&Metamethod::New) {
|
||||||
inject_fallback_new(&mut lua_funcs)?;
|
inject_fallback_new(&mut registry)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
inject_merged_drop(&mut ffi_funcs, lua_drop.as_ref())?;
|
inject_merged_drop(&mut registry, lua_drop.as_ref())?;
|
||||||
|
|
||||||
let ffi_shims = &ffi_funcs.shims;
|
let shims = ®istry.shims;
|
||||||
let ffi_build = &ffi_funcs.build;
|
let build = ®istry.build;
|
||||||
let lua_build = &lua_funcs.build;
|
let exports = generate_ffi_exports(®istry)?;
|
||||||
let ffi_exports = generate_ffi_exports(&ffi_funcs)?;
|
|
||||||
|
|
||||||
Ok(quote_spanned!(ty.span() =>
|
Ok(quote_spanned!(ty.span() =>
|
||||||
impl #ty { #(#ffi_shims)* }
|
impl #ty { #(#shims)* }
|
||||||
|
|
||||||
unsafe impl #ffi::Metatype for #ty {
|
unsafe impl #ffi::Metatype for #ty {
|
||||||
type Target = Self;
|
type Target = Self;
|
||||||
|
fn build(b: &mut #ffi::MetatypeBuilder) { #(#build)* }
|
||||||
fn build(b: &mut #ffi::MetatypeBuilder) {
|
|
||||||
#(#ffi_build)*
|
|
||||||
#(#lua_build)*
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ffi_exports
|
#exports
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,9 +212,15 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
|||||||
&& let Some(ref abi) = abi.name
|
&& let Some(ref abi) = abi.name
|
||||||
&& abi.value() == "Lua-C"
|
&& abi.value() == "Lua-C"
|
||||||
{
|
{
|
||||||
|
syn_assert!(
|
||||||
|
func.sig.generics.params.len() == 0,
|
||||||
|
func.sig.generics,
|
||||||
|
"cannot be generic"
|
||||||
|
);
|
||||||
|
|
||||||
func.sig.abi = None;
|
func.sig.abi = None;
|
||||||
|
|
||||||
let params = func
|
let params: Vec<_> = func
|
||||||
.sig
|
.sig
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
@ -221,6 +238,24 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
|||||||
ReturnType::Type(_, ref ty) => (**ty).clone(),
|
ReturnType::Type(_, ref ty) => (**ty).clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for param in params.iter() {
|
||||||
|
// double underscores are reserved for generated glue code
|
||||||
|
syn_assert!(
|
||||||
|
!pat_ident(¶m.pat)?.to_string().starts_with("__"),
|
||||||
|
param.pat,
|
||||||
|
"parameter names should not start with `__`"
|
||||||
|
);
|
||||||
|
|
||||||
|
// lifetime should be determined by the caller (lua)
|
||||||
|
if let Type::Reference(ref ty) = *param.ty {
|
||||||
|
syn_assert!(
|
||||||
|
ty.lifetime.is_none(),
|
||||||
|
ty.lifetime,
|
||||||
|
"lifetime should be determined by the caller"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let attrs = parse_ffi_function_attrs(&mut func.attrs)?;
|
let attrs = parse_ffi_function_attrs(&mut func.attrs)?;
|
||||||
attrs.metamethod.map(|mm| document_metamethod(func, mm));
|
attrs.metamethod.map(|mm| document_metamethod(func, mm));
|
||||||
|
|
||||||
@ -261,14 +296,26 @@ fn parse_ffi_function_attrs(attrs: &mut Vec<Attribute>) -> Result<FfiFunctionAtt
|
|||||||
Ok(parsed)
|
Ok(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum FfiParameterType {
|
enum FfiParameterType {
|
||||||
Default,
|
Default,
|
||||||
|
StringLike(StringLike),
|
||||||
|
OptionStringLike(StringLike),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ffi_param_type(_ty: &Type) -> FfiParameterType {
|
fn get_ffi_param_type(ty: &Type) -> FfiParameterType {
|
||||||
|
if let Some(str) = is_stringlike(ty) {
|
||||||
|
FfiParameterType::StringLike(str)
|
||||||
|
} else if let Some(arg) = is_optionlike(ty)
|
||||||
|
&& let Some(str) = is_stringlike(arg)
|
||||||
|
{
|
||||||
|
FfiParameterType::OptionStringLike(str)
|
||||||
|
} else {
|
||||||
FfiParameterType::Default
|
FfiParameterType::Default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum FfiReturnType {
|
enum FfiReturnType {
|
||||||
Void,
|
Void,
|
||||||
ByValue,
|
ByValue,
|
||||||
@ -298,23 +345,7 @@ fn get_ffi_ret_type(ty: &Type) -> FfiReturnType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FfiRegistry {
|
fn add_ffi_function(registry: &mut Registry, func: &FfiFunction) -> Result<()> {
|
||||||
ty: Ident,
|
|
||||||
shims: Vec<ImplItemFn>,
|
|
||||||
build: Vec<TokenStream>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FfiRegistry {
|
|
||||||
fn new(ty: Ident) -> Self {
|
|
||||||
Self {
|
|
||||||
ty,
|
|
||||||
shims: vec![],
|
|
||||||
build: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_ffi_function(registry: &mut FfiRegistry, func: &FfiFunction) -> Result<()> {
|
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let ty = ®istry.ty;
|
let ty = ®istry.ty;
|
||||||
let func_name = &func.name;
|
let func_name = &func.name;
|
||||||
@ -366,6 +397,41 @@ fn add_ffi_function(registry: &mut FfiRegistry, func: &FfiFunction) -> Result<()
|
|||||||
b.param::<#func_param>(#name);
|
b.param::<#func_param>(#name);
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
ty @ (FfiParameterType::StringLike(str) | FfiParameterType::OptionStringLike(str)) => {
|
||||||
|
let shim_param_len = format_ident!("arg{i}_len");
|
||||||
|
shim_params.push(quote_spanned!(func_param.span() =>
|
||||||
|
#shim_param: ::std::option::Option<&::std::primitive::u8>,
|
||||||
|
#shim_param_len: ::std::primitive::usize
|
||||||
|
));
|
||||||
|
let allow_nil = matches!(ty, FfiParameterType::OptionStringLike(_));
|
||||||
|
let check_utf8 = matches!(str, StringLike::Str);
|
||||||
|
let mut func_arg = quote_spanned!(func_param.span() =>
|
||||||
|
#shim_param.map(|s| ::std::slice::from_raw_parts(s, #shim_param_len))
|
||||||
|
);
|
||||||
|
func_arg = match str {
|
||||||
|
StringLike::SliceU8 => func_arg,
|
||||||
|
StringLike::BStr => {
|
||||||
|
quote_spanned!(func_param.span() => #func_arg.map(::bstr::BStr::new))
|
||||||
|
}
|
||||||
|
StringLike::Str => {
|
||||||
|
quote_spanned!(func_param.span() => #func_arg.map(|s| {
|
||||||
|
::std::debug_assert!(::std::str::from_utf8(s).is_ok());
|
||||||
|
::std::str::from_utf8_unchecked(s)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !allow_nil {
|
||||||
|
func_arg = quote_spanned!(func_param.span() => {
|
||||||
|
let arg = #func_arg;
|
||||||
|
::std::debug_assert!(arg.is_some());
|
||||||
|
arg.unwrap_unchecked()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
func_args.push(func_arg);
|
||||||
|
build.push(quote_spanned!(param.pat.span() =>
|
||||||
|
b.param_str(#name, #allow_nil, #check_utf8);
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +505,7 @@ fn add_ffi_function(registry: &mut FfiRegistry, func: &FfiFunction) -> Result<()
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_ffi_exports(registry: &FfiRegistry) -> Result<TokenStream> {
|
fn generate_ffi_exports(registry: &Registry) -> Result<TokenStream> {
|
||||||
let ty = ®istry.ty;
|
let ty = ®istry.ty;
|
||||||
let names = registry.shims.iter().map(|f| &f.sig.ident);
|
let names = registry.shims.iter().map(|f| &f.sig.ident);
|
||||||
|
|
||||||
@ -474,6 +540,12 @@ fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
|||||||
&& let Some(ref abi) = abi.name
|
&& let Some(ref abi) = abi.name
|
||||||
&& abi.value() == "Lua"
|
&& abi.value() == "Lua"
|
||||||
{
|
{
|
||||||
|
syn_assert!(
|
||||||
|
func.sig.generics.params.len() == 0,
|
||||||
|
func.sig.generics,
|
||||||
|
"cannot be generic"
|
||||||
|
);
|
||||||
|
|
||||||
let mut params: Vec<_> = func
|
let mut params: Vec<_> = func
|
||||||
.sig
|
.sig
|
||||||
.inputs
|
.inputs
|
||||||
@ -597,18 +669,7 @@ fn parse_lua_function_attrs(attrs: &mut Vec<Attribute>) -> Result<LuaFunctionAtt
|
|||||||
Ok(parsed)
|
Ok(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LuaRegistry {
|
fn add_lua_function(registry: &mut Registry, func: &LuaFunction) -> Result<()> {
|
||||||
ty: Ident,
|
|
||||||
build: Vec<TokenStream>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LuaRegistry {
|
|
||||||
fn new(ty: Ident) -> Self {
|
|
||||||
Self { ty, build: vec![] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_lua_function(registry: &mut LuaRegistry, func: &LuaFunction) -> Result<()> {
|
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let luaify = quote!(#ffi::__internal::luaify!);
|
let luaify = quote!(#ffi::__internal::luaify!);
|
||||||
let func_name = &func.name;
|
let func_name = &func.name;
|
||||||
@ -628,7 +689,7 @@ fn add_lua_function(registry: &mut LuaRegistry, func: &LuaFunction) -> Result<()
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_fallback_new(registry: &mut LuaRegistry) -> Result<()> {
|
fn inject_fallback_new(registry: &mut Registry) -> Result<()> {
|
||||||
let ty = ®istry.ty;
|
let ty = ®istry.ty;
|
||||||
let lua = format!(
|
let lua = format!(
|
||||||
r#"function() error("type '{}' has no constructor"); end"#,
|
r#"function() error("type '{}' has no constructor"); end"#,
|
||||||
@ -642,7 +703,7 @@ fn inject_fallback_new(registry: &mut LuaRegistry) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_merged_drop(registry: &mut FfiRegistry, lua: Option<&LuaFunction>) -> Result<()> {
|
fn inject_merged_drop(registry: &mut Registry, lua: Option<&LuaFunction>) -> Result<()> {
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let luaify = quote!(#ffi::__internal::luaify!);
|
let luaify = quote!(#ffi::__internal::luaify!);
|
||||||
let ty = ®istry.ty;
|
let ty = ®istry.ty;
|
||||||
|
@ -57,13 +57,13 @@ pub fn is_unit(ty: &Type) -> bool {
|
|||||||
|
|
||||||
pub fn is_primitivelike(ty: &Type) -> bool {
|
pub fn is_primitivelike(ty: &Type) -> bool {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Tuple(tuple) if tuple.elems.is_empty() => true, // unit type
|
Type::Tuple(tuple) if tuple.elems.is_empty() => return true, // unit type
|
||||||
Type::Reference(_) | Type::Ptr(_) => true,
|
Type::Reference(_) | Type::Ptr(_) => return true,
|
||||||
Type::Paren(paren) => is_primitivelike(&paren.elem),
|
Type::Paren(paren) => return is_primitivelike(&paren.elem),
|
||||||
Type::Path(path) => {
|
Type::Path(path) => {
|
||||||
if let Some(name) = path.path.get_ident() {
|
if let Some(name) = path.path.get_ident() {
|
||||||
matches!(
|
return matches!(
|
||||||
format!("{name}").as_str(),
|
name.to_string().as_str(),
|
||||||
"bool"
|
"bool"
|
||||||
| "u8"
|
| "u8"
|
||||||
| "u16"
|
| "u16"
|
||||||
@ -94,11 +94,66 @@ pub fn is_primitivelike(ty: &Type) -> bool {
|
|||||||
| "c_size_t"
|
| "c_size_t"
|
||||||
| "c_ssize_t"
|
| "c_ssize_t"
|
||||||
| "c_ptrdiff_t"
|
| "c_ptrdiff_t"
|
||||||
)
|
);
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
false
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1333,8 +1333,7 @@ impl<'s> DerefMut for StackGuard<'s> {
|
|||||||
|
|
||||||
impl<'s> Drop for StackGuard<'s> {
|
impl<'s> Drop for StackGuard<'s> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
#[cfg(debug_assertions)]
|
if cfg!(debug_assertions) && self.check_overpop {
|
||||||
if self.check_overpop {
|
|
||||||
let new_size = self.stack.size();
|
let new_size = self.stack.size();
|
||||||
assert!(
|
assert!(
|
||||||
self.size <= new_size,
|
self.size <= new_size,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user