fortran_descriptor_parser_macro/
lib.rs

1use quote::quote;
2
3#[derive(Debug, Clone)]
4struct Nested {
5    repetitions: usize,
6    elements: Vec<DataElement>,
7}
8
9#[derive(Debug, Clone)]
10struct ElementInfo {
11    repetitions: usize,
12    bytes_to_take: usize,
13}
14
15impl ElementInfo {
16    fn new(repetitions: usize, bytes_to_take: usize) -> Self {
17        Self {
18            repetitions,
19            bytes_to_take,
20        }
21    }
22}
23
24#[derive(Debug, Clone)]
25enum DataElement {
26    Integer(ElementInfo),
27    Float(ElementInfo),
28    Double(ElementInfo),
29    String(ElementInfo),
30    Nested(Nested),
31}
32
33impl DataElement {
34    fn bytes_to_take(&self) -> usize {
35        match self {
36            DataElement::Integer(element_info) => element_info.bytes_to_take,
37            DataElement::Float(element_info) => element_info.bytes_to_take,
38            DataElement::Double(element_info) => element_info.bytes_to_take,
39            DataElement::String(element_info) => element_info.bytes_to_take,
40            DataElement::Nested(_nested) => unreachable!(),
41        }
42    }
43
44    fn repetitions(&self) -> usize {
45        match self {
46            DataElement::Integer(element_info) => element_info.repetitions,
47            DataElement::Float(element_info) => element_info.repetitions,
48            DataElement::Double(element_info) => element_info.repetitions,
49            DataElement::String(element_info) => element_info.repetitions,
50            DataElement::Nested(_nested) => unreachable!(),
51        }
52    }
53}
54
55fn split_elements(s: &str) -> Vec<String> {
56    let mut complete_list: Vec<String> = vec![];
57    let mut current_element: Vec<char> = vec![];
58    let mut bracket_count = 0;
59    let chars = s.chars();
60    for c in chars {
61        match c {
62            ' ' => (),
63            ',' => {
64                if bracket_count == 0 {
65                    complete_list.push(current_element.iter().collect());
66                    current_element.clear();
67                } else {
68                    current_element.push(c);
69                }
70            }
71            '(' => {
72                bracket_count += 1;
73                current_element.push(c);
74            }
75            ')' => {
76                bracket_count -= 1;
77                current_element.push(c);
78            }
79            _ => {
80                current_element.push(c);
81            }
82        }
83    }
84    if current_element.is_empty() {
85        complete_list
86    } else {
87        complete_list.push(current_element.iter().collect());
88        complete_list
89    }
90}
91
92impl DataElement {
93    fn parse_element(s: &str) -> DataElement {
94        if s.contains("(") {
95            let (repetitions_str, rest) = s.split_at(s.find('(').unwrap());
96            let repetitions = if repetitions_str.is_empty() {
97                1
98            } else {
99                repetitions_str.parse::<usize>().unwrap_or_else(|_| {
100                    panic!("Can't convert {} to repetitions (usize)", repetitions_str)
101                })
102            };
103            let mut bracket_count = 0;
104            let mut inner: Vec<char> = Vec::new();
105
106            for c in rest.chars() {
107                match c {
108                    '(' => {
109                        if bracket_count > 0 {
110                            inner.push(c);
111                        }
112                        bracket_count += 1;
113                    }
114                    ')' => {
115                        bracket_count -= 1;
116                        if bracket_count < 1 {
117                            let inner: String = inner.iter().collect();
118                            let split = split_elements(&inner);
119                            let mut nested = Nested {
120                                repetitions,
121                                elements: Vec::new(),
122                            };
123                            parse_elements(&split, &mut nested.elements);
124                            return DataElement::Nested(nested);
125                        } else {
126                            inner.push(c);
127                        }
128                    }
129                    _ => {
130                        inner.push(c);
131                    }
132                }
133            }
134            panic!("Opening bracket was not closed: {}", repetitions_str);
135        } else {
136            let (i, c) =
137                if let Some((i, c)) = s.char_indices().find(|(_i, c)| c.is_ascii_alphabetic()) {
138                    (i, c)
139                } else {
140                    panic!("Element does not have a type identifier");
141                };
142            let (repetitions_str, bytes_to_take_str) = s.split_at(i);
143            let bytes_to_take_str: String = bytes_to_take_str.chars().skip(1).collect();
144            let repetitions = if repetitions_str.is_empty() {
145                1
146            } else {
147                repetitions_str.parse::<usize>().unwrap_or_else(|_| {
148                    panic!("Can't convert {} to repetitions (usize)", repetitions_str)
149                })
150            };
151            let bytes_to_take = bytes_to_take_str.parse::<usize>().unwrap_or_else(|_| {
152                panic!(
153                    "Can't convert {} to bytes_to_take (usize)",
154                    bytes_to_take_str
155                )
156            });
157            match c.to_ascii_uppercase() {
158                'I' => DataElement::Integer(ElementInfo::new(repetitions, bytes_to_take)),
159                'F' => DataElement::Float(ElementInfo::new(repetitions, bytes_to_take)),
160                'D' => DataElement::Double(ElementInfo::new(repetitions, bytes_to_take)),
161                'S' => DataElement::String(ElementInfo::new(repetitions, bytes_to_take)),
162                _ => panic!("Unsupported type {}", c),
163            }
164        }
165    }
166}
167
168fn parse_elements(split: &Vec<String>, list: &mut Vec<DataElement>) {
169    for s in split {
170        list.push(DataElement::parse_element(s));
171    }
172}
173
174fn expand_elements(elements: &[DataElement]) -> Vec<DataElement> {
175    let mut expanded_elements: Vec<DataElement> = Vec::new();
176    for element in elements.iter() {
177        match element {
178            DataElement::Nested(nested) => {
179                for _ in 0..nested.repetitions {
180                    let mut nested_elements = expand_elements(&nested.elements);
181                    expanded_elements.append(&mut nested_elements);
182                }
183            }
184            _ => {
185                for _ in 0..element.repetitions() {
186                    expanded_elements.push(element.clone());
187                }
188            }
189        }
190    }
191    expanded_elements
192}
193
194/// Please refer to the crate documentation of `fortran_descriptor_parser`
195#[proc_macro]
196pub fn descriptor_parser(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
197    let mut input_iter = input.into_iter();
198    let input_string = if let Some(tree) = input_iter.next() {
199        match tree {
200            proc_macro::TokenTree::Literal(literal) => literal.to_string(),
201            _ => panic!("Please provide a string, found {:?}", tree),
202        }
203    } else {
204        panic!("Please provide a string literal, found empty input");
205    };
206    let input_string: String = input_string.chars().filter(|c| *c != '"').collect();
207    let split = split_elements(&input_string);
208    let mut elements = Vec::new();
209    parse_elements(&split, &mut elements);
210
211    let expanded_elements = expand_elements(&elements);
212    let bytes_to_take = expanded_elements
213        .iter()
214        .fold(0, |acc, e| acc + e.bytes_to_take());
215
216    let mut parse_tokens = Vec::new();
217    for e in expanded_elements.iter() {
218        match e {
219            DataElement::Integer(element_info) => {
220                let bytes_to_take = element_info.bytes_to_take;
221                parse_tokens.push(quote! {
222                    <[u8] as ::fortran_descriptor_parser::FromSlice<i32>>::to_type(::fortran_descriptor_parser::get_sub_slice(&mut start_byte, #bytes_to_take, i))?
223                 });
224            }
225            DataElement::Float(element_info) => {
226                let bytes_to_take = element_info.bytes_to_take;
227                parse_tokens.push(quote! {
228                    <[u8] as ::fortran_descriptor_parser::FromSlice<f32>>::to_type(::fortran_descriptor_parser::get_sub_slice(&mut start_byte, #bytes_to_take, i))?
229                 });
230            }
231            DataElement::Double(element_info) => {
232                let bytes_to_take = element_info.bytes_to_take;
233                parse_tokens.push(quote! {
234                    <[u8] as ::fortran_descriptor_parser::FromSlice<f64>>::to_type(::fortran_descriptor_parser::get_sub_slice(&mut start_byte, #bytes_to_take, i))?
235                 });
236            }
237            DataElement::String(element_info) => {
238                let bytes_to_take = element_info.bytes_to_take;
239                parse_tokens.push(quote! {
240                    <[u8] as ::fortran_descriptor_parser::FromSlice<String>>::to_type(::fortran_descriptor_parser::get_sub_slice(&mut start_byte, #bytes_to_take, i))?
241                 });
242            }
243            DataElement::Nested(_nested) => unreachable!(),
244        }
245    }
246    quote! {
247        |i: &[u8]| {
248            if i.len() < #bytes_to_take {
249                return Err(::fortran_descriptor_parser::DescriptorParserError::NotEnoughBytes(i.len(), #bytes_to_take));
250            }
251            let mut start_byte: usize = 0;
252            let parsers = (#(#parse_tokens),*);
253            Ok(parsers)
254        }
255    }
256    .into()
257}