crystal_cif_io/grammar/structures/loop_struct/
body.rs

1use winnow::{
2    combinator::{preceded, repeat},
3    Parser,
4};
5
6use crate::{
7    data_dict::{CifTerm, LoopValueTerm},
8    grammar::{tags_values::Value, whitespace_comments::WhiteSpace, SyntacticUnit, Tag},
9};
10
11#[derive(Debug, Clone)]
12pub struct LoopBody {
13    values: Vec<Value>,
14}
15
16impl LoopBody {
17    pub fn new(values: Vec<Value>) -> Self {
18        Self { values }
19    }
20
21    pub fn values(&self) -> &[Value] {
22        &self.values
23    }
24
25    /// Get nth column value, suitable for viewing data of the same tag in the loop.
26    pub fn nth_column_values(&self, nth: usize, column_width: usize) -> Vec<Value> {
27        self.values
28            .chunks(column_width)
29            .map(|chunk| chunk[nth].clone())
30            .collect()
31    }
32
33    /// Create `LoopBody` from a uniform array of `Vec<Value>` columns.
34    pub fn from_columns<T: LoopValueTerm>(columns: &[T], column_length: usize) -> Self {
35        Self::new(
36            (0..column_length)
37                .flat_map(|i| {
38                    columns
39                        .iter()
40                        .map(|c| c.values()[i].clone())
41                        .collect::<Vec<Value>>()
42                })
43                .collect::<Vec<Value>>(),
44        )
45    }
46}
47
48impl SyntacticUnit for LoopBody {
49    type ParseResult = Self;
50
51    type FormatOutput = String;
52
53    fn parser(input: &mut &str) -> winnow::prelude::PResult<Self::ParseResult> {
54        (
55            Value::parser,
56            repeat(0.., preceded(WhiteSpace::parser, Value::parser)),
57        )
58            .map(|(first, following): (Value, Vec<Value>)| {
59                let mut values = vec![first];
60                values.extend(following);
61                LoopBody::new(values)
62            })
63            .parse_next(input)
64    }
65
66    fn formatted_output(&self) -> Self::FormatOutput {
67        self.values()
68            .iter()
69            .map(|v| format!("{v}"))
70            .collect::<Vec<String>>()
71            .join(" ")
72    }
73}
74
75#[derive(Debug, Clone)]
76pub struct LoopColumn {
77    tag: Tag,
78    values: Vec<Value>,
79}
80
81impl AsRef<[Value]> for LoopColumn {
82    fn as_ref(&self) -> &[Value] {
83        <Vec<Value> as AsRef<[Value]>>::as_ref(&self.values)
84    }
85}
86
87impl LoopColumn {
88    pub fn new(tag: Tag, values: Vec<Value>) -> Self {
89        Self { tag, values }
90    }
91
92    pub fn values(&self) -> &[Value] {
93        &self.values
94    }
95
96    pub fn tag(&self) -> &Tag {
97        &self.tag
98    }
99
100    pub fn tag_mut(&mut self) -> &mut Tag {
101        &mut self.tag
102    }
103
104    pub fn values_mut(&mut self) -> &mut Vec<Value> {
105        &mut self.values
106    }
107}
108
109impl CifTerm for LoopColumn {
110    fn tag(&self) -> Tag {
111        self.tag.clone()
112    }
113}
114
115impl LoopValueTerm for LoopColumn {
116    fn values(&self) -> Vec<Value> {
117        self.values().to_vec()
118    }
119}