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