rdcl_aoc_helpers/machine/
mod.rs1use std::convert::TryFrom;
3
4use crate::machine::hook::{HookResult, PreExecuteHook};
5use crate::machine::instruction::MachineInstruction;
6use crate::machine::output_receiver::{NoopOutputReceiver, OutputReceiver};
7use crate::machine::register::{HashMapRegister, MachineRegister};
8
9pub mod hook;
11
12pub mod instruction;
14
15pub mod output_receiver;
17
18pub mod register;
20
21pub struct Machine<I: MachineInstruction, R: MachineRegister, O: OutputReceiver<R>> {
23 instructions: Vec<I>,
24 pub register: R,
25 pub output_receiver: O,
26 counter: i64,
27}
28
29impl<I: MachineInstruction> Machine<I, HashMapRegister, NoopOutputReceiver> {
30 pub fn new_simple_machine(
32 instructions: &[I],
33 ) -> Machine<I, HashMapRegister, NoopOutputReceiver> {
34 Machine {
35 instructions: instructions.to_vec(),
36 register: HashMapRegister::default(),
37 output_receiver: NoopOutputReceiver,
38 counter: 0,
39 }
40 }
41}
42
43impl<I, R, O> Machine<I, R, O>
44where
45 I: MachineInstruction,
46 R: MachineRegister,
47 O: OutputReceiver<R>,
48{
49 pub fn new_machine(instructions: &[I], register: R, output_receiver: O) -> Machine<I, R, O> {
51 Machine {
52 instructions: instructions.to_vec(),
53 register,
54 output_receiver,
55 counter: 0,
56 }
57 }
58
59 pub fn run<H: PreExecuteHook<I>>(&mut self, pre_execute_hook: &mut H) {
61 while let Some((idx, instruction)) = self.get_next_instruction() {
62 match pre_execute_hook.run(self, &instruction, idx) {
63 HookResult::Proceed => {
64 self.counter +=
65 instruction.execute(&mut self.register, &mut self.output_receiver);
66 }
67 HookResult::Skip => {
68 self.counter += 1;
69 }
70 HookResult::Goto(idx) => {
71 self.counter = idx;
72 }
73 HookResult::Abort => {
74 return;
75 }
76 }
77 }
78 }
79
80 pub fn get_counter(&self) -> i64 {
82 self.counter
83 }
84
85 pub fn get_instruction(&self, idx: i64) -> Option<(usize, I)> {
87 usize::try_from(idx).ok().and_then(|idx| {
88 self.instructions
89 .get(idx)
90 .map(|instruction| (idx, instruction.clone()))
91 })
92 }
93
94 pub fn set_instruction(&mut self, idx: i64, new_instruction: &I) {
96 usize::try_from(idx).ok().and_then(|idx| {
97 self.instructions
98 .get_mut(idx)
99 .map(|instruction| *instruction = new_instruction.clone())
100 });
101 }
102
103 fn get_next_instruction(&self) -> Option<(usize, I)> {
105 self.get_instruction(self.counter)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::error::ParseError;
112 use crate::machine::hook::NoopHook;
113 use crate::machine::instruction::ParsedMachineInstruction;
114
115 use super::*;
116
117 #[test]
118 fn test_machine() {
119 let instructions = vec![MockInstruction; 3];
120 let mut machine = Machine::new_simple_machine(&instructions);
121
122 machine.run(&mut NoopHook::default());
123
124 assert_eq!(machine.register.read('a'), 30);
125 }
126
127 #[derive(Clone)]
128 struct MockInstruction;
129
130 impl MachineInstruction for MockInstruction {
131 fn execute<R: MachineRegister, O: OutputReceiver<R>>(
132 &self,
133 register: &mut R,
134 _output_receiver: &mut O,
135 ) -> i64 {
136 register.increment('a', 10);
137 1
138 }
139
140 fn from_parsed_machine_instruction(
141 _parsed: &ParsedMachineInstruction,
142 ) -> Result<Self, ParseError> {
143 unimplemented!()
144 }
145 }
146}