luau_vm/state/
call_info.rs1use core::ptr::NonNull;
2
3use crate::function::RawProto;
4use crate::function::{Closure, Proto};
5use crate::handle::RawHandle;
6use crate::handle::sealed::Sealed;
7use crate::value::{RawTValue, TValueCursor};
8
9#[repr(C)]
10pub struct RawCallInfo {
11 pub base: *mut RawTValue,
12 pub function: *mut RawTValue,
13 pub top: *mut RawTValue,
14 pub proto: *mut RawProto,
15 pub saved: RawCallInfoSaved,
16 pub n_results: i32,
17 pub flags: u32,
18}
19
20#[repr(C)]
21pub union RawCallInfoSaved {
22 pub saved_pc: *const u32,
23 pub errfunc: i32,
24}
25
26#[derive(Clone, Copy, PartialEq, Eq)]
27#[repr(transparent)]
28pub struct CallInfo {
36 raw: NonNull<RawCallInfo>,
37}
38
39#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
40#[repr(transparent)]
41pub struct CallInfoCursor(*mut RawCallInfo);
46
47#[allow(
48 clippy::missing_safety_doc,
49 reason = "CallInfo's shared raw-view contract is documented on CallInfo"
50)]
51impl CallInfo {
52 pub const unsafe fn from_raw(raw: NonNull<RawCallInfo>) -> Self {
53 Self { raw }
54 }
55
56 pub fn base(&self) -> TValueCursor {
57 unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().base) }
58 }
59
60 pub fn function(&self) -> TValueCursor {
61 unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().function) }
62 }
63
64 pub fn top(&self) -> TValueCursor {
65 unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().top) }
66 }
67
68 pub fn set_base(&self, base: TValueCursor) {
69 unsafe {
70 self.as_ptr().as_mut().unwrap_unchecked().base = base.as_ptr();
71 }
72 }
73
74 pub fn set_function(&self, function: TValueCursor) {
75 unsafe {
76 self.as_ptr().as_mut().unwrap_unchecked().function = function.as_ptr();
77 }
78 }
79
80 pub fn set_top(&self, top: TValueCursor) {
81 unsafe {
82 self.as_ptr().as_mut().unwrap_unchecked().top = top.as_ptr();
83 }
84 }
85
86 pub fn proto(&self) -> Option<Proto> {
87 let proto = unsafe { self.as_ptr().as_ref().unwrap_unchecked().proto };
88 NonNull::new(proto).map(|raw| unsafe { Proto::from_raw(raw) })
89 }
90
91 pub fn set_proto(&self, proto: Option<Proto>) {
92 unsafe {
93 self.as_ptr().as_mut().unwrap_unchecked().proto =
94 proto.map_or(core::ptr::null_mut(), |proto| proto.as_ptr());
95 }
96 }
97
98 pub unsafe fn saved_pc(&self) -> *const u32 {
99 unsafe { self.as_ptr().as_ref().unwrap_unchecked().saved.saved_pc }
100 }
101
102 pub unsafe fn set_saved_pc(&self, saved_pc: *const u32) {
103 unsafe {
104 self.as_ptr().as_mut().unwrap_unchecked().saved.saved_pc = saved_pc;
105 }
106 }
107
108 pub unsafe fn errfunc(&self) -> i32 {
109 unsafe { self.as_ptr().as_ref().unwrap_unchecked().saved.errfunc }
110 }
111
112 pub unsafe fn set_errfunc(&self, errfunc: i32) {
113 unsafe {
114 self.as_ptr().as_mut().unwrap_unchecked().saved.errfunc = errfunc;
115 }
116 }
117
118 pub unsafe fn init_call(
119 &self,
120 function: TValueCursor,
121 top: TValueCursor,
122 n_results: i32,
123 proto: Option<Proto>,
124 ) {
125 unsafe {
126 self.set_function(function);
127 self.set_base(function.add(1));
128 self.set_top(top);
129 self.set_proto(proto);
130 self.set_saved_pc(core::ptr::null());
131 self.as_ptr().as_mut().unwrap_unchecked().flags = 0;
132 self.as_ptr().as_mut().unwrap_unchecked().n_results = n_results;
133 }
134 }
135
136 pub unsafe fn rebase_stack(&self, old_stack: TValueCursor, new_stack: TValueCursor) {
137 unsafe {
138 self.set_top(new_stack.add(self.top().addr_offset_from(old_stack) as usize));
139 self.set_base(new_stack.add(self.base().addr_offset_from(old_stack) as usize));
140 self.set_function(new_stack.add(self.function().addr_offset_from(old_stack) as usize));
141 }
142 }
143
144 pub unsafe fn function_closure(&self) -> Closure {
146 unsafe { self.function().value_unchecked().closure_value() }
147 }
148
149 pub unsafe fn is_lua_function(&self) -> bool {
151 unsafe { self.function_closure().is_lua() }
152 }
153
154 pub unsafe fn is_lua(&self) -> bool {
156 unsafe { self.function().value_unchecked().is_function() && self.is_lua_function() }
157 }
158}
159
160#[allow(
161 clippy::missing_safety_doc,
162 reason = "CallInfoCursor's navigation contract is documented on CallInfoCursor"
163)]
164impl CallInfoCursor {
165 pub const fn as_ptr(&self) -> *mut RawCallInfo {
169 self.0
170 }
171
172 pub const fn from_ptr(raw: *mut RawCallInfo) -> Self {
173 Self(raw)
174 }
175
176 pub const fn is_null(&self) -> bool {
177 self.0.is_null()
178 }
179
180 pub unsafe fn call_info_unchecked(&self) -> CallInfo {
181 debug_assert!(!self.is_null());
182 unsafe { CallInfo::from_raw(NonNull::new_unchecked(self.0)) }
183 }
184
185 pub fn call_info(&self) -> Option<CallInfo> {
186 NonNull::new(self.0).map(|raw| unsafe { CallInfo::from_raw(raw) })
187 }
188
189 pub unsafe fn add(self, count: usize) -> Self {
190 unsafe { Self::from_ptr(self.0.add(count)) }
191 }
192
193 pub unsafe fn sub(self, count: usize) -> Self {
194 unsafe { Self::from_ptr(self.0.sub(count)) }
195 }
196
197 pub unsafe fn offset(self, count: isize) -> Self {
198 unsafe { Self::from_ptr(self.0.offset(count)) }
199 }
200
201 pub unsafe fn offset_from(self, other: Self) -> isize {
202 unsafe { self.0.offset_from(other.0) }
203 }
204}
205
206impl Sealed for CallInfo {}
207
208impl RawHandle for CallInfo {
209 type Raw = RawCallInfo;
210
211 fn as_ptr(&self) -> *mut Self::Raw {
212 self.raw.as_ptr()
213 }
214}
215
216impl AsRef<CallInfo> for CallInfo {
217 fn as_ref(&self) -> &CallInfo {
218 self
219 }
220}
221
222impl AsRef<CallInfoCursor> for CallInfoCursor {
223 fn as_ref(&self) -> &CallInfoCursor {
224 self
225 }
226}