flow_expression_parser/parse/
v0.rs1use std::collections::HashMap;
2
3use once_cell::sync::Lazy;
4use regex::Regex;
5
6use crate::{parse, Error};
7
8pub(crate) static CONNECTION_TARGET_REGEX: Lazy<Regex> = Lazy::new(|| {
9 Regex::new(&format!(
10 r"^({}|{}|{}|{}|{}|[a-zA-Z][a-zA-Z0-9_]*)(?:\[(\w*)\])?$",
11 DEFAULT_ID,
12 parse::SCHEMATIC_INPUT,
13 parse::SCHEMATIC_OUTPUT,
14 parse::NS_LINK,
15 parse::CORE_ID
16 ))
17 .unwrap()
18});
19
20pub static CONNECTION_SEPARATOR: &str = "=>";
22
23const DEFAULT_ID: &str = "<>";
25
26type Result<T> = std::result::Result<T, Error>;
27
28pub fn parse_target(s: &str) -> Result<(Option<&str>, Option<&str>)> {
30 CONNECTION_TARGET_REGEX.captures(s.trim()).map_or_else(
31 || {
32 Err(Error::ConnectionTargetSyntax(
33 s.to_owned(),
34 "Unspecified error".to_owned(),
35 ))
36 },
37 |captures| {
38 Ok((
39 captures.get(1).map(|m| m.as_str().trim()),
40 captures.get(2).map(|m| m.as_str().trim()),
41 ))
42 },
43 )
44}
45
46pub fn parse_id(id: &str) -> Result<(&str, &str)> {
48 if !id.contains("::") {
49 Err(Error::ComponentIdError(id.to_owned()))
50 } else {
51 id.split_once("::")
52 .ok_or_else(|| Error::ComponentIdError(id.to_owned()))
53 }
54}
55
56type ConnectionDefinitionParts = (String, String, Option<HashMap<String, serde_json::Value>>);
57
58fn parse_from_or_sender(from: &str, default_port: Option<&str>) -> Result<ConnectionDefinitionParts> {
59 match parse_target(from) {
60 Ok((from_ref, from_port)) => Ok((
61 match from_ref {
62 Some(DEFAULT_ID) => parse::SCHEMATIC_INPUT,
63 Some(v) => v,
64 None => return Err(Error::NoDefaultReference(from.to_owned())),
65 }
66 .to_owned(),
67 from_port
68 .or(default_port)
69 .ok_or_else(|| Error::NoDefaultPort(from.to_owned()))?
70 .to_owned(),
71 Default::default(),
72 )),
73 Err(_e) => match serde_json::from_str::<serde_json::Value>(from) {
75 Ok(_) => Ok((
76 parse::SENDER_ID.to_owned(),
77 parse::SENDER_PORT.to_owned(),
78 serde_json::from_str::<serde_json::Value>(from.trim())
79 .map(|v| Some(HashMap::from([("default".to_owned(), v)])))
80 .map_err(|e| Error::InvalidSenderData(e.to_string()))?,
81 )),
82 Err(e) => Err(Error::ConnectionTargetSyntax(from.to_owned(), e.to_string())),
83 },
84 }
85}
86
87pub fn parse_connection(s: &str) -> Result<(ConnectionDefinitionParts, ConnectionDefinitionParts)> {
89 let s = s.trim();
90 s.split_once(CONNECTION_SEPARATOR).map_or_else(
91 || Err(Error::ConnectionDefinitionSyntax(s.to_owned())),
92 |(from, to)| {
93 let (to_ref, to_port) = parse_target(to.trim())?;
94 let from = parse_from_or_sender(from.trim(), to_port)?;
95 let to = (
96 match to_ref {
97 Some(DEFAULT_ID) => parse::SCHEMATIC_OUTPUT,
98 Some(v) => v,
99 None => return Err(Error::NoDefaultReference(s.to_owned())),
100 }
101 .to_owned(),
102 to_port
103 .map(|s| s.to_owned())
104 .or_else(|| Some(from.1.clone()))
105 .ok_or_else(|| Error::NoDefaultPort(s.to_owned()))?,
106 Default::default(),
107 );
108 Ok((from, to))
109 },
110 )
111}
112
113#[cfg(test)]
114mod tests {
115
116 use anyhow::Result;
117 use pretty_assertions::assert_eq;
118
119 use super::*;
120 #[test_logger::test]
121 fn test_reserved() -> Result<()> {
122 let parsed = parse_target("input[foo]")?;
123 assert_eq!(parsed, (Some("input"), Some("foo")));
124 Ok(())
125 }
126
127 #[test_logger::test]
128 fn test_basic() -> Result<()> {
129 let parsed = parse_target("ref[foo]")?;
130 assert_eq!(parsed, (Some("ref"), Some("foo")));
131 Ok(())
132 }
133
134 #[test_logger::test]
135 fn test_default_with_port() -> Result<()> {
136 let parsed = parse_target("<>[foo]")?;
137 assert_eq!(parsed, (Some(DEFAULT_ID), Some("foo")));
138 Ok(())
139 }
140
141 #[test_logger::test]
142 fn test_default() -> Result<()> {
143 let parsed = parse_target("<>")?;
144 assert_eq!(parsed, (Some(DEFAULT_ID), None));
145 Ok(())
146 }
147
148 #[test_logger::test]
149 fn test_connection_basic() -> Result<()> {
150 let parsed = parse_connection("ref1[in] => ref2[out]")?;
151 assert_eq!(
152 parsed,
153 (
154 ("ref1".to_owned(), "in".to_owned(), Default::default(),),
155 ("ref2".to_owned(), "out".to_owned(), Default::default(),),
156 )
157 );
158 Ok(())
159 }
160
161 #[test_logger::test]
162 fn test_bare_num_default() -> Result<()> {
163 let parsed = parse_connection("5 => ref2[out]")?;
164 let num = 5;
165
166 assert_eq!(
167 parsed,
168 (
169 (
170 parse::SENDER_ID.to_owned(),
171 parse::SENDER_PORT.to_owned(),
172 Some(HashMap::from([("default".into(), num.into())])),
173 ),
174 ("ref2".to_owned(), "out".to_owned(), Default::default(),),
175 )
176 );
177 Ok(())
178 }
179
180 #[test_logger::test]
181 fn test_connection_default_input_named_port() -> Result<()> {
182 let parsed = parse_connection("<>[in] => ref2[out]")?;
183 assert_eq!(
184 parsed,
185 (
186 (parse::SCHEMATIC_INPUT.to_owned(), "in".to_owned(), Default::default(),),
187 ("ref2".to_owned(), "out".to_owned(), Default::default(),),
188 )
189 );
190 Ok(())
191 }
192
193 #[test_logger::test]
194 fn test_connection_default_output_named_port() -> Result<()> {
195 let parsed = parse_connection("ref1[in] => <>[out]")?;
196 assert_eq!(
197 parsed,
198 (
199 ("ref1".to_owned(), "in".to_owned(), Default::default(),),
200 (parse::SCHEMATIC_OUTPUT.to_owned(), "out".to_owned(), Default::default(),),
201 )
202 );
203 Ok(())
204 }
205
206 #[test_logger::test]
207 fn test_connection_default_output() -> Result<()> {
208 let parsed = parse_connection("ref1[port] => <>")?;
209 assert_eq!(
210 parsed,
211 (
212 ("ref1".to_owned(), "port".to_owned(), Default::default(),),
213 (
214 parse::SCHEMATIC_OUTPUT.to_owned(),
215 "port".to_owned(),
216 Default::default(),
217 ),
218 )
219 );
220 Ok(())
221 }
222
223 #[test_logger::test]
224 fn test_connection_default_input() -> Result<()> {
225 let parsed = parse_connection("<> => ref1[port]")?;
226 assert_eq!(
227 parsed,
228 (
229 (parse::SCHEMATIC_INPUT.to_owned(), "port".to_owned(), Default::default(),),
230 ("ref1".to_owned(), "port".to_owned(), Default::default(),),
231 )
232 );
233 Ok(())
234 }
235
236 #[test_logger::test]
237 fn test_connection_with_default_data() -> Result<()> {
238 let parsed = parse_connection(r#""default"=>ref1[port]"#)?;
239 assert_eq!(
240 parsed,
241 (
242 (
243 parse::SENDER_ID.to_owned(),
244 parse::SENDER_PORT.to_owned(),
245 Some(HashMap::from([("default".into(), "default".into())])),
246 ),
247 ("ref1".to_owned(), "port".to_owned(), Default::default(),),
248 )
249 );
250 Ok(())
251 }
252
253 #[test_logger::test]
254 fn regression_1() -> Result<()> {
255 let parsed = parse_connection(r#""1234512345" => <>[output]"#)?;
256 assert_eq!(
257 parsed,
258 (
259 (
260 parse::SENDER_ID.to_owned(),
261 parse::SENDER_PORT.to_owned(),
262 Some(HashMap::from([("default".into(), "1234512345".into())])),
263 ),
264 (
265 parse::SCHEMATIC_OUTPUT.to_owned(),
266 "output".to_owned(),
267 Default::default(),
268 ),
269 )
270 );
271 Ok(())
272 }
273}