dynamo_runtime/
protocols.rs1use serde::{Deserialize, Serialize};
17use std::str::FromStr;
18
19use crate::pipeline::PipelineError;
20
21pub mod annotated;
22pub mod maybe_error;
23
24pub type LeaseId = i64;
25
26const DEFAULT_NAMESPACE: &str = "NS";
28
29const DEFAULT_COMPONENT: &str = "C";
30
31const DEFAULT_ENDPOINT: &str = "E";
32
33pub const ENDPOINT_SCHEME: &str = "dyn://";
37
38#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
39pub struct Component {
40 pub name: String,
41 pub namespace: String,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
55pub struct Endpoint {
56 pub namespace: String,
57 pub component: String,
58 pub name: String,
59}
60
61impl PartialEq<Vec<&str>> for Endpoint {
62 fn eq(&self, other: &Vec<&str>) -> bool {
63 if other.len() != 3 {
64 return false;
65 }
66
67 self.namespace == other[0] && self.component == other[1] && self.name == other[2]
68 }
69}
70
71impl PartialEq<Endpoint> for Vec<&str> {
72 fn eq(&self, other: &Endpoint) -> bool {
73 other == self
74 }
75}
76
77impl Default for Endpoint {
78 fn default() -> Self {
79 Endpoint {
80 namespace: DEFAULT_NAMESPACE.to_string(),
81 component: DEFAULT_COMPONENT.to_string(),
82 name: DEFAULT_ENDPOINT.to_string(),
83 }
84 }
85}
86
87impl From<&str> for Endpoint {
88 fn from(input: &str) -> Self {
114 let mut result = Endpoint::default();
115
116 let elements: Vec<&str> = input
118 .trim_matches([' ', '/', '.'])
119 .split(['.', '/'])
120 .filter(|x| !x.is_empty())
121 .collect();
122
123 match elements.len() {
124 0 => {}
125 1 => {
126 result.component = elements[0].to_string();
127 }
128 2 => {
129 result.namespace = elements[0].to_string();
130 result.component = elements[1].to_string();
131 }
132 3 => {
133 result.namespace = elements[0].to_string();
134 result.component = elements[1].to_string();
135 result.name = elements[2].to_string();
136 }
137 x if x > 3 => {
138 result.namespace = elements[0].to_string();
139 result.component = elements[1].to_string();
140 result.name = elements[2..].join("_");
141 }
142 _ => unreachable!(),
143 }
144 result
145 }
146}
147
148impl FromStr for Endpoint {
149 type Err = PipelineError;
150
151 fn from_str(s: &str) -> Result<Self, Self::Err> {
172 let cleaned = s.strip_prefix(ENDPOINT_SCHEME).unwrap_or(s);
173 Ok(Endpoint::from(cleaned))
174 }
175}
176
177impl Endpoint {
178 pub fn as_url(&self) -> String {
180 format!(
181 "{ENDPOINT_SCHEME}{}.{}.{}",
182 self.namespace, self.component, self.name
183 )
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use std::convert::TryFrom;
191 use std::str::FromStr;
192
193 #[test]
194 fn test_valid_endpoint_from() {
195 let input = "namespace1/component1/endpoint1";
196 let endpoint = Endpoint::from(input);
197
198 assert_eq!(endpoint.namespace, "namespace1");
199 assert_eq!(endpoint.component, "component1");
200 assert_eq!(endpoint.name, "endpoint1");
201 }
202
203 #[test]
204 fn test_valid_endpoint_from_str() {
205 let input = "namespace2/component2/endpoint2";
206 let endpoint = Endpoint::from_str(input).unwrap();
207
208 assert_eq!(endpoint.namespace, "namespace2");
209 assert_eq!(endpoint.component, "component2");
210 assert_eq!(endpoint.name, "endpoint2");
211 }
212
213 #[test]
214 fn test_valid_endpoint_parse() {
215 let input = "namespace3/component3/endpoint3";
216 let endpoint: Endpoint = input.parse().unwrap();
217
218 assert_eq!(endpoint.namespace, "namespace3");
219 assert_eq!(endpoint.component, "component3");
220 assert_eq!(endpoint.name, "endpoint3");
221 }
222
223 #[test]
224 fn test_endpoint_from() {
225 let result = Endpoint::from("component");
226 assert_eq!(
227 result,
228 vec![DEFAULT_NAMESPACE, "component", DEFAULT_ENDPOINT]
229 );
230 }
231
232 #[test]
233 fn test_namespace_component_endpoint() {
234 let result = Endpoint::from("namespace.component.endpoint");
235 assert_eq!(result, vec!["namespace", "component", "endpoint"]);
236 }
237
238 #[test]
239 fn test_forward_slash_separator() {
240 let result = Endpoint::from("namespace/component");
241 assert_eq!(result, vec!["namespace", "component", DEFAULT_ENDPOINT]);
242 }
243
244 #[test]
245 fn test_multiple_parts() {
246 let result = Endpoint::from("namespace.component.endpoint.other.parts");
247 assert_eq!(
248 result,
249 vec!["namespace", "component", "endpoint_other_parts"]
250 );
251 }
252
253 #[test]
254 fn test_mixed_separators() {
255 let result: Endpoint = "namespace/component.endpoint".into();
257 assert_eq!(result, vec!["namespace", "component", "endpoint"]);
258 }
259
260 #[test]
261 fn test_empty_string() {
262 let result = Endpoint::from("");
263 assert_eq!(
264 result,
265 vec![DEFAULT_NAMESPACE, DEFAULT_COMPONENT, DEFAULT_ENDPOINT]
266 );
267
268 let result = Endpoint::from(" ");
270 assert_eq!(
271 result,
272 vec![DEFAULT_NAMESPACE, DEFAULT_COMPONENT, DEFAULT_ENDPOINT]
273 );
274 }
275}