Implement string parameter specialisation
This commit is contained in:
@@ -485,12 +485,17 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn param_str(&mut self, name: impl Display) -> &mut Self {
|
||||
// fast-path for &str and &[u8]-like parameters
|
||||
pub fn param_str(
|
||||
&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`
|
||||
// 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 {
|
||||
lparams,
|
||||
cparams,
|
||||
@@ -499,22 +504,26 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
..
|
||||
} = self;
|
||||
|
||||
let param_ptr = <*const u8>::cdecl("ptr");
|
||||
let param_len = usize::cdecl("len");
|
||||
let param_ptr = <*const u8>::cdecl(&name);
|
||||
let param_len = usize::cdecl(format!("{name}_len"));
|
||||
|
||||
(!lparams.is_empty()).then(|| lparams.push_str(", "));
|
||||
(!cparams.is_empty()).then(|| cparams.push_str(", "));
|
||||
(!cargs.is_empty()).then(|| cargs.push_str(", "));
|
||||
|
||||
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!(prelude, "local __{name}_len = 0; ").unwrap();
|
||||
write!(
|
||||
prelude,
|
||||
r#"if {name} ~= nil then assert(type({name}) == "string", "string expected in argument '{name}', got " .. type({name})); __{name}_len = #{name}; end; "#
|
||||
)
|
||||
.unwrap();
|
||||
write!(prelude, "local __{name}_len = 0; if {name} ~= nil then ").unwrap();
|
||||
write!(prelude, r#"assert(type({name}) == "string", "string expected in argument '{name}', got " .. type({name})); "#).unwrap();
|
||||
write!(prelude, r#"__{name}_len = #{name}; "#).unwrap();
|
||||
if check_utf8 {
|
||||
write!(prelude, r#"assert(__C.{IS_UTF8_FN}({name}, __{name}_len), "argument '{name}' must be a valid utf-8 string"); "#).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
|
||||
}
|
||||
|
||||
@@ -549,21 +558,21 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
if T::Into::ty() == TypeType::Void {
|
||||
write!(lua, "__C.{func}({cargs}); {postlude}end").unwrap();
|
||||
} else {
|
||||
let check = T::postlude("__res");
|
||||
write!(lua, "local __res = __C.{func}({cargs}); ").unwrap();
|
||||
write!(lua, "{check}{postlude}return __res; end").unwrap();
|
||||
let check = T::postlude("__ret");
|
||||
write!(lua, "local __ret = __C.{func}({cargs}); ").unwrap();
|
||||
write!(lua, "{check}{postlude}return __ret; end").unwrap();
|
||||
}
|
||||
|
||||
writeln!(cdef, "{};", T::Into::cdecl(display!("{func}({cparams})"))).unwrap();
|
||||
}
|
||||
FfiReturnConvention::ByOutParam => {
|
||||
let ct = T::Into::name();
|
||||
let check = T::postlude("__res");
|
||||
write!(lua, "local __res = __new(__ct.{ct}); __C.{func}(__res").unwrap();
|
||||
let check = T::postlude("__out");
|
||||
write!(lua, "local __out = __new(__ct.{ct}); __C.{func}(__out").unwrap();
|
||||
if !cargs.is_empty() {
|
||||
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();
|
||||
if !cparams.is_empty() {
|
||||
write!(cdef, ", {cparams}").unwrap();
|
||||
|
||||
Reference in New Issue
Block a user