tarantool/
tuple.rs

1//! Tuples
2//!
3//! The `tuple` submodule provides read-only access for the tuple userdata type.
4//! It allows, for a single tuple: selective retrieval of the field contents, retrieval of information about size,
5//! iteration over all the fields, and conversion from/to rust structures
6//!
7//! See also:
8//! - [Tuples](https://www.tarantool.io/en/doc/2.2/book/box/data_model/#tuples)
9//! - [Lua reference: Submodule box.tuple](https://www.tarantool.io/en/doc/2.2/reference/reference_lua/box_tuple/)
10//! - [C API reference: Module tuple](https://www.tarantool.io/en/doc/2.2/dev_guide/reference_capi/tuple/)
11use std::borrow::Cow;
12use std::cmp::Ordering;
13use std::convert::TryFrom;
14use std::ffi::{CStr, CString};
15use std::fmt::{self, Debug, Formatter};
16use std::io::Write;
17use std::ops::Range;
18use std::os::raw::{c_char, c_int};
19use std::ptr::{null, NonNull};
20
21use rmp::Marker;
22use serde::Serialize;
23
24use crate::error::{self, Error, Result, TarantoolError};
25#[cfg(feature = "picodata")]
26use crate::ffi::sql::PortC;
27use crate::ffi::tarantool as ffi;
28use crate::index;
29use crate::tlua;
30
31/// Tuple
32pub struct Tuple {
33    ptr: NonNull<ffi::BoxTuple>,
34}
35
36impl Debug for Tuple {
37    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
38        if let Ok(v) = self.decode::<rmpv::Value>() {
39            f.debug_tuple("Tuple").field(&v).finish()
40        } else {
41            // Probably will never happen but better safe than sorry
42            f.debug_tuple("Tuple").field(&self.to_vec()).finish()
43        }
44    }
45}
46
47impl Tuple {
48    /// Create a new tuple from `value` implementing [`ToTupleBuffer`].
49    #[inline]
50    pub fn new<T>(value: &T) -> Result<Self>
51    where
52        T: ToTupleBuffer + ?Sized,
53    {
54        Ok(Self::from(&value.to_tuple_buffer()?))
55    }
56
57    /// # Safety
58    /// `data` must point to a buffer containing `len` bytes representing a
59    /// valid messagepack array
60    #[inline(always)]
61    pub unsafe fn from_raw_data(data: *mut c_char, len: u32) -> Self {
62        let format = TupleFormat::default();
63        let tuple_ptr = ffi::box_tuple_new(format.inner, data as _, data.add(len as _) as _);
64
65        Self::from_ptr(NonNull::new_unchecked(tuple_ptr))
66    }
67
68    /// # Safety
69    /// `data` must represent a valid messagepack array
70    #[inline(always)]
71    pub unsafe fn from_slice(data: &[u8]) -> Self {
72        let format = TupleFormat::default();
73        let Range { start, end } = data.as_ptr_range();
74        let tuple_ptr = ffi::box_tuple_new(format.inner, start as _, end as _);
75
76        Self::from_ptr(NonNull::new_unchecked(tuple_ptr))
77    }
78
79    #[inline]
80    pub fn try_from_slice(data: &[u8]) -> Result<Self> {
81        let data = validate_msgpack(data)?;
82        unsafe { Ok(Self::from_slice(data)) }
83    }
84
85    #[inline(always)]
86    pub fn from_ptr(mut ptr: NonNull<ffi::BoxTuple>) -> Self {
87        unsafe { ffi::box_tuple_ref(ptr.as_mut()) };
88        Tuple { ptr }
89    }
90
91    #[inline(always)]
92    pub fn try_from_ptr(ptr: *mut ffi::BoxTuple) -> Option<Self> {
93        NonNull::new(ptr).map(Self::from_ptr)
94    }
95
96    /// Return the number of fields in tuple (the size of MsgPack Array).
97    #[inline(always)]
98    pub fn len(&self) -> u32 {
99        unsafe { ffi::box_tuple_field_count(self.ptr.as_ptr()) }
100    }
101
102    #[inline(always)]
103    pub fn is_empty(&self) -> bool {
104        self.len() == 0
105    }
106
107    /// Will return the number of bytes in the tuple.
108    ///
109    /// With both the memtx storage engine and the vinyl storage engine the default maximum is one megabyte
110    /// (`memtx_max_tuple_size` or `vinyl_max_tuple_size`). Every field has one or more "length" bytes preceding the
111    /// actual contents, so `bsize()` returns a value which is slightly greater than the sum of the lengths of the
112    /// contents.
113    ///
114    /// The value does not include the size of "struct tuple"
115    /// (for the current size of this structure look in the tuple.h file in Tarantool’s source code).
116    #[inline(always)]
117    pub fn bsize(&self) -> usize {
118        unsafe { self.ptr.as_ref().bsize() }
119    }
120
121    /// Return the associated format.
122    #[inline(always)]
123    pub fn format(&self) -> TupleFormat {
124        // Safety: safe because `self.ptr` is valid
125        let inner = unsafe { ffi::box_tuple_format(self.ptr.as_ptr()) };
126
127        // Safety: safe because `inner` is valid
128        unsafe {
129            if inner != ffi::box_tuple_format_default() {
130                ffi::box_tuple_format_ref(inner)
131            }
132        }
133
134        TupleFormat { inner }
135    }
136
137    /// Allocate and initialize a new `Tuple` iterator. The `Tuple` iterator
138    /// allow to iterate over fields at root level of MsgPack array.
139    ///
140    /// Example:
141    /// ```no_run
142    /// # fn foo<T: serde::de::DeserializeOwned>(tuple: tarantool::tuple::Tuple) {
143    /// let mut it = tuple.iter().unwrap();
144    ///
145    /// while let Some(field) = it.next::<T>().unwrap() {
146    ///     // process data
147    /// }
148    ///
149    /// // rewind iterator to first position
150    /// it.rewind();
151    /// assert!(it.position() == 0);
152    ///
153    /// // rewind iterator to first position
154    /// let field = it.seek::<T>(3).unwrap();
155    /// assert!(it.position() == 4);
156    /// }
157    /// ```
158    #[inline]
159    pub fn iter(&self) -> Result<TupleIterator> {
160        let inner = unsafe { ffi::box_tuple_iterator(self.ptr.as_ptr()) };
161        if inner.is_null() {
162            Err(TarantoolError::last().into())
163        } else {
164            Ok(TupleIterator { inner })
165        }
166    }
167
168    /// Deserialize a tuple field specified by zero-based array index.
169    ///
170    /// - `fieldno` - zero-based index in MsgPack array.
171    ///
172    /// Returns:
173    /// - `Ok(None)` if `fieldno >= self.len()`
174    /// - `Err(e)` if deserialization failed
175    /// - `Ok(Some(field value))` otherwise
176    ///
177    /// See also [`Tuple::try_get`], [`Tuple::get`].
178    #[inline(always)]
179    pub fn field<'a, T>(&'a self, fieldno: u32) -> Result<Option<T>>
180    where
181        T: Decode<'a>,
182    {
183        unsafe {
184            let field_ptr = ffi::box_tuple_field(self.ptr.as_ptr(), fieldno);
185            field_value_from_ptr(field_ptr as _)
186        }
187    }
188
189    /// Deserialize a tuple field specified by an index implementing
190    /// [`TupleIndex`] trait.
191    ///
192    /// Currently 2 types of indexes are supported:
193    /// - `u32` - zero-based index in MsgPack array (See also [`Tuple::field`])
194    /// - `&str` - JSON path for tuples with non default formats
195    ///
196    /// **NOTE**: getting tuple fields by JSON paths is not supported in all
197    /// tarantool versions. Use [`tarantool::ffi::has_tuple_field_by_path`] to
198    /// check whether it's supported in your case.
199    /// If `has_tuple_field_by_path` returns `false` this function will always
200    /// return `Err`.
201    ///
202    /// Returns:
203    /// - `Ok(None)` if index wasn't found
204    /// - `Err(e)` if deserialization failed (or api not supported)
205    /// - `Ok(Some(field value))` otherwise
206    ///
207    /// See also [`Tuple::get`].
208    ///
209    /// [`tarantool::ffi::has_tuple_field_by_path`]:
210    /// crate::ffi::has_tuple_field_by_path
211    #[inline(always)]
212    pub fn try_get<'a, I, T>(&'a self, key: I) -> Result<Option<T>>
213    where
214        I: TupleIndex,
215        T: Decode<'a>,
216    {
217        key.get_field(self)
218    }
219
220    /// Deserialize a tuple field specified by an index implementing
221    /// [`TupleIndex`] trait.
222    ///
223    /// Currently 2 types of indexes are supported:
224    /// - `u32` - zero-based index in MsgPack array (See also [`Tuple::field`])
225    /// - `&str` - JSON path for tuples with non default formats
226    ///
227    /// **NOTE**: getting tuple fields by JSON paths is not supported in all
228    /// tarantool versions. Use [`tarantool::ffi::has_tuple_field_by_path`] to
229    /// check whether it's supported in your case.
230    /// If `has_tuple_field_by_path` returns `false` this function will always
231    /// **panic**.
232    ///
233    /// Returns:
234    /// - `None` if index wasn't found
235    /// - **panics** if deserialization failed (or api not supported)
236    /// - `Some(field value)` otherwise
237    ///
238    /// See also [`Tuple::get`].
239    ///
240    /// [`tarantool::ffi::has_tuple_field_by_path`]:
241    /// crate::ffi::has_tuple_field_by_path
242    #[inline(always)]
243    #[track_caller]
244    pub fn get<'a, I, T>(&'a self, key: I) -> Option<T>
245    where
246        I: TupleIndex,
247        T: Decode<'a>,
248    {
249        self.try_get(key).expect("Error during getting tuple field")
250    }
251
252    /// Decode tuple contents as `T`.
253    ///
254    /// **NOTE**: Because [`Tuple`] implements [`DecodeOwned`], you can do
255    /// something like this
256    /// ```no_run
257    /// use tarantool::tuple::{Decode, Tuple};
258    /// let tuple: Tuple;
259    /// # tuple = Tuple::new(&[1, 2, 3]).unwrap();
260    /// let deep_copy: Tuple = tuple.decode().unwrap();
261    /// let inc_ref_count: Tuple = tuple.clone();
262    /// ```
263    /// "Decoding" a `Tuple` into a `Tuple` will basically perform a **deep
264    /// copy** of its contents, while `tuple.clone()` will just increase tuple's
265    /// reference count. There's probably no use case for deep copying the
266    /// tuple, because there's actully no way to move data out of it, so keep
267    /// this in mind.
268    #[inline]
269    pub fn decode<T>(&self) -> Result<T>
270    where
271        T: DecodeOwned,
272    {
273        #[cfg(feature = "picodata")]
274        return Decode::decode(self.data());
275        #[cfg(not(feature = "picodata"))]
276        return Decode::decode(&self.to_vec());
277    }
278
279    /// Get tuple contents as a vector of raw bytes.
280    ///
281    /// Returns tuple bytes in msgpack encoding.
282    #[inline]
283    pub fn to_vec(&self) -> Vec<u8> {
284        let size = self.bsize();
285        let mut buf = Vec::with_capacity(size);
286
287        unsafe {
288            let actual_size = ffi::box_tuple_to_buf(self.ptr.as_ptr(), buf.as_ptr() as _, size);
289            buf.set_len(actual_size as usize);
290        }
291
292        buf
293    }
294
295    /// Return pointer to underlying tuple.
296    #[inline(always)]
297    pub fn as_ptr(&self) -> *mut ffi::BoxTuple {
298        self.ptr.as_ptr()
299    }
300}
301
302////////////////////////////////////////////////////////////////////////////////
303// TupleIndex
304////////////////////////////////////////////////////////////////////////////////
305
306/// Types implementing this trait can be used as arguments for the
307/// [`Tuple::get`] method.
308///
309/// This is a helper trait, so you don't want to use it directly.
310pub trait TupleIndex {
311    fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
312    where
313        T: Decode<'a>;
314}
315
316impl TupleIndex for u32 {
317    #[inline(always)]
318    fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
319    where
320        T: Decode<'a>,
321    {
322        tuple.field(self)
323    }
324}
325
326impl TupleIndex for &str {
327    #[inline(always)]
328    fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
329    where
330        T: Decode<'a>,
331    {
332        use once_cell::sync::Lazy;
333        use std::io::{Error as IOError, ErrorKind};
334        static API: Lazy<std::result::Result<Api, dlopen::Error>> = Lazy::new(|| unsafe {
335            let c_str = std::ffi::CStr::from_bytes_with_nul_unchecked;
336            let lib = dlopen::symbor::Library::open_self()?;
337            let err = match lib.symbol_cstr(c_str(ffi::TUPLE_FIELD_BY_PATH_NEW_API.as_bytes())) {
338                Ok(api) => return Ok(Api::New(*api)),
339                Err(e) => e,
340            };
341            if let Ok(api) = lib.symbol_cstr(c_str(ffi::TUPLE_FIELD_BY_PATH_OLD_API.as_bytes())) {
342                return Ok(Api::Old(*api));
343            }
344            Err(err)
345        });
346
347        return match API.as_ref() {
348            Ok(Api::New(api)) => unsafe {
349                let field_ptr = api(tuple.ptr.as_ptr(), self.as_ptr() as _, self.len() as _, 1);
350                field_value_from_ptr(field_ptr as _)
351            },
352            Ok(Api::Old(api)) => unsafe {
353                let data_offset = tuple.ptr.as_ref().data_offset() as _;
354                let data = tuple.ptr.as_ptr().cast::<c_char>().add(data_offset);
355                let field_ptr = api(
356                    tuple.format().inner,
357                    data,
358                    data as _,
359                    self.as_ptr() as _,
360                    self.len() as _,
361                    tlua::util::hash(self),
362                );
363                field_value_from_ptr(field_ptr as _)
364            },
365            Err(e) => Err(Error::IO(IOError::new(ErrorKind::Unsupported, e))),
366        };
367
368        enum Api {
369            /// Before 2.10 private api `tuple_field_raw_by_full_path`
370            Old(
371                extern "C" fn(
372                    format: *const ffi::BoxTupleFormat,
373                    tuple: *const c_char,
374                    field_map: *const u32,
375                    path: *const c_char,
376                    path_len: u32,
377                    path_hash: u32,
378                ) -> *const c_char,
379            ),
380            /// After 2.10 public api `box_tuple_field_by_path`
381            New(
382                extern "C" fn(
383                    tuple: *const ffi::BoxTuple,
384                    path: *const c_char,
385                    path_len: u32,
386                    index_base: i32,
387                ) -> *const c_char,
388            ),
389        }
390    }
391}
392
393impl From<&TupleBuffer> for Tuple {
394    #[inline(always)]
395    fn from(buf: &TupleBuffer) -> Self {
396        unsafe { Self::from_raw_data(buf.as_ptr() as _, buf.len() as _) }
397    }
398}
399
400impl Drop for Tuple {
401    #[inline(always)]
402    fn drop(&mut self) {
403        unsafe { ffi::box_tuple_unref(self.ptr.as_ptr()) };
404    }
405}
406
407impl Clone for Tuple {
408    #[inline(always)]
409    fn clone(&self) -> Self {
410        unsafe { ffi::box_tuple_ref(self.ptr.as_ptr()) };
411        Tuple { ptr: self.ptr }
412    }
413}
414
415impl<'de> serde_bytes::Deserialize<'de> for Tuple {
416    #[inline]
417    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
418    where
419        D: serde::Deserializer<'de>,
420    {
421        let data: &[u8] = serde_bytes::Deserialize::deserialize(deserializer)?;
422        Self::try_from_slice(data).map_err(serde::de::Error::custom)
423    }
424}
425
426////////////////////////////////////////////////////////////////////////////////
427// ToTupleBuffer
428////////////////////////////////////////////////////////////////////////////////
429
430/// Types implementing this trait can be converted to tarantool tuple (msgpack
431/// array).
432pub trait ToTupleBuffer {
433    #[inline]
434    fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
435        let mut buf = Vec::with_capacity(128);
436        self.write_tuple_data(&mut buf)?;
437        TupleBuffer::try_from_vec(buf)
438    }
439
440    /// Returns a slice of bytes represeting the underlying tarantool tuple.
441    ///
442    /// Returns `None` if `Self` doesn't contain the data, in which case the
443    /// [`ToTupleBuffer::to_tuple_buffer`] should be used.
444    ///
445    /// This method exists as an optimization for wrapper types to eliminate
446    /// extra copies, in cases where the implementing type already contains the
447    /// tuple data (e.g. [`TupleBuffer`], [`RawBytes`], etc.).
448    #[inline(always)]
449    fn tuple_data(&self) -> Option<&[u8]> {
450        None
451    }
452
453    fn write_tuple_data(&self, w: &mut impl Write) -> Result<()>;
454}
455
456impl ToTupleBuffer for Tuple {
457    #[inline(always)]
458    fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
459        Ok(TupleBuffer::from(self))
460    }
461
462    #[cfg(feature = "picodata")]
463    #[inline(always)]
464    fn tuple_data(&self) -> Option<&[u8]> {
465        Some(self.data())
466    }
467
468    #[inline]
469    fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
470        #[cfg(feature = "picodata")]
471        w.write_all(self.data())?;
472        #[cfg(not(feature = "picodata"))]
473        w.write_all(&self.to_vec())?;
474        Ok(())
475    }
476}
477
478impl<T> ToTupleBuffer for T
479where
480    T: ?Sized,
481    T: Encode,
482{
483    #[inline(always)]
484    fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
485        self.encode(w)
486    }
487}
488
489////////////////////////////////////////////////////////////////////////////////
490// Encode
491////////////////////////////////////////////////////////////////////////////////
492
493/// Types implementing this trait can be serialized into a valid tarantool tuple
494/// (msgpack array).
495// TODO: remove this trait when `specialization` feature is stabilized
496// https://github.com/rust-lang/rust/issues/31844
497pub trait Encode: Serialize {
498    #[inline(always)]
499    fn encode(&self, w: &mut impl Write) -> Result<()> {
500        rmp_serde::encode::write(w, self).map_err(Into::into)
501    }
502}
503
504impl<T> Encode for &'_ T
505where
506    T: Encode,
507{
508    #[inline(always)]
509    fn encode(&self, w: &mut impl Write) -> Result<()> {
510        T::encode(*self, w)
511    }
512}
513
514impl Encode for () {
515    #[inline(always)]
516    fn encode(&self, w: &mut impl Write) -> Result<()> {
517        rmp_serde::encode::write(w, &Vec::<()>::new()).map_err(Into::into)
518    }
519}
520
521impl<T> Encode for [T] where T: Serialize {}
522impl<T> Encode for Vec<T> where T: Serialize {}
523
524macro_rules! impl_array {
525    ($($n:literal)+) => {
526        $(
527            #[allow(clippy::zero_prefixed_literal)]
528            impl<T> Encode for [T; $n] where T: Serialize {}
529        )+
530    }
531}
532
533impl_array! {
534    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
535    16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
536}
537
538macro_rules! impl_tuple {
539    () => {};
540    ($h:ident $($t:ident)*) => {
541        impl<$h, $($t),*> Encode for ($h, $($t),*)
542        where
543            $h: Serialize,
544            $($t: Serialize,)*
545        {}
546
547        impl_tuple! { $($t)* }
548    }
549}
550
551impl_tuple! { A B C D E F G H I J K L M N O P }
552
553////////////////////////////////////////////////////////////////////////////////
554// TupleBuffer
555////////////////////////////////////////////////////////////////////////////////
556
557/// Buffer containing tuple contents (MsgPack array)
558#[derive(Clone, PartialEq, Eq)]
559pub struct TupleBuffer(
560    // TODO(gmoshkin): previously TupleBuffer would use tarantool's transaction
561    // scoped memory allocator, but it would do so in a confusingly inefficient
562    // and error prone manner (redundant copies and use after free).
563    //
564    // This doesn't mean however that there's no point in using box_txn_alloc,
565    // but at this time I don't see an easy way to leave it within the current
566    // state of TupleBuffer.
567    //
568    // There might be a use for box_txn_alloc from within
569    // transaction::start_transaction, but a well thought through api is needed.
570    //
571    // TODO(gmoshkin): use smallvec::SmallVec instead
572    Vec<u8>,
573);
574
575impl TupleBuffer {
576    /// Get raw pointer to buffer.
577    #[inline(always)]
578    pub fn as_ptr(&self) -> *const u8 {
579        self.0.as_ptr()
580    }
581
582    /// Return the number of bytes used in memory by the tuple.
583    #[inline(always)]
584    pub fn len(&self) -> usize {
585        self.0.len()
586    }
587
588    #[inline(always)]
589    pub fn is_empty(&self) -> bool {
590        self.0.is_empty()
591    }
592
593    /// # Safety
594    /// `buf` must be a valid message pack array
595    #[track_caller]
596    #[inline(always)]
597    pub unsafe fn from_vec_unchecked(buf: Vec<u8>) -> Self {
598        Self(buf)
599    }
600
601    #[inline]
602    pub fn try_from_vec(data: Vec<u8>) -> Result<Self> {
603        let data = validate_msgpack(data)?;
604        unsafe { Ok(Self::from_vec_unchecked(data)) }
605    }
606}
607
608impl AsRef<[u8]> for TupleBuffer {
609    #[inline(always)]
610    fn as_ref(&self) -> &[u8] {
611        self.0.as_ref()
612    }
613}
614
615impl From<TupleBuffer> for Vec<u8> {
616    #[inline(always)]
617    fn from(b: TupleBuffer) -> Self {
618        b.0
619    }
620}
621
622impl TryFrom<Vec<u8>> for TupleBuffer {
623    type Error = Error;
624
625    #[inline(always)]
626    fn try_from(data: Vec<u8>) -> Result<Self> {
627        Self::try_from_vec(data)
628    }
629}
630
631impl From<Tuple> for TupleBuffer {
632    #[inline(always)]
633    fn from(t: Tuple) -> Self {
634        Self(t.to_vec())
635    }
636}
637
638impl From<&Tuple> for TupleBuffer {
639    #[inline(always)]
640    fn from(t: &Tuple) -> Self {
641        Self(t.to_vec())
642    }
643}
644
645impl Debug for TupleBuffer {
646    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
647        if let Ok(v) = rmpv::Value::decode(&self.0) {
648            f.debug_tuple("TupleBuffer").field(&v).finish()
649        } else {
650            f.debug_tuple("TupleBuffer").field(&self.0).finish()
651        }
652    }
653}
654
655impl ToTupleBuffer for TupleBuffer {
656    #[inline(always)]
657    fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
658        Ok(self.clone())
659    }
660
661    #[inline(always)]
662    fn tuple_data(&self) -> Option<&[u8]> {
663        Some(&self.0)
664    }
665
666    #[inline(always)]
667    fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
668        w.write_all(self.as_ref()).map_err(Into::into)
669    }
670}
671
672impl serde_bytes::Serialize for TupleBuffer {
673    #[inline(always)]
674    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
675    where
676        S: serde::Serializer,
677    {
678        serde_bytes::Serialize::serialize(&self.0, serializer)
679    }
680}
681
682impl<'de> serde_bytes::Deserialize<'de> for TupleBuffer {
683    #[inline]
684    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
685    where
686        D: serde::Deserializer<'de>,
687    {
688        let tmp: Vec<u8> = serde_bytes::Deserialize::deserialize(deserializer)?;
689        Self::try_from(tmp).map_err(serde::de::Error::custom)
690    }
691}
692
693////////////////////////////////////////////////////////////////////////////////
694// TupleFormat
695////////////////////////////////////////////////////////////////////////////////
696
697/// Tuple format
698///
699/// Each Tuple has associated format (class). Default format is used to
700/// create tuples which are not attach to any particular space.
701pub struct TupleFormat {
702    // FIXME: If this was a NonNull then rust can use it's layout optimizations,
703    // for example Option<TupleFormat> will have the same size as TupleFormat.
704    inner: *mut ffi::BoxTupleFormat,
705}
706
707impl TupleFormat {
708    #[inline(always)]
709    pub fn as_ptr(&self) -> *mut ffi::BoxTupleFormat {
710        self.inner
711    }
712}
713
714impl Default for TupleFormat {
715    #[inline(always)]
716    fn default() -> Self {
717        TupleFormat {
718            inner: unsafe { ffi::box_tuple_format_default() },
719        }
720    }
721}
722
723impl Drop for TupleFormat {
724    fn drop(&mut self) {
725        // Don't unref default format as it's not dynamically allocated
726        unsafe {
727            if self.inner != ffi::box_tuple_format_default() {
728                ffi::box_tuple_format_unref(self.inner)
729            }
730        }
731    }
732}
733
734impl Debug for TupleFormat {
735    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
736        if self.inner == Self::default().inner {
737            f.write_str("TupleFormat::default()")
738        } else {
739            f.debug_tuple("TupleFormat").field(&self.inner).finish()
740        }
741    }
742}
743
744////////////////////////////////////////////////////////////////////////////////
745// TupleIterator
746////////////////////////////////////////////////////////////////////////////////
747
748/// Tuple iterator
749pub struct TupleIterator {
750    inner: *mut ffi::BoxTupleIterator,
751}
752
753impl Debug for TupleIterator {
754    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
755        f.debug_struct("TupleIterator")
756            .field("position", &self.position())
757            .finish()
758    }
759}
760
761impl TupleIterator {
762    /// Return zero-based next position in iterator.
763    ///
764    /// That is, this function return the field id of field that will be
765    /// returned by the next call to `box_tuple_next(it)`. Returned value is zero
766    /// after initialization or rewind and `box_tuple_field_count(Tuple)`
767    /// after the end of iteration.
768    #[inline(always)]
769    pub fn position(&self) -> u32 {
770        unsafe { ffi::box_tuple_position(self.inner) }
771    }
772
773    /// Rewind iterator to the initial position.
774    #[inline(always)]
775    pub fn rewind(&mut self) {
776        unsafe { ffi::box_tuple_rewind(self.inner) }
777    }
778
779    /// Seek the Tuple iterator.
780    ///
781    /// Requested fieldno returned by next call to `box_tuple_next(it)`.
782    ///
783    /// - `fieldno` - zero-based position in MsgPack array.
784    ///
785    /// After call:
786    /// - `box_tuple_position(it) == fieldno` if returned value is not `None`
787    /// - `box_tuple_position(it) == box_tuple_field_count(Tuple)` if returned value is `None`.
788    #[inline]
789    pub fn seek<'t, T>(&'t mut self, fieldno: u32) -> Result<Option<T>>
790    where
791        T: Decode<'t>,
792    {
793        unsafe { field_value_from_ptr(ffi::box_tuple_seek(self.inner, fieldno) as _) }
794    }
795
796    /// Return the next Tuple field from Tuple iterator.
797    ///
798    /// Returns:
799    /// - `None` if `i >= box_tuple_field_count(Tuple)` or if field has a non primitive type
800    /// - field value otherwise
801    ///
802    /// After call:
803    /// - `box_tuple_position(it) == fieldno` if returned value is not `None`
804    /// - `box_tuple_position(it) == box_tuple_field_count(Tuple)` if returned value is `None`.
805    #[allow(clippy::should_implement_trait)]
806    #[inline]
807    pub fn next<'t, T>(&'t mut self) -> Result<Option<T>>
808    where
809        T: Decode<'t>,
810    {
811        unsafe { field_value_from_ptr(ffi::box_tuple_next(self.inner) as _) }
812    }
813
814    pub fn update(&mut self) {}
815}
816
817impl Drop for TupleIterator {
818    #[inline(always)]
819    fn drop(&mut self) {
820        unsafe { ffi::box_tuple_iterator_free(self.inner) }
821    }
822}
823
824impl TupleIterator {}
825
826////////////////////////////////////////////////////////////////////////////////
827// FieldType
828////////////////////////////////////////////////////////////////////////////////
829
830crate::define_str_enum! {
831    pub enum FieldType {
832        Any       = "any",
833        Unsigned  = "unsigned",
834        String    = "string",
835        Number    = "number",
836        Double    = "double",
837        Integer   = "integer",
838        Boolean   = "boolean",
839        Varbinary = "varbinary",
840        Scalar    = "scalar",
841        Decimal   = "decimal",
842        Uuid      = "uuid",
843        Datetime  = "datetime",
844        Array     = "array",
845        Map       = "map",
846    }
847}
848
849impl Default for FieldType {
850    #[inline(always)]
851    fn default() -> Self {
852        Self::Any
853    }
854}
855
856impl From<index::FieldType> for FieldType {
857    #[rustfmt::skip]
858    fn from(t: index::FieldType) -> Self {
859        match t {
860            // "any" type is not supported as index part,
861            // that's the only reason we need 2 enums.
862            index::FieldType::Unsigned  => Self::Unsigned,
863            index::FieldType::String    => Self::String,
864            index::FieldType::Number    => Self::Number,
865            index::FieldType::Double    => Self::Double,
866            index::FieldType::Integer   => Self::Integer,
867            index::FieldType::Boolean   => Self::Boolean,
868            index::FieldType::Varbinary => Self::Varbinary,
869            index::FieldType::Scalar    => Self::Scalar,
870            index::FieldType::Decimal   => Self::Decimal,
871            index::FieldType::Uuid      => Self::Uuid,
872            index::FieldType::Datetime  => Self::Datetime,
873            index::FieldType::Array     => Self::Array,
874        }
875    }
876}
877
878////////////////////////////////////////////////////////////////////////////////
879// KeyDef
880////////////////////////////////////////////////////////////////////////////////
881
882/// An object which describes how to extract a key for a given tarantool index
883/// from a tuple. Basically it contains information the parts of the key,
884/// specifically location of the parts within the tuple, their types, their
885/// nullability and collation.
886///
887/// Can be used to
888/// - compare tuples ([`Self::compare`])
889/// - extract a key from a tuple ([`Self::extract_key`])
890/// - check if a tuple has the expected format ([`Self::validate_tuple`])
891/// - etc.
892///
893/// You can construct one of these from an explicit list of key part definitions
894/// using [`Self::new`], or automtically from an index's metadata like so:
895/// ```no_run
896/// # use tarantool::index::Index;
897/// # use tarantool::space::Space;
898/// # use tarantool::tuple::KeyDef;
899/// let space = Space::find("some_space").unwrap();
900/// let index = space.index("some_index").unwrap();
901/// let meta = index.meta().unwrap();
902/// let key_def: KeyDef = meta.to_key_def();
903/// ```
904#[derive(Debug)]
905pub struct KeyDef {
906    inner: NonNull<ffi::BoxKeyDef>,
907}
908
909#[derive(Default, Debug, PartialEq, Eq, Hash)]
910pub struct KeyDefPart<'a> {
911    pub field_no: u32,
912    pub field_type: FieldType,
913    pub collation: Option<Cow<'a, CStr>>,
914    pub is_nullable: bool,
915    pub path: Option<Cow<'a, CStr>>,
916}
917
918impl<'a> KeyDefPart<'a> {
919    fn as_tt(&self) -> ffi::box_key_part_def_t {
920        let flags = if self.is_nullable {
921            ffi::BoxKeyDefPartFlag::IS_NULLABLE.bits()
922        } else {
923            0
924        };
925        ffi::box_key_part_def_t {
926            meat: ffi::BoxKeyDefPart {
927                fieldno: self.field_no,
928                field_type: self.field_type.as_cstr().as_ptr(),
929                flags,
930                collation: self
931                    .collation
932                    .as_deref()
933                    .map(CStr::as_ptr)
934                    .unwrap_or(null()),
935                path: self.path.as_deref().map(CStr::as_ptr).unwrap_or(null()),
936            },
937        }
938    }
939
940    pub fn from_index_part(p: &'a index::Part<u32>) -> Self {
941        let collation = p.collation.as_deref().map(|s| {
942            CString::new(s)
943                .expect("it's your fault if you put '\0' in collation")
944                .into()
945        });
946        let path = p.path.as_deref().map(|s| {
947            CString::new(s)
948                .expect("it's your fault if you put '\0' in collation")
949                .into()
950        });
951        Self {
952            field_no: p.field,
953            field_type: p.r#type.map(From::from).unwrap_or(FieldType::Any),
954            is_nullable: p.is_nullable.unwrap_or(false),
955            collation,
956            path,
957        }
958    }
959}
960
961impl KeyDef {
962    /// Create key definition with key fields with passed typed on passed positions.
963    /// May be used for tuple format creation and/or tuple comparison.
964    ///
965    /// - `items` - array with key field identifiers and key field types (see [FieldType](struct.FieldType.html))
966    #[inline]
967    pub fn new<'a>(parts: impl IntoIterator<Item = &'a KeyDefPart<'a>>) -> Result<Self> {
968        let mut tt_parts = parts.into_iter().map(KeyDefPart::as_tt).collect::<Vec<_>>();
969        let ptr = unsafe { ffi::box_key_def_new_v2(tt_parts.as_mut_ptr(), tt_parts.len() as _) };
970        let inner = NonNull::new(ptr).ok_or_else(TarantoolError::last)?;
971        Ok(KeyDef { inner })
972    }
973
974    /// Compare tuples using the key definition.
975    ///
976    /// - `tuple_a` - first tuple
977    /// - `tuple_b` - second tuple
978    ///
979    /// Returns:
980    /// - `Ordering::Equal`   if `key_fields(tuple_a) == key_fields(tuple_b)`
981    /// - `Ordering::Less`    if `key_fields(tuple_a) < key_fields(tuple_b)`
982    /// - `Ordering::Greater` if `key_fields(tuple_a) > key_fields(tuple_b)`
983    #[inline(always)]
984    pub fn compare(&self, tuple_a: &Tuple, tuple_b: &Tuple) -> Ordering {
985        unsafe {
986            ffi::box_tuple_compare(
987                tuple_a.ptr.as_ptr(),
988                tuple_b.ptr.as_ptr(),
989                self.inner.as_ptr(),
990            )
991            .cmp(&0)
992        }
993    }
994
995    /// Compare tuple with key using the key definition.
996    ///
997    /// - `tuple` - tuple
998    /// - `key` - key with MessagePack array header
999    ///
1000    /// Returns:
1001    /// - `Ordering::Equal`   if `key_fields(tuple) == parts(key)`
1002    /// - `Ordering::Less`    if `key_fields(tuple) < parts(key)`
1003    /// - `Ordering::Greater` if `key_fields(tuple) > parts(key)`
1004    #[inline]
1005    pub fn compare_with_key<K>(&self, tuple: &Tuple, key: &K) -> Ordering
1006    where
1007        K: ToTupleBuffer + ?Sized,
1008    {
1009        let key_buf = key.to_tuple_buffer().unwrap();
1010        let key_buf_ptr = key_buf.as_ptr() as _;
1011        unsafe {
1012            ffi::box_tuple_compare_with_key(tuple.ptr.as_ptr(), key_buf_ptr, self.inner.as_ptr())
1013                .cmp(&0)
1014        }
1015    }
1016
1017    /// Checks if `tuple` satisfies the key definition's format, i.e. do the
1018    /// tuple's fields described the `self`'s key parts have the same types.
1019    /// Note that the tuple may still not satisfy the full format of the space,
1020    /// this function only checks if it contains a part which could be used as
1021    /// a key of an index.
1022    ///
1023    /// There's currently no good way of checking if the tuple satisfies the
1024    /// format of the space other than trying to insert into that space.
1025    ///
1026    /// This function is used internally by [`Self::extract_key`] to check if
1027    /// it's safe to extract the key described by this `KeyDef` from a given tuple.
1028    #[inline]
1029    pub fn validate_tuple(&self, tuple: &Tuple) -> Result<()> {
1030        // SAFETY: safe as long as both pointers are valid.
1031        let rc =
1032            unsafe { ffi::box_key_def_validate_tuple(self.inner.as_ptr(), tuple.ptr.as_ptr()) };
1033        if rc != 0 {
1034            return Err(TarantoolError::last().into());
1035        }
1036        Ok(())
1037    }
1038
1039    /// Extracts the key described by this `KeyDef` from `tuple`.
1040    /// Returns an error if `tuple` doesn't satisfy this `KeyDef`.
1041    #[inline]
1042    pub fn extract_key(&self, tuple: &Tuple) -> Result<TupleBuffer> {
1043        self.validate_tuple(tuple)?;
1044        let res;
1045        // SAFETY: safe, because we only truncate the region to where it was
1046        // before the call to this function.
1047        unsafe {
1048            let used_before = ffi::box_region_used();
1049            let data = self.extract_key_raw(tuple, -1)?;
1050            res = TupleBuffer::from_vec_unchecked(data.into());
1051            ffi::box_region_truncate(used_before);
1052        }
1053        Ok(res)
1054    }
1055
1056    /// Extracts the key described by this `KeyDef` from `tuple`.
1057    ///
1058    /// TODO: what is `multikey_idx`? Pass a `-1` as the default value.
1059    ///
1060    /// Returns an error in case memory runs out.
1061    ///
1062    /// # Safety
1063    /// `tuple` must satisfy the key definition's format.
1064    /// Use [`Self::extract_key`] if you want the tuple to be validated automatically,
1065    /// or use [`Self::validate_tuple`] to validate the tuple explicitly.
1066    #[inline]
1067    pub unsafe fn extract_key_raw<'box_region>(
1068        &self,
1069        tuple: &Tuple,
1070        multikey_idx: i32,
1071    ) -> Result<&'box_region [u8]> {
1072        let slice;
1073        // SAFETY: safe as long as both pointers are valid.
1074        unsafe {
1075            let mut size = 0;
1076            let data = ffi::box_key_def_extract_key(
1077                self.inner.as_ptr(),
1078                tuple.ptr.as_ptr(),
1079                multikey_idx,
1080                &mut size,
1081            );
1082            if data.is_null() {
1083                return Err(TarantoolError::last().into());
1084            }
1085            slice = std::slice::from_raw_parts(data as _, size as _);
1086        }
1087        Ok(slice)
1088    }
1089
1090    /// Calculate a tuple hash for a given key definition.
1091    /// At the moment 32-bit murmur3 hash is used but it may
1092    /// change in future.
1093    ///
1094    /// - `tuple` - tuple
1095    ///
1096    /// Returns:
1097    /// - 32-bit murmur3 hash value
1098    #[cfg(feature = "picodata")]
1099    pub fn hash(&self, tuple: &Tuple) -> u32 {
1100        unsafe { ffi::box_tuple_hash(tuple.ptr.as_ptr(), self.inner.as_ptr()) }
1101    }
1102}
1103
1104impl Drop for KeyDef {
1105    #[inline(always)]
1106    fn drop(&mut self) {
1107        unsafe { ffi::box_key_def_delete(self.inner.as_ptr()) }
1108    }
1109}
1110
1111impl From<&index::Metadata<'_>> for KeyDef {
1112    #[inline(always)]
1113    fn from(meta: &index::Metadata<'_>) -> Self {
1114        meta.to_key_def()
1115    }
1116}
1117
1118unsafe fn field_value_from_ptr<'de, T>(field_ptr: *mut u8) -> Result<Option<T>>
1119where
1120    T: Decode<'de>,
1121{
1122    if field_ptr.is_null() {
1123        return Ok(None);
1124    }
1125
1126    // Theoretically this is an exploit point, which would allow reading up to
1127    // 2gigs of memory in case `value_ptr` happens to point to memory which
1128    // isn't a field of a tuple, but is a valid messagepack value
1129    let max_len = u32::MAX >> 1;
1130    let rough_slice = std::slice::from_raw_parts(field_ptr, max_len as _);
1131    let mut cursor = std::io::Cursor::new(rough_slice);
1132    let start = cursor.position() as usize;
1133    // There's overhead for iterating over the whole msgpack value, but this is
1134    // necessary.
1135    crate::msgpack::skip_value(&mut cursor)?;
1136    let value_range = start..(cursor.position() as usize);
1137    let rough_slice = cursor.into_inner();
1138    let value_slice = &rough_slice[value_range];
1139    Ok(Some(T::decode(value_slice)?))
1140}
1141
1142////////////////////////////////////////////////////////////////////////////////
1143// FunctionCtx
1144////////////////////////////////////////////////////////////////////////////////
1145
1146#[repr(C)]
1147#[derive(Debug)]
1148pub struct FunctionCtx {
1149    inner: *mut ffi::BoxFunctionCtx,
1150}
1151
1152impl FunctionCtx {
1153    /// Return a Tuple from stored procedure.
1154    ///
1155    /// Returned Tuple is automatically reference counted by Tarantool.
1156    ///
1157    /// - `tuple` - a Tuple to return
1158    #[inline]
1159    pub fn return_tuple(&self, tuple: &Tuple) -> Result<c_int> {
1160        let result = unsafe { ffi::box_return_tuple(self.inner, tuple.ptr.as_ptr()) };
1161        if result < 0 {
1162            Err(TarantoolError::last().into())
1163        } else {
1164            Ok(result)
1165        }
1166    }
1167
1168    /// Return a value encoded as MessagePack from a stored procedure.
1169    ///
1170    /// MessagePack is not validated, for the sake of speed. It is
1171    /// expected to be a single encoded object. An attempt to encode
1172    /// and return multiple objects without wrapping them into an
1173    /// `MP_ARRAY` or `MP_MAP` is undefined behaviour.
1174    ///
1175    /// - `value` - value to be encoded to MessagePack
1176    #[inline]
1177    pub fn return_mp<T>(&self, value: &T) -> Result<c_int>
1178    where
1179        T: Serialize + ?Sized,
1180    {
1181        let buf = rmp_serde::to_vec_named(value)?;
1182        self.return_bytes(&buf)
1183    }
1184
1185    /// Return raw bytes representing a MessagePack value from a stored
1186    /// procedure.
1187    ///
1188    /// MessagePack is not validated, for the sake of speed. It is
1189    /// expected to be a single encoded object. An attempt to encode
1190    /// and return multiple objects without wrapping them into an
1191    /// `MP_ARRAY` or `MP_MAP` is undefined behaviour.
1192    ///
1193    /// - `bytes` - raw msgpack bytes to be returned
1194    #[inline]
1195    pub fn return_bytes(&self, bytes: &[u8]) -> Result<c_int> {
1196        let Range { start, end } = bytes.as_ptr_range();
1197        let result = unsafe { ffi::box_return_mp(self.inner, start as _, end as _) };
1198
1199        if result < 0 {
1200            Err(TarantoolError::last().into())
1201        } else {
1202            Ok(result)
1203        }
1204    }
1205
1206    #[cfg(feature = "picodata")]
1207    #[inline]
1208    pub fn mut_port_c(&mut self) -> &mut PortC {
1209        unsafe {
1210            let mut ctx = NonNull::new_unchecked(self.inner);
1211            NonNull::new_unchecked(ctx.as_mut().port)
1212                .as_mut()
1213                .as_mut_port_c()
1214        }
1215    }
1216}
1217
1218////////////////////////////////////////////////////////////////////////////////
1219// FunctionArgs
1220////////////////////////////////////////////////////////////////////////////////
1221
1222#[repr(C)]
1223pub struct FunctionArgs {
1224    pub start: *const u8,
1225    pub end: *const u8,
1226}
1227
1228impl Debug for FunctionArgs {
1229    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1230        f.debug_tuple("FunctionArgs")
1231            .field(&Tuple::from(self))
1232            .finish()
1233    }
1234}
1235
1236impl From<FunctionArgs> for Tuple {
1237    #[inline(always)]
1238    fn from(args: FunctionArgs) -> Tuple {
1239        Tuple::from(&args)
1240    }
1241}
1242
1243impl From<&FunctionArgs> for Tuple {
1244    #[inline(always)]
1245    fn from(args: &FunctionArgs) -> Tuple {
1246        unsafe { Tuple::from_raw_data(args.start as _, args.end.offset_from(args.start) as _) }
1247    }
1248}
1249
1250impl FunctionArgs {
1251    /// Decode the msgpack value represented by the function args.
1252    #[inline(always)]
1253    pub fn decode<'a, T>(&'a self) -> Result<T>
1254    where
1255        T: Decode<'a>,
1256    {
1257        let slice = unsafe {
1258            std::slice::from_raw_parts(self.start, self.end.offset_from(self.start) as _)
1259        };
1260        T::decode(slice)
1261    }
1262}
1263
1264/// Push MessagePack data into a session data channel - socket,
1265/// console or whatever is behind the session. Note, that
1266/// successful push does not guarantee delivery in case it was sent
1267/// into the network. Just like with `write()`/`send()` system calls.
1268#[inline]
1269pub fn session_push<T>(value: &T) -> Result<()>
1270where
1271    T: ToTupleBuffer + ?Sized,
1272{
1273    let buf = value.to_tuple_buffer().unwrap();
1274    let buf_ptr = buf.as_ptr() as *const c_char;
1275    if unsafe { ffi::box_session_push(buf_ptr, buf_ptr.add(buf.len())) } < 0 {
1276        Err(TarantoolError::last().into())
1277    } else {
1278        Ok(())
1279    }
1280}
1281
1282#[inline]
1283fn validate_msgpack<T>(data: T) -> Result<T>
1284where
1285    T: AsRef<[u8]> + Into<Vec<u8>>,
1286{
1287    let mut slice = data.as_ref();
1288    let m = rmp::decode::read_marker(&mut slice)?;
1289    if !matches!(m, Marker::FixArray(_) | Marker::Array16 | Marker::Array32) {
1290        return Err(error::EncodeError::InvalidMP(data.into()).into());
1291    }
1292    Ok(data)
1293}
1294
1295impl<L> tlua::Push<L> for Tuple
1296where
1297    L: tlua::AsLua,
1298{
1299    type Err = tlua::Void;
1300
1301    #[inline(always)]
1302    fn push_to_lua(&self, lua: L) -> tlua::PushResult<L, Self> {
1303        unsafe {
1304            ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
1305            Ok(tlua::PushGuard::new(lua, 1))
1306        }
1307    }
1308}
1309
1310impl<L> tlua::PushOne<L> for Tuple where L: tlua::AsLua {}
1311
1312impl<L> tlua::PushInto<L> for Tuple
1313where
1314    L: tlua::AsLua,
1315{
1316    type Err = tlua::Void;
1317
1318    #[inline(always)]
1319    fn push_into_lua(self, lua: L) -> tlua::PushResult<L, Self> {
1320        unsafe {
1321            ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
1322            Ok(tlua::PushGuard::new(lua, 1))
1323        }
1324    }
1325}
1326
1327impl<L> tlua::PushOneInto<L> for Tuple where L: tlua::AsLua {}
1328
1329impl<L> tlua::LuaRead<L> for Tuple
1330where
1331    L: tlua::AsLua,
1332{
1333    fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> tlua::ReadResult<Self, L> {
1334        let lua_ptr = tlua::AsLua::as_lua(&lua);
1335        let mut ptr = unsafe { ffi::luaT_istuple(lua_ptr, index.get()) };
1336        if ptr.is_null() {
1337            let format = TupleFormat::default();
1338            ptr = unsafe { ffi::luaT_tuple_new(lua_ptr, index.get(), format.inner) };
1339        }
1340        Self::try_from_ptr(ptr).ok_or_else(|| {
1341            let e = tlua::WrongType::info("reading tarantool tuple")
1342                .expected_type::<Self>()
1343                .actual_single_lua(&lua, index);
1344            (lua, e)
1345        })
1346    }
1347}
1348
1349impl<L> tlua::LuaRead<L> for TupleBuffer
1350where
1351    L: tlua::AsLua,
1352{
1353    fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> tlua::ReadResult<Self, L> {
1354        unsafe {
1355            let svp = ffi::box_region_used();
1356            let lua_ptr = tlua::AsLua::as_lua(&lua);
1357            let ptr = ffi::luaT_istuple(lua_ptr, index.get());
1358            if let Some(tuple) = Tuple::try_from_ptr(ptr) {
1359                return Ok(Self::from(tuple));
1360            }
1361            let mut len = 0;
1362            let data = ffi::luaT_tuple_encode(lua_ptr, index.get(), &mut len);
1363            if data.is_null() {
1364                let e = tlua::WrongType::info("converting Lua value to tarantool tuple")
1365                    .expected("msgpack array")
1366                    .actual(format!("error: {}", TarantoolError::last().message()));
1367                return Err((lua, e));
1368            }
1369            let data = std::slice::from_raw_parts(data, len);
1370            let data = Vec::from(data);
1371            ffi::box_region_truncate(svp);
1372            Ok(Self::from_vec_unchecked(data))
1373        }
1374    }
1375}
1376
1377////////////////////////////////////////////////////////////////////////////////
1378// Decode
1379////////////////////////////////////////////////////////////////////////////////
1380
1381/// Types implementing this trait can be decoded from msgpack.
1382///
1383/// [`Tuple`] also implements [`Decode`] with an implementation which just
1384/// copies the bytes as is (and validates them).
1385pub trait Decode<'de>: Sized {
1386    fn decode(data: &'de [u8]) -> Result<Self>;
1387}
1388
1389impl<'de, T> Decode<'de> for T
1390where
1391    T: serde::Deserialize<'de>,
1392{
1393    #[inline(always)]
1394    fn decode(data: &'de [u8]) -> Result<Self> {
1395        rmp_serde::from_slice(data).map_err(|e| Error::decode::<T>(e, data.into()))
1396    }
1397}
1398
1399impl Decode<'_> for Tuple {
1400    #[inline(always)]
1401    fn decode(data: &[u8]) -> Result<Self> {
1402        Self::try_from_slice(data)
1403    }
1404}
1405
1406/// Types implementing this trait can be decoded from msgpack by value.
1407///
1408/// `DecodeOwned` is to [`Decode`] what [`DeserializeOwned`] is to
1409/// [`Deserialize`].
1410///
1411/// [`Deserialize`]: serde::Deserialize
1412/// [`DeserializeOwned`]: serde::de::DeserializeOwned
1413pub trait DecodeOwned: for<'de> Decode<'de> {}
1414impl<T> DecodeOwned for T where T: for<'de> Decode<'de> {}
1415
1416////////////////////////////////////////////////////////////////////////////////
1417// RawBytes
1418////////////////////////////////////////////////////////////////////////////////
1419
1420/// A wrapper type for reading raw bytes from a tuple.
1421///
1422/// Can be used to read a field of a tuple as raw bytes:
1423/// ```no_run
1424/// use tarantool::{tuple::Tuple, tuple::RawBytes};
1425/// let tuple = Tuple::new(&(1, (2, 3, 4), 5)).unwrap();
1426/// let second_field: &RawBytes = tuple.get(1).unwrap();
1427/// assert_eq!(&**second_field, &[0x93, 2, 3, 4]);
1428/// ```
1429///
1430/// This type also implements [`ToTupleBuffer`] such that `to_tuple_buffer`
1431/// returns `Ok` only if the underlying bytes represent a valid tuple (msgpack
1432/// array).
1433#[derive(Debug)]
1434#[repr(transparent)]
1435pub struct RawBytes(pub [u8]);
1436
1437impl RawBytes {
1438    /// Convert a slice of bytes `data` into a `&RawBytes`.
1439    #[inline(always)]
1440    pub fn new(data: &[u8]) -> &Self {
1441        // SAFETY: this is safe, because `RawBytes` has `#[repr(transparent)]`
1442        unsafe { &*(data as *const [u8] as *const RawBytes) }
1443    }
1444}
1445
1446impl<'a> From<&'a [u8]> for &'a RawBytes {
1447    #[inline(always)]
1448    fn from(data: &'a [u8]) -> Self {
1449        RawBytes::new(data)
1450    }
1451}
1452
1453impl<'de> Decode<'de> for &'de RawBytes {
1454    #[inline(always)]
1455    fn decode(data: &'de [u8]) -> Result<Self> {
1456        // TODO: only read msgpack bytes
1457        Ok(RawBytes::new(data))
1458    }
1459}
1460
1461impl ToTupleBuffer for RawBytes {
1462    #[inline(always)]
1463    fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
1464        let data = &**self;
1465        validate_msgpack(data)?;
1466        w.write_all(data).map_err(Into::into)
1467    }
1468
1469    #[inline(always)]
1470    fn tuple_data(&self) -> Option<&[u8]> {
1471        let data = &**self;
1472        validate_msgpack(data).ok()?;
1473        Some(data)
1474    }
1475}
1476
1477impl std::ops::Deref for RawBytes {
1478    type Target = [u8];
1479    #[inline(always)]
1480    fn deref(&self) -> &Self::Target {
1481        &self.0
1482    }
1483}
1484
1485impl std::borrow::ToOwned for RawBytes {
1486    type Owned = RawByteBuf;
1487    #[inline(always)]
1488    fn to_owned(&self) -> Self::Owned {
1489        self.0.to_vec().into()
1490    }
1491}
1492
1493////////////////////////////////////////////////////////////////////////////////
1494// RawByteBuf
1495////////////////////////////////////////////////////////////////////////////////
1496
1497/// A wrapper type for reading raw bytes from a tuple.
1498///
1499/// The difference between [`TupleBuffer`] and `RawByteBuf` is that the former
1500/// can only contain a valid tarantool tuple (msgpack array), while the latter
1501/// can contain any sequence of bytes.
1502///
1503/// This type also implements [`ToTupleBuffer`] such that `to_tuple_buffer`
1504/// returns `Ok` only if the underlying bytes represent a valid tuple.
1505#[derive(Debug, PartialEq, Eq, Clone)]
1506pub struct RawByteBuf(pub Vec<u8>);
1507
1508impl serde_bytes::Serialize for RawByteBuf {
1509    #[inline(always)]
1510    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1511    where
1512        S: serde::Serializer,
1513    {
1514        serde_bytes::Serialize::serialize(&self.0, serializer)
1515    }
1516}
1517
1518impl<'de> serde_bytes::Deserialize<'de> for RawByteBuf {
1519    #[inline(always)]
1520    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1521    where
1522        D: serde::Deserializer<'de>,
1523    {
1524        serde_bytes::Deserialize::deserialize(deserializer).map(Self)
1525    }
1526}
1527
1528impl From<Vec<u8>> for RawByteBuf {
1529    #[inline(always)]
1530    fn from(b: Vec<u8>) -> Self {
1531        Self(b)
1532    }
1533}
1534
1535impl Decode<'_> for RawByteBuf {
1536    #[inline(always)]
1537    fn decode(data: &[u8]) -> Result<Self> {
1538        // TODO: only read msgpack bytes
1539        Ok(Self(data.into()))
1540    }
1541}
1542
1543impl ToTupleBuffer for RawByteBuf {
1544    #[inline(always)]
1545    fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
1546        let data = self.as_slice();
1547        validate_msgpack(data)?;
1548        w.write_all(data).map_err(Into::into)
1549    }
1550
1551    #[inline(always)]
1552    fn tuple_data(&self) -> Option<&[u8]> {
1553        let data = self.as_slice();
1554        validate_msgpack(data).ok()?;
1555        Some(data)
1556    }
1557}
1558
1559impl std::ops::Deref for RawByteBuf {
1560    type Target = Vec<u8>;
1561    #[inline(always)]
1562    fn deref(&self) -> &Self::Target {
1563        &self.0
1564    }
1565}
1566
1567impl std::ops::DerefMut for RawByteBuf {
1568    #[inline(always)]
1569    fn deref_mut(&mut self) -> &mut Self::Target {
1570        &mut self.0
1571    }
1572}
1573
1574impl std::borrow::Borrow<RawBytes> for RawByteBuf {
1575    #[inline(always)]
1576    fn borrow(&self) -> &RawBytes {
1577        RawBytes::new(self.0.as_slice())
1578    }
1579}
1580
1581#[cfg(feature = "picodata")]
1582mod picodata {
1583    use super::*;
1584    use crate::static_ref;
1585
1586    ////////////////////////////////////////////////////////////////////////////
1587    // Tuple picodata extensions
1588    ////////////////////////////////////////////////////////////////////////////
1589
1590    impl Tuple {
1591        /// !!!
1592        /// WARNING:
1593        /// NO LONGER SUPPORTED - PANICS WHEN USED!
1594        /// !!!
1595        ///
1596        /// Returns messagepack encoded tuple with named fields (messagepack map).
1597        ///
1598        /// Returned map has only numeric keys if tuple has default tuple format (see [TupleFormat](struct.TupleFormat.html)),
1599        /// for example when tuple dont belongs to any space. If tuple has greater fields than named
1600        /// fields in tuple format - then additional fields are  presents in the map with numeric keys.
1601        ///
1602        /// This function is useful if there is no information about tuple fields in program runtime.
1603        #[deprecated = "did not find its use"]
1604        #[inline(always)]
1605        pub fn as_named_buffer(&self) -> Result<Vec<u8>> {
1606            crate::say_error!("Tuple::as_named_buffer is no longer supported");
1607            panic!("Tuple::as_named_buffer is no longer supported");
1608        }
1609
1610        /// Returns a slice of data contained in the tuple.
1611        #[inline]
1612        pub fn data(&self) -> &[u8] {
1613            unsafe {
1614                // Safety: safe because we only construct `Tuple` from valid pointers to `box_tuple_t`.
1615                let tuple = self.ptr.as_ref();
1616                tuple.data()
1617            }
1618        }
1619    }
1620
1621    impl PartialEq for Tuple {
1622        #[inline]
1623        fn eq(&self, other: &Self) -> bool {
1624            if self.ptr == other.ptr {
1625                return true;
1626            }
1627
1628            if self.bsize() != other.bsize() {
1629                return false;
1630            }
1631
1632            self.data() == other.data()
1633        }
1634    }
1635
1636    impl serde_bytes::Serialize for Tuple {
1637        #[inline(always)]
1638        fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1639        where
1640            S: serde::Serializer,
1641        {
1642            serde_bytes::Serialize::serialize(self.data(), serializer)
1643        }
1644    }
1645
1646    ////////////////////////////////////////////////////////////////////////////
1647    // TupleFormat picodata extensions
1648    ////////////////////////////////////////////////////////////////////////////
1649
1650    impl TupleFormat {
1651        /// Returns a tuple format with a custom **experimental** virtual table implementation
1652        /// for creating tuples with the rust allocator.
1653        #[inline]
1654        pub fn with_rust_allocator() -> &'static Self {
1655            static mut SINGLETON: Option<TupleFormat> = None;
1656
1657            // Safety: only makes sense to call this from tx thread
1658            if unsafe { static_ref!(mut SINGLETON) }.is_none() {
1659                // Safety: this code is valid for picodata's tarantool-2.11.2-137-ga0f7c15f75.
1660                unsafe {
1661                    let inner = ffi::box_tuple_format_new(std::ptr::null_mut(), 0);
1662                    (*inner).vtab.tuple_new = vtab_impl::tuple_new_rust_allocator;
1663                    (*inner).vtab.tuple_delete = vtab_impl::tuple_delete_rust_allocator;
1664                    SINGLETON = Some(Self { inner });
1665                }
1666            }
1667
1668            unsafe { static_ref!(const SINGLETON) }
1669                .as_ref()
1670                .expect("just made sure it's there")
1671        }
1672
1673        /// !!!
1674        /// WARNING:
1675        /// NO LONGER SUPPORTED - PANICS WHEN USED!
1676        /// !!!
1677        ///
1678        /// Return tuple field names count.
1679        #[deprecated = "did not find its use"]
1680        pub fn name_count(&self) -> u32 {
1681            crate::say_error!("TupleFormat::name_count is no longer supported");
1682            panic!("TupleFormat::name_count is no longer supported");
1683        }
1684
1685        /// !!!
1686        /// WARNING:
1687        /// NO LONGER SUPPORTED - PANICS WHEN USED!
1688        /// !!!
1689        ///
1690        /// Return tuple field names.
1691        #[deprecated = "did not find its use"]
1692        pub fn names(&self) -> impl Iterator<Item = &str> {
1693            crate::say_error!("TupleFormat::names is no longer supported");
1694            // weird hack over "never type does not implement all traits".
1695            // if we just panic, it will infer the type of a function as a never type
1696            // and it won't compile because `!` does not implement `Iterator` trait.
1697            // wrapping in a closure will make it behave like `unwrap` on a failure
1698            (|| panic!("TupleFormat::names is no longer supported"))();
1699            // this is also part of a hack because we need correct type inference
1700            Vec::new().into_iter()
1701        }
1702    }
1703}
1704
1705////////////////////////////////////////////////////////////////////////////////
1706// TupleBuilder (picodata only)
1707////////////////////////////////////////////////////////////////////////////////
1708
1709#[cfg(feature = "picodata")]
1710pub struct TupleBuilder {
1711    // Note: currently this is always `true` but we may want to support the
1712    // other case in the future.
1713    // The code is already written anyway, but not yet tested.
1714    is_rust_allocated: bool,
1715    buffer: Vec<u8>,
1716}
1717
1718#[cfg(feature = "picodata")]
1719impl TupleBuilder {
1720    const TUPLE_HEADER_PADDING: &'static [u8] = &[0; std::mem::size_of::<ffi::BoxTuple>()];
1721
1722    /// Returns a `TupleBuilder` which will construct tuples with a special
1723    /// **experimental** implementation based on the rust memory allocator.
1724    ///
1725    /// **USE AT YOUR OWN RISK.**
1726    #[inline(always)]
1727    pub fn rust_allocated() -> Self {
1728        Self {
1729            is_rust_allocated: true,
1730            buffer: Vec::new(),
1731        }
1732    }
1733
1734    #[inline(always)]
1735    pub fn buffer(&self) -> &[u8] {
1736        &self.buffer
1737    }
1738
1739    /// Reserve at least `capacity` more bytes.
1740    ///
1741    /// Note that this will also make sure there's enough data for the unrelying tuple header.
1742    #[inline]
1743    pub fn reserve(&mut self, mut capacity: usize) {
1744        if self.is_rust_allocated && self.buffer.capacity() == 0 {
1745            capacity += std::mem::size_of::<ffi::BoxTuple>();
1746        }
1747        self.buffer.reserve(capacity);
1748    }
1749
1750    #[inline]
1751    pub fn append(&mut self, data: &[u8]) {
1752        if self.is_rust_allocated && self.buffer.is_empty() {
1753            self.buffer
1754                .reserve(Self::TUPLE_HEADER_PADDING.len() + data.len());
1755            self.buffer.extend_from_slice(Self::TUPLE_HEADER_PADDING);
1756        }
1757        self.buffer.extend_from_slice(data);
1758    }
1759
1760    #[inline]
1761    pub fn into_tuple(self) -> Result<Tuple> {
1762        if self.is_rust_allocated {
1763            self.into_tuple_rust_allocated()
1764        } else {
1765            Tuple::try_from_slice(&self.buffer)
1766        }
1767    }
1768
1769    fn into_tuple_rust_allocated(self) -> Result<Tuple> {
1770        use crate::error::BoxError;
1771        use crate::error::TarantoolErrorCode;
1772
1773        if self.buffer.is_empty() {
1774            #[rustfmt::skip]
1775            return Err(BoxError::new(TarantoolErrorCode::IllegalParams, "cannot construct an empty tuple").into());
1776        }
1777
1778        if self.buffer.len() < Self::TUPLE_HEADER_PADDING.len() {
1779            #[rustfmt::skip]
1780            return Err(BoxError::new(TarantoolErrorCode::IllegalParams, "buffer is corrupted").into());
1781        }
1782
1783        let mut tuple_chunk = self.buffer;
1784        let data_offset = Self::TUPLE_HEADER_PADDING.len();
1785        let data_len = tuple_chunk.len() - data_offset;
1786        validate_msgpack(&tuple_chunk[data_offset..])?;
1787
1788        let format = TupleFormat::with_rust_allocator();
1789
1790        let tuple = tuple_chunk.as_mut_ptr().cast::<ffi::BoxTuple>();
1791        unsafe {
1792            std::ptr::write(
1793                tuple,
1794                // Analogous to `tuple_create(tuple, 0, tuple_format_id(format), data_offset, data_len, make_compact = false)`
1795                ffi::BoxTuple {
1796                    refs: 0,
1797                    flags: 0,
1798                    format_id: (*format.inner).id,
1799                    data_offset: data_offset as _,
1800                    bsize: data_len as _,
1801                },
1802            );
1803        }
1804        // The new tuple references the format
1805        unsafe {
1806            ffi::box_tuple_format_ref(format.inner);
1807        }
1808
1809        // Forget the Vec, it will be deallocated in `tuple_delete_rust_allocator`
1810        _ = Box::into_raw(tuple_chunk.into_boxed_slice());
1811
1812        // Safety: tuple points into `self.buffer` which we already checked is not empty
1813        let tuple = unsafe { NonNull::new_unchecked(tuple) };
1814        let tuple = Tuple::from_ptr(tuple);
1815        return Ok(tuple);
1816    }
1817}
1818
1819#[cfg(feature = "picodata")]
1820impl std::io::Write for TupleBuilder {
1821    #[inline(always)]
1822    fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
1823        self.append(data);
1824        Ok(data.len())
1825    }
1826
1827    #[inline(always)]
1828    fn flush(&mut self) -> std::io::Result<()> {
1829        Ok(())
1830    }
1831}
1832
1833// Note: this code is valid for picodata's tarantool-2.11.2-137-ga0f7c15f75.
1834// TODO: we should export some things from tarantool which would make this code
1835// more safe, for example a constructor for box_tuple_format which accepts the
1836// new & delete callbacks for the virtual table.
1837#[cfg(feature = "picodata")]
1838mod vtab_impl {
1839    use super::*;
1840
1841    /// Adapted from `runtime_tuple_new` in src/box/tuple.c
1842    pub unsafe extern "C" fn tuple_new_rust_allocator(
1843        format: *mut ffi::BoxTupleFormat,
1844        data: *const u8,
1845        end: *const u8,
1846    ) -> *mut ffi::BoxTuple {
1847        #[rustfmt::skip]
1848        debug_assert_eq!((*format).vtab.tuple_delete, tuple_delete_rust_allocator as ffi::FnTupleDelete);
1849
1850        const TUPLE_HEADER_SIZE: usize = std::mem::size_of::<ffi::BoxTuple>();
1851        let data_offset = TUPLE_HEADER_SIZE;
1852        // Skipping field map calculations, as we don't support them yet
1853
1854        let data_len = end.offset_from(data);
1855        debug_assert!(data_len >= 0);
1856        let data_len = data_len as usize;
1857        debug_assert!(data_len <= u32::MAX as usize);
1858
1859        // Allocate memory for the tuple header and data
1860        let total_size = data_offset + data_len;
1861        let mut tuple_chunk: Vec<u8> = Vec::with_capacity(total_size);
1862
1863        let tuple = tuple_chunk.as_mut_ptr().cast::<ffi::BoxTuple>();
1864        std::ptr::write(
1865            tuple,
1866            // Analogous to `tuple_create(tuple, 0, tuple_format_id(format), data_offset, data_len, make_compact = false)`
1867            ffi::BoxTuple {
1868                refs: 0,
1869                flags: 0,
1870                format_id: (*format).id,
1871                data_offset: data_offset as _,
1872                bsize: data_len as _,
1873            },
1874        );
1875        ffi::box_tuple_format_ref(format);
1876
1877        let data_slice = std::slice::from_raw_parts(data, data_len);
1878        tuple_chunk.set_len(total_size);
1879        let tuple_data = &mut tuple_chunk[data_offset..];
1880        debug_assert_eq!(data_slice.len(), tuple_data.len());
1881        tuple_data.copy_from_slice(data_slice);
1882
1883        // Forget the Vec, it will be deallocated in `tuple_delete_rust_allocator`
1884        let tuple_chunk: Box<[u8]> = tuple_chunk.into_boxed_slice();
1885        _ = Box::into_raw(tuple_chunk);
1886
1887        return tuple;
1888    }
1889
1890    /// Adapted from `runtime_tuple_delete` in src/box/tuple.c
1891    pub unsafe extern "C" fn tuple_delete_rust_allocator(
1892        format: *mut ffi::BoxTupleFormat,
1893        tuple: *mut ffi::BoxTuple,
1894    ) {
1895        #[rustfmt::skip]
1896        debug_assert_eq!((*format).vtab.tuple_delete, tuple_delete_rust_allocator as ffi::FnTupleDelete);
1897
1898        debug_assert!(tuple != 0 as _);
1899        debug_assert_eq!((*tuple).refs, 0);
1900        const FLAG_TUPLE_HAS_UPLOADED_REFS: u8 = 1 << 0;
1901        debug_assert_eq!(((*tuple).flags & FLAG_TUPLE_HAS_UPLOADED_REFS), 0);
1902
1903        ffi::box_tuple_format_unref(format);
1904
1905        let total_size = (*tuple).data_offset() as usize + (*tuple).bsize();
1906
1907        let tuple_chunk_start = tuple.cast::<u8>();
1908        let tuple_chunk_slice = std::slice::from_raw_parts_mut(tuple_chunk_start, total_size);
1909        // Drop the memory allocated in `tuple_new_rust_allocator`
1910        let tuple_chunk: Box<[u8]> = Box::from_raw(tuple_chunk_slice);
1911        drop(tuple_chunk);
1912    }
1913}
1914
1915#[cfg(feature = "internal_test")]
1916mod test {
1917    #![allow(clippy::redundant_clone)]
1918    use super::*;
1919    use crate::space;
1920    use crate::space::Space;
1921    use pretty_assertions::assert_eq;
1922
1923    #[crate::test(tarantool = "crate")]
1924    fn tuple_buffer_from_lua() {
1925        let svp = unsafe { ffi::box_region_used() };
1926
1927        let lua = crate::lua_state();
1928        let t: TupleBuffer = lua
1929            .eval("return { 3, 'foo', { true, box.NIL, false } }")
1930            .unwrap();
1931
1932        #[derive(::serde::Deserialize, PartialEq, Eq, Debug)]
1933        struct S {
1934            i: i32,
1935            s: String,
1936            t: [Option<bool>; 3],
1937        }
1938
1939        let s = S::decode(t.as_ref()).unwrap();
1940        assert_eq!(
1941            s,
1942            S {
1943                i: 3,
1944                s: "foo".into(),
1945                t: [Some(true), None, Some(false)]
1946            }
1947        );
1948
1949        let res = lua.eval::<TupleBuffer>("return 1, 2, 3");
1950        assert_eq!(
1951            res.unwrap_err().to_string(),
1952            "failed converting Lua value to tarantool tuple: msgpack array expected, got error: A tuple or a table expected, got number
1953    while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got (number, number, number)"
1954        );
1955
1956        let res = lua.eval::<TupleBuffer>("return { 1, 2, foo = 'bar' }");
1957        assert_eq!(
1958            res.unwrap_err().to_string(),
1959            "failed converting Lua value to tarantool tuple: msgpack array expected, got error: Tuple/Key must be MsgPack array
1960    while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got table"
1961        );
1962
1963        let res = lua.eval::<TupleBuffer>(
1964            "ffi = require 'ffi';
1965            local cdata = ffi.new('struct { int x; int y; }', { x = -1, y = 2 })
1966            return { 1, cdata }",
1967        );
1968        assert_eq!(
1969            res.unwrap_err().to_string(),
1970            "failed converting Lua value to tarantool tuple: msgpack array expected, got error: unsupported Lua type 'cdata'
1971    while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got table"
1972        );
1973
1974        assert_eq!(svp, unsafe { ffi::box_region_used() });
1975    }
1976
1977    #[crate::test(tarantool = "crate")]
1978    fn decode_error() {
1979        use super::*;
1980
1981        let buf = (1, 2, 3).to_tuple_buffer().unwrap();
1982        let err = <(String, String)>::decode(buf.as_ref()).unwrap_err();
1983        assert_eq!(
1984            err.to_string(),
1985            r#"failed to decode tuple: invalid type: integer `1`, expected a string when decoding msgpack b"\x93\x01\x02\x03" into rust type (alloc::string::String, alloc::string::String)"#
1986        );
1987
1988        let buf = ("hello", [1, 2, 3], "goodbye").to_tuple_buffer().unwrap();
1989        let err = <(String, (i32, String, i32), String)>::decode(buf.as_ref()).unwrap_err();
1990        assert_eq!(
1991            err.to_string(),
1992            r#"failed to decode tuple: invalid type: integer `2`, expected a string when decoding msgpack b"\x93\xa5hello\x93\x01\x02\x03\xa7goodbye" into rust type (alloc::string::String, (i32, alloc::string::String, i32), alloc::string::String)"#
1993        )
1994    }
1995
1996    #[crate::test(tarantool = "crate")]
1997    fn key_def_extract_key() {
1998        let space = Space::builder(&crate::temp_space_name!())
1999            .field(("id", space::FieldType::Unsigned))
2000            .field(("not-key", space::FieldType::Array))
2001            .field(("s", space::FieldType::String))
2002            .field(("nested", space::FieldType::Any))
2003            .create()
2004            .unwrap();
2005
2006        let index = space
2007            .index_builder("pk")
2008            .part("id")
2009            .part("s")
2010            .part(
2011                index::Part::<String>::field("nested")
2012                    .field_type(index::FieldType::Unsigned)
2013                    .path("[2].blabla"),
2014            )
2015            .create()
2016            .unwrap();
2017
2018        let key_def = index.meta().unwrap().to_key_def();
2019
2020        let tuple = Tuple::new(&["foo"]).unwrap();
2021        let e = key_def.extract_key(&tuple).unwrap_err();
2022        assert_eq!(e.to_string(), "box error: KeyPartType: Supplied key type of part 0 does not match index part type: expected unsigned");
2023
2024        let tuple = Tuple::new(&[1]).unwrap();
2025        let e = key_def.extract_key(&tuple).unwrap_err();
2026        // XXX: notice how this error message shows the 1-based index, but the
2027        // previous one showed the 0-based index. You can thank tarantool devs
2028        // for that.
2029        assert_eq!(
2030            e.to_string(),
2031            "box error: FieldMissing: Tuple field [3] required by space format is missing"
2032        );
2033
2034        let tuple = Tuple::new(&(1, [1, 2, 3], "foo")).unwrap();
2035        let e = key_def.extract_key(&tuple).unwrap_err();
2036        assert_eq!(
2037            e.to_string(),
2038            "box error: FieldMissing: Tuple field [4][2].blabla required by space format is missing"
2039        );
2040
2041        let raw_data = b"\x94\x69\x93\x01\x02\x03\xa3foo\x93\xc0\x81\xa6blabla\x42\x07"; // [0x69, [1, 2, 3], "foo", [null, {blabla: 0x42}, 7]]
2042        let tuple = Tuple::new(RawBytes::new(raw_data)).unwrap();
2043        let key = key_def.extract_key(&tuple).unwrap();
2044        assert_eq!(key.as_ref(), b"\x93\x69\xa3foo\x42"); // [0x69, "foo", 0x42]
2045
2046        let raw_data = b"\x94\x13\xa9not-array\xa3bar\x92\xc0\x81\xa6blabla\x37"; // [0x13, "not-array", "bar", [null, {blabla: 0x37}]]
2047
2048        // Even though the tuple doesn't actually satisfy the space's format,
2049        // the key def only know about the locations & types of the key parts,
2050        // so it doesn't care.
2051        let tuple = Tuple::new(RawBytes::new(raw_data)).unwrap();
2052        let key = key_def.extract_key(&tuple).unwrap();
2053        assert_eq!(key.as_ref(), b"\x93\x13\xa3bar\x37");
2054
2055        // This tuple can't be inserted into the space.
2056        let e = space.insert(&tuple).unwrap_err();
2057        assert_eq!(e.to_string(), "box error: FieldType: Tuple field 2 (not-key) type does not match one required by operation: expected array, got string");
2058    }
2059
2060    #[cfg(feature = "picodata")]
2061    #[crate::test(tarantool = "crate")]
2062    fn tuple_data() {
2063        // Check getting tuple data from a "runtime" tuple.
2064        let tuple = Tuple::new(&(69, "nice", [3, 2, 1])).unwrap();
2065        // \x93 -- array of length 3
2066        // \x45 -- number 0x45 == 69
2067        // \xa4nice -- string of length 4 "nice"
2068        // \x93\x03\x02\x01 -- array [3, 2, 1], do you see the pattern yet?
2069        assert_eq!(tuple.data(), b"\x93\x45\xa4nice\x93\x03\x02\x01");
2070
2071        // Check getting tuple data from a memtx tuple stored in a space.
2072        let space = Space::builder(&crate::temp_space_name!())
2073            .field(("id", space::FieldType::Unsigned))
2074            .field(("name", space::FieldType::String))
2075            .create()
2076            .unwrap();
2077
2078        space.index_builder("pk").create().unwrap();
2079
2080        let tuple = space.insert(&(13, "37")).unwrap();
2081        assert_eq!(tuple.data(), b"\x92\x0d\xa237");
2082    }
2083
2084    #[cfg(feature = "picodata")]
2085    #[crate::test(tarantool = "crate")]
2086    fn compare_tuples() {
2087        // \x92 -- array of length 2
2088        // \xa3foo, \xa3bar -- strings of length 3 "foo" & "bar" respectively
2089        let data = b"\x92\xa3foo\xa3bar";
2090        let tuple_1 = Tuple::try_from_slice(data).unwrap();
2091
2092        // Tuples with the same underlying pointer are equal.
2093        let tuple_1_clone = tuple_1.clone();
2094        assert_eq!(tuple_1_clone.as_ptr(), tuple_1.as_ptr());
2095        assert_eq!(tuple_1_clone, tuple_1);
2096
2097        // Tuple with same data but different underlying pointer (the slowest case).
2098        let tuple_1_equivalent = Tuple::try_from_slice(data).unwrap();
2099        assert_ne!(tuple_1_equivalent.as_ptr(), tuple_1.as_ptr());
2100        assert_eq!(tuple_1_equivalent, tuple_1);
2101
2102        // Tuple with different data (optimized case for different length).
2103        // \x93 -- array of length 3
2104        // \x10, \x20, \x30 -- numbers 0x10, 0x20, 0x30 respectively
2105        let other_data = b"\x93\x10\x20\x30";
2106        let tuple_2 = Tuple::try_from_slice(other_data).unwrap();
2107        assert_ne!(data.len(), other_data.len());
2108        assert_ne!(tuple_1, tuple_2);
2109
2110        // Tuple with different data (slow case for same length).
2111        // \x92 -- array of length 2
2112        // \xa3foo, \xa3baz -- strings of length 3 "foo" & "baz" respectively
2113        let other_data_same_len = b"\x92\xa3foo\xa3baz";
2114        assert_eq!(data.len(), other_data_same_len.len());
2115        let tuple_3 = Tuple::try_from_slice(other_data_same_len).unwrap();
2116        assert_ne!(tuple_2, tuple_3);
2117    }
2118
2119    #[cfg(feature = "picodata")]
2120    #[crate::test(tarantool = "crate")]
2121    fn serialize_deserialize() {
2122        #[derive(Debug, serde::Serialize, serde::Deserialize)]
2123        struct Wrapper {
2124            #[serde(with = "serde_bytes")]
2125            tuple: Tuple,
2126        }
2127
2128        // Serialize tuple to msgpack
2129        let data = rmp_serde::to_vec_named(&Wrapper {
2130            tuple: Tuple::new(&(0x77, "hello", 0x77)).unwrap(),
2131        })
2132        .unwrap();
2133        // \x81 -- mapping with 1 entry
2134        // \xa5tuple -- key "tuple"
2135        // \xc4\x09 -- header for string of binary data with length 9
2136        // \x93\x77\xa5hello\x77 -- this is the binary data payload
2137        assert_eq!(&data, b"\x81\xa5tuple\xc4\x09\x93\x77\xa5hello\x77");
2138
2139        // Deserialize tuple from msgpack.
2140        // Task for the reader, decode this msgpack in your mind.
2141        let data = b"\x81\xa5tuple\xc4\x0c\x94\xa7numbers\x03\x01\x04";
2142        let w: Wrapper = rmp_serde::from_slice(data).unwrap();
2143        let s: &str = w.tuple.field(0).unwrap().unwrap();
2144        assert_eq!(s, "numbers");
2145        let n: i32 = w.tuple.field(1).unwrap().unwrap();
2146        assert_eq!(n, 3);
2147        let n: i32 = w.tuple.field(2).unwrap().unwrap();
2148        assert_eq!(n, 1);
2149        let n: i32 = w.tuple.field(3).unwrap().unwrap();
2150        assert_eq!(n, 4);
2151
2152        // Fail to deserialize tuple from msgpack.
2153        let data = b"\x81\xa5tuple\xc4\x01\x45";
2154        let e = rmp_serde::from_slice::<Wrapper>(data).unwrap_err();
2155        assert_eq!(e.to_string(), "failed to encode tuple: invalid msgpack value (expected array, found Integer(PosInt(69)))");
2156    }
2157
2158    #[cfg(feature = "picodata")]
2159    #[crate::test(tarantool = "crate")]
2160    fn rust_allocated_tuples() {
2161        let mut builder = TupleBuilder::rust_allocated();
2162        // Array of length 1
2163        builder.append(b"\x91");
2164        // Binary string with 1-bytes length = 0x10 (16)
2165        builder.append(b"\xc4\x10");
2166        builder.append(b"0123456789abcdef");
2167        let tuple = builder.into_tuple().unwrap();
2168
2169        // Make sure all of the tuple APIs work with this tuple.
2170        assert_eq!(tuple.len(), 1);
2171        assert_eq!(tuple.bsize(), 19);
2172        assert_eq!(tuple.data(), b"\x91\xc4\x100123456789abcdef");
2173        assert_eq!(tuple.to_vec(), b"\x91\xc4\x100123456789abcdef");
2174
2175        let (value,): (serde_bytes::ByteBuf,) = tuple.decode().unwrap();
2176        assert_eq!(value, b"0123456789abcdef");
2177
2178        let value: &serde_bytes::Bytes = tuple.field(0).unwrap().unwrap();
2179        assert_eq!(value, b"0123456789abcdef");
2180
2181        let mut iter = tuple.iter().unwrap();
2182        let value: &serde_bytes::Bytes = iter.next().unwrap().unwrap();
2183        assert_eq!(value, b"0123456789abcdef");
2184        assert_eq!(iter.next::<()>().unwrap(), None);
2185
2186        #[rustfmt::skip]
2187        assert_eq!(tuple.format().as_ptr(), TupleFormat::with_rust_allocator().as_ptr());
2188
2189        // Check error case
2190        let mut builder = TupleBuilder::rust_allocated();
2191        // String of length 1
2192        builder.append(b"\xa1!");
2193        let e = builder.into_tuple().unwrap_err();
2194        assert_eq!(e.to_string(), "failed to encode tuple: invalid msgpack value (expected array, found String(Utf8String { s: Ok(\"!\") }))");
2195
2196        // Check that reserve also works
2197        let mut builder = TupleBuilder::rust_allocated();
2198        builder.reserve(4);
2199        builder.append(b"\x93");
2200        builder.append(b"\x01");
2201        builder.append(b"\x02");
2202        builder.append(b"\x03");
2203        let tuple = builder.into_tuple().unwrap();
2204        let value: (i32, i32, i32) = tuple.decode().unwrap();
2205        assert_eq!(value, (1, 2, 3));
2206
2207        // Check that insufficient reserve also works
2208        let mut builder = TupleBuilder::rust_allocated();
2209        builder.reserve(0);
2210        builder.append(b"\x91");
2211        builder.append(b"\xa5");
2212        builder.append(b"hell");
2213        builder.append(b"o");
2214        let tuple = builder.into_tuple().unwrap();
2215        let (value,): (String,) = tuple.decode().unwrap();
2216        assert_eq!(value, "hello");
2217
2218        // Check Write for TupleBuilder
2219        let mut builder = TupleBuilder::rust_allocated();
2220        rmp_serde::encode::write(&mut builder, &(1, "two", 3.14)).unwrap();
2221        let tuple = builder.into_tuple().unwrap();
2222        let value: (i32, String, f32) = tuple.decode().unwrap();
2223        assert_eq!(value, (1, "two".to_owned(), 3.14));
2224    }
2225
2226    #[cfg(feature = "picodata")]
2227    #[crate::test(tarantool = "crate")]
2228    fn tuple_format_no_use_after_free() {
2229        let mut builder = TupleBuilder::rust_allocated();
2230        // Empty array
2231        builder.append(b"\x90");
2232        let tuple = builder.into_tuple().unwrap();
2233
2234        let original_ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2235        assert!(original_ref_count > 0);
2236
2237        let f1 = tuple.format();
2238
2239        // XXX: not sure if this is undefined behaviour or not, but we're
2240        // getting `.refs` from the same static immutable reference everytime, but the value changes.
2241        // Let's just hope rust thinks this is a different reference after each function call
2242        // (even though the pointer is definitely the same).
2243        let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2244        assert_eq!(ref_count, original_ref_count + 1);
2245
2246        let f2 = tuple.format();
2247
2248        let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2249        assert_eq!(ref_count, original_ref_count + 2);
2250
2251        drop(f1);
2252
2253        let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2254        assert_eq!(ref_count, original_ref_count + 1);
2255
2256        drop(f2);
2257
2258        let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2259        assert_eq!(ref_count, original_ref_count);
2260    }
2261}