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_comment! {
535                concat!("Constructs a new `", stringify!($type), "` without
536checking to see if `addr` is actually ", $adj, ".
537
538# Safety
539
540It is up to the caller to make sure that `addr` is ", $adj, " to avoid breaking
541the guarantees of `", stringify!($type), "`. See [`", stringify!($type), "`] for
542more details."),
543                pub const unsafe fn new_unchecked(addr: A) -> $type<A> {
544                    $type(addr)
545                }
546            }
547        }
548
549        impl<A> sealed::Sealed for $type<A> {}
550        impl<A: $trait> Witness<A> for $type<A> {
551            fn new(addr: A) -> Option<$type<A>> {
552                $type::new(addr)
553            }
554
555            unsafe fn new_unchecked(addr: A) -> $type<A> {
556                $type(addr)
557            }
558
559            #[inline]
560            fn into_addr(self) -> A {
561                self.0
562            }
563        }
564
565        impl<A: $trait> TransposableWitness<A> for $type<A> {
566            type Map<T> = $type<T>;
567        }
568
569        impl<A: $trait> AsRef<$type<A>> for $type<A> {
570            fn as_ref(&self) -> &$type<A> {
571                self
572            }
573        }
574
575        impl<A: $trait> AsRef<A> for $type<A> {
576            fn as_ref(&self) -> &A {
577                &self.0
578            }
579        }
580
581        impl<A: $trait> Deref for $type<A> {
582            type Target = A;
583
584            #[inline]
585            fn deref(&self) -> &A {
586                &self.0
587            }
588        }
589
590        impl<A: Display> Display for $type<A> {
591            #[inline]
592            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
593                self.0.fmt(f)
594            }
595        }
596
597        // Witness types help provide type safety for the compiler. The things
598        // they witness should be evident from seeing the contained type so we
599        // save some characters and offer a passthrough Debug impl.
600        impl<A: Debug> Debug for $type<A> {
601            #[inline]
602            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
603                self.0.fmt(f)
604            }
605        }
606    };
607}
608
609/// Implements an `into_specified` method on the witness type `$type`.
610///
611/// - `$trait` is the name of the trait associated with the witnessed property
612/// - `$method` is the method on `$trait` which determines whether the property
613///   holds (e.g., `is_unicast`)
614///
615/// An `into_specified` method is predicated on the witnessed property implying
616/// that the address is also specified (e.g., `UnicastAddress::is_unicast`
617/// implies `SpecifiedAddress::is_specified`).
618macro_rules! impl_into_specified {
619    ($type:ident, $trait:ident, $method:ident) => {
620        impl<A: $trait + SpecifiedAddress> $type<A> {
621            doc_comment! {
622                concat!("Converts this `", stringify!($type), "` into a
623[`SpecifiedAddr`].
624
625[`", stringify!($trait), "::", stringify!($method), "`] implies
626[`SpecifiedAddress::is_specified`], so all `", stringify!($type), "`s are
627guaranteed to be specified, so this conversion is infallible."),
628                #[inline]
629                pub fn into_specified(self) -> SpecifiedAddr<A> {
630                    SpecifiedAddr(self.0)
631                }
632            }
633        }
634
635        impl<A: $trait + SpecifiedAddress> From<$type<A>> for SpecifiedAddr<A> {
636            fn from(addr: $type<A>) -> SpecifiedAddr<A> {
637                addr.into_specified()
638            }
639        }
640    };
641}
642
643/// Implements [`Witness`] for a nested witness type.
644///
645/// Accepted Formats:
646/// * `impl_nested_witness!(trait1, type1, trait2, type2)`
647///     Implements `Witness<A>` for `type1<type2<A>>`.
648/// * `impl_nested_witness!(trait1, type1, trait2, type2, trait3, type3)`
649///     Implements `Witness<A>` for `type1<type2<type3<A>>>`.
650///
651/// Due to the nature of combinatorix, it is not advised to use this macro
652/// for all possible combinations of nested witnesses, only those that are
653/// actually instantiated in code.
654macro_rules! impl_nested_witness {
655    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident) => {
656        impl<A: $trait1 + $trait2> Witness<A> for $type1<$type2<A>> {
657            #[inline]
658            fn new(addr: A) -> Option<$type1<$type2<A>>> {
659                $type2::new(addr).and_then(Witness::<$type2<A>>::new)
660            }
661
662            unsafe fn new_unchecked(addr: A) -> $type1<$type2<A>> {
663                $type1($type2(addr))
664            }
665
666            #[inline]
667            fn into_addr(self) -> A {
668                self.0.into_addr()
669            }
670        }
671
672        impl<A: $trait1 + $trait2> AsRef<A> for $type1<$type2<A>> {
673            fn as_ref(&self) -> &A {
674                &self.0 .0
675            }
676        }
677    };
678    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident, $trait3:ident, $type3:ident) => {
679        impl<A: $trait1 + $trait2 + $trait3> Witness<A> for $type1<$type2<$type3<A>>> {
680            #[inline]
681            fn new(addr: A) -> Option<$type1<$type2<$type3<A>>>> {
682                $type3::new(addr).and_then(Witness::<$type3<A>>::new)
683            }
684
685            unsafe fn new_unchecked(addr: A) -> $type1<$type2<$type3<A>>> {
686                $type1($type2($type3(addr)))
687            }
688
689            #[inline]
690            fn into_addr(self) -> A {
691                self.0.into_addr()
692            }
693        }
694
695        impl<A: $trait1 + $trait2 + $trait3> AsRef<A> for $type1<$type2<$type3<A>>> {
696            fn as_ref(&self) -> &A {
697                &self.0 .0
698            }
699        }
700    };
701}
702
703/// Implements `From<T> or SpecifiedAddr<A>` where `T` is the nested witness.
704///
705/// Accepted Formats:
706/// * `impl_into_specified_for_nested_witness!(trait1, type1, trait2, type2)`
707///     Implements `From<type1<type2<A>>> for SpecifiedAddr<A>`.
708/// * `impl_nested_witness!(trait1, type1, trait2, type2, trait3, type3)`
709///     Implements `From<type1<type2<type3<<A>>>> for SpecifiedAddr<A>`.
710///
711/// Due to the nature of combinatorix, it is not advised to use this macro
712/// for all possible combinations of nested witnesses, only those that are
713/// actually instantiated in code.
714macro_rules! impl_into_specified_for_nested_witness {
715    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident) => {
716        impl<A: $trait1 + $trait2 + SpecifiedAddress> From<$type1<$type2<A>>> for SpecifiedAddr<A> {
717            fn from(addr: $type1<$type2<A>>) -> SpecifiedAddr<A> {
718                SpecifiedAddr(addr.into_addr())
719            }
720        }
721    };
722    ($trait1:ident, $type1:ident, $trait2:ident, $type2:ident, $trait3:ident, $type3:ident) => {
723        impl<A: $trait1 + $trait2 + $trait3 + SpecifiedAddress> From<$type1<$type2<$type3<A>>>>
724            for SpecifiedAddr<A>
725        {
726            fn from(addr: $type1<$type2<$type3<A>>>) -> SpecifiedAddr<A> {
727                SpecifiedAddr(addr.into_addr())
728            }
729        }
730    };
731}
732
733/// Implements `TryFrom<$from_ty<A>> for $into_ty<A>`
734macro_rules! impl_try_from_witness {
735    (@inner [$from_ty:ident: $from_trait:ident], [$into_ty:ident: $into_trait:ident]) => {
736        impl<A: $from_trait + $into_trait> TryFrom<$from_ty<A>> for $into_ty<A> {
737            type Error = ();
738            fn try_from(addr: $from_ty<A>) -> Result<$into_ty<A>, ()> {
739                Witness::<A>::from_witness(addr).ok_or(())
740            }
741        }
742    };
743    ([$from_ty:ident: $from_trait:ident], $([$into_ty:ident: $into_trait:ident]),*) => {
744        $(
745            impl_try_from_witness!(@inner [$from_ty: $from_trait], [$into_ty: $into_trait]);
746        )*
747    }
748}
749
750// SpecifiedAddr
751impl_witness!(SpecifiedAddr, "specified", SpecifiedAddress, is_specified);
752impl_try_from_witness!(
753    [SpecifiedAddr: SpecifiedAddress],
754    [UnicastAddr: UnicastAddress],
755    [MulticastAddr: MulticastAddress],
756    [BroadcastAddr: BroadcastAddress],
757    [LinkLocalAddr: LinkLocalAddress],
758    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
759    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
760    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
761    [NonMappedAddr: MappedAddress]
762);
763
764// UnicastAddr
765impl_witness!(UnicastAddr, "unicast", UnicastAddress, is_unicast);
766impl_into_specified!(UnicastAddr, UnicastAddress, is_unicast);
767impl_nested_witness!(UnicastAddress, UnicastAddr, LinkLocalAddress, LinkLocalAddr);
768impl_nested_witness!(UnicastAddress, UnicastAddr, MappedAddress, NonMappedAddr);
769impl_into_specified_for_nested_witness!(
770    UnicastAddress,
771    UnicastAddr,
772    LinkLocalAddress,
773    LinkLocalAddr
774);
775impl_into_specified_for_nested_witness!(UnicastAddress, UnicastAddr, MappedAddress, NonMappedAddr);
776impl_try_from_witness!(
777    [UnicastAddr: UnicastAddress],
778    [MulticastAddr: MulticastAddress],
779    [BroadcastAddr: BroadcastAddress],
780    [LinkLocalAddr: LinkLocalAddress],
781    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
782    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
783    [NonMappedAddr: MappedAddress]
784);
785
786// MulticastAddr
787impl_witness!(MulticastAddr, "multicast", MulticastAddress, is_multicast);
788impl_into_specified!(MulticastAddr, MulticastAddress, is_multicast);
789impl_nested_witness!(MulticastAddress, MulticastAddr, LinkLocalAddress, LinkLocalAddr);
790impl_nested_witness!(MulticastAddress, MulticastAddr, MappedAddress, NonMappedAddr);
791impl_into_specified_for_nested_witness!(
792    MulticastAddress,
793    MulticastAddr,
794    LinkLocalAddress,
795    LinkLocalAddr
796);
797impl_into_specified_for_nested_witness!(
798    MulticastAddress,
799    MulticastAddr,
800    MappedAddress,
801    NonMappedAddr
802);
803impl_try_from_witness!(
804    [MulticastAddr: MulticastAddress],
805    [UnicastAddr: UnicastAddress],
806    [BroadcastAddr: BroadcastAddress],
807    [LinkLocalAddr: LinkLocalAddress],
808    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
809    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
810    [NonMappedAddr: MappedAddress]
811);
812
813impl<A: MulticastAddress + MappedAddress> MulticastAddr<A> {
814    /// Wraps `self` in the [`NonMappedAddr`] witness type.
815    pub fn non_mapped(self) -> NonMappedAddr<MulticastAddr<A>> {
816        // Safety: IPv4 addresses cannot be mapped. For IPv6 addresses, the
817        // multicast subnet (FF00::/8) and the ipv4-mapped-ipv6 address space
818        // (::FFFF:0000:0000/96) are disjoint: presence in the multicast subnet
819        // implies absence from the ipv4-mapped-ipv6 address space.
820        unsafe { NonMappedAddr::new_unchecked(self) }
821    }
822}
823
824// NonMulticastAddr - An address known to not be multicast.
825//
826// Note this type is similar to `UnicastAddr`, but not identical: all
827// `UnicastAddr' can also be `NonMulticastAddr`, but not all `NonMulticastAddr`
828// can be `UnicastAddr`. E.g. an IPv4 Broadcast Addr is non-multicast but not
829// unicast.
830impl_witness!(NonMulticastAddr, "non-multicast", MulticastAddress, is_non_multicast);
831impl_nested_witness!(MulticastAddress, NonMulticastAddr, SpecifiedAddress, SpecifiedAddr);
832impl_nested_witness!(MulticastAddress, NonMulticastAddr, UnicastAddress, UnicastAddr);
833impl_nested_witness!(MulticastAddress, NonMulticastAddr, BroadcastAddress, BroadcastAddr);
834impl_nested_witness!(MulticastAddress, NonMulticastAddr, MappedAddress, NonMappedAddr);
835// NB: Implement nested witness to a depth of three, only for the types that are
836// actually used by consumers of this library.
837impl_nested_witness!(
838    MulticastAddress,
839    NonMulticastAddr,
840    MappedAddress,
841    NonMappedAddr,
842    SpecifiedAddress,
843    SpecifiedAddr
844);
845impl_into_specified_for_nested_witness!(
846    MulticastAddress,
847    NonMulticastAddr,
848    MappedAddress,
849    NonMappedAddr,
850    SpecifiedAddress,
851    SpecifiedAddr
852);
853
854// BroadcastAddr
855impl_witness!(BroadcastAddr, "broadcast", BroadcastAddress, is_broadcast);
856impl_into_specified!(BroadcastAddr, BroadcastAddress, is_broadcast);
857impl_nested_witness!(BroadcastAddress, BroadcastAddr, LinkLocalAddress, LinkLocalAddr);
858impl_nested_witness!(BroadcastAddress, BroadcastAddr, MappedAddress, NonMappedAddr);
859impl_into_specified_for_nested_witness!(
860    BroadcastAddress,
861    BroadcastAddr,
862    LinkLocalAddress,
863    LinkLocalAddr
864);
865impl_into_specified_for_nested_witness!(
866    BroadcastAddress,
867    BroadcastAddr,
868    MappedAddress,
869    NonMappedAddr
870);
871impl_try_from_witness!(
872    [BroadcastAddr: BroadcastAddress],
873    [UnicastAddr: UnicastAddress],
874    [MulticastAddr: MulticastAddress],
875    [LinkLocalAddr: LinkLocalAddress],
876    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
877    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
878    [NonMappedAddr: MappedAddress]
879);
880
881// LinkLocalAddr
882impl_witness!(LinkLocalAddr, "link-local", LinkLocalAddress, is_link_local);
883impl_into_specified!(LinkLocalAddr, LinkLocalAddress, is_link_local);
884impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, UnicastAddress, UnicastAddr);
885impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, MulticastAddress, MulticastAddr);
886impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, BroadcastAddress, BroadcastAddr);
887impl_nested_witness!(LinkLocalAddress, LinkLocalAddr, MappedAddress, NonMappedAddr);
888impl_into_specified_for_nested_witness!(
889    LinkLocalAddress,
890    LinkLocalAddr,
891    UnicastAddress,
892    UnicastAddr
893);
894impl_into_specified_for_nested_witness!(
895    LinkLocalAddress,
896    LinkLocalAddr,
897    MulticastAddress,
898    MulticastAddr
899);
900impl_into_specified_for_nested_witness!(
901    LinkLocalAddress,
902    LinkLocalAddr,
903    BroadcastAddress,
904    BroadcastAddr
905);
906impl_into_specified_for_nested_witness!(
907    LinkLocalAddress,
908    LinkLocalAddr,
909    MappedAddress,
910    NonMappedAddr
911);
912impl_try_from_witness!(
913    [LinkLocalAddr: LinkLocalAddress],
914    [UnicastAddr: UnicastAddress],
915    [MulticastAddr: MulticastAddress],
916    [BroadcastAddr: BroadcastAddress],
917    [NonMappedAddr: MappedAddress]
918);
919
920// NonMappedAddr
921impl_witness!(NonMappedAddr, "non_mapped", MappedAddress, is_non_mapped);
922impl_nested_witness!(MappedAddress, NonMappedAddr, SpecifiedAddress, SpecifiedAddr);
923impl_nested_witness!(MappedAddress, NonMappedAddr, UnicastAddress, UnicastAddr);
924impl_nested_witness!(MappedAddress, NonMappedAddr, MulticastAddress, MulticastAddr);
925impl_nested_witness!(MappedAddress, NonMappedAddr, BroadcastAddress, BroadcastAddr);
926impl_nested_witness!(MappedAddress, NonMappedAddr, LinkLocalAddress, LinkLocalAddr);
927impl_into_specified_for_nested_witness!(
928    MappedAddress,
929    NonMappedAddr,
930    SpecifiedAddress,
931    SpecifiedAddr
932);
933impl_into_specified_for_nested_witness!(MappedAddress, NonMappedAddr, UnicastAddress, UnicastAddr);
934impl_into_specified_for_nested_witness!(
935    MappedAddress,
936    NonMappedAddr,
937    MulticastAddress,
938    MulticastAddr
939);
940impl_into_specified_for_nested_witness!(
941    MappedAddress,
942    NonMappedAddr,
943    BroadcastAddress,
944    BroadcastAddr
945);
946impl_into_specified_for_nested_witness!(
947    MappedAddress,
948    NonMappedAddr,
949    LinkLocalAddress,
950    LinkLocalAddr
951);
952impl_try_from_witness!(
953    [NonMappedAddr: MappedAddress],
954    [SpecifiedAddr: SpecifiedAddress],
955    [UnicastAddr: UnicastAddress],
956    [MulticastAddr: MulticastAddress],
957    [BroadcastAddr: BroadcastAddress],
958    [LinkLocalAddr: LinkLocalAddress],
959    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
960    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
961    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress]
962);
963
964// NOTE(joshlf): We provide these type aliases both for convenience and also to
965// steer users towards these types and away from `UnicastAddr<LinkLocalAddr<A>>`
966// and `MulticastAddr<LinkLocalAddr<A>>`, which are also valid. The reason we
967// still implement `Witness<A>` for those types is that user code may contain
968// generic contexts (e.g., some code with `UnicastAddr<A>`, and other code which
969// wishes to supply `A = LinkLocalAddr<AA>`), and we want to support that use
970// case.
971
972/// An address that can be link-local and unicast.
973///
974/// `LinkLocalUnicastAddress` is a shorthand for `LinkLocalAddress +
975/// UnicastAddress`.
976pub trait LinkLocalUnicastAddress: LinkLocalAddress + UnicastAddress {}
977impl<A: LinkLocalAddress + UnicastAddress> LinkLocalUnicastAddress for A {}
978
979/// An address that can be link-local and multicast.
980///
981/// `LinkLocalMulticastAddress` is a shorthand for `LinkLocalAddress +
982/// MulticastAddress`.
983pub trait LinkLocalMulticastAddress: LinkLocalAddress + MulticastAddress {}
984impl<A: LinkLocalAddress + MulticastAddress> LinkLocalMulticastAddress for A {}
985
986/// An address that can be link-local and broadcast.
987///
988/// `LinkLocalBroadcastAddress` is a shorthand for `LinkLocalAddress +
989/// BroadcastAddress`.
990pub trait LinkLocalBroadcastAddress: LinkLocalAddress + BroadcastAddress {}
991impl<A: LinkLocalAddress + BroadcastAddress> LinkLocalBroadcastAddress for A {}
992
993/// A link-local unicast address.
994pub type LinkLocalUnicastAddr<A> = LinkLocalAddr<UnicastAddr<A>>;
995
996/// A link-local multicast address.
997pub type LinkLocalMulticastAddr<A> = LinkLocalAddr<MulticastAddr<A>>;
998
999/// A link-local broadcast address.
1000pub type LinkLocalBroadcastAddr<A> = LinkLocalAddr<BroadcastAddr<A>>;
1001
1002impl_try_from_witness!(
1003    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
1004    [UnicastAddr: UnicastAddress],
1005    [MulticastAddr: MulticastAddress],
1006    [LinkLocalAddr: LinkLocalAddress],
1007    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
1008    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress]
1009);
1010impl_try_from_witness!(
1011    [LinkLocalMulticastAddr: LinkLocalMulticastAddress],
1012    [UnicastAddr: UnicastAddress],
1013    [MulticastAddr: MulticastAddress],
1014    [LinkLocalAddr: LinkLocalAddress],
1015    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
1016    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress]
1017);
1018impl_try_from_witness!(
1019    [LinkLocalBroadcastAddr: LinkLocalBroadcastAddress],
1020    [UnicastAddr: UnicastAddress],
1021    [MulticastAddr: MulticastAddress],
1022    [LinkLocalAddr: LinkLocalAddress],
1023    [LinkLocalUnicastAddr: LinkLocalUnicastAddress],
1024    [LinkLocalMulticastAddr: LinkLocalMulticastAddress]
1025);
1026
1027/// A witness type for an address and a scope zone.
1028///
1029/// `AddrAndZone` carries an address that *may* have a scope, alongside the
1030/// particular zone of that scope. The zone is also referred to as a "scope
1031/// identifier" in some systems (such as Linux).
1032///
1033/// Note that although `AddrAndZone` acts as a witness type, it does not
1034/// implement [`Witness`] since it carries both the address and scoping
1035/// information, and not only the witnessed address.
1036#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1037pub struct AddrAndZone<A, Z>(A, Z);
1038
1039impl<A: ScopeableAddress, Z> AddrAndZone<A, Z> {
1040    /// Constructs a new `AddrAndZone`, returning `Some` only if the provided
1041    /// `addr`'s scope can have a zone (`addr.scope().can_have_zone()`).
1042    pub fn new(addr: A, zone: Z) -> Option<Self> {
1043        if addr.scope().can_have_zone() {
1044            Some(Self(addr, zone))
1045        } else {
1046            None
1047        }
1048    }
1049}
1050
1051impl<A: ScopeableAddress + IpAddress, Z> AddrAndZone<A, Z> {
1052    /// Constructs a new `AddrAndZone`, returning `Some` only if the provided
1053    /// `addr`'s scope can have a zone (`addr.scope().can_have_zone()`) and
1054    /// `addr` is not a loopback address.
1055    pub fn new_not_loopback(addr: A, zone: Z) -> Option<Self> {
1056        if addr.scope().can_have_zone() && !addr.is_loopback() {
1057            Some(Self(addr, zone))
1058        } else {
1059            None
1060        }
1061    }
1062}
1063
1064impl<A, Z> AddrAndZone<A, Z> {
1065    /// Constructs a new `AddrAndZone` without checking to see if `addr`'s scope
1066    /// can have a zone.
1067    ///
1068    /// # Safety
1069    ///
1070    /// It is up to the caller to make sure that `addr`'s scope can have a zone
1071    /// to avoid breaking the guarantees of `AddrAndZone`.
1072    #[inline]
1073    pub const unsafe fn new_unchecked(addr: A, zone: Z) -> Self {
1074        Self(addr, zone)
1075    }
1076
1077    /// Consumes this `AddrAndZone`, returning the address and zone separately.
1078    pub fn into_addr_scope_id(self) -> (A, Z) {
1079        let AddrAndZone(addr, zone) = self;
1080        (addr, zone)
1081    }
1082
1083    /// Translates the zone identifier using the provided function.
1084    pub fn map_zone<Y>(self, f: impl FnOnce(Z) -> Y) -> AddrAndZone<A, Y> {
1085        let AddrAndZone(addr, zone) = self;
1086        AddrAndZone(addr, f(zone))
1087    }
1088
1089    /// Translates the address using `f`.
1090    pub fn map_addr<B>(self, f: impl FnOnce(A) -> B) -> AddrAndZone<B, Z> {
1091        let Self(addr, zone) = self;
1092        AddrAndZone(f(addr), zone)
1093    }
1094
1095    /// Attempts to translate the zone identifier using the provided function.
1096    pub fn try_map_zone<Y, E>(
1097        self,
1098        f: impl FnOnce(Z) -> Result<Y, E>,
1099    ) -> Result<AddrAndZone<A, Y>, E> {
1100        let AddrAndZone(addr, zone) = self;
1101        f(zone).map(|zone| AddrAndZone(addr, zone))
1102    }
1103
1104    /// Accesses the addr for this `AddrAndZone`.
1105    pub fn addr(&self) -> A
1106    where
1107        A: Copy,
1108    {
1109        let AddrAndZone(addr, _zone) = self;
1110        *addr
1111    }
1112
1113    /// Converts from `AddrAndZone<A, Z>` to `AddrAndZone<&A, &Z>`.
1114    pub fn as_ref(&self) -> AddrAndZone<&A, &Z> {
1115        let Self(addr, zone) = self;
1116        AddrAndZone(addr, zone)
1117    }
1118}
1119
1120impl<A: Display, Z: Display> Display for AddrAndZone<A, Z> {
1121    #[inline]
1122    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1123        write!(f, "{}%{}", self.0, self.1)
1124    }
1125}
1126
1127impl<A, Z> sealed::Sealed for AddrAndZone<A, Z> {}
1128
1129impl<A: SpecifiedAddress, Z> From<AddrAndZone<SpecifiedAddr<A>, Z>> for AddrAndZone<A, Z> {
1130    fn from(AddrAndZone(addr, zone): AddrAndZone<SpecifiedAddr<A>, Z>) -> Self {
1131        Self(addr.into_addr(), zone)
1132    }
1133}
1134
1135/// An address that may have an associated scope zone.
1136#[allow(missing_docs)]
1137#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1138pub enum ZonedAddr<A, Z> {
1139    Unzoned(A),
1140    Zoned(AddrAndZone<A, Z>),
1141}
1142
1143impl<A: Display, Z: Display> Display for ZonedAddr<A, Z> {
1144    #[inline]
1145    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1146        match self {
1147            Self::Unzoned(addr) => write!(f, "{addr}"),
1148            Self::Zoned(addr_and_zone) => write!(f, "{addr_and_zone}"),
1149        }
1150    }
1151}
1152
1153impl<A, Z> ZonedAddr<A, Z> {
1154    /// Decomposes this `ZonedAddr` into an addr and an optional scope zone.
1155    pub fn into_addr_zone(self) -> (A, Option<Z>) {
1156        match self {
1157            ZonedAddr::Unzoned(addr) => (addr, None),
1158            ZonedAddr::Zoned(scope_and_zone) => {
1159                let (addr, zone) = scope_and_zone.into_addr_scope_id();
1160                (addr, Some(zone))
1161            }
1162        }
1163    }
1164
1165    /// Accesses the addr for this `ZonedAddr`.
1166    pub fn addr(&self) -> A
1167    where
1168        A: Copy,
1169    {
1170        match self {
1171            ZonedAddr::Unzoned(addr) => *addr,
1172            ZonedAddr::Zoned(addr_and_zone) => addr_and_zone.addr(),
1173        }
1174    }
1175
1176    /// Translates the zone identifier using the provided function.
1177    pub fn map_zone<Y>(self, f: impl FnOnce(Z) -> Y) -> ZonedAddr<A, Y> {
1178        match self {
1179            ZonedAddr::Unzoned(u) => ZonedAddr::Unzoned(u),
1180            ZonedAddr::Zoned(z) => ZonedAddr::Zoned(z.map_zone(f)),
1181        }
1182    }
1183
1184    /// Translates the address using `f`.
1185    pub fn map_addr<B>(self, f: impl FnOnce(A) -> B) -> ZonedAddr<B, Z> {
1186        match self {
1187            Self::Unzoned(u) => ZonedAddr::Unzoned(f(u)),
1188            Self::Zoned(z) => ZonedAddr::Zoned(z.map_addr(f)),
1189        }
1190    }
1191
1192    /// Converts from `&ZonedAddr<A, Z>` to `ZonedAddr<&A, &Z>`.
1193    pub fn as_ref(&self) -> ZonedAddr<&A, &Z> {
1194        match self {
1195            Self::Unzoned(u) => ZonedAddr::Unzoned(u),
1196            Self::Zoned(z) => ZonedAddr::Zoned(z.as_ref()),
1197        }
1198    }
1199}
1200
1201impl<A: ScopeableAddress, Z> ZonedAddr<A, Z> {
1202    /// Creates a new `ZonedAddr` with the provided optional scope zone.
1203    ///
1204    /// If `zone` is `None`, [`ZonedAddr::Unzoned`] is returned. Otherwise, a
1205    /// [`ZonedAddr::Zoned`] is returned only if the provided `addr`'s scope can
1206    /// have a zone (`addr.scope().can_have_zone()`).
1207    pub fn new(addr: A, zone: Option<Z>) -> Option<Self> {
1208        match zone {
1209            Some(zone) => AddrAndZone::new(addr, zone).map(ZonedAddr::Zoned),
1210            None => Some(ZonedAddr::Unzoned(addr)),
1211        }
1212    }
1213}
1214
1215impl<A: IpAddress + ScopeableAddress, Z: Clone> ZonedAddr<A, Z> {
1216    /// Creates a [`ZonedAddr::Zoned`] iff `addr` can have a zone and is not
1217    /// loopback.
1218    ///
1219    /// `get_zone` is only called if the address needs a zone.
1220    pub fn new_zoned_if_necessary(addr: A, get_zone: impl FnOnce() -> Z) -> Self {
1221        match AddrAndZone::new_not_loopback(addr, ()) {
1222            Some(addr_and_zone) => Self::Zoned(addr_and_zone.map_zone(move |()| get_zone())),
1223            None => Self::Unzoned(addr),
1224        }
1225    }
1226}
1227
1228impl<A: ScopeableAddress<Scope = ()>, Z> ZonedAddr<A, Z> {
1229    /// Retrieves the addr for this `ZonedAddr` when the `Scope` is `()`.
1230    ///
1231    /// `()` is a known implementation that never allows `AddrAndZone` to be
1232    /// constructed so we can safely drop the zone information.
1233    pub fn into_unzoned(self) -> A {
1234        match self {
1235            ZonedAddr::Unzoned(u) => u,
1236            ZonedAddr::Zoned(_z) => unreachable!(),
1237        }
1238    }
1239}
1240
1241impl<A, Z> From<AddrAndZone<A, Z>> for ZonedAddr<A, Z> {
1242    fn from(a: AddrAndZone<A, Z>) -> Self {
1243        Self::Zoned(a)
1244    }
1245}
1246
1247impl<A: SpecifiedAddress, Z> From<ZonedAddr<SpecifiedAddr<A>, Z>> for ZonedAddr<A, Z> {
1248    fn from(zoned_addr: ZonedAddr<SpecifiedAddr<A>, Z>) -> Self {
1249        match zoned_addr {
1250            ZonedAddr::Unzoned(a) => Self::Unzoned(a.into_addr()),
1251            ZonedAddr::Zoned(z) => Self::Zoned(z.into()),
1252        }
1253    }
1254}
1255
1256impl<A, I: Ip> GenericOverIp<I> for SpecifiedAddr<A> {
1257    type Type = SpecifiedAddr<I::Addr>;
1258}
1259
1260impl<A: IpAddress, I: Ip> GenericOverIp<I> for MulticastAddr<A> {
1261    type Type = MulticastAddr<I::Addr>;
1262}
1263
1264impl<A: GenericOverIp<I>, I: Ip, Z> GenericOverIp<I> for ZonedAddr<A, Z> {
1265    type Type = ZonedAddr<A::Type, Z>;
1266}
1267
1268impl<A: GenericOverIp<I>, I: Ip, Z> GenericOverIp<I> for AddrAndZone<A, Z> {
1269    type Type = AddrAndZone<A::Type, Z>;
1270}
1271
1272/// Provides a `Display` implementation for printing an address and a port.
1273#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1274pub struct AddrAndPortFormatter<A, P, I: Ip> {
1275    addr: A,
1276    port: P,
1277    _marker: IpVersionMarker<I>,
1278}
1279
1280impl<A, P, I: Ip> AddrAndPortFormatter<A, P, I> {
1281    /// Construct a new `AddrAndPortFormatter`.
1282    pub fn new(addr: A, port: P) -> Self {
1283        Self { addr, port, _marker: IpVersionMarker::new() }
1284    }
1285}
1286
1287impl<A: Display, P: Display, I: Ip> Display for AddrAndPortFormatter<A, P, I> {
1288    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1289        let Self { addr, port, _marker } = self;
1290        let IpInvariant(result) = I::map_ip(
1291            IpInvariant((addr, port, f)),
1292            |IpInvariant((addr, port, f))| IpInvariant(write!(f, "{}:{}", addr, port)),
1293            |IpInvariant((addr, port, f))| IpInvariant(write!(f, "[{}]:{}", addr, port)),
1294        );
1295        result
1296    }
1297}
1298
1299#[cfg(test)]
1300mod tests {
1301    use super::*;
1302
1303    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
1304    enum Address {
1305        Unspecified,
1306        GlobalUnicast,
1307        GlobalMulticast,
1308        GlobalBroadcast,
1309        LinkLocalUnicast,
1310        LinkLocalMulticast,
1311        LinkLocalBroadcast,
1312        MappedUnicast,
1313        MappedMulticast,
1314        MappedBroadcast,
1315    }
1316
1317    impl SpecifiedAddress for Address {
1318        fn is_specified(&self) -> bool {
1319            *self != Address::Unspecified
1320        }
1321    }
1322
1323    impl UnicastAddress for Address {
1324        fn is_unicast(&self) -> bool {
1325            use Address::*;
1326            match self {
1327                GlobalUnicast | LinkLocalUnicast | MappedUnicast => true,
1328                Unspecified | GlobalMulticast | GlobalBroadcast | LinkLocalMulticast
1329                | LinkLocalBroadcast | MappedMulticast | MappedBroadcast => false,
1330            }
1331        }
1332    }
1333
1334    impl MulticastAddress for Address {
1335        fn is_multicast(&self) -> bool {
1336            use Address::*;
1337            match self {
1338                GlobalMulticast | LinkLocalMulticast | MappedMulticast => true,
1339                Unspecified | GlobalUnicast | GlobalBroadcast | LinkLocalUnicast
1340                | MappedUnicast | MappedBroadcast | LinkLocalBroadcast => false,
1341            }
1342        }
1343    }
1344
1345    impl BroadcastAddress for Address {
1346        fn is_broadcast(&self) -> bool {
1347            use Address::*;
1348            match self {
1349                GlobalBroadcast | LinkLocalBroadcast | MappedBroadcast => true,
1350                Unspecified | GlobalUnicast | GlobalMulticast | LinkLocalUnicast
1351                | MappedUnicast | MappedMulticast | LinkLocalMulticast => false,
1352            }
1353        }
1354    }
1355
1356    impl LinkLocalAddress for Address {
1357        fn is_link_local(&self) -> bool {
1358            use Address::*;
1359            match self {
1360                LinkLocalUnicast | LinkLocalMulticast | LinkLocalBroadcast => true,
1361                Unspecified | GlobalUnicast | GlobalMulticast | GlobalBroadcast | MappedUnicast
1362                | MappedBroadcast | MappedMulticast => false,
1363            }
1364        }
1365    }
1366
1367    impl MappedAddress for Address {
1368        fn is_non_mapped(&self) -> bool {
1369            use Address::*;
1370            match self {
1371                MappedUnicast | MappedBroadcast | MappedMulticast => false,
1372                Unspecified | GlobalUnicast | GlobalMulticast | GlobalBroadcast
1373                | LinkLocalUnicast | LinkLocalMulticast | LinkLocalBroadcast => true,
1374            }
1375        }
1376    }
1377
1378    #[derive(Copy, Clone, Eq, PartialEq)]
1379    enum AddressScope {
1380        LinkLocal,
1381        Global,
1382    }
1383
1384    impl Scope for AddressScope {
1385        fn can_have_zone(&self) -> bool {
1386            matches!(self, AddressScope::LinkLocal)
1387        }
1388    }
1389
1390    impl ScopeableAddress for Address {
1391        type Scope = AddressScope;
1392
1393        fn scope(&self) -> AddressScope {
1394            if self.is_link_local() {
1395                AddressScope::LinkLocal
1396            } else {
1397                AddressScope::Global
1398            }
1399        }
1400    }
1401
1402    #[test]
1403    fn specified_addr() {
1404        assert_eq!(
1405            SpecifiedAddr::new(Address::GlobalUnicast),
1406            Some(SpecifiedAddr(Address::GlobalUnicast))
1407        );
1408        assert_eq!(SpecifiedAddr::new(Address::Unspecified), None);
1409    }
1410
1411    #[test]
1412    fn unicast_addr() {
1413        assert_eq!(
1414            UnicastAddr::new(Address::GlobalUnicast),
1415            Some(UnicastAddr(Address::GlobalUnicast))
1416        );
1417        assert_eq!(UnicastAddr::new(Address::GlobalMulticast), None);
1418        assert_eq!(
1419            unsafe { UnicastAddr::new_unchecked(Address::GlobalUnicast) },
1420            UnicastAddr(Address::GlobalUnicast)
1421        );
1422    }
1423
1424    #[test]
1425    fn multicast_addr() {
1426        assert_eq!(
1427            MulticastAddr::new(Address::GlobalMulticast),
1428            Some(MulticastAddr(Address::GlobalMulticast))
1429        );
1430        assert_eq!(MulticastAddr::new(Address::GlobalUnicast), None);
1431        assert_eq!(
1432            unsafe { MulticastAddr::new_unchecked(Address::GlobalMulticast) },
1433            MulticastAddr(Address::GlobalMulticast)
1434        );
1435    }
1436
1437    #[test]
1438    fn broadcast_addr() {
1439        assert_eq!(
1440            BroadcastAddr::new(Address::GlobalBroadcast),
1441            Some(BroadcastAddr(Address::GlobalBroadcast))
1442        );
1443        assert_eq!(BroadcastAddr::new(Address::GlobalUnicast), None);
1444        assert_eq!(
1445            unsafe { BroadcastAddr::new_unchecked(Address::GlobalBroadcast) },
1446            BroadcastAddr(Address::GlobalBroadcast)
1447        );
1448    }
1449
1450    #[test]
1451    fn link_local_addr() {
1452        assert_eq!(
1453            LinkLocalAddr::new(Address::LinkLocalUnicast),
1454            Some(LinkLocalAddr(Address::LinkLocalUnicast))
1455        );
1456        assert_eq!(LinkLocalAddr::new(Address::GlobalMulticast), None);
1457        assert_eq!(
1458            unsafe { LinkLocalAddr::new_unchecked(Address::LinkLocalUnicast) },
1459            LinkLocalAddr(Address::LinkLocalUnicast)
1460        );
1461    }
1462
1463    #[test]
1464    fn non_mapped_addr() {
1465        assert_eq!(
1466            NonMappedAddr::new(Address::LinkLocalUnicast),
1467            Some(NonMappedAddr(Address::LinkLocalUnicast))
1468        );
1469        assert_eq!(NonMappedAddr::new(Address::MappedUnicast), None);
1470        assert_eq!(
1471            NonMappedAddr::new(Address::LinkLocalMulticast),
1472            Some(NonMappedAddr(Address::LinkLocalMulticast))
1473        );
1474        assert_eq!(NonMappedAddr::new(Address::MappedMulticast), None);
1475        assert_eq!(
1476            NonMappedAddr::new(Address::LinkLocalBroadcast),
1477            Some(NonMappedAddr(Address::LinkLocalBroadcast))
1478        );
1479        assert_eq!(NonMappedAddr::new(Address::MappedBroadcast), None);
1480    }
1481
1482    macro_rules! test_nested {
1483        ($outer:ident, $inner:ident, $($input:ident => $output:expr,)*) => {
1484            $(
1485                assert_eq!($inner::new(Address::$input).and_then($outer::new), $output);
1486            )*
1487        };
1488    }
1489
1490    #[test]
1491    fn nested_link_local() {
1492        // Test UnicastAddr<LinkLocalAddr>, MulticastAddr<LinkLocalAddr>,
1493        // BroadcastAddr<LinkLocalAddr>, LinkLocalAddr<UnicastAddr>,
1494        // LinkLocalAddr<MulticastAddr>, LinkLocalAddr<BroadcastAddr>.
1495
1496        // Unicast
1497        test_nested!(
1498            UnicastAddr,
1499            LinkLocalAddr,
1500            Unspecified => None,
1501            GlobalUnicast => None,
1502            GlobalMulticast => None,
1503            LinkLocalUnicast => Some(UnicastAddr(LinkLocalAddr(Address::LinkLocalUnicast))),
1504            LinkLocalMulticast => None,
1505            LinkLocalBroadcast => None,
1506        );
1507
1508        // Multicast
1509        test_nested!(
1510            MulticastAddr,
1511            LinkLocalAddr,
1512            Unspecified => None,
1513            GlobalUnicast => None,
1514            GlobalMulticast => None,
1515            LinkLocalUnicast => None,
1516            LinkLocalMulticast => Some(MulticastAddr(LinkLocalAddr(Address::LinkLocalMulticast))),
1517            LinkLocalBroadcast => None,
1518        );
1519
1520        // Broadcast
1521        test_nested!(
1522            BroadcastAddr,
1523            LinkLocalAddr,
1524            Unspecified => None,
1525            GlobalUnicast => None,
1526            GlobalMulticast => None,
1527            LinkLocalUnicast => None,
1528            LinkLocalMulticast => None,
1529            LinkLocalBroadcast => Some(BroadcastAddr(LinkLocalAddr(Address::LinkLocalBroadcast))),
1530        );
1531
1532        // Link-local
1533        test_nested!(
1534            LinkLocalAddr,
1535            UnicastAddr,
1536            Unspecified => None,
1537            GlobalUnicast => None,
1538            GlobalMulticast => None,
1539            LinkLocalUnicast => Some(LinkLocalAddr(UnicastAddr(Address::LinkLocalUnicast))),
1540            LinkLocalMulticast => None,
1541            LinkLocalBroadcast => None,
1542        );
1543        test_nested!(
1544            LinkLocalAddr,
1545            MulticastAddr,
1546            Unspecified => None,
1547            GlobalUnicast => None,
1548            GlobalMulticast => None,
1549            LinkLocalUnicast => None,
1550            LinkLocalMulticast => Some(LinkLocalAddr(MulticastAddr(Address::LinkLocalMulticast))),
1551            LinkLocalBroadcast => None,
1552        );
1553        test_nested!(
1554            LinkLocalAddr,
1555            BroadcastAddr,
1556            Unspecified => None,
1557            GlobalUnicast => None,
1558            GlobalMulticast => None,
1559            LinkLocalUnicast => None,
1560            LinkLocalMulticast => None,
1561            LinkLocalBroadcast => Some(LinkLocalAddr(BroadcastAddr(Address::LinkLocalBroadcast))),
1562        );
1563    }
1564
1565    #[test]
1566    fn nested_non_mapped() {
1567        // Test:
1568        //   UnicastAddr<NonMappedAddr>, NonMappedAddr<UnicastAddr>,
1569        //   MulticastAddr<NonMappedAddr>, NonMappedAddr<MulticastAddr>,
1570        //   BroadcastAddr<NonMappedAddr>, NonMappedAddr<BroadcastAddr>,
1571
1572        // Unicast
1573        test_nested!(
1574            UnicastAddr,
1575            NonMappedAddr,
1576            Unspecified => None,
1577            LinkLocalUnicast => Some(UnicastAddr(NonMappedAddr(Address::LinkLocalUnicast))),
1578            LinkLocalMulticast => None,
1579            LinkLocalBroadcast => None,
1580            MappedUnicast => None,
1581            MappedMulticast => None,
1582            MappedBroadcast => None,
1583        );
1584
1585        // Multicast
1586        test_nested!(
1587            MulticastAddr,
1588            NonMappedAddr,
1589            Unspecified => None,
1590            LinkLocalUnicast => None,
1591            LinkLocalMulticast => Some(MulticastAddr(NonMappedAddr(Address::LinkLocalMulticast))),
1592            LinkLocalBroadcast => None,
1593            MappedUnicast => None,
1594            MappedMulticast => None,
1595            MappedBroadcast => None,
1596        );
1597
1598        // Broadcast
1599        test_nested!(
1600            BroadcastAddr,
1601            NonMappedAddr,
1602            Unspecified => None,
1603            LinkLocalUnicast => None,
1604            LinkLocalMulticast => None,
1605            LinkLocalBroadcast => Some(BroadcastAddr(NonMappedAddr(Address::LinkLocalBroadcast))),
1606            MappedUnicast => None,
1607            MappedMulticast => None,
1608            MappedBroadcast => None,
1609        );
1610
1611        // non-mapped
1612        test_nested!(
1613            NonMappedAddr,
1614            UnicastAddr,
1615            Unspecified => None,
1616            LinkLocalUnicast => Some(NonMappedAddr(UnicastAddr(Address::LinkLocalUnicast))),
1617            LinkLocalMulticast => None,
1618            LinkLocalBroadcast => None,
1619            MappedUnicast => None,
1620            MappedMulticast => None,
1621            MappedBroadcast => None,
1622        );
1623        test_nested!(
1624            NonMappedAddr,
1625            MulticastAddr,
1626            Unspecified => None,
1627            LinkLocalUnicast => None,
1628            LinkLocalMulticast => Some(NonMappedAddr(MulticastAddr(Address::LinkLocalMulticast))),
1629            LinkLocalBroadcast => None,
1630            MappedUnicast => None,
1631            MappedMulticast => None,
1632            MappedBroadcast => None,
1633        );
1634        test_nested!(
1635            NonMappedAddr,
1636            BroadcastAddr,
1637            Unspecified => None,
1638            LinkLocalUnicast => None,
1639            LinkLocalMulticast => None,
1640            LinkLocalBroadcast => Some(NonMappedAddr(BroadcastAddr(Address::LinkLocalBroadcast))),
1641            MappedUnicast => None,
1642            MappedMulticast => None,
1643            MappedBroadcast => None,
1644        );
1645    }
1646
1647    #[test]
1648    fn addr_and_zone() {
1649        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, ());
1650        assert_eq!(addr_and_zone, Some(AddrAndZone(Address::LinkLocalUnicast, ())));
1651        assert_eq!(addr_and_zone.unwrap().into_addr_scope_id(), (Address::LinkLocalUnicast, ()));
1652        assert_eq!(AddrAndZone::new(Address::GlobalUnicast, ()), None);
1653        assert_eq!(
1654            unsafe { AddrAndZone::new_unchecked(Address::LinkLocalUnicast, ()) },
1655            AddrAndZone(Address::LinkLocalUnicast, ())
1656        );
1657    }
1658
1659    #[test]
1660    fn addr_and_zone_map_zone() {
1661        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 65).unwrap();
1662        assert_eq!(
1663            addr_and_zone.map_zone(|x| char::from_u32(x).unwrap()),
1664            AddrAndZone::new(Address::LinkLocalUnicast, 'A').unwrap()
1665        );
1666    }
1667
1668    #[test]
1669    fn addr_and_zone_try_map_zone() {
1670        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 32).unwrap();
1671        assert_eq!(
1672            addr_and_zone.try_map_zone(|x| Ok::<_, ()>(x + 1)),
1673            Ok(AddrAndZone::new(Address::LinkLocalUnicast, 33).unwrap())
1674        );
1675
1676        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 32).unwrap();
1677        assert_eq!(addr_and_zone.try_map_zone(|x| Err::<i32, _>(x - 1)), Err(31),);
1678    }
1679
1680    #[test]
1681    fn scoped_address() {
1682        // Type alias to help the compiler when the scope type can't be
1683        // inferred.
1684        type ZonedAddr = crate::ZonedAddr<Address, ()>;
1685        assert_eq!(
1686            ZonedAddr::new(Address::GlobalUnicast, None),
1687            Some(ZonedAddr::Unzoned(Address::GlobalUnicast))
1688        );
1689        assert_eq!(
1690            ZonedAddr::new(Address::Unspecified, None).unwrap().into_addr_zone(),
1691            (Address::Unspecified, None)
1692        );
1693        assert_eq!(
1694            ZonedAddr::new(Address::LinkLocalUnicast, None),
1695            Some(ZonedAddr::Unzoned(Address::LinkLocalUnicast))
1696        );
1697        assert_eq!(ZonedAddr::new(Address::GlobalUnicast, Some(())), None);
1698        assert_eq!(ZonedAddr::new(Address::Unspecified, Some(())), None);
1699        assert_eq!(
1700            ZonedAddr::new(Address::LinkLocalUnicast, Some(())),
1701            Some(ZonedAddr::Zoned(AddrAndZone(Address::LinkLocalUnicast, ())))
1702        );
1703
1704        assert_eq!(
1705            ZonedAddr::new(Address::GlobalUnicast, None).unwrap().into_addr_zone(),
1706            (Address::GlobalUnicast, None)
1707        );
1708        assert_eq!(
1709            ZonedAddr::new(Address::LinkLocalUnicast, Some(())).unwrap().into_addr_zone(),
1710            (Address::LinkLocalUnicast, Some(()))
1711        );
1712    }
1713
1714    #[test]
1715    fn transpose_with_fully_qualified_types() {
1716        let addr: SpecifiedAddr<NonMappedAddr<Address>> =
1717            <NonMappedAddr<SpecifiedAddr<Address>> as Witness<SpecifiedAddr<Address>>>::transpose::<
1718                Address,
1719            >(
1720                NonMappedAddr::new(
1721                    SpecifiedAddr::new(Address::LinkLocalUnicast)
1722                        .expect("should be specified addr"),
1723                )
1724                .expect("should be non-mapped addr"),
1725            );
1726        assert_eq!(
1727            addr,
1728            SpecifiedAddr::new(
1729                NonMappedAddr::new(Address::LinkLocalUnicast).expect("should be non-mapped addr")
1730            )
1731            .expect("should be specified addr")
1732        )
1733    }
1734
1735    #[test]
1736    fn transpose_with_inferred_types() {
1737        assert_eq!(
1738            NonMappedAddr::new(
1739                SpecifiedAddr::new(Address::LinkLocalUnicast).expect("should be specified addr")
1740            )
1741            .expect("should be non-mapped addr")
1742            .transpose(),
1743            SpecifiedAddr::new(
1744                NonMappedAddr::new(Address::LinkLocalUnicast).expect("should be non-mapped addr")
1745            )
1746            .expect("should be specified addr")
1747        )
1748    }
1749}