1use g_code::{
2 command,
3 emit::Token,
4 parse::{ast::Snippet, snippet_parser},
5};
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11pub enum Tool {
12 Off,
13 On,
14}
15
16#[derive(Copy, Clone, PartialEq, Eq, Debug)]
18pub enum Distance {
19 Absolute,
20 Relative,
21}
22
23#[derive(Debug, Clone)]
26pub struct Machine<'input> {
27 supported_functionality: SupportedFunctionality,
28 tool_state: Option<Tool>,
29 distance_mode: Option<Distance>,
30 tool_on_sequence: Snippet<'input>,
31 tool_off_sequence: Snippet<'input>,
32 program_begin_sequence: Snippet<'input>,
33 program_end_sequence: Snippet<'input>,
34 empty_snippet: Snippet<'input>,
36}
37
38#[derive(Debug, Default, Clone, PartialEq)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub struct MachineConfig {
41 pub supported_functionality: SupportedFunctionality,
42 pub tool_on_sequence: Option<String>,
43 pub tool_off_sequence: Option<String>,
44 pub begin_sequence: Option<String>,
45 pub end_sequence: Option<String>,
46}
47
48#[derive(Debug, Default, Clone, PartialEq)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50pub struct SupportedFunctionality {
51 pub circular_interpolation: bool,
55}
56
57impl<'input> Machine<'input> {
58 pub fn new(
59 supported_functionality: SupportedFunctionality,
60 tool_on_sequence: Option<Snippet<'input>>,
61 tool_off_sequence: Option<Snippet<'input>>,
62 program_begin_sequence: Option<Snippet<'input>>,
63 program_end_sequence: Option<Snippet<'input>>,
64 ) -> Self {
65 let empty_snippet = snippet_parser("").expect("empty string is a valid snippet");
66 Self {
67 supported_functionality,
68 tool_on_sequence: tool_on_sequence.unwrap_or_else(|| empty_snippet.clone()),
69 tool_off_sequence: tool_off_sequence.unwrap_or_else(|| empty_snippet.clone()),
70 program_begin_sequence: program_begin_sequence.unwrap_or_else(|| empty_snippet.clone()),
71 program_end_sequence: program_end_sequence.unwrap_or_else(|| empty_snippet.clone()),
72 empty_snippet,
73 tool_state: Default::default(),
74 distance_mode: Default::default(),
75 }
76 }
77
78 pub fn supported_functionality(&self) -> &SupportedFunctionality {
79 &self.supported_functionality
80 }
81
82 pub fn tool_on(&mut self) -> impl Iterator<Item = Token<'input>> + '_ {
84 if self.tool_state == Some(Tool::Off) || self.tool_state.is_none() {
85 self.tool_state = Some(Tool::On);
86 self.tool_on_sequence.iter_emit_tokens()
87 } else {
88 self.empty_snippet.iter_emit_tokens()
89 }
90 }
91
92 pub fn tool_off(&mut self) -> impl Iterator<Item = Token<'input>> + '_ {
94 if self.tool_state == Some(Tool::On) || self.tool_state.is_none() {
95 self.tool_state = Some(Tool::Off);
96 self.tool_off_sequence.iter_emit_tokens()
97 } else {
98 self.empty_snippet.iter_emit_tokens()
99 }
100 }
101
102 pub fn program_begin(&self) -> impl Iterator<Item = Token<'input>> + '_ {
104 self.program_begin_sequence.iter_emit_tokens()
105 }
106
107 pub fn program_end(&self) -> impl Iterator<Item = Token<'input>> + '_ {
109 self.program_end_sequence.iter_emit_tokens()
110 }
111
112 pub fn absolute(&mut self) -> Vec<Token<'input>> {
114 if self.distance_mode == Some(Distance::Relative) || self.distance_mode.is_none() {
115 self.distance_mode = Some(Distance::Absolute);
116 command!(AbsoluteDistanceMode {}).into_token_vec()
117 } else {
118 vec![]
119 }
120 }
121
122 pub fn relative(&mut self) -> Vec<Token<'input>> {
124 if self.distance_mode == Some(Distance::Absolute) || self.distance_mode.is_none() {
125 self.distance_mode = Some(Distance::Relative);
126 command!(RelativeDistanceMode {}).into_token_vec()
127 } else {
128 vec![]
129 }
130 }
131}