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]
105 pub unsafe fn try_from_ptr_dont_ref(ptr: *mut ffi::BoxTuple) -> Option<Self> {
106 let ptr = NonNull::new(ptr)?;
107
108 #[cfg(feature = "picodata")]
109 debug_assert_ne!(ptr.as_ref().refs, 0);
110
111 Some(Self { ptr })
112 }
113
114 #[inline(always)]
116 pub fn len(&self) -> u32 {
117 unsafe { ffi::box_tuple_field_count(self.ptr.as_ptr()) }
118 }
119
120 #[inline(always)]
121 pub fn is_empty(&self) -> bool {
122 self.len() == 0
123 }
124
125 #[inline(always)]
135 pub fn bsize(&self) -> usize {
136 unsafe { self.ptr.as_ref().bsize() }
137 }
138
139 #[inline(always)]
141 pub fn format(&self) -> TupleFormat {
142 let inner = unsafe { ffi::box_tuple_format(self.ptr.as_ptr()) };
144
145 unsafe {
147 if inner != ffi::box_tuple_format_default() {
148 ffi::box_tuple_format_ref(inner)
149 }
150 }
151
152 TupleFormat { inner }
153 }
154
155 #[inline]
177 pub fn iter(&self) -> Result<TupleIterator> {
178 let inner = unsafe { ffi::box_tuple_iterator(self.ptr.as_ptr()) };
179 if inner.is_null() {
180 Err(TarantoolError::last().into())
181 } else {
182 Ok(TupleIterator { inner })
183 }
184 }
185
186 #[inline(always)]
197 pub fn field<'a, T>(&'a self, fieldno: u32) -> Result<Option<T>>
198 where
199 T: Decode<'a>,
200 {
201 unsafe {
202 let field_ptr = ffi::box_tuple_field(self.ptr.as_ptr(), fieldno);
203 field_value_from_ptr(field_ptr as _)
204 }
205 }
206
207 #[inline(always)]
230 pub fn try_get<'a, I, T>(&'a self, key: I) -> Result<Option<T>>
231 where
232 I: TupleIndex,
233 T: Decode<'a>,
234 {
235 key.get_field(self)
236 }
237
238 #[inline(always)]
261 #[track_caller]
262 pub fn get<'a, I, T>(&'a self, key: I) -> Option<T>
263 where
264 I: TupleIndex,
265 T: Decode<'a>,
266 {
267 self.try_get(key).expect("Error during getting tuple field")
268 }
269
270 #[inline]
287 pub fn decode<T>(&self) -> Result<T>
288 where
289 T: DecodeOwned,
290 {
291 #[cfg(feature = "picodata")]
292 return Decode::decode(self.data());
293 #[cfg(not(feature = "picodata"))]
294 return Decode::decode(&self.to_vec());
295 }
296
297 #[inline]
301 pub fn to_vec(&self) -> Vec<u8> {
302 let size = self.bsize();
303 let mut buf = Vec::with_capacity(size);
304
305 unsafe {
306 let actual_size = ffi::box_tuple_to_buf(self.ptr.as_ptr(), buf.as_ptr() as _, size);
307 buf.set_len(actual_size as usize);
308 }
309
310 buf
311 }
312
313 #[inline(always)]
315 pub fn as_ptr(&self) -> *mut ffi::BoxTuple {
316 self.ptr.as_ptr()
317 }
318}
319
320pub trait TupleIndex {
329 fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
330 where
331 T: Decode<'a>;
332}
333
334impl TupleIndex for u32 {
335 #[inline(always)]
336 fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
337 where
338 T: Decode<'a>,
339 {
340 tuple.field(self)
341 }
342}
343
344impl TupleIndex for &str {
345 #[inline(always)]
346 fn get_field<'a, T>(self, tuple: &'a Tuple) -> Result<Option<T>>
347 where
348 T: Decode<'a>,
349 {
350 use once_cell::sync::Lazy;
351 use std::io::{Error as IOError, ErrorKind};
352 static API: Lazy<std::result::Result<Api, libloading::Error>> = Lazy::new(|| unsafe {
353 let lib = libloading::os::unix::Library::this();
354 let err = match lib.get(ffi::TUPLE_FIELD_BY_PATH_NEW_API.as_bytes()) {
355 Ok(api) => return Ok(Api::New(*api)),
356 Err(e) => e,
357 };
358 if let Ok(api) = lib.get(ffi::TUPLE_FIELD_BY_PATH_OLD_API.as_bytes()) {
359 return Ok(Api::Old(*api));
360 }
361 Err(err)
362 });
363
364 return match API.as_ref() {
365 Ok(Api::New(api)) => unsafe {
366 let field_ptr = api(tuple.ptr.as_ptr(), self.as_ptr() as _, self.len() as _, 1);
367 field_value_from_ptr(field_ptr as _)
368 },
369 Ok(Api::Old(api)) => unsafe {
370 let data_offset = tuple.ptr.as_ref().data_offset() as _;
371 let data = tuple.ptr.as_ptr().cast::<c_char>().add(data_offset);
372 let field_ptr = api(
373 tuple.format().inner,
374 data,
375 data as _,
376 self.as_ptr() as _,
377 self.len() as _,
378 tlua::util::hash(self),
379 );
380 field_value_from_ptr(field_ptr as _)
381 },
382 Err(e) => Err(Error::IO(IOError::new(ErrorKind::Unsupported, e))),
383 };
384
385 enum Api {
386 Old(
388 extern "C" fn(
389 format: *const ffi::BoxTupleFormat,
390 tuple: *const c_char,
391 field_map: *const u32,
392 path: *const c_char,
393 path_len: u32,
394 path_hash: u32,
395 ) -> *const c_char,
396 ),
397 New(
399 extern "C" fn(
400 tuple: *const ffi::BoxTuple,
401 path: *const c_char,
402 path_len: u32,
403 index_base: i32,
404 ) -> *const c_char,
405 ),
406 }
407 }
408}
409
410impl From<&TupleBuffer> for Tuple {
411 #[inline(always)]
412 fn from(buf: &TupleBuffer) -> Self {
413 unsafe { Self::from_raw_data(buf.as_ptr() as _, buf.len() as _) }
414 }
415}
416
417impl Drop for Tuple {
418 #[inline(always)]
419 fn drop(&mut self) {
420 unsafe { ffi::box_tuple_unref(self.ptr.as_ptr()) };
421 }
422}
423
424impl Clone for Tuple {
425 #[inline(always)]
426 fn clone(&self) -> Self {
427 unsafe { ffi::box_tuple_ref(self.ptr.as_ptr()) };
428 Tuple { ptr: self.ptr }
429 }
430}
431
432impl<'de> serde_bytes::Deserialize<'de> for Tuple {
433 #[inline]
434 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
435 where
436 D: serde::Deserializer<'de>,
437 {
438 let data: &[u8] = serde_bytes::Deserialize::deserialize(deserializer)?;
439 Self::try_from_slice(data).map_err(serde::de::Error::custom)
440 }
441}
442
443pub trait ToTupleBuffer {
450 #[inline]
451 fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
452 let mut buf = Vec::with_capacity(128);
453 self.write_tuple_data(&mut buf)?;
454 TupleBuffer::try_from_vec(buf)
455 }
456
457 #[inline(always)]
466 fn tuple_data(&self) -> Option<&[u8]> {
467 None
468 }
469
470 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()>;
471}
472
473impl ToTupleBuffer for Tuple {
474 #[inline(always)]
475 fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
476 Ok(TupleBuffer::from(self))
477 }
478
479 #[cfg(feature = "picodata")]
480 #[inline(always)]
481 fn tuple_data(&self) -> Option<&[u8]> {
482 Some(self.data())
483 }
484
485 #[inline]
486 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
487 #[cfg(feature = "picodata")]
488 w.write_all(self.data())?;
489 #[cfg(not(feature = "picodata"))]
490 w.write_all(&self.to_vec())?;
491 Ok(())
492 }
493}
494
495impl<T> ToTupleBuffer for T
496where
497 T: ?Sized,
498 T: Encode,
499{
500 #[inline(always)]
501 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
502 self.encode(w)
503 }
504}
505
506pub trait Encode: Serialize {
515 #[inline(always)]
516 fn encode(&self, w: &mut impl Write) -> Result<()> {
517 rmp_serde::encode::write(w, self).map_err(Into::into)
518 }
519}
520
521impl<T> Encode for &'_ T
522where
523 T: Encode,
524{
525 #[inline(always)]
526 fn encode(&self, w: &mut impl Write) -> Result<()> {
527 T::encode(*self, w)
528 }
529}
530
531impl Encode for () {
532 #[inline(always)]
533 fn encode(&self, w: &mut impl Write) -> Result<()> {
534 rmp_serde::encode::write(w, &Vec::<()>::new()).map_err(Into::into)
535 }
536}
537
538impl<T> Encode for [T] where T: Serialize {}
539impl<T> Encode for Vec<T> where T: Serialize {}
540
541macro_rules! impl_array {
542 ($($n:literal)+) => {
543 $(
544 #[allow(clippy::zero_prefixed_literal)]
545 impl<T> Encode for [T; $n] where T: Serialize {}
546 )+
547 }
548}
549
550impl_array! {
551 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
552 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
553}
554
555macro_rules! impl_tuple {
556 () => {};
557 ($h:ident $($t:ident)*) => {
558 impl<$h, $($t),*> Encode for ($h, $($t),*)
559 where
560 $h: Serialize,
561 $($t: Serialize,)*
562 {}
563
564 impl_tuple! { $($t)* }
565 }
566}
567
568impl_tuple! { A B C D E F G H I J K L M N O P }
569
570#[derive(Clone, PartialEq, Eq)]
576pub struct TupleBuffer(
577 Vec<u8>,
590);
591
592impl TupleBuffer {
593 #[inline(always)]
595 pub fn as_ptr(&self) -> *const u8 {
596 self.0.as_ptr()
597 }
598
599 #[inline(always)]
601 pub fn len(&self) -> usize {
602 self.0.len()
603 }
604
605 #[inline(always)]
606 pub fn is_empty(&self) -> bool {
607 self.0.is_empty()
608 }
609
610 #[track_caller]
613 #[inline(always)]
614 pub unsafe fn from_vec_unchecked(buf: Vec<u8>) -> Self {
615 Self(buf)
616 }
617
618 #[inline]
619 pub fn try_from_vec(data: Vec<u8>) -> Result<Self> {
620 let data = validate_msgpack(data)?;
621 unsafe { Ok(Self::from_vec_unchecked(data)) }
622 }
623}
624
625impl AsRef<[u8]> for TupleBuffer {
626 #[inline(always)]
627 fn as_ref(&self) -> &[u8] {
628 self.0.as_ref()
629 }
630}
631
632impl From<TupleBuffer> for Vec<u8> {
633 #[inline(always)]
634 fn from(b: TupleBuffer) -> Self {
635 b.0
636 }
637}
638
639impl TryFrom<Vec<u8>> for TupleBuffer {
640 type Error = Error;
641
642 #[inline(always)]
643 fn try_from(data: Vec<u8>) -> Result<Self> {
644 Self::try_from_vec(data)
645 }
646}
647
648impl From<Tuple> for TupleBuffer {
649 #[inline(always)]
650 fn from(t: Tuple) -> Self {
651 Self(t.to_vec())
652 }
653}
654
655impl From<&Tuple> for TupleBuffer {
656 #[inline(always)]
657 fn from(t: &Tuple) -> Self {
658 Self(t.to_vec())
659 }
660}
661
662impl Debug for TupleBuffer {
663 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
664 if let Ok(v) = rmpv::Value::decode(&self.0) {
665 f.debug_tuple("TupleBuffer").field(&v).finish()
666 } else {
667 f.debug_tuple("TupleBuffer").field(&self.0).finish()
668 }
669 }
670}
671
672impl ToTupleBuffer for TupleBuffer {
673 #[inline(always)]
674 fn to_tuple_buffer(&self) -> Result<TupleBuffer> {
675 Ok(self.clone())
676 }
677
678 #[inline(always)]
679 fn tuple_data(&self) -> Option<&[u8]> {
680 Some(&self.0)
681 }
682
683 #[inline(always)]
684 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
685 w.write_all(self.as_ref()).map_err(Into::into)
686 }
687}
688
689impl serde_bytes::Serialize for TupleBuffer {
690 #[inline(always)]
691 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
692 where
693 S: serde::Serializer,
694 {
695 serde_bytes::Serialize::serialize(&self.0, serializer)
696 }
697}
698
699impl<'de> serde_bytes::Deserialize<'de> for TupleBuffer {
700 #[inline]
701 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
702 where
703 D: serde::Deserializer<'de>,
704 {
705 let tmp: Vec<u8> = serde_bytes::Deserialize::deserialize(deserializer)?;
706 Self::try_from(tmp).map_err(serde::de::Error::custom)
707 }
708}
709
710pub struct TupleFormat {
719 inner: *mut ffi::BoxTupleFormat,
722}
723
724impl TupleFormat {
725 #[inline(always)]
726 pub fn as_ptr(&self) -> *mut ffi::BoxTupleFormat {
727 self.inner
728 }
729}
730
731impl Default for TupleFormat {
732 #[inline(always)]
733 fn default() -> Self {
734 TupleFormat {
735 inner: unsafe { ffi::box_tuple_format_default() },
736 }
737 }
738}
739
740impl Drop for TupleFormat {
741 fn drop(&mut self) {
742 unsafe {
744 if self.inner != ffi::box_tuple_format_default() {
745 ffi::box_tuple_format_unref(self.inner)
746 }
747 }
748 }
749}
750
751impl Debug for TupleFormat {
752 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
753 if self.inner == Self::default().inner {
754 f.write_str("TupleFormat::default()")
755 } else {
756 f.debug_tuple("TupleFormat").field(&self.inner).finish()
757 }
758 }
759}
760
761pub struct TupleIterator {
767 inner: *mut ffi::BoxTupleIterator,
768}
769
770impl Debug for TupleIterator {
771 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
772 f.debug_struct("TupleIterator")
773 .field("position", &self.position())
774 .finish()
775 }
776}
777
778impl TupleIterator {
779 #[inline(always)]
786 pub fn position(&self) -> u32 {
787 unsafe { ffi::box_tuple_position(self.inner) }
788 }
789
790 #[inline(always)]
792 pub fn rewind(&mut self) {
793 unsafe { ffi::box_tuple_rewind(self.inner) }
794 }
795
796 #[inline]
806 pub fn seek<'t, T>(&'t mut self, fieldno: u32) -> Result<Option<T>>
807 where
808 T: Decode<'t>,
809 {
810 unsafe { field_value_from_ptr(ffi::box_tuple_seek(self.inner, fieldno) as _) }
811 }
812
813 #[allow(clippy::should_implement_trait)]
823 #[inline]
824 pub fn next<'t, T>(&'t mut self) -> Result<Option<T>>
825 where
826 T: Decode<'t>,
827 {
828 unsafe { field_value_from_ptr(ffi::box_tuple_next(self.inner) as _) }
829 }
830
831 pub fn update(&mut self) {}
832}
833
834impl Drop for TupleIterator {
835 #[inline(always)]
836 fn drop(&mut self) {
837 unsafe { ffi::box_tuple_iterator_free(self.inner) }
838 }
839}
840
841impl TupleIterator {}
842
843crate::define_str_enum! {
848 pub enum FieldType {
849 Any = "any",
850 Unsigned = "unsigned",
851 String = "string",
852 Number = "number",
853 Double = "double",
854 Integer = "integer",
855 Boolean = "boolean",
856 Varbinary = "varbinary",
857 Scalar = "scalar",
858 Decimal = "decimal",
859 Uuid = "uuid",
860 Datetime = "datetime",
861 Array = "array",
862 Map = "map",
863 }
864}
865
866impl Default for FieldType {
867 #[inline(always)]
868 fn default() -> Self {
869 Self::Any
870 }
871}
872
873impl From<index::FieldType> for FieldType {
874 #[rustfmt::skip]
875 fn from(t: index::FieldType) -> Self {
876 match t {
877 index::FieldType::Unsigned => Self::Unsigned,
880 index::FieldType::String => Self::String,
881 index::FieldType::Number => Self::Number,
882 index::FieldType::Double => Self::Double,
883 index::FieldType::Integer => Self::Integer,
884 index::FieldType::Boolean => Self::Boolean,
885 index::FieldType::Varbinary => Self::Varbinary,
886 index::FieldType::Scalar => Self::Scalar,
887 index::FieldType::Decimal => Self::Decimal,
888 index::FieldType::Uuid => Self::Uuid,
889 index::FieldType::Datetime => Self::Datetime,
890 index::FieldType::Array => Self::Array,
891 }
892 }
893}
894
895#[derive(Debug)]
922pub struct KeyDef {
923 inner: NonNull<ffi::BoxKeyDef>,
924}
925
926#[derive(Default, Debug, PartialEq, Eq, Hash)]
927pub struct KeyDefPart<'a> {
928 pub field_no: u32,
929 pub field_type: FieldType,
930 pub collation: Option<Cow<'a, CStr>>,
931 pub is_nullable: bool,
932 pub path: Option<Cow<'a, CStr>>,
933}
934
935impl<'a> KeyDefPart<'a> {
936 fn as_tt(&self) -> ffi::box_key_part_def_t {
937 let flags = if self.is_nullable {
938 ffi::BoxKeyDefPartFlag::IS_NULLABLE.bits()
939 } else {
940 0
941 };
942 ffi::box_key_part_def_t {
943 meat: ffi::BoxKeyDefPart {
944 fieldno: self.field_no,
945 field_type: self.field_type.as_cstr().as_ptr(),
946 flags,
947 collation: self
948 .collation
949 .as_deref()
950 .map(CStr::as_ptr)
951 .unwrap_or(null()),
952 path: self.path.as_deref().map(CStr::as_ptr).unwrap_or(null()),
953 },
954 }
955 }
956
957 pub fn from_index_part(p: &'a index::Part<u32>) -> Self {
958 let collation = p.collation.as_deref().map(|s| {
959 CString::new(s)
960 .expect("it's your fault if you put '\0' in collation")
961 .into()
962 });
963 let path = p.path.as_deref().map(|s| {
964 CString::new(s)
965 .expect("it's your fault if you put '\0' in collation")
966 .into()
967 });
968 Self {
969 field_no: p.field,
970 field_type: p.r#type.map(From::from).unwrap_or(FieldType::Any),
971 is_nullable: p.is_nullable.unwrap_or(false),
972 collation,
973 path,
974 }
975 }
976}
977
978impl KeyDef {
979 #[inline]
984 pub fn new<'a>(parts: impl IntoIterator<Item = &'a KeyDefPart<'a>>) -> Result<Self> {
985 let mut tt_parts = parts.into_iter().map(KeyDefPart::as_tt).collect::<Vec<_>>();
986 let ptr = unsafe { ffi::box_key_def_new_v2(tt_parts.as_mut_ptr(), tt_parts.len() as _) };
987 let inner = NonNull::new(ptr).ok_or_else(TarantoolError::last)?;
988 Ok(KeyDef { inner })
989 }
990
991 #[inline(always)]
1001 pub fn compare(&self, tuple_a: &Tuple, tuple_b: &Tuple) -> Ordering {
1002 unsafe {
1003 ffi::box_tuple_compare(
1004 tuple_a.ptr.as_ptr(),
1005 tuple_b.ptr.as_ptr(),
1006 self.inner.as_ptr(),
1007 )
1008 .cmp(&0)
1009 }
1010 }
1011
1012 #[inline]
1022 pub fn compare_with_key<K>(&self, tuple: &Tuple, key: &K) -> Ordering
1023 where
1024 K: ToTupleBuffer + ?Sized,
1025 {
1026 let key_buf = key.to_tuple_buffer().unwrap();
1027 let key_buf_ptr = key_buf.as_ptr() as _;
1028 unsafe {
1029 ffi::box_tuple_compare_with_key(tuple.ptr.as_ptr(), key_buf_ptr, self.inner.as_ptr())
1030 .cmp(&0)
1031 }
1032 }
1033
1034 #[inline]
1046 pub fn validate_tuple(&self, tuple: &Tuple) -> Result<()> {
1047 let rc =
1049 unsafe { ffi::box_key_def_validate_tuple(self.inner.as_ptr(), tuple.ptr.as_ptr()) };
1050 if rc != 0 {
1051 return Err(TarantoolError::last().into());
1052 }
1053 Ok(())
1054 }
1055
1056 #[inline]
1059 pub fn extract_key(&self, tuple: &Tuple) -> Result<TupleBuffer> {
1060 self.validate_tuple(tuple)?;
1061 let res;
1062 unsafe {
1065 let used_before = ffi::box_region_used();
1066 let data = self.extract_key_raw(tuple, -1)?;
1067 res = TupleBuffer::from_vec_unchecked(data.into());
1068 ffi::box_region_truncate(used_before);
1069 }
1070 Ok(res)
1071 }
1072
1073 #[inline]
1084 pub unsafe fn extract_key_raw<'box_region>(
1085 &self,
1086 tuple: &Tuple,
1087 multikey_idx: i32,
1088 ) -> Result<&'box_region [u8]> {
1089 let slice;
1090 unsafe {
1092 let mut size = 0;
1093 let data = ffi::box_key_def_extract_key(
1094 self.inner.as_ptr(),
1095 tuple.ptr.as_ptr(),
1096 multikey_idx,
1097 &mut size,
1098 );
1099 if data.is_null() {
1100 return Err(TarantoolError::last().into());
1101 }
1102 slice = std::slice::from_raw_parts(data as _, size as _);
1103 }
1104 Ok(slice)
1105 }
1106
1107 #[cfg(feature = "picodata")]
1116 pub fn hash(&self, tuple: &Tuple) -> u32 {
1117 unsafe { ffi::box_tuple_hash(tuple.ptr.as_ptr(), self.inner.as_ptr()) }
1118 }
1119}
1120
1121impl Drop for KeyDef {
1122 #[inline(always)]
1123 fn drop(&mut self) {
1124 unsafe { ffi::box_key_def_delete(self.inner.as_ptr()) }
1125 }
1126}
1127
1128impl From<&index::Metadata<'_>> for KeyDef {
1129 #[inline(always)]
1130 fn from(meta: &index::Metadata<'_>) -> Self {
1131 meta.to_key_def()
1132 }
1133}
1134
1135unsafe fn field_value_from_ptr<'de, T>(field_ptr: *mut u8) -> Result<Option<T>>
1136where
1137 T: Decode<'de>,
1138{
1139 if field_ptr.is_null() {
1140 return Ok(None);
1141 }
1142
1143 let max_len = u32::MAX >> 1;
1147 let rough_slice = std::slice::from_raw_parts(field_ptr, max_len as _);
1148 let mut cursor = std::io::Cursor::new(rough_slice);
1149 let start = cursor.position() as usize;
1150 crate::msgpack::skip_value(&mut cursor)?;
1153 let value_range = start..(cursor.position() as usize);
1154 let rough_slice = cursor.into_inner();
1155 let value_slice = &rough_slice[value_range];
1156 Ok(Some(T::decode(value_slice)?))
1157}
1158
1159#[repr(C)]
1164#[derive(Debug)]
1165pub struct FunctionCtx {
1166 inner: *mut ffi::BoxFunctionCtx,
1167}
1168
1169impl FunctionCtx {
1170 #[inline]
1176 pub fn return_tuple(&self, tuple: &Tuple) -> Result<c_int> {
1177 let result = unsafe { ffi::box_return_tuple(self.inner, tuple.ptr.as_ptr()) };
1178 if result < 0 {
1179 Err(TarantoolError::last().into())
1180 } else {
1181 Ok(result)
1182 }
1183 }
1184
1185 #[inline]
1194 pub fn return_mp<T>(&self, value: &T) -> Result<c_int>
1195 where
1196 T: Serialize + ?Sized,
1197 {
1198 let buf = rmp_serde::to_vec_named(value)?;
1199 self.return_bytes(&buf)
1200 }
1201
1202 #[inline]
1212 pub fn return_bytes(&self, bytes: &[u8]) -> Result<c_int> {
1213 let Range { start, end } = bytes.as_ptr_range();
1214 let result = unsafe { ffi::box_return_mp(self.inner, start as _, end as _) };
1215
1216 if result < 0 {
1217 Err(TarantoolError::last().into())
1218 } else {
1219 Ok(result)
1220 }
1221 }
1222
1223 #[cfg(feature = "picodata")]
1224 #[inline]
1225 pub fn mut_port_c(&mut self) -> &mut PortC {
1226 unsafe {
1227 let mut ctx = NonNull::new_unchecked(self.inner);
1228 NonNull::new_unchecked(ctx.as_mut().port)
1229 .as_mut()
1230 .as_mut_port_c()
1231 }
1232 }
1233}
1234
1235#[repr(C)]
1240pub struct FunctionArgs {
1241 pub start: *const u8,
1242 pub end: *const u8,
1243}
1244
1245impl Debug for FunctionArgs {
1246 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1247 f.debug_tuple("FunctionArgs")
1248 .field(&Tuple::from(self))
1249 .finish()
1250 }
1251}
1252
1253impl From<FunctionArgs> for Tuple {
1254 #[inline(always)]
1255 fn from(args: FunctionArgs) -> Tuple {
1256 Tuple::from(&args)
1257 }
1258}
1259
1260impl From<&FunctionArgs> for Tuple {
1261 #[inline(always)]
1262 fn from(args: &FunctionArgs) -> Tuple {
1263 unsafe { Tuple::from_raw_data(args.start as _, args.end.offset_from(args.start) as _) }
1264 }
1265}
1266
1267impl FunctionArgs {
1268 #[inline(always)]
1270 pub fn decode<'a, T>(&'a self) -> Result<T>
1271 where
1272 T: Decode<'a>,
1273 {
1274 let slice = unsafe {
1275 std::slice::from_raw_parts(self.start, self.end.offset_from(self.start) as _)
1276 };
1277 T::decode(slice)
1278 }
1279}
1280
1281#[inline]
1286pub fn session_push<T>(value: &T) -> Result<()>
1287where
1288 T: ToTupleBuffer + ?Sized,
1289{
1290 let buf = value.to_tuple_buffer().unwrap();
1291 let buf_ptr = buf.as_ptr() as *const c_char;
1292 if unsafe { ffi::box_session_push(buf_ptr, buf_ptr.add(buf.len())) } < 0 {
1293 Err(TarantoolError::last().into())
1294 } else {
1295 Ok(())
1296 }
1297}
1298
1299#[inline]
1300fn validate_msgpack<T>(data: T) -> Result<T>
1301where
1302 T: AsRef<[u8]> + Into<Vec<u8>>,
1303{
1304 let mut slice = data.as_ref();
1305 let m = rmp::decode::read_marker(&mut slice)?;
1306 if !matches!(m, Marker::FixArray(_) | Marker::Array16 | Marker::Array32) {
1307 return Err(error::EncodeError::InvalidMP(data.into()).into());
1308 }
1309 Ok(data)
1310}
1311
1312impl<L> tlua::Push<L> for Tuple
1313where
1314 L: tlua::AsLua,
1315{
1316 type Err = tlua::Void;
1317
1318 #[inline(always)]
1319 fn push_to_lua(&self, lua: L) -> tlua::PushResult<L, Self> {
1320 unsafe {
1321 ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
1322 Ok(tlua::PushGuard::new(lua, 1))
1323 }
1324 }
1325}
1326
1327impl<L> tlua::PushOne<L> for Tuple where L: tlua::AsLua {}
1328
1329impl<L> tlua::PushInto<L> for Tuple
1330where
1331 L: tlua::AsLua,
1332{
1333 type Err = tlua::Void;
1334
1335 #[inline(always)]
1336 fn push_into_lua(self, lua: L) -> tlua::PushResult<L, Self> {
1337 unsafe {
1338 ffi::luaT_pushtuple(tlua::AsLua::as_lua(&lua), self.ptr.as_ptr());
1339 Ok(tlua::PushGuard::new(lua, 1))
1340 }
1341 }
1342}
1343
1344impl<L> tlua::PushOneInto<L> for Tuple where L: tlua::AsLua {}
1345
1346impl<L> tlua::LuaRead<L> for Tuple
1347where
1348 L: tlua::AsLua,
1349{
1350 fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> tlua::ReadResult<Self, L> {
1351 let lua_ptr = tlua::AsLua::as_lua(&lua);
1352 let mut ptr = unsafe { ffi::luaT_istuple(lua_ptr, index.get()) };
1353 if ptr.is_null() {
1354 let format = TupleFormat::default();
1355 ptr = unsafe { ffi::luaT_tuple_new(lua_ptr, index.get(), format.inner) };
1356 }
1357 Self::try_from_ptr(ptr).ok_or_else(|| {
1358 let e = tlua::WrongType::info("reading tarantool tuple")
1359 .expected_type::<Self>()
1360 .actual_single_lua(&lua, index);
1361 (lua, e)
1362 })
1363 }
1364}
1365
1366impl<L> tlua::LuaRead<L> for TupleBuffer
1367where
1368 L: tlua::AsLua,
1369{
1370 fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> tlua::ReadResult<Self, L> {
1371 unsafe {
1372 let svp = ffi::box_region_used();
1373 let lua_ptr = tlua::AsLua::as_lua(&lua);
1374 let ptr = ffi::luaT_istuple(lua_ptr, index.get());
1375 if let Some(tuple) = Tuple::try_from_ptr(ptr) {
1376 return Ok(Self::from(tuple));
1377 }
1378 let mut len = 0;
1379 let data = ffi::luaT_tuple_encode(lua_ptr, index.get(), &mut len);
1380 if data.is_null() {
1381 let e = tlua::WrongType::info("converting Lua value to tarantool tuple")
1382 .expected("msgpack array")
1383 .actual(format!("error: {}", TarantoolError::last().message()));
1384 return Err((lua, e));
1385 }
1386 let data = std::slice::from_raw_parts(data, len);
1387 let data = Vec::from(data);
1388 ffi::box_region_truncate(svp);
1389 Ok(Self::from_vec_unchecked(data))
1390 }
1391 }
1392}
1393
1394pub trait Decode<'de>: Sized {
1403 fn decode(data: &'de [u8]) -> Result<Self>;
1404}
1405
1406impl<'de, T> Decode<'de> for T
1407where
1408 T: serde::Deserialize<'de>,
1409{
1410 #[inline(always)]
1411 fn decode(data: &'de [u8]) -> Result<Self> {
1412 rmp_serde::from_slice(data).map_err(|e| Error::decode::<T>(e, data.into()))
1413 }
1414}
1415
1416impl Decode<'_> for Tuple {
1417 #[inline(always)]
1418 fn decode(data: &[u8]) -> Result<Self> {
1419 Self::try_from_slice(data)
1420 }
1421}
1422
1423pub trait DecodeOwned: for<'de> Decode<'de> {}
1431impl<T> DecodeOwned for T where T: for<'de> Decode<'de> {}
1432
1433#[derive(Debug)]
1451#[repr(transparent)]
1452pub struct RawBytes(pub [u8]);
1453
1454impl RawBytes {
1455 #[inline(always)]
1457 pub fn new(data: &[u8]) -> &Self {
1458 unsafe { &*(data as *const [u8] as *const RawBytes) }
1460 }
1461}
1462
1463impl<'a> From<&'a [u8]> for &'a RawBytes {
1464 #[inline(always)]
1465 fn from(data: &'a [u8]) -> Self {
1466 RawBytes::new(data)
1467 }
1468}
1469
1470impl<'de> Decode<'de> for &'de RawBytes {
1471 #[inline(always)]
1472 fn decode(data: &'de [u8]) -> Result<Self> {
1473 Ok(RawBytes::new(data))
1475 }
1476}
1477
1478impl ToTupleBuffer for RawBytes {
1479 #[inline(always)]
1480 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
1481 let data = &**self;
1482 validate_msgpack(data)?;
1483 w.write_all(data).map_err(Into::into)
1484 }
1485
1486 #[inline(always)]
1487 fn tuple_data(&self) -> Option<&[u8]> {
1488 let data = &**self;
1489 validate_msgpack(data).ok()?;
1490 Some(data)
1491 }
1492}
1493
1494impl std::ops::Deref for RawBytes {
1495 type Target = [u8];
1496 #[inline(always)]
1497 fn deref(&self) -> &Self::Target {
1498 &self.0
1499 }
1500}
1501
1502impl std::borrow::ToOwned for RawBytes {
1503 type Owned = RawByteBuf;
1504 #[inline(always)]
1505 fn to_owned(&self) -> Self::Owned {
1506 self.0.to_vec().into()
1507 }
1508}
1509
1510#[derive(Debug, PartialEq, Eq, Clone)]
1523pub struct RawByteBuf(pub Vec<u8>);
1524
1525impl serde_bytes::Serialize for RawByteBuf {
1526 #[inline(always)]
1527 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1528 where
1529 S: serde::Serializer,
1530 {
1531 serde_bytes::Serialize::serialize(&self.0, serializer)
1532 }
1533}
1534
1535impl<'de> serde_bytes::Deserialize<'de> for RawByteBuf {
1536 #[inline(always)]
1537 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1538 where
1539 D: serde::Deserializer<'de>,
1540 {
1541 serde_bytes::Deserialize::deserialize(deserializer).map(Self)
1542 }
1543}
1544
1545impl From<Vec<u8>> for RawByteBuf {
1546 #[inline(always)]
1547 fn from(b: Vec<u8>) -> Self {
1548 Self(b)
1549 }
1550}
1551
1552impl Decode<'_> for RawByteBuf {
1553 #[inline(always)]
1554 fn decode(data: &[u8]) -> Result<Self> {
1555 Ok(Self(data.into()))
1557 }
1558}
1559
1560impl ToTupleBuffer for RawByteBuf {
1561 #[inline(always)]
1562 fn write_tuple_data(&self, w: &mut impl Write) -> Result<()> {
1563 let data = self.as_slice();
1564 validate_msgpack(data)?;
1565 w.write_all(data).map_err(Into::into)
1566 }
1567
1568 #[inline(always)]
1569 fn tuple_data(&self) -> Option<&[u8]> {
1570 let data = self.as_slice();
1571 validate_msgpack(data).ok()?;
1572 Some(data)
1573 }
1574}
1575
1576impl std::ops::Deref for RawByteBuf {
1577 type Target = Vec<u8>;
1578 #[inline(always)]
1579 fn deref(&self) -> &Self::Target {
1580 &self.0
1581 }
1582}
1583
1584impl std::ops::DerefMut for RawByteBuf {
1585 #[inline(always)]
1586 fn deref_mut(&mut self) -> &mut Self::Target {
1587 &mut self.0
1588 }
1589}
1590
1591impl std::borrow::Borrow<RawBytes> for RawByteBuf {
1592 #[inline(always)]
1593 fn borrow(&self) -> &RawBytes {
1594 RawBytes::new(self.0.as_slice())
1595 }
1596}
1597
1598#[cfg(feature = "picodata")]
1599mod picodata {
1600 use super::*;
1601 use crate::static_ref;
1602
1603 impl Tuple {
1608 #[deprecated = "did not find its use"]
1621 #[inline(always)]
1622 pub fn as_named_buffer(&self) -> Result<Vec<u8>> {
1623 crate::say_error!("Tuple::as_named_buffer is no longer supported");
1624 panic!("Tuple::as_named_buffer is no longer supported");
1625 }
1626
1627 #[inline]
1629 pub fn data(&self) -> &[u8] {
1630 unsafe {
1631 let tuple = self.ptr.as_ref();
1633 tuple.data()
1634 }
1635 }
1636 }
1637
1638 impl PartialEq for Tuple {
1639 #[inline]
1640 fn eq(&self, other: &Self) -> bool {
1641 if self.ptr == other.ptr {
1642 return true;
1643 }
1644
1645 if self.bsize() != other.bsize() {
1646 return false;
1647 }
1648
1649 self.data() == other.data()
1650 }
1651 }
1652
1653 impl serde_bytes::Serialize for Tuple {
1654 #[inline(always)]
1655 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1656 where
1657 S: serde::Serializer,
1658 {
1659 serde_bytes::Serialize::serialize(self.data(), serializer)
1660 }
1661 }
1662
1663 impl TupleFormat {
1668 #[inline]
1671 pub fn with_rust_allocator() -> &'static Self {
1672 static mut SINGLETON: Option<TupleFormat> = None;
1673
1674 if unsafe { static_ref!(mut SINGLETON) }.is_none() {
1676 unsafe {
1678 let inner = ffi::box_tuple_format_new(std::ptr::null_mut(), 0);
1679 (*inner).vtab.tuple_new = vtab_impl::tuple_new_rust_allocator;
1680 (*inner).vtab.tuple_delete = vtab_impl::tuple_delete_rust_allocator;
1681 SINGLETON = Some(Self { inner });
1682 }
1683 }
1684
1685 unsafe { static_ref!(const SINGLETON) }
1686 .as_ref()
1687 .expect("just made sure it's there")
1688 }
1689
1690 #[deprecated = "did not find its use"]
1697 pub fn name_count(&self) -> u32 {
1698 crate::say_error!("TupleFormat::name_count is no longer supported");
1699 panic!("TupleFormat::name_count is no longer supported");
1700 }
1701
1702 #[deprecated = "did not find its use"]
1709 pub fn names(&self) -> impl Iterator<Item = &str> {
1710 crate::say_error!("TupleFormat::names is no longer supported");
1711 (|| panic!("TupleFormat::names is no longer supported"))();
1716 Vec::new().into_iter()
1718 }
1719 }
1720}
1721
1722#[cfg(feature = "picodata")]
1727pub struct TupleBuilder {
1728 is_rust_allocated: bool,
1732 buffer: Vec<u8>,
1733}
1734
1735#[cfg(feature = "picodata")]
1736impl TupleBuilder {
1737 const TUPLE_HEADER_PADDING: &'static [u8] = &[0; std::mem::size_of::<ffi::BoxTuple>()];
1738
1739 #[inline(always)]
1744 pub fn rust_allocated() -> Self {
1745 Self {
1746 is_rust_allocated: true,
1747 buffer: Vec::new(),
1748 }
1749 }
1750
1751 #[inline(always)]
1752 pub fn buffer(&self) -> &[u8] {
1753 &self.buffer
1754 }
1755
1756 #[inline]
1760 pub fn reserve(&mut self, mut capacity: usize) {
1761 if self.is_rust_allocated && self.buffer.capacity() == 0 {
1762 capacity += std::mem::size_of::<ffi::BoxTuple>();
1763 }
1764 self.buffer.reserve(capacity);
1765 }
1766
1767 #[inline]
1768 pub fn append(&mut self, data: &[u8]) {
1769 if self.is_rust_allocated && self.buffer.is_empty() {
1770 if self.buffer.capacity() == 0 {
1771 self.buffer
1772 .reserve(Self::TUPLE_HEADER_PADDING.len() + data.len());
1773 }
1774 self.buffer.extend_from_slice(Self::TUPLE_HEADER_PADDING);
1775 }
1776 self.buffer.extend_from_slice(data);
1777 }
1778
1779 #[inline]
1780 pub fn into_tuple(self) -> Result<Tuple> {
1781 if self.is_rust_allocated {
1782 self.into_tuple_rust_allocated()
1783 } else {
1784 Tuple::try_from_slice(&self.buffer)
1785 }
1786 }
1787
1788 fn into_tuple_rust_allocated(self) -> Result<Tuple> {
1789 use crate::error::BoxError;
1790 use crate::error::TarantoolErrorCode;
1791
1792 if self.buffer.is_empty() {
1793 #[rustfmt::skip]
1794 return Err(BoxError::new(TarantoolErrorCode::IllegalParams, "cannot construct an empty tuple").into());
1795 }
1796
1797 if self.buffer.len() < Self::TUPLE_HEADER_PADDING.len() {
1798 #[rustfmt::skip]
1799 return Err(BoxError::new(TarantoolErrorCode::IllegalParams, "buffer is corrupted").into());
1800 }
1801
1802 let mut tuple_chunk = self.buffer;
1803 let data_offset = Self::TUPLE_HEADER_PADDING.len();
1804 let data_len = tuple_chunk.len() - data_offset;
1805 validate_msgpack(&tuple_chunk[data_offset..])?;
1806
1807 let format = TupleFormat::with_rust_allocator();
1808
1809 let tuple = tuple_chunk.as_mut_ptr().cast::<ffi::BoxTuple>();
1810 unsafe {
1811 std::ptr::write(
1812 tuple,
1813 ffi::BoxTuple {
1815 refs: 0,
1816 flags: 0,
1817 format_id: (*format.inner).id,
1818 data_offset: data_offset as _,
1819 bsize: data_len as _,
1820 },
1821 );
1822 }
1823 unsafe {
1825 ffi::box_tuple_format_ref(format.inner);
1826 }
1827
1828 _ = Box::into_raw(tuple_chunk.into_boxed_slice());
1830
1831 let tuple = unsafe { NonNull::new_unchecked(tuple) };
1833 let tuple = Tuple::from_ptr(tuple);
1834 return Ok(tuple);
1835 }
1836}
1837
1838#[cfg(feature = "picodata")]
1839impl std::io::Write for TupleBuilder {
1840 #[inline(always)]
1841 fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
1842 self.append(data);
1843 Ok(data.len())
1844 }
1845
1846 #[inline(always)]
1847 fn flush(&mut self) -> std::io::Result<()> {
1848 Ok(())
1849 }
1850}
1851
1852#[cfg(feature = "picodata")]
1857mod vtab_impl {
1858 use super::*;
1859
1860 pub unsafe extern "C" fn tuple_new_rust_allocator(
1862 format: *mut ffi::BoxTupleFormat,
1863 data: *const u8,
1864 end: *const u8,
1865 ) -> *mut ffi::BoxTuple {
1866 const TUPLE_HEADER_SIZE: usize = std::mem::size_of::<ffi::BoxTuple>();
1867 let data_offset = TUPLE_HEADER_SIZE;
1868 let data_len = end.offset_from(data);
1871 debug_assert!(data_len >= 0);
1872 let data_len = data_len as usize;
1873 debug_assert!(data_len <= u32::MAX as usize);
1874
1875 let total_size = data_offset + data_len;
1877 let mut tuple_chunk: Vec<u8> = Vec::with_capacity(total_size);
1878
1879 let tuple = tuple_chunk.as_mut_ptr().cast::<ffi::BoxTuple>();
1880 std::ptr::write(
1881 tuple,
1882 ffi::BoxTuple {
1884 refs: 0,
1885 flags: 0,
1886 format_id: (*format).id,
1887 data_offset: data_offset as _,
1888 bsize: data_len as _,
1889 },
1890 );
1891 ffi::box_tuple_format_ref(format);
1892
1893 let data_slice = std::slice::from_raw_parts(data, data_len);
1894 tuple_chunk.set_len(total_size);
1895 let tuple_data = &mut tuple_chunk[data_offset..];
1896 debug_assert_eq!(data_slice.len(), tuple_data.len());
1897 tuple_data.copy_from_slice(data_slice);
1898
1899 let tuple_chunk: Box<[u8]> = tuple_chunk.into_boxed_slice();
1901 _ = Box::into_raw(tuple_chunk);
1902
1903 return tuple;
1904 }
1905
1906 pub unsafe extern "C" fn tuple_delete_rust_allocator(
1908 format: *mut ffi::BoxTupleFormat,
1909 tuple: *mut ffi::BoxTuple,
1910 ) {
1911 debug_assert!(tuple != 0 as _);
1912 debug_assert_eq!((*tuple).refs, 0);
1913 const FLAG_TUPLE_HAS_UPLOADED_REFS: u8 = 1 << 0;
1914 debug_assert_eq!(((*tuple).flags & FLAG_TUPLE_HAS_UPLOADED_REFS), 0);
1915
1916 ffi::box_tuple_format_unref(format);
1917
1918 let total_size = (*tuple).data_offset() as usize + (*tuple).bsize();
1919
1920 let tuple_chunk_start = tuple.cast::<u8>();
1921 let tuple_chunk_slice = std::slice::from_raw_parts_mut(tuple_chunk_start, total_size);
1922 let tuple_chunk: Box<[u8]> = Box::from_raw(tuple_chunk_slice);
1924 drop(tuple_chunk);
1925 }
1926}
1927
1928#[cfg(feature = "internal_test")]
1929mod test {
1930 #![allow(clippy::redundant_clone)]
1931 use super::*;
1932 use crate::space;
1933 use crate::space::Space;
1934 use pretty_assertions::assert_eq;
1935
1936 #[crate::test(tarantool = "crate")]
1937 fn tuple_buffer_from_lua() {
1938 let svp = unsafe { ffi::box_region_used() };
1939
1940 let lua = crate::lua_state();
1941 let t: TupleBuffer = lua
1942 .eval("return { 3, 'foo', { true, box.NIL, false } }")
1943 .unwrap();
1944
1945 #[derive(::serde::Deserialize, PartialEq, Eq, Debug)]
1946 struct S {
1947 i: i32,
1948 s: String,
1949 t: [Option<bool>; 3],
1950 }
1951
1952 let s = S::decode(t.as_ref()).unwrap();
1953 assert_eq!(
1954 s,
1955 S {
1956 i: 3,
1957 s: "foo".into(),
1958 t: [Some(true), None, Some(false)]
1959 }
1960 );
1961
1962 let res = lua.eval::<TupleBuffer>("return 1, 2, 3");
1963 assert_eq!(
1964 res.unwrap_err().to_string(),
1965 "failed converting Lua value to tarantool tuple: msgpack array expected, got error: A tuple or a table expected, got number
1966 while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got (number, number, number)"
1967 );
1968
1969 let res = lua.eval::<TupleBuffer>("return { 1, 2, foo = 'bar' }");
1970 assert_eq!(
1971 res.unwrap_err().to_string(),
1972 "failed converting Lua value to tarantool tuple: msgpack array expected, got error: Tuple/Key must be MsgPack array
1973 while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got table"
1974 );
1975
1976 let res = lua.eval::<TupleBuffer>(
1977 "ffi = require 'ffi';
1978 local cdata = ffi.new('struct { int x; int y; }', { x = -1, y = 2 })
1979 return { 1, cdata }",
1980 );
1981 assert_eq!(
1982 res.unwrap_err().to_string(),
1983 "failed converting Lua value to tarantool tuple: msgpack array expected, got error: unsupported Lua type 'cdata'
1984 while reading value(s) returned by Lua: tarantool::tuple::TupleBuffer expected, got table"
1985 );
1986
1987 assert_eq!(svp, unsafe { ffi::box_region_used() });
1988 }
1989
1990 #[crate::test(tarantool = "crate")]
1991 fn decode_error() {
1992 use super::*;
1993
1994 let buf = (1, 2, 3).to_tuple_buffer().unwrap();
1995 let err = <(String, String)>::decode(buf.as_ref()).unwrap_err();
1996 assert_eq!(
1997 err.to_string(),
1998 r#"failed to decode tuple: invalid type: integer `1`, expected a string when decoding msgpack b"\x93\x01\x02\x03" into rust type (alloc::string::String, alloc::string::String)"#
1999 );
2000
2001 let buf = ("hello", [1, 2, 3], "goodbye").to_tuple_buffer().unwrap();
2002 let err = <(String, (i32, String, i32), String)>::decode(buf.as_ref()).unwrap_err();
2003 assert_eq!(
2004 err.to_string(),
2005 r#"failed to decode tuple: invalid type: integer `2`, expected a string when decoding msgpack b"\x93\xa5hello\x93\x01\x02\x03\xa7goodbye" into rust type (alloc::string::String, (i32, alloc::string::String, i32), alloc::string::String)"#
2006 )
2007 }
2008
2009 #[crate::test(tarantool = "crate")]
2010 fn key_def_extract_key() {
2011 let space = Space::builder(&crate::temp_space_name!())
2012 .field(("id", space::FieldType::Unsigned))
2013 .field(("not-key", space::FieldType::Array))
2014 .field(("s", space::FieldType::String))
2015 .field(("nested", space::FieldType::Any))
2016 .create()
2017 .unwrap();
2018
2019 let index = space
2020 .index_builder("pk")
2021 .part("id")
2022 .part("s")
2023 .part(
2024 index::Part::<String>::field("nested")
2025 .field_type(index::FieldType::Unsigned)
2026 .path("[2].blabla"),
2027 )
2028 .create()
2029 .unwrap();
2030
2031 let key_def = index.meta().unwrap().to_key_def();
2032
2033 let tuple = Tuple::new(&["foo"]).unwrap();
2034 let e = key_def.extract_key(&tuple).unwrap_err();
2035 assert_eq!(e.to_string(), "box error: KeyPartType: Supplied key type of part 0 does not match index part type: expected unsigned");
2036
2037 let tuple = Tuple::new(&[1]).unwrap();
2038 let e = key_def.extract_key(&tuple).unwrap_err();
2039 assert_eq!(
2043 e.to_string(),
2044 "box error: FieldMissing: Tuple field [3] required by space format is missing"
2045 );
2046
2047 let tuple = Tuple::new(&(1, [1, 2, 3], "foo")).unwrap();
2048 let e = key_def.extract_key(&tuple).unwrap_err();
2049 assert_eq!(
2050 e.to_string(),
2051 "box error: FieldMissing: Tuple field [4][2].blabla required by space format is missing"
2052 );
2053
2054 let raw_data = b"\x94\x69\x93\x01\x02\x03\xa3foo\x93\xc0\x81\xa6blabla\x42\x07"; let tuple = Tuple::new(RawBytes::new(raw_data)).unwrap();
2056 let key = key_def.extract_key(&tuple).unwrap();
2057 assert_eq!(key.as_ref(), b"\x93\x69\xa3foo\x42"); let raw_data = b"\x94\x13\xa9not-array\xa3bar\x92\xc0\x81\xa6blabla\x37"; let tuple = Tuple::new(RawBytes::new(raw_data)).unwrap();
2065 let key = key_def.extract_key(&tuple).unwrap();
2066 assert_eq!(key.as_ref(), b"\x93\x13\xa3bar\x37");
2067
2068 let e = space.insert(&tuple).unwrap_err();
2070 assert_eq!(e.to_string(), "box error: FieldType: Tuple field 2 (not-key) type does not match one required by operation: expected array, got string");
2071 }
2072
2073 #[cfg(feature = "picodata")]
2074 #[crate::test(tarantool = "crate")]
2075 fn tuple_data() {
2076 let tuple = Tuple::new(&(69, "nice", [3, 2, 1])).unwrap();
2078 assert_eq!(tuple.data(), b"\x93\x45\xa4nice\x93\x03\x02\x01");
2083
2084 let space = Space::builder(&crate::temp_space_name!())
2086 .field(("id", space::FieldType::Unsigned))
2087 .field(("name", space::FieldType::String))
2088 .create()
2089 .unwrap();
2090
2091 space.index_builder("pk").create().unwrap();
2092
2093 let tuple = space.insert(&(13, "37")).unwrap();
2094 assert_eq!(tuple.data(), b"\x92\x0d\xa237");
2095 }
2096
2097 #[cfg(feature = "picodata")]
2098 #[crate::test(tarantool = "crate")]
2099 fn compare_tuples() {
2100 let data = b"\x92\xa3foo\xa3bar";
2103 let tuple_1 = Tuple::try_from_slice(data).unwrap();
2104
2105 let tuple_1_clone = tuple_1.clone();
2107 assert_eq!(tuple_1_clone.as_ptr(), tuple_1.as_ptr());
2108 assert_eq!(tuple_1_clone, tuple_1);
2109
2110 let tuple_1_equivalent = Tuple::try_from_slice(data).unwrap();
2112 assert_ne!(tuple_1_equivalent.as_ptr(), tuple_1.as_ptr());
2113 assert_eq!(tuple_1_equivalent, tuple_1);
2114
2115 let other_data = b"\x93\x10\x20\x30";
2119 let tuple_2 = Tuple::try_from_slice(other_data).unwrap();
2120 assert_ne!(data.len(), other_data.len());
2121 assert_ne!(tuple_1, tuple_2);
2122
2123 let other_data_same_len = b"\x92\xa3foo\xa3baz";
2127 assert_eq!(data.len(), other_data_same_len.len());
2128 let tuple_3 = Tuple::try_from_slice(other_data_same_len).unwrap();
2129 assert_ne!(tuple_2, tuple_3);
2130 }
2131
2132 #[cfg(feature = "picodata")]
2133 #[crate::test(tarantool = "crate")]
2134 fn serialize_deserialize() {
2135 #[derive(Debug, serde::Serialize, serde::Deserialize)]
2136 struct Wrapper {
2137 #[serde(with = "serde_bytes")]
2138 tuple: Tuple,
2139 }
2140
2141 let data = rmp_serde::to_vec_named(&Wrapper {
2143 tuple: Tuple::new(&(0x77, "hello", 0x77)).unwrap(),
2144 })
2145 .unwrap();
2146 assert_eq!(&data, b"\x81\xa5tuple\xc4\x09\x93\x77\xa5hello\x77");
2151
2152 let data = b"\x81\xa5tuple\xc4\x0c\x94\xa7numbers\x03\x01\x04";
2155 let w: Wrapper = rmp_serde::from_slice(data).unwrap();
2156 let s: &str = w.tuple.field(0).unwrap().unwrap();
2157 assert_eq!(s, "numbers");
2158 let n: i32 = w.tuple.field(1).unwrap().unwrap();
2159 assert_eq!(n, 3);
2160 let n: i32 = w.tuple.field(2).unwrap().unwrap();
2161 assert_eq!(n, 1);
2162 let n: i32 = w.tuple.field(3).unwrap().unwrap();
2163 assert_eq!(n, 4);
2164
2165 let data = b"\x81\xa5tuple\xc4\x01\x45";
2167 let e = rmp_serde::from_slice::<Wrapper>(data).unwrap_err();
2168 assert_eq!(e.to_string(), "failed to encode tuple: invalid msgpack value (expected array, found Integer(PosInt(69)))");
2169 }
2170
2171 #[cfg(feature = "picodata")]
2172 #[crate::test(tarantool = "crate")]
2173 fn rust_allocated_tuples() {
2174 let mut builder = TupleBuilder::rust_allocated();
2175 builder.append(b"\x91");
2177 builder.append(b"\xc4\x10");
2179 builder.append(b"0123456789abcdef");
2180 let tuple = builder.into_tuple().unwrap();
2181
2182 assert_eq!(tuple.len(), 1);
2184 assert_eq!(tuple.bsize(), 19);
2185 assert_eq!(tuple.data(), b"\x91\xc4\x100123456789abcdef");
2186 assert_eq!(tuple.to_vec(), b"\x91\xc4\x100123456789abcdef");
2187
2188 let (value,): (serde_bytes::ByteBuf,) = tuple.decode().unwrap();
2189 assert_eq!(value, b"0123456789abcdef");
2190
2191 let value: &serde_bytes::Bytes = tuple.field(0).unwrap().unwrap();
2192 assert_eq!(value, b"0123456789abcdef");
2193
2194 let mut iter = tuple.iter().unwrap();
2195 let value: &serde_bytes::Bytes = iter.next().unwrap().unwrap();
2196 assert_eq!(value, b"0123456789abcdef");
2197 assert_eq!(iter.next::<()>().unwrap(), None);
2198
2199 #[rustfmt::skip]
2200 assert_eq!(tuple.format().as_ptr(), TupleFormat::with_rust_allocator().as_ptr());
2201
2202 let mut builder = TupleBuilder::rust_allocated();
2204 builder.append(b"\xa1!");
2206 let e = builder.into_tuple().unwrap_err();
2207 assert_eq!(e.to_string(), "failed to encode tuple: invalid msgpack value (expected array, found String(Utf8String { s: Ok(\"!\") }))");
2208
2209 let mut builder = TupleBuilder::rust_allocated();
2211 builder.reserve(4);
2212 builder.append(b"\x93");
2213 builder.append(b"\x01");
2214 builder.append(b"\x02");
2215 builder.append(b"\x03");
2216 let tuple = builder.into_tuple().unwrap();
2217 let value: (i32, i32, i32) = tuple.decode().unwrap();
2218 assert_eq!(value, (1, 2, 3));
2219
2220 let mut builder = TupleBuilder::rust_allocated();
2222 builder.reserve(0);
2223 builder.append(b"\x91");
2224 builder.append(b"\xa5");
2225 builder.append(b"hell");
2226 builder.append(b"o");
2227 let tuple = builder.into_tuple().unwrap();
2228 let (value,): (String,) = tuple.decode().unwrap();
2229 assert_eq!(value, "hello");
2230
2231 let mut builder = TupleBuilder::rust_allocated();
2233 rmp_serde::encode::write(&mut builder, &(1, "two", 3.14)).unwrap();
2234 let tuple = builder.into_tuple().unwrap();
2235 let value: (i32, String, f32) = tuple.decode().unwrap();
2236 assert_eq!(value, (1, "two".to_owned(), 3.14));
2237 }
2238
2239 #[cfg(feature = "picodata")]
2240 #[crate::test(tarantool = "crate")]
2241 fn tuple_format_no_use_after_free() {
2242 let mut builder = TupleBuilder::rust_allocated();
2243 builder.append(b"\x90");
2245 let tuple = builder.into_tuple().unwrap();
2246
2247 let original_ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2248 assert!(original_ref_count > 0);
2249
2250 let f1 = tuple.format();
2251
2252 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2257 assert_eq!(ref_count, original_ref_count + 1);
2258
2259 let f2 = tuple.format();
2260
2261 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2262 assert_eq!(ref_count, original_ref_count + 2);
2263
2264 drop(f1);
2265
2266 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2267 assert_eq!(ref_count, original_ref_count + 1);
2268
2269 drop(f2);
2270
2271 let ref_count = unsafe { (*TupleFormat::with_rust_allocator().as_ptr()).refs };
2272 assert_eq!(ref_count, original_ref_count);
2273 }
2274}