@@ -10,6 +10,17 @@ use error::Error;
1010
1111pub use ugh_privacy:: Unknown ;
1212
13+ macro_rules! accepts {
14+ ( $( $expected: pat) ,+) => (
15+ fn accepts( ty: & :: types:: Type ) -> bool {
16+ match * ty {
17+ $( $expected) |+ => true ,
18+ _ => false
19+ }
20+ }
21+ )
22+ }
23+
1324macro_rules! check_types {
1425 ( $( $expected: pat) ,+; $actual: ident) => (
1526 match $actual {
@@ -347,51 +358,105 @@ make_postgres_type! {
347358 INT8RANGEARRAYOID => Int8RangeArray : Kind :: Array ( Type :: Int8Range )
348359}
349360
350- /// A trait for types that can be created from a Postgres value
351- pub trait FromSql {
352- /// Creates a new value of this type from a buffer of Postgres data.
361+ /// A trait for types that can be created from a Postgres value.
362+ pub trait FromSql : Sized {
363+ /// Creates a new value of this type from a `Reader` of Postgres data.
353364 ///
354- /// If the value was `NULL`, the buffer will be `None`.
355- fn from_sql ( ty : & Type , raw : Option < & [ u8 ] > ) -> Result < Self > ;
356- }
365+ /// If the value was `NULL`, the `Reader` will be `None`.
366+ ///
367+ /// The caller of this method is responsible for ensuring that this type
368+ /// is compatible with the Postgres `Type`.
369+ ///
370+ /// The default implementation calls `FromSql::from_sql` when `raw` is
371+ /// `Some` and returns `Err(Error::WasNull)` when `raw` is `None`. It does
372+ /// not typically need to be overridden.
373+ fn from_sql_nullable < R : Reader > ( ty : & Type , raw : Option < & mut R > ) -> Result < Self > {
374+ match raw {
375+ Some ( raw) => FromSql :: from_sql ( ty, raw) ,
376+ None => Err ( Error :: WasNull ) ,
377+ }
378+ }
357379
358- /// A utility trait used by `FromSql` implementations
359- pub trait RawFromSql {
360380 /// Creates a new value of this type from a `Reader` of Postgres data.
361381 ///
362- /// It is the caller's responsibility to ensure that Postgres data of this
363- /// type can be turned in to this type.
364- fn raw_from_sql < R : Reader > ( ty : & Type , raw : & mut R ) -> Result < Self > ;
382+ /// The caller of this method is responsible for ensuring that this type
383+ /// is compatible with the Postgres `Type`.
384+ fn from_sql < R : Reader > ( ty : & Type , raw : & mut R ) -> Result < Self > ;
385+
386+ /// Determines if a value of this type can be created from the specified
387+ /// Postgres `Type`.
388+ fn accepts ( ty : & Type ) -> bool ;
389+ }
390+
391+ impl < T : FromSql > FromSql for Option < T > {
392+ fn from_sql_nullable < R : Reader > ( ty : & Type , raw : Option < & mut R > ) -> Result < Option < T > > {
393+ match raw {
394+ Some ( raw) => <T as FromSql >:: from_sql ( ty, raw) . map ( |e| Some ( e) ) ,
395+ None => Ok ( None ) ,
396+ }
397+ }
398+
399+ fn from_sql < R : Reader > ( ty : & Type , raw : & mut R ) -> Result < Option < T > > {
400+ <T as FromSql >:: from_sql ( ty, raw) . map ( |e| Some ( e) )
401+ }
402+
403+ fn accepts ( ty : & Type ) -> bool {
404+ <T as FromSql >:: accepts ( ty)
405+ }
365406}
366407
367- impl RawFromSql for bool {
368- fn raw_from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < bool > {
369- Ok ( ( try!( raw. read_u8 ( ) ) ) != 0 )
408+ impl FromSql for bool {
409+ fn from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < bool > {
410+ Ok ( try!( raw. read_u8 ( ) ) != 0 )
370411 }
412+
413+ accepts ! ( Type :: Bool ) ;
371414}
372415
373- impl RawFromSql for Vec < u8 > {
374- fn raw_from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < Vec < u8 > > {
416+ impl FromSql for Vec < u8 > {
417+ fn from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < Vec < u8 > > {
375418 Ok ( try!( raw. read_to_end ( ) ) )
376419 }
420+
421+ accepts ! ( Type :: ByteA ) ;
377422}
378423
379- impl RawFromSql for String {
380- fn raw_from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < String > {
424+ impl FromSql for String {
425+ fn from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < String > {
381426 String :: from_utf8 ( try!( raw. read_to_end ( ) ) ) . map_err ( |_| Error :: BadResponse )
382427 }
428+
429+ fn accepts ( ty : & Type ) -> bool {
430+ match * ty {
431+ Type :: Varchar | Type :: Text | Type :: CharN | Type :: Name => true ,
432+ Type :: Unknown ( ref u) if u. name ( ) == "citext" => true ,
433+ _ => false ,
434+ }
435+ }
383436}
384437
385- raw_from_impl ! ( i8 , read_i8) ;
386- raw_from_impl ! ( i16 , read_be_i16) ;
387- raw_from_impl ! ( i32 , read_be_i32) ;
388- raw_from_impl ! ( u32 , read_be_u32) ;
389- raw_from_impl ! ( i64 , read_be_i64) ;
390- raw_from_impl ! ( f32 , read_be_f32) ;
391- raw_from_impl ! ( f64 , read_be_f64) ;
438+ macro_rules! primitive_from {
439+ ( $t: ty, $f: ident, $( $expected: pat) ,+) => {
440+ impl FromSql for $t {
441+ fn from_sql<R : Reader >( _: & Type , raw: & mut R ) -> Result <$t> {
442+ Ok ( try!( raw. $f( ) ) )
443+ }
392444
393- impl RawFromSql for IpAddr {
394- fn raw_from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < IpAddr > {
445+ accepts!( $( $expected) ,+) ;
446+ }
447+ }
448+ }
449+
450+ primitive_from ! ( i8 , read_i8, Type :: Char ) ;
451+ primitive_from ! ( i16 , read_be_i16, Type :: Int2 ) ;
452+ primitive_from ! ( i32 , read_be_i32, Type :: Int4 ) ;
453+ primitive_from ! ( u32 , read_be_u32, Type :: Oid ) ;
454+ primitive_from ! ( i64 , read_be_i64, Type :: Int8 ) ;
455+ primitive_from ! ( f32 , read_be_f32, Type :: Float4 ) ;
456+ primitive_from ! ( f64 , read_be_f64, Type :: Float8 ) ;
457+
458+ impl FromSql for IpAddr {
459+ fn from_sql < R : Reader > ( _: & Type , raw : & mut R ) -> Result < IpAddr > {
395460 let family = try!( raw. read_u8 ( ) ) ;
396461 let _bits = try!( raw. read_u8 ( ) ) ;
397462 let _is_cidr = try!( raw. read_u8 ( ) ) ;
@@ -416,83 +481,50 @@ impl RawFromSql for IpAddr {
416481 _ => Err ( Error :: BadResponse ) ,
417482 }
418483 }
484+
485+ accepts ! ( Type :: Inet , Type :: Cidr ) ;
419486}
420487
421- from_raw_from_impl ! ( Type :: Bool ; bool ) ;
422- from_raw_from_impl ! ( Type :: ByteA ; Vec <u8 >) ;
423- from_raw_from_impl ! ( Type :: Char ; i8 ) ;
424- from_raw_from_impl ! ( Type :: Int2 ; i16 ) ;
425- from_raw_from_impl ! ( Type :: Int4 ; i32 ) ;
426- from_raw_from_impl ! ( Type :: Oid ; u32 ) ;
427- from_raw_from_impl ! ( Type :: Int8 ; i64 ) ;
428- from_raw_from_impl ! ( Type :: Float4 ; f32 ) ;
429- from_raw_from_impl ! ( Type :: Float8 ; f64 ) ;
430- from_raw_from_impl ! ( Type :: Inet , Type :: Cidr ; IpAddr ) ;
488+ impl FromSql for HashMap < String , Option < String > > {
489+ fn from_sql < R : Reader > ( _: & Type , raw : & mut R )
490+ -> Result < HashMap < String , Option < String > > > {
491+ let mut map = HashMap :: new ( ) ;
431492
432- impl FromSql for Option < String > {
433- fn from_sql ( ty : & Type , raw : Option < & [ u8 ] > ) -> Result < Option < String > > {
434- match * ty {
435- Type :: Varchar | Type :: Text | Type :: CharN | Type :: Name => { }
436- Type :: Unknown ( ref u) if u. name ( ) == "citext" => { }
437- _ => return Err ( Error :: WrongType ( ty. clone ( ) ) )
438- }
493+ let count = try!( raw. read_be_i32 ( ) ) ;
439494
440- match raw {
441- Some ( mut buf) => {
442- Ok ( Some ( try!( RawFromSql :: raw_from_sql ( ty, & mut buf) ) ) )
443- }
444- None => Ok ( None )
445- }
446- }
447- }
495+ for _ in range ( 0 , count) {
496+ let key_len = try!( raw. read_be_i32 ( ) ) ;
497+ let key = try!( raw. read_exact ( key_len as usize ) ) ;
498+ let key = match String :: from_utf8 ( key) {
499+ Ok ( key) => key,
500+ Err ( _) => return Err ( Error :: BadResponse ) ,
501+ } ;
448502
449- from_option_impl ! ( String ) ;
503+ let val_len = try!( raw. read_be_i32 ( ) ) ;
504+ let val = if val_len < 0 {
505+ None
506+ } else {
507+ let val = try!( raw. read_exact ( val_len as usize ) ) ;
508+ match String :: from_utf8 ( val) {
509+ Ok ( val) => Some ( val) ,
510+ Err ( _) => return Err ( Error :: BadResponse ) ,
511+ }
512+ } ;
450513
451- impl FromSql for Option < HashMap < String , Option < String > > > {
452- fn from_sql ( ty : & Type , raw : Option < & [ u8 ] > )
453- -> Result < Option < HashMap < String , Option < String > > > > {
454- match * ty {
455- Type :: Unknown ( ref u) if u. name ( ) == "hstore" => { }
456- _ => return Err ( Error :: WrongType ( ty. clone ( ) ) )
514+ map. insert ( key, val) ;
457515 }
458516
459- match raw {
460- Some ( buf) => {
461- let mut rdr = buf;
462- let mut map = HashMap :: new ( ) ;
463-
464- let count = try!( rdr. read_be_i32 ( ) ) ;
465-
466- for _ in range ( 0 , count) {
467- let key_len = try!( rdr. read_be_i32 ( ) ) ;
468- let key = try!( rdr. read_exact ( key_len as usize ) ) ;
469- let key = match String :: from_utf8 ( key) {
470- Ok ( key) => key,
471- Err ( _) => return Err ( Error :: BadResponse ) ,
472- } ;
473-
474- let val_len = try!( rdr. read_be_i32 ( ) ) ;
475- let val = if val_len < 0 {
476- None
477- } else {
478- let val = try!( rdr. read_exact ( val_len as usize ) ) ;
479- match String :: from_utf8 ( val) {
480- Ok ( val) => Some ( val) ,
481- Err ( _) => return Err ( Error :: BadResponse ) ,
482- }
483- } ;
484-
485- map. insert ( key, val) ;
486- }
487- Ok ( Some ( map) )
488- }
489- None => Ok ( None )
517+ Ok ( map)
518+ }
519+
520+ fn accepts ( ty : & Type ) -> bool {
521+ match * ty {
522+ Type :: Unknown ( ref u) if u. name ( ) == "hstore" => true ,
523+ _ => false
490524 }
491525 }
492526}
493527
494- from_option_impl ! ( HashMap <String , Option <String >>) ;
495-
496528/// A trait for types that can be converted into Postgres values
497529pub trait ToSql {
498530 /// Converts the value of `self` into the binary format appropriate for the
0 commit comments