cuprate_types/address_type.rs
1//! Types of network addresses; used in P2P.
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "epee")]
7use cuprate_epee_encoding::{
8 error,
9 macros::bytes::{Buf, BufMut},
10 EpeeValue, Marker,
11};
12
13use strum::{
14 AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
15};
16
17/// An enumeration of address types.
18///
19/// Used in `cuprate_p2p` and `cuprate_types`
20///
21/// Original definition:
22/// - <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/epee/include/net/enums.h/#L49>
23///
24/// # Serde
25/// This type's `serde` implementation (de)serializes from a [`u8`].
26///
27/// ```rust
28/// use cuprate_types::AddressType as A;
29/// use serde_json::{to_string, from_str};
30///
31/// assert_eq!(from_str::<A>(&"0").unwrap(), A::Invalid);
32/// assert_eq!(from_str::<A>(&"1").unwrap(), A::Ipv4);
33/// assert_eq!(from_str::<A>(&"2").unwrap(), A::Ipv6);
34/// assert_eq!(from_str::<A>(&"3").unwrap(), A::I2p);
35/// assert_eq!(from_str::<A>(&"4").unwrap(), A::Tor);
36///
37/// assert_eq!(to_string(&A::Invalid).unwrap(), "0");
38/// assert_eq!(to_string(&A::Ipv4).unwrap(), "1");
39/// assert_eq!(to_string(&A::Ipv6).unwrap(), "2");
40/// assert_eq!(to_string(&A::I2p).unwrap(), "3");
41/// assert_eq!(to_string(&A::Tor).unwrap(), "4");
42/// ```
43#[derive(
44 Copy,
45 Clone,
46 Default,
47 Debug,
48 PartialEq,
49 Eq,
50 PartialOrd,
51 Ord,
52 Hash,
53 AsRefStr,
54 Display,
55 EnumCount,
56 EnumIs,
57 EnumString,
58 FromRepr,
59 IntoStaticStr,
60 VariantArray,
61)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(feature = "serde", serde(untagged, try_from = "u8", into = "u8"))]
64#[repr(u8)]
65pub enum AddressType {
66 #[default]
67 Invalid,
68 Ipv4,
69 Ipv6,
70 I2p,
71 Tor,
72}
73
74impl AddressType {
75 /// Convert [`Self`] to a [`u8`].
76 ///
77 /// ```rust
78 /// use cuprate_types::AddressType as A;
79 ///
80 /// assert_eq!(A::Invalid.to_u8(), 0);
81 /// assert_eq!(A::Ipv4.to_u8(), 1);
82 /// assert_eq!(A::Ipv6.to_u8(), 2);
83 /// assert_eq!(A::I2p.to_u8(), 3);
84 /// assert_eq!(A::Tor.to_u8(), 4);
85 /// ```
86 pub const fn to_u8(self) -> u8 {
87 self as u8
88 }
89
90 /// Convert a [`u8`] to a [`Self`].
91 ///
92 /// # Errors
93 /// This returns [`None`] if `u > 4`.
94 ///
95 /// ```rust
96 /// use cuprate_types::AddressType as A;
97 ///
98 /// assert_eq!(A::from_u8(0), Some(A::Invalid));
99 /// assert_eq!(A::from_u8(1), Some(A::Ipv4));
100 /// assert_eq!(A::from_u8(2), Some(A::Ipv6));
101 /// assert_eq!(A::from_u8(3), Some(A::I2p));
102 /// assert_eq!(A::from_u8(4), Some(A::Tor));
103 /// assert_eq!(A::from_u8(5), None);
104 /// ```
105 pub const fn from_u8(u: u8) -> Option<Self> {
106 Some(match u {
107 0 => Self::Invalid,
108 1 => Self::Ipv4,
109 2 => Self::Ipv6,
110 3 => Self::I2p,
111 4 => Self::Tor,
112 _ => return None,
113 })
114 }
115}
116
117impl From<AddressType> for u8 {
118 fn from(value: AddressType) -> Self {
119 value.to_u8()
120 }
121}
122
123impl TryFrom<u8> for AddressType {
124 type Error = u8;
125 fn try_from(value: u8) -> Result<Self, Self::Error> {
126 match Self::from_u8(value) {
127 Some(s) => Ok(s),
128 None => Err(value),
129 }
130 }
131}
132
133#[cfg(feature = "epee")]
134impl EpeeValue for AddressType {
135 const MARKER: Marker = u8::MARKER;
136
137 fn read<B: Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
138 let u = u8::read(r, marker)?;
139 Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 4"))
140 }
141
142 fn write<B: BufMut>(self, w: &mut B) -> error::Result<()> {
143 let u = self.to_u8();
144 u8::write(u, w)?;
145 Ok(())
146 }
147}