1use alloc::{borrow::ToOwned, format, string::String};
15use core::{borrow::Borrow, convert::TryFrom, fmt, str::FromStr};
16
17use zenoh_result::{bail, zerror, Error as ZError, ZResult};
18
19use super::{locator::*, parameters};
20
21pub const PROTO_SEPARATOR: char = '/';
23pub const METADATA_SEPARATOR: char = '?';
24pub const CONFIG_SEPARATOR: char = '#';
25
26pub(super) fn protocol(s: &str) -> &str {
28 let pdix = s.find(PROTO_SEPARATOR).unwrap_or(s.len());
29 &s[..pdix]
30}
31
32pub(super) fn address(s: &str) -> &str {
33 let pdix = s.find(PROTO_SEPARATOR).unwrap_or(s.len());
34 let midx = s.find(METADATA_SEPARATOR).unwrap_or(s.len());
35 let cidx = s.find(CONFIG_SEPARATOR).unwrap_or(s.len());
36 &s[pdix + 1..midx.min(cidx)]
37}
38
39pub(super) fn metadata(s: &str) -> &str {
40 match s.find(METADATA_SEPARATOR) {
41 Some(midx) => {
42 let cidx = s.find(CONFIG_SEPARATOR).unwrap_or(s.len());
43 &s[midx + 1..cidx]
44 }
45 None => "",
46 }
47}
48
49pub(super) fn config(s: &str) -> &str {
50 match s.find(CONFIG_SEPARATOR) {
51 Some(cidx) => &s[cidx + 1..],
52 None => "",
53 }
54}
55
56#[repr(transparent)]
58#[derive(Copy, Clone, PartialEq, Eq, Hash)]
59pub struct Protocol<'a>(pub(super) &'a str);
60
61impl<'a> Protocol<'a> {
62 pub fn as_str(&self) -> &'a str {
63 self.0
64 }
65}
66
67impl AsRef<str> for Protocol<'_> {
68 fn as_ref(&self) -> &str {
69 self.as_str()
70 }
71}
72
73impl fmt::Display for Protocol<'_> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.write_str(self.as_str())
76 }
77}
78
79impl fmt::Debug for Protocol<'_> {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(f, "{}", self)
82 }
83}
84
85#[repr(transparent)]
86#[derive(PartialEq, Eq, Hash)]
87pub struct ProtocolMut<'a>(&'a mut EndPoint);
88
89impl<'a> ProtocolMut<'a> {
90 pub fn as_str(&'a self) -> &'a str {
91 address(self.0.as_str())
92 }
93
94 pub fn set(&mut self, p: &str) -> ZResult<()> {
95 let ep = EndPoint::new(p, self.0.address(), self.0.metadata(), self.0.config())?;
96
97 self.0.inner = ep.inner;
98 Ok(())
99 }
100}
101
102impl AsRef<str> for ProtocolMut<'_> {
103 fn as_ref(&self) -> &str {
104 self.as_str()
105 }
106}
107
108impl fmt::Display for ProtocolMut<'_> {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 f.write_str(self.as_str())
111 }
112}
113
114impl fmt::Debug for ProtocolMut<'_> {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "{}", self)
117 }
118}
119
120#[repr(transparent)]
122#[derive(Copy, Clone, PartialEq, Eq, Hash)]
123pub struct Address<'a>(pub(super) &'a str);
124
125impl<'a> Address<'a> {
126 pub fn as_str(&self) -> &'a str {
127 self.0
128 }
129}
130
131impl AsRef<str> for Address<'_> {
132 fn as_ref(&self) -> &str {
133 self.as_str()
134 }
135}
136
137impl fmt::Display for Address<'_> {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 f.write_str(self.as_str())
140 }
141}
142
143impl fmt::Debug for Address<'_> {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "{}", self)
146 }
147}
148
149#[repr(transparent)]
150#[derive(PartialEq, Eq, Hash)]
151pub struct AddressMut<'a>(&'a mut EndPoint);
152
153impl<'a> AddressMut<'a> {
154 pub fn as_str(&'a self) -> &'a str {
155 address(self.0.as_str())
156 }
157
158 pub fn set(&'a mut self, a: &str) -> ZResult<()> {
159 let ep = EndPoint::new(self.0.protocol(), a, self.0.metadata(), self.0.config())?;
160
161 self.0.inner = ep.inner;
162 Ok(())
163 }
164}
165
166impl AsRef<str> for AddressMut<'_> {
167 fn as_ref(&self) -> &str {
168 self.as_str()
169 }
170}
171
172impl fmt::Display for AddressMut<'_> {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.write_str(self.as_str())
175 }
176}
177
178impl fmt::Debug for AddressMut<'_> {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 write!(f, "{}", self)
181 }
182}
183
184#[repr(transparent)]
186#[derive(Copy, Clone, PartialEq, Eq, Hash)]
187pub struct Metadata<'a>(pub(super) &'a str);
188
189impl<'a> Metadata<'a> {
190 pub const RELIABILITY: &'static str = "rel";
191 pub const PRIORITIES: &'static str = "prio";
192
193 pub fn as_str(&self) -> &'a str {
194 self.0
195 }
196
197 pub fn is_empty(&'a self) -> bool {
198 self.as_str().is_empty()
199 }
200
201 pub fn iter(&'a self) -> impl DoubleEndedIterator<Item = (&'a str, &'a str)> + Clone {
202 parameters::iter(self.0)
203 }
204
205 pub fn get(&'a self, k: &str) -> Option<&'a str> {
206 parameters::get(self.0, k)
207 }
208
209 pub fn values(&'a self, k: &str) -> impl DoubleEndedIterator<Item = &'a str> {
210 parameters::values(self.0, k)
211 }
212}
213
214impl AsRef<str> for Metadata<'_> {
215 fn as_ref(&self) -> &str {
216 self.as_str()
217 }
218}
219
220impl fmt::Display for Metadata<'_> {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 f.write_str(self.as_str())
223 }
224}
225
226impl fmt::Debug for Metadata<'_> {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 write!(f, "{}", self)
229 }
230}
231
232#[repr(transparent)]
233#[derive(PartialEq, Eq, Hash)]
234pub struct MetadataMut<'a>(&'a mut EndPoint);
235
236impl<'a> MetadataMut<'a> {
237 pub fn as_str(&'a self) -> &'a str {
238 metadata(self.0.as_str())
239 }
240
241 pub fn is_empty(&'a self) -> bool {
242 self.as_str().is_empty()
243 }
244}
245
246impl MetadataMut<'_> {
247 pub fn extend_from_iter<'s, I, K, V>(&mut self, iter: I) -> ZResult<()>
248 where
249 I: Iterator<Item = (&'s K, &'s V)> + Clone,
250 K: Borrow<str> + 's + ?Sized,
251 V: Borrow<str> + 's + ?Sized,
252 {
253 let ep = EndPoint::new(
254 self.0.protocol(),
255 self.0.address(),
256 parameters::from_iter(parameters::sort(parameters::join(
257 self.0.metadata().iter(),
258 iter.map(|(k, v)| (k.borrow(), v.borrow())),
259 ))),
260 self.0.config(),
261 )?;
262
263 self.0.inner = ep.inner;
264 Ok(())
265 }
266
267 pub fn insert<K, V>(&mut self, k: K, v: V) -> ZResult<()>
268 where
269 K: Borrow<str>,
270 V: Borrow<str>,
271 {
272 let ep = EndPoint::new(
273 self.0.protocol(),
274 self.0.address(),
275 parameters::insert_sort(self.0.metadata().as_str(), k.borrow(), v.borrow()).0,
276 self.0.config(),
277 )?;
278
279 self.0.inner = ep.inner;
280 Ok(())
281 }
282
283 pub fn remove<K>(&mut self, k: K) -> ZResult<()>
284 where
285 K: Borrow<str>,
286 {
287 let ep = EndPoint::new(
288 self.0.protocol(),
289 self.0.address(),
290 parameters::remove(self.0.metadata().as_str(), k.borrow()).0,
291 self.0.config(),
292 )?;
293
294 self.0.inner = ep.inner;
295 Ok(())
296 }
297}
298
299impl AsRef<str> for MetadataMut<'_> {
300 fn as_ref(&self) -> &str {
301 self.as_str()
302 }
303}
304
305impl fmt::Display for MetadataMut<'_> {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 f.write_str(self.as_str())
308 }
309}
310
311impl fmt::Debug for MetadataMut<'_> {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 write!(f, "{}", self)
314 }
315}
316
317#[repr(transparent)]
319#[derive(Copy, Clone, PartialEq, Eq, Hash)]
320pub struct Config<'a>(pub(super) &'a str);
321
322impl<'a> Config<'a> {
323 pub fn as_str(&self) -> &'a str {
324 self.0
325 }
326
327 pub fn is_empty(&'a self) -> bool {
328 self.as_str().is_empty()
329 }
330
331 pub fn iter(&'a self) -> impl DoubleEndedIterator<Item = (&'a str, &'a str)> + Clone {
332 parameters::iter(self.0)
333 }
334
335 pub fn get(&'a self, k: &str) -> Option<&'a str> {
336 parameters::get(self.0, k)
337 }
338
339 pub fn values(&'a self, k: &str) -> impl DoubleEndedIterator<Item = &'a str> {
340 parameters::values(self.0, k)
341 }
342}
343
344impl AsRef<str> for Config<'_> {
345 fn as_ref(&self) -> &str {
346 self.as_str()
347 }
348}
349
350impl fmt::Display for Config<'_> {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 f.write_str(self.as_str())
353 }
354}
355
356impl fmt::Debug for Config<'_> {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 write!(f, "{}", self)
359 }
360}
361
362#[repr(transparent)]
363#[derive(PartialEq, Eq, Hash)]
364pub struct ConfigMut<'a>(&'a mut EndPoint);
365
366impl<'a> ConfigMut<'a> {
367 pub fn as_str(&'a self) -> &'a str {
368 config(self.0.as_str())
369 }
370
371 pub fn is_empty(&'a self) -> bool {
372 self.as_str().is_empty()
373 }
374}
375
376impl ConfigMut<'_> {
377 pub fn extend_from_iter<'s, I, K, V>(&mut self, iter: I) -> ZResult<()>
378 where
379 I: Iterator<Item = (&'s K, &'s V)> + Clone,
380 K: Borrow<str> + 's + ?Sized,
381 V: Borrow<str> + 's + ?Sized,
382 {
383 let ep = EndPoint::new(
384 self.0.protocol(),
385 self.0.address(),
386 self.0.metadata(),
387 parameters::from_iter(parameters::sort(parameters::join(
388 self.0.config().iter(),
389 iter.map(|(k, v)| (k.borrow(), v.borrow())),
390 ))),
391 )?;
392
393 self.0.inner = ep.inner;
394 Ok(())
395 }
396
397 pub fn insert<K, V>(&mut self, k: K, v: V) -> ZResult<()>
398 where
399 K: Borrow<str>,
400 V: Borrow<str>,
401 {
402 let ep = EndPoint::new(
403 self.0.protocol(),
404 self.0.address(),
405 self.0.metadata(),
406 parameters::insert_sort(self.0.config().as_str(), k.borrow(), v.borrow()).0,
407 )?;
408
409 self.0.inner = ep.inner;
410 Ok(())
411 }
412
413 pub fn remove<K>(&mut self, k: K) -> ZResult<()>
414 where
415 K: Borrow<str>,
416 {
417 let ep = EndPoint::new(
418 self.0.protocol(),
419 self.0.address(),
420 self.0.metadata(),
421 parameters::remove(self.0.config().as_str(), k.borrow()).0,
422 )?;
423
424 self.0.inner = ep.inner;
425 Ok(())
426 }
427}
428
429impl AsRef<str> for ConfigMut<'_> {
430 fn as_ref(&self) -> &str {
431 self.as_str()
432 }
433}
434
435impl fmt::Display for ConfigMut<'_> {
436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 f.write_str(self.as_str())
438 }
439}
440
441impl fmt::Debug for ConfigMut<'_> {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 write!(f, "{}", self)
444 }
445}
446
447#[derive(Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
474#[serde(into = "String")]
475#[serde(try_from = "String")]
476pub struct EndPoint {
477 pub(super) inner: String,
478}
479
480impl EndPoint {
481 pub fn new<A, B, C, D>(protocol: A, address: B, metadata: C, config: D) -> ZResult<Self>
482 where
483 A: AsRef<str>,
484 B: AsRef<str>,
485 C: AsRef<str>,
486 D: AsRef<str>,
487 {
488 let p: &str = protocol.as_ref();
489 let a: &str = address.as_ref();
490 let m: &str = metadata.as_ref();
491 let c: &str = config.as_ref();
492
493 let len = p.len() + a.len() + m.len();
494 if len > u8::MAX as usize {
495 bail!("Endpoint too big: {} bytes. Max: {} bytes. ", len, u8::MAX);
496 }
497
498 let s = match (m.is_empty(), c.is_empty()) {
499 (true, true) => format!("{p}{PROTO_SEPARATOR}{a}"),
500 (false, true) => format!("{p}{PROTO_SEPARATOR}{a}{METADATA_SEPARATOR}{m}"),
501 (true, false) => format!("{p}{PROTO_SEPARATOR}{a}{CONFIG_SEPARATOR}{c}"),
502 (false, false) => {
503 format!("{p}{PROTO_SEPARATOR}{a}{METADATA_SEPARATOR}{m}{CONFIG_SEPARATOR}{c}")
504 }
505 };
506
507 Self::try_from(s)
508 }
509
510 pub fn as_str(&self) -> &str {
511 self.inner.as_str()
512 }
513
514 pub fn split(&self) -> (Protocol, Address, Metadata, Config) {
515 (
516 self.protocol(),
517 self.address(),
518 self.metadata(),
519 self.config(),
520 )
521 }
522
523 pub fn protocol(&self) -> Protocol {
524 Protocol(protocol(self.inner.as_str()))
525 }
526
527 pub fn protocol_mut(&mut self) -> ProtocolMut {
528 ProtocolMut(self)
529 }
530
531 pub fn address(&self) -> Address {
532 Address(address(self.inner.as_str()))
533 }
534
535 pub fn address_mut(&mut self) -> AddressMut {
536 AddressMut(self)
537 }
538
539 pub fn metadata(&self) -> Metadata {
540 Metadata(metadata(self.inner.as_str()))
541 }
542
543 pub fn metadata_mut(&mut self) -> MetadataMut {
544 MetadataMut(self)
545 }
546
547 pub fn config(&self) -> Config {
548 Config(config(self.inner.as_str()))
549 }
550
551 pub fn config_mut(&mut self) -> ConfigMut {
552 ConfigMut(self)
553 }
554
555 pub fn to_locator(&self) -> Locator {
556 self.clone().into()
557 }
558}
559
560impl From<Locator> for EndPoint {
561 fn from(val: Locator) -> Self {
562 val.0
563 }
564}
565
566impl fmt::Display for EndPoint {
567 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568 f.write_str(&self.inner)
569 }
570}
571
572impl fmt::Debug for EndPoint {
573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574 write!(f, "{}", self)
575 }
576}
577
578impl From<EndPoint> for String {
579 fn from(v: EndPoint) -> String {
580 v.inner
581 }
582}
583
584impl TryFrom<String> for EndPoint {
585 type Error = ZError;
586
587 fn try_from(s: String) -> Result<Self, Self::Error> {
588 const ERR: &str =
589 "Endpoints must be of the form <protocol>/<address>[?<metadata>][#<config>]";
590
591 let pidx = s
592 .find(PROTO_SEPARATOR)
593 .and_then(|i| (!s[..i].is_empty() && !s[i + 1..].is_empty()).then_some(i))
594 .ok_or_else(|| zerror!("{}: {}", ERR, s))?;
595
596 match (s.find(METADATA_SEPARATOR), s.find(CONFIG_SEPARATOR)) {
597 (None, None) => Ok(EndPoint { inner: s }),
599 (Some(midx), None) if midx > pidx && !s[midx + 1..].is_empty() => {
601 let mut inner = String::with_capacity(s.len());
602 inner.push_str(&s[..midx + 1]); parameters::from_iter_into(
604 parameters::sort(parameters::iter(&s[midx + 1..])),
605 &mut inner,
606 );
607 Ok(EndPoint { inner })
608 }
609 (None, Some(cidx)) if cidx > pidx && !s[cidx + 1..].is_empty() => {
611 let mut inner = String::with_capacity(s.len());
612 inner.push_str(&s[..cidx + 1]); parameters::from_iter_into(
614 parameters::sort(parameters::iter(&s[cidx + 1..])),
615 &mut inner,
616 );
617 Ok(EndPoint { inner })
618 }
619 (Some(midx), Some(cidx))
621 if midx > pidx
622 && cidx > midx
623 && !s[midx + 1..cidx].is_empty()
624 && !s[cidx + 1..].is_empty() =>
625 {
626 let mut inner = String::with_capacity(s.len());
627 inner.push_str(&s[..midx + 1]); parameters::from_iter_into(
630 parameters::sort(parameters::iter(&s[midx + 1..cidx])),
631 &mut inner,
632 );
633
634 inner.push(CONFIG_SEPARATOR);
635 parameters::from_iter_into(
636 parameters::sort(parameters::iter(&s[cidx + 1..])),
637 &mut inner,
638 );
639
640 Ok(EndPoint { inner })
641 }
642 _ => Err(zerror!("{}: {}", ERR, s).into()),
643 }
644 }
645}
646
647impl FromStr for EndPoint {
648 type Err = ZError;
649
650 fn from_str(s: &str) -> Result<Self, Self::Err> {
651 Self::try_from(s.to_owned())
652 }
653}
654
655impl EndPoint {
656 #[cfg(feature = "test")]
657 pub fn rand() -> Self {
658 use rand::{
659 distributions::{Alphanumeric, DistString},
660 Rng,
661 };
662
663 const MIN: usize = 2;
664 const MAX: usize = 8;
665
666 let mut rng = rand::thread_rng();
667 let mut endpoint = String::new();
668
669 let len = rng.gen_range(MIN..MAX);
670 let proto = Alphanumeric.sample_string(&mut rng, len);
671 endpoint.push_str(proto.as_str());
672
673 endpoint.push(PROTO_SEPARATOR);
674
675 let len = rng.gen_range(MIN..MAX);
676 let address = Alphanumeric.sample_string(&mut rng, len);
677 endpoint.push_str(address.as_str());
678
679 if rng.gen_bool(0.5) {
680 endpoint.push(METADATA_SEPARATOR);
681 parameters::rand(&mut endpoint);
682 }
683 if rng.gen_bool(0.5) {
684 endpoint.push(CONFIG_SEPARATOR);
685 parameters::rand(&mut endpoint);
686 }
687
688 endpoint.parse().unwrap()
689 }
690}
691
692#[test]
693fn endpoints() {
694 assert!(EndPoint::from_str("/").is_err());
695 assert!(EndPoint::from_str("?").is_err());
696 assert!(EndPoint::from_str("#").is_err());
697
698 assert!(EndPoint::from_str("udp").is_err());
699 assert!(EndPoint::from_str("/udp").is_err());
700 assert!(EndPoint::from_str("udp/").is_err());
701
702 assert!(EndPoint::from_str("udp/127.0.0.1:7447?").is_err());
703 assert!(EndPoint::from_str("udp?127.0.0.1:7447").is_err());
704 assert!(EndPoint::from_str("udp?127.0.0.1:7447/meta").is_err());
705
706 assert!(EndPoint::from_str("udp/127.0.0.1:7447#").is_err());
707 assert!(EndPoint::from_str("udp/127.0.0.1:7447?#").is_err());
708 assert!(EndPoint::from_str("udp/127.0.0.1:7447#?").is_err());
709 assert!(EndPoint::from_str("udp#127.0.0.1:7447/").is_err());
710 assert!(EndPoint::from_str("udp#127.0.0.1:7447/?").is_err());
711 assert!(EndPoint::from_str("udp/127.0.0.1:7447?a=1#").is_err());
712
713 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447").unwrap();
714 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447");
715 assert_eq!(endpoint.protocol().as_str(), "udp");
716 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
717 assert!(endpoint.metadata().as_str().is_empty());
718 assert_eq!(endpoint.metadata().iter().count(), 0);
719
720 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447?a=1;b=2").unwrap();
721 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2");
722 assert_eq!(endpoint.protocol().as_str(), "udp");
723 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
724 assert_eq!(endpoint.metadata().as_str(), "a=1;b=2");
725 assert_eq!(endpoint.metadata().iter().count(), 2);
726 endpoint
727 .metadata()
728 .iter()
729 .find(|x| x == &("a", "1"))
730 .unwrap();
731 assert_eq!(endpoint.metadata().get("a"), Some("1"));
732 endpoint
733 .metadata()
734 .iter()
735 .find(|x| x == &("b", "2"))
736 .unwrap();
737 assert_eq!(endpoint.metadata().get("b"), Some("2"));
738 assert!(endpoint.config().as_str().is_empty());
739 assert_eq!(endpoint.config().iter().count(), 0);
740
741 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447?b=2;a=1").unwrap();
742 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2");
743 assert_eq!(endpoint.protocol().as_str(), "udp");
744 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
745 assert_eq!(endpoint.metadata().as_str(), "a=1;b=2");
746 assert_eq!(endpoint.metadata().iter().count(), 2);
747 endpoint
748 .metadata()
749 .iter()
750 .find(|x| x == &("a", "1"))
751 .unwrap();
752 assert_eq!(endpoint.metadata().get("a"), Some("1"));
753 endpoint
754 .metadata()
755 .iter()
756 .find(|x| x == &("b", "2"))
757 .unwrap();
758 assert_eq!(endpoint.metadata().get("a"), Some("1"));
759 assert!(endpoint.config().as_str().is_empty());
760 assert_eq!(endpoint.config().iter().count(), 0);
761
762 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447#A=1;B=2").unwrap();
763 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447#A=1;B=2");
764 assert_eq!(endpoint.protocol().as_str(), "udp");
765 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
766 assert!(endpoint.metadata().as_str().is_empty());
767 assert_eq!(endpoint.metadata().iter().count(), 0);
768 assert_eq!(endpoint.config().as_str(), "A=1;B=2");
769 assert_eq!(endpoint.config().iter().count(), 2);
770 endpoint.config().iter().find(|x| x == &("A", "1")).unwrap();
771 assert_eq!(endpoint.config().get("A"), Some("1"));
772 endpoint.config().iter().find(|x| x == &("B", "2")).unwrap();
773 assert_eq!(endpoint.config().get("B"), Some("2"));
774
775 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447#B=2;A=1").unwrap();
776 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447#A=1;B=2");
777 assert_eq!(endpoint.protocol().as_str(), "udp");
778 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
779 assert!(endpoint.metadata().as_str().is_empty());
780 assert_eq!(endpoint.metadata().iter().count(), 0);
781 assert_eq!(endpoint.config().as_str(), "A=1;B=2");
782 assert_eq!(endpoint.config().iter().count(), 2);
783 endpoint.config().iter().find(|x| x == &("A", "1")).unwrap();
784 assert_eq!(endpoint.config().get("A"), Some("1"));
785 endpoint.config().iter().find(|x| x == &("B", "2")).unwrap();
786 assert_eq!(endpoint.config().get("B"), Some("2"));
787
788 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447?a=1;b=2#A=1;B=2").unwrap();
789 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2#A=1;B=2");
790 assert_eq!(endpoint.protocol().as_str(), "udp");
791 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
792 assert_eq!(endpoint.metadata().as_str(), "a=1;b=2");
793 assert_eq!(endpoint.metadata().iter().count(), 2);
794 endpoint
795 .metadata()
796 .iter()
797 .find(|x| x == &("a", "1"))
798 .unwrap();
799 assert_eq!(endpoint.metadata().get("a"), Some("1"));
800 endpoint
801 .metadata()
802 .iter()
803 .find(|x| x == &("b", "2"))
804 .unwrap();
805 assert_eq!(endpoint.metadata().get("b"), Some("2"));
806 assert_eq!(endpoint.config().as_str(), "A=1;B=2");
807 assert_eq!(endpoint.config().iter().count(), 2);
808 endpoint.config().iter().find(|x| x == &("A", "1")).unwrap();
809 assert_eq!(endpoint.config().get("A"), Some("1"));
810 endpoint.config().iter().find(|x| x == &("B", "2")).unwrap();
811 assert_eq!(endpoint.config().get("B"), Some("2"));
812
813 let endpoint = EndPoint::from_str("udp/127.0.0.1:7447?b=2;a=1#B=2;A=1").unwrap();
814 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2#A=1;B=2");
815 assert_eq!(endpoint.protocol().as_str(), "udp");
816 assert_eq!(endpoint.address().as_str(), "127.0.0.1:7447");
817 assert_eq!(endpoint.metadata().as_str(), "a=1;b=2");
818 assert_eq!(endpoint.metadata().iter().count(), 2);
819 endpoint
820 .metadata()
821 .iter()
822 .find(|x| x == &("a", "1"))
823 .unwrap();
824 assert_eq!(endpoint.metadata().get("a"), Some("1"));
825 endpoint
826 .metadata()
827 .iter()
828 .find(|x| x == &("b", "2"))
829 .unwrap();
830 assert_eq!(endpoint.metadata().get("b"), Some("2"));
831 assert_eq!(endpoint.config().as_str(), "A=1;B=2");
832 assert_eq!(endpoint.config().iter().count(), 2);
833 endpoint.config().iter().find(|x| x == &("A", "1")).unwrap();
834 assert_eq!(endpoint.config().get("A"), Some("1"));
835 endpoint.config().iter().find(|x| x == &("B", "2")).unwrap();
836 assert_eq!(endpoint.config().get("B"), Some("2"));
837
838 let mut endpoint = EndPoint::from_str("udp/127.0.0.1:7447?a=1;b=2").unwrap();
839 endpoint.metadata_mut().insert("c", "3").unwrap();
840 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2;c=3");
841
842 let mut endpoint = EndPoint::from_str("udp/127.0.0.1:7447?b=2;c=3").unwrap();
843 endpoint.metadata_mut().insert("a", "1").unwrap();
844 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2;c=3");
845
846 let mut endpoint = EndPoint::from_str("udp/127.0.0.1:7447?a=1;b=2").unwrap();
847 endpoint.config_mut().insert("A", "1").unwrap();
848 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2#A=1");
849
850 let mut endpoint = EndPoint::from_str("udp/127.0.0.1:7447?b=2;c=3#B=2").unwrap();
851 endpoint.config_mut().insert("A", "1").unwrap();
852 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?b=2;c=3#A=1;B=2");
853
854 let mut endpoint = EndPoint::from_str("udp/127.0.0.1:7447").unwrap();
855 endpoint
856 .metadata_mut()
857 .extend_from_iter([("a", "1"), ("c", "3"), ("b", "2")].iter().copied())
858 .unwrap();
859 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447?a=1;b=2;c=3");
860
861 let mut endpoint = EndPoint::from_str("udp/127.0.0.1:7447").unwrap();
862 endpoint
863 .config_mut()
864 .extend_from_iter([("A", "1"), ("C", "3"), ("B", "2")].iter().copied())
865 .unwrap();
866 assert_eq!(endpoint.as_str(), "udp/127.0.0.1:7447#A=1;B=2;C=3");
867
868 let endpoint =
869 EndPoint::from_str("udp/127.0.0.1:7447#iface=en0;join=224.0.0.1|224.0.0.2|224.0.0.3")
870 .unwrap();
871 let c = endpoint.config();
872 assert_eq!(c.get("iface"), Some("en0"));
873 assert_eq!(c.get("join"), Some("224.0.0.1|224.0.0.2|224.0.0.3"));
874 assert_eq!(c.values("iface").count(), 1);
875 let mut i = c.values("iface");
876 assert_eq!(i.next(), Some("en0"));
877 assert_eq!(c.values("join").count(), 3);
878 let mut i = c.values("join");
879 assert_eq!(i.next(), Some("224.0.0.1"));
880 assert_eq!(i.next(), Some("224.0.0.2"));
881 assert_eq!(i.next(), Some("224.0.0.3"));
882 assert_eq!(i.next(), None);
883}