discord_cassandra_cpp/cassandra/
row.rs

1use crate::cassandra::error::*;
2
3use crate::cassandra::inet::Inet;
4use crate::cassandra::iterator::{MapIterator, SetIterator, UserTypeIterator};
5use crate::cassandra::result::CassResult;
6use crate::cassandra::util::{Protected, ProtectedInner};
7use crate::cassandra::uuid::Uuid;
8use crate::cassandra::value::Value;
9use crate::cassandra_sys::cass_false;
10use crate::cassandra_sys::cass_iterator_free;
11use crate::cassandra_sys::cass_iterator_from_row;
12use crate::cassandra_sys::cass_iterator_get_column;
13use crate::cassandra_sys::cass_iterator_next;
14use crate::cassandra_sys::cass_row_get_column;
15use crate::cassandra_sys::cass_row_get_column_by_name_n;
16use crate::cassandra_sys::cass_true;
17use crate::cassandra_sys::CassIterator as _CassIterator;
18use crate::cassandra_sys::CassRow as _Row;
19use std::fmt;
20use std::fmt::Debug;
21use std::fmt::Display;
22use std::fmt::Formatter;
23use std::iter;
24use std::iter::IntoIterator;
25use std::marker::PhantomData;
26use std::os::raw::c_char;
27
28/// A collection of column values. Read-only, so thread-safe.
29pub struct Row<'a>(*const _Row, PhantomData<&'a CassResult>);
30
31unsafe impl<'a> Sync for Row<'a> {}
32unsafe impl<'a> Send for Row<'a> {}
33
34impl<'a> ProtectedInner<*const _Row> for Row<'a> {
35    fn inner(&self) -> *const _Row {
36        self.0
37    }
38}
39
40impl<'a> Protected<*const _Row> for Row<'a> {
41    fn build(inner: *const _Row) -> Self {
42        if inner.is_null() {
43            panic!("Unexpected null pointer")
44        };
45        Row(inner, PhantomData)
46    }
47}
48
49impl<'a> Debug for Row<'a> {
50    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
51        for column in self {
52            write!(f, "{:?}\t", Value::build(column.inner()))?;
53        }
54        Ok(())
55    }
56}
57
58impl<'a> Display for Row<'a> {
59    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
60        for column in self {
61            write!(f, "{}\t", Value::build(column.inner()))?;
62        }
63        Ok(())
64    }
65}
66
67/// Auto inferencing conversion from c* to rust
68pub trait AsRustType<T> {
69    /// convert while reading cassandra columns
70    fn get(&self, index: usize) -> Result<T>;
71
72    /// convert while reading cassandra columns by name
73    fn get_by_name<S>(&self, name: S) -> Result<T>
74    where
75        S: Into<String>;
76}
77
78impl AsRustType<bool> for Row<'_> {
79    fn get(&self, index: usize) -> Result<bool> {
80        let col = self.get_column(index)?;
81        col.get_bool()
82    }
83
84    fn get_by_name<S>(&self, name: S) -> Result<bool>
85    where
86        S: Into<String>,
87    {
88        self.get_column_by_name(name)?.get_bool()
89    }
90}
91
92impl AsRustType<String> for Row<'_> {
93    fn get(&self, index: usize) -> Result<String> {
94        let col = self.get_column(index)?;
95        col.get_string()
96    }
97
98    fn get_by_name<S>(&self, name: S) -> Result<String>
99    where
100        S: Into<String>,
101    {
102        let col = self.get_column_by_name(name)?;
103        col.get_string()
104    }
105}
106
107impl AsRustType<f64> for Row<'_> {
108    fn get(&self, index: usize) -> Result<f64> {
109        let col = self.get_column(index)?;
110        col.get_f64()
111    }
112
113    fn get_by_name<S>(&self, name: S) -> Result<f64>
114    where
115        S: Into<String>,
116    {
117        let col = self.get_column_by_name(name)?;
118        col.get_f64()
119    }
120}
121
122impl AsRustType<f32> for Row<'_> {
123    fn get(&self, index: usize) -> Result<f32> {
124        let col = self.get_column(index)?;
125        col.get_f32()
126    }
127
128    fn get_by_name<S>(&self, name: S) -> Result<f32>
129    where
130        S: Into<String>,
131    {
132        let col = self.get_column_by_name(name)?;
133        col.get_f32()
134    }
135}
136
137impl AsRustType<i64> for Row<'_> {
138    fn get(&self, index: usize) -> Result<i64> {
139        let col = self.get_column(index)?;
140        col.get_i64()
141    }
142
143    fn get_by_name<S>(&self, name: S) -> Result<i64>
144    where
145        S: Into<String>,
146    {
147        let col = self.get_column_by_name(name)?;
148        col.get_i64()
149    }
150}
151
152impl AsRustType<i32> for Row<'_> {
153    fn get(&self, index: usize) -> Result<i32> {
154        let col = self.get_column(index)?;
155        col.get_i32()
156    }
157
158    fn get_by_name<S>(&self, name: S) -> Result<i32>
159    where
160        S: Into<String>,
161    {
162        let col = self.get_column_by_name(name)?;
163        col.get_i32()
164    }
165}
166
167impl AsRustType<i16> for Row<'_> {
168    fn get(&self, index: usize) -> Result<i16> {
169        let col = self.get_column(index)?;
170        col.get_i16()
171    }
172
173    fn get_by_name<S>(&self, name: S) -> Result<i16>
174    where
175        S: Into<String>,
176    {
177        let col = self.get_column_by_name(name)?;
178        col.get_i16()
179    }
180}
181
182impl AsRustType<i8> for Row<'_> {
183    fn get(&self, index: usize) -> Result<i8> {
184        let col = self.get_column(index)?;
185        col.get_i8()
186    }
187
188    fn get_by_name<S>(&self, name: S) -> Result<i8>
189    where
190        S: Into<String>,
191    {
192        let col = self.get_column_by_name(name)?;
193        col.get_i8()
194    }
195}
196
197impl AsRustType<u32> for Row<'_> {
198    fn get(&self, index: usize) -> Result<u32> {
199        let col = self.get_column(index)?;
200        col.get_u32()
201    }
202
203    fn get_by_name<S>(&self, name: S) -> Result<u32>
204    where
205        S: Into<String>,
206    {
207        let col = self.get_column_by_name(name)?;
208        col.get_u32()
209    }
210}
211
212impl AsRustType<Inet> for Row<'_> {
213    fn get(&self, index: usize) -> Result<Inet> {
214        let col = self.get_column(index)?;
215        col.get_inet()
216    }
217
218    fn get_by_name<S>(&self, name: S) -> Result<Inet>
219    where
220        S: Into<String>,
221    {
222        let col = self.get_column_by_name(name)?;
223        col.get_inet()
224    }
225}
226
227impl AsRustType<SetIterator> for Row<'_> {
228    fn get(&self, index: usize) -> Result<SetIterator> {
229        let col = self.get_column(index)?;
230        col.get_set()
231    }
232
233    fn get_by_name<S>(&self, name: S) -> Result<SetIterator>
234    where
235        S: Into<String>,
236    {
237        let col = self.get_column_by_name(name)?;
238        col.get_set()
239    }
240}
241
242impl AsRustType<MapIterator> for Row<'_> {
243    fn get(&self, index: usize) -> Result<MapIterator> {
244        let col = self.get_column(index)?;
245        col.get_map()
246    }
247
248    fn get_by_name<S>(&self, name: S) -> Result<MapIterator>
249    where
250        S: Into<String>,
251    {
252        let col = self.get_column_by_name(name)?;
253        col.get_map()
254    }
255}
256
257impl AsRustType<UserTypeIterator> for Row<'_> {
258    fn get(&self, index: usize) -> Result<UserTypeIterator> {
259        let col = self.get_column(index)?;
260        col.get_user_type()
261    }
262
263    fn get_by_name<S>(&self, name: S) -> Result<UserTypeIterator>
264    where
265        S: Into<String>,
266    {
267        let col = self.get_column_by_name(name)?;
268        col.get_user_type()
269    }
270}
271
272impl AsRustType<Uuid> for Row<'_> {
273    fn get(&self, index: usize) -> Result<Uuid> {
274        let col = self.get_column(index)?;
275        col.get_uuid()
276    }
277
278    fn get_by_name<S>(&self, name: S) -> Result<Uuid>
279    where
280        S: Into<String>,
281    {
282        let col = self.get_column_by_name(name)?;
283        col.get_uuid()
284    }
285}
286
287impl AsRustType<uuid::Uuid> for Row<'_> {
288    fn get(&self, index: usize) -> Result<uuid::Uuid> {
289        let col = self.get_column(index)?;
290        col.get_uuid().map(|x| x.into())
291    }
292
293    fn get_by_name<S>(&self, name: S) -> Result<uuid::Uuid>
294    where
295        S: Into<String>,
296    {
297        let col = self.get_column_by_name(name)?;
298        col.get_uuid().map(|x| x.into())
299    }
300}
301
302impl AsRustType<Vec<u8>> for Row<'_> {
303    fn get(&self, index: usize) -> Result<Vec<u8>> {
304        let col = self.get_column(index)?;
305        col.get_bytes().map(|b| b.to_vec())
306    }
307
308    fn get_by_name<S>(&self, name: S) -> Result<Vec<u8>>
309    where
310        S: Into<String>,
311    {
312        let col = self.get_column_by_name(name)?;
313        col.get_bytes().map(|b| b.to_vec())
314    }
315}
316
317impl<'a> Row<'a> {
318    /// Get a particular column by index
319    pub fn get_column(&self, index: usize) -> Result<Value> {
320        unsafe {
321            let col = cass_row_get_column(self.0, index);
322            if col.is_null() {
323                Err(CassErrorCode::LIB_INDEX_OUT_OF_BOUNDS.to_error())
324            } else {
325                Ok(Value::build(col))
326            }
327        }
328    }
329
330    /// Get a particular column by name
331    pub fn get_column_by_name<S>(&self, name: S) -> Result<Value>
332    where
333        S: Into<String>,
334    {
335        unsafe {
336            let name_str = name.into();
337            let name_ptr = name_str.as_ptr() as *const c_char;
338            let col = cass_row_get_column_by_name_n(self.0, name_ptr, name_str.len());
339            if col.is_null() {
340                Err(CassErrorCode::LIB_INDEX_OUT_OF_BOUNDS.to_error())
341            } else {
342                Ok(Value::build(col))
343            }
344        }
345    }
346}
347
348/// An iterator over the columns in a row
349#[derive(Debug)]
350pub struct RowIterator(pub *mut _CassIterator);
351
352// The underlying C type has no thread-local state, but does not support access
353// from multiple threads: https://datastax.github.io/cpp-driver/topics/#thread-safety
354unsafe impl Send for RowIterator {}
355
356impl Drop for RowIterator {
357    fn drop(&mut self) {
358        unsafe { cass_iterator_free(self.0) }
359    }
360}
361
362impl iter::Iterator for RowIterator {
363    type Item = Value;
364
365    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
366        unsafe {
367            match cass_iterator_next(self.0) {
368                cass_false => None,
369                cass_true => Some(Value::build(cass_iterator_get_column(self.0))),
370            }
371        }
372    }
373}
374
375impl<'a> Iterator for &'a RowIterator {
376    type Item = Value;
377
378    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
379        unsafe {
380            match cass_iterator_next(self.0) {
381                cass_false => None,
382                cass_true => Some(Value::build(cass_iterator_get_column(self.0))),
383            }
384        }
385    }
386}
387
388impl Display for RowIterator {
389    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
390        for item in self {
391            write!(f, "{}\t", Value::build(item.inner()))?;
392        }
393        Ok(())
394    }
395}
396
397impl IntoIterator for Row<'_> {
398    type Item = Value;
399    type IntoIter = RowIterator;
400
401    /// Creates a new iterator for the specified row. This can be
402    /// used to iterate over columns in a row.
403    fn into_iter(self) -> Self::IntoIter {
404        unsafe { RowIterator(cass_iterator_from_row(self.0)) }
405    }
406}
407
408impl<'a> IntoIterator for &'a Row<'_> {
409    type Item = Value;
410    type IntoIter = RowIterator;
411    fn into_iter(self) -> Self::IntoIter {
412        unsafe { RowIterator(cass_iterator_from_row(self.0)) }
413    }
414}