1use core::hash::Hash;
2use core::hash::Hasher;
3use std::collections::HashSet;
4
5use nom::bytes::complete::tag;
6use nom::character::complete::space0;
7use nom::combinator::map;
8use nom::sequence::preceded;
9use nom::IResult;
10use nom::Parser;
11
12#[derive(Clone, Debug, PartialEq, Eq)]
16pub enum Form {
17 IJ(HashSet<ArcVal>),
19 R(HashSet<ArcVal>),
21}
22
23#[derive(Clone, Debug)]
28pub enum ArcVal {
29 A(f64),
31 B(f64),
33 C(f64),
35
36 E(f64),
38 F(f64),
40
41 S(f64),
43
44 I(f64),
46 J(f64),
48
49 P(f64),
51 R(f64),
53
54 U(f64),
56 V(f64),
58
59 X(f64),
61 Y(f64),
63 Z(f64),
65 W(f64),
67}
68
69impl Eq for ArcVal {}
70
71impl PartialEq for ArcVal {
75 fn eq(&self, other: &Self) -> bool {
76 match (self, other) {
77 (Self::A(x), Self::A(y))
78 | (Self::B(x), Self::B(y))
79 | (Self::C(x), Self::C(y))
80 | (Self::E(x), Self::E(y))
81 | (Self::F(x), Self::F(y))
82 | (Self::I(x), Self::I(y))
83 | (Self::J(x), Self::J(y))
84 | (Self::P(x), Self::P(y))
85 | (Self::R(x), Self::R(y))
86 | (Self::S(x), Self::S(y))
87 | (Self::U(x), Self::U(y))
88 | (Self::V(x), Self::V(y))
89 | (Self::W(x), Self::W(y))
90 | (Self::X(x), Self::X(y))
91 | (Self::Y(x), Self::Y(y))
92 | (Self::Z(x), Self::Z(y)) => x.to_bits() == y.to_bits(),
93 _ => false,
94 }
95 }
96}
97
98impl Hash for ArcVal {
107 fn hash<H: Hasher>(&self, state: &mut H) {
108 match self {
109 Self::A(_) => "A".hash(state),
110 Self::B(_) => "B".hash(state),
111 Self::C(_) => "C".hash(state),
112 Self::E(_) => "E".hash(state),
113 Self::F(_) => "F".hash(state),
114 Self::I(_) => "I".hash(state),
115 Self::J(_) => "J".hash(state),
116 Self::P(_) => "P".hash(state),
117 Self::R(_) => "R".hash(state),
118 Self::S(_) => "S".hash(state),
119 Self::U(_) => "U".hash(state),
120 Self::V(_) => "V".hash(state),
121 Self::W(_) => "W".hash(state),
122 Self::X(_) => "X".hash(state),
123 Self::Y(_) => "Y".hash(state),
124 Self::Z(_) => "Z".hash(state),
125 }
126 }
127}
128
129macro_rules! parse_arc_val {
136 ($name:ident, $tag:literal, $variant:ident) => {
137 #[doc = "Extracts"]
138 #[doc = stringify!($tag)]
139 #[doc = " parameter"]
140 #[doc = ""]
141 #[doc = "# Errors"]
142 #[doc = " When match fails."]
143 pub fn $name(i: &str) -> IResult<&str, ArcVal> {
144 map(
145 preceded((space0, tag($tag)), crate::double::double_no_exponent),
146 ArcVal::$variant,
147 )
148 .parse(i)
149 }
150 };
151}
152
153parse_arc_val!(parse_arc_a, "A", A);
154parse_arc_val!(parse_arc_b, "B", B);
155parse_arc_val!(parse_arc_c, "C", C);
156parse_arc_val!(parse_arc_e, "E", E);
157
158parse_arc_val!(parse_arc_i, "I", I);
159parse_arc_val!(parse_arc_j, "J", J);
160parse_arc_val!(parse_arc_p, "P", P);
161parse_arc_val!(parse_arc_r, "R", R);
162
163parse_arc_val!(parse_arc_f, "F", F);
164parse_arc_val!(parse_arc_s, "S", S);
165parse_arc_val!(parse_arc_u, "U", U);
166parse_arc_val!(parse_arc_v, "V", V);
167
168parse_arc_val!(parse_arc_w, "W", W);
169parse_arc_val!(parse_arc_x, "X", X);
170parse_arc_val!(parse_arc_y, "Y", Y);
171parse_arc_val!(parse_arc_z, "Z", Z);
172
173#[cfg(test)]
174mod test {
175 use super::*;
176
177 #[test]
179 fn parse_a_macro() {
180 assert_eq!(parse_arc_a("A95.110"), Ok(("", ArcVal::A(95.110))));
181 }
182
183 #[test]
185 fn parse_negative_value() {
186 assert_eq!(parse_arc_e("E-1.1"), Ok(("", ArcVal::E(-1.1))));
187 assert_eq!(parse_arc_i("I-10.10"), Ok(("", ArcVal::I(-10.10))));
188 assert_eq!(parse_arc_j("J-100.100"), Ok(("", ArcVal::J(-100.100))));
189 }
190
191 #[test]
192 fn pos_value_equality() {
193 assert!(ArcVal::A(95.0) == ArcVal::A(95.0));
195
196 assert!(ArcVal::A(95.0) != ArcVal::B(9.0));
198
199 assert!(ArcVal::A(95.0) != ArcVal::B(95.0));
201 }
202}