use std::os::raw::c_char;
use std::ptr::null_mut;
use num_traits::ToPrimitive;
use crate::error::{Error, TarantoolError};
use crate::tuple::{ffi::BoxTuple, AsTuple, Tuple, TupleBuffer};
pub struct Index {
space_id: u32,
index_id: u32,
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, ToPrimitive)]
pub enum IteratorType {
Eq = 0,
Req = 1,
All = 2,
LT = 3,
LE = 4,
GE = 5,
GT = 6,
BitsAllSet = 7,
BitsAnySet = 8,
BitsAllNotSet = 9,
Ovelaps = 10,
Neigbor = 11,
}
impl Index {
pub(crate) fn new(space_id: u32, index_id: u32) -> Self {
Index { space_id, index_id }
}
pub fn get<K>(&self, key: &K) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe {
ffi::box_index_get(
self.space_id,
self.index_id,
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
&mut result_ptr,
)
} < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn select<K>(&self, iterator_type: IteratorType, key: &K) -> Result<IndexIterator, Error>
where
K: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let ptr = unsafe {
ffi::box_index_iterator(
self.space_id,
self.index_id,
iterator_type.to_i32().unwrap(),
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
)
};
if ptr.is_null() {
return Err(TarantoolError::last().into());
}
Ok(IndexIterator {
ptr,
_key_data: key_buf,
})
}
pub fn delete<K>(&mut self, key: &K) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe {
ffi::box_delete(
self.space_id,
self.index_id,
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
&mut result_ptr,
)
} < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn update<K, Op>(&mut self, key: &K, ops: &Vec<Op>) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
Op: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let ops_buf = ops.serialize_as_tuple().unwrap();
let ops_buf_ptr = ops_buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe {
ffi::box_update(
self.space_id,
self.index_id,
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
ops_buf_ptr,
ops_buf_ptr.offset(ops_buf.len() as isize),
0,
&mut result_ptr,
)
} < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn upsert<T, Op>(&mut self, value: &T, ops: &Vec<Op>) -> Result<Option<Tuple>, Error>
where
T: AsTuple,
Op: AsTuple,
{
let value_buf = value.serialize_as_tuple().unwrap();
let value_buf_ptr = value_buf.as_ptr() as *const c_char;
let ops_buf = ops.serialize_as_tuple().unwrap();
let ops_buf_ptr = ops_buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe {
ffi::box_upsert(
self.space_id,
self.index_id,
value_buf_ptr,
value_buf_ptr.offset(value_buf.len() as isize),
ops_buf_ptr,
ops_buf_ptr.offset(ops_buf.len() as isize),
0,
&mut result_ptr,
)
} < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn len(&self) -> Result<usize, Error> {
let result = unsafe { ffi::box_index_len(self.space_id, self.index_id) };
if result < 0 {
Err(TarantoolError::last().into())
} else {
Ok(result as usize)
}
}
pub fn bsize(&self) -> Result<usize, Error> {
let result = unsafe { ffi::box_index_bsize(self.space_id, self.index_id) };
if result < 0 {
Err(TarantoolError::last().into())
} else {
Ok(result as usize)
}
}
pub fn random(&self, seed: u32) -> Result<Option<Tuple>, Error> {
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe { ffi::box_index_random(self.space_id, self.index_id, seed, &mut result_ptr) } < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn min<K>(&self, key: &K) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe {
ffi::box_index_min(
self.space_id,
self.index_id,
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
&mut result_ptr,
)
} < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn max<K>(&self, key: &K) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe {
ffi::box_index_max(
self.space_id,
self.index_id,
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
&mut result_ptr,
)
} < 0
{
return Err(TarantoolError::last().into());
}
Ok(if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
})
}
pub fn count<K>(&self, iterator_type: IteratorType, key: &K) -> Result<usize, Error>
where
K: AsTuple,
{
let key_buf = key.serialize_as_tuple().unwrap();
let key_buf_ptr = key_buf.as_ptr() as *const c_char;
let result = unsafe {
ffi::box_index_count(
self.space_id,
self.index_id,
iterator_type.to_i32().unwrap(),
key_buf_ptr,
key_buf_ptr.offset(key_buf.len() as isize),
)
};
if result < 0 {
Err(TarantoolError::last().into())
} else {
Ok(result as usize)
}
}
pub fn extract_key(&self, tuple: Tuple) -> Tuple {
let mut result_size: u32 = 0;
let result_ptr = unsafe {
ffi::box_tuple_extract_key(
tuple.into_ptr(),
self.space_id,
self.index_id,
&mut result_size,
)
};
Tuple::from_raw_data(result_ptr, result_size)
}
}
pub struct IndexIterator {
ptr: *mut ffi::BoxIterator,
_key_data: TupleBuffer,
}
impl Iterator for IndexIterator {
type Item = Tuple;
fn next(&mut self) -> Option<Self::Item> {
let mut result_ptr = null_mut::<BoxTuple>();
if unsafe { ffi::box_iterator_next(self.ptr, &mut result_ptr) } < 0 {
return None;
}
if result_ptr.is_null() {
None
} else {
Some(Tuple::from_ptr(result_ptr))
}
}
}
impl Drop for IndexIterator {
fn drop(&mut self) {
unsafe { ffi::box_iterator_free(self.ptr) };
}
}
mod ffi {
use std::os::raw::{c_char, c_int};
use crate::tuple::ffi::BoxTuple;
#[repr(C)]
pub struct BoxIterator {
_unused: [u8; 0],
}
extern "C" {
pub fn box_index_iterator(
space_id: u32,
index_id: u32,
type_: c_int,
key: *const c_char,
key_end: *const c_char,
) -> *mut BoxIterator;
pub fn box_iterator_next(iterator: *mut BoxIterator, result: *mut *mut BoxTuple) -> c_int;
pub fn box_iterator_free(iterator: *mut BoxIterator);
pub fn box_index_len(space_id: u32, index_id: u32) -> isize;
pub fn box_index_bsize(space_id: u32, index_id: u32) -> isize;
pub fn box_index_random(
space_id: u32,
index_id: u32,
rnd: u32,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_index_get(
space_id: u32,
index_id: u32,
key: *const c_char,
key_end: *const c_char,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_index_min(
space_id: u32,
index_id: u32,
key: *const c_char,
key_end: *const c_char,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_index_max(
space_id: u32,
index_id: u32,
key: *const c_char,
key_end: *const c_char,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_index_count(
space_id: u32,
index_id: u32,
type_: c_int,
key: *const c_char,
key_end: *const c_char,
) -> isize;
pub fn box_delete(
space_id: u32,
index_id: u32,
key: *const c_char,
key_end: *const c_char,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_update(
space_id: u32,
index_id: u32,
key: *const c_char,
key_end: *const c_char,
ops: *const c_char,
ops_end: *const c_char,
index_base: c_int,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_upsert(
space_id: u32,
index_id: u32,
tuple: *const c_char,
tuple_end: *const c_char,
ops: *const c_char,
ops_end: *const c_char,
index_base: c_int,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_tuple_extract_key(
tuple: *const BoxTuple,
space_id: u32,
index_id: u32,
key_size: *mut u32,
) -> *mut c_char;
}
}