Skip to main content

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}