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#[cfg(target_os = "redox")]
19const AF_INET: u8 = 1;
20
21#[allow(clippy::cast_possible_truncation)] #[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 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 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}