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