use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Formatter};
use std::io::Write;
use std::ops::{Deref, Range};
use std::os::raw::{c_char, c_int};
use std::ptr::NonNull;
use num_derive::ToPrimitive;
use num_traits::ToPrimitive;
use rmp::Marker;
use serde::Serialize;
use tarantool_proc::impl_tuple_encode;
use crate::error::{self, Error, Result, TarantoolError};
use crate::ffi::tarantool as ffi;
use crate::tlua;
pub use rmp;
pub use tarantool_proc::Encode;
pub struct Tuple {
ptr: NonNull<ffi::BoxTuple>,
}
impl Debug for Tuple {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if let Ok(v) = self.decode::<rmpv::Value>() {
f.debug_tuple("Tuple").field(&v).finish()
} else {
f.debug_tuple("Tuple").field(&self.as_buffer()).finish()
}
}
}
impl Tuple {
#[inline]
pub fn new<T>(value: &T) -> Result<Self>
where
T: ToTupleBuffer,
{
Ok(Self::from(&value.to_tuple_buffer()?))
}
#[deprecated = "Use `Tuple::new` instead."]
#[inline]
pub fn from_struct<T>(value: &T) -> Result<Self>
where
T: ToTupleBuffer,
{
Self::new(value)
}
pub unsafe fn from_raw_data(data: *mut c_char, len: u32) -> Self {
let format = TupleFormat::default();
let tuple_ptr = ffi::box_tuple_new(format.inner, data as _, data.add(len as _) as _);
Self::from_ptr(NonNull::new_unchecked(tuple_ptr))
}
pub unsafe fn from_slice(data: &[u8]) -> Self {
let format = TupleFormat::default();
let Range { start, end } = data.as_ptr_range();
let tuple_ptr = ffi::box_tuple_new(format.inner, start as _, end as _);
Self::from_ptr(NonNull::new_unchecked(tuple_ptr))
}
pub fn try_from_slice(data: &[u8]) -> Result<Self> {
let data = validate_msgpack(data)?;
unsafe { Ok(Self::from_slice(data)) }
}
pub fn from_ptr(mut ptr: NonNull<ffi::BoxTuple>) -> Self {
unsafe { ffi::box_tuple_ref(ptr.as_mut()) };
Tuple { ptr }
}
pub fn try_from_ptr(ptr: *mut ffi::BoxTuple) -> Option<Self> {
NonNull::new(ptr).map(Self::from_ptr)
}
pub fn len(&self) -> u32 {
unsafe { ffi::box_tuple_field_count(self.ptr.as_ptr()) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn bsize(&self) -> usize {
unsafe { self.ptr.as_ref().bsize() }
}
pub fn format(&self) -> TupleFormat {
TupleFormat {
inner: unsafe { ffi::box_tuple_format(self.ptr.as_ptr()) },
}
}
pub fn iter(&self) -> Result<TupleIterator> {
let inner = unsafe { ffi::box_tuple_iterator(self.ptr.as_ptr()) };
if inner.is_null() {
Err(TarantoolError::last().into())
} else {
Ok(TupleIterator { inner })
}
}
pub fn field<'a, T>(&'a self, fieldno: u32) -> Result<Option<T>>
where
T: Decode<'a>,
{
unsafe {
let field_ptr = ffi::box_tuple_field(self.ptr.as_ptr(), fieldno);
field_value_from_ptr(field_ptr as _)
}
}
#[inline(always)]
pub fn try_get<'a, I, T>(&'a self, key: I) -> Result<Option<T>>
where
I: TupleIndex,
T: Decode<'a>,
{
key.get_field(self)
}
#[inline(always)]
#[track_caller]
pub fn get<'a, I, T>(&'a self, key: I) -> Option<T>
where
I: TupleIndex,
T: Decode<'a>,
{
self.try_get(key).expect("Error during getting tuple field")
}
#[inline]
pub fn decode<T>(&self) -> Result<T>
where
T: DecodeOwned,
{
let raw_data = self.as_buffer();
Decode::decode(&raw_data)
}
#[deprecated = "Use `Tuple::decode` instead"]
pub fn as_struct<T>(&self) -> Result<T>
where
T: DecodeOwned,
{
self.decode()
}
#[inline]
pub(crate) fn as_buffer(&self) -> Vec<u8> {
let size = self.bsize();
let mut buf = Vec::with_capacity(size);
unsafe {
let actual_size = ffi::box_tuple_to_buf(self.ptr.as_ptr(), buf.as_ptr() as _, size);
buf.set_len(actual_size as usize);
}
buf
}
#[deprecated = "Use `Tuple::decode` instead"]
pub fn into_struct<T>(self) -> Result<T>
where
T: DecodeOwned,
{
self.decode()
}
pub(crate) fn into_ptr(self) -> *mut ffi::BoxTuple {
self.ptr.as_ptr()
}
}
pub trait TupleIndex {
fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
where
T: Decode<'a>;
}
impl TupleIndex for u32 {
#[inline(always)]
fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
where
T: Decode<'a>,
{
tuple.field(self)
}
}
impl TupleIndex for &str {
#[inline(always)]
fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
where
T: Decode<'a>,
{
use once_cell::sync::Lazy;
use std::io::{Error as IOError, ErrorKind};
static API: Lazy<std::result::Result<Api, dlopen::Error>> = Lazy::new(|| unsafe {
let c_str = std::ffi::CStr::from_bytes_with_nul_unchecked;
let lib = dlopen::symbor::Library::open_self()?;
let err = match lib.symbol_cstr(c_str(ffi::TUPLE_FIELD_BY_PATH_NEW_API.as_bytes())) {
Ok(api) => return Ok(Api::New(*api)),
Err(e) => e,
};
if let Ok(api) = lib.symbol_cstr(c_str(ffi::TUPLE_FIELD_BY_PATH_OLD_API.as_bytes())) {
return Ok(Api::Old(*api));
}
Err(err)
});
return match API.as_ref() {
Ok(Api::New(api)) => unsafe {
let field_ptr = api(tuple.ptr.as_ptr(), self.as_ptr() as _, self.len() as _, 1);
field_value_from_ptr(field_ptr as _)
},
Ok(Api::Old(api)) => unsafe {
let data_offset = tuple.ptr.as_ref().data_offset() as _;
let data = tuple.ptr.as_ptr().cast::<c_char>().add(data_offset);
let field_ptr = api(
tuple.format().inner,
data,
data as _,
self.as_ptr() as _,
self.len() as _,
tlua::util::hash(self),
);
field_value_from_ptr(field_ptr as _)
},
Err(e) => Err(Error::IO(IOError::new(ErrorKind::Unsupported, e))),
};
enum Api {
Old(
extern "C" fn(
format: *const ffi::BoxTupleFormat,
tuple: *const c_char,
field_map: *const u32,
path: *const c_char,
path_len: u32,
path_hash: u32,
) -> *const c_char,
),
New(
extern "C" fn(
tuple: *const ffi::BoxTuple,
path: *const c_char,
path_len: u32,
index_base: i32,
) -> *const c_char,
),
}
}
}
impl From<&TupleBuffer> for Tuple {
fn from(buf: &TupleBuffer) -> Self {
unsafe { Self::from_raw_data(buf.as_ptr() as _, buf.len() as _) }
}
}
impl Drop for Tuple {
fn drop(&mut self) {
unsafe { ffi::box_tuple_unref(self.ptr.as_ptr()) };
}
}
impl Clone for Tuple {
fn clone(&self) -> Self {
unsafe { ffi::box_tuple_ref(self.ptr.as_ptr()) };
Tuple { ptr: self.ptr }
}
}
pub trait ToTupleBuffer {
fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
let mut buf = Vec::with_capacity(128);
self.write_tuple_data(&mut buf)?;
TupleBuffer::try_from_vec(buf)
}
fn write_tuple_data(&self, w: &mut impl Write) -> Result<()>;
}
impl ToTupleBuffer for Tuple {
#[inline]
fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
Ok(TupleBuffer::from(self))
}
#[inline]
fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
w.write_all(&self.as_buffer()).map_err(Into::into)
}
}
#[allow(deprecated)]
impl<T> ToTupleBuffer for T
where
T: ?Sized,
T: AsTuple,
{
#[inline]
fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
self.serialize_to(w)
}
}
#[deprecated = "This is a legacy trait which will be removed in future. \
Implement `Encode` for custom types instead. \
Use `ToTupleBuffer` if you need the tuple data instead."]
pub trait AsTuple: Serialize {
#[inline]
fn serialize_as_tuple(&self) -> Result<TupleBuffer> {
TupleBuffer::try_from(AsTuple::serialize(self)?)
}
#[inline]
fn serialize(&self) -> Result<Vec<u8>> {
let mut vec = Vec::with_capacity(128);
self.serialize_to(&mut vec)?;
Ok(vec)
}
fn serialize_to(&self, w: &mut impl Write) -> Result<()> {
rmp_serde::encode::write(w, self).map_err(Into::into)
}
}
pub trait Encode: Serialize {
fn encode(&self, w: &mut impl Write) -> Result<()> {
rmp_serde::encode::write(w, self).map_err(Into::into)
}
}
impl<'a, T> Encode for &'a T
where
T: Encode,
{
fn encode(&self, w: &mut impl Write) -> Result<()> {
T::encode(*self, w)
}
}
impl Encode for () {
fn encode(&self, w: &mut impl Write) -> Result<()> {
rmp_serde::encode::write(w, &Vec::<()>::new()).map_err(Into::into)
}
}
impl<T> Encode for [T] where T: Serialize {}
impl<T> Encode for Vec<T> where T: Serialize {}
macro_rules! impl_array {
($($n:literal)+) => {
$(
#[allow(clippy::zero_prefixed_literal)]
impl<T> Encode for [T; $n] where T: Serialize {}
)+
}
}
impl_array! {
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
}
macro_rules! impl_tuple {
() => {};
($h:ident $($t:ident)*) => {
impl<$h, $($t),*> Encode for ($h, $($t),*)
where
$h: Serialize,
$($t: Serialize,)*
{}
impl_tuple! { $($t)* }
}
}
impl_tuple! { A B C D E F G H I J K L M N O P }
pub trait _Encode {
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()>;
}
impl _Encode for () {
fn encode(&self, w: &mut impl Write, _named: bool) -> Result<()> {
rmp::encode::write_nil(w)?;
Ok(())
}
}
impl<T> _Encode for [T]
where
T: _Encode,
{
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
rmp::encode::write_array_len(w, self.len() as u32)?;
for v in self.iter() {
v.encode(w, named)?;
}
Ok(())
}
}
impl<T> _Encode for Vec<T>
where
T: _Encode,
{
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
self[..].as_ref().encode(w, named)
}
}
impl<'a, T> _Encode for Cow<'a, T>
where
T: _Encode + ToOwned + ?Sized,
{
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
self.deref().encode(w, named)
}
}
impl _Encode for String {
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
self.as_str().encode(w, named)
}
}
impl _Encode for str {
fn encode(&self, w: &mut impl Write, _named: bool) -> Result<()> {
rmp::encode::write_str(w, self).map_err(Into::into)
}
}
impl<K, V> _Encode for BTreeMap<K, V>
where
K: _Encode,
V: _Encode,
{
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
rmp::encode::write_map_len(w, self.len() as u32)?;
for (k, v) in self.iter() {
k.encode(w, named)?;
v.encode(w, named)?;
}
Ok(())
}
}
impl _Encode for char {
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
self.to_string().encode(w, named)
}
}
macro_rules! impl_simple_encode {
($(($t:ty, $f:tt, $conv:ty))+) => {
$(
impl _Encode for $t{
fn encode(&self, w: &mut impl Write, _named: bool) -> Result<()> {
rmp::encode::$f(w, *self as $conv)?;
Ok(())
}
}
)+
}
}
impl_simple_encode! {
(u8, write_uint, u64)
(u16, write_uint, u64)
(u32, write_uint, u64)
(u64, write_uint, u64)
(usize, write_uint, u64)
(i8, write_sint, i64)
(i16, write_sint, i64)
(i32, write_sint, i64)
(i64, write_sint, i64)
(isize, write_sint, i64)
(f32, write_f32, f32)
(f64, write_f64, f64)
(bool, write_bool, bool)
(&str, write_str, &str)
}
macro_rules! _impl_array {
($($n:literal)+) => {
$(
#[allow(clippy::zero_prefixed_literal)]
impl<T> _Encode for [T; $n] where T: _Encode {
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
rmp::encode::write_array_len(w, $n)?;
for item in self {
item.encode(w, named)?;
}
Ok(())
}
}
)+
}
}
_impl_array! {
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
}
impl_tuple_encode!();
impl _Encode for serde_json::Value {
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
let bytes = if named {
rmp_serde::to_vec_named(self)?
} else {
rmp_serde::to_vec(self)?
};
w.write_all(bytes.as_slice())?;
Ok(())
}
}
impl _Encode for serde_json::Map<String, serde_json::Value> {
fn encode(&self, w: &mut impl Write, named: bool) -> Result<()> {
let bytes = if named {
rmp_serde::to_vec_named(self)?
} else {
rmp_serde::to_vec(self)?
};
w.write_all(bytes.as_slice())?;
Ok(())
}
}
#[allow(deprecated)]
impl<T> AsTuple for T
where
T: ?Sized,
T: Encode,
{
fn serialize_to(&self, w: &mut impl Write) -> Result<()> {
self.encode(w)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct TupleBuffer(
): previously TupleBuffer would use tarantool's transaction
Vec<u8>,
);
impl TupleBuffer {
#[inline]
pub fn as_ptr(&self) -> *const u8 {
self.0.as_ptr()
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[track_caller]
#[inline]
pub unsafe fn from_vec_unchecked(buf: Vec<u8>) -> Self {
Self(buf)
}
#[inline]
pub fn try_from_vec(data: Vec<u8>) -> Result<Self> {
let data = validate_msgpack(data)?;
unsafe { Ok(Self::from_vec_unchecked(data)) }
}
}
impl AsRef<[u8]> for TupleBuffer {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl From<TupleBuffer> for Vec<u8> {
#[inline]
fn from(b: TupleBuffer) -> Self {
b.0
}
}
impl TryFrom<Vec<u8>> for TupleBuffer {
type Error = Error;
#[inline]
fn try_from(data: Vec<u8>) -> Result<Self> {
Self::try_from_vec(data)
}
}
impl From<Tuple> for TupleBuffer {
#[inline]
fn from(t: Tuple) -> Self {
Self(t.as_buffer())
}
}
impl From<&Tuple> for TupleBuffer {
#[inline]
fn from(t: &Tuple) -> Self {
Self(t.as_buffer())
}
}
impl Debug for TupleBuffer {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if let Ok(v) = rmpv::Value::decode(&self.0) {
f.debug_tuple("TupleBuffer").field(&v).finish()
} else {
f.debug_tuple("TupleBuffer").field(&self.0).finish()
}
}
}
impl ToTupleBuffer for TupleBuffer {
#[inline]
fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
Ok(self.clone())
}
#[inline]
fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
w.write_all(self.as_ref()).map_err(Into::into)
}
}
impl serde_bytes::Serialize for TupleBuffer {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_bytes::Serialize::serialize(&self.0, serializer)
}
}
impl<'de> serde_bytes::Deserialize<'de> for TupleBuffer {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let tmp: Vec<u8> = serde_bytes::Deserialize::deserialize(deserializer)?;
Self::try_from(tmp).map_err(serde::de::Error::custom)
}
}
pub struct TupleFormat {
inner: *mut ffi::BoxTupleFormat,
}
impl Default for TupleFormat {
fn default() -> Self {
TupleFormat {
inner: unsafe { ffi::box_tuple_format_default() },
}
}
}
impl Debug for TupleFormat {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.inner == Self::default().inner {
f.write_str("TupleFormat::default()")
} else {
f.debug_tuple("TupleFormat").field(&self.inner).finish()
}
}
}
pub struct TupleIterator {
inner: *mut ffi::BoxTupleIterator,
}
impl Debug for TupleIterator {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("TupleIterator")
.field("position", &self.position())
.finish()
}
}
impl TupleIterator {
pub fn position(&self) -> u32 {
unsafe { ffi::box_tuple_position(self.inner) }
}
pub fn rewind(&mut self) {
unsafe { ffi::box_tuple_rewind(self.inner) }
}
pub fn seek<'t, T>(&'t mut self, fieldno: u32) -> Result<Option<T>>
where
T: Decode<'t>,
{
unsafe { field_value_from_ptr(ffi::box_tuple_seek(self.inner, fieldno) as _) }
}
#[allow(clippy::should_implement_trait)]
pub fn next<'t, T>(&'t mut self) -> Result<Option<T>>
where
T: Decode<'t>,
{
unsafe { field_value_from_ptr(ffi::box_tuple_next(self.inner) as _) }
}
pub fn update(&mut self) {}
}
impl Drop for TupleIterator {
fn drop(&mut self) {
unsafe { ffi::box_tuple_iterator_free(self.inner) }
}
}
impl TupleIterator {}
#[repr(u32)]
#[derive(Copy, Clone, Debug, ToPrimitive, PartialEq, Eq, Hash)]
pub enum FieldType {
Any = 0,
Unsigned,
String,
Number,
Double,
Integer,
Boolean,
Varbinary,
Scalar,
Decimal,
Uuid,
Array,
Map,
}
#[derive(Debug)]
pub struct KeyDef {
inner: *mut ffi::BoxKeyDef,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct KeyDefItem {
pub field_id: u32,
pub field_type: FieldType,
}
impl KeyDefItem {
pub fn new(field_id: u32, field_type: FieldType) -> Self {
Self {
field_id,
field_type,
}
}
}
impl From<(u32, FieldType)> for KeyDefItem {
fn from((field_id, field_type): (u32, FieldType)) -> Self {
Self {
field_id,
field_type,
}
}
}
impl KeyDef {
#[inline]
pub fn new(items: impl IntoIterator<Item = impl Into<KeyDefItem>>) -> Self {
let iter = items.into_iter();
let (size, _) = iter.size_hint();
let mut ids = Vec::with_capacity(size);
let mut types = Vec::with_capacity(size);
for KeyDefItem {
field_id,
field_type,
} in iter.map(Into::into)
{
ids.push(field_id);
types.push(field_type.to_u32().unwrap());
}
KeyDef {
inner: unsafe {
ffi::box_key_def_new(ids.as_mut_ptr(), types.as_mut_ptr(), size as u32)
},
}
}
pub fn compare(&self, tuple_a: &Tuple, tuple_b: &Tuple) -> Ordering {
unsafe {
ffi::box_tuple_compare(tuple_a.ptr.as_ptr(), tuple_b.ptr.as_ptr(), self.inner).cmp(&0)
}
}
pub fn compare_with_key<K>(&self, tuple: &Tuple, key: &K) -> Ordering
where
K: ToTupleBuffer,
{
let key_buf = key.to_tuple_buffer().unwrap();
let key_buf_ptr = key_buf.as_ptr() as _;
unsafe {
ffi::box_tuple_compare_with_key(tuple.ptr.as_ptr(), key_buf_ptr, self.inner).cmp(&0)
}
}
}
impl Drop for KeyDef {
fn drop(&mut self) {
unsafe { ffi::box_key_def_delete(self.inner) }
}
}
unsafe fn field_value_from_ptr<'de, T>(field_ptr: *mut u8) -> Result<Option<T>>
where
T: Decode<'de>,
{
if field_ptr.is_null() {
return Ok(None);
}
let max_len = u32::MAX >> 1;
let rough_slice = std::slice::from_raw_parts(field_ptr, max_len as _);
let mut cursor = std::io::Cursor::new(rough_slice);
let start = cursor.position() as usize;
crate::msgpack::skip_value(&mut cursor)?;
let value_range = start..(cursor.position() as usize);
let rough_slice = cursor.into_inner();
let value_slice = &rough_slice[value_range];
Ok(Some(T::decode(value_slice)?))
}
#[repr(C)]
#[derive(Debug)]
pub struct FunctionCtx {
inner: *mut ffi::BoxFunctionCtx,
}
impl FunctionCtx {
#[inline]
pub fn return_tuple(&self, tuple: &Tuple) -> Result<c_int> {
let result = unsafe { ffi::box_return_tuple(self.inner, tuple.ptr.as_ptr()) };
if result < 0 {
Err(TarantoolError::last().into())
} else {
Ok(result)
}
}
#[inline]
pub fn return_mp<T>(&self, value: &T) -> Result<c_int>
where
T: Serialize,
{
let buf = rmp_serde::to_vec_named(value)?;
self.return_bytes(&buf)
}
#[inline]
pub fn return_bytes(&self, bytes: &[u8]) -> Result<c_int> {
let Range { start, end } = bytes.as_ptr_range();
let result = unsafe { ffi::box_return_mp(self.inner, start as _, end as _) };
if result < 0 {
Err(TarantoolError::last().into())
} else {
Ok(result)
}
}
}
#[repr(C)]
pub struct FunctionArgs {
pub start: *const u8,
pub end: *const u8,
}
impl Debug for FunctionArgs {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_tuple("FunctionArgs")
.field(&Tuple::from(self))
.finish()
}
}
impl From<FunctionArgs> for Tuple {
fn from(args: FunctionArgs) -> Tuple {
Tuple::from(&args)
}
}
impl From<&FunctionArgs> for Tuple {
fn from(args: &FunctionArgs) -> Tuple {
unsafe { Tuple::from_raw_data(args.start as _, args.end.offset_from(args.start) as _) }
}
}
impl FunctionArgs {
#[inline(always)]
pub fn decode<'a, T>(&'a self) -> Result<T>
where
T: Decode<'a>,
{
let slice = unsafe {
std::slice::from_raw_parts(self.start, self.end.offset_from(self.start) as _)
};
T::decode(slice)
}
#[inline(always)]
#[deprecated = "Use `FunctionArgs::decode` instead."]
pub fn as_struct<T>(&self) -> Result<T>
where
T: DecodeOwned,
{
Tuple::from(self).decode()
}
}
pub fn session_push<T>(value: &T) -> Result<()>
where
T: ToTupleBuffer,
{
let buf = value.to_tuple_buffer().unwrap();
let buf_ptr = buf.as_ptr() as *const c_char;
if unsafe { ffi::box_session_push(buf_ptr, buf_ptr.add(buf.len())) } < 0 {
Err(TarantoolError::last().into())
} else {
Ok(())
}
}
#[inline(always)]
fn validate_msgpack<T>(data: T) -> Result<T>
where
T: AsRef<[u8]> + Into<Vec<u8>>,
{
let mut slice = data.as_ref();
let m = rmp::decode::read_marker(&mut slice)?;
if !matches!(m, Marker::FixArray(_) | Marker::Array16 | Marker::Array32) {
return Err(error::Encode::InvalidMP(data.into()).into());
}
Ok(data)
}
impl<L> tlua::Push<L> for Tuple
where
L: tlua::AsLua,
{
type Err = tlua::Void;
fn push_to_lua(&self, lua: L) -> tlua::PushResult<L, Self> {
unsafe {
ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
Ok(tlua::PushGuard::new(lua, 1))
}
}
}
impl<L> tlua::PushOne<L> for Tuple where L: tlua::AsLua {}
impl<L> tlua::PushInto<L> for Tuple
where
L: tlua::AsLua,
{
type Err = tlua::Void;
fn push_into_lua(self, lua: L) -> tlua::PushResult<L, Self> {
unsafe {
ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
Ok(tlua::PushGuard::new(lua, 1))
}
}
}
impl<L> tlua::PushOneInto<L> for Tuple where L: tlua::AsLua {}
impl<L> tlua::LuaRead<L> for Tuple
where
L: tlua::AsLua,
{
fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> std::result::Result<Self, L> {
let ptr = unsafe { ffi::luaT_istuple(tlua::AsLua::as_lua(&lua), index.get()) };
Self::try_from_ptr(ptr).ok_or(lua)
}
}
pub trait Decode<'de>: Sized {
fn decode(data: &'de [u8]) -> Result<Self>;
}
impl<'de, T> Decode<'de> for T
where
T: serde::Deserialize<'de>,
{
fn decode(data: &'de [u8]) -> Result<Self> {
Ok(rmp_serde::from_slice(data)?)
}
}
impl Decode<'_> for Tuple {
fn decode(data: &[u8]) -> Result<Self> {
Self::try_from_slice(data)
}
}
pub trait DecodeOwned: for<'de> Decode<'de> {}
impl<T> DecodeOwned for T where T: for<'de> Decode<'de> {}
#[derive(Debug)]
#[repr(transparent)]
pub struct RawBytes(pub [u8]);
impl<'de> Decode<'de> for &'de RawBytes {
#[inline(always)]
fn decode(data: &'de [u8]) -> Result<Self> {
unsafe { Ok(&*(data as *const [u8] as *const RawBytes)) }
}
}
impl ToTupleBuffer for RawBytes {
#[inline(always)]
fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
let data = &**self;
validate_msgpack(data)?;
w.write_all(data).map_err(Into::into)
}
}
impl std::ops::Deref for RawBytes {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RawByteBuf(pub Vec<u8>);
impl serde_bytes::Serialize for RawByteBuf {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_bytes::Serialize::serialize(&self.0, serializer)
}
}
impl<'de> serde_bytes::Deserialize<'de> for RawByteBuf {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
serde_bytes::Deserialize::deserialize(deserializer).map(Self)
}
}
impl From<Vec<u8>> for RawByteBuf {
#[inline(always)]
fn from(b: Vec<u8>) -> Self {
Self(b)
}
}
impl Decode<'_> for RawByteBuf {
#[inline(always)]
fn decode(data: &[u8]) -> Result<Self> {
Ok(Self(data.into()))
}
}
impl ToTupleBuffer for RawByteBuf {
#[inline(always)]
fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
let data = self.as_slice();
validate_msgpack(data)?;
w.write_all(data).map_err(Into::into)
}
}
impl std::ops::Deref for RawByteBuf {
type Target = Vec<u8>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for RawByteBuf {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(feature = "picodata")]
mod picodata {
use crate::tuple::{Tuple, TupleFormat};
use crate::Result;
use std::ffi::CStr;
use std::io::{Cursor, Write};
use std::marker::PhantomData;
use std::os::raw::c_char;
impl Tuple {
pub fn as_named_buffer(&self) -> Result<Vec<u8>> {
let format = self.format();
let buff = self.as_buffer();
let field_count = self.len();
let mut named_buffer = Vec::with_capacity(buff.len());
let mut cursor = Cursor::new(&buff);
rmp::encode::write_map_len(&mut named_buffer, field_count)?;
rmp::decode::read_array_len(&mut cursor)?;
format.names().try_for_each(|field_name| -> Result<()> {
let value_start = cursor.position() as usize;
crate::msgpack::skip_value(&mut cursor)?;
let value_end = cursor.position() as usize;
rmp::encode::write_str(&mut named_buffer, field_name)?;
Ok(named_buffer.write_all(&buff[value_start..value_end])?)
})?;
for i in 0..field_count - format.name_count() {
let value_start = cursor.position() as usize;
crate::msgpack::skip_value(&mut cursor)?;
let value_end = cursor.position() as usize;
rmp::encode::write_u32(&mut named_buffer, i)?;
named_buffer.write_all(&buff[value_start..value_end])?;
}
Ok(named_buffer)
}
}
impl TupleFormat {
pub fn name_count(&self) -> u32 {
unsafe { (*(*self.inner).dict).name_count }
}
pub fn names(&self) -> impl Iterator<Item = &str> {
let ptr = unsafe { (*(*self.inner).dict).names };
NameIterator {
ptr,
len: self.name_count() as usize,
pos: 0,
_p: PhantomData,
}
}
}
pub(crate) struct NameIterator<'a> {
ptr: *const *const c_char,
len: usize,
pos: usize,
_p: PhantomData<&'a ()>,
}
impl<'a> Iterator for NameIterator<'a> {
type Item = &'a str;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.len {
return None;
}
unsafe {
let str_ptr = self.ptr.add(self.pos);
self.pos += 1;
Some(
CStr::from_ptr(*str_ptr)
.to_str()
.expect("invalid utf-8 string"),
)
}
}
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use super::_Encode;
use serde::Deserialize;
use tarantool_proc::Encode;
#[test]
pub fn encode_struct() {
#[derive(Clone, Encode, Deserialize, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test1 {
b: u32,
}
#[derive(Clone, Encode, Deserialize, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test {
a: usize,
b: String,
c: Test1,
}
let mut bytes = vec![];
let original = Test {
a: 1,
b: "abc".to_owned(),
c: Test1 { b: 0 },
};
original.encode(&mut bytes, false).unwrap();
let decoded: Test = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
pub fn encode_tuple_struct() {
#[derive(Clone, Encode, Deserialize, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test(u32, bool);
let mut bytes = vec![];
let original = Test(0, true);
original.encode(&mut bytes, false).unwrap();
let decoded: Test = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
pub fn encode_unit_struct() {
#[derive(Clone, Encode, Deserialize, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test;
let mut bytes = vec![];
let original = Test;
original.encode(&mut bytes, false).unwrap();
let decoded: Test = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
pub fn encode_enum() {
#[derive(Clone, Encode, Deserialize, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum Foo {
BarUnit,
BarTuple1(bool),
BarTupleN((), (), ()),
BarStruct1 { bar: bool },
BarStructN { bar1: (), bar2: (), bar3: () },
}
let mut bytes = vec![];
let original = Foo::BarUnit;
original.encode(&mut bytes, false).unwrap();
let decoded: Foo = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let mut bytes = vec![];
let original = Foo::BarTuple1(true);
original.encode(&mut bytes, false).unwrap();
let decoded: Foo = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let mut bytes = vec![];
let original = Foo::BarTupleN((), (), ());
original.encode(&mut bytes, false).unwrap();
let decoded: Foo = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let mut bytes = vec![];
let original = Foo::BarStruct1 { bar: false };
original.encode(&mut bytes, false).unwrap();
let decoded: Foo = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let mut bytes = vec![];
let original = Foo::BarStructN {
bar1: (),
bar2: (),
bar3: (),
};
original.encode(&mut bytes, false).unwrap();
let decoded: Foo = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
pub fn encode_vec() {
let mut bytes = vec![];
let original = vec![1u32];
original.encode(&mut bytes, false).unwrap();
let decoded: Vec<u32> = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let mut bytes = vec![];
let original = vec![(), (), (), (), ()];
original.encode(&mut bytes, false).unwrap();
let decoded: Vec<()> = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
pub fn encode_map() {
let mut bytes = vec![];
let mut original = BTreeMap::new();
original.insert(1, "abc".to_string());
original.insert(2, "def".to_string());
original.encode(&mut bytes, false).unwrap();
let decoded: BTreeMap<u32, String> = rmp_serde::from_slice(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
}