actix_settings/settings/
address.rs

1use once_cell::sync::Lazy;
2use regex::Regex;
3use serde::Deserialize;
4
5use crate::{Error, Parse};
6
7static ADDR_REGEX: Lazy<Regex> = Lazy::new(|| {
8    Regex::new(
9        r#"(?x)
10        \[                     # opening square bracket
11        (\s)*                  # optional whitespace
12            "(?P<host>[^"]+)"  # host name (string)
13            ,                  # separating comma
14            (\s)*              # optional whitespace
15            (?P<port>\d+)      # port number (integer)
16        (\s)*                  # optional whitespace
17        \]                     # closing square bracket
18    "#,
19    )
20    .expect("Failed to compile regex: ADDR_REGEX")
21});
22
23static ADDR_LIST_REGEX: Lazy<Regex> = Lazy::new(|| {
24    Regex::new(
25        r#"(?x)
26        \[                           # opening square bracket (list)
27        (\s)*                        # optional whitespace
28            (?P<elements>(
29                \[".*", (\s)* \d+\]  # element
30                (,)?                 # element separator
31                (\s)*                # optional whitespace
32            )*)
33        (\s)*                        # optional whitespace
34        \]                           # closing square bracket (list)
35    "#,
36    )
37    .expect("Failed to compile regex: ADDRS_REGEX")
38});
39
40/// A host/port pair for the server to bind to.
41#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
42pub struct Address {
43    /// Host part of address.
44    pub host: String,
45
46    /// Port part of address.
47    pub port: u16,
48}
49
50impl Parse for Address {
51    fn parse(string: &str) -> Result<Self, Error> {
52        let mut items = string
53            .trim()
54            .trim_start_matches('[')
55            .trim_end_matches(']')
56            .split(',');
57
58        let parse_error = || Error::ParseAddressError(string.to_string());
59
60        if !ADDR_REGEX.is_match(string) {
61            return Err(parse_error());
62        }
63
64        Ok(Self {
65            host: items.next().ok_or_else(parse_error)?.trim().to_string(),
66            port: items.next().ok_or_else(parse_error)?.trim().parse()?,
67        })
68    }
69}
70
71impl Parse for Vec<Address> {
72    fn parse(string: &str) -> Result<Self, Error> {
73        let parse_error = || Error::ParseAddressError(string.to_string());
74
75        if !ADDR_LIST_REGEX.is_match(string) {
76            return Err(parse_error());
77        }
78
79        let mut addrs = vec![];
80
81        for list_caps in ADDR_LIST_REGEX.captures_iter(string) {
82            let elements = &list_caps["elements"].trim();
83            for elt_caps in ADDR_REGEX.captures_iter(elements) {
84                addrs.push(Address {
85                    host: elt_caps["host"].to_string(),
86                    port: elt_caps["port"].parse()?,
87                });
88            }
89        }
90
91        Ok(addrs)
92    }
93}