// Copyright 2021 Ian Jackson and contributors to Hippotat
-// SPDX-License-Identifier: AGPL-3.0-or-later
+// SPDX-License-Identifier: GPL-3.0-or-later
// There is NO WARRANTY.
use crate::prelude::*;
-#[derive(Debug,Clone)]
+#[derive(Debug,Copy,Clone)]
+pub enum LinkEnd { Server, Client }
+
+#[derive(Debug,Clone,Hash,Eq,PartialEq,Ord,PartialOrd)]
pub struct ServerName(pub String);
-#[derive(Debug,Clone,Copy)]
-pub struct ClientName(pub Ipv4Addr);
+#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd)]
+pub struct ClientName(pub IpAddr);
-#[derive(Debug,Clone)]
-pub enum SectionName {
- Link { server: ServerName, client: ClientName },
- Client(ClientName),
- Server(ServerName), // includes SERVER, which is slightly special
- Common,
- Default,
+#[derive(Debug,Clone,Hash,Eq,PartialEq,Ord,PartialOrd)]
+pub struct LinkName {
+ pub server: ServerName,
+ pub client: ClientName,
}
-pub use SectionName as SN;
impl FromStr for ClientName {
type Err = AE;
#[throws(AE)]
fn from_str(s: &str) -> Self {
- let v4addr: Ipv4Addr = s.parse()
- .context("invalid client name (IPv4 address)")?;
- if s != v4addr.to_string() {
- throw!(anyhow!("invalid client name (unusual IPv4 address syntax)"));
- }
- ClientName(v4addr)
+ ClientName(
+ if let Ok(v4addr) = s.parse::<Ipv4Addr>() {
+ if s != v4addr.to_string() {
+ throw!(anyhow!("invalid client name (unusual IPv4 address syntax)"));
+ }
+ v4addr.into()
+ } else if let Ok(v6addr) = s.parse::<Ipv6Addr>() {
+ if s != v6addr.to_string() {
+ throw!(anyhow!("invalid client name (non-canonical IPv6 address)"));
+ }
+ v6addr.into()
+ } else {
+ throw!(anyhow!("invalid client name (IPv4 or IPv6 address)"))
+ }
+ )
}
}
^ (?: SERVER
| [0-9a-z][-0-9a-z]* (:? \.
[0-9a-z][-0-9a-z]* )*
- )"x, s) {
+ ) $"x, s) {
throw!(anyhow!("bad syntax for server name"));
}
- if regex_is_match!(r"[a-z-]", s) {
+ if ! regex_is_match!(r"[A-Za-z-]", s) {
throw!(anyhow!("bad syntax for server name \
(too much like an IPv4 address)"));
}
}
}
-impl FromStr for SectionName {
- type Err = AE;
- #[throws(AE)]
- fn from_str(s: &str) -> Self {
- match s {
- "COMMON" => return SN::Common,
- "DEFAULT" => return SN::Default,
- _ => { }
- };
- if let Ok(n@ ServerName(_)) = s.parse() { return SN::Server(n) }
- if let Ok(n@ ClientName(_)) = s.parse() { return SN::Client(n) }
- let (server, client) = s.split_ascii_whitespace().collect_tuple()
- .ok_or_else(|| anyhow!(
- "bad section name \
- (must be COMMON, DEFAULT, <server>, <client>, or <server> <client>"
- ))?;
- let server = server.parse().context("server name in link section name")?;
- let client = client.parse().context("client name in link section name")?;
- SN::Link { server, client }
+impl Display for ServerName {
+ #[throws(fmt::Error)]
+ fn fmt(&self, f: &mut fmt::Formatter) { Display::fmt(&self.0, f)?; }
+}
+impl Display for ClientName {
+ #[throws(fmt::Error)]
+ fn fmt(&self, f: &mut fmt::Formatter) { Display::fmt(&self.0, f)?; }
+}
+impl Display for LinkName {
+ #[throws(fmt::Error)]
+ fn fmt(&self, f: &mut fmt::Formatter) {
+ write!(f, "[{} {}]", &self.server, &self.client)?;
}
}