Skip to main content

diesel/pg/types/
network_address.rs

1extern crate ipnetwork;
2extern crate libc;
3
4use self::ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
5use core::net::{Ipv4Addr, Ipv6Addr};
6use std::io::prelude::*;
7
8use crate::deserialize::{self, FromSql, FromSqlRow};
9use crate::pg::{Pg, PgValue};
10#[cfg(test)]
11use crate::query_builder::bind_collector::ByteWrapper;
12use crate::serialize::{self, IsNull, Output, ToSql};
13use crate::sql_types::{Cidr, Inet};
14
15#[cfg(windows)]
16const AF_INET: u8 = 2;
17// Maybe not used, but defining to follow Rust's libstd/net/sys
18#[cfg(target_os = "redox")]
19const AF_INET: u8 = 1;
20
21#[allow(clippy::cast_possible_truncation)] // it's 2
22#[cfg(not(any(windows, target_os = "redox")))]
23const AF_INET: u8 = libc::AF_INET as u8;
24
25const PGSQL_AF_INET: u8 = AF_INET;
26const PGSQL_AF_INET6: u8 = AF_INET + 1;
27
28#[allow(dead_code)]
29mod foreign_derives {
30    use super::*;
31    use crate::expression::AsExpression;
32
33    #[derive(const _: () =
    {
        use diesel;
        impl<'__expr> diesel::expression::AsExpression<Inet> for
            &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr, '__expr2> diesel::expression::AsExpression<Inet> for
            &'__expr2 &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr, '__expr2>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for &'__expr2 &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<__DB>
            diesel::serialize::ToSql<diesel::sql_types::Nullable<Inet>, __DB>
            for IpNetwork where __DB: diesel::backend::Backend,
            Self: diesel::serialize::ToSql<Inet, __DB> {
            fn to_sql<'__b>(&'__b self,
                out: &mut diesel::serialize::Output<'__b, '_, __DB>)
                -> diesel::serialize::Result {
                diesel::serialize::ToSql::<Inet, __DB>::to_sql(self, out)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr> diesel::expression::AsExpression<Inet> for
            &'__expr alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for &'__expr alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr> diesel::expression::AsExpression<Inet> for
            &'__expr alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for &'__expr alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr> diesel::expression::AsExpression<Inet> for
            &'__expr alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for &'__expr alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        impl diesel::expression::AsExpression<Inet> for IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<Inet> for
            alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<Inet> for
            alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<Inet> for
            alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Inet, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Inet>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>
            for alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Inet>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Inet>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<'__expr> diesel::expression::AsExpression<Cidr> for
            &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr, '__expr2> diesel::expression::AsExpression<Cidr> for
            &'__expr2 &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr, '__expr2>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for &'__expr2 &'__expr IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl<__DB>
            diesel::serialize::ToSql<diesel::sql_types::Nullable<Cidr>, __DB>
            for IpNetwork where __DB: diesel::backend::Backend,
            Self: diesel::serialize::ToSql<Cidr, __DB> {
            fn to_sql<'__b>(&'__b self,
                out: &mut diesel::serialize::Output<'__b, '_, __DB>)
                -> diesel::serialize::Result {
                diesel::serialize::ToSql::<Cidr, __DB>::to_sql(self, out)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr> diesel::expression::AsExpression<Cidr> for
            &'__expr alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for &'__expr alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr> diesel::expression::AsExpression<Cidr> for
            &'__expr alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for &'__expr alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr> diesel::expression::AsExpression<Cidr> for
            &'__expr alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl<'__expr>
            diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for &'__expr alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                &'__expr IpNetwork>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(&**self)
            }
        }
        impl diesel::expression::AsExpression<Cidr> for IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for IpNetwork {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<Cidr> for
            alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for alloc::rc::Rc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<Cidr> for
            alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for alloc::sync::Arc<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        impl diesel::expression::AsExpression<Cidr> for
            alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<Cidr, Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<Cidr>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
        #[diagnostic::do_not_recommend]
        impl diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>
            for alloc::boxed::Box<IpNetwork> {
            type Expression =
                diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<Cidr>,
                Self>;
            fn as_expression(self)
                ->
                    <Self as
                    diesel::expression::AsExpression<diesel::sql_types::Nullable<Cidr>>>::Expression {
                diesel::internal::derives::as_expression::Bound::new(self)
            }
        }
    };AsExpression, const _: () =
    {
        use diesel;
        impl<__DB, __ST> diesel::deserialize::Queryable<__ST, __DB> for
            IpNetwork where __DB: diesel::backend::Backend,
            __ST: diesel::sql_types::SingleValue,
            Self: diesel::deserialize::FromSql<__ST, __DB> {
            type Row = Self;
            fn build(row: Self) -> diesel::deserialize::Result<Self> {
                diesel::deserialize::Result::Ok(row)
            }
        }
    };FromSqlRow)]
