166 lines
4.5 KiB
Rust
166 lines
4.5 KiB
Rust
use crate::{
|
|
__internal::{disp, display},
|
|
FfiReturnConvention, FromFfi, IS_UTF8_FN, ToFfi, Type,
|
|
};
|
|
use bstr::BStr;
|
|
use luaffi_impl::{cdef, metatype};
|
|
use std::{fmt::Display, slice};
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
#[cdef]
|
|
pub struct lua_buf {
|
|
__ptr: *const u8,
|
|
__len: usize,
|
|
}
|
|
|
|
#[metatype]
|
|
impl lua_buf {}
|
|
|
|
// not implemented yet
|
|
#[derive(Debug, Clone, Copy)]
|
|
#[cdef]
|
|
pub struct lua_buffer {
|
|
__ptr: *const u8,
|
|
__len: usize,
|
|
__cap: usize,
|
|
}
|
|
|
|
#[metatype]
|
|
impl lua_buffer {}
|
|
|
|
unsafe impl<'s> FromFfi for &'s [u8] {
|
|
type From = lua_buf;
|
|
type FromArg = Option<&'s Self::From>;
|
|
|
|
fn require_keepalive() -> bool {
|
|
true
|
|
}
|
|
|
|
fn prelude(arg: &str) -> impl Display {
|
|
// this converts string arguments to a `lua_buf` with a pointer to the string and its length
|
|
disp(move |f| {
|
|
let ct = Self::From::name();
|
|
write!(
|
|
f,
|
|
r#"assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "#
|
|
)?;
|
|
write!(f, "{arg} = __new(__ct.{ct}, {arg}, #{arg}); end; ")
|
|
})
|
|
}
|
|
|
|
fn convert(from: Self::From) -> Self {
|
|
// SAFETY: we already checked that the string is nonnull from the lua side
|
|
debug_assert!(!from.__ptr.is_null());
|
|
unsafe { slice::from_raw_parts(from.__ptr, from.__len) }
|
|
}
|
|
|
|
fn convert_arg(from: Self::FromArg) -> Self {
|
|
// SAFETY: we already checked that the string is nonnull from the lua side
|
|
debug_assert!(from.is_some());
|
|
unsafe { FromFfi::convert(*from.unwrap_unchecked()) }
|
|
}
|
|
}
|
|
|
|
unsafe impl<'s> FromFfi for &'s BStr {
|
|
type From = <&'s [u8] as FromFfi>::From;
|
|
type FromArg = <&'s [u8] as FromFfi>::FromArg;
|
|
|
|
fn require_keepalive() -> bool {
|
|
<&'s [u8] as FromFfi>::require_keepalive()
|
|
}
|
|
|
|
fn prelude(arg: &str) -> impl Display {
|
|
<&'s [u8] as FromFfi>::prelude(arg)
|
|
}
|
|
|
|
fn convert(from: Self::From) -> Self {
|
|
<&'s [u8] as FromFfi>::convert(from).into()
|
|
}
|
|
|
|
fn convert_arg(from: Self::FromArg) -> Self {
|
|
<&'s [u8] as FromFfi>::convert_arg(from).into()
|
|
}
|
|
}
|
|
|
|
unsafe impl<'s> FromFfi for &'s str {
|
|
type From = lua_buf;
|
|
type FromArg = Option<&'s Self::From>;
|
|
|
|
fn require_keepalive() -> bool {
|
|
true
|
|
}
|
|
|
|
fn prelude(arg: &str) -> impl Display {
|
|
disp(move |f| {
|
|
let ct = Self::From::name();
|
|
write!(
|
|
f,
|
|
r#"assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "#
|
|
)?;
|
|
write!(
|
|
f,
|
|
r#"assert(__C.{IS_UTF8_FN}({arg}, #{arg}), "argument '{arg}' must be a valid utf-8 string"); "#
|
|
)?;
|
|
write!(f, "{arg} = __new(__ct.{ct}, {arg}, #{arg}); ")
|
|
})
|
|
}
|
|
|
|
fn convert(from: Self::From) -> Self {
|
|
// SAFETY: we already checked that the string is nonnull and valid utf8 from the lua side
|
|
debug_assert!(!from.__ptr.is_null());
|
|
let s = unsafe { slice::from_raw_parts(from.__ptr, from.__len) };
|
|
|
|
debug_assert!(
|
|
std::str::from_utf8(s).is_ok(),
|
|
"<&str>::convert() called on an invalid utf8 string when it was checked to be valid"
|
|
);
|
|
|
|
unsafe { std::str::from_utf8_unchecked(s) }
|
|
}
|
|
|
|
fn convert_arg(from: Self::FromArg) -> Self {
|
|
// SAFETY: we already checked that the string is nonnull and valid utf8 from the lua side
|
|
debug_assert!(from.is_some());
|
|
unsafe { FromFfi::convert(*from.unwrap_unchecked()) }
|
|
}
|
|
}
|
|
|
|
unsafe impl ToFfi for &'static [u8] {
|
|
type To = lua_buf;
|
|
|
|
fn convert(self) -> Self::To {
|
|
lua_buf {
|
|
__ptr: self.as_ptr(),
|
|
__len: self.len(),
|
|
}
|
|
}
|
|
|
|
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
|
display!("{ret} = __intern({ret}.__ptr, {ret}.__len)")
|
|
}
|
|
}
|
|
|
|
unsafe impl ToFfi for &'static BStr {
|
|
type To = <&'static [u8] as ToFfi>::To;
|
|
|
|
fn convert(self) -> Self::To {
|
|
<&'static [u8] as ToFfi>::convert(self.as_ref())
|
|
}
|
|
|
|
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
|
<&'static [u8] as ToFfi>::postlude(ret, conv)
|
|
}
|
|
}
|
|
|
|
unsafe impl ToFfi for &'static str {
|
|
type To = <&'static [u8] as ToFfi>::To;
|
|
|
|
fn convert(self) -> Self::To {
|
|
<&'static [u8] as ToFfi>::convert(self.as_bytes())
|
|
}
|
|
|
|
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
|
<&'static [u8] as ToFfi>::postlude(ret, conv)
|
|
}
|
|
}
|