crystal_cif_io/grammar/structures/
data_items.rs1use 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}