1use core::ptr::NonNull;
2
3use crate::Table;
4use crate::buffer::Buffer;
5use crate::function::{Closure, Proto, UpVal};
6use crate::handle::RawHandle;
7use crate::state::ThreadState;
8use crate::string::TString;
9use crate::thread::Thread;
10use crate::types::{
11 LUA_TBUFFER, LUA_TCLASS, LUA_TFUNCTION, LUA_TOBJECT, LUA_TPROTO, LUA_TSTRING, LUA_TTABLE,
12 LUA_TTHREAD, LUA_TUPVALUE, LUA_TUSERDATA,
13};
14use crate::userdata::Userdata;
15use crate::{Class, Object};
16
17use crate::table::LuaNode;
18use crate::value::TValue;
19
20#[repr(C)]
21pub struct RawGcObject {
22 pub tt: u8,
23 pub marked: u8,
24 pub memcat: u8,
25}
26
27#[derive(Clone, Copy, PartialEq, Eq)]
28#[repr(transparent)]
29pub struct GcObject {
37 raw: NonNull<RawGcObject>,
38}
39
40#[allow(
47 clippy::missing_safety_doc,
48 reason = "the sole method uses the unsafe trait's closed conversion contract"
49)]
50pub(crate) unsafe trait GcHandle: Into<GcObject> {
51 unsafe fn from_gc_object(object: GcObject) -> Self;
52}
53
54#[allow(
55 clippy::missing_safety_doc,
56 reason = "GcObject's shared raw-handle contract is documented on GcObject"
57)]
58impl GcObject {
59 pub const unsafe fn from_raw(raw: NonNull<RawGcObject>) -> Self {
60 Self { raw }
61 }
62
63 pub unsafe fn init_header(&self, thread: &Thread, type_tag: u8) {
65 unsafe {
66 let raw = self.as_ptr().as_mut().unwrap_unchecked();
67 raw.memcat = thread.as_ptr().as_ref().unwrap_unchecked().active_memcat;
68 raw.marked = thread.global().white();
69 raw.tt = type_tag;
70 }
71 }
72
73 pub unsafe fn to_string(&self) -> TString {
75 debug_assert_eq!(
76 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
77 LUA_TSTRING as u8
78 );
79 unsafe { TString::from_raw(self.raw.cast()) }
80 }
81
82 pub unsafe fn to_userdata(&self) -> Userdata {
84 debug_assert_eq!(
85 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
86 LUA_TUSERDATA as u8
87 );
88 unsafe { Userdata::from_raw(self.raw.cast()) }
89 }
90
91 pub unsafe fn to_closure(&self) -> Closure {
93 debug_assert_eq!(
94 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
95 LUA_TFUNCTION as u8
96 );
97 unsafe { Closure::from_raw(self.raw.cast()) }
98 }
99
100 pub unsafe fn to_table(&self) -> Table {
102 debug_assert_eq!(
103 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
104 LUA_TTABLE as u8
105 );
106 unsafe { Table::from_raw(self.raw.cast()) }
107 }
108
109 pub unsafe fn to_proto(&self) -> Proto {
111 debug_assert_eq!(
112 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
113 LUA_TPROTO as u8
114 );
115 unsafe { Proto::from_raw(self.raw.cast()) }
116 }
117
118 pub unsafe fn to_upvalue(&self) -> UpVal {
120 debug_assert_eq!(
121 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
122 LUA_TUPVALUE as u8
123 );
124 unsafe { UpVal::from_raw(self.raw.cast()) }
125 }
126
127 pub unsafe fn to_state(&self) -> Thread {
129 debug_assert_eq!(
130 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
131 LUA_TTHREAD as u8
132 );
133 unsafe { Thread::from_raw(self.raw.cast()) }
134 }
135
136 pub unsafe fn to_buffer(&self) -> Buffer {
138 debug_assert_eq!(
139 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
140 LUA_TBUFFER as u8
141 );
142 unsafe { Buffer::from_raw(self.raw.cast()) }
143 }
144
145 pub unsafe fn to_class(&self) -> Class {
147 debug_assert_eq!(
148 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
149 LUA_TCLASS as u8
150 );
151 unsafe { Class::from_raw(self.raw.cast()) }
152 }
153
154 pub unsafe fn to_object(&self) -> Object {
156 debug_assert_eq!(
157 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt },
158 LUA_TOBJECT as u8
159 );
160 unsafe { Object::from_raw(self.raw.cast()) }
161 }
162}
163
164impl From<TValue> for GcObject {
165 fn from(value: TValue) -> Self {
166 value.gc_value()
167 }
168}
169
170impl From<TString> for GcObject {
171 fn from(value: TString) -> Self {
172 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
173 }
174}
175
176impl From<Table> for GcObject {
177 fn from(value: Table) -> Self {
178 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
179 }
180}
181
182impl From<LuaNode> for GcObject {
183 fn from(value: LuaNode) -> Self {
184 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
185 }
186}
187
188impl From<Proto> for GcObject {
189 fn from(value: Proto) -> Self {
190 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
191 }
192}
193
194impl From<Closure> for GcObject {
195 fn from(value: Closure) -> Self {
196 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
197 }
198}
199
200impl From<UpVal> for GcObject {
201 fn from(value: UpVal) -> Self {
202 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
203 }
204}
205
206impl From<Userdata> for GcObject {
207 fn from(value: Userdata) -> Self {
208 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
209 }
210}
211
212impl From<Buffer> for GcObject {
213 fn from(value: Buffer) -> Self {
214 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
215 }
216}
217
218impl From<Thread> for GcObject {
219 fn from(value: Thread) -> Self {
220 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
221 }
222}
223
224impl From<&Thread> for GcObject {
225 fn from(value: &Thread) -> Self {
226 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
227 }
228}
229
230impl From<Class> for GcObject {
231 fn from(value: Class) -> Self {
232 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
233 }
234}
235
236impl From<Object> for GcObject {
237 fn from(value: Object) -> Self {
238 unsafe { Self::from_raw(NonNull::new_unchecked(value.as_ptr().cast())) }
239 }
240}
241
242unsafe impl GcHandle for TString {
243 unsafe fn from_gc_object(object: GcObject) -> Self {
244 unsafe { Self::from_raw(object.raw.cast()) }
245 }
246}
247
248unsafe impl GcHandle for Table {
249 unsafe fn from_gc_object(object: GcObject) -> Self {
250 unsafe { Self::from_raw(object.raw.cast()) }
251 }
252}
253
254unsafe impl GcHandle for Proto {
255 unsafe fn from_gc_object(object: GcObject) -> Self {
256 unsafe { Self::from_raw(object.raw.cast()) }
257 }
258}
259
260unsafe impl GcHandle for Closure {
261 unsafe fn from_gc_object(object: GcObject) -> Self {
262 unsafe { Self::from_raw(object.raw.cast()) }
263 }
264}
265
266unsafe impl GcHandle for UpVal {
267 unsafe fn from_gc_object(object: GcObject) -> Self {
268 unsafe { Self::from_raw(object.raw.cast()) }
269 }
270}
271
272unsafe impl GcHandle for Userdata {
273 unsafe fn from_gc_object(object: GcObject) -> Self {
274 unsafe { Self::from_raw(object.raw.cast()) }
275 }
276}
277
278unsafe impl GcHandle for Buffer {
279 unsafe fn from_gc_object(object: GcObject) -> Self {
280 unsafe { Self::from_raw(object.raw.cast()) }
281 }
282}
283
284unsafe impl GcHandle for Thread {
285 unsafe fn from_gc_object(object: GcObject) -> Self {
286 unsafe { Self::from_raw(object.raw.cast()) }
287 }
288}
289
290unsafe impl GcHandle for Class {
291 unsafe fn from_gc_object(object: GcObject) -> Self {
292 unsafe { Self::from_raw(object.raw.cast()) }
293 }
294}
295
296unsafe impl GcHandle for Object {
297 unsafe fn from_gc_object(object: GcObject) -> Self {
298 unsafe { Self::from_raw(object.raw.cast()) }
299 }
300}
301impl crate::handle::sealed::Sealed for GcObject {}
302impl RawHandle for GcObject {
303 type Raw = RawGcObject;
304
305 fn as_ptr(&self) -> *mut Self::Raw {
306 self.raw.as_ptr()
307 }
308}
309
310impl AsRef<GcObject> for GcObject {
311 fn as_ref(&self) -> &GcObject {
312 self
313 }
314}