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 <sfackler@gmail.com>"]
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 as isize - 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
pub fn from_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() as i32 == 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-
pub fn from_vec(data: Vec<T>, lower_bound: isize) -> Array<T> {
73+
pub fn from_vec(data: Vec<T>, lower_bound: i32) -> Array<T> {
7474
Array {
7575
dims: vec![Dimension {
76-
len: data.len(),
76+
len: data.len() as i32,
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-
pub fn wrap(&mut self, lower_bound: isize) {
87+
pub fn wrap(&mut self, 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-
fn shift_idx(&self, indices: &[isize]) -> usize {
123+
fn shift_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
pub fn iter_mut<'a>(&'a mut self) -> 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+
pub fn into_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-
fn index<T>(&self, array: &Array<T>) -> usize;
164+
fn index<T>(&self, array: &Array<T>) -> i32;
159165
}
160166

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

167-
impl ArrayIndex for isize {
168-
fn index<T>(&self, array: &Array<T>) -> usize {
169-
let slice: &[isize] = &[*self];
173+
impl ArrayIndex for i32 {
174+
fn index<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
impl ArrayIndex for ($($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
type Output = T;
223229
fn index(&self, idx: I) -> &T {
224230
let idx = idx.index(self);
225-
&self.data[idx]
231+
&self.data[idx as usize]
226232
}
227233
}
228234

229235
impl<T, I: ArrayIndex> IndexMut<I> for Array<T> {
230236
fn index_mut(&mut self, idx: I) -> &mut T {
231237
let idx = idx.index(self);
232-
&mut self.data[idx]
238+
&mut self.data[idx as usize]
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> FromSql for Array<T>
1210
where T: FromSql
1311
{
14-
fn from_sql<R: Read>(ty: &Type, raw: &mut R, 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+
fn from_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>()) as usize;
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-
let mut dim_info = Vec::with_capacity(ndim);
25-
for _ in 0..ndim {
26-
dim_info.push(Dimension {
27-
len: try!(raw.read_u32::<BigEndian>()) as usize,
28-
lower_bound: try!(raw.read_i32::<BigEndian>()) as isize,
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-
let mut elements = Vec::with_capacity(nele);
38-
for _ in 0..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-
let mut limit = raw.take(len as u64);
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-
return Err(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
fn accepts(ty: &Type) -> bool {
@@ -65,44 +41,34 @@ impl<T> FromSql for Array<T>
6541
impl<T> ToSql for Array<T>
6642
where T: ToSql
6743
{
68-
fn to_sql<W: ?Sized + Write>(&self,
69-
ty: &Type,
70-
mut w: &mut W,
71-
info: &SessionInfo)
72-
-> postgres::Result<IsNull> {
44+
fn to_sql(&self, ty: &Type, w: &mut Vec<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 in self.dimensions() {
83-
try!(w.write_i32::<BigEndian>(try!(downcast(info.len))));
84-
85-
let bound = if info.lower_bound > i32::max_value() as isize ||
86-
info.lower_bound < i32::min_value() as isize {
87-
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
88-
return Err(Error::Conversion(err));
89-
} else {
90-
info.lower_bound as i32
91-
};
92-
try!(w.write_i32::<BigEndian>(bound));
93-
}
94-
95-
let mut inner_buf = vec![];
96-
for v in self {
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-
fn downcast(len: usize) -> Result<i32> {
121-
if len > i32::max_value() as usize {
122-
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
123-
Err(Error::Conversion(err))
124-
} else {
125-
Ok(len as i32)
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
use Array;
13693

13794
fn test_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
fn test_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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy