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