34    #[diesel(foreign_derive)]
35    #[diesel(sql_type = Inet)]
36    #[diesel(sql_type = Cidr)]
37    struct IpNetworkProxy(IpNetwork);
38}
39
40macro_rules! err {
41    () => {
42        Err("invalid network address format".into())
43    };
44    ($msg:expr_2021) => {
45        Err(format!("invalid network address format. {}", $msg).into())
46    };
47}
48
49macro_rules! assert_or_error {
50    ($cond:expr_2021) => {
51        if !$cond {
52            return err!();
53        }
54    };
55
56    ($cond:expr_2021, $msg:expr_2021) => {
57        if !$cond {
58            return err!($msg);
59        }
60    };
61}
62
63macro_rules! impl_Sql {
64    ($ty: ty, $net_type: expr_2021) => {
65        #[cfg(all(feature = "postgres_backend", feature = "network-address"))]
66        impl FromSql<$ty, Pg> for IpNetwork {
67            fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
68                // https://github.com/postgres/postgres/blob/55c3391d1e6a201b5b891781d21fe682a8c64fe6/src/include/utils/inet.h#L23-L28
69                let bytes = value.as_bytes();
70                assert_or_error!(4 <= bytes.len(), "input is too short.");
71                let af = bytes[0];
72                let prefix = bytes[1];
73                let net_type = bytes[2];
74                let len = bytes[3];
75                assert_or_error!(
76                    net_type == $net_type,
77                    format!("returned type isn't a {}", stringify!($ty))
78                );
79                if af == PGSQL_AF_INET {
80                    assert_or_error!(bytes.len() == 8);
81                    assert_or_error!(len == 4, "the data isn't the size of ipv4");
82                    let b = &bytes[4..];
83                    let addr = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
84                    let inet = Ipv4Network::new(addr, prefix)?;
85                    Ok(IpNetwork::V4(inet))
86                } else if af == PGSQL_AF_INET6 {
87                    assert_or_error!(bytes.len() == 20);
88                    assert_or_error!(len == 16, "the data isn't the size of ipv6");
89                    let b = &bytes[4..];
90                    let addr = Ipv6Addr::from([
91                        b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11],
92                        b[12], b[13], b[14], b[15],
93                    ]);
94                    let inet = Ipv6Network::new(addr, prefix)?;
95                    Ok(IpNetwork::V6(inet))
96                } else {
97                    err!()
98                }
99            }
100        }
101
102        #[cfg(all(feature = "postgres_backend", feature = "network-address"))]
103        impl ToSql<$ty, Pg> for IpNetwork {
104            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
105                use self::ipnetwork::IpNetwork::*;
106                let net_type = $net_type;
107                match *self {
108                    V4(ref net) => {
109                        let mut data = [0u8; 8];
110                        let af = PGSQL_AF_INET;
111                        let prefix = net.prefix();
112                        let len: u8 = 4;
113                        let addr = if net_type == 0 {
114                            net.ip().octets()
115                        } else {
116                            network_v4(net).octets()
117                        };
118                        data[0] = af;
119                        data[1] = prefix;
120                        data[2] = net_type;
121                        data[3] = len;
122                        data[4..].copy_from_slice(&addr);
123                        out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
124                    }
125                    V6(ref net) => {
126                        let mut data = [0u8; 20];
127                        let af = PGSQL_AF_INET6;
128                        let prefix = net.prefix();
129                        let len: u8 = 16;
130                        let addr = if net_type == 0 {
131                            net.ip().octets()
132                        } else {
133                            network_v6(net).octets()
134                        };
135                        data[0] = af;
136                        data[1] = prefix;
137                        data[2] = net_type;
138                        data[3] = len;
139                        data[4..].copy_from_slice(&addr);
140                        out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
141                    }
142                }
143            }
144        }
145    };
146}
147
148impl FromSql<Inet, Pg> for IpNetwork {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        let bytes = value.as_bytes();
        if !(4 <= bytes.len()) {
            return Err(::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                        "input is too short."))
                            }).into());
        };
        let af = bytes[0];
        let prefix = bytes[1];
        let net_type = bytes[2];
        let len = bytes[3];
        if !(net_type == 0) {
            return Err(::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                        ::alloc::__export::must_use({
                                                ::alloc::fmt::format(format_args!("returned type isn\'t a {0}",
                                                        "Inet"))
                                            })))
                            }).into());
        };
        if af == PGSQL_AF_INET {
            if !(bytes.len() == 8) {
                return Err("invalid network address format".into());
            };
            if !(len == 4) {
                return Err(::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                            "the data isn't the size of ipv4"))
                                }).into());
            };
            let b = &bytes[4..];
            let addr = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
            let inet = Ipv4Network::new(addr, prefix)?;
            Ok(IpNetwork::V4(inet))
        } else if af == PGSQL_AF_INET6 {
            if !(bytes.len() == 20) {
                return Err("invalid network address format".into());
            };
            if !(len == 16) {
                return Err(::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                            "the data isn't the size of ipv6"))
                                }).into());
            };
            let b = &bytes[4..];
            let addr =
                Ipv6Addr::from([b[0], b[1], b[2], b[3], b[4], b[5], b[6],
                            b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14],
                            b[15]]);
            let inet = Ipv6Network::new(addr, prefix)?;
            Ok(IpNetwork::V6(inet))
        } else { Err("invalid network address format".into()) }
    }
}
impl ToSql<Inet, Pg> for IpNetwork {
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>)
        -> serialize::Result {
        use self::ipnetwork::IpNetwork::*;
        let net_type = 0;
        match *self {
            V4(ref net) => {
                let mut data = [0u8; 8];
                let af = PGSQL_AF_INET;
                let prefix = net.prefix();
                let len: u8 = 4;
                let addr =
                    if net_type == 0 {
                        net.ip().octets()
                    } else { network_v4(net).octets() };
                data[0] = af;
                data[1] = prefix;
                data[2] = net_type;
                data[3] = len;
                data[4..].copy_from_slice(&addr);
                out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
            }
            V6(ref net) => {
                let mut data = [0u8; 20];
                let af = PGSQL_AF_INET6;
                let prefix = net.prefix();
                let len: u8 = 16;
                let addr =
                    if net_type == 0 {
                        net.ip().octets()
                    } else { network_v6(net).octets() };
                data[0] = af;
                data[1] = prefix;
                data[2] = net_type;
                data[3] = len;
                data[4..].copy_from_slice(&addr);
                out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
            }
        }
    }
}impl_Sql!(Inet, 0);
149impl FromSql<Cidr, Pg> for IpNetwork {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        let bytes = value.as_bytes();
        if !(4 <= bytes.len()) {
            return Err(::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                        "input is too short."))
                            }).into());
        };
        let af = bytes[0];
        let prefix = bytes[1];
        let net_type = bytes[2];
        let len = bytes[3];
        if !(net_type == 1) {
            return Err(::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                        ::alloc::__export::must_use({
                                                ::alloc::fmt::format(format_args!("returned type isn\'t a {0}",
                                                        "Cidr"))
                                            })))
                            }).into());
        };
        if af == PGSQL_AF_INET {
            if !(bytes.len() == 8) {
                return Err("invalid network address format".into());
            };
            if !(len == 4) {
                return Err(::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                            "the data isn't the size of ipv4"))
                                }).into());
            };
            let b = &bytes[4..];
            let addr = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
            let inet = Ipv4Network::new(addr, prefix)?;
            Ok(IpNetwork::V4(inet))
        } else if af == PGSQL_AF_INET6 {
            if !(bytes.len() == 20) {
                return Err("invalid network address format".into());
            };
            if !(len == 16) {
                return Err(::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("invalid network address format. {0}",
                                            "the data isn't the size of ipv6"))
                                }).into());
            };
            let b = &bytes[4..];
            let addr =
                Ipv6Addr::from([b[0], b[1], b[2], b[3], b[4], b[5], b[6],
                            b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14],
                            b[15]]);
            let inet = Ipv6Network::new(addr, prefix)?;
            Ok(IpNetwork::V6(inet))
        } else { Err("invalid network address format".into()) }
    }
}
impl ToSql<Cidr, Pg> for IpNetwork {
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>)
        -> serialize::Result {
        use self::ipnetwork::IpNetwork::*;
        let net_type = 1;
        match *self {
            V4(ref net) => {
                let mut data = [0u8; 8];
                let af = PGSQL_AF_INET;
                let prefix = net.prefix();
                let len: u8 = 4;
                let addr =
                    if net_type == 0 {
                        net.ip().octets()
                    } else { network_v4(net).octets() };
                data[0] = af;
                data[1] = prefix;
                data[2] = net_type;
                data[3] = len;
                data[4..].copy_from_slice(&addr);
                out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
            }
            V6(ref net) => {
                let mut data = [0u8; 20];
                let af = PGSQL_AF_INET6;
                let prefix = net.prefix();
                let len: u8 = 16;
                let addr =
                    if net_type == 0 {
                        net.ip().octets()
                    } else { network_v6(net).octets() };
                data[0] = af;
                data[1] = prefix;
                data[2] = net_type;
                data[3] = len;
                data[4..].copy_from_slice(&addr);
                out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
            }
        }
    }
}impl_Sql!(Cidr, 1);
150
151fn network_v4(net: &Ipv4Network) -> Ipv4Addr {
152    let mask = u32::from(net.mask());
153    let ip = u32::from(net.ip()) & mask;
154    Ipv4Addr::from(ip)
155}
156
157fn network_v6(net: &Ipv6Network) -> Ipv6Addr {
158    let mask = u128::from(net.mask());
159    let network = u128::from(net.ip()) & mask;
160    Ipv6Addr::from(network)
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use crate::test_helpers::format_error;
167
168    #[diesel_test_helper::test]
169    fn v4address_to_sql() {
170        macro_rules! test_to_sql {
171            ($ty:ty, $net_type:expr) => {
172                let mut buffer = Vec::new();
173                {
174                    let mut bytes = Output::test(ByteWrapper(&mut buffer));
175                    let test_address =
176                        IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap());
177                    ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap();
178                }
179                assert_eq!(buffer, vec![PGSQL_AF_INET, 32, $net_type, 4, 127, 0, 0, 1]);
180            };
181        }
182
183        test_to_sql!(Inet, 0);
184        test_to_sql!(Cidr, 1);
185    }
186
187    #[diesel_test_helper::test]
188    fn some_v4address_from_sql() {
189        macro_rules! test_some_address_from_sql {
190            ($ty:tt) => {
191                let input_address =
192                    IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap());
193                let mut buffer = Vec::new();
194                {
195                    let mut bytes = Output::test(ByteWrapper(&mut buffer));
196                    ToSql::<$ty, Pg>::to_sql(&input_address, &mut bytes).unwrap();
197                }
198                let output_address =
199                    FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&buffer)).unwrap();
200                assert_eq!(input_address, output_address);
201            };
202        }
203
204        test_some_address_from_sql!(Cidr);
205        test_some_address_from_sql!(Inet);
206    }
207
208    #[diesel_test_helper::test]
209    fn v6address_to_sql() {
210        macro_rules! test_to_sql {
211            ($ty:ty, $net_type:expr, $last:expr) => {
212                let mut buffer = Vec::new();
213                {
214                    let mut bytes = Output::test(ByteWrapper(&mut buffer));
215                    let test_address = IpNetwork::V6(
216                        Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap(),
217                    );
218                    ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap();
219                }
220                assert_eq!(
221                    buffer,
222                    vec![
223                        PGSQL_AF_INET6,
224                        64,
225                        $net_type,
226                        16,
227                        0,
228                        0,
229                        0,
230                        0,
231                        0,
232                        0,
233                        0,
234                        0,
235                        0,
236                        0,
237                        0,
238                        0,
239                        0,
240                        0,
241                        0,
242                        $last,
243                    ]
244                );
245            };
246        }
247
248        // `::1/64` keeps its host bit as an `Inet` and loses it as a `Cidr`
249        test_to_sql!(Inet, 0, 1);
250        test_to_sql!(Cidr, 1, 0);
251    }
252
253    #[diesel_test_helper::test]
254    fn some_v6address_from_sql() {
255        macro_rules! test_some_address_from_sql {
256            ($ty:tt, $last:expr) => {
257                let input_address = IpNetwork::V6(
258                    Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, $last), 64).unwrap(),
259                );
260                let mut buffer = Vec::new();
261                {
262                    let mut bytes = Output::test(ByteWrapper(&mut buffer));
263                    ToSql::<$ty, Pg>::to_sql(&input_address, &mut bytes).unwrap();
264                }
265                let output_address =
266                    FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&buffer)).unwrap();
267                assert_eq!(input_address, output_address);
268            };
269        }
270
271        test_some_address_from_sql!(Inet, 1);
272        test_some_address_from_sql!(Cidr, 0);
273    }
274
275    #[diesel_test_helper::test]
276    fn bad_address_from_sql() {
277        macro_rules! bad_address_from_sql {
278            ($ty:tt) => {
279                let address: Result<IpNetwork, _> =
280                    FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&[7, PGSQL_AF_INET, 0]));
281                assert_eq!(
282                    format_error(&*address.unwrap_err()),
283                    "invalid network address format. input is too short."
284                );
285            };
286        }
287
288        bad_address_from_sql!(Inet);
289        bad_address_from_sql!(Cidr);
290    }
291
292    #[diesel_test_helper::test]
293    fn no_address_from_sql() {
294        macro_rules! test_no_address_from_sql {
295            ($ty:ty) => {
296                let address: Result<IpNetwork, _> = FromSql::<$ty, Pg>::from_nullable_sql(None);
297                assert_eq!(
298                    format_error(&*address.unwrap_err()),
299                    "Unexpected null for non-null column"
300                );
301            };
302        }
303
304        test_no_address_from_sql!(Inet);
305        test_no_address_from_sql!(Cidr);
306    }
307}