crystal_cif_io/grammar/structures/
data_items.rs

1use crate::{grammar::tags_values::Value, LoopColumn};
2use std::fmt::Display;
3
4use winnow::{combinator::alt, error::StrContext, Parser};
5
6use crate::grammar::SyntacticUnit;
7
8use super::{
9    loop_struct::{LoopColumns, LoopUnit},
10    tag_value_line::SingleLineData,
11};
12
13#[derive(Debug, Clone)]
14pub enum DataItems {
15    SingleValue(SingleLineData),
16    MultiValues(LoopColumns),
17}
18
19pub trait CIFDataType {}
20
21impl CIFDataType for SingleLineData {}
22impl CIFDataType for LoopUnit {}
23
24impl DataItems {
25    pub fn get_single_value_by_tag<T: AsRef<str>>(&self, tag: T) -> Option<&SingleLineData> {
26        match self {
27            DataItems::SingleValue(tv) => {
28                if tag.as_ref() == tv.tag().as_ref() {
29                    Some(tv)
30                } else {
31                    None
32                }
33            }
34            DataItems::MultiValues(_) => None,
35        }
36    }
37
38    pub fn get_loop_column_values_by_tag<T: AsRef<str>>(&self, tag: T) -> Option<LoopColumn> {
39        if let DataItems::MultiValues(loop_unit) = self {
40            loop_unit.find_loop_column_by_tag(tag).cloned()
41        } else {
42            None
43        }
44    }
45
46    pub fn as_single_value(&self) -> Option<&SingleLineData> {
47        if let Self::SingleValue(v) = self {
48            Some(v)
49        } else {
50            None
51        }
52    }
53
54    pub fn as_multi_values(&self) -> Option<&LoopColumns> {
55        if let Self::MultiValues(v) = self {
56            Some(v)
57        } else {
58            None
59        }
60    }
61}
62
63impl SyntacticUnit for DataItems {
64    type ParseResult = Self;
65
66    type FormatOutput = String;
67
68    fn parser(input: &mut &str) -> winnow::prelude::PResult<Self::ParseResult> {
69        alt((
70            SingleLineData::parser
71                .map(DataItems::SingleValue)
72                .context(StrContext::Label("Single line data")),
73            LoopUnit::parser
74                .map(LoopColumns::from)
75                .map(DataItems::MultiValues)
76                .context(StrContext::Label("Loop")),
77        ))
78        .parse_next(input)
79    }
80
81    fn formatted_output(&self) -> Self::FormatOutput {
82        match self {
83            DataItems::SingleValue(v) => format!("{v}"),
84            DataItems::MultiValues(v) => format!("\n{}\n", LoopUnit::from(v)),
85        }
86    }
87}
88
89impl Display for DataItems {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "{}", self.formatted_output())
92    }
93}