From 1aa9b4aa026b9b55c8ed6f1faae8b1d8ab082119 Mon Sep 17 00:00:00 2001 From: luaneko Date: Tue, 24 Jun 2025 22:22:58 +1000 Subject: [PATCH] Implement IntoFfi for Result --- crates/luaffi/src/result.rs | 76 +++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/crates/luaffi/src/result.rs b/crates/luaffi/src/result.rs index 24c82cb..05f50a7 100644 --- a/crates/luaffi/src/result.rs +++ b/crates/luaffi/src/result.rs @@ -1,4 +1,72 @@ -// pub enum lua_result { -// Err(lua_error), -// Ok(T), -// } +use crate::{ + __internal::{disp, display}, + Cdef, CdefBuilder, IntoFfi, Type, TypeBuilder, TypeType, + string::{DROP_BUFFER_FN, lua_buffer}, +}; +use std::{ffi::c_int, fmt::Display}; + +#[repr(C)] +#[allow(non_camel_case_types)] +pub enum lua_result { + Err(lua_buffer), // __tag = 0 + Ok(T), // __tag = 1 +} + +unsafe impl Type for lua_result { + fn name() -> impl Display { + display!("result__{}", T::name()) + } + + fn ty() -> TypeType { + TypeType::Aggregate + } + + fn cdecl(name: impl Display) -> impl Display { + display!("struct {} {name}", Self::name()) + } + + fn build(b: &mut TypeBuilder) { + b.cdef::(); + } +} + +unsafe impl Cdef for lua_result { + fn build(b: &mut CdefBuilder) { + b.field::("__tag").inner_union(|b| { + (T::ty() != TypeType::Void).then(|| b.field::("__value")); + b.field::("__err"); + }); + } +} + +unsafe impl IntoFfi for Result { + type Into = lua_result; + + fn convert(self) -> Self::Into { + match self { + Ok(value) => lua_result::Ok(T::convert(value)), + Err(err) => lua_result::Err(lua_buffer::new(err.to_string())), + } + } + + fn postlude(ret: &str) -> impl Display { + disp(move |f| { + let ct = T::Into::name(); + write!(f, "if {ret}.__tag ~= 0 then ")?; + match T::Into::ty() { + TypeType::Void => write!(f, "{ret} = nil; "), // for void results, we don't have a __value + TypeType::Primitive => write!(f, "{ret} = {ret}.__value; "), + TypeType::Aggregate => write!(f, "{ret} = __new(__ct.{ct}, {ret}.__value); "), + }?; + write!(f, "{}", T::postlude(ret))?; + write!( + f, + "else \ + local __{ret}_msg = __intern({ret}.__err.__ptr, {ret}.__err.__len); \ + __C.{DROP_BUFFER_FN}({ret}.__err); \ + return error(__{ret}_msg); \ + end; " + ) + }) + } +}