@@ -296,6 +296,11 @@ impl WrongTypeNew for WrongType {
296
296
/// In addition to the types listed above, `FromSql` is implemented for
297
297
/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
298
298
/// 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.
299
304
pub trait FromSql : Sized {
300
305
/// Creates a new value of this type from a `Read`er of the binary format
301
306
/// of the specified Postgres `Type`.
@@ -343,6 +348,46 @@ impl FromSql for bool {
343
348
accepts ! ( Type :: Bool ) ;
344
349
}
345
350
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
+
346
391
impl FromSql for Vec < u8 > {
347
392
fn from_sql < R : Read > ( _: & Type , raw : & mut R , _: & SessionInfo ) -> Result < Vec < u8 > > {
348
393
let mut buf = vec ! [ ] ;
@@ -496,6 +541,12 @@ pub enum IsNull {
496
541
/// In addition to the types listed above, `ToSql` is implemented for
497
542
/// `Option<T>` where `T` implements `ToSql`. An `Option<T>` represents a
498
543
/// 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.
499
550
pub trait ToSql : fmt:: Debug {
500
551
/// Converts the value of `self` into the binary format of the specified
501
552
/// Postgres `Type`, writing it to `out`.
@@ -573,6 +624,48 @@ impl ToSql for bool {
573
624
accepts ! ( Type :: Bool ) ;
574
625
}
575
626
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
+
576
669
impl < ' a > ToSql for & ' a [ u8 ] {
577
670
to_sql_checked ! ( ) ;
578
671
@@ -584,6 +677,18 @@ impl<'a> ToSql for &'a [u8] {
584
677
accepts ! ( Type :: Bytea ) ;
585
678
}
586
679
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
+
587
692
impl ToSql for Vec < u8 > {
588
693
to_sql_checked ! ( ) ;
589
694
0 commit comments