1use std::fmt::Display;
16
17use super::AsStr;
18use crate::error::Error;
19
20pub fn apply<T: Ip>(v: &T, (kind,): (IpKind,)) -> Result<(), Error> {
21 if v.validate_ip(kind).is_err() {
22 return Err(Error::new(format!("not a valid {kind} address")));
23 }
24 Ok(())
25}
26
27pub trait Ip {
28 type Error: Display;
29
30 fn validate_ip(&self, kind: IpKind) -> Result<(), Self::Error>;
31}
32
33#[derive(Clone, Copy)]
34pub enum IpKind {
35 Any,
36 V4,
37 V6,
38}
39
40impl Display for IpKind {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 match self {
43 IpKind::Any => write!(f, "IP"),
44 IpKind::V4 => write!(f, "IPv4"),
45 IpKind::V6 => write!(f, "IPv6"),
46 }
47 }
48}
49
50impl<T: AsStr> Ip for T {
51 type Error = std::net::AddrParseError;
52
53 fn validate_ip(&self, kind: IpKind) -> Result<(), Self::Error> {
54 let v = self.as_str();
55 match kind {
56 IpKind::Any => {
57 let _ = v.parse::<std::net::IpAddr>()?;
58 }
59 IpKind::V4 => {
60 let _ = v.parse::<std::net::Ipv4Addr>()?;
61 }
62 IpKind::V6 => {
63 let _ = v.parse::<std::net::Ipv6Addr>()?;
64 }
65 };
66 Ok(())
67 }
68}
69
70impl<T: Ip> Ip for Option<T> {
71 type Error = T::Error;
72
73 fn validate_ip(&self, kind: IpKind) -> Result<(), Self::Error> {
74 match self {
75 Some(value) => value.validate_ip(kind),
76 None => Ok(()),
77 }
78 }
79}