koibumi_node/
net.rs

1//! Types for handling bootstrap domain names.
2
3use std::{convert::TryFrom, fmt, str::FromStr};
4
5use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
6
7use koibumi_core::net::SocketAddrExt;
8use koibumi_net::{
9    domain::{ParseSocketDomainError, SocketDomain},
10    socks::SocketAddr as SocksSocketAddr,
11};
12
13/// A bootstrap socket address or an extended socket address.
14#[derive(Clone, PartialEq, Eq, Hash, Debug)]
15pub enum SocketAddrNode {
16    /// An extended socket address.
17    AddrExt(SocketAddrExt),
18    /// A socket domain name.
19    Domain(SocketDomain),
20}
21
22impl fmt::Display for SocketAddrNode {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::AddrExt(addr) => addr.fmt(f),
26            Self::Domain(domain) => domain.fmt(f),
27        }
28    }
29}
30
31impl Serialize for SocketAddrNode {
32    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
33    where
34        S: Serializer,
35    {
36        serializer.serialize_str(&self.to_string())
37    }
38}
39
40impl<'de> Deserialize<'de> for SocketAddrNode {
41    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
42    where
43        D: Deserializer<'de>,
44    {
45        let s = String::deserialize(deserializer)?;
46        s.parse().map_err(de::Error::custom)
47    }
48}
49
50impl From<SocketAddrExt> for SocketAddrNode {
51    fn from(addr: SocketAddrExt) -> Self {
52        Self::AddrExt(addr)
53    }
54}
55
56impl From<SocketDomain> for SocketAddrNode {
57    fn from(domain: SocketDomain) -> Self {
58        Self::Domain(domain)
59    }
60}
61
62/// The error type returned when a conversion from a Bootstrap socket domain name
63/// to a SOCKS socket address fails.
64///
65/// This error is used as the error type for the `TryFrom` implementation
66/// for `SocksSocketAddr`.
67#[derive(Clone, PartialEq, Eq, Debug)]
68pub enum TryFromSocketAddrNodeError {
69    /// Could not convert the socket domain name to an extended socket address.
70    Domain(SocketDomain),
71}
72
73impl fmt::Display for TryFromSocketAddrNodeError {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        match self {
76            Self::Domain(domain) => write!(
77                f,
78                "could not convert {} to an extended socket address",
79                domain
80            ),
81        }
82    }
83}
84
85impl std::error::Error for TryFromSocketAddrNodeError {}
86
87impl TryFrom<SocketAddrNode> for SocketAddrExt {
88    type Error = TryFromSocketAddrNodeError;
89
90    fn try_from(addr: SocketAddrNode) -> Result<Self, <Self as TryFrom<SocketAddrNode>>::Error> {
91        match addr {
92            SocketAddrNode::AddrExt(addr) => Ok(addr),
93            SocketAddrNode::Domain(domain) => Err(TryFromSocketAddrNodeError::Domain(domain)),
94        }
95    }
96}
97
98/// An error which can be returned
99/// when parsing a socket address for a node.
100///
101/// This error is used as the error type for the `FromStr` implementation
102/// for [`SocketAddrNode`].
103///
104/// [`SocketAddrNode`]: enum.SocketAddrNode.html
105#[derive(Clone, PartialEq, Eq, Debug)]
106pub enum ParseSocketAddrNodeError {
107    /// An error was caught when parsing a socket domain name.
108    /// The actual error caught is returned
109    /// as a payload of this variant.
110    ParseSocketDomainError(ParseSocketDomainError),
111}
112
113impl fmt::Display for ParseSocketAddrNodeError {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        match self {
116            Self::ParseSocketDomainError(err) => err.fmt(f),
117        }
118    }
119}
120
121impl std::error::Error for ParseSocketAddrNodeError {}
122
123impl From<ParseSocketDomainError> for ParseSocketAddrNodeError {
124    fn from(err: ParseSocketDomainError) -> Self {
125        Self::ParseSocketDomainError(err)
126    }
127}
128
129impl FromStr for SocketAddrNode {
130    type Err = ParseSocketAddrNodeError;
131
132    fn from_str(s: &str) -> Result<Self, Self::Err> {
133        if let Ok(addr) = s.parse::<SocketAddrExt>() {
134            return Ok(Self::AddrExt(addr));
135        }
136        Ok(Self::Domain(s.parse::<SocketDomain>()?))
137    }
138}
139
140#[test]
141fn test_socket_addr_node_from_str() {
142    use koibumi_net::domain::Domain;
143
144    let test = "example.org:1234".parse::<SocketAddrNode>().unwrap();
145    let expected = SocketAddrNode::Domain(SocketDomain::new(
146        Domain::new("example.org").unwrap(),
147        1234.into(),
148    ));
149    assert_eq!(test, expected);
150}
151
152impl From<SocketAddrNode> for SocksSocketAddr {
153    fn from(addr: SocketAddrNode) -> Self {
154        match addr {
155            SocketAddrNode::AddrExt(addr) => addr.into(),
156            SocketAddrNode::Domain(domain) => domain.into(),
157        }
158    }
159}