plantuml_parser/
filedata.rs1use crate::Error;
2use crate::ParseContainer;
3use crate::PlantUmlContent;
4use crate::{IncludeToken, PlantUmlLine};
5use std::sync::Arc;
6
7#[derive(Clone, Debug)]
51pub struct PlantUmlFileData {
52 contents: Vec<PlantUmlContent>,
53}
54
55impl PlantUmlFileData {
56 pub fn parse_from_str<S>(input: S) -> Result<Self, Error>
60 where
61 S: Into<String>,
62 {
63 let input = ParseContainer::new(Arc::new(input.into()));
64 Self::parse(input)
65 }
66
67 pub fn parse(input: ParseContainer) -> Result<Self, Error> {
71 let mut contents = vec![];
72 let mut input = input;
73 let (mut rest, (_, mut line)) = PlantUmlLine::parse(input.clone())?;
74
75 'outer: while !rest.is_empty() {
76 while line.empty().is_some() {
77 (rest, (_, line)) = PlantUmlLine::parse(input.clone())?;
78 if line.empty().is_none() {
79 break;
80 }
81 if rest.is_empty() {
82 break 'outer;
83 }
84 input = rest;
85 }
86
87 let (tmp_rest, content) = PlantUmlContent::parse(input)?;
88 input = tmp_rest;
89 contents.push(content);
90 if input.is_empty() {
91 break;
92 }
93 (rest, (_, line)) = PlantUmlLine::parse(input.clone())?;
94 }
95
96 Ok(Self { contents })
97 }
98
99 pub fn get_by_token(&self, token: &IncludeToken) -> Option<&PlantUmlContent> {
103 if let Some(content) = token.id().and_then(|id| self.get_by_id(id)) {
104 Some(content)
105 } else if let Some(content) = token.index().and_then(|index| self.get(index)) {
106 Some(content)
107 } else {
108 self.get(0)
109 }
110 }
111
112 pub fn get(&self, index: usize) -> Option<&PlantUmlContent> {
114 self.contents.get(index)
115 }
116
117 pub fn get_by_id(&self, id: &str) -> Option<&PlantUmlContent> {
119 self.contents.iter().find(|x| x.id() == Some(id))
120 }
121
122 pub fn iter(&self) -> std::slice::Iter<'_, PlantUmlContent> {
124 self.contents.iter()
125 }
126
127 pub fn is_empty(&self) -> bool {
129 self.contents.is_empty()
130 }
131
132 pub fn len(&self) -> usize {
134 self.contents.len()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 use anyhow::Result;
143
144 #[test]
145 fn test_parse_plant_uml_file_data() -> Result<()> {
146 let testdata = r#"@startuml
148 @enduml
149
150 @startuml a
151 a -> b
152 @enduml
153
154
155 @startuml(id=b)
156 b -> a
157 @enduml
158
159 "#;
160 let parsed = PlantUmlFileData::parse(testdata.into())?;
161 assert_eq!(parsed.contents.len(), 3);
162
163 let content_0 = parsed.get(0).unwrap();
164 assert!(content_0.id().is_none());
165
166 let content_1 = parsed.get(1).unwrap();
167 assert_eq!(content_1.id(), Some("a"));
168 assert_eq!(content_1.inner(), " a -> b\n");
169
170 let content_a = parsed.get_by_id("a").unwrap();
171 assert_eq!(content_a.id(), Some("a"));
172 assert_eq!(content_a.inner(), " a -> b\n");
173
174 let content_2 = parsed.get(2).unwrap();
175 assert_eq!(content_2.id(), Some("b"));
176 assert_eq!(content_2.inner(), " b -> a\n");
177
178 let content_b = parsed.get_by_id("b").unwrap();
179 assert_eq!(content_b.id(), Some("b"));
180 assert_eq!(content_b.inner(), " b -> a\n");
181
182 assert!(parsed.get(3).is_none());
183
184 Ok(())
185 }
186
187 #[test]
188 fn test_unclosed() -> Result<()> {
189 let testdata = r#"@startuml
191 @e
192
193 "#;
194
195 let result = PlantUmlFileData::parse_from_str(testdata);
196 assert!(result.is_err());
197
198 Ok(())
199 }
200}