2013-08-31 23:11:42 +00:00
|
|
|
use std::rt::io::Decorator;
|
|
|
|
use std::rt::io::extensions::WriterByteConversions;
|
|
|
|
use std::rt::io::mem::MemWriter;
|
2013-08-28 04:36:27 +00:00
|
|
|
use std::str;
|
2013-08-31 23:11:42 +00:00
|
|
|
use std::f32;
|
|
|
|
use std::f64;
|
2013-08-28 04:36:27 +00:00
|
|
|
|
2013-08-30 05:58:26 +00:00
|
|
|
pub type Oid = i32;
|
|
|
|
|
2013-08-30 06:28:46 +00:00
|
|
|
// Values from pg_type.h
|
|
|
|
static BOOLOID: Oid = 16;
|
2013-08-31 23:11:42 +00:00
|
|
|
static INT8OID: Oid = 20;
|
|
|
|
static INT2OID: Oid = 21;
|
|
|
|
static INT4OID: Oid = 23;
|
|
|
|
static FLOAT4OID: Oid = 700;
|
|
|
|
static FLOAT8OID: Oid = 701;
|
2013-09-02 17:27:09 +00:00
|
|
|
static VARCHAROID: Oid = 1043;
|
2013-08-30 06:28:46 +00:00
|
|
|
|
2013-08-30 05:58:26 +00:00
|
|
|
pub enum Format {
|
|
|
|
Text = 0,
|
|
|
|
Binary = 1
|
|
|
|
}
|
|
|
|
|
2013-08-28 04:36:27 +00:00
|
|
|
pub trait FromSql {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! from_str_impl(
|
|
|
|
($t:ty) => (
|
|
|
|
impl FromSql for Option<$t> {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> Option<$t> {
|
|
|
|
match *raw {
|
|
|
|
None => None,
|
|
|
|
Some(ref buf) => {
|
|
|
|
let s = str::from_bytes_slice(buf.as_slice());
|
|
|
|
Some(FromStr::from_str(s).unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
macro_rules! from_option_impl(
|
|
|
|
($t:ty) => (
|
|
|
|
impl FromSql for $t {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> $t {
|
|
|
|
// FIXME when you can specify Self types properly
|
|
|
|
let ret: Option<$t> = FromSql::from_sql(raw);
|
|
|
|
ret.unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2013-08-30 06:28:46 +00:00
|
|
|
impl FromSql for Option<bool> {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> Option<bool> {
|
|
|
|
match *raw {
|
|
|
|
None => None,
|
|
|
|
Some(ref buf) => {
|
|
|
|
assert_eq!(1, buf.len());
|
|
|
|
match buf[0] as char {
|
|
|
|
't' => Some(true),
|
|
|
|
'f' => Some(false),
|
|
|
|
byte => fail!("Invalid byte: %?", byte)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
from_option_impl!(bool)
|
|
|
|
|
2013-08-28 04:36:27 +00:00
|
|
|
from_str_impl!(int)
|
|
|
|
from_option_impl!(int)
|
|
|
|
from_str_impl!(i8)
|
|
|
|
from_option_impl!(i8)
|
|
|
|
from_str_impl!(i16)
|
|
|
|
from_option_impl!(i16)
|
|
|
|
from_str_impl!(i32)
|
|
|
|
from_option_impl!(i32)
|
|
|
|
from_str_impl!(i64)
|
|
|
|
from_option_impl!(i64)
|
|
|
|
from_str_impl!(uint)
|
|
|
|
from_option_impl!(uint)
|
|
|
|
from_str_impl!(u8)
|
|
|
|
from_option_impl!(u8)
|
|
|
|
from_str_impl!(u16)
|
|
|
|
from_option_impl!(u16)
|
|
|
|
from_str_impl!(u32)
|
|
|
|
from_option_impl!(u32)
|
|
|
|
from_str_impl!(u64)
|
|
|
|
from_option_impl!(u64)
|
2013-08-31 23:11:42 +00:00
|
|
|
|
|
|
|
impl FromSql for Option<f32> {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> Option<f32> {
|
|
|
|
match *raw {
|
|
|
|
None => None,
|
|
|
|
Some(ref buf) => {
|
|
|
|
Some(match str::from_bytes_slice(buf.as_slice()) {
|
|
|
|
"NaN" => f32::NaN,
|
|
|
|
"Infinity" => f32::infinity,
|
|
|
|
"-Infinity" => f32::neg_infinity,
|
|
|
|
str => FromStr::from_str(str).unwrap()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-28 04:36:27 +00:00
|
|
|
from_option_impl!(f32)
|
2013-08-31 23:11:42 +00:00
|
|
|
|
|
|
|
impl FromSql for Option<f64> {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> Option<f64> {
|
|
|
|
match *raw {
|
|
|
|
None => None,
|
|
|
|
Some(ref buf) => {
|
|
|
|
Some(match str::from_bytes_slice(buf.as_slice()) {
|
|
|
|
"NaN" => f64::NaN,
|
|
|
|
"Infinity" => f64::infinity,
|
|
|
|
"-Infinity" => f64::neg_infinity,
|
|
|
|
str => FromStr::from_str(str).unwrap()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-28 04:36:27 +00:00
|
|
|
from_option_impl!(f64)
|
|
|
|
|
|
|
|
impl FromSql for Option<~str> {
|
|
|
|
fn from_sql(raw: &Option<~[u8]>) -> Option<~str> {
|
|
|
|
do raw.chain_ref |buf| {
|
|
|
|
Some(str::from_bytes(buf.as_slice()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
from_option_impl!(~str)
|
|
|
|
|
|
|
|
pub trait ToSql {
|
2013-08-30 05:58:26 +00:00
|
|
|
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>);
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 17:27:09 +00:00
|
|
|
macro_rules! check_oid(
|
|
|
|
($expected:ident, $actual:ident) => (
|
|
|
|
if $expected != $actual {
|
|
|
|
fail!("Attempted to bind an invalid type. Expected Oid %? but got \
|
|
|
|
Oid %?", $expected, $actual);
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
macro_rules! to_option_impl(
|
2013-09-02 17:27:09 +00:00
|
|
|
($oid:ident, $t:ty) => (
|
2013-08-28 04:36:27 +00:00
|
|
|
impl ToSql for Option<$t> {
|
2013-08-30 05:58:26 +00:00
|
|
|
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
|
2013-09-02 17:27:09 +00:00
|
|
|
check_oid!($oid, ty)
|
|
|
|
|
2013-08-30 05:58:26 +00:00
|
|
|
match *self {
|
|
|
|
None => (Text, None),
|
2013-09-02 17:27:09 +00:00
|
|
|
Some(ref val) => val.to_sql(ty)
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2013-08-31 23:11:42 +00:00
|
|
|
macro_rules! to_conversions_impl(
|
|
|
|
($oid:ident, $t:ty, $f:ident) => (
|
|
|
|
impl ToSql for $t {
|
|
|
|
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
|
2013-09-02 17:27:09 +00:00
|
|
|
check_oid!($oid, ty)
|
|
|
|
|
|
|
|
let mut writer = MemWriter::new();
|
|
|
|
writer.$f(*self);
|
|
|
|
(Binary, Some(writer.inner()))
|
2013-08-31 23:11:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2013-08-30 06:28:46 +00:00
|
|
|
impl ToSql for bool {
|
|
|
|
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
|
2013-09-02 17:27:09 +00:00
|
|
|
check_oid!(BOOLOID, ty)
|
|
|
|
(Binary, Some(~[*self as u8]))
|
2013-08-30 06:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(BOOLOID, bool)
|
2013-08-30 06:28:46 +00:00
|
|
|
|
2013-08-31 23:11:42 +00:00
|
|
|
to_conversions_impl!(INT2OID, i16, write_be_i16_)
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(INT2OID, i16)
|
2013-08-31 23:11:42 +00:00
|
|
|
to_conversions_impl!(INT4OID, i32, write_be_i32_)
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(INT4OID, i32)
|
2013-08-31 23:11:42 +00:00
|
|
|
to_conversions_impl!(INT8OID, i64, write_be_i64_)
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(INT8OID, i64)
|
2013-08-31 23:11:42 +00:00
|
|
|
to_conversions_impl!(FLOAT4OID, f32, write_be_f32_)
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(FLOAT4OID, f32)
|
2013-08-31 23:11:42 +00:00
|
|
|
to_conversions_impl!(FLOAT8OID, f64, write_be_f64_)
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(FLOAT8OID, f64)
|
2013-08-28 04:36:27 +00:00
|
|
|
|
|
|
|
impl<'self> ToSql for &'self str {
|
2013-09-02 17:27:09 +00:00
|
|
|
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
|
|
|
|
check_oid!(VARCHAROID, ty)
|
2013-08-30 05:58:26 +00:00
|
|
|
(Text, Some(self.as_bytes().to_owned()))
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-02 17:27:09 +00:00
|
|
|
to_option_impl!(VARCHAROID, ~str)
|
2013-08-28 04:36:27 +00:00
|
|
|
|
|
|
|
impl<'self> ToSql for Option<&'self str> {
|
2013-08-30 05:58:26 +00:00
|
|
|
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
|
2013-09-02 17:27:09 +00:00
|
|
|
check_oid!(VARCHAROID, ty)
|
2013-08-30 05:58:26 +00:00
|
|
|
match *self {
|
|
|
|
None => (Text, None),
|
|
|
|
Some(val) => val.to_sql(ty)
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|