diff --git a/crates/luaffi/src/lib.rs b/crates/luaffi/src/lib.rs index fee204a..5e1fc92 100644 --- a/crates/luaffi/src/lib.rs +++ b/crates/luaffi/src/lib.rs @@ -129,7 +129,7 @@ fn cache_local(f: &mut Formatter, list: &[(&str, &str)]) -> fmt::Result { #[derive(Debug, Clone, Default)] pub struct Registry { types: HashSet, - funcs: HashSet, + decls: HashSet, cdef: String, lua: String, } @@ -146,16 +146,16 @@ impl Registry { pub fn include(&mut self) -> &mut Self { self.types .insert(T::name().to_string()) - .then(|| T::build(&mut TypeBuilder::new::(self))); + .then(|| T::build(&mut TypeBuilder::new(self))); self } pub fn declare(&mut self, name: impl Display) -> &mut Self { assert!(T::ty() != TypeType::Void, "cannot declare void type"); self.include::() - .funcs - .insert(name.to_string()) - .then(|| writeln!(self.cdef, "{};", T::extern_cdecl(name)).unwrap()); + .decls + .insert(T::extern_cdecl(&name).to_string()) + .then(|| writeln!(self.cdef, "{};", T::extern_cdecl(&name)).unwrap()); self } @@ -184,7 +184,7 @@ impl Display for Registry { cache_local(f, CACHE_LIBS)?; cache_local(f, CACHE_LOCALS)?; writeln!(f, "{}", include_str!("./lib.lua"))?; - writeln!(f, "__cdef [[\n{}\n]];", self.cdef.trim())?; + writeln!(f, "__cdef [[\n{}\n]];", self.cdef.trim_end())?; write!(f, "{}", self.lua) } } @@ -210,31 +210,23 @@ pub enum TypeType { #[derive(Debug)] pub struct TypeBuilder<'r> { - registry: &'r mut Registry, + reg: &'r mut Registry, } impl<'r> TypeBuilder<'r> { - fn new(registry: &'r mut Registry) -> Self { - let ct = T::name(); - let cdecl = T::cdecl(""); - writeln!(registry.lua, r#"__ct.{ct} = __typeof("{cdecl}");"#).unwrap(); - Self { registry } - } - - pub fn include(&mut self) -> &mut Self { - self.registry.include::(); - self + fn new(reg: &'r mut Registry) -> Self { + Self { reg } } pub fn cdef(&mut self) -> &mut Self { - let mut b = CdefBuilder::new::(self.registry); + let mut b = CdefBuilder::new::(self.reg); ::build(&mut b); drop(b); self } pub fn metatype(&mut self) -> &mut Self { - let mut b = MetatypeBuilder::new::(self.registry); + let mut b = MetatypeBuilder::new::(self.reg); ::build(&mut b); drop(b); self @@ -251,16 +243,16 @@ pub unsafe trait Cdef: Type { #[derive(Debug)] pub struct CdefBuilder<'r> { - registry: &'r mut Registry, + reg: &'r mut Registry, cdef: String, align: usize, opaque: usize, } impl<'r> CdefBuilder<'r> { - fn new(registry: &'r mut Registry) -> Self { + fn new(reg: &'r mut Registry) -> Self { Self { - registry, + reg, cdef: format!("{} {{ ", T::cdecl("")), align: mem::align_of::(), opaque: 0, @@ -269,7 +261,7 @@ impl<'r> CdefBuilder<'r> { pub fn field(&mut self, name: impl Display) -> &mut Self { assert!(T::ty() != TypeType::Void, "cannot declare void field"); - self.registry.include::(); + self.reg.include::(); self.field_raw(T::cdecl(name)) } @@ -303,14 +295,11 @@ impl<'r> CdefBuilder<'r> { impl<'r> Drop for CdefBuilder<'r> { fn drop(&mut self) { let Self { - registry, - cdef, - align, - .. + reg, cdef, align, .. } = self; - registry.cdef.push_str(cdef); - writeln!(registry.cdef, "}} __attribute__((aligned({align})));").unwrap(); + reg.cdef.push_str(cdef); + writeln!(reg.cdef, "}} __attribute__((aligned({align})));").unwrap(); } } @@ -321,26 +310,34 @@ pub unsafe trait Metatype { #[derive(Debug)] pub struct MetatypeBuilder<'r> { - registry: &'r mut Registry, + reg: &'r mut Registry, ct: String, cdef: String, lua: String, lua_includes: Vec<&'static str>, + has_index: bool, } impl<'r> MetatypeBuilder<'r> { - fn new(registry: &'r mut Registry) -> Self { + fn new(reg: &'r mut Registry) -> Self { + // NOTE: this needs to be written first, because recursively included dependency types might + // need it + let ct = T::Target::name(); + let cdecl = T::Target::cdecl(""); + writeln!(reg.lua, r#"__ct.{ct} = __typeof("{cdecl}");"#).unwrap(); + Self { - registry, + reg, ct: T::Target::name().to_string(), cdef: String::new(), - lua: r#"do local __mt, __idx = {}, {}; __mt.__index = __idx; "#.into(), + lua: String::new(), lua_includes: vec![], + has_index: false, } } pub fn declare(&mut self, name: impl Display) -> &mut Self { - self.registry.declare::(name); + self.reg.declare::(name); self } @@ -357,11 +354,13 @@ impl<'r> MetatypeBuilder<'r> { write!(self.lua, "__idx.{name} = ").unwrap(); f(&mut MetatypeFunctionBuilder::new(self)); writeln!(self.lua, ";").unwrap(); + self.has_index = true; self } pub fn index_raw(&mut self, name: impl Display, value: impl Display) -> &mut Self { writeln!(self.lua, "__idx.{name} = {value};").unwrap(); + self.has_index = true; self } @@ -385,18 +384,27 @@ impl<'r> MetatypeBuilder<'r> { impl<'r> Drop for MetatypeBuilder<'r> { fn drop(&mut self) { let Self { - registry, + reg, ct, cdef, lua, - lua_includes: lua_postlude, + lua_includes, + has_index, } = self; - registry.cdef.push_str(cdef); - registry.lua.push_str(lua); - writeln!(registry.lua, r#"__metatype(__ct.{ct}, __mt); end;"#).unwrap(); - for lua in lua_postlude { - writeln!(registry.lua, r#"do {lua} end;"#).unwrap(); + write!(reg.lua, r#"do local __mt = {{}}; "#).unwrap(); + + if *has_index { + write!(reg.lua, r#"local __idx = {{}}; __mt.__index = __idx; "#).unwrap(); + } + + reg.cdef.push_str(cdef); + reg.lua.push_str(lua.trim_end()); + + writeln!(reg.lua, r#"__metatype(__ct.{ct}, __mt); end;"#).unwrap(); + + for lua in lua_includes { + writeln!(reg.lua, "do {}\nend;", lua.trim_end()).unwrap(); } } } @@ -471,7 +479,7 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> { ); let Self { - metatype: MetatypeBuilder { registry, .. }, + metatype: MetatypeBuilder { reg, .. }, lparams, cparams, cargs, @@ -480,7 +488,7 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> { .. } = self; - registry.include::(); + reg.include::(); (!lparams.is_empty()).then(|| lparams.push_str(", ")); (!cparams.is_empty()).then(|| cparams.push_str(", ")); @@ -552,13 +560,7 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> { pub fn call(&mut self, func: impl Display) { let Self { - metatype: - MetatypeBuilder { - registry, - cdef, - lua, - .. - }, + metatype: MetatypeBuilder { reg, cdef, lua, .. }, lparams, cparams, cargs, @@ -567,7 +569,7 @@ impl<'r, 'm> MetatypeFunctionBuilder<'r, 'm> { .. } = self; - registry.include::(); + reg.include::(); write!(lua, "function({lparams}) {prelude}").unwrap(); match T::convention() { @@ -812,7 +814,7 @@ macro_rules! impl_ptr { } fn build(b: &mut TypeBuilder) { - b.include::(); + b.reg.include::(); } } }; @@ -1009,7 +1011,7 @@ where } fn build(b: &mut TypeBuilder) { - b.include::(); + b.reg.include::(); } } @@ -1039,7 +1041,7 @@ where } fn build(b: &mut TypeBuilder) { - b.include::(); + b.reg.include::(); } } @@ -1103,8 +1105,8 @@ macro_rules! impl_externcfn { } fn build(b: &mut TypeBuilder) { - $(b.include::<$arg>();)* - b.include::<$ret>(); + $(b.reg.include::<$arg>();)* + b.reg.include::<$ret>(); } } }; diff --git a/crates/luaffi/src/option.rs b/crates/luaffi/src/option.rs index 56865c0..99e5dfa 100644 --- a/crates/luaffi/src/option.rs +++ b/crates/luaffi/src/option.rs @@ -1,6 +1,6 @@ use crate::{ __internal::{disp, display, type_id}, - Cdef, CdefBuilder, IntoFfi, KEEP_FN, Type, TypeBuilder, TypeType, + Cdef, CdefBuilder, IntoFfi, KEEP_FN, Metatype, MetatypeBuilder, Type, TypeBuilder, TypeType, }; use std::{ffi::c_int, fmt::Display}; @@ -25,7 +25,7 @@ unsafe impl Type for lua_option { } fn build(b: &mut TypeBuilder) { - b.cdef::(); + b.cdef::().metatype::(); } } @@ -36,6 +36,11 @@ unsafe impl Cdef for lua_option { } } +unsafe impl Metatype for lua_option { + type Target = Self; + fn build(_b: &mut MetatypeBuilder) {} +} + unsafe impl> IntoFfi for Option { type Into = lua_option; diff --git a/crates/luaffi/src/result.rs b/crates/luaffi/src/result.rs index 5d6e01f..f6e107d 100644 --- a/crates/luaffi/src/result.rs +++ b/crates/luaffi/src/result.rs @@ -1,6 +1,6 @@ use crate::{ __internal::{disp, display, type_id}, - Cdef, CdefBuilder, IntoFfi, KEEP_FN, Type, TypeBuilder, TypeType, + Cdef, CdefBuilder, IntoFfi, KEEP_FN, Metatype, MetatypeBuilder, Type, TypeBuilder, TypeType, string::{DROP_BUFFER_FN, lua_buffer}, }; use std::{ffi::c_int, fmt::Display}; @@ -26,7 +26,7 @@ unsafe impl Type for lua_result { } fn build(b: &mut TypeBuilder) { - b.cdef::(); + b.cdef::().metatype::(); } } @@ -39,6 +39,11 @@ unsafe impl Cdef for lua_result { } } +unsafe impl Metatype for lua_result { + type Target = Self; + fn build(_b: &mut MetatypeBuilder) {} +} + unsafe impl, E: Display> IntoFfi for Result { type Into = lua_result;