zenoh_protocol/core/
endpoint.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14use 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
21// Parsing chars
22pub const PROTO_SEPARATOR: char = '/';
23pub const METADATA_SEPARATOR: char = '?';
24pub const CONFIG_SEPARATOR: char = '#';
25
26// Parsing functions
27pub(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// Protocol
57#[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// Address
121#[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// Metadata
185#[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// Config
318#[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/// A string that respects the [`EndPoint`] canon form: `<locator>[#<config>]`.
448///
449/// `<locator>` is a valid [`Locator`] and `<config>` is of the form
450/// `<key1>=<value1>;...;<keyN>=<valueN>` where keys are alphabetically sorted. `<config>` is
451/// optional and can be provided to configure some aspects for an [`EndPoint`], e.g. the interface
452/// to listen on or connect to.
453///
454/// A full [`EndPoint`] string is hence in the form of `<proto>/<address>[?<metadata>][#config]`.
455///
456/// ## Metadata
457///
458/// - **`prio`**: a priority range bounded inclusively below and above (e.g. `2-4` signifies
459///   priorities 2, 3 and 4). This value is used to select the link used for transmission based on
460///   the Priority of the message in question.
461///
462///   For example, `tcp/localhost:7447?prio=1-3` assigns priorities
463///   [`crate::core::Priority::RealTime`], [`crate::core::Priority::InteractiveHigh`] and
464///   [`crate::core::Priority::InteractiveLow`] to the established link.
465///
466/// - **`rel`**: either "0" for [`crate::core::Reliability::BestEffort`] or "1" for
467///   [`crate::core::Reliability::Reliable`]. This value is used to select the link used for
468///   transmission based on the reliability of the message in question.
469///
470///   For example, `tcp/localhost:7447?prio=6-7;rel=0` assigns priorities
471///   [`crate::core::Priority::DataLow`] and [`crate::core::Priority::Background`], and
472///   [`crate::core::Reliability::BestEffort`] to the established link.
473#[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            // No metadata or config at all
598            (None, None) => Ok(EndPoint { inner: s }),
599            // There is some metadata
600            (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]); // Includes metadata separator
603                parameters::from_iter_into(
604                    parameters::sort(parameters::iter(&s[midx + 1..])),
605                    &mut inner,
606                );
607                Ok(EndPoint { inner })
608            }
609            // There is some config
610            (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]); // Includes config separator
613                parameters::from_iter_into(
614                    parameters::sort(parameters::iter(&s[cidx + 1..])),
615                    &mut inner,
616                );
617                Ok(EndPoint { inner })
618            }
619            // There is some metadata and some config
620            (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]); // Includes metadata separator
628
629                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}