pub struct DebugController { /* private fields */ }Expand description
Controls a DebugSession from a
frontend (MCP server, DAP adapter, Web console, …).
Thread-safe: Clone + Send + Sync.
Implementations§
Source§impl DebugController
impl DebugController
Sourcepub fn state(&self) -> SessionState
pub fn state(&self) -> SessionState
Current session state (non-blocking, coarse-grained).
Returns whether the VM is Idle, Running, Paused, or Terminated.
PauseReason is not preserved in the atomic representation —
use wait_event to obtain the precise reason
from DebugEvent::Paused.
Sourcepub fn wait_event(&self) -> Result<DebugEvent, DebugError>
pub fn wait_event(&self) -> Result<DebugEvent, DebugError>
Block until the next event arrives from the engine.
This is the authoritative source for session events. In
particular, DebugEvent::Paused carries the precise
PauseReason that state() does not preserve.
Examples found in repository?
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11 let lua = Lua::new();
12
13 // Create debug session + controller.
14 let (session, controller) = DebugSession::new();
15 session.attach(&lua)?;
16
17 // Set a breakpoint on line 4.
18 let bp_id = controller.set_breakpoint("@example.lua", 4, None)?;
19 println!("Breakpoint {bp_id} set at @example.lua:4");
20
21 // Run Lua code on a separate thread.
22 // mlua 0.11's LuaError is not Send, so convert to a string error
23 // for cross-thread transport.
24 let handle = std::thread::spawn(move || -> Result<i64, String> {
25 lua.load(
26 r#"
27local a = 10
28local b = 20
29local c = 30
30local result = a + b + c
31return result
32"#,
33 )
34 .set_name("@example.lua")
35 .eval::<i64>()
36 .map_err(|e| e.to_string())
37 });
38
39 // Wait for the breakpoint hit.
40 match controller.wait_event()? {
41 DebugEvent::Paused { reason, stack } => {
42 println!("VM paused: {reason:?}");
43 for frame in &stack {
44 let line_str = frame
45 .line
46 .map_or_else(|| "?".to_string(), |l| l.to_string());
47 println!(
48 " frame {}: {} ({}:{})",
49 frame.id, frame.name, frame.source, line_str
50 );
51 }
52
53 // Inspect locals.
54 match controller.get_locals(0) {
55 Ok(locals) => {
56 println!("Locals:");
57 for var in &locals {
58 println!(" {} = {} ({})", var.name, var.value, var.type_name);
59 }
60 }
61 Err(e) => println!("Failed to get locals: {e}"),
62 }
63
64 // Evaluate an expression.
65 match controller.evaluate("a + b", None) {
66 Ok(result) => println!("Eval 'a + b' = {result}"),
67 Err(e) => println!("Eval failed: {e}"),
68 }
69 }
70 other => println!("Unexpected event: {other:?}"),
71 }
72
73 // Resume.
74 controller.continue_execution()?;
75
76 // Wait for completion.
77 let result = handle.join().unwrap()?;
78 println!("Lua returned: {result}");
79
80 Ok(())
81}Sourcepub fn try_event(&self) -> Result<Option<DebugEvent>, DebugError>
pub fn try_event(&self) -> Result<Option<DebugEvent>, DebugError>
Try to receive an event without blocking.
Sourcepub fn wait_event_timeout(
&self,
timeout: Duration,
) -> Result<Option<DebugEvent>, DebugError>
pub fn wait_event_timeout( &self, timeout: Duration, ) -> Result<Option<DebugEvent>, DebugError>
Block until the next event arrives, with a timeout.
Returns Ok(None) if the timeout elapses without an event.
Sourcepub fn set_breakpoint(
&self,
source: &str,
line: usize,
condition: Option<&str>,
) -> Result<BreakpointId, DebugError>
pub fn set_breakpoint( &self, source: &str, line: usize, condition: Option<&str>, ) -> Result<BreakpointId, DebugError>
Set a breakpoint. Returns the assigned ID.
Works in any session state (Idle, Running, Paused,
Terminated) — the breakpoint registry is shared via
Arc<Mutex<…>> and accessed directly, not through the command
channel.
Examples found in repository?
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11 let lua = Lua::new();
12
13 // Create debug session + controller.
14 let (session, controller) = DebugSession::new();
15 session.attach(&lua)?;
16
17 // Set a breakpoint on line 4.
18 let bp_id = controller.set_breakpoint("@example.lua", 4, None)?;
19 println!("Breakpoint {bp_id} set at @example.lua:4");
20
21 // Run Lua code on a separate thread.
22 // mlua 0.11's LuaError is not Send, so convert to a string error
23 // for cross-thread transport.
24 let handle = std::thread::spawn(move || -> Result<i64, String> {
25 lua.load(
26 r#"
27local a = 10
28local b = 20
29local c = 30
30local result = a + b + c
31return result
32"#,
33 )
34 .set_name("@example.lua")
35 .eval::<i64>()
36 .map_err(|e| e.to_string())
37 });
38
39 // Wait for the breakpoint hit.
40 match controller.wait_event()? {
41 DebugEvent::Paused { reason, stack } => {
42 println!("VM paused: {reason:?}");
43 for frame in &stack {
44 let line_str = frame
45 .line
46 .map_or_else(|| "?".to_string(), |l| l.to_string());
47 println!(
48 " frame {}: {} ({}:{})",
49 frame.id, frame.name, frame.source, line_str
50 );
51 }
52
53 // Inspect locals.
54 match controller.get_locals(0) {
55 Ok(locals) => {
56 println!("Locals:");
57 for var in &locals {
58 println!(" {} = {} ({})", var.name, var.value, var.type_name);
59 }
60 }
61 Err(e) => println!("Failed to get locals: {e}"),
62 }
63
64 // Evaluate an expression.
65 match controller.evaluate("a + b", None) {
66 Ok(result) => println!("Eval 'a + b' = {result}"),
67 Err(e) => println!("Eval failed: {e}"),
68 }
69 }
70 other => println!("Unexpected event: {other:?}"),
71 }
72
73 // Resume.
74 controller.continue_execution()?;
75
76 // Wait for completion.
77 let result = handle.join().unwrap()?;
78 println!("Lua returned: {result}");
79
80 Ok(())
81}Sourcepub fn remove_breakpoint(&self, id: BreakpointId) -> Result<bool, DebugError>
pub fn remove_breakpoint(&self, id: BreakpointId) -> Result<bool, DebugError>
Remove a breakpoint by ID.
Sourcepub fn list_breakpoints(&self) -> Result<Vec<Breakpoint>, DebugError>
pub fn list_breakpoints(&self) -> Result<Vec<Breakpoint>, DebugError>
List all breakpoints.
Sourcepub fn continue_execution(&self) -> Result<(), DebugError>
pub fn continue_execution(&self) -> Result<(), DebugError>
Resume execution.
Examples found in repository?
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11 let lua = Lua::new();
12
13 // Create debug session + controller.
14 let (session, controller) = DebugSession::new();
15 session.attach(&lua)?;
16
17 // Set a breakpoint on line 4.
18 let bp_id = controller.set_breakpoint("@example.lua", 4, None)?;
19 println!("Breakpoint {bp_id} set at @example.lua:4");
20
21 // Run Lua code on a separate thread.
22 // mlua 0.11's LuaError is not Send, so convert to a string error
23 // for cross-thread transport.
24 let handle = std::thread::spawn(move || -> Result<i64, String> {
25 lua.load(
26 r#"
27local a = 10
28local b = 20
29local c = 30
30local result = a + b + c
31return result
32"#,
33 )
34 .set_name("@example.lua")
35 .eval::<i64>()
36 .map_err(|e| e.to_string())
37 });
38
39 // Wait for the breakpoint hit.
40 match controller.wait_event()? {
41 DebugEvent::Paused { reason, stack } => {
42 println!("VM paused: {reason:?}");
43 for frame in &stack {
44 let line_str = frame
45 .line
46 .map_or_else(|| "?".to_string(), |l| l.to_string());
47 println!(
48 " frame {}: {} ({}:{})",
49 frame.id, frame.name, frame.source, line_str
50 );
51 }
52
53 // Inspect locals.
54 match controller.get_locals(0) {
55 Ok(locals) => {
56 println!("Locals:");
57 for var in &locals {
58 println!(" {} = {} ({})", var.name, var.value, var.type_name);
59 }
60 }
61 Err(e) => println!("Failed to get locals: {e}"),
62 }
63
64 // Evaluate an expression.
65 match controller.evaluate("a + b", None) {
66 Ok(result) => println!("Eval 'a + b' = {result}"),
67 Err(e) => println!("Eval failed: {e}"),
68 }
69 }
70 other => println!("Unexpected event: {other:?}"),
71 }
72
73 // Resume.
74 controller.continue_execution()?;
75
76 // Wait for completion.
77 let result = handle.join().unwrap()?;
78 println!("Lua returned: {result}");
79
80 Ok(())
81}Sourcepub fn step_into(&self) -> Result<(), DebugError>
pub fn step_into(&self) -> Result<(), DebugError>
Step into the next line (descend into calls).
Sourcepub fn step_over(&self) -> Result<(), DebugError>
pub fn step_over(&self) -> Result<(), DebugError>
Step to the next line at the same or shallower call depth.
Sourcepub fn step_out(&self) -> Result<(), DebugError>
pub fn step_out(&self) -> Result<(), DebugError>
Step out of the current function.
Sourcepub fn pause(&self) -> Result<(), DebugError>
pub fn pause(&self) -> Result<(), DebugError>
Request the VM to pause at the next opportunity.
Sets an atomic flag that is checked on every Lua line event. Effective in any state — if the VM is Running, it will pause at the next executed line.
Sourcepub fn get_stack_trace(&self) -> Result<Vec<StackFrame>, DebugError>
pub fn get_stack_trace(&self) -> Result<Vec<StackFrame>, DebugError>
Get the current call stack.
Sourcepub fn get_locals(&self, frame_id: usize) -> Result<Vec<Variable>, DebugError>
pub fn get_locals(&self, frame_id: usize) -> Result<Vec<Variable>, DebugError>
Get local variables at a stack frame.
Examples found in repository?
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11 let lua = Lua::new();
12
13 // Create debug session + controller.
14 let (session, controller) = DebugSession::new();
15 session.attach(&lua)?;
16
17 // Set a breakpoint on line 4.
18 let bp_id = controller.set_breakpoint("@example.lua", 4, None)?;
19 println!("Breakpoint {bp_id} set at @example.lua:4");
20
21 // Run Lua code on a separate thread.
22 // mlua 0.11's LuaError is not Send, so convert to a string error
23 // for cross-thread transport.
24 let handle = std::thread::spawn(move || -> Result<i64, String> {
25 lua.load(
26 r#"
27local a = 10
28local b = 20
29local c = 30
30local result = a + b + c
31return result
32"#,
33 )
34 .set_name("@example.lua")
35 .eval::<i64>()
36 .map_err(|e| e.to_string())
37 });
38
39 // Wait for the breakpoint hit.
40 match controller.wait_event()? {
41 DebugEvent::Paused { reason, stack } => {
42 println!("VM paused: {reason:?}");
43 for frame in &stack {
44 let line_str = frame
45 .line
46 .map_or_else(|| "?".to_string(), |l| l.to_string());
47 println!(
48 " frame {}: {} ({}:{})",
49 frame.id, frame.name, frame.source, line_str
50 );
51 }
52
53 // Inspect locals.
54 match controller.get_locals(0) {
55 Ok(locals) => {
56 println!("Locals:");
57 for var in &locals {
58 println!(" {} = {} ({})", var.name, var.value, var.type_name);
59 }
60 }
61 Err(e) => println!("Failed to get locals: {e}"),
62 }
63
64 // Evaluate an expression.
65 match controller.evaluate("a + b", None) {
66 Ok(result) => println!("Eval 'a + b' = {result}"),
67 Err(e) => println!("Eval failed: {e}"),
68 }
69 }
70 other => println!("Unexpected event: {other:?}"),
71 }
72
73 // Resume.
74 controller.continue_execution()?;
75
76 // Wait for completion.
77 let result = handle.join().unwrap()?;
78 println!("Lua returned: {result}");
79
80 Ok(())
81}Sourcepub fn get_upvalues(&self, frame_id: usize) -> Result<Vec<Variable>, DebugError>
pub fn get_upvalues(&self, frame_id: usize) -> Result<Vec<Variable>, DebugError>
Get upvalues at a stack frame.
Sourcepub fn evaluate(
&self,
expression: &str,
frame_id: Option<usize>,
) -> Result<String, DebugError>
pub fn evaluate( &self, expression: &str, frame_id: Option<usize>, ) -> Result<String, DebugError>
Evaluate a Lua expression while paused.
When frame_id is Some, the expression is evaluated in the
scope of that stack frame — locals, upvalues, and globals are
all accessible. When None, evaluation runs in the global
scope only.
Examples found in repository?
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11 let lua = Lua::new();
12
13 // Create debug session + controller.
14 let (session, controller) = DebugSession::new();
15 session.attach(&lua)?;
16
17 // Set a breakpoint on line 4.
18 let bp_id = controller.set_breakpoint("@example.lua", 4, None)?;
19 println!("Breakpoint {bp_id} set at @example.lua:4");
20
21 // Run Lua code on a separate thread.
22 // mlua 0.11's LuaError is not Send, so convert to a string error
23 // for cross-thread transport.
24 let handle = std::thread::spawn(move || -> Result<i64, String> {
25 lua.load(
26 r#"
27local a = 10
28local b = 20
29local c = 30
30local result = a + b + c
31return result
32"#,
33 )
34 .set_name("@example.lua")
35 .eval::<i64>()
36 .map_err(|e| e.to_string())
37 });
38
39 // Wait for the breakpoint hit.
40 match controller.wait_event()? {
41 DebugEvent::Paused { reason, stack } => {
42 println!("VM paused: {reason:?}");
43 for frame in &stack {
44 let line_str = frame
45 .line
46 .map_or_else(|| "?".to_string(), |l| l.to_string());
47 println!(
48 " frame {}: {} ({}:{})",
49 frame.id, frame.name, frame.source, line_str
50 );
51 }
52
53 // Inspect locals.
54 match controller.get_locals(0) {
55 Ok(locals) => {
56 println!("Locals:");
57 for var in &locals {
58 println!(" {} = {} ({})", var.name, var.value, var.type_name);
59 }
60 }
61 Err(e) => println!("Failed to get locals: {e}"),
62 }
63
64 // Evaluate an expression.
65 match controller.evaluate("a + b", None) {
66 Ok(result) => println!("Eval 'a + b' = {result}"),
67 Err(e) => println!("Eval failed: {e}"),
68 }
69 }
70 other => println!("Unexpected event: {other:?}"),
71 }
72
73 // Resume.
74 controller.continue_execution()?;
75
76 // Wait for completion.
77 let result = handle.join().unwrap()?;
78 println!("Lua returned: {result}");
79
80 Ok(())
81}Sourcepub fn disconnect(&self) -> Result<(), DebugError>
pub fn disconnect(&self) -> Result<(), DebugError>
Disconnect from the session.
Trait Implementations§
Source§impl Clone for DebugController
impl Clone for DebugController
Source§fn clone(&self) -> DebugController
fn clone(&self) -> DebugController
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for DebugController
impl RefUnwindSafe for DebugController
impl Send for DebugController
impl Sync for DebugController
impl Unpin for DebugController
impl UnsafeUnpin for DebugController
impl UnwindSafe for DebugController
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more