castep_cell_parser/pest_parser/
mod.rs

1#![allow(unused_imports)]
2use std::{collections::HashMap, fmt::Display};
3
4use pest::iterators::Pairs;
5use pest_derive::Parser;
6
7mod block;
8mod cell_object;
9mod keyword_value;
10
11pub use block::{Block, BlockBuilder, BlockBuilderError, BlockIO};
12pub use cell_object::CELLObject;
13pub use keyword_value::{KeywordValue, SingleKeyword};
14
15#[derive(Debug, Parser)]
16#[grammar = "src/cell.pest"]
17pub struct CELLParser;
18
19impl CELLParser {
20    /// Build `HashMap<String, CELLObject>` from `Pairs<'_, Rule>`
21    /// Caution: I decided to convert all keys to **lowercase**, because while `CASTEP` parses the files caselessly,
22    /// it is hard to handle the case-sensitiveness in pure `HashMap`.
23    pub fn cell_doc_map(pairs: Pairs<'_, Rule>) -> ParsedCellDoc {
24        ParsedCellDoc(HashMap::from_iter(pairs.into_iter().enumerate().map(
25            |(idx, pair)| match pair.as_rule() {
26                Rule::block => {
27                    let inner_rules = pair.into_inner();
28                    let block_name = inner_rules
29                        .find_first_tagged("block_name")
30                        .unwrap()
31                        .as_str()
32                        // Forced to lowercase!
33                        .to_lowercase();
34                    let block_lines = inner_rules
35                        .find_tagged("block_values") // get all value lines
36                        .flat_map(|lines| {
37                            lines
38                                .into_inner()
39                                .map(|pair| pair.as_str().to_string())
40                                .collect::<Vec<String>>()
41                        })
42                        .collect::<Vec<String>>();
43                    let block = Block::new(idx, block_name.to_string(), block_lines);
44                    (block_name, CELLObject::Block(block))
45                }
46                Rule::kv_pair => {
47                    let mut inner_rules = pair.into_inner();
48                    // Forced to lowercase!
49                    let name = inner_rules.next().unwrap().as_str();
50                    let value = inner_rules.next().unwrap().as_str().to_string();
51                    (
52                        name.to_lowercase(),
53                        CELLObject::KeywordValue(KeywordValue::new(idx, name.to_string(), value)),
54                    )
55                }
56                Rule::single_keywords => {
57                    // Forced to lowercase!
58                    let name = pair.as_str();
59                    (
60                        name.to_lowercase(),
61                        CELLObject::SingleKeyword(SingleKeyword::new(idx, name.to_string())),
62                    )
63                }
64                _ => unreachable!(),
65            },
66        )))
67    }
68
69    /// Used for `.cell` format
70    /// Maintained the order from parsed document
71    pub fn ordered_cell_doc(cell_doc_map: &HashMap<String, CELLObject>) -> OrderedCellDoc {
72        let mut ordered_cell_doc: Vec<CELLObject> = cell_doc_map.values().cloned().collect();
73        ordered_cell_doc.sort_by_key(|obj| obj.order());
74        OrderedCellDoc(ordered_cell_doc)
75    }
76
77    /// Used for `.param` format
78    /// Maintained the order from parsed document
79    pub fn ordered_param_doc(cell_doc_map: &HashMap<String, CELLObject>) -> OrderedParamDoc {
80        let mut ordered_param_doc: Vec<CELLObject> = cell_doc_map.values().cloned().collect();
81        ordered_param_doc.sort_by_key(|obj| obj.order());
82        OrderedParamDoc(ordered_param_doc)
83    }
84}
85
86#[derive(Debug, Clone)]
87pub struct ParsedCellDoc(HashMap<String, CELLObject>);
88
89impl std::ops::DerefMut for ParsedCellDoc {
90    fn deref_mut(&mut self) -> &mut Self::Target {
91        &mut self.0
92    }
93}
94
95impl std::ops::Deref for ParsedCellDoc {
96    type Target = HashMap<String, CELLObject>;
97
98    fn deref(&self) -> &Self::Target {
99        &self.0
100    }
101}
102
103#[derive(Debug, Clone)]
104pub struct OrderedCellDoc(Vec<CELLObject>);
105#[derive(Debug, Clone)]
106pub struct OrderedParamDoc(Vec<CELLObject>);
107
108impl Display for OrderedCellDoc {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        write!(
111            f,
112            "{}",
113            self.0
114                .iter()
115                .map(|obj| obj.to_string())
116                .collect::<Vec<String>>()
117                .join("\n\n")
118        )
119    }
120}
121
122impl Display for OrderedParamDoc {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        write!(
125            f,
126            "{}",
127            self.0
128                .iter()
129                .map(|obj| obj.to_string())
130                .collect::<Vec<String>>()
131                .join("\n")
132        )
133    }
134}