@@ -296,6 +296,11 @@ impl WrongTypeNew for WrongType {
296296/// In addition to the types listed above, `FromSql` is implemented for
297297/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
298298/// nullable Postgres value.
299+ ///
300+ /// # Arrays
301+ ///
302+ /// `FromSql` is implemented for `Vec<T>` where `T` implements `FromSql`, and
303+ /// corresponds to one-dimensional Postgres arrays.
299304pub trait FromSql : Sized {
300305 /// Creates a new value of this type from a `Read`er of the binary format
301306 /// of the specified Postgres `Type`.
@@ -343,6 +348,46 @@ impl FromSql for bool {
343348 accepts ! ( Type :: Bool ) ;
344349}
345350
351+ impl < T : FromSql > FromSql for Vec < T > {
352+ fn from_sql < R : Read > ( ty : & Type , raw : & mut R , info : & SessionInfo ) -> Result < Vec < T > > {
353+ let member_type = match * ty. kind ( ) {
354+ Kind :: Array ( ref member) => member,
355+ _ => panic ! ( "expected array type" ) ,
356+ } ;
357+
358+ if try!( raw. read_i32 :: < BigEndian > ( ) ) != 1 {
359+ return Err ( Error :: Conversion ( "array contains too many dimensions" . into ( ) ) ) ;
360+ }
361+
362+ let _has_nulls = try!( raw. read_i32 :: < BigEndian > ( ) ) ;
363+ let _member_oid = try!( raw. read_u32 :: < BigEndian > ( ) ) ;
364+
365+ let count = try!( raw. read_i32 :: < BigEndian > ( ) ) ;
366+ let _index_offset = try!( raw. read_i32 :: < BigEndian > ( ) ) ;
367+
368+ let mut out = Vec :: with_capacity ( count as usize ) ;
369+ for _ in 0 ..count {
370+ let len = try!( raw. read_i32 :: < BigEndian > ( ) ) ;
371+ let value = if len < 0 {
372+ try!( T :: from_sql_null ( & member_type, info) )
373+ } else {
374+ let mut raw = raw. take ( len as u64 ) ;
375+ try!( T :: from_sql ( & member_type, & mut raw, info) )
376+ } ;
377+ out. push ( value)
378+ }
379+
380+ Ok ( out)
381+ }
382+
383+ fn accepts ( ty : & Type ) -> bool {
384+ match * ty. kind ( ) {
385+ Kind :: Array ( ref inner) => T :: accepts ( inner) ,
386+ _ => false ,
387+ }
388+ }
389+ }
390+
346391impl FromSql for Vec < u8 > {
347392 fn from_sql < R : Read > ( _: & Type , raw : & mut R , _: & SessionInfo ) -> Result < Vec < u8 > > {
348393 let mut buf = vec ! [ ] ;
@@ -496,6 +541,12 @@ pub enum IsNull {
496541/// In addition to the types listed above, `ToSql` is implemented for
497542/// `Option<T>` where `T` implements `ToSql`. An `Option<T>` represents a
498543/// nullable Postgres value.
544+ ///
545+ /// # Arrays
546+ ///
547+ /// `ToSql` is implemented for `Vec<T>` and `&[T]` where `T` implements `ToSql`,
548+ /// and corresponds to one-dimentional Postgres arrays with an index offset of
549+ /// 0.
499550pub trait ToSql : fmt:: Debug {
500551 /// Converts the value of `self` into the binary format of the specified
501552 /// Postgres `Type`, writing it to `out`.
@@ -573,6 +624,48 @@ impl ToSql for bool {
573624 accepts ! ( Type :: Bool ) ;
574625}
575626
627+ impl < ' a , T : ToSql > ToSql for & ' a [ T ] {
628+ to_sql_checked ! ( ) ;
629+
630+ fn to_sql < W : Write + ?Sized > ( & self , ty : & Type ,
631+ mut w : & mut W ,
632+ ctx : & SessionInfo )
633+ -> Result < IsNull > {
634+ let member_type = match * ty. kind ( ) {
635+ Kind :: Array ( ref member) => member,
636+ _ => panic ! ( "expected array type" ) ,
637+ } ;
638+
639+ try!( w. write_i32 :: < BigEndian > ( 1 ) ) ; // number of dimensions
640+ try!( w. write_i32 :: < BigEndian > ( 1 ) ) ; // has nulls
641+ try!( w. write_u32 :: < BigEndian > ( member_type. oid ( ) ) ) ;
642+
643+ try!( w. write_i32 :: < BigEndian > ( try!( downcast ( self . len ( ) ) ) ) ) ;
644+ try!( w. write_i32 :: < BigEndian > ( 0 ) ) ; // index offset
645+
646+ let mut inner_buf = vec ! [ ] ;
647+ for e in * self {
648+ match try!( e. to_sql ( & member_type, & mut inner_buf, ctx) ) {
649+ IsNull :: No => {
650+ try!( w. write_i32 :: < BigEndian > ( try!( downcast ( inner_buf. len ( ) ) ) ) ) ;
651+ try!( w. write_all ( & inner_buf) ) ;
652+ }
653+ IsNull :: Yes => try!( w. write_i32 :: < BigEndian > ( -1 ) ) ,
654+ }
655+ inner_buf. clear ( ) ;
656+ }
657+
658+ Ok ( IsNull :: No )
659+ }
660+
661+ fn accepts ( ty : & Type ) -> bool {
662+ match * ty. kind ( ) {
663+ Kind :: Array ( ref member) => T :: accepts ( member) ,
664+ _ => false ,
665+ }
666+ }
667+ }
668+
576669impl < ' a > ToSql for & ' a [ u8 ] {
577670 to_sql_checked ! ( ) ;
578671
@@ -584,6 +677,18 @@ impl<'a> ToSql for &'a [u8] {
584677 accepts ! ( Type :: Bytea ) ;
585678}
586679
680+ impl < T : ToSql > ToSql for Vec < T > {
681+ to_sql_checked ! ( ) ;
682+
683+ fn to_sql < W : Write + ?Sized > ( & self , ty : & Type , w : & mut W , ctx : & SessionInfo ) -> Result < IsNull > {
684+ <& [ T ] as ToSql >:: to_sql ( & & * * self , ty, w, ctx)
685+ }
686+
687+ fn accepts ( ty : & Type ) -> bool {
688+ <& [ T ] as ToSql >:: accepts ( ty)
689+ }
690+ }
691+
587692impl ToSql for Vec < u8 > {
588693 to_sql_checked ! ( ) ;
589694
0 commit comments