libbf/runtime/
step_runner.rs1use crate::prelude::ProgramIndex;
3
4use super::*;
5
6pub struct StepRunner<'a, R, W> {
12 program: &'a Program,
13 runtime: internal::Runtime<R, W>,
14 index: Option<ProgramIndex>,
15}
16
17impl<'a, R, W> StepRunner<'a, R, W>
18where
19 R: Read,
20 W: Write,
21{
22 pub fn new(program: &'a Program, input: R, output: W) -> Self {
24 Self::with_memsize(program, input, output, DEFAULT_MEMSIZE)
25 }
26
27 pub fn with_memsize(program: &'a Program, input: R, output: W, memsize: MemorySize) -> Self {
29 let runtime = internal::Runtime::new(input, output, memsize);
30 Self {
31 program,
32 runtime,
33 index: program.first_index(),
34 }
35 }
36
37 pub fn get_index(&self) -> Option<&ProgramIndex> {
41 self.index.as_ref()
42 }
43
44 pub fn get_current_instruction(&self) -> Option<&Instruction> {
46 self.index.as_ref().map(|index| &self.program[index])
47 }
48
49 pub fn get_pointer(&self) -> isize {
51 self.runtime.get_pointer()
52 }
53
54 pub fn get_data_at_mut(&mut self, address: isize) -> Option<&mut u8> {
56 self.runtime.get_data_at_mut(address)
57 }
58
59 pub fn is_running(&self) -> bool {
61 self.index.is_some()
62 }
63
64 pub fn step(&mut self) -> Result<(), RuntimeError> {
66 if let Some(index) = &mut self.index {
67 let inst = &self.program[index];
68 match self.runtime.exec_one(inst)? {
69 internal::NextAction::Next => {
70 if !self.program.step_index(index) && !index.step_out() {
71 self.index = None;
72 }
73 }
74 internal::NextAction::StepIn(sub) => {
75 if !sub.is_empty() {
76 index.step_in();
77 }
78 }
79 }
80 }
81 Ok(())
82 }
83}