1use std::{convert::TryFrom, net::Ipv4Addr};
2
3use nom::{
4 character::complete::{char, digit1},
5 combinator::map_res,
6 sequence::tuple,
7 IResult,
8};
9use snafu::{ensure, Snafu};
10
11#[derive(Debug, Snafu)]
12pub enum Error {
13 NameWithoutIp,
14 FailedToParse { message: String },
15 IncompleteParse,
16}
17
18fn digit(i: &str) -> IResult<&str, u8> {
19 map_res(digit1, |int_val: &str| int_val.parse::<u8>())(i)
20}
21
22fn ip_address(i: &str) -> IResult<&str, Ipv4Addr> {
23 map_res(
24 tuple((digit, char('-'), digit, char('-'), digit, char('-'), digit)),
25 |(a, _, b, _, c, _, d)| Ipv4Addr::try_from([a, b, c, d]),
26 )(i)
27}
28
29pub fn ip_address_from_url<S: AsRef<str>>(url: S) -> Result<Ipv4Addr, Error> {
30 let splitted: Vec<_> = url.as_ref().split('.').collect();
31 ensure!(splitted.len() >= 2, NameWithoutIpSnafu);
32
33 let ip_segment = *splitted.first().unwrap();
34 let (rest, ip) = ip_address(ip_segment).map_err(|e| Error::FailedToParse {
35 message: e.to_string(),
36 })?;
37 ensure!(rest.is_empty(), IncompleteParseSnafu);
38
39 Ok(ip)
40}