1use 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
31pub 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 f.debug_tuple("Tuple").field(&self.to_vec()).finish()
43 }
44 }
45}
46
47impl Tuple {
48 #[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 #[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 #[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 #[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 #[inline(always)]
117 pub fn bsize(&self) -> usize {
118 unsafe { self.ptr.as_ref().bsize() }
119 }
120
121 #[inline(always)]
123 pub fn format(&self) -> TupleFormat {
124 let inner = unsafe { ffi::box_tuple_format(self.ptr.as_ptr()) };
126
127 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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline(always)]
297 pub fn as_ptr(&self) -> *mut ffi::BoxTuple {
298 self.ptr.as_ptr()
299 }
300}
301
302pub trait TupleIndex {
311 fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
312 where
313 T: Decode<'a>;
314}
315
316impl TupleIndex for u32 {
317 #[inline(always)]
318 fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
319 where
320 T: Decode<'a>,
321 {
322 tuple.field(self)
323 }
324}
325
326impl TupleIndex for &str {
327 #[inline(always)]
328 fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
329 where
330 T: Decode<'a>,
331 {
332 use once_cell::sync::Lazy;
333 use std::io::{Error as IOError, ErrorKind};
334 static API: Lazy<std::result::Result<Api, dlopen::Error>> = Lazy::new(|| unsafe {
335 let c_str = std::ffi::CStr::from_bytes_with_nul_unchecked;
336 let lib = dlopen::symbor::Library::open_self()?;
337 let err = match lib.symbol_cstr(c_str(ffi::TUPLE_FIELD_BY_PATH_NEW_API.as_bytes())) {
338 Ok(api) => return Ok(Api::New(*api)),
339 Err(e) => e,
340 };
341 if let Ok(api) = lib.symbol_cstr(c_str(ffi::TUPLE_FIELD_BY_PATH_OLD_API.as_bytes())) {
342 return Ok(Api::Old(*api));
343 }
344 Err(err)
345 });
346
347 return match API.as_ref() {
348 Ok(Api::New(api)) => unsafe {
349 let field_ptr = api(tuple.ptr.as_ptr(), self.as_ptr() as _, self.len() as _, 1);
350 field_value_from_ptr(field_ptr as _)
351 },
352 Ok(Api::Old(api)) => unsafe {
353 let data_offset = tuple.ptr.as_ref().data_offset() as _;
354 let data = tuple.ptr.as_ptr().cast::<c_char>().add(data_offset);
355 let field_ptr = api(
356 tuple.format().inner,
357 data,
358 data as _,
359 self.as_ptr() as _,
360 self.len() as _,
361 tlua::util::hash(self),
362 );
363 field_value_from_ptr(field_ptr as _)
364 },
365 Err(e) => Err(Error::IO(IOError::new(ErrorKind::Unsupported, e))),
366 };
367
368 enum Api {
369 Old(
371 extern "C" fn(
372 format: *const ffi::BoxTupleFormat,
373 tuple: *const c_char,
374 field_map: *const u32,
375 path: *const c_char,
376 path_len: u32,
377 path_hash: u32,
378 ) -> *const c_char,
379 ),
380 New(
382 extern "C" fn(
383 tuple: *const ffi::BoxTuple,
384 path: *const c_char,
385 path_len: u32,
386 index_base: i32,
387 ) -> *const c_char,
388 ),
389 }
390 }
391}
392
393impl From<&TupleBuffer> for Tuple {
394 #[inline(always)]
395 fn from(buf: &TupleBuffer) -> Self {
396 unsafe { Self::from_raw_data(buf.as_ptr() as _, buf.len() as _) }
397 }
398}
399
400impl Drop for Tuple {
401 #[inline(always)]
402 fn drop(&mut self) {
403 unsafe { ffi::box_tuple_unref(self.ptr.as_ptr()) };
404 }
405}
406
407impl Clone for Tuple {
408 #[inline(always)]
409 fn clone(&self) -> Self {
410 unsafe { ffi::box_tuple_ref(self.ptr.as_ptr()) };
411 Tuple { ptr: self.ptr }
412 }
413}
414
415impl<'de> serde_bytes::Deserialize<'de> for Tuple {
416 #[inline]
417 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
418 where
419 D: serde::Deserializer<'de>,
420 {
421 let data: &[u8] = serde_bytes::Deserialize::deserialize(deserializer)?;
422 Self::try_from_slice(data).map_err(serde::de::Error::custom)
423 }
424}
425
426pub trait ToTupleBuffer {
433 #[inline]
434 fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
435 let mut buf = Vec::with_capacity(128);
436 self.write_tuple_data(&mut buf)?;
437 TupleBuffer::try_from_vec(buf)
438 }
439
440 #[inline(always)]
449 fn tuple_data(&self) -> Option<&[u8]> {
450 None
451 }
452
453 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()>;
454}
455
456impl ToTupleBuffer for Tuple {
457 #[inline(always)]
458 fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
459 Ok(TupleBuffer::from(self))
460 }
461
462 #[cfg(feature = "picodata")]
463 #[inline(always)]
464 fn tuple_data(&self) -> Option<&[u8]> {
465 Some(self.data())
466 }
467
468 #[inline]
469 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
470 #[cfg(feature = "picodata")]
471 w.write_all(self.data())?;
472 #[cfg(not(feature = "picodata"))]
473 w.write_all(&self.to_vec())?;
474 Ok(())
475 }
476}
477
478impl<T> ToTupleBuffer for T
479where
480 T: ?Sized,
481 T: Encode,
482{
483 #[inline(always)]
484 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
485 self.encode(w)
486 }
487}
488
489pub trait Encode: Serialize {
498 #[inline(always)]
499 fn encode(&self, w: &mut impl Write) -> Result<()> {
500 rmp_serde::encode::write(w, self).map_err(Into::into)
501 }
502}
503
504impl<T> Encode for &'_ T
505where
506 T: Encode,
507{
508 #[inline(always)]
509 fn encode(&self, w: &mut impl Write) -> Result<()> {
510 T::encode(*self, w)
511 }
512}
513
514impl Encode for () {
515 #[inline(always)]
516 fn encode(&self, w: &mut impl Write) -> Result<()> {
517 rmp_serde::encode::write(w, &Vec::<()>::new()).map_err(Into::into)
518 }
519}
520
521impl<T> Encode for [T] where T: Serialize {}
522impl<T> Encode for Vec<T> where T: Serialize {}
523
524macro_rules! impl_array {
525 ($($n:literal)+) => {
526 $(
527 #[allow(clippy::zero_prefixed_literal)]
528 impl<T> Encode for [T; $n] where T: Serialize {}
529 )+
530 }
531}
532
533impl_array! {
534 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
535 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
536}
537
538macro_rules! impl_tuple {
539 () => {};
540 ($h:ident $($t:ident)*) => {
541 impl<$h, $($t),*> Encode for ($h, $($t),*)
542 where
543 $h: Serialize,
544 $($t: Serialize,)*
545 {}
546
547 impl_tuple! { $($t)* }
548 }
549}
550
551impl_tuple! { A B C D E F G H I J K L M N O P }
552
553#[derive(Clone, PartialEq, Eq)]
559pub struct TupleBuffer(
560 Vec<u8>,
573);
574
575impl TupleBuffer {
576 #[inline(always)]
578 pub fn as_ptr(&self) -> *const u8 {
579 self.0.as_ptr()
580 }
581
582 #[inline(always)]
584 pub fn len(&self) -> usize {
585 self.0.len()
586 }
587
588 #[inline(always)]
589 pub fn is_empty(&self) -> bool {
590 self.0.is_empty()
591 }
592
593 #[track_caller]
596 #[inline(always)]
597 pub unsafe fn from_vec_unchecked(buf: Vec<u8>) -> Self {
598 Self(buf)
599 }
600
601 #[inline]
602 pub fn try_from_vec(data: Vec<u8>) -> Result<Self> {
603 let data = validate_msgpack(data)?;
604 unsafe { Ok(Self::from_vec_unchecked(data)) }
605 }
606}
607
608impl AsRef<[u8]> for TupleBuffer {
609 #[inline(always)]
610 fn as_ref(&self) -> &[u8] {
611 self.0.as_ref()
612 }
613}
614
615impl From<TupleBuffer> for Vec<u8> {
616 #[inline(always)]
617 fn from(b: TupleBuffer) -> Self {
618 b.0
619 }
620}
621
622impl TryFrom<Vec<u8>> for TupleBuffer {
623 type Error = Error;
624
625 #[inline(always)]
626 fn try_from(data: Vec<u8>) -> Result<Self> {
627 Self::try_from_vec(data)
628 }
629}
630
631impl From<Tuple> for TupleBuffer {
632 #[inline(always)]
633 fn from(t: Tuple) -> Self {
634 Self(t.to_vec())
635 }
636}
637
638impl From<&Tuple> for TupleBuffer {
639 #[inline(always)]
640 fn from(t: &Tuple) -> Self {
641 Self(t.to_vec())
642 }
643}
644
645impl Debug for TupleBuffer {
646 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
647 if let Ok(v) = rmpv::Value::decode(&self.0) {
648 f.debug_tuple("TupleBuffer").field(&v).finish()
649 } else {
650 f.debug_tuple("TupleBuffer").field(&self.0).finish()
651 }
652 }
653}
654
655impl ToTupleBuffer for TupleBuffer {
656 #[inline(always)]
657 fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
658 Ok(self.clone())
659 }
660
661 #[inline(always)]
662 fn tuple_data(&self) -> Option<&[u8]> {
663 Some(&self.0)
664 }
665
666 #[inline(always)]
667 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
668 w.write_all(self.as_ref()).map_err(Into::into)
669 }
670}
671
672impl serde_bytes::Serialize for TupleBuffer {
673 #[inline(always)]
674 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
675 where
676 S: serde::Serializer,
677 {
678 serde_bytes::Serialize::serialize(&self.0, serializer)
679 }
680}
681
682impl<'de> serde_bytes::Deserialize<'de> for TupleBuffer {
683 #[inline]
684 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
685 where
686 D: serde::Deserializer<'de>,
687 {
688 let tmp: Vec<u8> = serde_bytes::Deserialize::deserialize(deserializer)?;
689 Self::try_from(tmp).map_err(serde::de::Error::custom)
690 }
691}
692
693pub struct TupleFormat {
702 inner: *mut ffi::BoxTupleFormat,
705}
706
707impl TupleFormat {
708 #[inline(always)]
709 pub fn as_ptr(&self) -> *mut ffi::BoxTupleFormat {
710 self.inner
711 }
712}
713
714impl Default for TupleFormat {
715 #[inline(always)]
716 fn default() -> Self {
717 TupleFormat {
718 inner: unsafe { ffi::box_tuple_format_default() },
719 }
720 }
721}
722
723impl Drop for TupleFormat {
724 fn drop(&mut self) {
725 unsafe {
727 if self.inner != ffi::box_tuple_format_default() {
728 ffi::box_tuple_format_unref(self.inner)
729 }
730 }
731 }
732}
733
734impl Debug for TupleFormat {
735 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
736 if self.inner == Self::default().inner {
737 f.write_str("TupleFormat::default()")
738 } else {
739 f.debug_tuple("TupleFormat").field(&self.inner).finish()
740 }
741 }
742}
743
744pub struct TupleIterator {
750 inner: *mut ffi::BoxTupleIterator,
751}
752
753impl Debug for TupleIterator {
754 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
755 f.debug_struct("TupleIterator")
756 .field("position", &self.position())
757 .finish()
758 }
759}
760
761impl TupleIterator {
762 #[inline(always)]
769 pub fn position(&self) -> u32 {
770 unsafe { ffi::box_tuple_position(self.inner) }
771 }
772
773 #[inline(always)]
775 pub fn rewind(&mut self) {
776 unsafe { ffi::box_tuple_rewind(self.inner) }
777 }
778
779 #[inline]
789 pub fn seek<'t, T>(&'t mut self, fieldno: u32) -> Result<Option<T>>
790 where
791 T: Decode<'t>,
792 {
793 unsafe { field_value_from_ptr(ffi::box_tuple_seek(self.inner, fieldno) as _) }
794 }
795
796 #[allow(clippy::should_implement_trait)]
806 #[inline]
807 pub fn next<'t, T>(&'t mut self) -> Result<Option<T>>
808 where
809 T: Decode<'t>,
810 {
811 unsafe { field_value_from_ptr(ffi::box_tuple_next(self.inner) as _) }
812 }
813
814 pub fn update(&mut self) {}
815}
816
817impl Drop for TupleIterator {
818 #[inline(always)]
819 fn drop(&mut self) {
820 unsafe { ffi::box_tuple_iterator_free(self.inner) }
821 }
822}
823
824impl TupleIterator {}
825
826crate::define_str_enum! {
831 pub enum FieldType {
832 Any = "any",
833 Unsigned = "unsigned",
834 String = "string",
835 Number = "number",
836 Double = "double",
837 Integer = "integer",
838 Boolean = "boolean",
839 Varbinary = "varbinary",
840 Scalar = "scalar",
841 Decimal = "decimal",
842 Uuid = "uuid",
843 Datetime = "datetime",
844 Array = "array",
845 Map = "map",
846 }
847}
848
849impl Default for FieldType {
850 #[inline(always)]
851 fn default() -> Self {
852 Self::Any
853 }
854}
855
856impl From<index::FieldType> for FieldType {
857 #[rustfmt::skip]
858 fn from(t: index::FieldType) -> Self {
859 match t {
860 index::FieldType::Unsigned => Self::Unsigned,
863 index::FieldType::String => Self::String,
864 index::FieldType::Number => Self::Number,
865 index::FieldType::Double => Self::Double,
866 index::FieldType::Integer => Self::Integer,
867 index::FieldType::Boolean => Self::Boolean,
868 index::FieldType::Varbinary => Self::Varbinary,
869 index::FieldType::Scalar => Self::Scalar,
870 index::FieldType::Decimal => Self::Decimal,
871 index::FieldType::Uuid => Self::Uuid,
872 index::FieldType::Datetime => Self::Datetime,
873 index::FieldType::Array => Self::Array,
874 }
875 }
876}
877
878#[derive(Debug)]
905pub struct KeyDef {
906 inner: NonNull<ffi::BoxKeyDef>,
907}
908
909#[derive(Default, Debug, PartialEq, Eq, Hash)]
910pub struct KeyDefPart<'a> {
911 pub field_no: u32,
912 pub field_type: FieldType,
913 pub collation: Option<Cow<'a, CStr>>,
914 pub is_nullable: bool,
915 pub path: Option<Cow<'a, CStr>>,
916}
917
918impl<'a> KeyDefPart<'a> {
919 fn as_tt(&self) -> ffi::box_key_part_def_t {
920 let flags = if self.is_nullable {
921 ffi::BoxKeyDefPartFlag::IS_NULLABLE.bits()
922 } else {
923 0
924 };
925 ffi::box_key_part_def_t {
926 meat: ffi::BoxKeyDefPart {
927 fieldno: self.field_no,
928 field_type: self.field_type.as_cstr().as_ptr(),
929 flags,
930 collation: self
931 .collation
932 .as_deref()
933 .map(CStr::as_ptr)
934 .unwrap_or(null()),
935 path: self.path.as_deref().map(CStr::as_ptr).unwrap_or(null()),
936 },
937 }
938 }
939
940 pub fn from_index_part(p: &'a index::Part<u32>) -> Self {
941 let collation = p.collation.as_deref().map(|s| {
942 CString::new(s)
943 .expect("it's your fault if you put '\0' in collation")
944 .into()
945 });
946 let path = p.path.as_deref().map(|s| {
947 CString::new(s)
948 .expect("it's your fault if you put '\0' in collation")
949 .into()
950 });
951 Self {
952 field_no: p.field,
953 field_type: p.r#type.map(From::from).unwrap_or(FieldType::Any),
954 is_nullable: p.is_nullable.unwrap_or(false),
955 collation,
956 path,
957 }
958 }
959}
960
961impl KeyDef {
962 #[inline]
967 pub fn new<'a>(parts: impl IntoIterator<Item = &'a KeyDefPart<'a>>) -> Result<Self> {
968 let mut tt_parts = parts.into_iter().map(KeyDefPart::as_tt).collect::<Vec<_>>();
969 let ptr = unsafe { ffi::box_key_def_new_v2(tt_parts.as_mut_ptr(), tt_parts.len() as _) };
970 let inner = NonNull::new(ptr).ok_or_else(TarantoolError::last)?;
971 Ok(KeyDef { inner })
972 }
973
974 #[inline(always)]
984 pub fn compare(&self, tuple_a: &Tuple, tuple_b: &Tuple) -> Ordering {
985 unsafe {
986 ffi::box_tuple_compare(
987 tuple_a.ptr.as_ptr(),
988 tuple_b.ptr.as_ptr(),
989 self.inner.as_ptr(),
990 )
991 .cmp(&0)
992 }
993 }
994
995 #[inline]
1005 pub fn compare_with_key<K>(&self, tuple: &Tuple, key: &K) -> Ordering
1006 where
1007 K: ToTupleBuffer + ?Sized,
1008 {
1009 let key_buf = key.to_tuple_buffer().unwrap();
1010 let key_buf_ptr = key_buf.as_ptr() as _;
1011 unsafe {
1012 ffi::box_tuple_compare_with_key(tuple.ptr.as_ptr(), key_buf_ptr, self.inner.as_ptr())
1013 .cmp(&0)
1014 }
1015 }
1016
1017 #[inline]
1029 pub fn validate_tuple(&self, tuple: &Tuple) -> Result<()> {
1030 let rc =
1032 unsafe { ffi::box_key_def_validate_tuple(self.inner.as_ptr(), tuple.ptr.as_ptr()) };
1033 if rc != 0 {
1034 return Err(TarantoolError::last().into());
1035 }
1036 Ok(())
1037 }
1038
1039 #[inline]
1042 pub fn extract_key(&self, tuple: &Tuple) -> Result<TupleBuffer> {
1043 self.validate_tuple(tuple)?;
1044 let res;
1045 unsafe {
1048 let used_before = ffi::box_region_used();
1049 let data = self.extract_key_raw(tuple, -1)?;
1050 res = TupleBuffer::from_vec_unchecked(data.into());
1051 ffi::box_region_truncate(used_before);
1052 }
1053 Ok(res)
1054 }
1055
1056 #[inline]
1067 pub unsafe fn extract_key_raw<'box_region>(
1068 &self,
1069 tuple: &Tuple,
1070 multikey_idx: i32,
1071 ) -> Result<&'box_region [u8]> {
1072 let slice;
1073 unsafe {
1075 let mut size = 0;
1076 let data = ffi::box_key_def_extract_key(
1077 self.inner.as_ptr(),
1078 tuple.ptr.as_ptr(),
1079 multikey_idx,
1080 &mut size,
1081 );
1082 if data.is_null() {
1083 return Err(TarantoolError::last().into());
1084 }
1085 slice = std::slice::from_raw_parts(data as _, size as _);
1086 }
1087 Ok(slice)
1088 }
1089
1090 #[cfg(feature = "picodata")]
1099 pub fn hash(&self, tuple: &Tuple) -> u32 {
1100 unsafe { ffi::box_tuple_hash(tuple.ptr.as_ptr(), self.inner.as_ptr()) }
1101 }
1102}
1103
1104impl Drop for KeyDef {
1105 #[inline(always)]
1106 fn drop(&mut self) {
1107 unsafe { ffi::box_key_def_delete(self.inner.as_ptr()) }
1108 }
1109}
1110
1111impl From<&index::Metadata<'_>> for KeyDef {
1112 #[inline(always)]
1113 fn from(meta: &index::Metadata<'_>) -> Self {
1114 meta.to_key_def()
1115 }
1116}
1117
1118unsafe fn field_value_from_ptr<'de, T>(field_ptr: *mut u8) -> Result<Option<T>>
1119where
1120 T: Decode<'de>,
1121{
1122 if field_ptr.is_null() {
1123 return Ok(None);
1124 }
1125
1126 let max_len = u32::MAX >> 1;
1130 let rough_slice = std::slice::from_raw_parts(field_ptr, max_len as _);
1131 let mut cursor = std::io::Cursor::new(rough_slice);
1132 let start = cursor.position() as usize;
1133 crate::msgpack::skip_value(&mut cursor)?;
1136 let value_range = start..(cursor.position() as usize);
1137 let rough_slice = cursor.into_inner();
1138 let value_slice = &rough_slice[value_range];
1139 Ok(Some(T::decode(value_slice)?))
1140}
1141
1142#[repr(C)]
1147#[derive(Debug)]
1148pub struct FunctionCtx {
1149 inner: *mut ffi::BoxFunctionCtx,
1150}
1151
1152impl FunctionCtx {
1153 #[inline]
1159 pub fn return_tuple(&self, tuple: &Tuple) -> Result<c_int> {
1160 let result = unsafe { ffi::box_return_tuple(self.inner, tuple.ptr.as_ptr()) };
1161 if result < 0 {
1162 Err(TarantoolError::last().into())
1163 } else {
1164 Ok(result)
1165 }
1166 }
1167
1168 #[inline]
1177 pub fn return_mp<T>(&self, value: &T) -> Result<c_int>
1178 where
1179 T: Serialize + ?Sized,
1180 {
1181 let buf = rmp_serde::to_vec_named(value)?;
1182 self.return_bytes(&buf)
1183 }
1184
1185 #[inline]
1195 pub fn return_bytes(&self, bytes: &[u8]) -> Result<c_int> {
1196 let Range { start, end } = bytes.as_ptr_range();
1197 let result = unsafe { ffi::box_return_mp(self.inner, start as _, end as _) };
1198
1199 if result < 0 {
1200 Err(TarantoolError::last().into())
1201 } else {
1202 Ok(result)
1203 }
1204 }
1205
1206 #[cfg(feature = "picodata")]
1207 #[inline]
1208 pub fn mut_port_c(&mut self) -> &mut PortC {
1209 unsafe {
1210 let mut ctx = NonNull::new_unchecked(self.inner);
1211 NonNull::new_unchecked(ctx.as_mut().port)
1212 .as_mut()
1213 .as_mut_port_c()
1214 }
1215 }
1216}
1217
1218#[repr(C)]
1223pub struct FunctionArgs {
1224 pub start: *const u8,
1225 pub end: *const u8,
1226}
1227
1228impl Debug for FunctionArgs {
1229 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1230 f.debug_tuple("FunctionArgs")
1231 .field(&Tuple::from(self))
1232 .finish()
1233 }
1234}
1235
1236impl From<FunctionArgs> for Tuple {
1237 #[inline(always)]
1238 fn from(args: FunctionArgs) -> Tuple {
1239 Tuple::from(&args)
1240 }
1241}
1242
1243impl From<&FunctionArgs> for Tuple {
1244 #[inline(always)]
1245 fn from(args: &FunctionArgs) -> Tuple {
1246 unsafe { Tuple::from_raw_data(args.start as _, args.end.offset_from(args.start) as _) }
1247 }
1248}
1249
1250impl FunctionArgs {
1251 #[inline(always)]
1253 pub fn decode<'a, T>(&'a self) -> Result<T>
1254 where
1255 T: Decode<'a>,
1256 {
1257 let slice = unsafe {
1258 std::slice::from_raw_parts(self.start, self.end.offset_from(self.start) as _)
1259 };
1260 T::decode(slice)
1261 }
1262}
1263
1264#[inline]
1269pub fn session_push<T>(value: &T) -> Result<()>
1270where
1271 T: ToTupleBuffer + ?Sized,
1272{
1273 let buf = value.to_tuple_buffer().unwrap();
1274 let buf_ptr = buf.as_ptr() as *const c_char;
1275 if unsafe { ffi::box_session_push(buf_ptr, buf_ptr.add(buf.len())) } < 0 {
1276 Err(TarantoolError::last().into())
1277 } else {
1278 Ok(())
1279 }
1280}
1281
1282#[inline]
1283fn validate_msgpack<T>(data: T) -> Result<T>
1284where
1285 T: AsRef<[u8]> + Into<Vec<u8>>,
1286{
1287 let mut slice = data.as_ref();
1288 let m = rmp::decode::read_marker(&mut slice)?;
1289 if !matches!(m, Marker::FixArray(_) | Marker::Array16 | Marker::Array32) {
1290 return Err(error::EncodeError::InvalidMP(data.into()).into());
1291 }
1292 Ok(data)
1293}
1294
1295impl<L> tlua::Push<L> for Tuple
1296where
1297 L: tlua::AsLua,
1298{
1299 type Err = tlua::Void;
1300
1301 #[inline(always)]
1302 fn push_to_lua(&self, lua: L) -> tlua::PushResult<L, Self> {
1303 unsafe {
1304 ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
1305 Ok(tlua::PushGuard::new(lua, 1))
1306 }
1307 }
1308}
1309
1310impl<L> tlua::PushOne<L> for Tuple where L: tlua::AsLua {}
1311
1312impl<L> tlua::PushInto<L> for Tuple
1313where
1314 L: tlua::AsLua,
1315{
1316 type Err = tlua::Void;
1317
1318 #[inline(always)]
1319 fn push_into_lua(self, lua: L) -> tlua::PushResult<L, Self> {
1320 unsafe {
1321 ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
1322 Ok(tlua::PushGuard::new(lua, 1))
1323 }
1324 }
1325}
1326
1327impl<L> tlua::PushOneInto<L> for Tuple where L: tlua::AsLua {}
1328
1329impl<L> tlua::LuaRead<L> for Tuple
1330where
1331 L: tlua::AsLua,
1332{
1333 fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> tlua::ReadResult<Self, L> {
1334 let lua_ptr = tlua::AsLua::as_lua(&lua);
1335 let mut ptr = unsafe { ffi::luaT_istuple(lua_ptr, index.get()) };
1336 if ptr.is_null() {
1337 let format = TupleFormat::default();
1338 ptr = unsafe { ffi::luaT_tuple_new(lua_ptr, index.get(), format.inner) };
1339 }
1340 Self::try_from_ptr(ptr).ok_or_else(|| {
1341 let e = tlua::WrongType::info("reading tarantool tuple")
1342 .expected_type::<Self>()
1343 .actual_single_lua(&lua, index);
1344 (lua, e)
1345 })
1346 }
1347}
1348
1349impl<L> tlua::LuaRead<L> for TupleBuffer
1350where
1351 L: tlua::AsLua,
1352{
1353 fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> tlua::ReadResult<Self, L> {
1354 unsafe {
1355 let svp = ffi::box_region_used();
1356 let lua_ptr = tlua::AsLua::as_lua(&lua);
1357 let ptr = ffi::luaT_istuple(lua_ptr, index.get());
1358 if let Some(tuple) = Tuple::try_from_ptr(ptr) {
1359 return Ok(Self::from(tuple));
1360 }
1361 let mut len = 0;
1362 let data = ffi::luaT_tuple_encode(lua_ptr, index.get(), &mut len);
1363 if data.is_null() {
1364 let e = tlua::WrongType::info("converting Lua value to tarantool tuple")
1365 .expected("msgpack array")
1366 .actual(format!("error: {}", TarantoolError::last().message()));
1367 return Err((lua, e));
1368 }
1369 let data = std::slice::from_raw_parts(data, len);
1370 let data = Vec::from(data);
1371 ffi::box_region_truncate(svp);
1372 Ok(Self::from_vec_unchecked(data))
1373 }
1374 }
1375}
1376
1377pub trait Decode<'de>: Sized {
1386 fn decode(data: &'de [u8]) -> Result<Self>;
1387}
1388
1389impl<'de, T> Decode<'de> for T
1390where
1391 T: serde::Deserialize<'de>,
1392{
1393 #[inline(always)]
1394 fn decode(data: &'de [u8]) -> Result<Self> {
1395 rmp_serde::from_slice(data).map_err(|e| Error::decode::<T>(e, data.into()))
1396 }
1397}
1398
1399impl Decode<'_> for Tuple {
1400 #[inline(always)]
1401 fn decode(data: &[u8]) -> Result<Self> {
1402 Self::try_from_slice(data)
1403 }
1404}
1405
1406pub trait DecodeOwned: for<'de> Decode<'de> {}
1414impl<T> DecodeOwned for T where T: for<'de> Decode<'de> {}
1415
1416#[derive(Debug)]
1434#[repr(transparent)]
1435pub struct RawBytes(pub [u8]);
1436
1437impl RawBytes {
1438 #[inline(always)]
1440 pub fn new(data: &[u8]) -> &Self {
1441 unsafe { &*(data as *const [u8] as *const RawBytes) }
1443 }
1444}
1445
1446impl<'a> From<&'a [u8]> for &'a RawBytes {
1447 #[inline(always)]
1448 fn from(data: &'a [u8]) -> Self {
1449 RawBytes::new(data)
1450 }
1451}
1452
1453impl<'de> Decode<'de> for &'de RawBytes {
1454 #[inline(always)]
1455 fn decode(data: &'de [u8]) -> Result<Self> {
1456 Ok(RawBytes::new(data))
1458 }
1459}
1460
1461impl ToTupleBuffer for RawBytes {
1462 #[inline(always)]
1463 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
1464 let data = &**self;
1465 validate_msgpack(data)?;
1466 w.write_all(data).map_err(Into::into)
1467 }
1468
1469 #[inline(always)]
1470 fn tuple_data(&self) -> Option<&[u8]> {
1471 let data = &**self;
1472 validate_msgpack(data).ok()?;
1473 Some(data)
1474 }
1475}
1476
1477impl std::ops::Deref for RawBytes {
1478 type Target = [u8];
1479 #[inline(always)]
1480 fn deref(&self) -> &Self::Target {
1481 &self.0
1482 }
1483}
1484
1485impl std::borrow::ToOwned for RawBytes {
1486 type Owned = RawByteBuf;
1487 #[inline(always)]
1488 fn to_owned(&self) -> Self::Owned {
1489 self.0.to_vec().into()
1490 }
1491}
1492
1493#[derive(Debug, PartialEq, Eq, Clone)]
1506pub struct RawByteBuf(pub Vec<u8>);
1507
1508impl serde_bytes::Serialize for RawByteBuf {
1509 #[inline(always)]
1510 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1511 where
1512 S: serde::Serializer,
1513 {
1514 serde_bytes::Serialize::serialize(&self.0, serializer)
1515 }
1516}
1517
1518impl<'de> serde_bytes::Deserialize<'de> for RawByteBuf {
1519 #[inline(always)]
1520 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1521 where
1522 D: serde::Deserializer<'de>,
1523 {
1524 serde_bytes::Deserialize::deserialize(deserializer).map(Self)
1525 }
1526}
1527
1528impl From<Vec<u8>> for RawByteBuf {
1529 #[inline(always)]
1530 fn from(b: Vec<u8>) -> Self {
1531 Self(b)
1532 }
1533}
1534
1535impl Decode<'_> for RawByteBuf {
1536 #[inline(always)]
1537 fn decode(data: &[u8]) -> Result<Self> {
1538 Ok(Self(data.into()))
1540 }
1541}
1542
1543impl ToTupleBuffer for RawByteBuf {
1544 #[inline(always)]
1545 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
1546 let data = self.as_slice();
1547 validate_msgpack(data)?;
1548 w.write_all(data).map_err(Into::into)
1549 }
1550
1551 #[inline(always)]
1552 fn tuple_data(&self) -> Option<&[u8]> {
1553 let data = self.as_slice();
1554 validate_msgpack(data).ok()?;
1555 Some(data)
1556 }
1557}
1558
1559impl std::ops::Deref for RawByteBuf {
1560 type Target = Vec<u8>;
1561 #[inline(always)]
1562 fn deref(&self) -> &Self::Target {
1563 &self.0
1564 }
1565}
1566
1567impl std::ops::DerefMut for RawByteBuf {
1568 #[inline(always)]
1569 fn deref_mut(&mut self) -> &mut Self::Target {
1570 &mut self.0
1571 }
1572}
1573
1574impl std::borrow::Borrow<RawBytes> for RawByteBuf {
1575 #[inline(always)]
1576 fn borrow(&self) -> &RawBytes {
1577 RawBytes::new(self.0.as_slice())
1578 }
1579}
1580
1581#[cfg(feature = "picodata")]
1582mod picodata {
1583 use super::*;
1584 use crate::static_ref;
1585
1586 impl Tuple {
1591 #[deprecated = "did not find its use"]
1604 #[inline(always)]
1605 pub fn as_named_buffer(&self) -> Result<Vec<u8>> {
1606 crate::say_error!("Tuple::as_named_buffer is no longer supported");
1607 panic!("Tuple::as_named_buffer is no longer supported");
1608 }
1609
1610 #[inline]
1612 pub fn data(&self) -> &[u8] {
1613 unsafe {
1614 let tuple = self.ptr.as_ref();
1616 tuple.data()
1617 }
1618 }
1619 }
1620
1621 impl PartialEq for Tuple {
1622 #[inline]
1623 fn eq(&self, other: &Self) -> bool {
1624 if self.ptr == other.ptr {
1625 return true;
1626 }
1627
1628 if self.bsize() != other.bsize() {
1629 return false;
1630 }
1631
1632 self.data() == other.data()
1633 }
1634 }
1635
1636 impl serde_bytes::Serialize for Tuple {
1637 #[inline(always)]
1638 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1639 where
1640 S: serde::Serializer,
1641 {
1642 serde_bytes::Serialize::serialize(self.data(), serializer)
1643 }
1644 }
1645
1646 impl TupleFormat {
1651 #[inline]
1654 pub fn with_rust_allocator() -> &'static Self {
1655 static mut SINGLETON: Option<TupleFormat> = None;
1656
1657 if unsafe { static_ref!(mut SINGLETON) }.is_none() {
1659 unsafe {
1661 let inner = ffi::box_tuple_format_new(std::ptr::null_mut(), 0);
1662 (*inner).vtab.tuple_new = vtab_impl::tuple_new_rust_allocator;
1663 (*inner).vtab.tuple_delete = vtab_impl::tuple_delete_rust_allocator;
1664 SINGLETON = Some(Self { inner });
1665 }
1666 }
1667
1668 unsafe { static_ref!(const SINGLETON) }
1669 .as_ref()
1670 .expect("just made sure it's there")
1671 }
1672
1673 #[deprecated = "did not find its use"]
1680 pub fn name_count(&self) -> u32 {
1681 crate::say_error!("TupleFormat::name_count is no longer supported");
1682 panic!("TupleFormat::name_count is no longer supported");
1683 }
1684
1685 #[deprecated = "did not find its use"]
1692 pub fn names(&self) -> impl Iterator<Item = &str> {
1693 crate::say_error!("TupleFormat::names is no longer supported");
1694 (|| panic!("TupleFormat::names is no longer supported"))();
1699 Vec::new().into_iter()
1701 }
1702 }
1703}
1704
1705#[cfg(feature = "picodata")]
1710pub struct TupleBuilder {
1711 is_rust_allocated: bool,
1715 buffer: Vec<u8>,
1716}
1717
1718#[cfg(feature = "picodata")]
1719impl TupleBuilder {
1720 const TUPLE_HEADER_PADDING: &'static [u8] = &[0; std::mem::size_of::<ffi::BoxTuple>()];
1721
1722 #[inline(always)]
1727 pub fn rust_allocated() -> Self {
1728 Self {
1729 is_rust_allocated: true,
1730 buffer: Vec::new(),
1731 }
1732 }
1733
1734 #[inline(always)]
1735 pub fn buffer(&self) -> &[u8] {
1736 &self.buffer
1737 }
1738
1739 #[inline]
1743 pub fn reserve(&mut self, mut capacity: usize) {
1744 if self.is_rust_allocated && self.buffer.capacity() == 0 {
1745 capacity += std::mem::size_of::<ffi::BoxTuple>();
1746 }
1747 self.buffer.reserve(capacity);
1748 }
1749
1750 #[inline]
1751 pub fn append(&mut self, data: &[u8]) {
1752 if self.is_rust_allocated && self.buffer.is_empty() {
1753 self.buffer
1754 .reserve(Self::TUPLE_HEADER_PADDING.len() + data.len());
1755 self.buffer.extend_from_slice(Self::TUPLE_HEADER_PADDING);
1756 }
1757 self.buffer.extend_from_slice(data);
1758 }
1759
1760 #[inline]
1761 pub fn into_tuple(self) -> Result<Tuple> {
1762 if self.is_rust_allocated {
1763 self.into_tuple_rust_allocated()
1764 } else {
1765 Tuple::try_from_slice(&self.buffer)
1766 }
1767 }
1768
1769 fn into_tuple_rust_allocated(self) -> Result<Tuple> {
1770 use crate::error::BoxError;
1771 use crate::error::TarantoolErrorCode;
1772
1773 if self.buffer.is_empty() {
1774 #[rustfmt::skip]
1775 return Err(BoxError::new(TarantoolErrorCode::IllegalParams, "cannot construct an empty tuple").into());
1776 }
1777
1778 if self.buffer.len() < Self::TUPLE_HEADER_PADDING.len() {
1779 #[rustfmt::skip]
1780 return Err(BoxError::new(TarantoolErrorCode::IllegalParams, "buffer is corrupted").into());
1781 }
1782
1783 let mut tuple_chunk = self.buffer;
1784 let data_offset = Self::TUPLE_HEADER_PADDING.len();
1785 let data_len = tuple_chunk.len() - data_offset;
1786 validate_msgpack(&tuple_chunk[data_offset..])?;
1787
1788 let format = TupleFormat::with_rust_allocator();
1789
1790 let tuple = tuple_chunk.as_mut_ptr().cast::<ffi::BoxTuple>();
1791 unsafe {
1792 std::ptr::write(
1793 tuple,
1794 ffi::BoxTuple {
1796 refs: 0,
1797 flags: 0,
1798 format_id: (*format.inner).id,
1799 data_offset: data_offset as _,
1800 bsize: data_len as _,
1801 },
1802 );
1803 }
1804 unsafe {
1806 ffi::box_tuple_format_ref(format.inner);
1807 }
1808
1809 _ = Box::into_raw(tuple_chunk.into_boxed_slice());
1811
1812 let tuple = unsafe { NonNull::new_unchecked(tuple) };
1814 let tuple = Tuple::from_ptr(tuple);
1815 return Ok(tuple);
1816 }
1817}
1818
1819#[cfg(feature = "picodata")]
1820impl std::io::Write for TupleBuilder {
1821 #[inline(always)]
1822 fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
1823 self.append(data);
1824 Ok(data.len())
1825 }
1826
1827 #[inline(always)]
1828 fn flush(&mut self) -> std::io::Result<()> {
1829 Ok(())
1830 }
1831}
1832
1833#[cfg(feature = "picodata")]
1838mod vtab_impl {
1839 use super::*;
1840
1841 pub unsafe extern "C" fn tuple_new_rust_allocator(
1843 format: *mut ffi::BoxTupleFormat,
1844 data: *const u8,
1845 end: *const u8,
1846 ) -> *mut ffi::BoxTuple {
1847 #[rustfmt::skip]
1848 debug_assert_eq!((*format).vtab.tuple_delete, tuple_delete_rust_allocator as ffi::FnTupleDelete);
1849
1850 const TUPLE_HEADER_SIZE: usize = std::mem::size_of::<ffi::BoxTuple>();
1851 let data_offset = TUPLE_HEADER_SIZE;
1852 let data_len = end.offset_from(data);
1855 debug_assert!(data_len >= 0);
1856 let data_len = data_len as usize;
1857 debug_assert!(data_len <= u32::MAX as usize);
1858
1859 let total_size = data_offset + data_len;
1861 let mut tuple_chunk: Vec<u8> = Vec::with_capacity(total_size);
1862
1863 let tuple = tuple_chunk.as_mut_ptr().cast::<ffi::BoxTuple>();
1864 std::ptr::write(
1865 tuple,
1866 ffi::BoxTuple {
1868 refs: 0,
1869 flags: 0,
1870 format_id: (*format).id,
1871 data_offset: data_offset as _,
1872 bsize: data_len as _,
1873 },
1874 );
1875 ffi::box_tuple_format_ref(format);
1876
1877 let data_slice = std::slice::from_raw_parts(data, data_len);
1878 tuple_chunk.set_len(total_size);
1879 let tuple_data = &mut tuple_chunk[data_offset..];
1880 debug_assert_eq!(data_slice.len(), tuple_data.len());
1881 tuple_data.copy_from_slice(data_slice);
1882
1883 let tuple_chunk: Box<[u8]> = tuple_chunk.into_boxed_slice();
1885 _ = Box::into_raw(tuple_chunk);
1886
1887 return tuple;
1888 }
1889
1890 pub unsafe extern "C" fn tuple_delete_rust_allocator(
1892 format: *mut ffi::BoxTupleFormat,
1893 tuple: *mut ffi::BoxTuple,
1894 ) {
1895 #[rustfmt::skip]
1896 debug_assert_eq!((*format).vtab.tuple_delete, tuple_delete_rust_allocator as ffi::FnTupleDelete);
1897
1898 debug_assert!(tuple != 0 as _);
1899 debug_assert_eq!((*tuple).refs, 0);
1900 const FLAG_TUPLE_HAS_UPLOADED_REFS: u8 = 1 << 0;
1901 debug_assert_eq!(((*tuple).flags & FLAG_TUPLE_HAS_UPLOADED_REFS), 0);
1902
1903 ffi::box_tuple_format_unref(format);
1904
1905 let total_size = (*tuple).data_offset() as usize + (*tuple).bsize();
1906
1907 let tuple_chunk_start = tuple.cast::<u8>();
1908 let tuple_chunk_slice = std::slice::from_raw_parts_mut(tuple_chunk_start, total_size);
1909 let tuple_chunk: Box<[u8]> = Box::from_raw(tuple_chunk_slice);
1911 drop(tuple_chunk);
1912 }
1913}
1914
1915#[cfg(feature = "internal_test")]
1916mod test {
1917 #![allow(clippy::redundant_clone)]
1918 use super::*;
1919 use crate::space;
1920 use crate::space::Space;
1921 use pretty_assertions::assert_eq;
1922
1923 #[crate::test(tarantool = "crate")]
1924 fn tuple_buffer_from_lua() {
1925 let svp = unsafe { ffi::box_region_used() };
1926
1927 let lua = crate::lua_state();
1928 let t: TupleBuffer = lua
1929 .eval("return { 3, 'foo', { true, box.NIL, false } }")
1930 .unwrap();
1931
1932 #[derive(::serde::Deserialize, PartialEq, Eq, Debug)]
1933 struct S {
1934 i: i32,
1935 s: String,
1936 t: [Option<bool>; 3],
1937 }
1938
1939 let s = S::decode(t.as_ref()).unwrap();
1940 assert_eq!(
1941 s,
1942 S {
1943 i: 3,
1944 s: "foo".into(),
1945 t: [Some(true), None, Some(false)]
1946 }
1947 );
1948
1949 let res = lua.eval::<TupleBuffer>("return 1, 2, 3");
1950 assert_eq!(
1951 res.unwrap_err().to_string(),
1952 "failed converting Lua value to tarantool tuple: msgpack array expected, got error: A tuple or a table expected, got number
1953 while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got (number, number, number)"
1954 );
1955
1956 let res = lua.eval::<TupleBuffer>("return { 1, 2, foo = 'bar' }");
1957 assert_eq!(
1958 res.unwrap_err().to_string(),
1959 "failed converting Lua value to tarantool tuple: msgpack array expected, got error: Tuple/Key must be MsgPack array
1960 while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got table"
1961 );
1962
1963 let res = lua.eval::<TupleBuffer>(
1964 "ffi = require 'ffi';
1965 local cdata = ffi.new('struct { int x; int y; }', { x = -1, y = 2 })
1966 return { 1, cdata }",
1967 );
1968 assert_eq!(
1969 res.unwrap_err().to_string(),
1970 "failed converting Lua value to tarantool tuple: msgpack array expected, got error: unsupported Lua type 'cdata'
1971 while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got table"
1972 );
1973
1974 assert_eq!(svp, unsafe { ffi::box_region_used() });
1975 }
1976
1977 #[crate::test(tarantool = "crate")]
1978 fn decode_error() {
1979 use super::*;
1980
1981 let buf = (1, 2, 3).to_tuple_buffer().unwrap();
1982 let err = <(String, String)>::decode(buf.as_ref()).unwrap_err();
1983 assert_eq!(
1984 err.to_string(),
1985 r#"failed to decode tuple: invalid type: integer `1`, expected a string when decoding msgpack b"\x93\x01\x02\x03" into rust type (alloc::string::String, alloc::string::String)"#
1986 );
1987
1988 let buf = ("hello", [1, 2, 3], "goodbye").to_tuple_buffer().unwrap();
1989 let err = <(String, (i32, String, i32), String)>::decode(buf.as_ref()).unwrap_err();
1990 assert_eq!(
1991 err.to_string(),
1992 r#"failed to decode tuple: invalid type: integer `2`, expected a string when decoding msgpack b"\x93\xa5hello\x93\x01\x02\x03\xa7goodbye" into rust type (alloc::string::String, (i32, alloc::string::String, i32), alloc::string::String)"#
1993 )
1994 }
1995
1996 #[crate::test(tarantool = "crate")]
1997 fn key_def_extract_key() {
1998 let space = Space::builder(&crate::temp_space_name!())
1999 .field(("id", space::FieldType::Unsigned))
2000 .field(("not-key", space::FieldType::Array))
2001 .field(("s", space::FieldType::String))
2002 .field(("nested", space::FieldType::Any))
2003 .create()
2004 .unwrap();
2005
2006 let index = space
2007 .index_builder("pk")
2008 .part("id")
2009 .part("s")
2010 .part(
2011 index::Part::<String>::field("nested")
2012 .field_type(index::FieldType::Unsigned)
2013 .path("[2].blabla"),
2014 )
2015 .create()
2016 .unwrap();
2017
2018 let key_def = index.meta().unwrap().to_key_def();
2019
2020 let tuple = Tuple::new(&["foo"]).unwrap();
2021 let e = key_def.extract_key(&tuple).unwrap_err();
2022 assert_eq!(e.to_string(), "box error: KeyPartType: Supplied key type of part 0 does not match index part type: expected unsigned");
2023
2024 let tuple = Tuple::new(&[1]).unwrap();
2025 let e = key_def.extract_key(&tuple).unwrap_err();
2026 assert_eq!(
2030 e.to_string(),
2031 "box error: FieldMissing: Tuple field [3] required by space format is missing"
2032 );
2033
2034 let tuple = Tuple::new(&(1, [1, 2, 3], "foo")).unwrap();
2035 let e = key_def.extract_key(&tuple).unwrap_err();
2036 assert_eq!(
2037 e.to_string(),
2038 "box error: FieldMissing: Tuple field [4][2].blabla required by space format is missing"
2039 );
2040
2041 let raw_data = b"\x94\x69\x93\x01\x02\x03\xa3foo\x93\xc0\x81\xa6blabla\x42\x07"; let tuple = Tuple::new(RawBytes::new(raw_data)).unwrap();
2043 let key = key_def.extract_key(&tuple).unwrap();
2044 assert_eq!(key.as_ref(), b"\x93\x69\xa3foo\x42"); let raw_data = b"\x94\x13\xa9not-array\xa3bar\x92\xc0\x81\xa6blabla\x37"; let tuple = Tuple::new(RawBytes::new(raw_data)).unwrap();
2052 let key = key_def.extract_key(&tuple).unwrap();
2053 assert_eq!(key.as_ref(), b"\x93\x13\xa3bar\x37");
2054
2055 let e = space.insert(&tuple).unwrap_err();
2057 assert_eq!(e.to_string(), "box error: FieldType: Tuple field 2 (not-key) type does not match one required by operation: expected array, got string");
2058 }
2059
2060 #[cfg(feature = "picodata")]
2061 #[crate::test(tarantool = "crate")]
2062 fn tuple_data() {
2063 let tuple = Tuple::new(&(69, "nice", [3, 2, 1])).unwrap();
2065 assert_eq!(tuple.data(), b"\x93\x45\xa4nice\x93\x03\x02\x01");
2070
2071 let space = Space::builder(&crate::temp_space_name!())
2073 .field(("id", space::FieldType::Unsigned))
2074 .field(("name", space::FieldType::String))
2075 .create()
2076 .unwrap();
2077
2078 space.index_builder("pk").create().unwrap();
2079
2080 let tuple = space.insert(&(13, "37")).unwrap();
2081 assert_eq!(tuple.data(), b"\x92\x0d\xa237");
2082 }
2083
2084 #[cfg(feature = "picodata")]
2085 #[crate::test(tarantool = "crate")]
2086 fn compare_tuples() {
2087 let data = b"\x92\xa3foo\xa3bar";
2090 let tuple_1 = Tuple::try_from_slice(data).unwrap();
2091
2092 let tuple_1_clone = tuple_1.clone();
2094 assert_eq!(tuple_1_clone.as_ptr(), tuple_1.as_ptr());
2095 assert_eq!(tuple_1_clone, tuple_1);
2096
2097 let tuple_1_equivalent = Tuple::try_from_slice(data).unwrap();
2099 assert_ne!(tuple_1_equivalent.as_ptr(), tuple_1.as_ptr());
2100 assert_eq!(tuple_1_equivalent, tuple_1);
2101
2102 let other_data = b"\x93\x10\x20\x30";
2106 let tuple_2 = Tuple::try_from_slice(other_data).unwrap();
2107 assert_ne!(data.len(), other_data.len());
2108 assert_ne!(tuple_1, tuple_2);
2109
2110 let other_data_same_len = b"\x92\xa3foo\xa3baz";
2114 assert_eq!(data.len(), other_data_same_len.len());
2115 let tuple_3 = Tuple::try_from_slice(other_data_same_len).unwrap();
2116 assert_ne!(tuple_2, tuple_3);
2117 }
2118
2119 #[cfg(feature = "picodata")]
2120 #[crate::test(tarantool = "crate")]
2121 fn serialize_deserialize() {
2122 #[derive(Debug, serde::Serialize, serde::Deserialize)]
2123 struct Wrapper {
2124 #[serde(with = "serde_bytes")]
2125 tuple: Tuple,
2126 }
2127
2128 let data = rmp_serde::to_vec_named(&Wrapper {
2130 tuple: Tuple::new(&(0x77, "hello", 0x77)).unwrap(),
2131 })
2132 .unwrap();
2133 assert_eq!(&data, b"\x81\xa5tuple\xc4\x09\x93\x77\xa5hello\x77");
2138
2139 let data = b"\x81\xa5tuple\xc4\x0c\x94\xa7numbers\x03\x01\x04";
2142 let w: Wrapper = rmp_serde::from_slice(data).unwrap();
2143 let s: &str = w.tuple.field(0).unwrap().unwrap();
2144 assert_eq!(s, "numbers");
2145 let n: i32 = w.tuple.field(1).unwrap().unwrap();
2146 assert_eq!(n, 3);
2147 let n: i32 = w.tuple.field(2).unwrap().unwrap();
2148 assert_eq!(n, 1);
2149 let n: i32 = w.tuple.field(3).unwrap().unwrap();
2150 assert_eq!(n, 4);
2151
2152 let data = b"\x81\xa5tuple\xc4\x01\x45";
2154 let e = rmp_serde::from_slice::<Wrapper>(data).unwrap_err();
2155 assert_eq!(e.to_string(), "failed to encode tuple: invalid msgpack value (expected array, found Integer(PosInt(69)))");
2156 }
2157
2158 #[cfg(feature = "picodata")]
2159 #[crate::test(tarantool = "crate")]
2160 fn rust_allocated_tuples() {
2161 let mut builder = TupleBuilder::rust_allocated();
2162 builder.append(b"\x91");
2164 builder.append(b"\xc4\x10");
2166 builder.append(b"0123456789abcdef");
2167 let tuple = builder.into_tuple().unwrap();
2168
2169 assert_eq!(tuple.len(), 1);
2171 assert_eq!(tuple.bsize(), 19);
2172 assert_eq!(tuple.data(), b"\x91\xc4\x100123456789abcdef");
2173 assert_eq!(tuple.to_vec(), b"\x91\xc4\x100123456789abcdef");
2174
2175 let (value,): (serde_bytes::ByteBuf,) = tuple.decode().unwrap();
2176 assert_eq!(value, b"0123456789abcdef");
2177
2178 let value: &serde_bytes::Bytes = tuple.field(0).unwrap().unwrap();
2179 assert_eq!(value, b"0123456789abcdef");
2180
2181 let mut iter = tuple.iter().unwrap();
2182 let value: &serde_bytes::Bytes = iter.next().unwrap().unwrap();
2183 assert_eq!(value, b"0123456789abcdef");
2184 assert_eq!(iter.next::<()>().unwrap(), None);
2185
2186 #[rustfmt::skip]
2187 assert_eq!(tuple.format().as_ptr(), TupleFormat::with_rust_allocator().as_ptr());
2188
2189 let mut builder = TupleBuilder::rust_allocated();
2191 builder.append(b"\xa1!");
2193 let e = builder.into_tuple().unwrap_err();
2194 assert_eq!(e.to_string(), "failed to encode tuple: invalid msgpack value (expected array, found String(Utf8String { s: Ok(\"!\") }))");
2195
2196 let mut builder = TupleBuilder::rust_allocated();
2198 builder.reserve(4);
2199 builder.append(b"\x93");
2200 builder.append(b"\x01");
2201 builder.append(b"\x02");
2202 builder.append(b"\x03");
2203 let tuple = builder.into_tuple().unwrap();
2204 let value: (i32, i32, i32) = tuple.decode().unwrap();
2205 assert_eq!(value, (1, 2, 3));
2206
2207 let mut builder = TupleBuilder::rust_allocated();
2209 builder.reserve(0);
2210 builder.append(b"\x91");
2211 builder.append(b"\xa5");
2212 builder.append(b"hell");
2213 builder.append(b"o");
2214 let tuple = builder.into_tuple().unwrap();
2215 let (value,): (String,) = tuple.decode().unwrap();
2216 assert_eq!(value, "hello");
2217
2218 let mut builder = TupleBuilder::rust_allocated();
2220 rmp_serde::encode::write(&mut builder, &(1, "two", 3.14)).unwrap();
2221 let tuple = builder.into_tuple().unwrap();
2222 let value: (i32, String, f32) = tuple.decode().unwrap();
2223 assert_eq!(value, (1, "two".to_owned(), 3.14));
2224 }
2225
2226 #[cfg(feature = "picodata")]
2227 #[crate::test(tarantool = "crate")]
2228 fn tuple_format_no_use_after_free() {
2229 let mut builder = TupleBuilder::rust_allocated();
2230 builder.append(b"\x90");
2232 let tuple = builder.into_tuple().unwrap();
2233
2234 let original_ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2235 assert!(original_ref_count > 0);
2236
2237 let f1 = tuple.format();
2238
2239 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2244 assert_eq!(ref_count, original_ref_count + 1);
2245
2246 let f2 = tuple.format();
2247
2248 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2249 assert_eq!(ref_count, original_ref_count + 2);
2250
2251 drop(f1);
2252
2253 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2254 assert_eq!(ref_count, original_ref_count + 1);
2255
2256 drop(f2);
2257
2258 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2259 assert_eq!(ref_count, original_ref_count);
2260 }
2261}