diff --git a/Cargo.toml b/Cargo.toml index 234cd807..9ae1c38b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ time = { version = "0.1.14", optional = true } unix_socket = { version = "0.4.1", optional = true, features = ["socket_timeout"] } uuid = { version = "0.1", optional = true } security-framework = { version = "0.1.1", optional = true } +bit-vec = { version = "0.4", optional = true } [dev-dependencies] url = "0.2" diff --git a/src/types/bit_vec.rs b/src/types/bit_vec.rs new file mode 100644 index 00000000..ea50d813 --- /dev/null +++ b/src/types/bit_vec.rs @@ -0,0 +1,41 @@ +extern crate bit_vec; + +use std::io::prelude::*; +use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; +use self::bit_vec::BitVec; + +use Result; +use types::{FromSql, ToSql, IsNull, Type, SessionInfo, downcast}; + +impl FromSql for BitVec { + fn from_sql(_: &Type, raw: &mut R, _: &SessionInfo) -> Result { + let len = try!(raw.read_i32::()) as usize; + let mut bytes = vec![]; + try!(raw.take(((len + 7) / 8) as u64).read_to_end(&mut bytes)); + + let mut bitvec = BitVec::from_bytes(&bytes); + while bitvec.len() > len { + bitvec.pop(); + } + + Ok(bitvec) + } + + accepts!(Type::Bit, Type::Varbit); +} + +impl ToSql for BitVec { + fn to_sql(&self, + _: &Type, + mut out: &mut W, + _: &SessionInfo) + -> Result { + try!(out.write_i32::(try!(downcast(self.len())))); + try!(out.write_all(&self.to_bytes())); + + Ok(IsNull::No) + } + + accepts!(Type::Bit, Type::Varbit); + to_sql_checked!(); +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 63cfdd4a..6971fd9f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -42,6 +42,8 @@ macro_rules! to_sql_checked { } } +#[cfg(feature = "bit-vec")] +mod bit_vec; #[cfg(feature = "uuid")] mod uuid; #[cfg(feature = "time")] @@ -586,6 +588,7 @@ impl error::Error for WasNull { /// | chrono::NaiveDate | DATE | /// | chrono::NaiveTime | TIME | /// | uuid::Uuid | UUID | +/// | bit_vec::BitVec | BIT, VARBIT | /// /// # Nullability /// @@ -796,6 +799,7 @@ pub enum IsNull { /// | chrono::NaiveDate | DATE | /// | chrono::NaiveTime | TIME | /// | uuid::Uuid | UUID | +/// | bit_vec::BitVec | BIT, VARBIT | /// /// # Nullability /// diff --git a/tests/types/bit_vec.rs b/tests/types/bit_vec.rs new file mode 100644 index 00000000..7c19dd04 --- /dev/null +++ b/tests/types/bit_vec.rs @@ -0,0 +1,26 @@ +extern crate bit_vec; + +use self::bit_vec::BitVec; +use types::test_type; + +#[test] +fn test_bit_params() { + let mut bv = BitVec::from_bytes(&[0b0110_1001, 0b0000_0111]); + bv.pop(); + bv.pop(); + test_type("BIT(14)", &[(Some(bv), + "B'01101001000001'"), + (None, "NULL")]) +} + +#[test] +fn test_varbit_params() { + let mut bv = BitVec::from_bytes(&[0b0110_1001, 0b0000_0111]); + bv.pop(); + bv.pop(); + test_type("VARBIT", &[(Some(bv), + "B'01101001000001'"), + (Some(BitVec::from_bytes(&[])), + "B''"), + (None, "NULL")]) +} diff --git a/tests/types/mod.rs b/tests/types/mod.rs index 0d67f4ee..c0069f75 100644 --- a/tests/types/mod.rs +++ b/tests/types/mod.rs @@ -7,6 +7,8 @@ use postgres::{Connection, SslMode}; use postgres::error::Error; use postgres::types::{ToSql, FromSql, Slice}; +#[cfg(feature = "bit-vec")] +mod bit_vec; #[cfg(feature = "uuid")] mod uuid; #[cfg(feature = "time")]