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_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() { Some(Self(addr, zone)) } else { None }
1044    }
1045}
1046
1047impl<A: ScopeableAddress + IpAddress, Z> AddrAndZone<A, Z> {
1048    /// Constructs a new `AddrAndZone`, returning `Some` only if the provided
1049    /// `addr`'s scope can have a zone (`addr.scope().can_have_zone()`) and
1050    /// `addr` is not a loopback address.
1051    pub fn new_not_loopback(addr: A, zone: Z) -> Option<Self> {
1052        if addr.scope().can_have_zone() && !addr.is_loopback() {
1053            Some(Self(addr, zone))
1054        } else {
1055            None
1056        }
1057    }
1058}
1059
1060impl<A, Z> AddrAndZone<A, Z> {
1061    /// Constructs a new `AddrAndZone` without checking to see if `addr`'s scope
1062    /// can have a zone.
1063    ///
1064    /// # Safety
1065    ///
1066    /// It is up to the caller to make sure that `addr`'s scope can have a zone
1067    /// to avoid breaking the guarantees of `AddrAndZone`.
1068    #[inline]
1069    pub const unsafe fn new_unchecked(addr: A, zone: Z) -> Self {
1070        Self(addr, zone)
1071    }
1072
1073    /// Consumes this `AddrAndZone`, returning the address and zone separately.
1074    pub fn into_addr_scope_id(self) -> (A, Z) {
1075        let AddrAndZone(addr, zone) = self;
1076        (addr, zone)
1077    }
1078
1079    /// Translates the zone identifier using the provided function.
1080    pub fn map_zone<Y>(self, f: impl FnOnce(Z) -> Y) -> AddrAndZone<A, Y> {
1081        let AddrAndZone(addr, zone) = self;
1082        AddrAndZone(addr, f(zone))
1083    }
1084
1085    /// Translates the address using `f`.
1086    pub fn map_addr<B>(self, f: impl FnOnce(A) -> B) -> AddrAndZone<B, Z> {
1087        let Self(addr, zone) = self;
1088        AddrAndZone(f(addr), zone)
1089    }
1090
1091    /// Attempts to translate the zone identifier using the provided function.
1092    pub fn try_map_zone<Y, E>(
1093        self,
1094        f: impl FnOnce(Z) -> Result<Y, E>,
1095    ) -> Result<AddrAndZone<A, Y>, E> {
1096        let AddrAndZone(addr, zone) = self;
1097        f(zone).map(|zone| AddrAndZone(addr, zone))
1098    }
1099
1100    /// Accesses the addr for this `AddrAndZone`.
1101    pub fn addr(&self) -> A
1102    where
1103        A: Copy,
1104    {
1105        let AddrAndZone(addr, _zone) = self;
1106        *addr
1107    }
1108
1109    /// Converts from `AddrAndZone<A, Z>` to `AddrAndZone<&A, &Z>`.
1110    pub fn as_ref(&self) -> AddrAndZone<&A, &Z> {
1111        let Self(addr, zone) = self;
1112        AddrAndZone(addr, zone)
1113    }
1114}
1115
1116impl<A: Display, Z: Display> Display for AddrAndZone<A, Z> {
1117    #[inline]
1118    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1119        write!(f, "{}%{}", self.0, self.1)
1120    }
1121}
1122
1123impl<A, Z> sealed::Sealed for AddrAndZone<A, Z> {}
1124
1125impl<A: SpecifiedAddress, Z> From<AddrAndZone<SpecifiedAddr<A>, Z>> for AddrAndZone<A, Z> {
1126    fn from(AddrAndZone(addr, zone): AddrAndZone<SpecifiedAddr<A>, Z>) -> Self {
1127        Self(addr.into_addr(), zone)
1128    }
1129}
1130
1131/// An address that may have an associated scope zone.
1132#[allow(missing_docs)]
1133#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1134pub enum ZonedAddr<A, Z> {
1135    Unzoned(A),
1136    Zoned(AddrAndZone<A, Z>),
1137}
1138
1139impl<A: Display, Z: Display> Display for ZonedAddr<A, Z> {
1140    #[inline]
1141    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1142        match self {
1143            Self::Unzoned(addr) => write!(f, "{addr}"),
1144            Self::Zoned(addr_and_zone) => write!(f, "{addr_and_zone}"),
1145        }
1146    }
1147}
1148
1149impl<A, Z> ZonedAddr<A, Z> {
1150    /// Decomposes this `ZonedAddr` into an addr and an optional scope zone.
1151    pub fn into_addr_zone(self) -> (A, Option<Z>) {
1152        match self {
1153            ZonedAddr::Unzoned(addr) => (addr, None),
1154            ZonedAddr::Zoned(scope_and_zone) => {
1155                let (addr, zone) = scope_and_zone.into_addr_scope_id();
1156                (addr, Some(zone))
1157            }
1158        }
1159    }
1160
1161    /// Accesses the addr for this `ZonedAddr`.
1162    pub fn addr(&self) -> A
1163    where
1164        A: Copy,
1165    {
1166        match self {
1167            ZonedAddr::Unzoned(addr) => *addr,
1168            ZonedAddr::Zoned(addr_and_zone) => addr_and_zone.addr(),
1169        }
1170    }
1171
1172    /// Translates the zone identifier using the provided function.
1173    pub fn map_zone<Y>(self, f: impl FnOnce(Z) -> Y) -> ZonedAddr<A, Y> {
1174        match self {
1175            ZonedAddr::Unzoned(u) => ZonedAddr::Unzoned(u),
1176            ZonedAddr::Zoned(z) => ZonedAddr::Zoned(z.map_zone(f)),
1177        }
1178    }
1179
1180    /// Translates the address using `f`.
1181    pub fn map_addr<B>(self, f: impl FnOnce(A) -> B) -> ZonedAddr<B, Z> {
1182        match self {
1183            Self::Unzoned(u) => ZonedAddr::Unzoned(f(u)),
1184            Self::Zoned(z) => ZonedAddr::Zoned(z.map_addr(f)),
1185        }
1186    }
1187
1188    /// Converts from `&ZonedAddr<A, Z>` to `ZonedAddr<&A, &Z>`.
1189    pub fn as_ref(&self) -> ZonedAddr<&A, &Z> {
1190        match self {
1191            Self::Unzoned(u) => ZonedAddr::Unzoned(u),
1192            Self::Zoned(z) => ZonedAddr::Zoned(z.as_ref()),
1193        }
1194    }
1195}
1196
1197impl<A: ScopeableAddress, Z> ZonedAddr<A, Z> {
1198    /// Creates a new `ZonedAddr` with the provided optional scope zone.
1199    ///
1200    /// If `zone` is `None`, [`ZonedAddr::Unzoned`] is returned. Otherwise, a
1201    /// [`ZonedAddr::Zoned`] is returned only if the provided `addr`'s scope can
1202    /// have a zone (`addr.scope().can_have_zone()`).
1203    pub fn new(addr: A, zone: Option<Z>) -> Option<Self> {
1204        match zone {
1205            Some(zone) => AddrAndZone::new(addr, zone).map(ZonedAddr::Zoned),
1206            None => Some(ZonedAddr::Unzoned(addr)),
1207        }
1208    }
1209}
1210
1211impl<A: IpAddress + ScopeableAddress, Z: Clone> ZonedAddr<A, Z> {
1212    /// Creates a [`ZonedAddr::Zoned`] iff `addr` can have a zone and is not
1213    /// loopback.
1214    ///
1215    /// `get_zone` is only called if the address needs a zone.
1216    pub fn new_zoned_if_necessary(addr: A, get_zone: impl FnOnce() -> Z) -> Self {
1217        match AddrAndZone::new_not_loopback(addr, ()) {
1218            Some(addr_and_zone) => Self::Zoned(addr_and_zone.map_zone(move |()| get_zone())),
1219            None => Self::Unzoned(addr),
1220        }
1221    }
1222}
1223
1224impl<A: ScopeableAddress<Scope = ()>, Z> ZonedAddr<A, Z> {
1225    /// Retrieves the addr for this `ZonedAddr` when the `Scope` is `()`.
1226    ///
1227    /// `()` is a known implementation that never allows `AddrAndZone` to be
1228    /// constructed so we can safely drop the zone information.
1229    pub fn into_unzoned(self) -> A {
1230        match self {
1231            ZonedAddr::Unzoned(u) => u,
1232            ZonedAddr::Zoned(_z) => unreachable!(),
1233        }
1234    }
1235}
1236
1237impl<A, Z> From<AddrAndZone<A, Z>> for ZonedAddr<A, Z> {
1238    fn from(a: AddrAndZone<A, Z>) -> Self {
1239        Self::Zoned(a)
1240    }
1241}
1242
1243impl<A: SpecifiedAddress, Z> From<ZonedAddr<SpecifiedAddr<A>, Z>> for ZonedAddr<A, Z> {
1244    fn from(zoned_addr: ZonedAddr<SpecifiedAddr<A>, Z>) -> Self {
1245        match zoned_addr {
1246            ZonedAddr::Unzoned(a) => Self::Unzoned(a.into_addr()),
1247            ZonedAddr::Zoned(z) => Self::Zoned(z.into()),
1248        }
1249    }
1250}
1251
1252impl<A, I: Ip> GenericOverIp<I> for SpecifiedAddr<A> {
1253    type Type = SpecifiedAddr<I::Addr>;
1254}
1255
1256impl<A: IpAddress, I: Ip> GenericOverIp<I> for MulticastAddr<A> {
1257    type Type = MulticastAddr<I::Addr>;
1258}
1259
1260impl<A: GenericOverIp<I>, I: Ip, Z> GenericOverIp<I> for ZonedAddr<A, Z> {
1261    type Type = ZonedAddr<A::Type, Z>;
1262}
1263
1264impl<A: GenericOverIp<I>, I: Ip, Z> GenericOverIp<I> for AddrAndZone<A, Z> {
1265    type Type = AddrAndZone<A::Type, Z>;
1266}
1267
1268/// Provides a `Display` implementation for printing an address and a port.
1269#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1270pub struct AddrAndPortFormatter<A, P, I: Ip> {
1271    addr: A,
1272    port: P,
1273    _marker: IpVersionMarker<I>,
1274}
1275
1276impl<A, P, I: Ip> AddrAndPortFormatter<A, P, I> {
1277    /// Construct a new `AddrAndPortFormatter`.
1278    pub fn new(addr: A, port: P) -> Self {
1279        Self { addr, port, _marker: IpVersionMarker::new() }
1280    }
1281}
1282
1283impl<A: Display, P: Display, I: Ip> Display for AddrAndPortFormatter<A, P, I> {
1284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1285        let Self { addr, port, _marker } = self;
1286        let IpInvariant(result) = I::map_ip(
1287            IpInvariant((addr, port, f)),
1288            |IpInvariant((addr, port, f))| IpInvariant(write!(f, "{}:{}", addr, port)),
1289            |IpInvariant((addr, port, f))| IpInvariant(write!(f, "[{}]:{}", addr, port)),
1290        );
1291        result
1292    }
1293}
1294
1295#[cfg(test)]
1296mod tests {
1297    use super::*;
1298
1299    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
1300    enum Address {
1301        Unspecified,
1302        GlobalUnicast,
1303        GlobalMulticast,
1304        GlobalBroadcast,
1305        LinkLocalUnicast,
1306        LinkLocalMulticast,
1307        LinkLocalBroadcast,
1308        MappedUnicast,
1309        MappedMulticast,
1310        MappedBroadcast,
1311    }
1312
1313    impl SpecifiedAddress for Address {
1314        fn is_specified(&self) -> bool {
1315            *self != Address::Unspecified
1316        }
1317    }
1318
1319    impl UnicastAddress for Address {
1320        fn is_unicast(&self) -> bool {
1321            use Address::*;
1322            match self {
1323                GlobalUnicast | LinkLocalUnicast | MappedUnicast => true,
1324                Unspecified | GlobalMulticast | GlobalBroadcast | LinkLocalMulticast
1325                | LinkLocalBroadcast | MappedMulticast | MappedBroadcast => false,
1326            }
1327        }
1328    }
1329
1330    impl MulticastAddress for Address {
1331        fn is_multicast(&self) -> bool {
1332            use Address::*;
1333            match self {
1334                GlobalMulticast | LinkLocalMulticast | MappedMulticast => true,
1335                Unspecified | GlobalUnicast | GlobalBroadcast | LinkLocalUnicast
1336                | MappedUnicast | MappedBroadcast | LinkLocalBroadcast => false,
1337            }
1338        }
1339    }
1340
1341    impl BroadcastAddress for Address {
1342        fn is_broadcast(&self) -> bool {
1343            use Address::*;
1344            match self {
1345                GlobalBroadcast | LinkLocalBroadcast | MappedBroadcast => true,
1346                Unspecified | GlobalUnicast | GlobalMulticast | LinkLocalUnicast
1347                | MappedUnicast | MappedMulticast | LinkLocalMulticast => false,
1348            }
1349        }
1350    }
1351
1352    impl LinkLocalAddress for Address {
1353        fn is_link_local(&self) -> bool {
1354            use Address::*;
1355            match self {
1356                LinkLocalUnicast | LinkLocalMulticast | LinkLocalBroadcast => true,
1357                Unspecified | GlobalUnicast | GlobalMulticast | GlobalBroadcast | MappedUnicast
1358                | MappedBroadcast | MappedMulticast => false,
1359            }
1360        }
1361    }
1362
1363    impl MappedAddress for Address {
1364        fn is_non_mapped(&self) -> bool {
1365            use Address::*;
1366            match self {
1367                MappedUnicast | MappedBroadcast | MappedMulticast => false,
1368                Unspecified | GlobalUnicast | GlobalMulticast | GlobalBroadcast
1369                | LinkLocalUnicast | LinkLocalMulticast | LinkLocalBroadcast => true,
1370            }
1371        }
1372    }
1373
1374    #[derive(Copy, Clone, Eq, PartialEq)]
1375    enum AddressScope {
1376        LinkLocal,
1377        Global,
1378    }
1379
1380    impl Scope for AddressScope {
1381        fn can_have_zone(&self) -> bool {
1382            matches!(self, AddressScope::LinkLocal)
1383        }
1384    }
1385
1386    impl ScopeableAddress for Address {
1387        type Scope = AddressScope;
1388
1389        fn scope(&self) -> AddressScope {
1390            if self.is_link_local() { AddressScope::LinkLocal } else { AddressScope::Global }
1391        }
1392    }
1393
1394    #[test]
1395    fn specified_addr() {
1396        assert_eq!(
1397            SpecifiedAddr::new(Address::GlobalUnicast),
1398            Some(SpecifiedAddr(Address::GlobalUnicast))
1399        );
1400        assert_eq!(SpecifiedAddr::new(Address::Unspecified), None);
1401    }
1402
1403    #[test]
1404    fn unicast_addr() {
1405        assert_eq!(
1406            UnicastAddr::new(Address::GlobalUnicast),
1407            Some(UnicastAddr(Address::GlobalUnicast))
1408        );
1409        assert_eq!(UnicastAddr::new(Address::GlobalMulticast), None);
1410        assert_eq!(
1411            unsafe { UnicastAddr::new_unchecked(Address::GlobalUnicast) },
1412            UnicastAddr(Address::GlobalUnicast)
1413        );
1414    }
1415
1416    #[test]
1417    fn multicast_addr() {
1418        assert_eq!(
1419            MulticastAddr::new(Address::GlobalMulticast),
1420            Some(MulticastAddr(Address::GlobalMulticast))
1421        );
1422        assert_eq!(MulticastAddr::new(Address::GlobalUnicast), None);
1423        assert_eq!(
1424            unsafe { MulticastAddr::new_unchecked(Address::GlobalMulticast) },
1425            MulticastAddr(Address::GlobalMulticast)
1426        );
1427    }
1428
1429    #[test]
1430    fn broadcast_addr() {
1431        assert_eq!(
1432            BroadcastAddr::new(Address::GlobalBroadcast),
1433            Some(BroadcastAddr(Address::GlobalBroadcast))
1434        );
1435        assert_eq!(BroadcastAddr::new(Address::GlobalUnicast), None);
1436        assert_eq!(
1437            unsafe { BroadcastAddr::new_unchecked(Address::GlobalBroadcast) },
1438            BroadcastAddr(Address::GlobalBroadcast)
1439        );
1440    }
1441
1442    #[test]
1443    fn link_local_addr() {
1444        assert_eq!(
1445            LinkLocalAddr::new(Address::LinkLocalUnicast),
1446            Some(LinkLocalAddr(Address::LinkLocalUnicast))
1447        );
1448        assert_eq!(LinkLocalAddr::new(Address::GlobalMulticast), None);
1449        assert_eq!(
1450            unsafe { LinkLocalAddr::new_unchecked(Address::LinkLocalUnicast) },
1451            LinkLocalAddr(Address::LinkLocalUnicast)
1452        );
1453    }
1454
1455    #[test]
1456    fn non_mapped_addr() {
1457        assert_eq!(
1458            NonMappedAddr::new(Address::LinkLocalUnicast),
1459            Some(NonMappedAddr(Address::LinkLocalUnicast))
1460        );
1461        assert_eq!(NonMappedAddr::new(Address::MappedUnicast), None);
1462        assert_eq!(
1463            NonMappedAddr::new(Address::LinkLocalMulticast),
1464            Some(NonMappedAddr(Address::LinkLocalMulticast))
1465        );
1466        assert_eq!(NonMappedAddr::new(Address::MappedMulticast), None);
1467        assert_eq!(
1468            NonMappedAddr::new(Address::LinkLocalBroadcast),
1469            Some(NonMappedAddr(Address::LinkLocalBroadcast))
1470        );
1471        assert_eq!(NonMappedAddr::new(Address::MappedBroadcast), None);
1472    }
1473
1474    macro_rules! test_nested {
1475        ($outer:ident, $inner:ident, $($input:ident => $output:expr,)*) => {
1476            $(
1477                assert_eq!($inner::new(Address::$input).and_then($outer::new), $output);
1478            )*
1479        };
1480    }
1481
1482    #[test]
1483    fn nested_link_local() {
1484        // Test UnicastAddr<LinkLocalAddr>, MulticastAddr<LinkLocalAddr>,
1485        // BroadcastAddr<LinkLocalAddr>, LinkLocalAddr<UnicastAddr>,
1486        // LinkLocalAddr<MulticastAddr>, LinkLocalAddr<BroadcastAddr>.
1487
1488        // Unicast
1489        test_nested!(
1490            UnicastAddr,
1491            LinkLocalAddr,
1492            Unspecified => None,
1493            GlobalUnicast => None,
1494            GlobalMulticast => None,
1495            LinkLocalUnicast => Some(UnicastAddr(LinkLocalAddr(Address::LinkLocalUnicast))),
1496            LinkLocalMulticast => None,
1497            LinkLocalBroadcast => None,
1498        );
1499
1500        // Multicast
1501        test_nested!(
1502            MulticastAddr,
1503            LinkLocalAddr,
1504            Unspecified => None,
1505            GlobalUnicast => None,
1506            GlobalMulticast => None,
1507            LinkLocalUnicast => None,
1508            LinkLocalMulticast => Some(MulticastAddr(LinkLocalAddr(Address::LinkLocalMulticast))),
1509            LinkLocalBroadcast => None,
1510        );
1511
1512        // Broadcast
1513        test_nested!(
1514            BroadcastAddr,
1515            LinkLocalAddr,
1516            Unspecified => None,
1517            GlobalUnicast => None,
1518            GlobalMulticast => None,
1519            LinkLocalUnicast => None,
1520            LinkLocalMulticast => None,
1521            LinkLocalBroadcast => Some(BroadcastAddr(LinkLocalAddr(Address::LinkLocalBroadcast))),
1522        );
1523
1524        // Link-local
1525        test_nested!(
1526            LinkLocalAddr,
1527            UnicastAddr,
1528            Unspecified => None,
1529            GlobalUnicast => None,
1530            GlobalMulticast => None,
1531            LinkLocalUnicast => Some(LinkLocalAddr(UnicastAddr(Address::LinkLocalUnicast))),
1532            LinkLocalMulticast => None,
1533            LinkLocalBroadcast => None,
1534        );
1535        test_nested!(
1536            LinkLocalAddr,
1537            MulticastAddr,
1538            Unspecified => None,
1539            GlobalUnicast => None,
1540            GlobalMulticast => None,
1541            LinkLocalUnicast => None,
1542            LinkLocalMulticast => Some(LinkLocalAddr(MulticastAddr(Address::LinkLocalMulticast))),
1543            LinkLocalBroadcast => None,
1544        );
1545        test_nested!(
1546            LinkLocalAddr,
1547            BroadcastAddr,
1548            Unspecified => None,
1549            GlobalUnicast => None,
1550            GlobalMulticast => None,
1551            LinkLocalUnicast => None,
1552            LinkLocalMulticast => None,
1553            LinkLocalBroadcast => Some(LinkLocalAddr(BroadcastAddr(Address::LinkLocalBroadcast))),
1554        );
1555    }
1556
1557    #[test]
1558    fn nested_non_mapped() {
1559        // Test:
1560        //   UnicastAddr<NonMappedAddr>, NonMappedAddr<UnicastAddr>,
1561        //   MulticastAddr<NonMappedAddr>, NonMappedAddr<MulticastAddr>,
1562        //   BroadcastAddr<NonMappedAddr>, NonMappedAddr<BroadcastAddr>,
1563
1564        // Unicast
1565        test_nested!(
1566            UnicastAddr,
1567            NonMappedAddr,
1568            Unspecified => None,
1569            LinkLocalUnicast => Some(UnicastAddr(NonMappedAddr(Address::LinkLocalUnicast))),
1570            LinkLocalMulticast => None,
1571            LinkLocalBroadcast => None,
1572            MappedUnicast => None,
1573            MappedMulticast => None,
1574            MappedBroadcast => None,
1575        );
1576
1577        // Multicast
1578        test_nested!(
1579            MulticastAddr,
1580            NonMappedAddr,
1581            Unspecified => None,
1582            LinkLocalUnicast => None,
1583            LinkLocalMulticast => Some(MulticastAddr(NonMappedAddr(Address::LinkLocalMulticast))),
1584            LinkLocalBroadcast => None,
1585            MappedUnicast => None,
1586            MappedMulticast => None,
1587            MappedBroadcast => None,
1588        );
1589
1590        // Broadcast
1591        test_nested!(
1592            BroadcastAddr,
1593            NonMappedAddr,
1594            Unspecified => None,
1595            LinkLocalUnicast => None,
1596            LinkLocalMulticast => None,
1597            LinkLocalBroadcast => Some(BroadcastAddr(NonMappedAddr(Address::LinkLocalBroadcast))),
1598            MappedUnicast => None,
1599            MappedMulticast => None,
1600            MappedBroadcast => None,
1601        );
1602
1603        // non-mapped
1604        test_nested!(
1605            NonMappedAddr,
1606            UnicastAddr,
1607            Unspecified => None,
1608            LinkLocalUnicast => Some(NonMappedAddr(UnicastAddr(Address::LinkLocalUnicast))),
1609            LinkLocalMulticast => None,
1610            LinkLocalBroadcast => None,
1611            MappedUnicast => None,
1612            MappedMulticast => None,
1613            MappedBroadcast => None,
1614        );
1615        test_nested!(
1616            NonMappedAddr,
1617            MulticastAddr,
1618            Unspecified => None,
1619            LinkLocalUnicast => None,
1620            LinkLocalMulticast => Some(NonMappedAddr(MulticastAddr(Address::LinkLocalMulticast))),
1621            LinkLocalBroadcast => None,
1622            MappedUnicast => None,
1623            MappedMulticast => None,
1624            MappedBroadcast => None,
1625        );
1626        test_nested!(
1627            NonMappedAddr,
1628            BroadcastAddr,
1629            Unspecified => None,
1630            LinkLocalUnicast => None,
1631            LinkLocalMulticast => None,
1632            LinkLocalBroadcast => Some(NonMappedAddr(BroadcastAddr(Address::LinkLocalBroadcast))),
1633            MappedUnicast => None,
1634            MappedMulticast => None,
1635            MappedBroadcast => None,
1636        );
1637    }
1638
1639    #[test]
1640    fn addr_and_zone() {
1641        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, ());
1642        assert_eq!(addr_and_zone, Some(AddrAndZone(Address::LinkLocalUnicast, ())));
1643        assert_eq!(addr_and_zone.unwrap().into_addr_scope_id(), (Address::LinkLocalUnicast, ()));
1644        assert_eq!(AddrAndZone::new(Address::GlobalUnicast, ()), None);
1645        assert_eq!(
1646            unsafe { AddrAndZone::new_unchecked(Address::LinkLocalUnicast, ()) },
1647            AddrAndZone(Address::LinkLocalUnicast, ())
1648        );
1649    }
1650
1651    #[test]
1652    fn addr_and_zone_map_zone() {
1653        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 65).unwrap();
1654        assert_eq!(
1655            addr_and_zone.map_zone(|x| char::from_u32(x).unwrap()),
1656            AddrAndZone::new(Address::LinkLocalUnicast, 'A').unwrap()
1657        );
1658    }
1659
1660    #[test]
1661    fn addr_and_zone_try_map_zone() {
1662        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 32).unwrap();
1663        assert_eq!(
1664            addr_and_zone.try_map_zone(|x| Ok::<_, ()>(x + 1)),
1665            Ok(AddrAndZone::new(Address::LinkLocalUnicast, 33).unwrap())
1666        );
1667
1668        let addr_and_zone = AddrAndZone::new(Address::LinkLocalUnicast, 32).unwrap();
1669        assert_eq!(addr_and_zone.try_map_zone(|x| Err::<i32, _>(x - 1)), Err(31),);
1670    }
1671
1672    #[test]
1673    fn scoped_address() {
1674        // Type alias to help the compiler when the scope type can't be
1675        // inferred.
1676        type ZonedAddr = crate::ZonedAddr<Address, ()>;
1677        assert_eq!(
1678            ZonedAddr::new(Address::GlobalUnicast, None),
1679            Some(ZonedAddr::Unzoned(Address::GlobalUnicast))
1680        );
1681        assert_eq!(
1682            ZonedAddr::new(Address::Unspecified, None).unwrap().into_addr_zone(),
1683            (Address::Unspecified, None)
1684        );
1685        assert_eq!(
1686            ZonedAddr::new(Address::LinkLocalUnicast, None),
1687            Some(ZonedAddr::Unzoned(Address::LinkLocalUnicast))
1688        );
1689        assert_eq!(ZonedAddr::new(Address::GlobalUnicast, Some(())), None);
1690        assert_eq!(ZonedAddr::new(Address::Unspecified, Some(())), None);
1691        assert_eq!(
1692            ZonedAddr::new(Address::LinkLocalUnicast, Some(())),
1693            Some(ZonedAddr::Zoned(AddrAndZone(Address::LinkLocalUnicast, ())))
1694        );
1695
1696        assert_eq!(
1697            ZonedAddr::new(Address::GlobalUnicast, None).unwrap().into_addr_zone(),
1698            (Address::GlobalUnicast, None)
1699        );
1700        assert_eq!(
1701            ZonedAddr::new(Address::LinkLocalUnicast, Some(())).unwrap().into_addr_zone(),
1702            (Address::LinkLocalUnicast, Some(()))
1703        );
1704    }
1705
1706    #[test]
1707    fn transpose_with_fully_qualified_types() {
1708        let addr: SpecifiedAddr<NonMappedAddr<Address>> =
1709            <NonMappedAddr<SpecifiedAddr<Address>> as Witness<SpecifiedAddr<Address>>>::transpose::<
1710                Address,
1711            >(
1712                NonMappedAddr::new(
1713                    SpecifiedAddr::new(Address::LinkLocalUnicast)
1714                        .expect("should be specified addr"),
1715                )
1716                .expect("should be non-mapped addr"),
1717            );
1718        assert_eq!(
1719            addr,
1720            SpecifiedAddr::new(
1721                NonMappedAddr::new(Address::LinkLocalUnicast).expect("should be non-mapped addr")
1722            )
1723            .expect("should be specified addr")
1724        )
1725    }
1726
1727    #[test]
1728    fn transpose_with_inferred_types() {
1729        assert_eq!(
1730            NonMappedAddr::new(
1731                SpecifiedAddr::new(Address::LinkLocalUnicast).expect("should be specified addr")
1732            )
1733            .expect("should be non-mapped addr")
1734            .transpose(),
1735            SpecifiedAddr::new(
1736                NonMappedAddr::new(Address::LinkLocalUnicast).expect("should be non-mapped addr")
1737            )
1738            .expect("should be specified addr")
1739        )
1740    }
1741}