use std::os::raw::c_char;
use std::ptr::null_mut;
use num_traits::ToPrimitive;
use crate::error::{Error, TarantoolError};
use crate::index::{Index, IndexIterator, IteratorType};
use crate::tuple::{AsTuple, Tuple};
#[repr(u32)]
#[derive(Debug, Clone, PartialEq, ToPrimitive)]
pub enum SystemSpace {
VinylDeferredDelete = 257,
Schema = 272,
Collation = 276,
VCollation = 277,
Space = 280,
VSpace = 281,
Sequence = 284,
SequenceData = 285,
VSequence = 286,
Index = 288,
VIndex = 289,
Func = 296,
VFunc = 297,
User = 304,
VUser = 305,
Priv = 312,
VPriv = 313,
Cluster = 320,
Trigger = 328,
Truncate = 330,
SpaceSequence = 340,
FkConstraint = 356,
CkConstraint = 364,
FuncIndex = 372,
SessionSettings = 380,
}
impl Into<Space> for SystemSpace {
fn into(self) -> Space {
Space {
id: self.to_u32().unwrap(),
}
}
}
pub struct Space {
id: u32,
}
impl Space {
pub fn find(name: &str) -> Option<Self> {
let id =
unsafe { ffi::box_space_id_by_name(name.as_ptr() as *const c_char, name.len() as u32) };
if id == ffi::BOX_ID_NIL {
None
} else {
Some(Self { id })
}
}
pub fn index(&self, name: &str) -> Option<Index> {
let index_id = unsafe {
ffi::box_index_id_by_name(self.id, name.as_ptr() as *const c_char, name.len() as u32)
};
if index_id == ffi::BOX_ID_NIL {
None
} else {
Some(Index::new(self.id, index_id))
}
}
#[inline(always)]
pub fn primary_key(&self) -> Index {
Index::new(self.id, 0)
}
pub fn insert<T>(&mut self, value: &T) -> Result<Option<Tuple>, Error>
where
T: AsTuple,
{
let buf = value.serialize_as_tuple().unwrap();
let buf_ptr = buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<ffi::BoxTuple>();
if unsafe {
ffi::box_insert(
self.id,
buf_ptr,
buf_ptr.offset(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 replace<T>(&mut self, value: &T) -> Result<Option<Tuple>, Error>
where
T: AsTuple,
{
let buf = value.serialize_as_tuple().unwrap();
let buf_ptr = buf.as_ptr() as *const c_char;
let mut result_ptr = null_mut::<ffi::BoxTuple>();
if unsafe {
ffi::box_replace(
self.id,
buf_ptr,
buf_ptr.offset(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))
})
}
#[inline(always)]
pub fn put<T>(&mut self, value: &T) -> Result<Option<Tuple>, Error>
where
T: AsTuple,
{
self.replace(value)
}
pub fn truncate(&mut self) -> Result<(), Error> {
if unsafe { ffi::box_truncate(self.id) } < 0 {
return Err(TarantoolError::last().into());
}
Ok(())
}
#[inline(always)]
pub fn len(&self) -> Result<usize, Error> {
self.primary_key().len()
}
#[inline(always)]
pub fn bsize(&self) -> Result<usize, Error> {
self.primary_key().bsize()
}
#[inline(always)]
pub fn get<K>(&self, key: &K) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
{
self.primary_key().get(key)
}
#[inline(always)]
pub fn select<K>(&self, iterator_type: IteratorType, key: &K) -> Result<IndexIterator, Error>
where
K: AsTuple,
{
self.primary_key().select(iterator_type, key)
}
pub fn count<K>(&self, iterator_type: IteratorType, key: &K) -> Result<usize, Error>
where
K: AsTuple,
{
self.primary_key().count(iterator_type, key)
}
#[inline(always)]
pub fn delete<K>(&mut self, key: &K) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
{
self.primary_key().delete(key)
}
#[inline(always)]
pub fn update<K, Op>(&mut self, key: &K, ops: &Vec<Op>) -> Result<Option<Tuple>, Error>
where
K: AsTuple,
Op: AsTuple,
{
self.primary_key().update(key, ops)
}
#[inline(always)]
pub fn upsert<T, Op>(&mut self, value: &T, ops: &Vec<Op>) -> Result<Option<Tuple>, Error>
where
T: AsTuple,
Op: AsTuple,
{
self.primary_key().upsert(value, ops)
}
}
mod ffi {
use std::os::raw::{c_char, c_int};
pub use crate::tuple::ffi::BoxTuple;
pub const BOX_ID_NIL: u32 = 2147483647;
extern "C" {
pub fn box_space_id_by_name(name: *const c_char, len: u32) -> u32;
pub fn box_index_id_by_name(space_id: u32, name: *const c_char, len: u32) -> u32;
pub fn box_insert(
space_id: u32,
tuple: *const c_char,
tuple_end: *const c_char,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_replace(
space_id: u32,
tuple: *const c_char,
tuple_end: *const c_char,
result: *mut *mut BoxTuple,
) -> c_int;
pub fn box_truncate(space_id: u32) -> c_int;
}
}