Add inet support

It's lossy ATM, since IpAddr doesn't store the netmask.

Closes #88
This commit is contained in:
Steven Fackler 2014-12-14 11:39:26 -08:00
parent db198a5b77
commit 3ac26d4961
4 changed files with 77 additions and 1 deletions

View File

@ -204,6 +204,10 @@ types. The driver currently supports the following conversions:
<td>serialize::json::Json</td>
<td>JSON</td>
</tr>
<tr>
<td>IpAddr</td>
<td>INET</td>
</tr>
<tr>
<td>time::Timespec</td>
<td>TIMESTAMP, TIMESTAMP WITH TIME ZONE</td>

View File

@ -98,7 +98,7 @@ pub mod types;
const CANARY: u32 = 0xdeadbeef;
/// A typedef of the result returned by many methods.
/// A type alias of the result returned by many methods.
pub type Result<T> = result::Result<T, Error>;
/// Specifies the target server to connect to.

View File

@ -2,6 +2,7 @@
use serialize::json;
use std::collections::HashMap;
use std::io::{ByRefReader, BufReader};
use std::io::net::ip::IpAddr;
use self::Type::*;
use Result;
@ -325,6 +326,7 @@ const JSONOID: Oid = 114;
const JSONARRAYOID: Oid = 199;
const FLOAT4OID: Oid = 700;
const FLOAT8OID: Oid = 701;
const INETOID: Oid = 869;
const BOOLARRAYOID: Oid = 1000;
const BYTEAARRAYOID: Oid = 1001;
const CHARARRAYOID: Oid = 1002;
@ -433,6 +435,8 @@ make_postgres_type!(
FLOAT4OID => Float4,
#[doc="FLOAT8/DOUBLE PRECISION"]
FLOAT8OID => Float8,
#[doc="INET"]
INETOID => Inet,
#[doc="BOOL[]"]
BOOLARRAYOID => BoolArray member Bool,
#[doc="BYTEA[]"]
@ -538,6 +542,29 @@ impl RawFromSql for json::Json {
}
}
impl RawFromSql for IpAddr {
fn raw_from_sql<R: Reader>(raw: &mut R) -> Result<IpAddr> {
let family = try!(raw.read_u8());
let _bits = try!(raw.read_u8());
let _is_cidr = try!(raw.read_u8());
let nb = try!(raw.read_u8());
let mut buf = &*try!(raw.read_exact(nb as uint));
match family {
2 if nb == 4 => Ok(IpAddr::Ipv4Addr(buf[0], buf[1], buf[2], buf[3])),
3 if nb == 16 => Ok(IpAddr::Ipv6Addr(try!(buf.read_be_u16()),
try!(buf.read_be_u16()),
try!(buf.read_be_u16()),
try!(buf.read_be_u16()),
try!(buf.read_be_u16()),
try!(buf.read_be_u16()),
try!(buf.read_be_u16()),
try!(buf.read_be_u16()))),
_ => Err(Error::BadData),
}
}
}
from_raw_from_impl!(Bool, bool)
from_raw_from_impl!(ByteA, Vec<u8>)
from_raw_from_impl!(Varchar | Text | CharN | Name, String)
@ -548,6 +575,7 @@ from_raw_from_impl!(Int8, i64)
from_raw_from_impl!(Float4, f32)
from_raw_from_impl!(Float8, f64)
from_raw_from_impl!(Json, json::Json)
from_raw_from_impl!(Inet, IpAddr)
from_raw_from_impl!(Int4Range, Range<i32>)
from_raw_from_impl!(Int8Range, Range<i64>)
@ -668,10 +696,44 @@ impl RawToSql for json::Json {
}
}
impl RawToSql for IpAddr {
fn raw_to_sql<W: Writer>(&self, raw: &mut W) -> Result<()> {
match *self {
IpAddr::Ipv4Addr(a, b, c, d) => {
let buf = [2, // family
32, // bits
0, // is_cidr
4, // nb
a, b, c, d // addr
];
try!(raw.write(&buf));
}
IpAddr::Ipv6Addr(a, b, c, d, e, f, g, h) => {
let buf = [3, // family
128, // bits
0, // is_cidr
16, // nb
];
try!(raw.write(&buf));
try!(raw.write_be_u16(a));
try!(raw.write_be_u16(b));
try!(raw.write_be_u16(c));
try!(raw.write_be_u16(d));
try!(raw.write_be_u16(e));
try!(raw.write_be_u16(f));
try!(raw.write_be_u16(g));
try!(raw.write_be_u16(h));
}
}
Ok(())
}
}
to_raw_to_impl!(Bool, bool)
to_raw_to_impl!(ByteA, Vec<u8>)
to_raw_to_impl!(Varchar | Text | CharN | Name, String)
to_raw_to_impl!(Json, json::Json)
to_raw_to_impl!(Inet, IpAddr)
to_raw_to_impl!(Char, i8)
to_raw_to_impl!(Int2, i16)
to_raw_to_impl!(Int4, i32)

View File

@ -4,6 +4,7 @@ use std::f32;
use std::f64;
use std::fmt;
use std::num::Float;
use std::io::net::ip::IpAddr;
use postgres::{Connection, SslMode};
use postgres::types::{ToSql, FromSql};
@ -164,6 +165,15 @@ fn test_json_params() {
(None, "NULL")])
}
#[test]
fn test_inet_params() {
test_type("INET", &[(Some(from_str::<IpAddr>("127.0.0.1").unwrap()),
"'127.0.0.1'"),
(Some(from_str("2001:0db8:85a3:0000:0000:8a2e:0370:7334").unwrap()),
"'2001:0db8:85a3:0000:0000:8a2e:0370:7334'"),
(None, "NULL")])
}
#[test]
fn test_int4range_params() {
test_range!("INT4RANGE", i32, 100i32, "100", 200i32, "200")