ip_network/
postgres_support.rs

1use std::error::Error;
2use postgres::types::{FromSql, IsNull, ToSql, Type, accepts, to_sql_checked};
3use crate::{IpNetwork, Ipv4Network, Ipv6Network};
4use crate::postgres_common;
5use postgres::types::private::BytesMut;
6
7type PostgresResult<T> = Result<T, Box<dyn Error + Sync + Send>>;
8
9impl<'a> FromSql<'a> for Ipv4Network {
10    fn from_sql(_: &Type, raw: &'a [u8]) -> PostgresResult<Ipv4Network> {
11        postgres_common::from_sql_ipv4_network(raw)
12    }
13
14    accepts!(CIDR);
15}
16
17impl<'a> FromSql<'a> for Ipv6Network {
18    fn from_sql(_: &Type, raw: &'a [u8]) -> PostgresResult<Ipv6Network> {
19        postgres_common::from_sql_ipv6_network(raw)
20    }
21
22    accepts!(CIDR);
23}
24
25impl<'a> FromSql<'a> for IpNetwork {
26    fn from_sql(t: &Type, raw: &'a [u8]) -> PostgresResult<IpNetwork> {
27        match raw[0] {
28            postgres_common::IPV4_TYPE => Ok(IpNetwork::V4(Ipv4Network::from_sql(t, raw)?)),
29            postgres_common::IPV6_TYPE => Ok(IpNetwork::V6(Ipv6Network::from_sql(t, raw)?)),
30            _ => Err("CIDR is not IP version 4 or 6".into()),
31        }
32    }
33
34    accepts!(CIDR);
35}
36
37impl ToSql for Ipv4Network {
38    fn to_sql(&self, _ty: &Type, w: &mut BytesMut) -> PostgresResult<IsNull> {
39        let bytes = postgres_common::to_sql_ipv4_network(self);
40        w.extend_from_slice(&bytes);
41
42        Ok(IsNull::No)
43    }
44
45    accepts!(CIDR);
46    to_sql_checked!();
47}
48
49impl ToSql for Ipv6Network {
50    fn to_sql(&self, _ty: &Type, w: &mut BytesMut) -> PostgresResult<IsNull> {
51        let bytes = postgres_common::to_sql_ipv6_network(self);
52        w.extend_from_slice(&bytes);
53
54        Ok(IsNull::No)
55    }
56
57    accepts!(CIDR);
58    to_sql_checked!();
59}
60
61impl ToSql for IpNetwork {
62    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> PostgresResult<IsNull> {
63        match *self {
64            IpNetwork::V4(ref network) => network.to_sql(ty, w),
65            IpNetwork::V6(ref network) => network.to_sql(ty, w),
66        }
67    }
68
69    accepts!(CIDR);
70    to_sql_checked!();
71}
72
73#[cfg(test)]
74mod tests {
75    use std::net::{Ipv4Addr, Ipv6Addr};
76    use postgres::types::{FromSql, ToSql};
77    use postgres::types::Type;
78    use crate::{IpNetwork, Ipv4Network, Ipv6Network};
79    use postgres::types::private::BytesMut;
80
81    fn return_test_ipv4_network() -> Ipv4Network {
82        Ipv4Network::new(Ipv4Addr::new(192, 168, 0, 0), 16).unwrap()
83    }
84
85    fn return_test_ipv6_network() -> Ipv6Network {
86        Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32).unwrap()
87    }
88
89    #[test]
90    fn ivp4_to_sql() {
91        let ip_network = return_test_ipv4_network();
92        let mut output = BytesMut::new();
93        assert!(ip_network.to_sql(&Type::CIDR, &mut output).is_ok());
94        assert_eq!(2, output[0]);
95        assert_eq!(16, output[1]);
96        assert_eq!(1, output[2]);
97        assert_eq!(4, output[3]);
98        assert_eq!(192, output[4]);
99        assert_eq!(168, output[5]);
100        assert_eq!(0, output[6]);
101        assert_eq!(0, output[7]);
102    }
103
104    #[test]
105    fn ivp4_both_direction() {
106        let ip_network = return_test_ipv4_network();
107        let mut output = BytesMut::new();
108
109        assert!(ip_network.to_sql(&Type::CIDR, &mut output).is_ok());
110
111        let result = Ipv4Network::from_sql(&Type::CIDR, &output);
112        assert!(result.is_ok());
113
114        let ip_network_converted = result.unwrap();
115        assert_eq!(ip_network, ip_network_converted);
116    }
117
118    #[test]
119    fn ivp6_to_sql() {
120        let ip_network = return_test_ipv6_network();
121        let mut output = BytesMut::new();
122        assert!(ip_network.to_sql(&Type::CIDR, &mut output).is_ok());
123        assert_eq!(3, output[0]);
124        assert_eq!(32, output[1]);
125        assert_eq!(1, output[2]);
126        assert_eq!(16, output[3]);
127        assert_eq!(0x20, output[4]);
128        assert_eq!(0x01, output[5]);
129        assert_eq!(0x0d, output[6]);
130        assert_eq!(0xb8, output[7]);
131        for i in 8..20 {
132            assert_eq!(0, output[i]);
133        }
134    }
135
136    #[test]
137    fn ivp6_both_direction() {
138        let ip_network = return_test_ipv6_network();
139        let mut output = BytesMut::new();
140
141        assert!(ip_network.to_sql(&Type::CIDR, &mut output).is_ok());
142
143        let result = Ipv6Network::from_sql(&Type::CIDR, &output);
144        assert!(result.is_ok());
145
146        let ip_network_converted = result.unwrap();
147        assert_eq!(ip_network, ip_network_converted);
148    }
149
150    #[test]
151    fn ipnetwork_to_sql_v4() {
152        let ip_network = IpNetwork::V4(return_test_ipv4_network());
153        let mut output = BytesMut::new();
154        assert!(ip_network.to_sql(&Type::CIDR, &mut output).is_ok());
155    }
156
157    #[test]
158    fn ipnetwork_to_sql_v6() {
159        let ip_network = IpNetwork::V6(return_test_ipv6_network());
160        let mut output = BytesMut::new();
161        assert!(ip_network.to_sql(&Type::CIDR, &mut output).is_ok());
162    }
163}