| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use core::fmt::{self, Display, Formatter}; |
| use core::ops::Deref; |
| |
| // NOTE: The "witness" types UnicastAddr and MulticastAddr - which provide the |
| // invariant that the value they contain is a unicast or multicast address |
| // respectively - cannot actually guarantee this property without certain |
| // promises from the implementations of the UnicastAddress and MulticastAddress |
| // traits that they rely on. In particular, the values must be "immutable" in |
| // the sense that, given only immutable references to the values, nothing about |
| // the values can change such that the "unicast-ness" or "multicast-ness" of the |
| // values change. Since the UnicastAddress and MulticastAddress traits are not |
| // unsafe traits, it would be unsound for unsafe code to rely for its soundness |
| // on this behavior. For a more in-depth discussion of why this isn't possible |
| // without an explicit opt-in on the part of the trait implementor, see this |
| // forum thread: https://users.rust-lang.org/t/prevent-interior-mutability/29403 |
| |
| /// Addresses that can be unicast. |
| /// |
| /// `UnicastAddress` is implemented by address types for which some values are |
| /// considered "unicast" addresses. It is only implemented for addresses whose |
| /// unicast-ness can be determined by looking only at the address itself (this |
| /// is notably not true for IPv4 addresses, which can be considered broadcast |
| /// addresses depending on the subnet in which they are used). |
| pub(crate) trait UnicastAddress { |
| /// Is this a unicast address? |
| /// |
| /// `is_unicast` must maintain the invariant that, if it is called twice on |
| /// the same object, and in between those two calls, no code has operated on |
| /// a mutable reference to that object, both calls will return the same |
| /// value. This property is required in order to implement [`UnicastAddr`]. |
| /// Note that, since this is not an `unsafe` trait, `unsafe` code may NOT |
| /// rely on this property for its soundness. However, code MAY rely on this |
| /// property for its correctness. |
| fn is_unicast(&self) -> bool; |
| } |
| |
| /// Addresses that can be multicast. |
| /// |
| /// `MulticastAddress` is implemented by address types for which some values are |
| /// considered "multicast" addresses. |
| pub(crate) trait MulticastAddress { |
| /// Is this a unicast address? |
| /// |
| /// `is_multicast` must maintain the invariant that, if it is called twice |
| /// on the same object, and in between those two calls, no code has operated |
| /// on a mutable reference to that object, both calls will return the same |
| /// value. This property is required in order to implement |
| /// [`MulticastAddr`]. Note that, since this is not an `unsafe` trait, |
| /// `unsafe` code may NOT rely on this property for its soundness. However, |
| /// code MAY rely on this property for its correctness. |
| fn is_multicast(&self) -> bool; |
| } |
| |
| /// Addresses that can be broadcast. |
| /// |
| /// `BroadcastAddress` is implemented by address types for which some values are |
| /// considered "broadcast" addresses. |
| pub(crate) trait BroadcastAddress { |
| /// Is this a broadcast address? |
| fn is_broadcast(&self) -> bool; |
| } |
| |
| /// An address which is guaranteed to be a unicast address. |
| /// |
| /// `UnicastAddr` wraps an address of type `A` and guarantees that it is a |
| /// unicast address. Note that this guarantee is contingent on a correct |
| /// implementation of the [`UnicastAddress`]. Since that trait is not `unsafe`, |
| /// `unsafe` code may NOT rely for its soundness on this guarantee. |
| #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] |
| pub(crate) struct UnicastAddr<A: UnicastAddress>(A); |
| |
| impl<A: UnicastAddress> UnicastAddr<A> { |
| /// Construct a new `UnicastAddr`. |
| /// |
| /// `new` returns `None` if `addr` is not a unicast address according to |
| /// [`UnicastAddr::is_unicast`]. |
| pub(crate) fn new(addr: A) -> Option<UnicastAddr<A>> { |
| if !addr.is_unicast() { |
| return None; |
| } |
| Some(UnicastAddr(addr)) |
| } |
| } |
| |
| impl<A: UnicastAddress + Clone> UnicastAddr<A> { |
| /// Get a clone of the address. |
| pub(crate) fn get(&self) -> A { |
| self.0.clone() |
| } |
| } |
| |
| impl<A: UnicastAddress> Deref for UnicastAddr<A> { |
| type Target = A; |
| |
| fn deref(&self) -> &A { |
| &self.0 |
| } |
| } |
| |
| impl<A: UnicastAddress + Display> Display for UnicastAddr<A> { |
| fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| self.0.fmt(f) |
| } |
| } |
| |
| /// An address which is guaranteed to be a multicast address. |
| /// |
| /// `MulticastAddr` wraps an address of type `A` and guarantees that it is a |
| /// multicast address. Note that this guarantee is contingent on a correct |
| /// implementation of the [`MulticastAddress`]. Since that trait is not |
| /// `unsafe`, `unsafe` code may NOT rely for its soundness on this guarantee. |
| #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] |
| pub(crate) struct MulticastAddr<A: MulticastAddress>(A); |
| |
| impl<A: MulticastAddress> MulticastAddr<A> { |
| /// Construct a new `MulticastAddr`. |
| /// |
| /// `new` returns `None` if `addr` is not a multicast address according to |
| /// [`MulticastAddr::is_multicast`]. |
| pub(crate) fn new(addr: A) -> Option<MulticastAddr<A>> { |
| if !addr.is_multicast() { |
| return None; |
| } |
| Some(MulticastAddr(addr)) |
| } |
| } |
| |
| impl<A: MulticastAddress + Clone> MulticastAddr<A> { |
| /// Get a clone of the address. |
| pub(crate) fn get(&self) -> A { |
| self.0.clone() |
| } |
| } |
| |
| impl<A: MulticastAddress> Deref for MulticastAddr<A> { |
| type Target = A; |
| |
| fn deref(&self) -> &A { |
| &self.0 |
| } |
| } |
| |
| impl<A: MulticastAddress + Display> Display for MulticastAddr<A> { |
| fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| self.0.fmt(f) |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
| enum Address { |
| Unicast, |
| Multicast, |
| } |
| |
| impl UnicastAddress for Address { |
| fn is_unicast(&self) -> bool { |
| *self == Address::Unicast |
| } |
| } |
| |
| impl MulticastAddress for Address { |
| fn is_multicast(&self) -> bool { |
| *self == Address::Multicast |
| } |
| } |
| |
| #[test] |
| fn test_unicast_addr() { |
| assert_eq!(UnicastAddr::new(Address::Unicast), Some(UnicastAddr(Address::Unicast))); |
| assert_eq!(UnicastAddr::new(Address::Multicast), None); |
| } |
| |
| #[test] |
| fn test_multicast_addr() { |
| assert_eq!(MulticastAddr::new(Address::Multicast), Some(MulticastAddr(Address::Multicast))); |
| assert_eq!(MulticastAddr::new(Address::Unicast), None); |
| } |
| } |