sqlite3_ext/value/value_list.rs
1use super::ValueRef;
2use crate::{ffi, sqlite3_match_version, sqlite3_require_version, types::*, FallibleIteratorMut};
3use std::ptr;
4
5/// Represents a list of values from SQLite.
6///
7/// SQLite provides these when a virtual table is processing all values of an IN constraint
8/// simultaneously, see
9/// [IndexInfoConstraint::set_value_list_wanted](crate::vtab::IndexInfoConstraint::set_value_list_wanted)
10/// for more information.
11///
12/// This struct is not an Iterator by itself. There are two recommended ways to interact with
13/// it. The first is a `while let`:
14///
15/// ```no_run
16/// use sqlite3_ext::*;
17///
18/// fn filter_list(list: &mut ValueRef) -> Result<()> {
19/// let mut list = ValueList::from_value_ref(list)?;
20/// while let Some(x) = list.next()? {
21/// println!("value is {:?}", x);
22/// }
23/// Ok(())
24/// }
25/// ```
26///
27/// Alternatively, the [map](Self::map) method turns this struct into a
28/// [FallibleIterator](crate::FallibleIterator):
29///
30/// ```no_run
31/// use sqlite3_ext::*;
32///
33/// fn filter_list(list: &mut ValueRef) -> Result<()> {
34/// let list: Vec<String> = ValueList::from_value_ref(list)?
35/// .map(|x| Ok(x.get_str()?.to_owned()))
36/// .collect()?;
37/// println!("values are {:?}", list);
38/// Ok(())
39/// }
40/// ```
41pub struct ValueList<'list> {
42 #[cfg_attr(not(modern_sqlite), allow(unused))]
43 base: &'list mut ValueRef,
44 #[cfg_attr(not(modern_sqlite), allow(unused))]
45 pending: Option<Option<ptr::NonNull<ffi::sqlite3_value>>>,
46}
47
48impl<'list> ValueList<'list> {
49 /// Attempt to create a ValueList from a ValueRef.
50 ///
51 /// # Safety
52 ///
53 /// The [SQLite documentation](https://www.sqlite.org/c3ref/vtab_in_first.html) states
54 /// that using this method outside of the
55 /// [VTabCursor::filter](crate::vtab::VTabCursor::filter) method is "undefined and
56 /// probably harmful". However, since the feature's introduction, the underlying
57 /// mechanism has always (as of SQLite 3.38.5) used the [pointer passing
58 /// interface](https://www.sqlite.org/bindptr.html) and is therefore be safe to use
59 /// with any ValueRef (although such a use will result in an Err).
60 ///
61 /// Requires SQLite 3.38.0.
62 pub fn from_value_ref(base: &'list mut ValueRef) -> Result<Self> {
63 let _ = base;
64 sqlite3_require_version!(3_038_000, unsafe {
65 let mut first: *mut ffi::sqlite3_value = ptr::null_mut();
66 Error::from_sqlite(ffi::sqlite3_vtab_in_first(base.as_ptr(), &mut first as _))?;
67 Ok(Self {
68 base,
69 pending: Some(ptr::NonNull::new(first)),
70 })
71 })
72 }
73}
74
75impl FallibleIteratorMut for ValueList<'_> {
76 type Item = ValueRef;
77 type Error = Error;
78
79 fn next(&mut self) -> Result<Option<&mut Self::Item>> {
80 sqlite3_match_version! {
81 3_038_000 => match self.pending.take() {
82 Some(Some(x)) => Ok(Some(unsafe { ValueRef::from_ptr(x.as_ptr()) })),
83 Some(None) => Ok(None),
84 None => {
85 let mut ret: *mut ffi::sqlite3_value = ptr::null_mut();
86 unsafe {
87 Error::from_sqlite(ffi::sqlite3_vtab_in_next(
88 self.base.as_ptr(),
89 &mut ret as _,
90 ))?;
91 if ret.is_null() {
92 Ok(None)
93 } else {
94 Ok(Some(ValueRef::from_ptr(ret)))
95 }
96 }
97 }
98 },
99 _ => unreachable!(),
100 }
101 }
102}