castep_cell_parser/pest_parser/
block.rs

1use std::fmt::Display;
2
3use derive_builder::Builder;
4use pest::iterators::Pair;
5
6use crate::CellParseError;
7
8use super::Rule;
9
10/// Freeform block in `.cell`
11#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Builder)]
12#[builder()]
13pub struct Block {
14    order: usize,
15    name: String,
16    values: Vec<String>,
17}
18
19impl Block {
20    pub fn new(order: usize, name: String, values: Vec<String>) -> Self {
21        Self {
22            order,
23            name,
24            values,
25        }
26    }
27
28    pub fn order(&self) -> usize {
29        self.order
30    }
31
32    pub fn name(&self) -> &str {
33        &self.name
34    }
35
36    pub fn values(&self) -> &[String] {
37        &self.values
38    }
39
40    pub fn values_mut(&mut self) -> &mut Vec<String> {
41        &mut self.values
42    }
43
44    pub fn from_pair(pair: Pair<'_, Rule>, order: usize) -> Self {
45        let inner_rules = pair.into_inner();
46        let block_name = inner_rules
47            .find_first_tagged("block_name")
48            .unwrap()
49            .as_str();
50        let block_lines = inner_rules
51            .find_tagged("block_values") // get all value lines
52            .flat_map(|lines| {
53                lines
54                    .into_inner()
55                    .map(|pair| pair.as_str().to_string())
56                    .collect::<Vec<String>>()
57            })
58            .collect::<Vec<String>>();
59        Self::new(order, block_name.to_string(), block_lines)
60    }
61}
62
63impl Display for Block {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        write!(
66            f,
67            "{}",
68            [
69                format!("%BLOCK {}", self.name()),
70                self.values()
71                    .iter()
72                    .map(|line| format!("  {line}"))
73                    .collect::<Vec<String>>()
74                    .join("\n"),
75                format!("%ENDBLOCK {}", self.name())
76            ]
77            .into_iter()
78            .filter(|line| !line.is_empty())
79            .collect::<Vec<String>>()
80            .join("\n")
81        )
82    }
83}
84
85/// Convert between the impl type and `Block`
86/// Usage: convert from parsed block to edit data,
87/// then convert back to block to insert back to the `HashMap<&str, CELLObject>`
88pub trait BlockIO {
89    type Item;
90    fn from_block(block: &Block) -> Result<Self::Item, CellParseError>;
91    fn to_block(&self, order: usize) -> Block;
92}