figure_skating_element_parser/
lib.rs1#![doc = include_str!("../docs.md")]
2
3use ::pest_derive::Parser;
4use pest::Parser;
5use thiserror::Error;
6
7#[derive(Parser)]
8#[grammar = "./grammar.pest"]
9pub struct ElementParser;
10
11#[derive(Debug)]
12pub struct ParsedElement {
13 pub element_type: String,
14 pub full_name: String,
15 pub base_value: f32,
16}
17
18#[derive(Debug, Error)]
19pub enum ParseError {
20 #[error("Failed to parse element: {0}")]
21 ParseError(String),
22}
23
24impl ParsedElement {
25 pub fn from_text(text: &str) -> Result<Vec<Self>, ParseError> {
26 let mut elements = Vec::new();
27
28 for line in text.split_whitespace() {
29 let pairs = ElementParser::parse(Rule::element, line)
30 .map_err(|e| ParseError::ParseError(e.to_string()))?;
31
32 for pair in pairs {
33 if pair.as_rule() == Rule::element {
34 let mut element_type = String::new();
35 let mut full_name = String::new();
36 let mut base_value = 0.0;
37
38 for inner_pair in pair.into_inner() {
39 match inner_pair.as_rule() {
40 Rule::jump => {
41 element_type = "Jump".to_string();
42 full_name = get_full_name(inner_pair.as_str());
43 base_value = get_base_value(inner_pair.as_str());
44 }
45 Rule::spin => {
46 element_type = "Spin".to_string();
47 full_name = get_full_name(inner_pair.as_str());
48 base_value = get_base_value(inner_pair.as_str());
49 }
50 Rule::step_sequence => {
51 element_type = "Step Sequence".to_string();
52 full_name = get_full_name(inner_pair.as_str());
53 base_value = get_base_value(inner_pair.as_str());
54 }
55
56 Rule::death_spiral => {
57 element_type = "Death Spiral".to_string();
58 full_name = get_full_name(inner_pair.as_str());
59 base_value = get_base_value(inner_pair.as_str());
60 }
61 Rule::pair_spin => {
62 element_type = "Pair Spin".to_string();
63 full_name = get_full_name(inner_pair.as_str());
64 base_value = get_base_value(inner_pair.as_str());
65 }
66 Rule::twizzle => {
67 element_type = "Twizzle".to_string();
68 full_name = get_full_name(inner_pair.as_str());
69 base_value = get_base_value(inner_pair.as_str());
70 }
71 Rule::choreographic_element => {
72 element_type = "Choreographic Element".to_string();
73 full_name = get_full_name(inner_pair.as_str());
74 base_value = get_base_value(inner_pair.as_str());
75 }
76 _ => {}
77 }
78 }
79
80 elements.push(ParsedElement {
81 element_type,
82 full_name,
83 base_value,
84 });
85 }
86 }
87 }
88
89 Ok(elements)
90 }
91}
92
93fn get_full_name(code: &str) -> String {
94 match code {
95 "1T" => "Single Toeloop".to_string(),
97 "2T" => "Double Toeloop".to_string(),
98 "3T" => "Triple Toeloop".to_string(),
99 "4T" => "Quad Toeloop".to_string(),
100 "1S" => "Single Salchow".to_string(),
101 "2S" => "Double Salchow".to_string(),
102 "3S" => "Triple Salchow".to_string(),
103 "4S" => "Quad Salchow".to_string(),
104 "1Lo" => "Single Loop".to_string(),
105 "2Lo" => "Double Loop".to_string(),
106 "3Lo" => "Triple Loop".to_string(),
107 "4Lo" => "Quad Loop".to_string(),
108 "1F" => "Single Flip".to_string(),
109 "2F" => "Double Flip".to_string(),
110 "3F" => "Triple Flip".to_string(),
111 "4F" => "Quad Flip".to_string(),
112 "1Lz" => "Single Lutz".to_string(),
113 "2Lz" => "Double Lutz".to_string(),
114 "3Lz" => "Triple Lutz".to_string(),
115 "4Lz" => "Quad Lutz".to_string(),
116 "1A" => "Single Axel".to_string(),
117 "2A" => "Double Axel".to_string(),
118 "3A" => "Triple Axel".to_string(),
119 "4A" => "Quad Axel".to_string(),
120
121 "USp" => "Upright Spin".to_string(),
123 "LSp" => "Layback Spin".to_string(),
124 "CSp" => "Camel Spin".to_string(),
125 "SSp" => "Sit Spin".to_string(),
126 "FUSp" => "Flying Upright Spin".to_string(),
127 "FLSp" => "Flying Layback Spin".to_string(),
128 "FCSp" => "Flying Camel Spin".to_string(),
129 "FSSp" => "Flying Sit Spin".to_string(),
130 "FCCSp" => "Flying Change Foot Camel Spin".to_string(),
131
132 "StSq" => "Step Sequence".to_string(),
134 "ChSq" => "Choreographic Sequence".to_string(),
135
136 "FiDs" => "Forward Inside Death Spiral".to_string(),
138 "BiDs" => "Backward Inside Death Spiral".to_string(),
139 "FoDs" => "Forward Outside Death Spiral".to_string(),
140 "BoDs" => "Backward Outside Death Spiral".to_string(),
141
142 "PSp" => "Pair Spin".to_string(),
144 "PCoSp" => "Pair Combination Spin".to_string(),
145
146 "STw" => "Twizzle".to_string(),
148
149 "ChLi1" => "Choreographic Lift".to_string(),
151 "ChSp1" => "Choreographic Spinning Movement".to_string(),
152
153 _ => "Unknown Element".to_string(),
154 }
155}
156
157fn get_base_value(code: &str) -> f32 {
159 match code {
160 "1T" => 0.4,
162 "2T" => 1.3,
163 "3T" => 4.2,
164 "4T" => 9.5,
165 "1S" => 0.4,
166 "2S" => 1.3,
167 "3S" => 4.3,
168 "4S" => 9.7,
169 "1Lo" => 0.5,
170 "2Lo" => 1.7,
171 "3Lo" => 4.9,
172 "4Lo" => 10.5,
173 "1F" => 0.5,
174 "2F" => 1.8,
175 "3F" => 5.3,
176 "4F" => 11.0,
177 "1Lz" => 0.6,
178 "2Lz" => 2.1,
179 "3Lz" => 6.0,
180 "4Lz" => 11.5,
181 "1A" => 1.1,
182 "2A" => 3.3,
183 "3A" => 8.0,
184 "4A" => 12.5,
185
186 "USp" => 1.2,
188 "LSp" => 1.5,
189 "CSp" => 1.7,
190 "SSp" => 1.8,
191 "FUSp" => 2.0,
192 "FLSp" => 2.3,
193 "FCSp" => 2.5,
194 "FSSp" => 2.6,
195 "FCCSp" => 2.8,
196
197 "StSq" => 1.5,
199 "ChSq" => 3.0,
200
201 "FiDs" => 1.5,
203 "BiDs" => 1.6,
204 "FoDs" => 1.7,
205 "BoDs" => 1.8,
206
207 "PSp" => 1.7,
209 "PCoSp" => 2.5,
210
211 "STw" => 1.0,
213
214 "ChLi1" => 1.1,
216 "ChSp1" => 1.1,
217
218 _ => 0.0,
219 }
220}
221
222pub fn parse_elements(text: &str) -> Result<Vec<ParsedElement>, ParseError> {
223 ParsedElement::from_text(text)
224}