ip/any/
interface.rs

1use core::fmt;
2use core::str::FromStr;
3
4#[cfg(any(test, feature = "arbitrary"))]
5use proptest::{
6    arbitrary::{any, Arbitrary},
7    prop_oneof,
8    strategy::{BoxedStrategy, Strategy},
9};
10
11use super::{delegate, Address, Prefix, PrefixLength};
12use crate::{
13    concrete::{self, Ipv4, Ipv6},
14    error::Error,
15    traits,
16};
17
18/// Either an IPv4 or IPv6 interface.
19///
20/// # Memory Use
21///
22/// Rust enums are sized to accomodate their largest variant, with smaller
23/// variants being padded to fill up any unused space.
24///
25/// As a result, users should avoid using this type in a context where only
26/// [`Interface::Ipv4`] variants are expected.
27///
28/// # Examples
29///
30/// ``` rust
31/// use ip::{
32///     traits::{Address as _, Interface as _},
33///     Any, Interface,
34/// };
35///
36/// let interface = "192.0.2.0/24".parse::<Interface<Any>>()?;
37///
38/// assert!(interface.network().is_documentation());
39/// # Ok::<(), ip::Error>(())
40/// ```
41#[allow(variant_size_differences)]
42#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
43pub enum Interface {
44    /// IPv4 interface variant.
45    Ipv4(concrete::Interface<Ipv4>),
46    /// IPv6 interface variant.
47    Ipv6(concrete::Interface<Ipv6>),
48}
49
50impl traits::Interface for Interface {
51    type Address = Address;
52    type Prefix = Prefix;
53    type PrefixLength = PrefixLength;
54
55    delegate! {
56        fn network(&self) -> Self::Address;
57        fn addr(&self) -> Self::Address;
58        fn trunc(&self) -> Self::Prefix;
59        fn prefix_len(&self) -> Self::PrefixLength;
60        fn broadcast(&self) -> Self::Address;
61    }
62}
63
64impl From<concrete::Interface<Ipv4>> for Interface {
65    fn from(interface: concrete::Interface<Ipv4>) -> Self {
66        Self::Ipv4(interface)
67    }
68}
69
70impl From<concrete::Interface<Ipv6>> for Interface {
71    fn from(interface: concrete::Interface<Ipv6>) -> Self {
72        Self::Ipv6(interface)
73    }
74}
75
76impl FromStr for Interface {
77    type Err = Error;
78
79    fn from_str(s: &str) -> Result<Self, Self::Err> {
80        concrete::Interface::<Ipv4>::from_str(s)
81            .map(Self::from)
82            .or_else(|_| concrete::Interface::<Ipv6>::from_str(s).map(Self::from))
83    }
84}
85
86impl fmt::Display for Interface {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match self {
89            Self::Ipv4(interface) => interface.fmt(f),
90            Self::Ipv6(interface) => interface.fmt(f),
91        }
92    }
93}
94
95#[cfg(any(test, feature = "arbitrary"))]
96impl Arbitrary for Interface {
97    type Parameters = ();
98    type Strategy = BoxedStrategy<Self>;
99
100    fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
101        prop_oneof![
102            any::<concrete::Interface<Ipv4>>().prop_map(Self::Ipv4),
103            any::<concrete::Interface<Ipv6>>().prop_map(Self::Ipv6),
104        ]
105        .boxed()
106    }
107}