use core::ptr::NonNull;
use crate::Table;
use crate::buffer::Buffer;
use crate::function::{Closure, Proto, UpVal};
use crate::handle::RawHandle;
use crate::state::ThreadState;
use crate::string::TString;
use crate::thread::Thread;
use crate::types::{
LUA_TBUFFER, LUA_TCLASS, LUA_TFUNCTION, LUA_TOBJECT, LUA_TPROTO, LUA_TSTRING, LUA_TTABLE,
LUA_TTHREAD, LUA_TUPVALUE, LUA_TUSERDATA,
};
use crate::userdata::Userdata;
use crate::{Class, Object};
use crate::table::LuaNode;
use crate::value::TValue;
#[repr(C)]
pub struct RawGcObject {
pub tt: u8,
pub marked: u8,
pub memcat: u8,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct GcObject {
raw: NonNull<RawGcObject>,
}
#[allow(
clippy::missing_safety_doc,
reason = "the sole method uses the unsafe trait's closed conversion contract"
)]
pub(crate) unsafe trait GcHandle: Into<GcObject> {
unsafe fn from_gc_object(object: GcObject) -> Self;
}
#[allow(
clippy::missing_safety_doc,
reason = "GcObject's shared raw-handle contract is documented on GcObject"
)]
impl GcObject {
pub const unsafe fn from_raw(raw: NonNull<RawGcObject>) -> Self {
Self { raw }
}
pub unsafe fn init_header(&self, thread: &Thread, type_tag: u8) {
unsafe {
let raw = self.as_ptr().as_mut().unwrap_unchecked();
raw.memcat = thread.as_ptr().as_ref().unwrap_unchecked().active_memcat;
raw.marked = thread.global().white();
raw.tt = type_tag;
}
}
pub unsafe fn to_string(&self) -> TString {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TSTRING as u8
);
unsafe { TString::from_raw(self.raw.cast()) }
}
pub unsafe fn to_userdata(&self) -> Userdata {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TUSERDATA as u8
);
unsafe { Userdata::from_raw(self.raw.cast()) }
}
pub unsafe fn to_closure(&self) -> Closure {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TFUNCTION as u8
);
unsafe { Closure::from_raw(self.raw.cast()) }
}
pub unsafe fn to_table(&self) -> Table {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TTABLE as u8
);
unsafe { Table::from_raw(self.raw.cast()) }
}
pub unsafe fn to_proto(&self) -> Proto {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TPROTO as u8
);
unsafe { Proto::from_raw(self.raw.cast()) }
}
pub unsafe fn to_upvalue(&self) -> UpVal {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TUPVALUE as u8
);
unsafe { UpVal::from_raw(self.raw.cast()) }
}
pub unsafe fn to_state(&self) -> Thread {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TTHREAD as u8
);
unsafe { Thread::from_raw(self.raw.cast()) }
}
pub unsafe fn to_buffer(&self) -> Buffer {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TBUFFER as u8
);
unsafe { Buffer::from_raw(self.raw.cast()) }
}
pub unsafe fn to_class(&self) -> Class {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TCLASS as u8
);
unsafe { Class::from_raw(self.raw.cast()) }
}
pub unsafe fn to_object(&self) -> Object {
debug_assert_eq!(
unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
LUA_TOBJECT as u8
);
unsafe { Object::from_raw(self.raw.cast()) }
}
}
impl From<TValue> for GcObject {
fn from(value: TValue) -> Self {
value.gc_value()
}
}
impl From<TString> for GcObject {
fn from(value: TString) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Table> for GcObject {
fn from(value: Table) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<LuaNode> for GcObject {
fn from(value: LuaNode) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Proto> for GcObject {
fn from(value: Proto) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Closure> for GcObject {
fn from(value: Closure) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<UpVal> for GcObject {
fn from(value: UpVal) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Userdata> for GcObject {
fn from(value: Userdata) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Buffer> for GcObject {
fn from(value: Buffer) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Thread> for GcObject {
fn from(value: Thread) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<&Thread> for GcObject {
fn from(value: &Thread) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Class> for GcObject {
fn from(value: Class) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
impl From<Object> for GcObject {
fn from(value: Object) -> Self {
unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
}
}
unsafe impl GcHandle for TString {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Table {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Proto {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Closure {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for UpVal {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Userdata {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Buffer {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Thread {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Class {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
unsafe impl GcHandle for Object {
unsafe fn from_gc_object(object: GcObject) -> Self {
unsafe { Self::from_raw(object.raw.cast()) }
}
}
impl crate::handle::sealed::Sealed for GcObject {}
impl RawHandle for GcObject {
type Raw = RawGcObject;
fn as_ptr(&self) -> *mut Self::Raw {
self.raw.as_ptr()
}
}
impl AsRef<GcObject> for GcObject {
fn as_ref(&self) -> &GcObject {
self
}
}