use crate::ffi::tarantool as ffi;
use crate::index::IndexId;
use crate::space::SpaceId;
use std::mem::align_of;
use std::mem::size_of;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ReadView {
inner: NonNull<ffi::box_read_view_t>,
space_indexes: Vec<(SpaceId, IndexId)>,
}
impl ReadView {
#[inline]
#[track_caller]
pub fn for_space_indexes(space_indexes: Vec<(SpaceId, IndexId)>) -> crate::Result<Self> {
const _: () = {
assert!(size_of::<(SpaceId, IndexId)>() == size_of::<ffi::space_index_id>());
assert!(align_of::<(SpaceId, IndexId)>() == align_of::<ffi::space_index_id>());
};
let loc = std::panic::Location::caller();
let name = format!("<rust@{}:{}>\0", loc.file(), loc.line());
let rv = unsafe {
ffi::box_read_view_open_for_given_spaces(
name.as_ptr() as _,
space_indexes.as_ptr() as _,
space_indexes.len() as _,
0,
)
};
let Some(rv) = NonNull::new(rv) else {
return Err(crate::error::TarantoolError::last().into());
};
Ok(Self {
inner: rv,
space_indexes,
})
}
#[inline(always)]
pub fn space_indexes(&self) -> Option<&[(SpaceId, IndexId)]> {
Some(&self.space_indexes)
}
#[inline]
pub fn iter_all(
&self,
space: SpaceId,
index: IndexId,
) -> crate::Result<Option<ReadViewIterator<'_>>> {
unsafe {
let mut iter = MaybeUninit::uninit();
let rc = ffi::box_read_view_iterator_all(
self.inner.as_ptr(),
space,
index,
iter.as_mut_ptr(),
);
if rc != 0 {
return Err(crate::error::TarantoolError::last().into());
}
let iter = iter.assume_init();
Ok(NonNull::new(iter).map(|inner| ReadViewIterator {
inner,
_marker: std::marker::PhantomData,
}))
}
}
}
impl Drop for ReadView {
#[inline(always)]
fn drop(&mut self) {
unsafe { ffi::box_read_view_close(self.inner.as_ptr()) }
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ReadViewIterator<'a> {
inner: NonNull<ffi::box_read_view_iterator_t>,
_marker: std::marker::PhantomData<&'a ()>,
}
impl<'a> Iterator for ReadViewIterator<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let mut data = MaybeUninit::uninit();
let mut size = MaybeUninit::uninit();
unsafe {
let rc = ffi::box_read_view_iterator_next_raw(
self.inner.as_ptr(),
data.as_mut_ptr(),
size.as_mut_ptr(),
);
if rc != 0 {
return None;
}
let data = data.assume_init();
let size = size.assume_init();
if data.is_null() {
return None;
}
Some(std::slice::from_raw_parts(data, size as _))
}
}
}
impl Drop for ReadViewIterator<'_> {
#[inline(always)]
fn drop(&mut self) {
unsafe { ffi::box_read_view_iterator_free(self.inner.as_ptr()) }
}
}
#[cfg(feature = "internal_test")]
mod tests {
use super::*;
use crate::space::Space;
use crate::space::SystemSpace;
use crate::temp_space_name;
#[crate::test(tarantool = "crate")]
fn read_view() {
let s = Space::builder(&temp_space_name!()).create().unwrap();
s.index_builder("pk").create().unwrap();
s.insert(&(1, 2, 3)).unwrap();
s.insert(&(2, "hello")).unwrap();
let rv = ReadView::for_space_indexes(vec![(s.id(), 0)]).unwrap();
assert_eq!(rv.iter_all(SystemSpace::Space as _, 0).unwrap(), None);
let mut iter = rv.iter_all(s.id(), 0).unwrap().unwrap();
assert_eq!(iter.next(), Some(&b"\x93\x01\x02\x03"[..]));
assert_eq!(iter.next(), Some(&b"\x92\x02\xa5hello"[..]));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
}
}