Skip to main content

net_types/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Networking types and operations.
6//!
7//! This crate defines types and operations useful for operating with various
8//! network protocols. Some general utilities are defined in the crate root,
9//! while protocol-specific operations are defined in their own modules.
10//!
11//! # Witness types
12//!
13//! This crate makes heavy use of the "witness type" pattern. A witness type is
14//! one whose existence "bears witness" to a particular property. For example,
15//! the [`UnicastAddr`] type wraps an existing address and guarantees that it
16//! is unicast.
17//!
18//! There are a few components to a witness type.
19//!
20//! First, each property is encoded in a trait. For example, the
21//! [`UnicastAddress`] trait is implemented by any address type which can be
22//! unicast. The [`is_unicast`] method is used to determine whether a given
23//! instance is unicast.
24//!
25//! Second, a witness type wraps an address. For example, `UnicastAddr<A>` can
26//! be used with any `A: UnicastAddress`. There are two ways to obtain an
27//! instance of a witness type. Some constants are constructed as witness types
28//! at compile time, and so provide a static guarantee of the witnessed property
29//! (e.g., [`Ipv6::LOOPBACK_IPV6_ADDRESS`] is a `UnicastAddr`). Otherwise, an
30//! instance can be constructed fallibly at runtime. For example,
31//! [`UnicastAddr::new`] accepts an `A` and returns an `Option<UnicastAddr<A>>`,
32//! returning `Some` if the address passes the `is_unicast` check, and `None`
33//! otherwise.
34//!
35//! Finally, each witness type implements the [`Witness`] trait, which allows
36//! code to be written which is generic over which witness type is used.
37//!
38//! Witness types enable a variety of operations which are only valid on certain
39//! types of addresses. For example, a multicast MAC address can be derived from
40//! a multicast IPv6 address, so the `MulticastAddr<Mac>` type implements
41//! `From<MulticastAddr<Ipv6Addr>>`. Similarly, given an [`Ipv6Addr`], the
42//! [`to_solicited_node_address`] method can be used to construct the address's
43//! solicited-node address, which is a `MulticastAddr<Ipv6Addr>`. Combining
44//! these, it's possible to take an `Ipv6Addr` and compute the solicited node
45//! address's multicast MAC address without performing any runtime validation:
46//!
47//! ```rust
48//! # use net_types::ethernet::Mac;
49//! # use net_types::ip::Ipv6Addr;
50//! # use net_types::MulticastAddr;
51//! fn to_solicited_node_multicast_mac(addr: &Ipv6Addr) -> MulticastAddr<Mac> {
52//!     addr.to_solicited_node_address().into()
53//! }
54//! ```
55//!
56//! # Naming Conventions
57//!
58//! When both types and traits exist which represent the same concept, the
59//! traits will be given a full name - such as [`IpAddress`] or
60//! [`UnicastAddress`] - while the types will be given an abbreviated name -
61//! such as [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], or [`UnicastAddr`].
62//!
63//! [`is_unicast`]: crate::UnicastAddress::is_unicast
64//! [`Ipv6::LOOPBACK_IPV6_ADDRESS`]: crate::ip::Ipv6::LOOPBACK_IPV6_ADDRESS
65//! [`to_solicited_node_address`]: crate::ip::Ipv6Addr::to_solicited_node_address
66//! [`IpAddress`]: crate::ip::IpAddress
67//! [`IpAddr`]: crate::ip::IpAddr
68//! [`Ipv4Addr`]: crate::ip::Ipv4Addr
69//! [`Ipv6Addr`]: crate::ip::Ipv6Addr
70
71#![deny(missing_docs)]
72#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
73
74pub mod ethernet;
75pub mod ip;
76
77use core::fmt::{self, Debug, Display, Formatter};
78use core::ops::Deref;
79
80use crate::ip::{GenericOverIp, Ip, IpAddress, IpInvariant, IpVersionMarker};
81
82mod sealed {
83    // Used to ensure that certain traits cannot be implemented by anyone
84    // outside this crate, such as the Ip and IpAddress traits.
85    pub trait Sealed {}
86}
87
88/// A type which is a witness to some property about an address.
89///
90/// A type which implements `Witness<A>` wraps an address of type `A` and
91/// guarantees some property about the wrapped address. It is implemented by
92/// [`SpecifiedAddr`], [`UnicastAddr`], [`MulticastAddr`], [`LinkLocalAddr`],
93/// and [`NonMappedAddr`].
94pub trait Witness<A>: AsRef<A> + Sized + sealed::Sealed {
95    /// Constructs a new witness type.
96    ///
97    /// `new` returns `None` if `addr` does not satisfy the property guaranteed
98    /// by `Self`.
99    fn new(addr: A) -> Option<Self>;
100
101    /// Constructs a new witness type without checking to see if `addr` actually
102    /// satisfies the required property.
103    ///
104    /// # Safety
105    ///
106    /// It is up to the caller to make sure that `addr` satisfies the required
107    /// property in order to avoid breaking the guarantees of this trait.
108    unsafe fn new_unchecked(addr: A) -> Self;
109
110    /// Constructs a new witness type from an existing witness type.
111    ///
112    /// `from_witness(witness)` is equivalent to `new(witness.into_addr())`.
113    fn from_witness<W: Witness<A>>(addr: W) -> Option<Self> {
114        Self::new(addr.into_addr())
115    }
116
117    // In a previous version of this code, we did `fn get(self) -> A where Self:
118    // Copy` (taking `self` by value and using `where Self: Copy`). That felt
119    // marginally cleaner, but it turns out that there are cases in which the
120    // user only has access to a reference and still wants to be able to call
121    // `get` without having to do the ugly `(*addr).get()`.
122
123    /// Gets a copy of the address.
124    #[inline]
125    fn get(&self) -> A
126    where
127        A: Copy,
128    {
129        *self.as_ref()
130    }
131
132    /// Consumes this witness and returns the contained `A`.
133    ///
134    /// If `A: Copy`, prefer [`get`] instead of `into_addr`. `get` is idiomatic
135    /// for wrapper types which which wrap `Copy` types (e.g., see
136    /// [`NonZeroUsize::get`] or [`Cell::get`]). `into_xxx` methods are
137    /// idiomatic only when `self` must be consumed by value because the wrapped
138    /// value is not `Copy` (e.g., see [`Cell::into_inner`]).
139    ///
140    /// [`get`]: Witness::get
141    /// [`NonZeroUsize::get`]: core::num::NonZeroUsize::get
142    /// [`Cell::get`]: core::cell::Cell::get
143    /// [`Cell::into_inner`]: core::cell::Cell::into_inner
144    fn into_addr(self) -> A;
145
146    /// Transposes this witness type with another witness type layered inside of
147    /// it.
148    /// (e.g. UnicastAddr<SpecifiedAddr<T>> -> SpecifiedAddr<UnicastAddr<T>>)
149    fn transpose<T>(self) -> A::Map<Self::Map<T>>
150    where
151        Self: TransposableWitness<A>,
152        A: TransposableWitness<T>,
153        Self::Map<T>: Witness<T>,
154        A::Map<Self::Map<T>>: Witness<Self::Map<T>>,
155    {
156        let middle = self.into_addr();
157        let innermost = middle.into_addr();
158        unsafe {
159            // SAFETY: We're transposing two witness layers, so we know that the
160            // inner address upheld both invariants that are witnessed.
161            let new_middle = Self::Map::<T>::new_unchecked(innermost);
162            A::Map::<Self::Map<T>>::new_unchecked(new_middle)
163        }
164    }
165}
166
167/// Witness types that can be transposed with other witness wrapper types.
168// Technically, this could be merged directly into the `Witness` trait rather
169// than exist as a separate trait. However, this ends up impeding type
170// inference, as the trait solver gets confused by the existence of `Witness`
171// impls both for single wrapper layers (`SpecifiedAddr<T>` impls `Witness<T>`)
172// and for nested wrappers (`UnicastAddr<SpecifiedAddr<T>>` also impls
173// `Witness<T>`). Since `transpose` is most useful for swapping single-layer
174// `Witness` impls nested within each other, we only want to impl
175// `TransposableWitness` for one wrapper layer at a time, which allows type
176// inference to work properly.
177pub trait TransposableWitness<A>: Witness<A> {
178    /// Maps the type wrapped by this witness.
179    type Map<T>;
180}
181
182// NOTE: The "witness" types UnicastAddr, MulticastAddr, and LinkLocalAddr -
183// which provide the invariant that the value they contain is a unicast,
184// multicast, or link-local address, respectively - cannot actually guarantee
185// this property without certain promises from the implementations of the
186// UnicastAddress, MulticastAddress, and LinkLocalAddress traits that they rely
187// on. In particular, the values must be "immutable" in the sense that, given
188// only immutable references to the values, nothing about the values can change
189// such that the "unicast-ness", "multicast-ness" or "link-local-ness" of the
190// values change. Since the UnicastAddress, MulticastAddress, and
191// LinkLocalAddress traits are not unsafe traits, it would be unsound for unsafe
192// code to rely for its soundness on this behavior. For a more in-depth
193// discussion of why this isn't possible without an explicit opt-in on the part
194// of the trait implementor, see this forum thread:
195// https://users.rust-lang.org/t/prevent-interior-mutability/29403
196
197/// Implements a trait for a witness type.
198///
199/// `impl_trait_for_witness` implements `$trait` for `$witness<A>` if `A:
200/// $trait`.
201macro_rules! impl_trait_for_witness {
202    ($trait:ident, $method:ident, $witness:ident) => {
203        impl<A: $trait> $trait for $witness<A> {
204            fn $method(&self) -> bool {
205                self.0.$method()
206            }
207        }
208    };
209}
210
211/// Implements a trait with an associated type for a witness type.
212///
213/// `impl_trait_with_associated_type_for_witness` implements `$trait` with
214/// associated type `$type` for `$witness<A>` if `A: $trait`.
215macro_rules! impl_trait_with_associated_type_for_witness {
216    ($trait:ident, $method:ident, $type:ident, $witness:ident) => {
217        impl<A: $trait> $trait for $witness<A> {
218            type $type = A::$type;
219            fn $method(&self) -> Self::$type {
220                self.0.$method()
221            }
222        }
223    };
224}
225
226/// Addresses that can be specified.
227///
228/// `SpecifiedAddress` is implemented by address types for which some values are
229/// considered [unspecified] addresses. Unspecified addresses are usually not
230/// legal to be used in actual network traffic, and are only meant to represent
231/// the lack of any defined address. The exact meaning of the unspecified
232/// address often varies by context. For example, the IPv4 address 0.0.0.0 and
233/// the IPv6 address :: can be used, in the context of creating a listening
234/// socket on systems that use the BSD sockets API, to listen on all local IP
235/// addresses rather than a particular one.
236///
237/// [unspecified]: https://en.wikipedia.org/wiki/0.0.0.0
238pub trait SpecifiedAddress {
239    /// Is this a specified address?
240    ///
241    /// `is_specified` must maintain the invariant that, if it is called twice
242    /// on the same object, and in between those two calls, no code has operated
243    /// on a mutable reference to that object, both calls will return the same
244    /// value. This property is required in order to implement
245    /// [`SpecifiedAddr`]. Note that, since this is not an `unsafe` trait,
246    /// `unsafe` code may NOT rely on this property for its soundness. However,
247    /// code MAY rely on this property for its correctness.
248    fn is_specified(&self) -> bool;
249}
250
251impl_trait_for_witness!(SpecifiedAddress, is_specified, UnicastAddr);
252impl_trait_for_witness!(SpecifiedAddress, is_specified, MulticastAddr);
253impl_trait_for_witness!(SpecifiedAddress, is_specified, BroadcastAddr);
254impl_trait_for_witness!(SpecifiedAddress, is_specified, LinkLocalAddr);
255impl_trait_for_witness!(SpecifiedAddress, is_specified, NonMappedAddr);
256
257/// Addresses that can be unicast.
258///
259/// `UnicastAddress` is implemented by address types for which some values are
260/// considered [unicast] addresses. Unicast addresses are used to identify a
261/// single network node, as opposed to broadcast and multicast addresses, which
262/// identify a group of nodes.
263///
264/// `UnicastAddress` is only implemented for addresses whose unicast-ness can be
265/// determined by looking only at the address itself (this is notably not true
266/// for IPv4 addresses, which can be considered broadcast addresses depending on
267/// the subnet in which they are used).
268///
269/// [unicast]: https://en.wikipedia.org/wiki/Unicast
270pub trait UnicastAddress {
271    /// Is this a unicast address?
272    ///
273    /// `is_unicast` must maintain the invariant that, if it is called twice on
274    /// the same object, and in between those two calls, no code has operated on
275    /// a mutable reference to that object, both calls will return the same
276    /// value. This property is required in order to implement [`UnicastAddr`].
277    /// Note that, since this is not an `unsafe` trait, `unsafe` code may NOT
278    /// rely on this property for its soundness. However, code MAY rely on this
279    /// property for its correctness.
280    ///
281    /// If this type also implements [`SpecifiedAddress`], then `a.is_unicast()`
282    /// implies `a.is_specified()`.
283    fn is_unicast(&self) -> bool;
284}
285
286impl_trait_for_witness!(UnicastAddress, is_unicast, SpecifiedAddr);
287impl_trait_for_witness!(UnicastAddress, is_unicast, MulticastAddr);
288impl_trait_for_witness!(UnicastAddress, is_unicast, BroadcastAddr);
289impl_trait_for_witness!(UnicastAddress, is_unicast, LinkLocalAddr);
290impl_trait_for_witness!(UnicastAddress, is_unicast, NonMappedAddr);
291
292/// Addresses that can be multicast.
293///
294/// `MulticastAddress` is implemented by address types for which some values are
295/// considered [multicast] addresses. Multicast addresses are used to identify a
296/// group of multiple network nodes, as opposed to unicast addresses, which
297/// identify a single node, or broadcast addresses, which identify all the nodes
298/// in some region of a network.
299///
300/// [multicast]: https://en.wikipedia.org/wiki/Multicast
301pub trait MulticastAddress {
302    /// Is this a multicast address?
303    ///
304    /// `is_multicast` must maintain the invariant that, if it is called twice
305    /// on the same object, and in between those two calls, no code has operated
306    /// on a mutable reference to that object, both calls will return the same
307    /// value. This property is required in order to implement
308    /// [`MulticastAddr`]. Note that, since this is not an `unsafe` trait,
309    /// `unsafe` code may NOT rely on this property for its soundness. However,
310    /// code MAY rely on this property for its correctness.
311    ///
312    /// If this type also implements [`SpecifiedAddress`], then
313    /// `a.is_multicast()` implies `a.is_specified()`.
314    fn is_multicast(&self) -> bool;
315
316    /// Is this a non-multicast address? The inverse of `is_multicast()`.
317    fn is_non_multicast(&self) -> bool {
318        !self.is_multicast()
319    }
320}
321
322impl_trait_for_witness!(MulticastAddress, is_multicast, SpecifiedAddr);
323impl_trait_for_witness!(MulticastAddress, is_multicast, UnicastAddr);
324impl_trait_for_witness!(MulticastAddress, is_multicast, BroadcastAddr);
325impl_trait_for_witness!(MulticastAddress, is_multicast, LinkLocalAddr);
326impl_trait_for_witness!(MulticastAddress, is_multicast, NonMappedAddr);
327
328/// Addresses that can be broadcast.
329///
330/// `BroadcastAddress` is implemented by address types for which some values are
331/// considered [broadcast] addresses. Broadcast addresses are used to identify
332/// all the nodes in some region of a network, as opposed to unicast addresses,
333/// which identify a single node, or multicast addresses, which identify a group
334/// of nodes (not necessarily all of them).
335///
336/// [broadcast]: https://en.wikipedia.org/wiki/Broadcasting_(networking)
337pub trait BroadcastAddress {
338    /// Is this a broadcast address?
339    ///
340    /// If this type also implements [`SpecifiedAddress`], then
341    /// `a.is_broadcast()` implies `a.is_specified()`.
342    fn is_broadcast(&self) -> bool;
343}
344
345impl_trait_for_witness!(BroadcastAddress, is_broadcast, SpecifiedAddr);
346impl_trait_for_witness!(BroadcastAddress, is_broadcast, UnicastAddr);
347impl_trait_for_witness!(BroadcastAddress, is_broadcast, MulticastAddr);
348impl_trait_for_witness!(BroadcastAddress, is_broadcast, LinkLocalAddr);
349impl_trait_for_witness!(BroadcastAddress, is_broadcast, NonMappedAddr);
350
351/// Addresses that can be a link-local.
352///
353/// `LinkLocalAddress` is implemented by address types for which some values are
354/// considered [link-local] addresses. Link-local addresses are used for
355/// communication within a network segment, as opposed to global/public
356/// addresses which may be used for communication across networks.
357///
358/// `LinkLocalAddress` is only implemented for addresses whose link-local-ness
359/// can be determined by looking only at the address itself.
360///
361/// [link-local]: https://en.wikipedia.org/wiki/Link-local_address
362pub trait LinkLocalAddress {
363    /// Is this a link-local address?
364    ///
365    /// `is_link_local` must maintain the invariant that, if it is called twice
366    /// on the same object, and in between those two calls, no code has operated
367    /// on a mutable reference to that object, both calls will return the same
368    /// value. This property is required in order to implement
369    /// [`LinkLocalAddr`]. Note that, since this is not an `unsafe` trait,
370    /// `unsafe` code may NOT rely on this property for its soundness. However,
371    /// code MAY rely on this property for its correctness.
372    ///
373    /// If this type also implements [`SpecifiedAddress`], then
374    /// `a.is_link_local()` implies `a.is_specified()`.
375    fn is_link_local(&self) -> bool;
376}
377
378impl_trait_for_witness!(LinkLocalAddress, is_link_local, SpecifiedAddr);
379impl_trait_for_witness!(LinkLocalAddress, is_link_local, UnicastAddr);
380impl_trait_for_witness!(LinkLocalAddress, is_link_local, MulticastAddr);
381impl_trait_for_witness!(LinkLocalAddress, is_link_local, BroadcastAddr);
382impl_trait_for_witness!(LinkLocalAddress, is_link_local, NonMappedAddr);
383
384/// A scope used by [`ScopeableAddress`]. See that trait's documentation for
385/// more information.
386///
387/// `Scope` is implemented for `()`. No addresses with the `()` scope can ever
388/// have an associated zone (in other words, `().can_have_zone()` always returns
389/// `false`).
390pub trait Scope {
391    /// Can addresses in this scope have an associated zone?
392    fn can_have_zone(&self) -> bool;
393}
394
395impl Scope for () {
396    fn can_have_zone(&self) -> bool {
397        false
398    }
399}
400
401/// An address that can be tied to some scope identifier.
402///
403/// `ScopeableAddress` is implemented by address types for which some values can
404/// have extra scoping information attached. Notably, some IPv6 addresses
405/// belonging to a particular scope class require extra metadata to identify the
406/// scope identifier or "zone". The zone is typically the networking interface
407/// identifier.
408///
409/// Address types which are never in any identified scope may still implement
410/// `ScopeableAddress` by setting the associated `Scope` type to `()`, which has
411/// the effect of ensuring that a zone can never be associated with an address
412/// (since the implementation of [`Scope::can_have_zone`] for `()` always
413/// returns `false`).
414pub trait ScopeableAddress {
415    /// The type of all non-global scopes.
416    type Scope: Scope;
417
418    /// The scope of this address.
419    ///
420    /// `scope` must maintain the invariant that, if it is called twice on the
421    /// same object, and in between those two calls, no code has operated on a
422    /// mutable reference to that object, both calls will return the same value.
423    /// This property is required in order to implement [`AddrAndZone`]. Note
424    /// that, since this is not an `unsafe` trait, `unsafe` code may NOT rely on
425    /// this property for its soundness. However, code MAY rely on this property
426    /// for its correctness.
427    ///
428    /// If this type also implements [`SpecifiedAddress`] then
429    /// `a.scope().can_have_zone()` implies `a.is_specified()`, since
430    /// unspecified addresses are always global, and the global scope cannot
431    /// have a zone.
432    fn scope(&self) -> Self::Scope;
433}
434
435impl_trait_with_associated_type_for_witness!(ScopeableAddress, scope, Scope, SpecifiedAddr);
436impl_trait_with_associated_type_for_witness!(ScopeableAddress, scope, Scope, UnicastAddr);
437impl_trait_with_associated_type_for_witness!(ScopeableAddress, scope, Scope, MulticastAddr);
438impl_trait_with_associated_type_for_witness!(ScopeableAddress, scope, Scope, BroadcastAddr);
439impl_trait_with_associated_type_for_witness!(ScopeableAddress, scope, Scope, LinkLocalAddr);
440impl_trait_with_associated_type_for_witness!(ScopeableAddress, scope, Scope, NonMappedAddr);
441
442/// An address that may represent an address from another addressing scheme.
443///
444/// `MappedAddress` is implemented by address types that can map another
445/// addressing scheme. Notably, IPv6 addresses, which may represent an IPv4
446/// address using the IPv4-mapped-Ipv6 subnet (e.g. ::FFFF:0:0/96).
447///
448/// Address types which cannot be used to represent another addressing scheme
449/// can still implement `MappedAddress` by treating all addresses as
450/// non-mapped.
451pub trait MappedAddress {
452    /// Is this a non-mapped address?
453    fn is_non_mapped(&self) -> bool;
454}
455
456impl_trait_for_witness!(MappedAddress, is_non_mapped, SpecifiedAddr);
457impl_trait_for_witness!(MappedAddress, is_non_mapped, UnicastAddr);
458impl_trait_for_witness!(MappedAddress, is_non_mapped, MulticastAddr);
459impl_trait_for_witness!(MappedAddress, is_non_mapped, BroadcastAddr);
460impl_trait_for_witness!(MappedAddress, is_non_mapped, LinkLocalAddr);
461
462macro_rules! doc_comment {
463    ($x:expr, $($tt:tt)*) => {
464        #[doc = $x]
465        $($tt)*
466    };
467}
468
469/// Define a witness type and implement methods and traits for it.
470///
471/// - `$type` is the type's name
472/// - `$adj` is a string literal representing the adjective used to describe
473///   addresses of this type for documentation purposes (e.g., "specified",
474///   "unicast", etc)
475/// - `$trait` is the name of the trait associated with the property to be
476///   witnessed
477/// - `$method` is the method on `$trait` which determines whether the property
478///   holds (e.g., `is_specified`)
479macro_rules! impl_witness {
480    ($type:ident, $adj:literal, $trait:ident, $method:ident) => {
481        doc_comment! {
482        concat!("An address which is guaranteed to be ", $adj, ".
483
484`", stringify!($type), "` wraps an address of type `A` and guarantees that it is
485a ", $adj, " address. Note that this guarantee is contingent on a correct
486implementation of the [`", stringify!($trait), "`] trait. Since that trait is
487not `unsafe`, `unsafe` code may NOT rely on this guarantee for its soundness."),
488            #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
489            pub struct $type<A>(A);
490        }
491
492        impl<A: $trait> $type<A> {
493            // NOTE(joshlf): It may seem odd to include `new` and `from_witness`
494            // constructors here when they already exists on the `Witness`
495            // trait, which this type implements. The reason we do this is that,
496            // since many of these types implement the `Witness` trait multiple
497            // times (e.g., `Witness<A> for LinkLocalAddr<A>` and `Witness<A>
498            // for LinkLocalAddr<MulticastAddr<A>`), if we didn't provide these
499            // constructors, callers invoking `Foo::new` or `Foo::from_witness`
500            // would need to `use` the `Witness` trait, and the compiler often
501            // doesn't have enough information to figure out which `Witness`
502            // implementation is meant in a given situation. This, in turn,
503            // requires a lot of boilerplate type annotations on the part of
504            // users. Providing these constructors helps alleviate this problem.
505
506            doc_comment! {
507                concat!("Constructs a new `", stringify!($type), "`.
508
509`new` returns `None` if `!addr.", stringify!($method), "()`."),
510                #[inline]
511                pub fn new(addr: A) -> Option<$type<A>> {
512                    if !addr.$method() {
513                        return None;
514                    }
515                    Some($type(addr))
516                }
517            }
518
519            doc_comment! {
520                concat!("Constructs a new `", stringify!($type), "` from a
521witness type.
522
523`from_witness(witness)` is equivalent to `new(witness.into_addr())`."),
524                pub fn from_witness<W: Witness<A>>(addr: W) -> Option<$type<A>> {
525                    $type::new(addr.into_addr())
526                }
527            }
528        }
529
530        // TODO(https://github.com/rust-lang/rust/issues/57563): Once traits
531        // other than `Sized` are supported for const fns, move this into the
532        // block with the `A: $trait` bound.
533        impl<A> $type<A> {
534            #[doc = concat!("Constructs a new `", stringify!($type), "` without
535checking to see if `addr` is actually ", $adj, ".")]
536            ///
537            /// # Safety
538            ///
539            #[doc = concat!("It is up to the caller to make sure that `addr`
540is ", $adj, " to avoid breaking the guarantees of `", stringify!($type), "`.
541See [`", stringify!($type), "`] for more details.")]
542            pub const unsafe fn new_unchecked(addr: A) -> $type<A> {
543                $type(addr)
544            }
545        }
546
547        impl<A> sealed::Sealed for $type<A> {}
548        impl<A: $trait> Witness<A> for $type<A> {
549            fn new(addr: A) -> Option<$type<A>> {
550                $type::new(addr)
551            }
552
553            unsafe fn new_unchecked(addr: A) -> $type<A> {
554                $type(addr)
555            }
556
557            #[inline]
558            fn into_addr(self) -> A {
559                self.0
560            }
561        }
562
563        impl<A: $trait> TransposableWitness<A> for $type<A> {
564            type Map<T> = $type<T>;
565        }
566
567        impl<A: $trait> AsRef<$type<A>> for $type<A> {
568            fn as_ref(&self) -> &$type<A> {
569                self
570            }
571        }
572
573        impl<A: $trait> AsRef<A> for $type<A> {
574            fn as_ref(&self) -> &A {
575                &self.0
576            }
577        }
578
579        impl<A: $trait> Deref for $type<A> {
580            type Target = A;
581
582            #[inline]
583            fn deref(&self) -> &A {
584                &self.0
585            }
586        }
587
588        impl<A: Display> Display for $type<A> {
589            #[inline]
590            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
591                self.0.fmt(f)
592            }
593        }
594
595        // Witness types help provide type safety for the compiler. The things
596        // they witness should be evident from seeing the contained type so we
597        // save some characters and offer a passthrough Debug impl.
598        impl<A: Debug> Debug for $type<A> {
599            #[inline]
600            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
601                self.0.fmt(f)
602            }
603        }
604    };
605}
606
607/// Implements an `into_specified` method on the witness type `$type`.
608///
609/// - `$trait` is the name of the trait associated with the witnessed property
610/// - `$method` is the method on `$trait` which determines whether the property
611///   holds (e.g., `is_unicast`)
612///
613/// An `into_specified` method is predicated on the witnessed property implying
614/// that the address is also specified (e.g., `UnicastAddress::is_unicast`
615/// implies `SpecifiedAddress::is_specified`).
616macro_rules! impl_into_specified {
617    ($type:ident, $trait:ident, $method:ident) => {
618        impl<A: $trait + SpecifiedAddress> $type<A> {
619            doc_comment! {
620                concat!("Converts this `", stringify!($type), "` into a
621[`SpecifiedAddr`].
622
623[`", stringify!($trait), "::", stringify!($method), "`] implies
624[`SpecifiedAddress::is_specified`], so all `", stringify!($type), "`s are
625guaranteed to be specified, so this conversion is infallible."),
626                #[inline]
627                pub fn into_specified(self) -> SpecifiedAddr<A> {
628                    SpecifiedAddr(self.0)
629                }
630            }
631        }
632
633        impl<A: $trait + SpecifiedAddress> From<$type<A>> for SpecifiedAddr<A> {
634            fn from(addr: $type<A>) -> SpecifiedAddr<A> {
635                addr.into_specified()
636            }
637        }
638    };
639}
640
641/// Implements [`Witness`] for a nested witness type.
642///
643/// Accepted Formats:
644/// * `impl_nested_witness!(trait1, type1, trait2, type2)`
645///     Implements `Witness<A>` for `type1<type2<A>>`.
646/// * `impl_nested_witness!(trait1, type1, trait2, type2, trait3, type3)`
647///     Implements `Witness<A>` for `type1<type2<type3<A>>>`.
648///
649/// Due to the nature of combinatorix, it is not advised to use this macro
650/// for all possible combinations of nested witnesses, only those that are
651/// actually instantiated in code.
652macro_rules! impl_nested_witness {
653    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident) => {
654        impl<A: $trait1 + $trait2> Witness<A> for $type1<$type2<A>> {
655            #[inline]
656            fn new(addr: A) -> Option<$type1<$type2<A>>> {
657                $type2::new(addr).and_then(Witness::<$type2<A>>::new)
658            }
659
660            unsafe fn new_unchecked(addr: A) -> $type1<$type2<A>> {
661                $type1($type2(addr))
662            }
663
664            #[inline]
665            fn into_addr(self) -> A {
666                self.0.into_addr()
667            }
668        }
669
670        impl<A: $trait1 + $trait2> AsRef<A> for $type1<$type2<A>> {
671            fn as_ref(&self) -> &A {
672                &self.0.0
673            }
674        }
675    };
676    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident, $trait3:ident, $type3:ident) => {
677        impl<A: $trait1 + $trait2 + $trait3> Witness<A> for $type1<$type2<$type3<A>>> {
678            #[inline]
679            fn new(addr: A) -> Option<$type1<$type2<$type3<A>>>> {
680                $type3::new(addr).and_then(Witness::<$type3<A>>::new)
681            }
682
683            unsafe fn new_unchecked(addr: A) -> $type1<$type2<$type3<A>>> {
684                $type1($type2($type3(addr)))
685            }
686
687            #[inline]
688            fn into_addr(self) -> A {
689                self.0.into_addr()
690            }
691        }
692
693        impl<A: $trait1 + $trait2 + $trait3> AsRef<A> for $type1<$type2<$type3<A>>> {
694            fn as_ref(&self) -> &A {
695                &self.0.0
696            }
697        }
698    };
699}
700
701/// Implements `From<T> or SpecifiedAddr<A>` where `T` is the nested witness.
702///
703/// Accepted Formats:
704/// * `impl_into_specified_for_nested_witness!(trait1, type1, trait2, type2)`
705///     Implements `From<type1<type2<A>>> for SpecifiedAddr<A>`.
706/// * `impl_nested_witness!(trait1, type1, trait2, type2, trait3, type3)`
707///     Implements `From<type1<type2<type3<<A>>>> for SpecifiedAddr<A>`.
708///
709/// Due to the nature of combinatorix, it is not advised to use this macro
710/// for all possible combinations of nested witnesses, only those that are
711/// actually instantiated in code.
712macro_rules! impl_into_specified_for_nested_witness {
713    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident) => {
714        impl<A: $trait1 + $trait2 + SpecifiedAddress> From<$type1<$type2<A>>> for SpecifiedAddr<A> {
715            fn from(addr: $type1<$type2<A>>) -> SpecifiedAddr<A> {
716                SpecifiedAddr(addr.into_addr())
717            }
718        }
719    };
720    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident, $trait3:ident, $type3:ident) => {
721        impl<A: $trait1 + $trait2 + $trait3 + SpecifiedAddress> From<$type1<$type2<$type3<A>>>>
722            for SpecifiedAddr<A>
723        {
724            fn from(addr: $type1<$type2<$type3<A>>>) -> SpecifiedAddr<A> {
725                SpecifiedAddr(addr.into_addr())
726            }
727        }
728    };
729}
730
731/// Implements `TryFrom<$from_ty<A>> for $into_ty<A>`
732macro_rules! impl_try_from_witness {
733    (@inner [$from_ty:ident: $from_trait:ident], [$into_ty:ident: $into_trait:ident]) => {
734        impl<A: $from_trait + $into_trait> TryFrom<$from_ty<A>> for $into_ty<A> {
735            type Error = ();
736            fn try_from(addr: $from_ty<A>) -> Result<$into_ty<A>, ()> {
737                Witness::<A>::from_witness(addr).ok_or(())
738            }
739        }
740    };
741    ([$from_ty:ident: $from_trait:ident], $([$into_ty:ident: $into_trait:ident]),*) => {
742        $(
743            impl_try_from_witness!(@inner [$from_ty: $from_trait], [$into_ty: $into_trait]);
744        )*
745    }
746}
747
748// SpecifiedAddr
749impl_witness!(SpecifiedAddr, "specified", SpecifiedAddress, is_specified);
750impl_try_from_witness!(
751    [SpecifiedAddr: SpecifiedAddress],
752    [UnicastAddr: UnicastAddress],
753    [MulticastAddr: MulticastAddress],
754    [BroadcastAddr: BroadcastAddress],
755    [LinkLocalAddr: LinkLocalAddress],
756    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
757    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
758    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
759    [NonMappedAddr: MappedAddress]
760);
761
762// UnicastAddr
763impl_witness!(UnicastAddr, "unicast", UnicastAddress, is_unicast);
764impl_into_specified!(UnicastAddr, UnicastAddress, is_unicast);
765impl_nested_witness!(UnicastAddress, UnicastAddr, LinkLocalAddress, LinkLocalAddr);
766impl_nested_witness!(UnicastAddress, UnicastAddr, MappedAddress, NonMappedAddr);
767impl_into_specified_for_nested_witness!(
768    UnicastAddress,
769    UnicastAddr,
770    LinkLocalAddress,
771    LinkLocalAddr
772);
773impl_into_specified_for_nested_witness!(UnicastAddress, UnicastAddr, MappedAddress, NonMappedAddr);
774impl_try_from_witness!(
775    [UnicastAddr: UnicastAddress],
776    [MulticastAddr: MulticastAddress],
777    [BroadcastAddr: BroadcastAddress],
778    [LinkLocalAddr: LinkLocalAddress],
779    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
780    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
781    [NonMappedAddr: MappedAddress]
782);
783
784// MulticastAddr
785impl_witness!(MulticastAddr, "multicast", MulticastAddress, is_multicast);
786impl_into_specified!(MulticastAddr, MulticastAddress, is_multicast);
787impl_nested_witness!(MulticastAddress, MulticastAddr, LinkLocalAddress, LinkLocalAddr);
788impl_nested_witness!(MulticastAddress, MulticastAddr, MappedAddress, NonMappedAddr);
789impl_into_specified_for_nested_witness!(
790    MulticastAddress,
791    MulticastAddr,
792    LinkLocalAddress,
793    LinkLocalAddr
794);
795impl_into_specified_for_nested_witness!(
796    MulticastAddress,
797    MulticastAddr,
798    MappedAddress,
799    NonMappedAddr
800);
801impl_try_from_witness!(
802    [MulticastAddr: MulticastAddress],
803    [UnicastAddr: UnicastAddress],
804    [BroadcastAddr: BroadcastAddress],
805    [LinkLocalAddr: LinkLocalAddress],
806    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
807    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
808    [NonMappedAddr: MappedAddress]
809);
810
811impl<A: MulticastAddress + MappedAddress> MulticastAddr<A> {
812    /// Wraps `self` in the [`NonMappedAddr`] witness type.
813    pub fn non_mapped(self) -> NonMappedAddr<MulticastAddr<A>> {
814        // Safety: IPv4 addresses cannot be mapped. For IPv6 addresses, the
815        // multicast subnet (FF00::/8) and the ipv4-mapped-ipv6 address space
816        // (::FFFF:0000:0000/96) are disjoint: presence in the multicast subnet
817        // implies absence from the ipv4-mapped-ipv6 address space.
818        unsafe { NonMappedAddr::new_unchecked(self) }
819    }
820}
821
822// NonMulticastAddr - An address known to not be multicast.
823//
824// Note this type is similar to `UnicastAddr`, but not identical: all
825// `UnicastAddr' can also be `NonMulticastAddr`, but not all `NonMulticastAddr`
826// can be `UnicastAddr`. E.g. an IPv4 Broadcast Addr is non-multicast but not
827// unicast.
828impl_witness!(NonMulticastAddr, "non-multicast", MulticastAddress, is_non_multicast);
829impl_nested_witness!(MulticastAddress, NonMulticastAddr, SpecifiedAddress, SpecifiedAddr);
830impl_nested_witness!(MulticastAddress, NonMulticastAddr, UnicastAddress, UnicastAddr);
831impl_nested_witness!(MulticastAddress, NonMulticastAddr, BroadcastAddress, BroadcastAddr);
832impl_nested_witness!(MulticastAddress, NonMulticastAddr, MappedAddress, NonMappedAddr);
833
834impl<A: MulticastAddress + UnicastAddress> From<UnicastAddr<A>> for NonMulticastAddr<A> {
835    #[inline]
836    fn from(addr: UnicastAddr<A>) -> Self {
837        // Safe because a unicast address is guaranteed to not be multicast.
838        unsafe { NonMulticastAddr::new_unchecked(addr.into_addr()) }
839    }
840}
841// NB: Implement nested witness to a depth of three, only for the types that are
842// actually used by consumers of this library.
843impl_nested_witness!(
844    MulticastAddress,
845    NonMulticastAddr,
846    MappedAddress,
847    NonMappedAddr,
848    SpecifiedAddress,
849    SpecifiedAddr
850);
851impl_into_specified_for_nested_witness!(
852    MulticastAddress,
853    NonMulticastAddr,
854    MappedAddress,
855    NonMappedAddr,
856    SpecifiedAddress,
857    SpecifiedAddr
858);
859
860// BroadcastAddr
861impl_witness!(BroadcastAddr, "broadcast", BroadcastAddress, is_broadcast);
862impl_into_specified!(BroadcastAddr, BroadcastAddress, is_broadcast);
863impl_nested_witness!(BroadcastAddress, BroadcastAddr, LinkLocalAddress, LinkLocalAddr);
864impl_nested_witness!(BroadcastAddress, BroadcastAddr, MappedAddress, NonMappedAddr);
865impl_into_specified_for_nested_witness!(
866    BroadcastAddress,
867    BroadcastAddr,
868    LinkLocalAddress,
869    LinkLocalAddr
870);
871impl_into_specified_for_nested_witness!(
872    BroadcastAddress,
873    BroadcastAddr,
874    MappedAddress,
875    NonMappedAddr
876);
877impl_try_from_witness!(
878    [BroadcastAddr: BroadcastAddress],
879    [UnicastAddr: UnicastAddress],
880    [MulticastAddr: MulticastAddress],
881    [LinkLocalAddr: LinkLocalAddress],
882    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
883    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
884    [NonMappedAddr: MappedAddress]
885);
886
887// LinkLocalAddr
888impl_witness!(LinkLocalAddr, "link-local", LinkLocalAddress, is_link_local);
889impl_into_specified!(LinkLocalAddr, LinkLocalAddress, is_link_local);
890impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, UnicastAddress, UnicastAddr);
891impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, MulticastAddress, MulticastAddr);
892impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, BroadcastAddress, BroadcastAddr);
893impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, MappedAddress, NonMappedAddr);
894impl_into_specified_for_nested_witness!(
895    LinkLocalAddress,
896    LinkLocalAddr,
897    UnicastAddress,
898    UnicastAddr
899);
900impl_into_specified_for_nested_witness!(
901    LinkLocalAddress,
902    LinkLocalAddr,
903    MulticastAddress,
904    MulticastAddr
905);
906impl_into_specified_for_nested_witness!(
907    LinkLocalAddress,
908    LinkLocalAddr,
909    BroadcastAddress,
910    BroadcastAddr
911);
912impl_into_specified_for_nested_witness!(
913    LinkLocalAddress,
914    LinkLocalAddr,
915    MappedAddress,
916    NonMappedAddr
917);
918impl_try_from_witness!(
919    [LinkLocalAddr: LinkLocalAddress],
920    [UnicastAddr: UnicastAddress],
921    [MulticastAddr: MulticastAddress],
922    [BroadcastAddr: BroadcastAddress],
923    [NonMappedAddr: MappedAddress]
924);
925
926// NonMappedAddr
927impl_witness!(NonMappedAddr, "non_mapped", MappedAddress, is_non_mapped);
928impl_nested_witness!(MappedAddress, NonMappedAddr, SpecifiedAddress, SpecifiedAddr);
929impl_nested_witness!(MappedAddress, NonMappedAddr, UnicastAddress, UnicastAddr);
930impl_nested_witness!(MappedAddress, NonMappedAddr, MulticastAddress, MulticastAddr);
931impl_nested_witness!(MappedAddress, NonMappedAddr, BroadcastAddress, BroadcastAddr);
932impl_nested_witness!(MappedAddress, NonMappedAddr, LinkLocalAddress, LinkLocalAddr);
933impl_into_specified_for_nested_witness!(
934    MappedAddress,
935    NonMappedAddr,
936    SpecifiedAddress,
937    SpecifiedAddr
938);
939impl_into_specified_for_nested_witness!(MappedAddress, NonMappedAddr, UnicastAddress, UnicastAddr);
940impl_into_specified_for_nested_witness!(
941    MappedAddress,
942    NonMappedAddr,
943    MulticastAddress,
944    MulticastAddr
945);
946impl_into_specified_for_nested_witness!(
947    MappedAddress,
948    NonMappedAddr,
949    BroadcastAddress,
950    BroadcastAddr
951);
952impl_into_specified_for_nested_witness!(
953    MappedAddress,
954    NonMappedAddr,
955    LinkLocalAddress,
956    LinkLocalAddr
957);
958impl_try_from_witness!(
959    [NonMappedAddr: MappedAddress],
960    [SpecifiedAddr: SpecifiedAddress],
961    [UnicastAddr: UnicastAddress],
962    [MulticastAddr: MulticastAddress],
963    [BroadcastAddr: BroadcastAddress],
964    [LinkLocalAddr: LinkLocalAddress],
965    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
966    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
967    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress]
968);
969
970// NOTE(joshlf): We provide these type aliases both for convenience and also to
971// steer users towards these types and away from `UnicastAddr<LinkLocalAddr<A>>`
972// and `MulticastAddr<LinkLocalAddr<A>>`, which are also valid. The reason we
973// still implement `Witness<A>` for those types is that user code may contain
974// generic contexts (e.g., some code with `UnicastAddr<A>`, and other code which
975// wishes to supply `A = LinkLocalAddr<AA>`), and we want to support that use
976// case.
977
978/// An address that can be link-local and unicast.
979///
980/// `LinkLocalUnicastAddress` is a shorthand for `LinkLocalAddress +
981/// UnicastAddress`.
982pub trait LinkLocalUnicastAddress: LinkLocalAddress + UnicastAddress {}
983impl<A: LinkLocalAddress + UnicastAddress> LinkLocalUnicastAddress for A {}
984
985/// An address that can be link-local and multicast.
986///
987/// `LinkLocalMulticastAddress` is a shorthand for `LinkLocalAddress +
988/// MulticastAddress`.
989pub trait LinkLocalMulticastAddress: LinkLocalAddress + MulticastAddress {}
990impl<A: LinkLocalAddress + MulticastAddress> LinkLocalMulticastAddress for A {}
991
992/// An address that can be link-local and broadcast.
993///
994/// `LinkLocalBroadcastAddress` is a shorthand for `LinkLocalAddress +
995/// BroadcastAddress`.
996pub trait LinkLocalBroadcastAddress: LinkLocalAddress + BroadcastAddress {}
997impl<A: LinkLocalAddress + BroadcastAddress> LinkLocalBroadcastAddress for A {}
998
999/// A link-local unicast address.
1000pub type LinkLocalUnicastAddr<A> = LinkLocalAddr<UnicastAddr<A>>;
1001
1002/// A link-local multicast address.
1003pub type LinkLocalMulticastAddr<A> = LinkLocalAddr<MulticastAddr<A>>;
1004
1005/// A link-local broadcast address.
1006pub type LinkLocalBroadcastAddr<A> = LinkLocalAddr<BroadcastAddr<A>>;
1007
1008impl_try_from_witness!(
1009    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
1010    [UnicastAddr: UnicastAddress],
1011    [MulticastAddr: MulticastAddress],
1012    [LinkLocalAddr: LinkLocalAddress],
1013    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
1014    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress]
1015);
1016impl_try_from_witness!(
1017    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
1018    [UnicastAddr: UnicastAddress],
1019    [MulticastAddr: MulticastAddress],
1020    [LinkLocalAddr: LinkLocalAddress],
1021    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
1022    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress]
1023);
1024impl_try_from_witness!(
1025    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
1026    [UnicastAddr: UnicastAddress],
1027    [MulticastAddr: MulticastAddress],
1028    [LinkLocalAddr: LinkLocalAddress],
1029    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
1030    [LinkLocalMulticastAddr: LinkLocalMulticastAddress]
1031);
1032
1033/// A witness type for an address and a scope zone.
1034///
1035/// `AddrAndZone` carries an address that *may* have a scope, alongside the
1036/// particular zone of that scope. The zone is also referred to as a "scope
1037/// identifier" in some systems (such as Linux).
1038///
1039/// Note that although `AddrAndZone` acts as a witness type, it does not
1040/// implement [`Witness`] since it carries both the address and scoping
1041/// information, and not only the witnessed address.
1042#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1043pub struct AddrAndZone<A, Z>(A, Z);
1044
1045impl<A: ScopeableAddress, Z> AddrAndZone<A, Z> {
1046    /// Constructs a new `AddrAndZone`, returning `Some` only if the provided
1047    /// `addr`'s scope can have a zone (`addr.scope().can_have_zone()`).
1048    pub fn new(addr: A, zone: Z) -> Option<Self> {
1049        if addr.scope().can_have_zone() { Some(Self(addr, zone)) } else { None }
1050    }
1051}
1052
1053impl<A: ScopeableAddress + IpAddress, Z> AddrAndZone<A, Z> {
1054    /// Constructs a new `AddrAndZone`, returning `Some` only if the provided
1055    /// `addr`'s scope can have a zone (`addr.scope().can_have_zone()`) and
1056    /// `addr` is not a loopback address.
1057    pub fn new_not_loopback(addr: A, zone: Z) -> Option<Self> {
1058        if addr.scope().can_have_zone() && !addr.is_loopback() {
1059            Some(Self(addr, zone))
1060        } else {
1061            None
1062        }
1063    }
1064}
1065
1066impl<A, Z> AddrAndZone<A, Z> {
1067    /// Constructs a new `AddrAndZone` without checking to see if `addr`'s scope
1068    /// can have a zone.
1069    ///
1070    /// # Safety
1071    ///
1072    /// It is up to the caller to make sure that `addr`'s scope can have a zone
1073    /// to avoid breaking the guarantees of `AddrAndZone`.
1074    #[inline]
1075    pub const unsafe fn new_unchecked(addr: A, zone: Z) -> Self {
1076        Self(addr, zone)
1077    }
1078
1079    /// Consumes this `AddrAndZone`, returning the address and zone separately.
1080    pub fn into_addr_scope_id(self) -> (A, Z) {
1081        let AddrAndZone(addr, zone) = self;
1082        (addr, zone)
1083    }
1084
1085    /// Translates the zone identifier using the provided function.
1086    pub fn map_zone<Y>(self, f: impl FnOnce(Z) -> Y) -> AddrAndZone<A, Y> {
1087        let AddrAndZone(addr, zone) = self;
1088        AddrAndZone(addr, f(zone))
1089    }
1090
1091    /// Translates the address using `f`.
1092    pub fn map_addr<B>(self, f: impl FnOnce(A) -> B) -> AddrAndZone<B, Z> {
1093        let Self(addr, zone) = self;
1094        AddrAndZone(f(addr), zone)
1095    }
1096
1097    /// Attempts to translate the zone identifier using the provided function.
1098    pub fn try_map_zone<Y, E>(
1099        self,
1100        f: impl FnOnce(Z) -> Result<Y, E>,
1101    ) -> Result<AddrAndZone<A, Y>, E> {
1102        let AddrAndZone(addr, zone) = self;
1103        f(zone).map(|zone| AddrAndZone(addr, zone))
1104    }
1105
1106    /// Accesses the addr for this `AddrAndZone`.
1107    pub fn addr(&self) -> A
1108    where
1109        A: Copy,
1110    {
1111        let AddrAndZone(addr, _zone) = self;
1112        *addr
1113    }
1114
1115    /// Converts from `AddrAndZone<A, Z>` to `AddrAndZone<&A, &Z>`.
1116    pub fn as_ref(&self) -> AddrAndZone<&A, &Z> {
1117        let Self(addr, zone) = self;
1118        AddrAndZone(addr, zone)
1119    }
1120}
1121
1122impl<A: Display, Z: Display> Display for AddrAndZone<A, Z> {
1123    #[inline]
1124    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1125        write!(f, "{}%{}", self.0, self.1)
1126    }
1127}
1128
1129impl<A, Z> sealed::Sealed for AddrAndZone<A, Z> {}
1130
1131impl<A: SpecifiedAddress, Z> From<AddrAndZone<SpecifiedAddr<A>, Z>> for AddrAndZone<A, Z> {
1132    fn from(AddrAndZone(addr, zone): AddrAndZone<SpecifiedAddr<A>, Z>) -> Self {
1133        Self(addr.into_addr(), zone)
1134    }
1135}
1136
1137/// An address that may have an associated scope zone.
1138#[allow(missing_docs)]
1139#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1140pub enum ZonedAddr<A, Z> {
1141    Unzoned(A),
1142    Zoned(AddrAndZone<A, Z>),
1143}
1144
1145impl<A: Display, Z: Display> Display for ZonedAddr<A, Z> {
1146    #[inline]
1147    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1148        match self {
1149            Self::Unzoned(addr) => write!(f, "{addr}"),
1150            Self::Zoned(addr_and_zone) => write!(f, "{addr_and_zone}"),
1151        }
1152    }
1153}
1154
1155impl<A, Z> ZonedAddr<A, Z> {
1156    /// Decomposes this `ZonedAddr` into an addr and an optional scope zone.
1157    pub fn into_addr_zone(self) -> (A, Option<Z>) {
1158        match self {
1159            ZonedAddr::Unzoned(addr) => (addr, None),
1160            ZonedAddr::Zoned(scope_and_zone) => {
1161                let (addr, zone) = scope_and_zone.into_addr_scope_id();
1162                (addr, Some(zone))
1163            }
1164        }
1165    }
1166
1167    /// Accesses the addr for this `ZonedAddr`.
1168    pub fn addr(&self) -> A
1169    where
1170        A: Copy,
1171    {
1172        match self {
1173            ZonedAddr::Unzoned(addr) => *addr,
1174            ZonedAddr::Zoned(addr_and_zone) => addr_and_zone.addr(),
1175        }
1176    }
1177
1178    /// Translates the zone identifier using the provided function.
1179    pub fn map_zone<Y>(self, f: impl FnOnce(Z) -> Y) -> ZonedAddr<A, Y> {
1180        match self {
1181            ZonedAddr::Unzoned(u) => ZonedAddr::Unzoned(u),
1182            ZonedAddr::Zoned(z) => ZonedAddr::Zoned(z.map_zone(f)),
1183        }
1184    }
1185
1186    /// Translates the address using `f`.
1187    pub fn map_addr<B>(self, f: impl FnOnce(A) -> B) -> ZonedAddr<B, Z> {
1188        match self {
1189            Self::Unzoned(u) => ZonedAddr::Unzoned(f(u)),
1190            Self::Zoned(z) => ZonedAddr::Zoned(z.map_addr(f)),
1191        }
1192    }
1193
1194    /// Converts from `&ZonedAddr<A, Z>` to `ZonedAddr<&A, &Z>`.
1195    pub fn as_ref(&self) -> ZonedAddr<&A, &Z> {
1196        match self {
1197            Self::Unzoned(u) => ZonedAddr::Unzoned(u),
1198            Self::Zoned(z) => ZonedAddr::Zoned(z.as_ref()),
1199        }
1200    }
1201}
1202
1203impl<A: ScopeableAddress, Z> ZonedAddr<A, Z> {
1204    /// Creates a new `ZonedAddr` with the provided optional scope zone.
1205    ///
1206    /// If `zone` is `None`, [`ZonedAddr::Unzoned`] is returned. Otherwise, a
1207    /// [`ZonedAddr::Zoned`] is returned only if the provided `addr`'s scope can
1208    /// have a zone (`addr.scope().can_have_zone()`).
1209    pub fn new(addr: A, zone: Option<Z>) -> Option<Self> {
1210        match zone {
1211            Some(zone) => AddrAndZone::new(addr, zone).map(ZonedAddr::Zoned),
1212            None => Some(ZonedAddr::Unzoned(addr)),
1213        }
1214    }
1215}
1216
1217impl<A: IpAddress + ScopeableAddress, Z: Clone> ZonedAddr<A, Z> {
1218    /// Creates a [`ZonedAddr::Zoned`] iff `addr` can have a zone and is not
1219    /// loopback.
1220    ///
1221    /// `get_zone` is only called if the address needs a zone.
1222    pub fn new_zoned_if_necessary(addr: A, get_zone: impl FnOnce() -> Z) -> Self {
1223        match AddrAndZone::new_not_loopback(addr, ()) {
1224            Some(addr_and_zone) => Self::Zoned(addr_and_zone.map_zone(move |()| get_zone())),
1225            None => Self::Unzoned(addr),
1226        }
1227    }
1228}
1229
1230impl<A: ScopeableAddress<Scope = ()>, Z> ZonedAddr<A, Z> {
1231    /// Retrieves the addr for this `ZonedAddr` when the `Scope` is `()`.
1232    ///
1233    /// `()` is a known implementation that never allows `AddrAndZone` to be
1234    /// constructed so we can safely drop the zone information.
1235    pub fn into_unzoned(self) -> A {
1236        match self {
1237            ZonedAddr::Unzoned(u) => u,
1238            ZonedAddr::Zoned(_z) => unreachable!(),
1239        }
1240    }
1241}
1242
1243impl<A, Z> From<AddrAndZone<A, Z>> for ZonedAddr<A, Z> {
1244    fn from(a: AddrAndZone<A, Z>) -> Self {
1245        Self::Zoned(a)
1246    }
1247}
1248
1249impl<A: SpecifiedAddress, Z> From<ZonedAddr<SpecifiedAddr<A>, Z>> for ZonedAddr<A, Z> {
1250    fn from(zoned_addr: ZonedAddr<SpecifiedAddr<A>, Z>) -> Self {
1251        match zoned_addr {
1252            ZonedAddr::Unzoned(a) => Self::Unzoned(a.into_addr()),
1253            ZonedAddr::Zoned(z) => Self::Zoned(z.into()),
1254        }
1255    }
1256}
1257
1258impl<A, I: Ip> GenericOverIp<I> for SpecifiedAddr<A> {
1259    type Type = SpecifiedAddr<I::Addr>;
1260}
1261
1262impl<A: IpAddress, I: Ip> GenericOverIp<I> for MulticastAddr<A> {
1263    type Type = MulticastAddr<I::Addr>;
1264}
1265
1266impl<A: GenericOverIp<I>, I: Ip, Z> GenericOverIp<I> for ZonedAddr<A, Z> {
1267    type Type = ZonedAddr<A::Type, Z>;
1268}
1269
1270impl<A: GenericOverIp<I>, I: Ip, Z> GenericOverIp<I> for AddrAndZone<A, Z> {
1271    type Type = AddrAndZone<A::Type, Z>;
1272}
1273
1274/// Provides a `Display` implementation for printing an address and a port.
1275#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1276pub struct AddrAndPortFormatter<A, P, I: Ip> {
1277    addr: A,
1278    port: P,
1279    _marker: IpVersionMarker<I>,
1280}
1281
1282impl<A, P, I: Ip> AddrAndPortFormatter<A, P, I> {
1283    /// Construct a new `AddrAndPortFormatter`.
1284    pub fn new(addr: A, port: P) -> Self {
1285        Self { addr, port, _marker: IpVersionMarker::new() }
1286    }
1287}
1288
1289impl<A: Display, P: Display, I: Ip> Display for AddrAndPortFormatter<A, P, I> {
1290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1291        let Self { addr, port, _marker } = self;
1292        let IpInvariant(result) = I::map_ip(
1293            IpInvariant((addr, port, f)),
1294            |IpInvariant((addr, port, f))| IpInvariant(write!(f, "{}:{}", addr, port)),
1295            |IpInvariant((addr, port, f))| IpInvariant(write!(f, "[{}]:{}", addr, port)),
1296        );
1297        result
1298    }
1299}
1300
1301#[cfg(test)]
1302mod tests {
1303    use super::*;
1304
1305    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
1306    enum Address {
1307        Unspecified,
1308        GlobalUnicast,
1309        GlobalMulticast,
1310        GlobalBroadcast,
1311        LinkLocalUnicast,
1312        LinkLocalMulticast,
1313        LinkLocalBroadcast,
1314        MappedUnicast,
1315        MappedMulticast,
1316        MappedBroadcast,
1317    }
1318
1319    impl SpecifiedAddress for Address {
1320        fn is_specified(&self) -> bool {
1321            *self != Address::Unspecified
1322        }
1323    }
1324
1325    impl UnicastAddress for Address {
1326        fn is_unicast(&self) -> bool {
1327            use Address::*;
1328            match self {
1329                GlobalUnicast | LinkLocalUnicast | MappedUnicast => true,
1330                Unspecified | GlobalMulticast | GlobalBroadcast | LinkLocalMulticast
1331                | LinkLocalBroadcast | MappedMulticast | MappedBroadcast => false,
1332            }
1333        }
1334    }
1335
1336    impl MulticastAddress for Address {
1337        fn is_multicast(&self) -> bool {
1338            use Address::*;
1339            match self {
1340                GlobalMulticast | LinkLocalMulticast | MappedMulticast => true,
1341                Unspecified | GlobalUnicast | GlobalBroadcast | LinkLocalUnicast
1342                | MappedUnicast | MappedBroadcast | LinkLocalBroadcast => false,
1343            }
1344        }
1345    }
1346
1347    impl BroadcastAddress for Address {
1348        fn is_broadcast(&self) -> bool {
1349            use Address::*;
1350            match self {
1351                GlobalBroadcast | LinkLocalBroadcast | MappedBroadcast => true,
1352                Unspecified | GlobalUnicast | GlobalMulticast | LinkLocalUnicast
1353                | MappedUnicast | MappedMulticast | LinkLocalMulticast => false,
1354            }
1355        }
1356    }
1357
1358    impl LinkLocalAddress for Address {
1359        fn is_link_local(&self) -> bool {
1360            use Address::*;
1361            match self {
1362                LinkLocalUnicast | LinkLocalMulticast | LinkLocalBroadcast => true,
1363                Unspecified | GlobalUnicast | GlobalMulticast | GlobalBroadcast | MappedUnicast
1364                | MappedBroadcast | MappedMulticast => false,
1365            }
1366        }
1367    }
1368
1369    impl MappedAddress for Address {
1370        fn is_non_mapped(&self) -> bool {
1371            use Address::*;
1372            match self {
1373                MappedUnicast | MappedBroadcast | MappedMulticast => false,
1374                Unspecified | GlobalUnicast | GlobalMulticast | GlobalBroadcast
1375                | LinkLocalUnicast | LinkLocalMulticast | LinkLocalBroadcast => true,
1376            }
1377        }
1378    }
1379
1380    #[derive(Copy, Clone, Eq, PartialEq)]
1381    enum AddressScope {
1382        LinkLocal,
1383        Global,
1384    }
1385
1386    impl Scope for AddressScope {
1387        fn can_have_zone(&self) -> bool {
1388            matches!(self, AddressScope::LinkLocal)
1389        }
1390    }
1391
1392    impl ScopeableAddress for Address {
1393        type Scope = AddressScope;
1394
1395        fn scope(&self) -> AddressScope {
1396            if self.is_link_local() { AddressScope::LinkLocal } else { AddressScope::Global }
1397        }
1398    }
1399
1400    #[test]
1401    fn specified_addr() {
1402        assert_eq!(
1403            SpecifiedAddr::new(Address::GlobalUnicast),
1404            Some(SpecifiedAddr(Address::GlobalUnicast))
1405        );
1406        assert_eq!(SpecifiedAddr::new(Address::Unspecified), None);
1407    }
1408
1409    #[test]
1410    fn unicast_addr() {
1411        assert_eq!(
1412            UnicastAddr::new(Address::GlobalUnicast),
1413            Some(UnicastAddr(Address::GlobalUnicast))
1414        );
1415        assert_eq!(UnicastAddr::new(Address::GlobalMulticast), None);
1416        assert_eq!(
1417            unsafe { UnicastAddr::new_unchecked(Address::GlobalUnicast) },
1418            UnicastAddr(Address::GlobalUnicast)
1419        );
1420    }
1421
1422    #[test]
1423    fn multicast_addr() {
1424        assert_eq!(
1425            MulticastAddr::new(Address::GlobalMulticast),
1426            Some(MulticastAddr(Address::GlobalMulticast))
1427        );
1428        assert_eq!(MulticastAddr::new(Address::GlobalUnicast), None);
1429        assert_eq!(
1430            unsafe { MulticastAddr::new_unchecked(Address::GlobalMulticast) },
1431            MulticastAddr(Address::GlobalMulticast)
1432        );
1433    }
1434
1435    #[test]
1436    fn broadcast_addr() {
1437        assert_eq!(
1438            BroadcastAddr::new(Address::GlobalBroadcast),
1439            Some(BroadcastAddr(Address::GlobalBroadcast))
1440        );
1441        assert_eq!(BroadcastAddr::new(Address::GlobalUnicast), None);
1442        assert_eq!(
1443            unsafe { BroadcastAddr::new_unchecked(Address::GlobalBroadcast) },
1444            BroadcastAddr(Address::GlobalBroadcast)
1445        );
1446    }
1447
1448    #[test]
1449    fn link_local_addr() {
1450        assert_eq!(
1451            LinkLocalAddr::new(Address::LinkLocalUnicast),
1452            Some(LinkLocalAddr(Address::LinkLocalUnicast))
1453        );
1454        assert_eq!(LinkLocalAddr::new(Address::GlobalMulticast), None);
1455        assert_eq!(
1456            unsafe { LinkLocalAddr::new_unchecked(Address::LinkLocalUnicast) },
1457            LinkLocalAddr(Address::LinkLocalUnicast)
1458        );
1459    }
1460
1461    #[test]
1462    fn non_mapped_addr() {
1463        assert_eq!(
1464            NonMappedAddr::new(Address::LinkLocalUnicast),
1465            Some(NonMappedAddr(Address::LinkLocalUnicast))
1466        );
1467        assert_eq!(NonMappedAddr::new(Address::MappedUnicast), None);
1468        assert_eq!(
1469            NonMappedAddr::new(Address::LinkLocalMulticast),
1470            Some(NonMappedAddr(Address::LinkLocalMulticast))
1471        );
1472        assert_eq!(NonMappedAddr::new(Address::MappedMulticast), None);
1473        assert_eq!(
1474            NonMappedAddr::new(Address::LinkLocalBroadcast),
1475            Some(NonMappedAddr(Address::LinkLocalBroadcast))
1476        );
1477        assert_eq!(NonMappedAddr::new(Address::MappedBroadcast), None);
1478    }
1479
1480    macro_rules! test_nested {
1481        ($outer:ident, $inner:ident, $($input:ident => $output:expr,)*) => {
1482            $(
1483                assert_eq!($inner::new(Address::$input).and_then($outer::new), $output);
1484            )*
1485        };
1486    }
1487
1488    #[test]
1489    fn nested_link_local() {
1490        // Test UnicastAddr<LinkLocalAddr>, MulticastAddr<LinkLocalAddr>,
1491        // BroadcastAddr<LinkLocalAddr>, LinkLocalAddr<UnicastAddr>,
1492        // LinkLocalAddr<MulticastAddr>, LinkLocalAddr<BroadcastAddr>.
1493
1494        // Unicast
1495        test_nested!(
1496            UnicastAddr,
1497            LinkLocalAddr,
1498            Unspecified => None,
1499            GlobalUnicast => None,
1500            GlobalMulticast => None,
1501            LinkLocalUnicast => Some(UnicastAddr(LinkLocalAddr(Address::LinkLocalUnicast))),
1502            LinkLocalMulticast => None,
1503            LinkLocalBroadcast => None,
1504        );
1505
1506        // Multicast
1507        test_nested!(
1508            MulticastAddr,
1509            LinkLocalAddr,
1510            Unspecified => None,
1511            GlobalUnicast => None,
1512            GlobalMulticast => None,
1513            LinkLocalUnicast => None,
1514            LinkLocalMulticast => Some(MulticastAddr(LinkLocalAddr(Address::LinkLocalMulticast))),
1515            LinkLocalBroadcast => None,
1516        );
1517
1518        // Broadcast
1519        test_nested!(
1520            BroadcastAddr,
1521            LinkLocalAddr,
1522            Unspecified => None,
1523            GlobalUnicast => None,
1524            GlobalMulticast => None,
1525            LinkLocalUnicast => None,
1526            LinkLocalMulticast => None,
1527            LinkLocalBroadcast => Some(BroadcastAddr(LinkLocalAddr(Address::LinkLocalBroadcast))),
1528        );
1529
1530        // Link-local
1531        test_nested!(
1532            LinkLocalAddr,
1533            UnicastAddr,
1534            Unspecified => None,
1535            GlobalUnicast => None,
1536            GlobalMulticast => None,
1537            LinkLocalUnicast => Some(LinkLocalAddr(UnicastAddr(Address::LinkLocalUnicast))),
1538            LinkLocalMulticast => None,
1539            LinkLocalBroadcast => None,
1540        );
1541        test_nested!(
1542            LinkLocalAddr,
1543            MulticastAddr,
1544            Unspecified => None,
1545            GlobalUnicast => None,
1546            GlobalMulticast => None,
1547            LinkLocalUnicast => None,
1548            LinkLocalMulticast => Some(LinkLocalAddr(MulticastAddr(Address::LinkLocalMulticast))),
1549            LinkLocalBroadcast => None,
1550        );
1551        test_nested!(
1552            LinkLocalAddr,
1553            BroadcastAddr,
1554            Unspecified => None,
1555            GlobalUnicast => None,
1556            GlobalMulticast => None,
1557            LinkLocalUnicast => None,
1558            LinkLocalMulticast => None,
1559            LinkLocalBroadcast => Some(LinkLocalAddr(BroadcastAddr(Address::LinkLocalBroadcast))),
1560        );
1561    }
1562
1563    #[test]
1564    fn nested_non_mapped() {
1565        // Test:
1566        //   UnicastAddr<NonMappedAddr>, NonMappedAddr<UnicastAddr>,
1567        //   MulticastAddr<NonMappedAddr>, NonMappedAddr<MulticastAddr>,
1568        //   BroadcastAddr<NonMappedAddr>, NonMappedAddr<BroadcastAddr>,
1569
1570        // Unicast
1571        test_nested!(
1572            UnicastAddr,
1573            NonMappedAddr,
1574            Unspecified => None,
1575            LinkLocalUnicast => Some(UnicastAddr(NonMappedAddr(Address::LinkLocalUnicast))),
1576            LinkLocalMulticast => None,
1577            LinkLocalBroadcast => None,
1578            MappedUnicast => None,
1579            MappedMulticast => None,
1580            MappedBroadcast => None,
1581        );
1582
1583        // Multicast
1584        test_nested!(
1585            MulticastAddr,
1586            NonMappedAddr,
1587            Unspecified => None,
1588            LinkLocalUnicast => None,
1589            LinkLocalMulticast => Some(MulticastAddr(NonMappedAddr(Address::LinkLocalMulticast))),
1590            LinkLocalBroadcast => None,
1591            MappedUnicast => None,
1592            MappedMulticast => None,
1593            MappedBroadcast => None,
1594        );
1595
1596        // Broadcast
1597        test_nested!(
1598            BroadcastAddr,
1599            NonMappedAddr,
1600            Unspecified => None,
1601            LinkLocalUnicast => None,
1602            LinkLocalMulticast => None,
1603            LinkLocalBroadcast => Some(BroadcastAddr(NonMappedAddr(Address::LinkLocalBroadcast))),
1604            MappedUnicast => None,
1605            MappedMulticast => None,
1606            MappedBroadcast => None,
1607        );
1608
1609        // non-mapped
1610        test_nested!(
1611            NonMappedAddr,
1612            UnicastAddr,
1613            Unspecified => None,
1614            LinkLocalUnicast => Some(NonMappedAddr(UnicastAddr(Address::LinkLocalUnicast))),
1615            LinkLocalMulticast => None,
1616            LinkLocalBroadcast => None,
1617            MappedUnicast => None,
1618            MappedMulticast => None,
1619            MappedBroadcast => None,
1620        );
1621        test_nested!(
1622            NonMappedAddr,
1623            MulticastAddr,
1624            Unspecified => None,
1625            LinkLocalUnicast => None,
1626            LinkLocalMulticast => Some(NonMappedAddr(MulticastAddr(Address::LinkLocalMulticast))),
1627            LinkLocalBroadcast => None,
1628            MappedUnicast => None,
1629            MappedMulticast => None,
1630            MappedBroadcast => None,
1631        );
1632        test_nested!(
1633            NonMappedAddr,
1634            BroadcastAddr,
1635            Unspecified => None,
1636            LinkLocalUnicast => None,
1637            LinkLocalMulticast => None,
1638            LinkLocalBroadcast => Some(NonMappedAddr(BroadcastAddr(Address::LinkLocalBroadcast))),
1639            MappedUnicast => None,
1640            MappedMulticast => None,
1641            MappedBroadcast => None,
1642        );
1643    }
1644
1645    #[test]
1646    fn addr_and_zone() {
1647        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, ());
1648        assert_eq!(addr_and_zone, Some(AddrAndZone(Address::LinkLocalUnicast, ())));
1649        assert_eq!(addr_and_zone.unwrap().into_addr_scope_id(), (Address::LinkLocalUnicast, ()));
1650        assert_eq!(AddrAndZone::new(Address::GlobalUnicast, ()), None);
1651        assert_eq!(
1652            unsafe { AddrAndZone::new_unchecked(Address::LinkLocalUnicast, ()) },
1653            AddrAndZone(Address::LinkLocalUnicast, ())
1654        );
1655    }
1656
1657    #[test]
1658    fn addr_and_zone_map_zone() {
1659        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 65).unwrap();
1660        assert_eq!(
1661            addr_and_zone.map_zone(|x| char::from_u32(x).unwrap()),
1662            AddrAndZone::new(Address::LinkLocalUnicast, 'A').unwrap()
1663        );
1664    }
1665
1666    #[test]
1667    fn addr_and_zone_try_map_zone() {
1668        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 32).unwrap();
1669        assert_eq!(
1670            addr_and_zone.try_map_zone(|x| Ok::<_, ()>(x + 1)),
1671            Ok(AddrAndZone::new(Address::LinkLocalUnicast, 33).unwrap())
1672        );
1673
1674        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 32).unwrap();
1675        assert_eq!(addr_and_zone.try_map_zone(|x| Err::<i32, _>(x - 1)), Err(31),);
1676    }
1677
1678    #[test]
1679    fn scoped_address() {
1680        // Type alias to help the compiler when the scope type can't be
1681        // inferred.
1682        type ZonedAddr = crate::ZonedAddr<Address, ()>;
1683        assert_eq!(
1684            ZonedAddr::new(Address::GlobalUnicast, None),
1685            Some(ZonedAddr::Unzoned(Address::GlobalUnicast))
1686        );
1687        assert_eq!(
1688            ZonedAddr::new(Address::Unspecified, None).unwrap().into_addr_zone(),
1689            (Address::Unspecified, None)
1690        );
1691        assert_eq!(
1692            ZonedAddr::new(Address::LinkLocalUnicast, None),
1693            Some(ZonedAddr::Unzoned(Address::LinkLocalUnicast))
1694        );
1695        assert_eq!(ZonedAddr::new(Address::GlobalUnicast, Some(())), None);
1696        assert_eq!(ZonedAddr::new(Address::Unspecified, Some(())), None);
1697        assert_eq!(
1698            ZonedAddr::new(Address::LinkLocalUnicast, Some(())),
1699            Some(ZonedAddr::Zoned(AddrAndZone(Address::LinkLocalUnicast, ())))
1700        );
1701
1702        assert_eq!(
1703            ZonedAddr::new(Address::GlobalUnicast, None).unwrap().into_addr_zone(),
1704            (Address::GlobalUnicast, None)
1705        );
1706        assert_eq!(
1707            ZonedAddr::new(Address::LinkLocalUnicast, Some(())).unwrap().into_addr_zone(),
1708            (Address::LinkLocalUnicast, Some(()))
1709        );
1710    }
1711
1712    #[test]
1713    fn transpose_with_fully_qualified_types() {
1714        let addr: SpecifiedAddr<NonMappedAddr<Address>> =
1715            <NonMappedAddr<SpecifiedAddr<Address>> as Witness<SpecifiedAddr<Address>>>::transpose::<
1716                Address,
1717            >(
1718                NonMappedAddr::new(
1719                    SpecifiedAddr::new(Address::LinkLocalUnicast)
1720                        .expect("should be specified addr"),
1721                )
1722                .expect("should be non-mapped addr"),
1723            );
1724        assert_eq!(
1725            addr,
1726            SpecifiedAddr::new(
1727                NonMappedAddr::new(Address::LinkLocalUnicast).expect("should be non-mapped addr")
1728            )
1729            .expect("should be specified addr")
1730        )
1731    }
1732
1733    #[test]
1734    fn transpose_with_inferred_types() {
1735        assert_eq!(
1736            NonMappedAddr::new(
1737                SpecifiedAddr::new(Address::LinkLocalUnicast).expect("should be specified addr")
1738            )
1739            .expect("should be non-mapped addr")
1740            .transpose(),
1741            SpecifiedAddr::new(
1742                NonMappedAddr::new(Address::LinkLocalUnicast).expect("should be non-mapped addr")
1743            )
1744            .expect("should be specified addr")
1745        )
1746    }
1747}