Skip to content

Commit 009d93e

Browse files
committed
Merge branch 'release-v0.7.0' into release
2 parents 3243417 + b199087 commit 009d93e

File tree

6 files changed

+108
-136
lines changed

6 files changed

+108
-136
lines changed

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
/target
22
/Cargo.lock
3+
/.idea
4+
*.iml

‎Cargo.toml‎

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
[package]
22
name = "postgres_array"
3-
version = "0.6.2"
3+
version = "0.7.0"
44
authors = ["Steven Fackler <[email protected]>"]
55
license = "MIT"
66
description = "Array support for rust-postgres"
77
repository = "https://github.com/sfackler/rust-postgres-array"
8-
documentation = "https://sfackler.github.io/rust-postgres-array/doc/v0.6.2/postgres_array"
8+
documentation = "https://sfackler.github.io/rust-postgres-array/doc/v0.7.0/postgres_array"
99

1010
[dependencies]
11-
postgres = "0.11"
12-
byteorder = "0.5"
13-
14-
[dev-dependencies]
15-
rustc-serialize = "0.3"
16-
time = "0.1"
17-
uuid = "0.1"
18-
postgres ={version = "0.11", features = ["rustc-serialize", "time", "uuid"] }
11+
fallible-iterator = "0.1"
12+
postgres = "0.12"
13+
postgres-protocol = "0.1"

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# rust-postgres-array
22
[![Build Status](https://travis-ci.org/sfackler/rust-postgres-array.svg?branch=master)](https://travis-ci.org/sfackler/rust-postgres-array)
33

4-
[Documentation](https://sfackler.github.io/rust-postgres-array/doc/v0.6.2/postgres_array)
4+
[Documentation](https://sfackler.github.io/rust-postgres-array/doc/v0.7.0/postgres_array)
55

66
Support for PostgreSQL arrays in [rust-postgres](https://github.com/sfackler/rust-postgres).

‎src/array.rs‎

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl<T: fmt::Display> fmt::Display for Array<T>{
1919
try!(write!(fmt,
2020
"[{}:{}]",
2121
dim.lower_bound,
22-
dim.lower_bound + dim.len asisize- 1));
22+
dim.lower_bound + dim.len - 1));
2323
}
2424
try!(write!(fmt,"="));
2525
}
@@ -61,7 +61,7 @@ impl<T> Array<T>{
6161
/// elements specified by the dimensions.
6262
pubfnfrom_parts(data:Vec<T>,dimensions:Vec<Dimension>) -> Array<T>{
6363
assert!((data.is_empty() && dimensions.is_empty()) ||
64-
data.len() == dimensions.iter().fold(1, |acc, i| acc * i.len),
64+
data.len()asi32== dimensions.iter().fold(1, |acc, i| acc * i.len),
6565
"size mismatch");
6666
Array{
6767
dims: dimensions,
@@ -70,10 +70,10 @@ impl<T> Array<T>{
7070
}
7171

7272
/// Creates a new one-dimensional array.
73-
pubfnfrom_vec(data:Vec<T>,lower_bound:isize) -> Array<T>{
73+
pubfnfrom_vec(data:Vec<T>,lower_bound:i32) -> Array<T>{
7474
Array{
7575
dims:vec![Dimension{
76-
len: data.len(),
76+
len: data.len()asi32,
7777
lower_bound: lower_bound,
7878
}],
7979
data: data,
@@ -84,7 +84,7 @@ impl<T> Array<T>{
8484
///
8585
/// For example, the one dimensional array `[1, 2]` would turn into the
8686
/// two-dimensional array `[[1, 2]]`.
87-
pubfnwrap(&mutself,lower_bound:isize){
87+
pubfnwrap(&mutself,lower_bound:i32){
8888
self.dims.insert(0,
8989
Dimension{
9090
len:1,
@@ -120,7 +120,7 @@ impl<T> Array<T>{
120120
&self.dims
121121
}
122122

123-
fnshift_idx(&self,indices:&[isize]) -> usize{
123+
fnshift_idx(&self,indices:&[i32]) -> i32{
124124
assert_eq!(self.dims.len(), indices.len());
125125
self.dims
126126
.iter()
@@ -144,6 +144,12 @@ impl<T> Array<T>{
144144
pubfniter_mut<'a>(&'amutself) -> IterMut<'a,T>{
145145
IterMut{inner:self.data.iter_mut()}
146146
}
147+
148+
/// Returns the underlying data vector for this Array in the
149+
/// higher-dimensional equivalent of row-major order.
150+
pubfninto_inner(self) -> Vec<T>{
151+
self.data
152+
}
147153
}
148154

149155
/// A trait implemented by types that can index into an `Array`.
@@ -155,51 +161,51 @@ pub trait ArrayIndex{
155161
///
156162
/// Panics if the value of `self` does not correspond to an in-bounds
157163
/// element of the `Array`.
158-
fnindex<T>(&self,array:&Array<T>) -> usize;
164+
fnindex<T>(&self,array:&Array<T>) -> i32;
159165
}
160166

161-
impl<'a>ArrayIndexfor&'a[isize]{
162-
fnindex<T>(&self,array:&Array<T>) -> usize{
167+
impl<'a>ArrayIndexfor&'a[i32]{
168+
fnindex<T>(&self,array:&Array<T>) -> i32{
163169
array.shift_idx(*self)
164170
}
165171
}
166172

167-
implArrayIndexforisize{
168-
fnindex<T>(&self,array:&Array<T>) -> usize{
169-
let slice:&[isize] = &[*self];
173+
implArrayIndexfori32{
174+
fnindex<T>(&self,array:&Array<T>) -> i32{
175+
let slice:&[i32] = &[*self];
170176
ArrayIndex::index(&slice, array)
171177
}
172178
}
173179

174180
macro_rules! tuple_impl {
175181
($($name:ident : $t:ty),+) => {
176182
implArrayIndexfor($($t,)+){
177-
fn index<T>(&self, array:&Array<T>) -> usize{
183+
fn index<T>(&self, array:&Array<T>) -> i32{
178184
let($($name,)+) = *self;
179-
let slice:&[isize] = &[$($name),+];
185+
let slice:&[i32] = &[$($name),+];
180186
ArrayIndex::index(&slice, array)
181187
}
182188
}
183189
}
184190
}
185191

186-
tuple_impl!(a:isize);
187-
tuple_impl!(a:isize, b:isize);
188-
tuple_impl!(a:isize, b:isize, c:isize);
189-
tuple_impl!(a:isize, b:isize, c:isize, d:isize);
190-
tuple_impl!(a:isize, b:isize, c:isize, d:isize, e:isize);
191-
tuple_impl!(a:isize, b:isize, c:isize, d:isize, e:isize, f:isize);
192-
tuple_impl!(a:isize, b:isize, c:isize, d:isize, e:isize, f:isize, g:isize);
193-
tuple_impl!(a:isize, b:isize, c:isize, d:isize, e:isize, f:isize, g:isize, h:isize);
194-
tuple_impl!(a:isize, b:isize, c:isize, d:isize, e:isize, f:isize, g:isize, h:isize, i:isize);
192+
tuple_impl!(a:i32);
193+
tuple_impl!(a:i32, b:i32);
194+
tuple_impl!(a:i32, b:i32, c:i32);
195+
tuple_impl!(a:i32, b:i32, c:i32, d:i32);
196+
tuple_impl!(a:i32, b:i32, c:i32, d:i32, e:i32);
197+
tuple_impl!(a:i32, b:i32, c:i32, d:i32, e:i32, f:i32);
198+
tuple_impl!(a:i32, b:i32, c:i32, d:i32, e:i32, f:i32, g:i32);
199+
tuple_impl!(a:i32, b:i32, c:i32, d:i32, e:i32, f:i32, g:i32, h:i32);
200+
tuple_impl!(a:i32, b:i32, c:i32, d:i32, e:i32, f:i32, g:i32, h:i32, i:i32);
195201

196202
/// Indexes into the `Array`, retrieving a reference to the contained
197203
/// value.
198204
///
199205
/// Since `Array`s can be multi-dimensional, the `Index` trait is
200206
/// implemented for a variety of index types. In the most generic case, a
201-
/// `&[isize]` can be used. In addition, a bare `isize` as well as tuples
202-
/// of up to 10 `isize` values may be used for convenience.
207+
/// `&[i32]` can be used. In addition, a bare `i32` as well as tuples
208+
/// of up to 10 `i32` values may be used for convenience.
203209
///
204210
/// # Panics
205211
///
@@ -222,14 +228,14 @@ impl<T, I: ArrayIndex> Index<I> for Array<T>{
222228
typeOutput = T;
223229
fnindex(&self,idx:I) -> &T{
224230
let idx = idx.index(self);
225-
&self.data[idx]
231+
&self.data[idxasusize]
226232
}
227233
}
228234

229235
impl<T,I:ArrayIndex>IndexMut<I>forArray<T>{
230236
fnindex_mut(&mutself,idx:I) -> &mutT{
231237
let idx = idx.index(self);
232-
&mutself.data[idx]
238+
&mutself.data[idxasusize]
233239
}
234240
}
235241

‎src/impls.rs‎

Lines changed: 45 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,33 @@
1-
use std::io::prelude::*;
2-
use std::error;
3-
use byteorder::{ReadBytesExt,WriteBytesExt,BigEndian};
4-
5-
use postgres::{self,Result};
6-
use postgres::error::Error;
7-
use postgres::types::{Type,Kind,ToSql,FromSql,Oid,IsNull,SessionInfo};
1+
use fallible_iterator::FallibleIterator;
2+
use postgres::types::{Type,Kind,ToSql,FromSql,IsNull,SessionInfo};
3+
use postgres_protocol::types;
4+
use postgres_protocol;
5+
use std::error::Error;
86

97
use{Array,Dimension};
108

119
impl<T>FromSqlforArray<T>
1210
whereT:FromSql
1311
{
14-
fnfrom_sql<R:Read>(ty:&Type,raw:&mutR,info:&SessionInfo) -> postgres::Result<Array<T>>{
15-
let element_type = match ty.kind(){
16-
&Kind::Array(ref ty) => ty,
17-
_ => panic!("unexpected type{:?}", ty),
12+
fnfrom_sql(ty:&Type,raw:&[u8],info:&SessionInfo) -> Result<Array<T>,Box<Error + Sync + Send>>{
13+
let element_type = match*ty.kind(){
14+
Kind::Array(ref ty) => ty,
15+
_ => unreachable!(),
1816
};
1917

20-
let ndim = try!(raw.read_u32::<BigEndian>())asusize;
21-
let _has_null = try!(raw.read_i32::<BigEndian>()) == 1;
22-
let _element_type:Oid = try!(raw.read_u32::<BigEndian>());
18+
let array = try!(types::array_from_sql(raw));
2319

24-
letmut dim_info = Vec::with_capacity(ndim);
25-
for _ in0..ndim {
26-
dim_info.push(Dimension{
27-
len: try!(raw.read_u32::<BigEndian>())asusize,
28-
lower_bound: try!(raw.read_i32::<BigEndian>())asisize,
29-
});
30-
}
31-
let nele = if dim_info.len() == 0{
32-
0
33-
}else{
34-
dim_info.iter().fold(1, |product, info| product * info.len)
35-
};
20+
let dimensions = try!(array.dimensions()
21+
.map(|d| {
22+
Dimension{len: d.len,lower_bound: d.lower_bound}
23+
})
24+
.collect());
3625

37-
letmut elements = Vec::with_capacity(nele);
38-
for _ in0..nele {
39-
let len = try!(raw.read_i32::<BigEndian>());
40-
if len < 0{
41-
elements.push(try!(FromSql::from_sql_null(&element_type, info)));
42-
}else{
43-
letmut limit = raw.take(len asu64);
44-
elements.push(try!(FromSql::from_sql(&element_type,&mut limit, info)));
45-
if limit.limit() != 0{
46-
let err:Box<error::Error + Sync + Send> = "from_sql call did not consume all \
47-
data"
48-
.into();
49-
returnErr(Error::Conversion(err));
50-
}
51-
}
52-
}
26+
let elements = try!(array.values()
27+
.and_then(|v| FromSql::from_sql_nullable(element_type, v, info))
28+
.collect());
5329

54-
Ok(Array::from_parts(elements,dim_info))
30+
Ok(Array::from_parts(elements,dimensions))
5531
}
5632

5733
fnaccepts(ty:&Type) -> bool{
@@ -65,44 +41,34 @@ impl<T> FromSql for Array<T>
6541
impl<T>ToSqlforArray<T>
6642
whereT:ToSql
6743
{
68-
fnto_sql<W: ?Sized + Write>(&self,
69-
ty:&Type,
70-
mutw:&mutW,
71-
info:&SessionInfo)
72-
-> postgres::Result<IsNull>{
44+
fnto_sql(&self,ty:&Type,w:&mutVec<u8>,info:&SessionInfo) -> Result<IsNull,Box<Error + Sync + Send>>{
7345
let element_type = match ty.kind(){
7446
&Kind::Array(ref ty) => ty,
75-
_ => panic!("unexpected type{:?}", ty),
47+
_ => unreachable!(),
7648
};
7749

78-
try!(w.write_i32::<BigEndian>(try!(downcast(self.dimensions().len()))));
79-
try!(w.write_i32::<BigEndian>(1));
80-
try!(w.write_u32::<BigEndian>(element_type.oid()));
81-
82-
for info inself.dimensions(){
83-
try!(w.write_i32::<BigEndian>(try!(downcast(info.len))));
84-
85-
let bound = if info.lower_bound > i32::max_value()asisize ||
86-
info.lower_bound < i32::min_value()asisize{
87-
let err:Box<error::Error + Sync + Send> = "value too large to transmit".into();
88-
returnErr(Error::Conversion(err));
89-
}else{
90-
info.lower_boundasi32
91-
};
92-
try!(w.write_i32::<BigEndian>(bound));
93-
}
94-
95-
letmut inner_buf = vec![];
96-
for v inself{
97-
match try!(v.to_sql(element_type,&mut inner_buf, info)){
98-
IsNull::Yes => try!(w.write_i32::<BigEndian>(-1)),
99-
IsNull::No => {
100-
try!(w.write_i32::<BigEndian>(try!(downcast(inner_buf.len()))));
101-
try!(w.write_all(&inner_buf));
50+
let dimensions = self.dimensions()
51+
.iter()
52+
.map(|d| {
53+
types::ArrayDimension{
54+
len: d.len,
55+
lower_bound: d.lower_bound,
10256
}
103-
}
104-
inner_buf.clear();
105-
}
57+
});
58+
let elements = self.iter();
59+
60+
try!(types::array_to_sql(dimensions,
61+
true,
62+
element_type.oid(),
63+
elements,
64+
|v, w| {
65+
match v.to_sql(element_type, w, info){
66+
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
67+
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
68+
Err(e) => Err(e),
69+
}
70+
},
71+
w));
10672

10773
Ok(IsNull::No)
10874
}
@@ -117,26 +83,17 @@ impl<T> ToSql for Array<T>
11783
to_sql_checked!();
11884
}
11985

120-
fndowncast(len:usize) -> Result<i32>{
121-
if len > i32::max_value()asusize{
122-
let err:Box<error::Error + Sync + Send> = "value too large to transmit".into();
123-
Err(Error::Conversion(err))
124-
}else{
125-
Ok(len asi32)
126-
}
127-
}
128-
12986
#[cfg(test)]
13087
mod test {
13188
use std::fmt;
13289

133-
use postgres::{Connection,SslMode};
90+
use postgres::{Connection,TlsMode};
13491
use postgres::types::{FromSql,ToSql};
13592
useArray;
13693

13794
fntest_type<T:PartialEq + FromSql + ToSql,S: fmt::Display>(sql_type:&str,
13895
checks:&[(T,S)]){
139-
let conn = Connection::connect("postgres://postgres@localhost",SslMode::None).unwrap();
96+
let conn = Connection::connect("postgres://postgres@localhost",TlsMode::None).unwrap();
14097
for&(ref val,ref repr)in checks.iter(){
14198
let stmt = conn.prepare(&format!("SELECT{}::{}",*repr, sql_type)).unwrap();
14299
let result = stmt.query(&[]).unwrap().iter().next().unwrap().get(0);
@@ -256,7 +213,7 @@ mod test{
256213

257214
#[test]
258215
fntest_empty_array(){
259-
let conn = Connection::connect("postgres://postgres@localhost",SslMode::None).unwrap();
216+
let conn = Connection::connect("postgres://postgres@localhost",TlsMode::None).unwrap();
260217
let stmt = conn.prepare("SELECT '{}'::INT4[]").unwrap();
261218
stmt.query(&[]).unwrap().iter().next().unwrap().get::<_,Array<i32>>(0);
262219
}

0 commit comments

Comments
(0)