Fix __eq metamethods throwing on type mismatch
This commit is contained in:
@@ -458,6 +458,7 @@ pub struct MetatypeFunctionBuilder<'r, 'm> {
|
||||
cargs: String, // C call arguments
|
||||
prelude: String, // lua function body prelude
|
||||
postlude: String, // lua function body postlude
|
||||
is_eqmm: bool,
|
||||
}
|
||||
|
||||
impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> {
|
||||
@@ -469,9 +470,15 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> {
|
||||
cargs: String::new(),
|
||||
prelude: String::new(),
|
||||
postlude: String::new(),
|
||||
is_eqmm: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_eqmm(&mut self, eq: bool) -> &mut Self {
|
||||
self.is_eqmm = eq; // are we building an __eq metamethod?
|
||||
self
|
||||
}
|
||||
|
||||
pub fn param<T: FromFfi>(&mut self, name: impl Display) -> &mut Self {
|
||||
let Self {
|
||||
metatype: MetatypeBuilder { reg, .. },
|
||||
@@ -510,6 +517,26 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn param_ctchecked<T: FromFfi, U: Type + Metatype<Target = U>>(
|
||||
&mut self,
|
||||
name: impl Display,
|
||||
) -> &mut Self {
|
||||
let ct = U::name();
|
||||
if self.is_eqmm {
|
||||
// special case for building __eq metamethods which are expected to return false if the
|
||||
// arguments aren't of the expected type, because otherwise the `==` and `~=` operators
|
||||
// could throw instead of returning false.
|
||||
write!(
|
||||
self.prelude,
|
||||
r#"if not __istype(__ct.{ct}, {name}) then return false; end; "#
|
||||
)
|
||||
} else {
|
||||
write!(self.prelude, r#"assert(__istype(__ct.{ct}, {name})); "#)
|
||||
}
|
||||
.unwrap();
|
||||
self.param::<T>(name)
|
||||
}
|
||||
|
||||
pub fn param_str(
|
||||
&mut self,
|
||||
name: impl Display,
|
||||
@@ -520,7 +547,9 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> {
|
||||
//
|
||||
// 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. this is used when the
|
||||
// #[metatype] macro detects a string-like parameter, currently defined to be &[u8], &str,
|
||||
// &BStr (from the bstr crate), or those types wrapped in Option<T>.
|
||||
let Self {
|
||||
lparams,
|
||||
cparams,
|
||||
@@ -780,8 +809,7 @@ macro_rules! impl_bigint_intoabi {
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
// this isn't "correct" per se, but it's much more ergonomic to work with numbers in
|
||||
// lua than with long longs wrapped in cdata. we gracefully accept the loss of
|
||||
// precision here and that 53 bits of precision for big integers are enough. (the
|
||||
// vain of Lua 5.3 integer subtype ;D )
|
||||
// precision here and that 53 bits of precision for big integers are enough.
|
||||
display!("{ret} = tonumber({ret}); ")
|
||||
}
|
||||
}
|
||||
@@ -837,22 +865,6 @@ impl_ptr!(*mut T, true);
|
||||
impl_ptr!(Option<&T>, false);
|
||||
impl_ptr!(Option<&mut T>, true);
|
||||
|
||||
macro_rules! impl_ptr_annotation {
|
||||
($ty:ty) => {
|
||||
impl<T> Annotation for $ty
|
||||
where
|
||||
T: Annotation,
|
||||
{
|
||||
fn annotation() -> impl Display {
|
||||
"lightuserdata"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_ptr_annotation!(*const T);
|
||||
impl_ptr_annotation!(*mut T);
|
||||
|
||||
macro_rules! impl_ref_annotation {
|
||||
($ty:ty) => {
|
||||
impl<T> Annotation for $ty
|
||||
|
||||
Reference in New Issue
Block a user