chiark / gitweb /
wip parsing
[hippotat.git] / src / types.rs
1 // Copyright 2021 Ian Jackson and contributors to Hippotat
2 // SPDX-License-Identifier: AGPL-3.0-or-later
3 // There is NO WARRANTY.
4
5 use crate::prelude::*;
6
7 #[derive(Debug,Clone)]
8 pub struct ServerName(pub String);
9
10 #[derive(Debug,Clone,Copy)]
11 pub struct ClientName(pub Ipv4Addr);
12
13 #[derive(Debug,Clone)]
14 pub enum SectionName {
15   Link { server: ServerName, client: ClientName },
16   Client(ClientName),
17   Server(ServerName), // includes SERVER, which is slightly special
18   Common,
19   Default,
20 }
21 pub use SectionName as SN;
22
23 impl FromStr for ClientName {
24   type Err = AE;
25   #[throws(AE)]
26   fn from_str(s: &str) -> Self {
27     let v4addr: Ipv4Addr = s.parse()
28       .context("invalid client name (IPv4 address)")?;
29     if s != v4addr.to_string() {
30       throw!(anyhow!("invalid client name (unusual IPv4 address syntax)"));
31     }
32     ClientName(v4addr)
33   }
34 }
35
36 impl FromStr for ServerName {
37   type Err = AE;
38   #[throws(AE)]
39   fn from_str(s: &str) -> Self {
40     if ! regex_is_match!(r"
41         ^ (?: SERVER
42             | [0-9a-z][-0-9a-z]* (:? \.
43               [0-9a-z][-0-9a-z]*        )*
44           )"x, s) {
45       throw!(anyhow!("bad syntax for server name"));
46     }
47     if regex_is_match!(r"[a-z-]", s) {
48       throw!(anyhow!("bad syntax for server name \
49                       (too much like an IPv4 address)"));
50     }
51     ServerName(s.into())
52   }
53 }
54
55 impl FromStr for SectionName {
56   type Err = AE;
57   #[throws(AE)]
58   fn from_str(s: &str) -> Self {
59     match s {
60       "COMMON" => return SN::Common,
61       "DEFAULT" => return SN::Default,
62       _ => { }
63     };
64     if let Ok(n@ ServerName(_)) = s.parse() { return SN::Server(n) }
65     if let Ok(n@ ClientName(_)) = s.parse() { return SN::Client(n) }
66     let (server, client) = s.split_ascii_whitespace().collect_tuple()
67       .ok_or_else(|| anyhow!(
68         "bad section name \
69          (must be COMMON, DEFAULT, <server>, <client>, or <server> <client>"
70       ))?;
71     let server = server.parse().context("server name in link section name")?;
72     let client = client.parse().context("client name in link section name")?;
73     SN::Link { server, client }
74   }
75 }