gcode_nom/params/
head.rs

1use core::hash::Hash;
2use core::hash::Hasher;
3
4use nom::bytes::complete::tag;
5use nom::character::complete::space0;
6use nom::combinator::map;
7use nom::sequence::preceded;
8use nom::IResult;
9use nom::Parser;
10
11/// Parameters for `Command::G0` and `Command::G1`
12#[derive(Clone, Debug)]
13pub enum PosVal {
14    /// Axis A
15    A(f64),
16    /// Axis B
17    B(f64),
18    /// Axis C
19    C(f64),
20
21    /// Extruder
22    E(f64),
23    /// sets the federate for all subsequent moved.
24    F(f64),
25
26    /// Sets the laser power for the move
27    S(f64),
28
29    /// Axis U
30    U(f64),
31    /// Axis V
32    V(f64),
33
34    /// Axis X
35    X(f64),
36    /// Axis Y
37    Y(f64),
38    /// Axis Z
39    Z(f64),
40    /// Axis W
41    W(f64),
42}
43
44impl Eq for PosVal {}
45
46/// Bit wise comparison cant' compare directly [NAN and inf]
47///
48/// N.B. Equality is not used in production code -  assertion testing only.
49impl PartialEq for PosVal {
50    fn eq(&self, other: &Self) -> bool {
51        match (self, other) {
52            (Self::A(x), Self::A(y))
53            | (Self::B(x), Self::B(y))
54            | (Self::C(x), Self::C(y))
55            | (Self::E(x), Self::E(y))
56            | (Self::F(x), Self::F(y))
57            | (Self::S(x), Self::S(y))
58            | (Self::U(x), Self::U(y))
59            | (Self::V(x), Self::V(y))
60            | (Self::W(x), Self::W(y))
61            | (Self::X(x), Self::X(y))
62            | (Self::Y(x), Self::Y(y))
63            | (Self::Z(x), Self::Z(y)) => x.to_bits() == y.to_bits(),
64            _ => false,
65        }
66    }
67}
68
69/// Hash is used to determine if an entry should be added to the Sets
70///
71/// malformed commands with duplicate parameters will be rejected here.
72///
73/// G1 X95.110 X96.233 E2.07708
74///
75/// By ignoring the f64 in hashing the parsed Command will only have one
76/// X value.
77impl Hash for PosVal {
78    fn hash<H: Hasher>(&self, state: &mut H) {
79        match self {
80            Self::A(_) => "A".hash(state),
81            Self::B(_) => "B".hash(state),
82            Self::C(_) => "C".hash(state),
83            Self::E(_) => "E".hash(state),
84            Self::F(_) => "F".hash(state),
85            Self::S(_) => "S".hash(state),
86            Self::U(_) => "U".hash(state),
87            Self::V(_) => "V".hash(state),
88            Self::W(_) => "W".hash(state),
89            Self::X(_) => "X".hash(state),
90            Self::Y(_) => "Y".hash(state),
91            Self::Z(_) => "Z".hash(state),
92        }
93    }
94}
95
96// A macro to make a parse_X() function where X is a parameter in a G0/G1 command
97//
98// BUGFIX: using double_no_exponent from double.rs
99// as parsing a float where an exponent conflicts
100// with the E parameter in GCode.
101// a replacement for nom::number::complete::double;
102macro_rules! parse_val {
103    ($name:ident, $tag:literal, $variant:ident) => {
104        #[doc = "Extracts"]
105        #[doc = stringify!($tag)]
106        #[doc = " parameter"]
107        #[doc = ""]
108        #[doc = "# Errors"]
109        #[doc = "  When match fails."]
110        pub fn $name(i: &str) -> IResult<&str, PosVal> {
111            map(
112                preceded((space0, tag($tag)), crate::double::double_no_exponent),
113                PosVal::$variant,
114            )
115            .parse(i)
116        }
117    };
118}
119
120parse_val!(parse_a, "A", A);
121parse_val!(parse_b, "B", B);
122parse_val!(parse_c, "C", C);
123// /// Extracts A parameter
124parse_val!(parse_e, "E", E);
125parse_val!(parse_f, "F", F);
126parse_val!(parse_s, "S", S);
127// ///
128parse_val!(parse_u, "U", U);
129parse_val!(parse_v, "V", V);
130parse_val!(parse_w, "W", W);
131// /// # Errorsparse_val!(parse_e, "E", E);
132parse_val!(parse_x, "X", X);
133parse_val!(parse_y, "Y", Y);
134parse_val!(parse_z, "Z", Z);
135// ///   When match fails.parse_val!(parse_s, "S", S);
136#[cfg(test)]
137mod test {
138    use super::*;
139
140    #[test]
141    fn pos_value_equality() {
142        // Pass: - parameter wrapper and inner value match.
143        assert!(PosVal::A(95.0) == PosVal::A(95.0));
144
145        // Fail: -  A = A but inner value is different.
146        assert!(PosVal::A(95.0) != PosVal::B(9.0));
147
148        // FAIL: - A != B but with identical inner value.
149        assert!(PosVal::A(95.0) != PosVal::B(95.0));
150    }
151}