Skip to content

Commit 9a4b51e

Browse files
committed
Add INT4[] support
1 parent 369657c commit 9a4b51e

4 files changed

Lines changed: 378 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ types. The driver currently supports the following conversions:
256256
<td>types::range::Range&lt;Timespec&gt;</td>
257257
<td>TSRANGE, TSTZRANGE</td>
258258
</tr>
259+
<tr>
260+
<td>types::array::ArrayBase&lt;i32&gt;</td>
261+
<td>INT4[], INT4[][], ...</td>
262+
</tr>
259263
</tbody>
260264
</table>
261265

test.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use lib::error::{DbError,
3232
QueryCanceled,
3333
InvalidCatalogName};
3434
use lib::types::{ToSql, FromSql, PgInt4, PgVarchar};
35+
use lib::types::array::{ArrayBase};
3536
use lib::types::range::{Range, Inclusive, Exclusive, RangeBound};
3637
use lib::pool::PostgresConnectionPool;
3738

@@ -420,6 +421,19 @@ fn test_tstzrange_params() {
420421
test_timespec_range_params("TSTZRANGE");
421422
}
422423
424+
#[test]
425+
fn test_int4array_params() {
426+
test_type("INT4[]",
427+
[(Some(ArrayBase::from_vec(~[Some(0i32), Some(1), None], 1)),
428+
"'{0,1,NULL}'"),
429+
(None, "NULL")]);
430+
let mut a = ArrayBase::from_vec(~[Some(0i32), Some(1)], 0);
431+
a.wrap(-1);
432+
a.push_move(ArrayBase::from_vec(~[None, Some(3)], 0));
433+
test_type("INT4[][]",
434+
[(Some(a), "'[-1:0][0:1]={{0,1},{NULL,3}}'")]);
435+
}
436+
423437
fn test_nan_param<T: Float+ToSql+FromSql>(sql_type: &str) {
424438
let conn = PostgresConnection::connect("postgres://postgres@localhost", &NoSsl);
425439
let stmt = conn.prepare("SELECT 'NaN'::" + sql_type);

types/array.rs

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
//! Multi-dimensional arrays with per-dimension specifiable lower bounds
2+
3+
use std::cast;
4+
use std::vec::VecIterator;
5+
6+
#[deriving(Eq, Clone)]
7+
pub struct DimensionInfo {
8+
len: uint,
9+
lower_bound: int,
10+
}
11+
12+
pub trait Array<T> {
13+
fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo];
14+
fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T>;
15+
fn get<'a>(&'a self, idx: int) -> &'a T;
16+
}
17+
18+
pub trait MutableArray<T> : Array<T> {
19+
fn slice_mut<'a>(&'a mut self, idx: int) -> MutArraySlice<'a, T> {
20+
MutArraySlice { slice: self.slice(idx) }
21+
}
22+
23+
fn get_mut<'a>(&'a mut self, idx: int) -> &'a mut T {
24+
unsafe { cast::transmute_mut(self.get(idx)) }
25+
}
26+
}
27+
28+
trait InternalArray<T> : Array<T> {
29+
fn shift_idx(&self, idx: int) -> uint {
30+
let shifted_idx = idx - self.get_dimension_info()[0].lower_bound;
31+
assert!(shifted_idx >= 0, "Out of bounds array access");
32+
shifted_idx as uint
33+
}
34+
35+
fn raw_get<'a>(&'a self, idx: uint, size: uint) -> &'a T;
36+
}
37+
38+
#[deriving(Eq, Clone)]
39+
pub struct ArrayBase<T> {
40+
priv info: ~[DimensionInfo],
41+
priv data: ~[T],
42+
}
43+
44+
impl<T> ArrayBase<T> {
45+
pub fn from_raw(data: ~[T], info: ~[DimensionInfo])
46+
-> ArrayBase<T> {
47+
assert!(!info.is_empty(), "Cannot create a 0x0 array");
48+
assert!(data.len() == info.iter().fold(1, |acc, i| acc * i.len),
49+
"Size mismatch");
50+
ArrayBase {
51+
info: info,
52+
data: data,
53+
}
54+
}
55+
56+
pub fn from_vec(data: ~[T], lower_bound: int) -> ArrayBase<T> {
57+
ArrayBase {
58+
info: ~[DimensionInfo {
59+
len: data.len(),
60+
lower_bound: lower_bound
61+
}],
62+
data: data
63+
}
64+
}
65+
66+
pub fn wrap(&mut self, lower_bound: int) {
67+
self.info.unshift(DimensionInfo {
68+
len: 1,
69+
lower_bound: lower_bound
70+
})
71+
}
72+
73+
pub fn push_move(&mut self, other: ArrayBase<T>) {
74+
assert!(self.info.len() - 1 == other.info.len(),
75+
"Cannot append differently shaped arrays");
76+
for (info1, info2) in self.info.iter().skip(1).zip(other.info.iter()) {
77+
assert!(info1 == info2, "Cannot append differently shaped arrays");
78+
}
79+
self.info[0].len += 1;
80+
self.data.push_all_move(other.data);
81+
}
82+
83+
pub fn values<'a>(&'a self) -> VecIterator<'a, T> {
84+
self.data.iter()
85+
}
86+
}
87+
88+
impl<T> Array<T> for ArrayBase<T> {
89+
fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
90+
self.info.as_slice()
91+
}
92+
93+
fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
94+
ArraySlice {
95+
parent: BaseParent(self),
96+
idx: self.shift_idx(idx)
97+
}
98+
}
99+
100+
fn get<'a>(&'a self, idx: int) -> &'a T {
101+
assert!(self.info.len() == 1,
102+
"Attempted to get from a multi-dimensional array");
103+
self.raw_get(self.shift_idx(idx), 1)
104+
}
105+
}
106+
107+
impl<T> MutableArray<T> for ArrayBase<T> {}
108+
109+
impl<T> InternalArray<T> for ArrayBase<T> {
110+
fn raw_get<'a>(&'a self, idx: uint, _size: uint) -> &'a T {
111+
&self.data[idx]
112+
}
113+
}
114+
115+
enum ArrayParent<'parent, T> {
116+
SliceParent(&'parent ArraySlice<'parent, T>),
117+
BaseParent(&'parent ArrayBase<T>),
118+
}
119+
120+
pub struct ArraySlice<'parent, T> {
121+
priv parent: ArrayParent<'parent, T>,
122+
priv idx: uint,
123+
}
124+
125+
impl<'parent, T> Array<T> for ArraySlice<'parent, T> {
126+
fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
127+
let info = match self.parent {
128+
SliceParent(p) => p.get_dimension_info(),
129+
BaseParent(p) => p.get_dimension_info()
130+
};
131+
info.slice_from(1)
132+
}
133+
134+
fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
135+
ArraySlice {
136+
parent: SliceParent(self),
137+
idx: self.shift_idx(idx)
138+
}
139+
}
140+
141+
fn get<'a>(&'a self, idx: int) -> &'a T {
142+
assert!(self.get_dimension_info().len() == 1,
143+
"Attempted to get from a multi-dimensional array");
144+
self.raw_get(self.shift_idx(idx), 1)
145+
}
146+
}
147+
148+
impl<'parent, T> InternalArray<T> for ArraySlice<'parent, T> {
149+
fn raw_get<'a>(&'a self, idx: uint, size: uint) -> &'a T {
150+
let size = size * self.get_dimension_info()[0].len;
151+
let idx = size * self.idx + idx;
152+
match self.parent {
153+
SliceParent(p) => p.raw_get(idx, size),
154+
BaseParent(p) => p.raw_get(idx, size)
155+
}
156+
}
157+
}
158+
159+
pub struct MutArraySlice<'parent, T> {
160+
priv slice: ArraySlice<'parent, T>
161+
}
162+
163+
impl<'parent, T> Array<T> for MutArraySlice<'parent, T> {
164+
fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
165+
self.slice.get_dimension_info()
166+
}
167+
168+
fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
169+
self.slice.slice(idx)
170+
}
171+
172+
fn get<'a>(&'a self, idx: int) -> &'a T {
173+
self.slice.get(idx)
174+
}
175+
}
176+
177+
impl<'parent, T> MutableArray<T> for MutArraySlice<'parent, T> {}
178+
179+
#[cfg(test)]
180+
mod tests {
181+
use super::*;
182+
183+
#[test]
184+
fn test_from_vec() {
185+
let a = ArrayBase::from_vec(~[0, 1, 2], -1);
186+
assert_eq!([DimensionInfo { len: 3, lower_bound: -1 }],
187+
a.get_dimension_info());
188+
assert_eq!(&0, a.get(-1));
189+
assert_eq!(&1, a.get(0));
190+
assert_eq!(&2, a.get(1));
191+
}
192+
193+
#[test]
194+
#[should_fail]
195+
fn test_get_2d_fail() {
196+
let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
197+
a.wrap(1);
198+
a.get(1);
199+
}
200+
201+
#[test]
202+
#[should_fail]
203+
fn test_2d_slice_range_fail() {
204+
let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
205+
a.wrap(1);
206+
a.slice(0);
207+
}
208+
209+
#[test]
210+
fn test_2d_slice_get() {
211+
let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
212+
a.wrap(1);
213+
let s = a.slice(1);
214+
assert_eq!(&0, s.get(-1));
215+
assert_eq!(&1, s.get(0));
216+
assert_eq!(&2, s.get(1));
217+
}
218+
219+
#[test]
220+
#[should_fail]
221+
fn test_push_move_wrong_lower_bound() {
222+
let mut a = ArrayBase::from_vec(~[1], -1);
223+
a.push_move(ArrayBase::from_vec(~[2], 0));
224+
}
225+
226+
#[test]
227+
#[should_fail]
228+
fn test_push_move_wrong_dims() {
229+
let mut a = ArrayBase::from_vec(~[1], -1);
230+
a.wrap(1);
231+
a.push_move(ArrayBase::from_vec(~[1, 2], -1));
232+
}
233+
234+
#[test]
235+
#[should_fail]
236+
fn test_push_move_wrong_dim_count() {
237+
let mut a = ArrayBase::from_vec(~[1], -1);
238+
a.wrap(1);
239+
let mut b = ArrayBase::from_vec(~[2], -1);
240+
b.wrap(1);
241+
a.push_move(b);
242+
}
243+
244+
#[test]
245+
fn test_push_move_ok() {
246+
let mut a = ArrayBase::from_vec(~[1, 2], 0);
247+
a.wrap(0);
248+
a.push_move(ArrayBase::from_vec(~[3, 4], 0));
249+
let s = a.slice(0);
250+
assert_eq!(&1, s.get(0));
251+
assert_eq!(&2, s.get(1));
252+
let s = a.slice(1);
253+
assert_eq!(&3, s.get(0));
254+
assert_eq!(&4, s.get(1));
255+
}
256+
257+
#[test]
258+
fn test_3d() {
259+
let mut a = ArrayBase::from_vec(~[0, 1], 0);
260+
a.wrap(0);
261+
a.push_move(ArrayBase::from_vec(~[2, 3], 0));
262+
a.wrap(0);
263+
let mut b = ArrayBase::from_vec(~[4, 5], 0);
264+
b.wrap(0);
265+
b.push_move(ArrayBase::from_vec(~[6, 7], 0));
266+
a.push_move(b);
267+
let s1 = a.slice(0);
268+
let s2 = s1.slice(0);
269+
assert_eq!(&0, s2.get(0));
270+
assert_eq!(&1, s2.get(1));
271+
let s2 = s1.slice(1);
272+
assert_eq!(&2, s2.get(0));
273+
assert_eq!(&3, s2.get(1));
274+
let s1 = a.slice(1);
275+
let s2 = s1.slice(0);
276+
assert_eq!(&4, s2.get(0));
277+
assert_eq!(&5, s2.get(1));
278+
let s2 = s1.slice(1);
279+
assert_eq!(&6, s2.get(0));
280+
assert_eq!(&7, s2.get(1));
281+
}
282+
}

0 commit comments

Comments
 (0)