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