low_luajit/lua/debug.rs
1use core::{ffi::CStr, mem::{self, MaybeUninit}, ptr};
2use crate::{LuaState, SafeFn, ffi::{self, LUA_IDSIZE, lua_Debug, lua_Hook}, map_ptr};
3
4#[cfg(doc)]
5use crate::CFunction;
6
7/// Debugging function that is called by specified [`HookEvent`]s.
8///
9/// See [`LuaState::set_hook`] for more information on how to enable an `Hook`.
10/// There can only be one `Hook` enabled at a time.
11///
12/// When called, `info` can be used to retrieve the [`HookEvent`] that called the hook (see [`DebugInfo::event`]).
13///
14/// If [`HookEvent::Line`] is the event that called the `Hook`, [`DebugInfo::current_line`] will also be set.
15///
16/// To get more information about the function that was running at the time,
17/// [`LuaState::get_info`] can be called using `info` without needing to specify a function using [`LuaState::get_stack`].
18///
19/// While the current `Hook` is running, it cannot be called again.
20/// Which means it is possible to call other functions from within the hook itself without issues.
21///
22/// Just like [`CFunction`], this type is technically a *subset* of [`lua_Hook`], as it only allows safe functions.
23/// Different methods will use either [`lua_Hook`] or `Hook` based on if they work with only safe functions or not.
24pub type Hook = extern "C-unwind" fn(lua: LuaState, info: &mut DebugInfo);
25
26impl SafeFn for Hook {
27 type RawFn = lua_Hook;
28
29 #[inline]
30 unsafe fn from_raw(raw: lua_Hook) -> Self {
31 // SAFETY: lua_Hook and Hook are effectively the same.
32 unsafe { mem::transmute(raw) }
33 }
34
35 #[inline]
36 fn to_raw(self) -> lua_Hook {
37 // SAFETY: Hook and lua_Hook are effectively the same.
38 unsafe { mem::transmute(self) }
39 }
40}
41
42/// All possible event types that can call the current [`Hook`].
43#[repr(i32)]
44#[derive(Debug, Clone, Copy)]
45pub enum HookEvent {
46 /// Calls the current [`Hook`] whenever a function is called, just after Lua enters the function but before it receives its arguments.
47 Call = ffi::LUA_HOOKCALL,
48
49 /// Calls the current [`Hook`] whenever a called function returns, just before Lua leaves the function.
50 ///
51 /// The values being returned by the returning function cannot be accessed.
52 Return = ffi::LUA_HOOKRET,
53
54 /// Calls the current [`Hook`] whenever a new line of code is executed or when Lua jumps back to a previous (or the same) line.
55 ///
56 /// This event only happens for Lua functions (not [`CFunction`]s).
57 Line = ffi::LUA_HOOKLINE,
58
59 /// Calls the current [`Hook`] every time after Lua executes a specified amount of instructions (see [`LuaState::set_hook`]).
60 ///
61 /// This event only happens for Lua functions (not [`CFunction`]s).
62 Count = ffi::LUA_HOOKCOUNT,
63}
64
65impl HookEvent {
66 /// [`HookEvent::Call`]'s mask value.
67 ///
68 /// See [`LuaState::set_hook`] for more information.
69 pub const MASK_CALL: i32 = ffi::LUA_MASKCALL;
70
71 /// [`HookEvent::Return`]'s mask value.
72 ///
73 /// See [`LuaState::set_hook`] for more information.
74 pub const MASK_RETURN: i32 = ffi::LUA_MASKRET;
75
76 /// [`HookEvent::Line`]'s mask value.
77 ///
78 /// See [`LuaState::set_hook`] for more information.
79 pub const MASK_LINE: i32 = ffi::LUA_MASKLINE;
80
81 /// [`HookEvent::Count`]'s mask value.
82 ///
83 /// See [`LuaState::set_hook`] for more information.
84 pub const MASK_COUNT: i32 = ffi::LUA_MASKCOUNT;
85
86 /// Returns this `HookEvent`'s mask value.
87 ///
88 /// See [`LuaState::set_hook`] for more information.
89 #[inline]
90 #[must_use]
91 pub const fn as_mask(self) -> i32 {
92 1 << self as i32
93 }
94}
95
96/// Activation record related to a specified active function.
97///
98/// All internal fields of this record may be unset if not requested,
99/// the methods describe how to request the field they return.
100///
101/// `DebugInfo`s can be directly created and used (see [`DebugInfo::new`]) or are passed as arguments to hooks (see [`Hook`]).
102///
103/// Requesting information related to different functions using the same `DebugInfo`
104/// will result in the activation record containing information related to both functions simultaneously...which could be confusing.
105/// *(Unless the requested information is the same both times, in which case all the info is just overwritten.)*
106#[repr(transparent)]
107#[derive(Debug, Clone)]
108pub struct DebugInfo(lua_Debug);
109
110/// Extracts the possibly uninitialized field only if the `DebugInfo::IS_FULLY_INIT` flag is toggled on.
111///
112/// Otherwise it makes the function return `None`.
113macro_rules! get_maybe_uninit_field {
114 ($self:ident.$zero:literal.$field:ident) => {
115 if $self.is_fully_init() {
116 // SAFETY: IS_FULLY_INIT should only be toggled on when all fields are initialized.
117 unsafe { $self.0.$field.assume_init() }
118 } else {
119 return None;
120 }
121 };
122 (&raw $self:ident.$zero:literal.$field:ident) => {
123 if $self.is_fully_init() { $self.0.$field.as_ptr() } else { return None; }
124 };
125}
126
127impl DebugInfo {
128 /// Creates a new `DebugInfo`.
129 ///
130 /// All the internal fields of the returned activation record will be unset, see [`LuaState::get_info`] to request information.
131 #[inline]
132 #[must_use]
133 pub const fn new() -> Self {
134 Self(lua_Debug {
135 event: -1 | Self::IS_FULLY_INIT,
136 name: MaybeUninit::new(ptr::null()),
137 namewhat: MaybeUninit::new(ptr::null()),
138 what: MaybeUninit::new(ptr::null()),
139 source: MaybeUninit::new(ptr::null()),
140 currentline: -1,
141 nups: MaybeUninit::new(-1),
142 linedefined: MaybeUninit::new(-1),
143 lastlinedefined: MaybeUninit::new(-1),
144 short_src: MaybeUninit::new([1; ffi::LUA_IDSIZE]),
145 i_ci: 0,
146 })
147 }
148
149 /// Wraps a pre-existing raw [`lua_Debug`].
150 ///
151 /// # Safety
152 ///
153 /// If all `MaybeUninit` fields are initialized:
154 /// - `name`, `namewhat`, `what`, and `source` must either be null or point to valid nul-terminated strings.
155 /// - `event` must either be `-1` or the numerical value of any [`HookEvent`] value bit or'd with `1 << 31`.
156 ///
157 /// If all `MaybeUninit` fields are uninitialized:
158 /// - `event` must be just the numerical value of any [`HookEvent`] value.
159 ///
160 /// A non-modified [`lua_Debug`] obtained from [`DebugInfo::into_raw`] should always be safe to use.
161 ///
162 /// If the private field is somehow accessed, it should preferably be kept at `0` or otherwise any value Lua might set it to.
163 #[inline]
164 #[must_use]
165 pub const unsafe fn from_raw(raw: lua_Debug) -> Self {
166 Self(raw)
167 }
168
169 /// Returns the wrapped [`lua_Debug`].
170 ///
171 /// There are no guarantees on the raw fields of the returned [`lua_Debug`]:
172 /// some fields may have unexpected values and the `MaybeUninit` fields may not be initialized.
173 ///
174 /// The raw [`lua_Debug`] can be safely converted back into a `DebugInfo` using [`DebugInfo::from_raw`], as long as it is not modified.
175 #[inline]
176 #[must_use]
177 pub const fn into_raw(self) -> lua_Debug {
178 self.0
179 }
180
181 /// Returns a pointer to the wrapped [`lua_Debug`].
182 ///
183 /// This can be used to pass this `DebugInfo` to raw [`ffi`] functions.
184 #[inline]
185 #[must_use]
186 pub const fn as_ptr(&self) -> *const lua_Debug {
187 &raw const self.0
188 }
189
190 /// Returns a mutable pointer to the wrapped [`lua_Debug`].
191 ///
192 /// This can be used to pass this `DebugInfo` to raw [`ffi`] functions.
193 #[inline]
194 #[must_use]
195 pub const fn as_mut_ptr(&mut self) -> *mut lua_Debug {
196 &raw mut self.0
197 }
198
199 /// Internal hack to keep `DebugInfo` safe to use:
200 /// when received from an [`Hook`], most of the fields are left uninitialized.
201 ///
202 /// Any method that may read a potentially uninitialized field will first check if `event` contains this bit flag:
203 /// if not, the field will not be read and `None` will be returned.
204 ///
205 /// If [`LuaState::get_info`] is called using a `DebugInfo` that is not masked as fully initialized,
206 /// the potentially uninitialized fields will be set to their default value and the `DebugInfo` will be marked as initialized.
207 ///
208 /// The advantage of this solution is that `DebugInfo`s created from within Rust continue to function almost completely normally,
209 /// while `DebugInfo`s received from an [`Hook`] can be used safely and are fully initialized only when actually needed.
210 ///
211 /// The disadvantage is that the `event` field is used for more than it was meant to and requires this bit flag to be removed whenever read,
212 /// which is an acceptable trade-off in my opinion.
213 const IS_FULLY_INIT: i32 = 1 << 31;
214
215 #[must_use]
216 const fn is_fully_init(&self) -> bool {
217 self.0.event & Self::IS_FULLY_INIT != 0
218 }
219
220 /// Returns the literal source of the specified function if said function was loaded via a string.
221 /// Otherwise, it returns the chunk name, which is usually `'@'` followed by the file path or `"=[C]"` (but could be anything).
222 ///
223 /// This field will only be set if the `'S'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
224 #[inline]
225 #[must_use]
226 pub const fn source(&self) -> Option<&CStr> {
227 let source = get_maybe_uninit_field!(self.0.source);
228 // SAFETY: self.0.source should always be a valid nul-terminated string pointer when not null.
229 map_ptr!(source, unsafe { CStr::from_ptr(source) })
230 }
231
232 /// Returns a "printable" version of [`DebugInfo::source`], intended to be used in error messages (which Lua does).
233 ///
234 /// The returned string is never longer than 60 characters.
235 ///
236 /// This field will only be set if the `'S'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
237 #[inline]
238 #[must_use]
239 pub const fn short_source(&self) -> Option<&CStr> {
240 let short_source = get_maybe_uninit_field!(&raw self.0.short_src);
241 // SAFETY: self.0.short_src is initialized and casting from [c_char] to [u8] is safe since they're both just 1 byte.
242 match CStr::from_bytes_until_nul(unsafe { &*short_source.cast::<[u8; ffi::LUA_IDSIZE]>() }) {
243 Ok(short_src) => Some(short_src),
244 Err(_) => None,
245 }
246 }
247
248 /// Returns the line number where the definition of the specified Lua function starts.
249 /// [`CFunction`]s return `None` instead.
250 ///
251 /// This field will only be set if the `'S'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
252 #[inline]
253 #[must_use]
254 pub const fn line_defined(&self) -> Option<i32> {
255 match get_maybe_uninit_field!(self.0.linedefined) {
256 -1 => None,
257 linedefined => Some(linedefined),
258 }
259 }
260
261 /// Returns the line number where the definition of the specified Lua function ends.
262 /// [`CFunction`]s return `None` instead.
263 ///
264 /// This field will only be set if the `'S'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
265 #[inline]
266 #[must_use]
267 pub const fn last_line_defined(&self) -> Option<i32> {
268 match get_maybe_uninit_field!(self.0.lastlinedefined) {
269 -1 => None,
270 lastlinedefined => Some(lastlinedefined),
271 }
272 }
273
274 /// Returns what the specified function is:
275 /// - `"Lua"` for Lua functions.
276 /// - `"C"` for [`CFunction`]s.
277 /// - `"main"` if it's the main part of a chunk.
278 ///
279 /// This field will only be set if the `'S'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
280 #[inline]
281 #[must_use]
282 pub const fn what(&self) -> Option<&CStr> {
283 let what = get_maybe_uninit_field!(self.0.what);
284 // SAFETY: self.0.what should always be a valid nul-terminated string pointer when not null.
285 map_ptr!(what, unsafe { CStr::from_ptr(what) })
286 }
287
288 /// Returns, if known, the current line where the specified function is executing.
289 /// `None` is returned if the current line is not known.
290 ///
291 /// This field will only be set if the `'l'` selector is used (see [`LuaState::get_info`]) or within [`Hook`]s called by [`HookEvent::Line`]
292 /// (see [`Hook`]), and will always be `None` otherwise.
293 #[inline]
294 #[must_use]
295 pub const fn current_line(&self) -> Option<i32> {
296 match self.0.currentline {
297 -1 => None,
298 currentline => Some(currentline),
299 }
300 }
301
302 /// Returns a reasonable name for the specified function based on how it was called, or `None` if no suitable name could be found.
303 ///
304 /// This field will only be set if the `'n'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
305 #[inline]
306 #[must_use]
307 pub const fn name(&self) -> Option<&CStr> {
308 let name = get_maybe_uninit_field!(self.0.name);
309 // SAFETY: self.0.name should always be a valid nul-terminated string pointer when not null.
310 map_ptr!(name, unsafe { CStr::from_ptr(name) })
311 }
312
313 /// Returns an explenation of how [`DebugInfo::name`] is found.
314 ///
315 /// Possible returned values are:
316 /// - `"global"`.
317 /// - `"local"`.
318 /// - `"method"`.
319 /// - `"field"`.
320 /// - `"upvalue"`.
321 /// - `"metamethod"`.
322 /// - `""`. *(Returned when no other option applies or no suitable name was found.)*
323 ///
324 /// This field will only be set if the `'n'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
325 #[inline]
326 #[must_use]
327 pub const fn name_what(&self) -> Option<&CStr> {
328 let namewhat = get_maybe_uninit_field!(self.0.namewhat);
329 // SAFETY: self.0.namewhat should always be a valid nul-terminated string pointer when not null.
330 map_ptr!(namewhat, unsafe { CStr::from_ptr(namewhat) })
331 }
332
333 /// Returns the number of upvalues of the specified function.
334 ///
335 /// This field will only be set if the `'u'` selector is used (see [`LuaState::get_info`]), and will always be `None` otherwise.
336 #[inline]
337 #[must_use]
338 pub const fn n_upvalues(&self) -> Option<i32> {
339 match get_maybe_uninit_field!(self.0.nups) {
340 -1 => None,
341 nups => Some(nups),
342 }
343 }
344
345 /// Returns the [`HookEvent`] that called the current [`Hook`].
346 ///
347 /// This field will only be set if this `DebugInfo` comes from the [`Hook`]'s arguments (see [`Hook`]), and will always be `None` otherwise.
348 #[inline]
349 #[must_use]
350 pub const fn event(&self) -> Option<HookEvent> {
351 match self.0.event {
352 -1 => None, // SAFETY: self.0.event (without the IS_FULLY_INIT flag) should always be a valid HookEvent.
353 event => Some(unsafe { mem::transmute::<i32, HookEvent>(event & !Self::IS_FULLY_INIT) })
354 }
355 }
356}
357
358impl Default for DebugInfo {
359 #[inline]
360 fn default() -> Self {
361 Self::new()
362 }
363}
364
365/// Debug interface functions.
366///
367/// See [ยง3.8](https://www.lua.org/manual/5.1/manual.html#3.8) for more information on the Debug interface.
368///
369/// *[See also the `DebugInfo` struct](struct.DebugInfo.html)*.
370impl LuaState {
371 /// Requests information about a specified function. The retrieved information will be stored in `info`.
372 ///
373 /// There are three ways to specify a function:
374 /// - From the interpreter runtime stack by using [`LuaState::get_stack`].
375 /// - From the top element by adding `'>'` at the start of `what` (the element will be popped).
376 /// - Pre-specified when [`DebugInfo`] is received from an [`Hook`]'s arguments (see [`Hook`]).
377 ///
378 /// The type of information requested is based on which "selectors" (characters) `what` contains:
379 /// - `'n'` will set [`DebugInfo::name`] and [`DebugInfo::name_what`].
380 /// - `'S'` will set [`DebugInfo::source`], [`DebugInfo::short_source`], [`DebugInfo::line_defined`],
381 /// [`DebugInfo::last_line_defined`], and [`DebugInfo::what`].
382 /// - `'l'` will set [`DebugInfo::current_line`].
383 /// - `'u'` will set [`DebugInfo::n_upvalues`].
384 /// - `'f'` pushes onto the stack the specified function itself.
385 /// - `'L'` pushes onto the stack a table whose indices are the number of valid lines (with associated code) of the specified function.
386 ///
387 /// *(The selectors are executed based on their order in `what`.)*
388 ///
389 /// If an invalid character is present in `what`, or `'>'` is used and the top elemenet is not a function,
390 /// this function will end early and return `false`. `true` is returned otherwise.
391 ///
392 /// # Panics
393 ///
394 /// Panics if none of the three ways of specifying a function are attempted.
395 #[inline]
396 pub fn get_info(&mut self, what: &CStr, info: &mut DebugInfo) -> bool {
397 // SAFETY: c_char can be casted as u8 (they're both 1 byte) and CStrs should always have at least 1 character (the nul terminator).
398 assert!(info.0.i_ci != 0 || unsafe { *what.as_ptr().cast::<u8>() == b'>' }, "tried to get debug information without specifying a function");
399
400 if !info.is_fully_init() {
401 // Initialize all MaybeUninit fields and mark the DebugInfo as fully initialized.
402 info.0.name.write(ptr::null());
403 info.0.namewhat.write(ptr::null());
404 info.0.what.write(ptr::null());
405 info.0.source.write(ptr::null());
406 info.0.nups.write(-1);
407 info.0.linedefined.write(-1);
408 info.0.lastlinedefined.write(-1);
409 info.0.short_src.write([1; LUA_IDSIZE]);
410 info.0.event |= DebugInfo::IS_FULLY_INIT;
411 }
412
413 // SAFETY: self.0, what, and info should always be valid and info either has a valid i_ci value or '>' is being used.
414 unsafe { ffi::lua_getinfo(self.0, what.as_ptr(), info.as_mut_ptr()) != 0 }
415 }
416
417 /// Prepare the given `info` to specify the function at the given `level`:
418 /// level `0` is the current running function, level `1` is the function that called the current running function, and so on.
419 ///
420 /// If the given `level` is invalid, `info` is not prepared and the function returns `false`. `true` is returned otherwise.
421 ///
422 /// This function is meant to be used alongside [`LuaState::get_info`] to get information about the specified function.
423 #[inline]
424 pub fn get_stack(&self, level: i32, info: &mut DebugInfo) -> bool {
425 // SAFETY: self.0 and info are always valid.
426 let success = unsafe { ffi::lua_getstack(self.0, level, info.as_mut_ptr()) != 0 };
427
428 if !success {
429 // Reset i_ci to keep it marked as invalid.
430 info.0.i_ci = 0;
431 }
432
433 success
434 }
435
436 /// Get information about a local variable of a specified function.
437 ///
438 /// There are three ways to specify a function:
439 /// - From the interpreter runtime stack by using [`LuaState::get_stack`].
440 /// - From the top element by passing `None` for `info` (the element will *not* be popped).
441 /// - Pre-specified when [`DebugInfo`] is received from an [`Hook`]'s arguments (see [`Hook`]).
442 ///
443 /// `n` selects which local to get, `1` being the first local and so on until the last local.
444 /// Negative values of `n` can be used to get vararg arguments.
445 ///
446 /// When `info` is `Some`, this function will push to the stack the local's value and return the local's name.
447 /// Otherwise only the name is returned and nothing is pushed to the stack.
448 ///
449 /// Invalid values of `n` or the top element not being a function (when `info` is `None`)
450 /// will result in the function returning `None` and pushing nothing to the stack.
451 ///
452 /// If the returned name is enclosed in round brackets, the queried local is an internal variable.
453 ///
454 /// # Panics
455 ///
456 /// Panics if none of the three ways of specifying a function are attempted.
457 #[inline]
458 pub fn get_local(&mut self, info: Option<&DebugInfo>, n: i32) -> Option<&CStr> {
459 if let Some(info) = info {
460 assert!(info.0.i_ci != 0, "tried to get a local without specifying a function");
461 }
462
463 // SAFETY: self.0 and info's pointer are always valid, lua_getlocal accepts a null lua_Debug,
464 // and lua_getlocal returns valid nul-terminated string pointers when not null.
465 let local = unsafe { ffi::lua_getlocal(self.0, info.map_or(ptr::null(), DebugInfo::as_ptr), n) };
466 map_ptr!(local, unsafe { CStr::from_ptr(local) })
467 }
468
469 /// Sets the value of a local variable of a specified function to the value of the top element (which is popped),
470 /// returning the local's name.
471 ///
472 /// There are *two* ways to specify a function:
473 /// - From the interpreter runtime stack by using [`LuaState::get_stack`].
474 /// - Pre-specified when [`DebugInfo`] is received from an [`Hook`]'s arguments (see [`Hook`]).
475 ///
476 /// `n` selects which local to get, `1` being the first local and so on until the last local.
477 /// Negative values of `n` can be used to get vararg arguments.
478 ///
479 /// Invalid values of `n` will result in the function returning `None` and not changing any local, but the top element will still be popped!
480 ///
481 /// If the returned name is enclosed in round brackets, the changed local is an internal variable.
482 ///
483 /// # Panics
484 ///
485 /// Panics if none of the two ways of specifying a function are attempted or if the stack is empty.
486 pub fn set_local(&mut self, info: &DebugInfo, n: i32) -> Option<&CStr> {
487 assert!(self.get_top() > 0, "tried to set a local's value despite having an empty stack");
488 assert!(info.0.i_ci != 0, "tried to set a local's value without specifying a function");
489
490 // SAFETY: self.0 and info's pointer are always valid, and lua_setlocal returns valid nul-terminated string pointers when not null.
491 let local = unsafe { ffi::lua_setlocal(self.0, info.as_ptr(), n) };
492 map_ptr!(local, unsafe { CStr::from_ptr(local) })
493 }
494
495 /// Get information about the `n`th upvalue of the function at index `func_index`.
496 ///
497 /// The upvalue's value is pushed onto the stack and its name is returned.
498 ///
499 /// If the `n`th upvalue doesn't exist or the element at index `func_index` is not a function,
500 /// `None` is returned and nothing is pushed onto the stack.
501 ///
502 /// If the function is a [`CFunction`], the returned upvalue name will be an empty string.
503 #[inline]
504 pub fn get_upvalue(&mut self, func_index: i32, n: i32) -> Option<&CStr> {
505 // SAFETY: self.0 is always valid and lua_getupvalue returns valid nul-terminated string pointers when not null.
506 let upvalue = unsafe { ffi::lua_getupvalue(self.0, func_index, n) };
507 map_ptr!(upvalue, unsafe { CStr::from_ptr(upvalue) })
508 }
509
510 /// Sets the value of the `n`th upvalue of the function at index `func_index` to the value of the top element (which is popped),
511 /// returning the upvalue's name.
512 ///
513 /// If the `n`th upvalue doesn't exist or the element at index `func_index` is not a function,
514 /// `None` is returned and the upvalue is not changed (the top element will not be popped).
515 ///
516 /// # Panics
517 ///
518 /// Panics if the stack is empty.
519 #[inline]
520 pub fn set_upvalue(&mut self, func_index: i32, n: i32) -> Option<&CStr> {
521 assert!(self.get_top() > 0, "tried to set an upvalue's value despite having an empty stack");
522
523 // SAFETY: self.0 is always valid and lua_setupvalue returns valid nul-terminated string pointers when not null.
524 let upvalue = unsafe { ffi::lua_setupvalue(self.0, func_index, n) };
525 map_ptr!(upvalue, unsafe { CStr::from_ptr(upvalue) })
526 }
527
528 /// Returns `true` if the `n`th upvalue of the function at index `func_index` exists, `false` otherwise.
529 #[inline]
530 pub fn is_function_upvalue(&mut self, func_index: i32, n: i32) -> bool {
531 let exists = self.get_upvalue(func_index, n).is_some();
532
533 if exists {
534 // Remove the upvalue's value from the stack.
535 self.pop(1);
536 }
537
538 exists
539 }
540
541 /// Returns an unique generic pointer for the `n`th upvalue of the function at index `func_index`.
542 ///
543 /// Different upvalues will always return different pointers,
544 /// thus the pointers can be compared to see if different functions share the same upvalue.
545 ///
546 /// If `func_index` or `n` are invalid a null pointer will be returned instead.
547 ///
548 /// There is no intended way to convert the pointer to the upvalue itself.
549 #[inline]
550 pub fn upvalue_id(&mut self, func_index: i32, n: i32) -> *mut () {
551 if self.is_function_upvalue(func_index, n) {
552 // SAFETY: self.0 is always valid and func_index and n are also valid.
553 unsafe { ffi::lua_upvalueid(self.0, func_index, n).cast() }
554 } else {
555 ptr::null_mut()
556 }
557 }
558
559 /// Returns the current [`Hook`], or `None` if no hook is currently enabled.
560 ///
561 /// [`lua_Hook`] is returned instead of [`Hook`] as this function cannot determine its safety.
562 #[inline]
563 pub fn get_hook(&self) -> Option<lua_Hook> {
564 // SAFETY: self.0 is always valid.
565 unsafe { ffi::lua_gethook(self.0) }
566 }
567
568 /// Sets a new debugging [`Hook`] function, replacing the previous hook (see [`Hook`]).
569 ///
570 /// `mask` specifies which [`HookEvent`]s can call `hook`,
571 /// the "mask value" of an [`HookEvent`] can be obtained from [`HookEvent::as_mask`] or from the `HookEvent::MASK_*` constants.
572 /// Different mask values can be bit or'd together so that the hook can be called from different events.
573 ///
574 /// If `mask` is `0` or invalid, this function behaves the same as [`LuaState::unset_hook`].
575 ///
576 /// If [`HookEvent::Count`] is one of the possible events for this hook, `count` specifies the amounts of instructions inbetween each call
577 /// (it's ignored otherwise).
578 ///
579 /// # Examples
580 ///
581 /// ```
582 /// # use low_luajit::{LuaState, DebugInfo, HookEvent};
583 /// extern "C-unwind" fn example_hook(lua: LuaState, info: &mut DebugInfo) {
584 /// println!("Hook called by {:?}!", info.event());
585 /// }
586 ///
587 /// # fn example(lua: LuaState) {
588 /// lua.set_hook(example_hook, HookEvent::MASK_CALL | HookEvent::MASK_RETURN, 0);
589 /// # }
590 /// ```
591 #[inline]
592 pub fn set_hook(&self, hook: Hook, mask: i32, count: i32) {
593 // SAFETY: self.0 is always valid and hook will be called properly.
594 unsafe { ffi::lua_sethook(self.0, Some(hook.to_raw()), mask, count); }
595 }
596
597 /// Disables the current [`Hook`], without replacing it with another.
598 ///
599 /// To replace it with a new one instead, see [`LuaState::set_hook`].
600 #[inline]
601 pub fn unset_hook(&self) {
602 // SAFETY: self.0 is always valid.
603 unsafe { ffi::lua_sethook(self.0, None, 0, 0); }
604 }
605
606 /// Returns the current [`Hook`]'s mask value.
607 ///
608 /// See [`LuaState::set_hook`] for more information.
609 #[inline]
610 pub fn get_hook_mask(&self) -> i32 {
611 // SAFETY: self.0 is always valid.
612 unsafe { ffi::lua_gethookmask(self.0) }
613 }
614
615 /// Returns the current [`Hook`]'s "count" (not the *current* count, simply the value that was specified).
616 ///
617 /// See [`LuaState::set_hook`] for more information.
618 #[inline]
619 pub fn get_hook_count(&self) -> i32 {
620 // SAFETY: self.0 is always valid.
621 unsafe { ffi::lua_gethookcount(self.0) }
622 }
623
624 // TODO: set_hook_mask or set_hook_count for convenience?
625}