Refactor luaffi proc-macro
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
__internal::{display, type_id},
|
||||
Cdef, CdefBuilder, FfiReturnConvention, IntoFfi, Metatype, MetatypeBuilder, Type, TypeBuilder,
|
||||
Cdef, CdefBuilder, IntoFfi, Metatype, MetatypeBuilder, Type, TypeBuilder, TypeType,
|
||||
UnsafeExternCFn,
|
||||
};
|
||||
use luaify::luaify;
|
||||
@@ -43,7 +43,7 @@ pub struct lua_future<F: Future<Output: IntoFfi>> {
|
||||
sig: Signature,
|
||||
poll: fn(Pin<&mut Self>, cx: &mut Context) -> Poll<()>,
|
||||
state: State<F>,
|
||||
take: unsafe extern "C" fn(&mut Self) -> <F::Output as IntoFfi>::To,
|
||||
take: unsafe extern "C" fn(&mut Self) -> <F::Output as IntoFfi>::Into,
|
||||
drop: unsafe extern "C" fn(&mut Self),
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ impl<F: Future<Output: IntoFfi>> lua_future<F> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn take(&mut self) -> <F::Output as IntoFfi>::To {
|
||||
unsafe extern "C" fn take(&mut self) -> <F::Output as IntoFfi>::Into {
|
||||
// `fut:__take()` returns the fulfilled value by-value (not by out-param) because if we
|
||||
// preallocate a cdata for the out-param and the thread for some reason gets dropped and
|
||||
// never resumed, the GC could call the destructor on an uninitialised cdata.
|
||||
@@ -136,8 +136,12 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Type for lua_future<F> {
|
||||
display!("future__{:x}", type_id::<F>())
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Aggregate
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
display!("struct future__{:x} {name}", type_id::<F>())
|
||||
display!("struct {} {name}", Self::name())
|
||||
}
|
||||
|
||||
fn build(s: &mut TypeBuilder) {
|
||||
@@ -148,7 +152,7 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Type for lua_future<F> {
|
||||
unsafe impl<F: Future<Output: IntoFfi> + 'static> Cdef for lua_future<F> {
|
||||
fn build(s: &mut CdefBuilder) {
|
||||
s.field_opaque(mem::offset_of!(Self, take)) // opaque .sig, .poll and .state
|
||||
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as IntoFfi>::To>>("__take")
|
||||
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as IntoFfi>::Into>>("__take")
|
||||
.field::<UnsafeExternCFn<(&mut Self,), ()>>("__drop");
|
||||
}
|
||||
}
|
||||
@@ -162,24 +166,25 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Metatype for lua_future<F> {
|
||||
}
|
||||
|
||||
unsafe impl<F: Future<Output: IntoFfi> + 'static> IntoFfi for lua_future<F> {
|
||||
type To = lua_future<F>;
|
||||
type Into = lua_future<F>;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
// When returning a future from Rust to Lua, yield it immediately to the runtime which will
|
||||
// poll it to completion in the background, then take the fulfilled value once the thread
|
||||
// gets resumed. Lua user code should never to worry about awaiting futures.
|
||||
//
|
||||
// Once the current thread gets resumed and we take the future's fulfilled value, we clear
|
||||
// the finaliser on the future and forget it (there is nothing to call drop on).
|
||||
// the finaliser on the future and forget it (there is nothing to drop once the value is
|
||||
// taken).
|
||||
//
|
||||
// `coroutine.yield` is cached as `yield` and `ffi.gc` as `gc` in locals (see lib.rs)
|
||||
// `coroutine.yield` is cached as `__yield` and `ffi.gc` as `__gc` in locals (see lib.rs)
|
||||
display!(
|
||||
"yield({ret}); {ret} = gc({ret}, nil):__take(); {}",
|
||||
<F::Output as IntoFfi>::postlude(ret, FfiReturnConvention::ByValue)
|
||||
"__yield({ret}); {ret} = __gc({ret}, nil):__take(); {}",
|
||||
<F::Output as IntoFfi>::postlude(ret)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ pub mod result;
|
||||
// `ffi.keep(obj)`.
|
||||
//
|
||||
// https://github.com/LuaJIT/LuaJIT/issues/1167
|
||||
pub const KEEP_FN: &str = "luaffi_keep";
|
||||
pub(crate) const KEEP_FN: &str = "luaffi_keep";
|
||||
#[unsafe(export_name = "luaffi_keep")]
|
||||
extern "C" fn __keep(_ptr: *const c_void) {}
|
||||
export![__keep];
|
||||
@@ -151,6 +151,7 @@ impl Registry {
|
||||
}
|
||||
|
||||
pub fn declare<T: Type>(&mut self, name: impl Display) -> &mut Self {
|
||||
assert!(T::ty() != TypeType::Void, "cannot declare void type");
|
||||
self.include::<T>()
|
||||
.funcs
|
||||
.insert(name.to_string())
|
||||
@@ -159,6 +160,7 @@ impl Registry {
|
||||
}
|
||||
|
||||
pub fn preload<T: Type>(&mut self, name: impl Display) -> &mut Self {
|
||||
assert!(T::ty() != TypeType::Void, "cannot declare void type");
|
||||
self.include::<T>();
|
||||
let ct = T::name();
|
||||
writeln!(
|
||||
@@ -189,6 +191,8 @@ impl Display for Registry {
|
||||
|
||||
pub unsafe trait Type {
|
||||
fn name() -> impl Display;
|
||||
fn ty() -> TypeType;
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display;
|
||||
fn extern_cdecl(name: impl Display) -> impl Display {
|
||||
Self::cdecl(name)
|
||||
@@ -197,6 +201,13 @@ pub unsafe trait Type {
|
||||
fn build(b: &mut TypeBuilder);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum TypeType {
|
||||
Void,
|
||||
Primitive,
|
||||
Aggregate,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypeBuilder<'r> {
|
||||
registry: &'r mut Registry,
|
||||
@@ -253,6 +264,7 @@ impl<'r> CdefBuilder<'r> {
|
||||
}
|
||||
|
||||
pub fn field<T: Type>(&mut self, name: impl Display) -> &mut Self {
|
||||
assert!(T::ty() != TypeType::Void, "cannot declare void field");
|
||||
self.registry.include::<T>();
|
||||
self.field_raw(T::cdecl(name))
|
||||
}
|
||||
@@ -390,21 +402,13 @@ pub unsafe trait FromFfi: Sized {
|
||||
}
|
||||
|
||||
pub unsafe trait IntoFfi: Sized {
|
||||
type To: Type + Sized;
|
||||
type Into: Type + Sized;
|
||||
|
||||
fn postlude(_ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
fn postlude(_ret: &str) -> impl Display {
|
||||
""
|
||||
}
|
||||
|
||||
fn convert(self) -> Self::To;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum FfiReturnConvention {
|
||||
Void,
|
||||
#[default]
|
||||
ByValue,
|
||||
ByOutParam,
|
||||
fn convert(self) -> Self::Into;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -428,6 +432,11 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
}
|
||||
|
||||
pub fn param<T: FromFfi>(&mut self, name: impl Display) -> &mut Self {
|
||||
assert!(
|
||||
T::From::ty() != TypeType::Void,
|
||||
"cannot declare void parameter"
|
||||
);
|
||||
|
||||
(!self.params.is_empty()).then(|| self.params.push_str(", "));
|
||||
(!self.args.is_empty()).then(|| self.args.push_str(", "));
|
||||
write!(self.params, "{name}").unwrap();
|
||||
@@ -468,7 +477,7 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn call<T: IntoFfi>(&mut self, func: impl Display, ret: FfiReturnConvention) {
|
||||
pub fn call<T: IntoFfi>(&mut self, func: impl Display) {
|
||||
let Self {
|
||||
metatype,
|
||||
params,
|
||||
@@ -480,21 +489,21 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
let lua = &mut metatype.lua;
|
||||
write!(lua, "function({params}) {prelude}").unwrap();
|
||||
|
||||
match ret {
|
||||
FfiReturnConvention::Void => {
|
||||
match T::Into::ty() {
|
||||
TypeType::Void => {
|
||||
write!(lua, "__C.{func}({args}); {postlude}end").unwrap();
|
||||
}
|
||||
FfiReturnConvention::ByValue => {
|
||||
let check = T::postlude("__res", ret);
|
||||
TypeType::Primitive => {
|
||||
let check = T::postlude("__res");
|
||||
write!(
|
||||
lua,
|
||||
"local __res = __C.{func}({args}); {check}{postlude}return __res; end"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
FfiReturnConvention::ByOutParam => {
|
||||
let ct = T::To::name();
|
||||
let check = T::postlude("__res", ret);
|
||||
TypeType::Aggregate => {
|
||||
let ct = T::Into::name();
|
||||
let check = T::postlude("__res");
|
||||
write!(lua, "local __res = __new(__ct.{ct}); __C.{func}(__res").unwrap();
|
||||
if !args.is_empty() {
|
||||
write!(lua, ", {args}").unwrap();
|
||||
@@ -505,15 +514,51 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_primitive {
|
||||
($rtype:ty, $ctype:expr) => {
|
||||
unsafe impl Type for $rtype {
|
||||
//
|
||||
// SAFETY: Unit type return maps to a C void return, which is a nil return in lua. There is no
|
||||
// equivalent to passing a unit type as an argument in C.
|
||||
//
|
||||
macro_rules! impl_void {
|
||||
($rty:ty) => {
|
||||
unsafe impl Type for $rty {
|
||||
fn name() -> impl Display {
|
||||
$ctype
|
||||
"void"
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Void
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
display!("{} {name}", $ctype)
|
||||
display!("void {name}")
|
||||
}
|
||||
|
||||
fn build(_b: &mut TypeBuilder) {}
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for $rty {
|
||||
type Into = ();
|
||||
fn convert(self) -> Self::Into {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_void!(());
|
||||
impl_void!(c_void);
|
||||
|
||||
macro_rules! impl_primitive {
|
||||
($rty:ty, $cty:expr) => {
|
||||
unsafe impl Type for $rty {
|
||||
fn name() -> impl Display {
|
||||
$cty
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Primitive
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
display!("{} {name}", $cty)
|
||||
}
|
||||
|
||||
fn build(_b: &mut TypeBuilder) {}
|
||||
@@ -521,8 +566,6 @@ macro_rules! impl_primitive {
|
||||
};
|
||||
}
|
||||
|
||||
impl_primitive!((), "void");
|
||||
impl_primitive!(c_void, "void");
|
||||
impl_primitive!(bool, "bool");
|
||||
impl_primitive!(u8, "uint8_t");
|
||||
impl_primitive!(u16, "uint16_t");
|
||||
@@ -537,24 +580,6 @@ impl_primitive!(isize, "intptr_t");
|
||||
impl_primitive!(c_float, "float");
|
||||
impl_primitive!(c_double, "double");
|
||||
|
||||
unsafe impl IntoFfi for () {
|
||||
//
|
||||
// SAFETY: Unit type return maps to a C void return, which is a nil return in lua. There is no
|
||||
// equivalent to passing a unit type as an argument in C. `c_void` cannot be returned from rust
|
||||
// so it should return the unit type instead.
|
||||
//
|
||||
type To = ();
|
||||
|
||||
fn convert(self) -> Self::To {}
|
||||
fn postlude(_ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
assert!(
|
||||
conv == FfiReturnConvention::Void,
|
||||
"void type cannot be instantiated"
|
||||
);
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FromFfi for bool {
|
||||
type From = bool;
|
||||
|
||||
@@ -570,24 +595,16 @@ unsafe impl FromFfi for bool {
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for bool {
|
||||
type To = bool;
|
||||
type Into = bool;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
disp(move |f| match conv {
|
||||
FfiReturnConvention::Void => unreachable!(),
|
||||
FfiReturnConvention::ByValue => Ok(()),
|
||||
FfiReturnConvention::ByOutParam => write!(f, "{ret} = {ret} ~= 0; "),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_number_fromabi {
|
||||
($rtype:ty) => {
|
||||
unsafe impl FromFfi for $rtype {
|
||||
($rty:ty) => {
|
||||
unsafe impl FromFfi for $rty {
|
||||
type From = Self;
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
@@ -615,21 +632,13 @@ impl_number_fromabi!(f32);
|
||||
impl_number_fromabi!(f64);
|
||||
|
||||
macro_rules! impl_number_intoabi {
|
||||
($rtype:ty) => {
|
||||
unsafe impl IntoFfi for $rtype {
|
||||
type To = Self;
|
||||
($rty:ty) => {
|
||||
unsafe impl IntoFfi for $rty {
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
disp(move |f| match conv {
|
||||
FfiReturnConvention::Void => unreachable!(),
|
||||
FfiReturnConvention::ByValue => Ok(()),
|
||||
FfiReturnConvention::ByOutParam => write!(f, "{ret} = tonumber({ret}); "),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -648,21 +657,20 @@ impl_number_intoabi!(c_float);
|
||||
impl_number_intoabi!(c_double);
|
||||
|
||||
macro_rules! impl_bigint_intoabi {
|
||||
($rtype:ty) => {
|
||||
unsafe impl IntoFfi for $rtype {
|
||||
type To = Self;
|
||||
($rty:ty) => {
|
||||
unsafe impl IntoFfi for $rty {
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
disp(move |f| match conv {
|
||||
FfiReturnConvention::Void => unreachable!(),
|
||||
FfiReturnConvention::ByValue | FfiReturnConvention::ByOutParam => {
|
||||
write!(f, "{ret} = tonumber({ret}); ")
|
||||
}
|
||||
})
|
||||
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 )
|
||||
display!("{ret} = tonumber({ret}); ")
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -682,6 +690,10 @@ macro_rules! impl_const_ptr {
|
||||
display!("const_{}_ptr", T::name())
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Primitive
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
T::cdecl(display!("const *{name}"))
|
||||
}
|
||||
@@ -704,6 +716,10 @@ macro_rules! impl_mut_ptr {
|
||||
display!("{}_ptr", T::name())
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Primitive
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
T::cdecl(display!("*{name}"))
|
||||
}
|
||||
@@ -753,13 +769,13 @@ impl_ptr_fromabi!(Option<&mut T>);
|
||||
macro_rules! impl_ptr_intoabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> IntoFfi for $ty {
|
||||
type To = Self;
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
display!("if {ret} == nil then {ret} = nil; end; ")
|
||||
}
|
||||
}
|
||||
@@ -822,9 +838,9 @@ impl_ref_fromabi!(&'s mut T);
|
||||
macro_rules! impl_ref_intoabi {
|
||||
($ty:ty) => {
|
||||
unsafe impl<T: Type> IntoFfi for $ty {
|
||||
type To = Self;
|
||||
type Into = Self;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
fn convert(self) -> Self::Into {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -845,6 +861,10 @@ unsafe impl<T: Type> Type for [T] {
|
||||
display!("{}_arr", T::name())
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Aggregate
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
display!("{name}[]")
|
||||
}
|
||||
@@ -859,6 +879,10 @@ unsafe impl<T: Type, const N: usize> Type for [T; N] {
|
||||
display!("{}_arr{N}", T::name())
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Aggregate
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
display!("{name}[{N}]")
|
||||
}
|
||||
@@ -891,6 +915,10 @@ macro_rules! impl_function {
|
||||
}))
|
||||
}
|
||||
|
||||
fn ty() -> TypeType {
|
||||
TypeType::Primitive
|
||||
}
|
||||
|
||||
fn cdecl(name: impl Display) -> impl Display {
|
||||
$ret::cdecl(disp(move |f| Ok({
|
||||
let mut _n = 0;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use crate::{
|
||||
__internal::{disp, display, export},
|
||||
FfiReturnConvention, FromFfi, IntoFfi,
|
||||
FromFfi, IntoFfi,
|
||||
};
|
||||
use bstr::{BStr, BString};
|
||||
use luaffi_impl::{cdef, metatype};
|
||||
use std::{fmt::Display, mem::ManuallyDrop, ptr, slice};
|
||||
|
||||
pub const IS_UTF8_FN: &str = "luaffi_is_utf8";
|
||||
pub const DROP_BUFFER_FN: &str = "luaffi_drop_buffer";
|
||||
pub(crate) const IS_UTF8_FN: &str = "luaffi_is_utf8";
|
||||
pub(crate) const DROP_BUFFER_FN: &str = "luaffi_drop_buffer";
|
||||
|
||||
#[unsafe(export_name = "luaffi_is_utf8")]
|
||||
unsafe extern "C" fn __is_utf8(ptr: *const u8, len: usize) -> bool {
|
||||
@@ -33,7 +33,16 @@ pub struct lua_buf {
|
||||
|
||||
#[metatype]
|
||||
impl lua_buf {
|
||||
fn null() -> Self {
|
||||
// this takes a slice and decomposes it into its raw parts. caller should ensure the result is
|
||||
// used only as long as the original buffer is still alive.
|
||||
pub(crate) fn new(s: &[u8]) -> Self {
|
||||
Self {
|
||||
__ptr: s.as_ptr(),
|
||||
__len: s.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn null() -> Self {
|
||||
Self {
|
||||
__ptr: ptr::null(),
|
||||
__len: 0,
|
||||
@@ -41,6 +50,36 @@ impl lua_buf {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cdef]
|
||||
pub struct lua_buffer {
|
||||
__ptr: *mut u8,
|
||||
__len: usize,
|
||||
__cap: usize,
|
||||
}
|
||||
|
||||
#[metatype]
|
||||
impl lua_buffer {
|
||||
// this takes ownership of the Vec and decomposes it into its raw parts. the result must be
|
||||
// dropped by `__drop_buffer` (see [`DROP_BUFFER_FN`]).
|
||||
pub(crate) fn new(s: impl Into<Vec<u8>>) -> Self {
|
||||
let s = s.into();
|
||||
Self {
|
||||
__cap: s.capacity(),
|
||||
__len: s.len(),
|
||||
__ptr: ManuallyDrop::new(s).as_mut_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn null() -> Self {
|
||||
Self {
|
||||
__ptr: ptr::null_mut(),
|
||||
__len: 0,
|
||||
__cap: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'s> FromFfi for &'s [u8] {
|
||||
type From = Option<&'s lua_buf>;
|
||||
|
||||
@@ -55,6 +94,8 @@ unsafe impl<'s> FromFfi for &'s [u8] {
|
||||
f,
|
||||
r#"assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "#
|
||||
)?;
|
||||
// SAFETY: the lua_buf is only valid for as long as the string is alive. we've ensured
|
||||
// that it is alive for at least the duration of the ffi call via `require_keepalive()`.
|
||||
write!(f, "{arg} = __new(__ct.lua_buf, {arg}, #{arg}); end; ")
|
||||
})
|
||||
}
|
||||
@@ -68,22 +109,6 @@ unsafe impl<'s> FromFfi for &'s [u8] {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'s> FromFfi for &'s BStr {
|
||||
type From = <&'s [u8] as FromFfi>::From;
|
||||
|
||||
fn require_keepalive() -> bool {
|
||||
<&[u8] as FromFfi>::require_keepalive()
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
<&[u8] as FromFfi>::prelude(arg)
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
<&[u8] as FromFfi>::convert(from).into()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'s> FromFfi for &'s str {
|
||||
type From = Option<&'s lua_buf>;
|
||||
|
||||
@@ -121,7 +146,77 @@ unsafe impl<'s> FromFfi for &'s str {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_optional_ref_from {
|
||||
unsafe impl IntoFfi for &'static [u8] {
|
||||
type Into = lua_buf;
|
||||
|
||||
fn convert(self) -> Self::Into {
|
||||
// SAFETY: the slice is 'static so the resulting lua_buf is always valid
|
||||
lua_buf::new(self)
|
||||
}
|
||||
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
display!("{ret} = __intern({ret}.__ptr, {ret}.__len)")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for Vec<u8> {
|
||||
type Into = lua_buffer;
|
||||
|
||||
fn convert(self) -> Self::Into {
|
||||
lua_buffer::new(self)
|
||||
}
|
||||
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
display!(
|
||||
"do local __{ret} = {ret}; {ret} = __intern({ret}.__ptr, {ret}.__len); __C.{DROP_BUFFER_FN}(__{ret}); end; "
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_via {
|
||||
($ty:ty, $via:ty) => {
|
||||
unsafe impl<'s> FromFfi for $ty {
|
||||
type From = <$via as FromFfi>::From;
|
||||
|
||||
fn require_keepalive() -> bool {
|
||||
<$via as FromFfi>::require_keepalive()
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
<$via as FromFfi>::prelude(arg)
|
||||
}
|
||||
|
||||
fn convert(from: Self::From) -> Self {
|
||||
<$via as FromFfi>::convert(from).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_via!(&'s BStr, &'s [u8]);
|
||||
|
||||
macro_rules! impl_into_via {
|
||||
($ty:ty, $via:ty) => {
|
||||
unsafe impl IntoFfi for $ty {
|
||||
type Into = <$via as IntoFfi>::Into;
|
||||
|
||||
fn convert(self) -> Self::Into {
|
||||
<$via as IntoFfi>::convert(self.into())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
<$via as IntoFfi>::postlude(ret)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_into_via!(&'static BStr, &'static [u8]);
|
||||
impl_into_via!(&'static str, &'static BStr);
|
||||
impl_into_via!(BString, Vec<u8>);
|
||||
impl_into_via!(String, BString);
|
||||
|
||||
macro_rules! impl_optional_from {
|
||||
($ty:ty) => {
|
||||
unsafe impl<'s> FromFfi for Option<$ty> {
|
||||
type From = <$ty as FromFfi>::From;
|
||||
@@ -131,7 +226,7 @@ macro_rules! impl_optional_ref_from {
|
||||
}
|
||||
|
||||
fn prelude(arg: &str) -> impl Display {
|
||||
// avoid constructing a `lua_buf` at all for nil arguments
|
||||
// just pass a null pointer if argument is nil
|
||||
display!(
|
||||
"if {arg} ~= nil then {}end; ",
|
||||
<$ty as FromFfi>::prelude(arg)
|
||||
@@ -145,152 +240,32 @@ macro_rules! impl_optional_ref_from {
|
||||
};
|
||||
}
|
||||
|
||||
impl_optional_ref_from!(&'s [u8]);
|
||||
impl_optional_ref_from!(&'s BStr);
|
||||
impl_optional_ref_from!(&'s str);
|
||||
|
||||
unsafe impl IntoFfi 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 IntoFfi for &'static BStr {
|
||||
type To = <&'static [u8] as IntoFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
<&[u8] as IntoFfi>::convert(self.as_ref())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
<&[u8] as IntoFfi>::postlude(ret, conv)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for &'static str {
|
||||
type To = <&'static [u8] as IntoFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
<&[u8] as IntoFfi>::convert(self.as_bytes())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
<&[u8] as IntoFfi>::postlude(ret, conv)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_optional_ref_into {
|
||||
($ty:ty) => {
|
||||
unsafe impl IntoFfi for Option<$ty> {
|
||||
type To = <$ty as IntoFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
self.map_or(lua_buf::null(), <$ty as IntoFfi>::convert)
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
display!(
|
||||
"if {ret}.__ptr == nil then {ret} = nil; else {}end; ",
|
||||
<$ty as IntoFfi>::postlude(ret, conv)
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_optional_ref_into!(&'static [u8]);
|
||||
impl_optional_ref_into!(&'static BStr);
|
||||
impl_optional_ref_into!(&'static str);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cdef]
|
||||
pub struct lua_buffer {
|
||||
__ptr: *mut u8,
|
||||
__len: usize,
|
||||
__cap: usize,
|
||||
}
|
||||
|
||||
#[metatype]
|
||||
impl lua_buffer {
|
||||
fn null() -> Self {
|
||||
Self {
|
||||
__ptr: ptr::null_mut(),
|
||||
__len: 0,
|
||||
__cap: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for Vec<u8> {
|
||||
type To = lua_buffer;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
lua_buffer {
|
||||
__cap: self.capacity(),
|
||||
__len: self.len(),
|
||||
__ptr: ManuallyDrop::new(self).as_mut_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
|
||||
display!(
|
||||
"do local __{ret} = {ret}; {ret} = __intern({ret}.__ptr, {ret}.__len); __C.{DROP_BUFFER_FN}(__{ret}); end; "
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for BString {
|
||||
type To = <Vec<u8> as IntoFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
<Vec<u8> as IntoFfi>::convert(self.into())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
<Vec<u8> as IntoFfi>::postlude(ret, conv)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl IntoFfi for String {
|
||||
type To = <Vec<u8> as IntoFfi>::To;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
<Vec<u8> as IntoFfi>::convert(self.into_bytes())
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
<Vec<u8> as IntoFfi>::postlude(ret, conv)
|
||||
}
|
||||
}
|
||||
impl_optional_from!(&'s [u8]);
|
||||
impl_optional_from!(&'s BStr);
|
||||
impl_optional_from!(&'s str);
|
||||
|
||||
macro_rules! impl_optional_into {
|
||||
($ty:ty) => {
|
||||
($ty:ty, $null:expr) => {
|
||||
unsafe impl IntoFfi for Option<$ty> {
|
||||
type To = <$ty as IntoFfi>::To;
|
||||
type Into = <$ty as IntoFfi>::Into;
|
||||
|
||||
fn convert(self) -> Self::To {
|
||||
self.map_or(lua_buffer::null(), <$ty as IntoFfi>::convert)
|
||||
fn convert(self) -> Self::Into {
|
||||
self.map_or($null, <$ty as IntoFfi>::convert)
|
||||
}
|
||||
|
||||
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
|
||||
fn postlude(ret: &str) -> impl Display {
|
||||
display!(
|
||||
"if {ret}.__ptr == nil then {ret} = nil; else {}end; ",
|
||||
<$ty as IntoFfi>::postlude(ret, conv)
|
||||
<$ty as IntoFfi>::postlude(ret)
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_optional_into!(Vec<u8>);
|
||||
impl_optional_into!(BString);
|
||||
impl_optional_into!(String);
|
||||
impl_optional_into!(&'static [u8], lua_buf::null());
|
||||
impl_optional_into!(&'static BStr, lua_buf::null());
|
||||
impl_optional_into!(&'static str, lua_buf::null());
|
||||
impl_optional_into!(Vec<u8>, lua_buffer::null());
|
||||
impl_optional_into!(BString, lua_buffer::null());
|
||||
impl_optional_into!(String, lua_buffer::null());
|
||||
|
||||
Reference in New Issue
Block a user