use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::Hash;
use std::io::{Read, Write};
use std::ops::Deref;
pub use tarantool_proc::{Decode, Encode};
use rmp::decode::{NumValueReadError, ValueReadError};
#[inline(always)]
pub fn encode(value: &impl Encode) -> Vec<u8> {
let mut v = Vec::with_capacity(128);
value
.encode(&mut v, &Context::DEFAULT)
.expect("encoding to vector should not fail");
v
}
#[inline(always)]
pub fn decode<'de, T: Decode<'de>>(mut bytes: &'de [u8]) -> Result<T, DecodeError> {
T::decode(&mut bytes, &Context::DEFAULT)
}
#[inline(always)]
pub fn decode_from_read<'de, T: Decode<'de>>(
bytes: &mut &'de [u8],
context: &Context,
) -> Result<T, DecodeError> {
T::decode(bytes, context)
}
pub struct Context {
struct_style: StructStyle,
}
impl Context {
pub const DEFAULT: Self = Self {
struct_style: StructStyle::Default,
};
}
impl Default for Context {
#[inline(always)]
fn default() -> Self {
Self::DEFAULT
}
}
impl Context {
#[inline(always)]
pub const fn with_struct_style(mut self, struct_style: StructStyle) -> Self {
self.struct_style = struct_style;
self
}
#[inline(always)]
pub fn struct_style(&self) -> StructStyle {
self.struct_style
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StructStyle {
#[default]
Default,
ForceAsMap,
ForceAsArray,
}
#[derive(Clone)]
pub struct ExtStruct<'a> {
pub tag: i8,
pub data: &'a [u8],
}
impl<'a> ExtStruct<'a> {
#[inline(always)]
pub fn new(tag: i8, data: &'a [u8]) -> Self {
Self { tag, data }
}
}
pub trait Decode<'de>: Sized {
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecodeError {
ty: &'static str,
pub part: Option<String>,
source: String,
}
impl Display for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "failed decoding {}", self.ty)?;
if let Some(ref part) = self.part {
write!(f, " ({part})")?;
}
write!(f, ": {}", self.source)
}
}
impl std::error::Error for DecodeError {}
impl DecodeError {
#[inline(always)]
pub fn new<DecodedTy>(source: impl ToString) -> Self {
Self {
ty: std::any::type_name::<DecodedTy>(),
source: source.to_string(),
part: None,
}
}
#[inline(always)]
pub fn with_part(mut self, part: impl ToString) -> Self {
self.part = Some(part.to_string());
self
}
#[inline(always)]
pub fn from_vre<DecodedTy>(value: ValueReadError) -> Self {
match value {
ValueReadError::TypeMismatch(marker) => {
let message = format!("got {marker:?}");
Self::new::<DecodedTy>(value).with_part(message)
}
err @ ValueReadError::InvalidDataRead(_)
| err @ ValueReadError::InvalidMarkerRead(_) => Self::new::<DecodedTy>(err),
}
}
#[inline(always)]
pub fn from_vre_with_field<DecodedTy>(value: ValueReadError, field: impl ToString) -> Self {
match value {
ValueReadError::TypeMismatch(marker) => {
let message = format!("got {marker:?} in field {}", field.to_string());
Self::new::<DecodedTy>(value).with_part(message)
}
err @ ValueReadError::InvalidDataRead(_)
| err @ ValueReadError::InvalidMarkerRead(_) => Self::new::<DecodedTy>(err),
}
}
#[inline(always)]
pub fn from_nvre<DecodedTy>(value: NumValueReadError) -> Self {
match value {
NumValueReadError::TypeMismatch(marker) => {
let message = format!("got {marker:?}");
Self::new::<DecodedTy>(value).with_part(message)
}
err @ NumValueReadError::InvalidDataRead(_)
| err @ NumValueReadError::InvalidMarkerRead(_)
| err @ NumValueReadError::OutOfRange => Self::new::<DecodedTy>(err),
}
}
}
impl<'de> Decode<'de> for () {
#[inline(always)]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
rmp::decode::read_nil(r).map_err(DecodeError::from_vre::<Self>)?;
Ok(())
}
}
impl<'de, T> Decode<'de> for Box<T>
where
T: Decode<'de>,
{
#[inline(always)]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
T::decode(r, context).map(Box::new)
}
}
impl<'de, T> Decode<'de> for std::rc::Rc<T>
where
T: Decode<'de>,
{
#[inline(always)]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
T::decode(r, context).map(std::rc::Rc::new)
}
}
impl<'de, T> Decode<'de> for Option<T>
where
T: Decode<'de>,
{
#[inline(always)]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
if !r.is_empty() && r[0] == super::MARKER_NULL {
rmp::decode::read_nil(r).map_err(DecodeError::from_vre::<Self>)?;
Ok(None)
} else {
T::decode(r, context).map(Some)
}
}
}
impl<'de, T> Decode<'de> for Vec<T>
where
T: Decode<'de>,
{
#[inline]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_array_len(r).map_err(DecodeError::from_vre::<Self>)? as usize;
let mut res = Vec::with_capacity(n);
for i in 0..n {
res.push(
T::decode(r, context).map_err(|err| {
DecodeError::new::<Self>(err).with_part(format!("element {i}"))
})?,
);
}
Ok(res)
}
}
impl<'de, T> Decode<'de> for HashSet<T>
where
T: Decode<'de> + Hash + Eq,
{
#[inline]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_array_len(r).map_err(DecodeError::from_vre::<Self>)? as usize;
let mut res = HashSet::with_capacity(n);
for i in 0..n {
let v = T::decode(r, context)
.map_err(|err| DecodeError::new::<Self>(err).with_part(format!("element {i}")))?;
res.insert(v);
}
Ok(res)
}
}
impl<'de, T> Decode<'de> for BTreeSet<T>
where
T: Decode<'de> + Ord + Eq,
{
#[inline]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_array_len(r).map_err(DecodeError::from_vre::<Self>)? as usize;
let mut res = BTreeSet::new();
for i in 0..n {
let v = T::decode(r, context)
.map_err(|err| DecodeError::new::<Self>(err).with_part(format!("element {i}")))?;
res.insert(v);
}
Ok(res)
}
}
impl<'de, T, const N: usize> Decode<'de> for [T; N]
where
T: Decode<'de>,
{
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_array_len(r).map_err(DecodeError::from_vre::<Self>)? as usize;
if n != N {
return Err(DecodeError::new::<Self>(format!(
"expected array count {N}, got {n}"
)));
}
let mut res = std::mem::MaybeUninit::uninit();
let ptr = &mut res as *mut _ as *mut [T; N] as *mut T;
let mut num_assigned = 0;
for i in 0..N {
match T::decode(r, context) {
Ok(v) => {
unsafe { std::ptr::write(ptr.add(i), v) }
num_assigned += 1;
}
Err(e) => {
for i in 0..num_assigned {
unsafe { std::ptr::drop_in_place(ptr.add(i)) }
}
return Err(DecodeError::new::<Self>(e).with_part(format!("element {i}")));
}
}
}
debug_assert_eq!(num_assigned, N);
return Ok(unsafe { res.assume_init() });
}
}
impl<'de, T> Decode<'de> for Cow<'_, T>
where
T: Decode<'de> + ToOwned,
{
#[allow(clippy::redundant_clone)]
#[inline(always)]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
Ok(Cow::Owned(
<T as Decode>::decode(r, context)
.map_err(DecodeError::new::<Self>)?
.to_owned(),
))
}
}
impl<'de> Decode<'de> for String {
#[inline]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_str_len(r).map_err(DecodeError::from_vre::<Self>)? as usize;
let mut buf = vec![0; n];
r.read_exact(&mut buf).map_err(DecodeError::new::<Self>)?;
String::from_utf8(buf).map_err(DecodeError::new::<Self>)
}
}
impl<'de> Decode<'de> for &'de str {
#[inline]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
let (res, bound) =
rmp::decode::read_str_from_slice(*r).map_err(DecodeError::new::<Self>)?;
*r = bound;
Ok(res)
}
}
impl<'de, K, V> Decode<'de> for BTreeMap<K, V>
where
K: Decode<'de> + Ord,
V: Decode<'de>,
{
#[inline]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_map_len(r).map_err(DecodeError::new::<Self>)?;
let mut res = BTreeMap::new();
for i in 0..n {
let k = K::decode(r, context)
.map_err(|err| DecodeError::new::<Self>(err).with_part(format!("{i}th key")))?;
let v = V::decode(r, context)
.map_err(|err| DecodeError::new::<Self>(err).with_part(format!("{i}th value")))?;
res.insert(k, v);
}
Ok(res)
}
}
impl<'de, K, V> Decode<'de> for HashMap<K, V>
where
K: Decode<'de> + Ord + Hash,
V: Decode<'de>,
{
#[inline]
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_map_len(r).map_err(DecodeError::from_vre::<Self>)?;
let mut res = HashMap::with_capacity(n as _);
for i in 0..n {
let k = K::decode(r, context)
.map_err(|err| DecodeError::new::<Self>(err).with_part(format!("{i}th key")))?;
let v = V::decode(r, context)
.map_err(|err| DecodeError::new::<Self>(err).with_part(format!("{i}th value")))?;
res.insert(k, v);
}
Ok(res)
}
}
impl<'de> Decode<'de> for char {
#[inline(always)]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
let n = rmp::decode::read_str_len(r).map_err(DecodeError::from_vre::<Self>)? as usize;
if n == 0 {
return Err(DecodeError::new::<char>(
"expected a msgpack non-empty string, got string length 0",
));
}
if n > 4 {
return Err(DecodeError::new::<char>(format!(
"expected a msgpack string not longer than 4 characters, got length {n}"
)));
}
let mut buf = [0; 4];
let buf = &mut buf[0..n];
r.read_exact(buf).map_err(DecodeError::new::<Self>)?;
let s = std::str::from_utf8(buf).map_err(DecodeError::new::<Self>)?;
if s.chars().count() != 1 {
return Err(DecodeError::new::<char>(format!(
"expected a single unicode character, got sequence of length {n}"
)));
} else {
Ok(s.chars()
.next()
.expect("just checked that there is 1 element"))
}
}
}
macro_rules! impl_simple_int_decode {
($(($t:ty, $f:tt))+) => {
$(
impl<'de> Decode<'de> for $t{
#[inline(always)]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
let value = rmp::decode::$f(r)
.map_err(DecodeError::from_nvre::<Self>)?;
Ok(value)
}
}
)+
}
}
macro_rules! impl_simple_decode {
($(($t:ty, $f:tt))+) => {
$(
impl<'de> Decode<'de> for $t{
#[inline(always)]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
let value = rmp::decode::$f(r)
.map_err(DecodeError::from_vre::<Self>)?;
Ok(value)
}
}
)+
}
}
impl_simple_int_decode! {
(u8, read_int)
(u16, read_int)
(u32, read_int)
(u64, read_int)
(usize, read_int)
(i8, read_int)
(i16, read_int)
(i32, read_int)
(i64, read_int)
(isize, read_int)
}
impl_simple_decode! {
(f32, read_f32)
(f64, read_f64)
(bool, read_bool)
}
macro_rules! impl_tuple_decode {
() => {};
($h:ident $($t:ident)*) => {
#[allow(non_snake_case)]
impl<'de, $h, $($t),*> Decode<'de> for ($h, $($t),*)
where
$h: Decode<'de>,
$($t: Decode<'de>,)*
{
fn decode(r: &mut &'de [u8], context: &Context) -> Result<Self, DecodeError> {
let array_len = rmp::decode::read_array_len(r)
.map_err(DecodeError::from_vre::<Self>)?;
let expected_len = crate::expr_count!($h $(, $t)*);
if array_len != expected_len {
return Err(DecodeError::new::<Self>(format!(
"Tuple length mismatch: expected: {}; actual: {}",
expected_len, array_len
)));
}
let $h : $h = Decode::decode(r, context)?;
$(
let $t : $t = Decode::decode(r, context)?;
)*
Ok(($h, $($t),*))
}
}
impl_tuple_decode! { $($t)* }
}
}
impl_tuple_decode! { A B C D E F G H I J K L M N O P }
impl<'de> Decode<'de> for ExtStruct<'de> {
#[inline]
fn decode(r: &mut &'de [u8], _context: &Context) -> Result<Self, DecodeError> {
let meta = rmp::decode::read_ext_meta(r).map_err(DecodeError::from_vre::<Self>)?;
let expected = meta.size as usize;
if r.len() < expected {
let actual = r.len();
*r = &r[actual..];
return Err(DecodeError::new::<Self>(format!(
"unexpected end of buffer (expected: {expected}, actual: {actual})"
)));
}
let (a, b) = r.split_at(expected);
*r = b;
Ok(Self::new(meta.typeid, a))
}
}
pub trait Encode {
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError>;
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("failed encoding: {0}")]
pub struct EncodeError(String);
impl From<rmp::encode::ValueWriteError> for EncodeError {
fn from(err: rmp::encode::ValueWriteError) -> Self {
Self(err.to_string())
}
}
impl From<std::io::Error> for EncodeError {
fn from(err: std::io::Error) -> Self {
Self(err.to_string())
}
}
impl Encode for () {
#[inline(always)]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_nil(w)?;
Ok(())
}
}
impl<T> Encode for &'_ T
where
T: Encode + ?Sized,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
(**self).encode(w, context)
}
}
impl<T> Encode for &'_ mut T
where
T: Encode + ?Sized,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
(**self).encode(w, context)
}
}
impl<T> Encode for Box<T>
where
T: Encode,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
(**self).encode(w, context)
}
}
impl<T> Encode for std::rc::Rc<T>
where
T: Encode,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
(**self).encode(w, context)
}
}
impl<T> Encode for Option<T>
where
T: Encode,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
if let Some(v) = self {
v.encode(w, context)
} else {
rmp::encode::write_nil(w)?;
Ok(())
}
}
}
impl<T> Encode for [T]
where
T: Encode,
{
#[inline]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_array_len(w, self.len() as _)?;
for v in self {
v.encode(w, context)?;
}
Ok(())
}
}
impl<T> Encode for BTreeSet<T>
where
T: Encode,
{
#[inline]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_array_len(w, self.len() as _)?;
for v in self {
v.encode(w, context)?;
}
Ok(())
}
}
impl<T> Encode for HashSet<T>
where
T: Encode,
{
#[inline]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_array_len(w, self.len() as _)?;
for v in self {
v.encode(w, context)?;
}
Ok(())
}
}
impl<T> Encode for Vec<T>
where
T: Encode,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
self[..].as_ref().encode(w, context)
}
}
impl<T> Encode for Cow<'_, T>
where
T: Encode + ToOwned + ?Sized,
{
#[inline(always)]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
self.deref().encode(w, context)
}
}
impl Encode for String {
#[inline(always)]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_str(w, self).map_err(Into::into)
}
}
impl Encode for str {
#[inline(always)]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_str(w, self).map_err(Into::into)
}
}
impl<K, V> Encode for BTreeMap<K, V>
where
K: Encode,
V: Encode,
{
#[inline]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_map_len(w, self.len() as u32)?;
for (k, v) in self.iter() {
k.encode(w, context)?;
v.encode(w, context)?;
}
Ok(())
}
}
impl<K, V> Encode for HashMap<K, V>
where
K: Encode,
V: Encode,
{
#[inline]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_map_len(w, self.len() as u32)?;
for (k, v) in self.iter() {
k.encode(w, context)?;
v.encode(w, context)?;
}
Ok(())
}
}
impl Encode for char {
#[inline(always)]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
let mut buf = [0; 4];
let s = self.encode_utf8(&mut buf);
rmp::encode::write_str(w, s)?;
Ok(())
}
}
macro_rules! impl_simple_encode {
($(($t:ty, $f:tt, $conv:ty))+) => {
$(
impl Encode for $t {
#[inline(always)]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
rmp::encode::$f(w, *self as $conv)?;
Ok(())
}
}
)+
}
}
impl_simple_encode! {
(u8, write_uint, u64)
(u16, write_uint, u64)
(u32, write_uint, u64)
(u64, write_uint, u64)
(usize, write_uint, u64)
(i8, write_sint, i64)
(i16, write_sint, i64)
(i32, write_sint, i64)
(i64, write_sint, i64)
(isize, write_sint, i64)
(f32, write_f32, f32)
(f64, write_f64, f64)
(bool, write_bool, bool)
}
impl<T, const N: usize> Encode for [T; N]
where
T: Encode,
{
#[inline]
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_array_len(w, N as _)?;
for item in self {
item.encode(w, context)?;
}
Ok(())
}
}
macro_rules! impl_tuple_encode {
() => {};
($h:ident $($t:ident)*) => {
#[allow(non_snake_case)]
impl<$h, $($t),*> Encode for ($h, $($t),*)
where
$h: Encode,
$($t: Encode,)*
{
fn encode(&self, w: &mut impl Write, context: &Context) -> Result<(), EncodeError> {
let ($h, $($t),*) = self;
rmp::encode::write_array_len(w, crate::expr_count!($h $(, $t)*))?;
$h.encode(w, context)?;
$( $t.encode(w, context)?; )*
Ok(())
}
}
impl_tuple_encode! { $($t)* }
}
}
impl_tuple_encode! { A B C D E F G H I J K L M N O P }
impl Encode for ExtStruct<'_> {
#[inline]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
rmp::encode::write_ext_meta(w, self.data.len() as u32, self.tag)?;
w.write_all(self.data).map_err(EncodeError::from)?;
Ok(())
}
}
impl Encode for serde_json::Value {
#[inline]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
let bytes = rmp_serde::to_vec(self).map_err(|e| EncodeError(e.to_string()))?;
w.write_all(bytes.as_slice())?;
Ok(())
}
}
impl Encode for serde_json::Map<String, serde_json::Value> {
#[inline]
fn encode(&self, w: &mut impl Write, _context: &Context) -> Result<(), EncodeError> {
let bytes = rmp_serde::to_vec(self).map_err(|e| EncodeError(e.to_string()))?;
w.write_all(bytes.as_slice())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use rmpv::Value;
use std::{collections::BTreeMap, io::Cursor};
const MAP_CTX: &Context = &Context::DEFAULT.with_struct_style(StructStyle::ForceAsMap);
const ARR_CTX: &Context = &Context::DEFAULT.with_struct_style(StructStyle::ForceAsArray);
#[track_caller]
fn assert_value(mut bytes: &[u8], v: rmpv::Value) {
let got = rmpv::decode::read_value(&mut bytes).unwrap();
assert_eq!(got, v);
}
#[test]
fn define_str_enum_regression() {
crate::define_str_enum! {
enum E {
A = "a",
B = "b",
}
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test {
a: String,
e: E,
b: bool,
}
let test = Test {
a: "abc".into(),
e: E::A,
b: true,
};
let bytes = encode(&test);
let test_dec: Test = decode(bytes.as_slice()).unwrap();
assert_eq!(test_dec, test);
let mut bytes = vec![];
test.encode(&mut bytes, MAP_CTX).unwrap();
let test_dec = Test::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(test_dec, test);
let test = vec![E::A, E::B, E::A];
let bytes = encode(&test);
let test_dec: Vec<E> = decode(bytes.as_slice()).unwrap();
assert_eq!(test_dec, test);
let test: HashMap<E, E> = vec![(E::A, E::B), (E::B, E::A)].into_iter().collect();
let bytes = encode(&test);
let test_dec: HashMap<E, E> = decode(bytes.as_slice()).unwrap();
assert_eq!(test_dec, test);
}
#[test]
fn encode_struct() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test1 {
b: u32,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test2 {
not_b: f32,
}
let test_1 = Test1 { b: 42 };
let bytes = encode(&test_1);
assert_value(
&bytes,
rmpv::Value::Array(vec![rmpv::Value::Integer(42.into())]),
);
let test_1_dec: Test1 = decode(bytes.as_slice()).unwrap();
assert_eq!(test_1_dec, test_1);
let err = decode::<Test2>(bytes.as_slice()).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_struct::Test2 (field not_b): \
failed decoding f32 (got FixPos(42)): the type decoded isn't match with the expected one"
);
let mut bytes = vec![];
test_1.encode(&mut bytes, MAP_CTX).unwrap();
assert_value(
&bytes,
Value::Map(vec![(Value::from("b"), Value::from(42))]),
);
let test_1_dec = Test1::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(test_1_dec, test_1);
let e = Test2::decode(&mut bytes.as_slice(), MAP_CTX).unwrap_err();
assert_eq!(
e.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_struct::Test2: expected field not_b, got b"
);
}
#[test]
fn decode_optionals() {
use std::f32::consts::TAU;
#[derive(Debug, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct TestNamedForbidden {
a: Option<Vec<String>>,
b: Vec<i32>,
c: Option<f32>,
d: Option<f32>,
}
let test_named_forbidden_helper_map = Value::Map(vec![
(Value::from("a"), Value::Nil),
(
Value::from("b"),
Value::Array(vec![Value::from(42), Value::from(52)]),
),
(Value::from("c"), Value::Nil),
(Value::from("d"), Value::from(TAU)),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_forbidden_helper_map).unwrap();
let decoded_map = TestNamedForbidden::decode(&mut encoded.as_slice(), MAP_CTX).unwrap();
assert_eq!(
decoded_map,
TestNamedForbidden {
a: None,
b: vec![42, 52],
c: None,
d: Some(TAU),
}
);
let test_named_forbidden_helper_map = Value::Map(vec![
(
Value::from("b"),
Value::Array(vec![Value::from(42), Value::from(52)]),
),
(Value::from("c"), Value::Nil),
(Value::from("d"), Value::from(TAU)),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_forbidden_helper_map).unwrap();
let decoded_map = TestNamedForbidden::decode(&mut encoded.as_slice(), MAP_CTX).unwrap();
assert_eq!(
decoded_map,
TestNamedForbidden {
a: None,
b: vec![42, 52],
c: None,
d: Some(TAU),
}
);
let test_named_forbidden_helper_arr = Value::Array(vec![
Value::Nil,
Value::Array(vec![Value::from(42), Value::from(52)]),
Value::Nil,
Value::from(TAU),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_forbidden_helper_arr).unwrap();
let decoded_arr = TestNamedForbidden::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_arr,
TestNamedForbidden {
a: None,
b: vec![42, 52],
c: None,
d: Some(TAU),
}
);
let test_named_forbidden_helper_arr = Value::Array(vec![
Value::Array(vec![Value::from(42), Value::from(52)]),
Value::Nil,
Value::from(TAU),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_forbidden_helper_arr).unwrap();
let err = TestNamedForbidden::decode(&mut encoded.as_slice(), ARR_CTX).unwrap_err();
assert_eq!(err.to_string(), "failed decoding tarantool::msgpack::encode::tests::decode_optionals::TestNamedForbidden: not enough fields, expected 4, got 3 (note: optional fields must be explicitly null unless `allow_array_optionals` attribute is passed)");
#[derive(Debug, Decode, PartialEq)]
#[encode(tarantool = "crate", allow_array_optionals)]
struct TestNamedAllowed {
a: Vec<i32>,
b: Option<f32>,
c: Option<bool>,
}
let test_named_allowed_helper_map = Value::Map(vec![
(
Value::from("a"),
Value::Array(vec![Value::from(42), Value::from(52)]),
),
(Value::from("b"), Value::Nil),
(Value::from("c"), Value::from(false)),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_allowed_helper_map).unwrap();
let decoded_map = TestNamedAllowed::decode(&mut encoded.as_slice(), MAP_CTX).unwrap();
assert_eq!(
decoded_map,
TestNamedAllowed {
a: vec![42, 52],
b: None,
c: Some(false),
}
);
let test_named_allowed_helper_map = Value::Map(vec![
(
Value::from("a"),
Value::Array(vec![Value::from(42), Value::from(52)]),
),
(Value::from("c"), Value::from(false)),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_allowed_helper_map).unwrap();
let decoded_map = TestNamedAllowed::decode(&mut encoded.as_slice(), MAP_CTX).unwrap();
assert_eq!(
decoded_map,
TestNamedAllowed {
a: vec![42, 52],
b: None,
c: Some(false),
}
);
let test_named_allowed_helper_arr = Value::Array(vec![
Value::Array(vec![Value::from(42), Value::from(52)]),
Value::Nil,
Value::from(false),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_allowed_helper_arr).unwrap();
let decoded_arr = TestNamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_arr,
TestNamedAllowed {
a: vec![42, 52],
b: None,
c: Some(false),
}
);
let test_named_allowed_helper_arr = Value::Array(vec![
Value::Array(vec![Value::from(42), Value::from(52)]),
Value::from(false),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_allowed_helper_arr).unwrap();
let err = TestNamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding f32 (got False): the type decoded isn't match with the expected one"
);
let test_named_allowed_helper_arr = Value::Array(vec![
Value::Array(vec![Value::from(42), Value::from(52)]),
Value::from(TAU),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_allowed_helper_arr).unwrap();
let decoded_arr = TestNamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_arr,
TestNamedAllowed {
a: vec![42, 52],
b: Some(TAU),
c: None
}
);
let test_named_allowed_helper_arr =
Value::Array(vec![Value::Array(vec![Value::from(42), Value::from(52)])]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_named_allowed_helper_arr).unwrap();
let decoded_arr = TestNamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_arr,
TestNamedAllowed {
a: vec![42, 52],
b: None,
c: None
}
);
#[derive(Debug, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct TestUnnamedForbidden(Option<f32>, i32, Option<i32>, Option<Vec<String>>);
let test_unnamed_forbidden_helper_arr = Value::Array(vec![
Value::Nil,
Value::from(42),
Value::Nil,
Value::Array(vec![Value::from("hello"), Value::from("world")]),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_unnamed_forbidden_helper_arr).unwrap();
let decoded_arr = TestUnnamedForbidden::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_arr,
TestUnnamedForbidden(None, 42, None, Some(vec!["hello".into(), "world".into()]))
);
let decoded_map = TestUnnamedForbidden::decode(&mut encoded.as_slice(), MAP_CTX).unwrap();
assert_eq!(decoded_arr, decoded_map);
let test_unnamed_forbidden_helper_arr = Value::Array(vec![
Value::from(42),
Value::Array(vec![Value::from("hello"), Value::from("world")]),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_unnamed_forbidden_helper_arr).unwrap();
let err_arr = TestUnnamedForbidden::decode(&mut encoded.as_slice(), ARR_CTX).unwrap_err();
assert_eq!(err_arr.to_string(), "failed decoding tarantool::msgpack::encode::tests::decode_optionals::TestUnnamedForbidden (0): failed decoding f32 (got FixPos(42)): the type decoded isn't match with the expected one");
let err_map = TestUnnamedForbidden::decode(&mut encoded.as_slice(), MAP_CTX).unwrap_err();
assert_eq!(err_map.to_string(), "failed decoding tarantool::msgpack::encode::tests::decode_optionals::TestUnnamedForbidden (0): failed decoding f32 (got FixPos(42)): the type decoded isn't match with the expected one");
#[derive(Debug, Decode, PartialEq)]
#[encode(tarantool = "crate", allow_array_optionals)]
struct TestUnnamedAllowed(i32, Option<i32>, Option<Vec<String>>);
let test_unnamed_allowed_helper_arr = Value::Array(vec![
Value::from(42),
Value::Nil,
Value::Array(vec![Value::from("hello"), Value::from("world")]),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_unnamed_allowed_helper_arr).unwrap();
let decoded_arr = TestUnnamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_arr,
TestUnnamedAllowed(42, None, Some(vec!["hello".into(), "world".into()]))
);
let decoded_map = TestUnnamedAllowed::decode(&mut encoded.as_slice(), MAP_CTX).unwrap();
assert_eq!(decoded_arr, decoded_map);
let test_unnamed_allowed_helper_arr = Value::Array(vec![
Value::from(42),
Value::Array(vec![Value::from("hello"), Value::from("world")]),
]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_unnamed_allowed_helper_arr).unwrap();
let err_arr = TestUnnamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap_err();
assert_eq!(err_arr.to_string(), "failed decoding tarantool::msgpack::encode::tests::decode_optionals::TestUnnamedAllowed (1): failed decoding i32 (got FixArray(2)): the type decoded isn't match with the expected one");
let err_map = TestUnnamedAllowed::decode(&mut encoded.as_slice(), MAP_CTX).unwrap_err();
assert_eq!(err_map.to_string(), "failed decoding tarantool::msgpack::encode::tests::decode_optionals::TestUnnamedAllowed (1): failed decoding i32 (got FixArray(2)): the type decoded isn't match with the expected one");
let test_unnamed_allowed_helper_arr = Value::Array(vec![Value::from(42), Value::from(52)]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_unnamed_allowed_helper_arr).unwrap();
let decoded_arr = TestUnnamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_arr, TestUnnamedAllowed(42, Some(52), None));
let test_unnamed_allowed_helper_arr = Value::Array(vec![Value::from(42)]);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &test_unnamed_allowed_helper_arr).unwrap();
let decoded_arr = TestUnnamedAllowed::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_arr, TestUnnamedAllowed(42, None, None));
}
#[test]
fn encode_raw() {
use serde::Serialize;
#[derive(Serialize, Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct TestHelper {
b: i32,
c: Vec<String>,
d: u64,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test1 {
#[encode(as_raw)]
b: Vec<u8>,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test2 {
b: i32,
#[encode(as_raw)]
c: Vec<u8>,
d: i32,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test3 {
#[encode(as_raw)]
not_b: Vec<u8>,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test4 {
b: Vec<String>,
#[encode(as_raw)]
c: Vec<u8>,
d: i32,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test5(#[encode(as_raw)] Vec<u8>);
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test6(Vec<String>, #[encode(as_raw)] Vec<u8>, i32);
let ctx = Context::default().with_struct_style(StructStyle::ForceAsMap);
let value = rmp_serde::encode::to_vec(&42).unwrap();
let original = Test1 { b: value };
let bytes = encode(&original);
assert_value(&bytes, Value::Array(vec![Value::from(42)]));
let decoded = decode::<Test1>(&bytes).unwrap();
assert_eq!(decoded, original);
let mut bytes = vec![];
original.encode(&mut bytes, &ctx).unwrap();
assert_value(
&bytes,
Value::Map(vec![(Value::from("b"), Value::from(42))]),
);
let decoded = Test1::decode(&mut bytes.as_slice(), &ctx).unwrap();
assert_eq!(decoded, original);
let err = decode::<Test3>(&bytes).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_raw::Test3 (got FixMap(1) in field not_b): the type decoded isn't match with the expected one"
);
let err = Test3::decode(&mut bytes.as_slice(), &ctx).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_raw::Test3: expected field not_b, got b"
);
let value = rmp_serde::to_vec(&42).unwrap();
let original = Test2 {
b: 52,
c: value,
d: 42,
};
let bytes = encode(&original);
assert_value(
&bytes,
Value::Array(vec![Value::from(52), Value::from(42), Value::from(42)]),
);
let decoded = decode::<Test2>(&bytes).unwrap();
assert_eq!(decoded, original);
let mut bytes = vec![];
original.encode(&mut bytes, &ctx).unwrap();
assert_value(
&bytes,
Value::Map(vec![
(Value::from("b"), Value::from(52)),
(Value::from("c"), Value::from(42)),
(Value::from("d"), Value::from(42)),
]),
);
let decoded = Test2::decode(&mut bytes.as_slice(), &ctx).unwrap();
assert_eq!(decoded, original);
let err = decode::<Test4>(bytes.as_slice()).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_raw::Test4 (got FixMap(3) in field b): the type decoded isn't match with the expected one"
);
let helper = TestHelper {
b: 42,
c: vec!["nothing".into(), "here".into()],
d: 52,
};
let value = rmp_serde::to_vec(&helper).unwrap();
let original = Test4 {
b: vec!["hello".into(), "world".into()],
c: value,
d: 52,
};
let bytes = encode(&original);
assert_value(
&bytes,
Value::Array(vec![
Value::Array(vec![Value::from("hello"), Value::from("world")]),
Value::Array(vec![
Value::from(42),
Value::Array(vec![Value::from("nothing"), Value::from("here")]),
Value::from(52),
]),
Value::from(52),
]),
);
let decoded = decode::<Test4>(&bytes).unwrap();
assert_eq!(decoded, original);
let mut bytes = vec![];
original.encode(&mut bytes, &ctx).unwrap();
assert_value(
&bytes,
Value::Map(vec![
(
Value::from("b"),
Value::Array(vec![Value::from("hello"), Value::from("world")]),
),
(
Value::from("c"),
Value::Array(vec![
Value::from(42),
Value::Array(vec![Value::from("nothing"), Value::from("here")]),
Value::from(52),
]),
),
(Value::from("d"), Value::from(52)),
]),
);
let err = decode::<Test2>(&bytes).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_raw::Test2 (got FixMap(3) in field b): the type decoded isn't match with the expected one"
);
let value = rmp_serde::encode::to_vec(&42).unwrap();
let original = Test5(value);
let bytes = encode(&original);
assert_value(&bytes, Value::Array(vec![Value::from(42)]));
let decoded = decode::<Test5>(&bytes).unwrap();
assert_eq!(decoded, original);
let err = decode::<Test6>(&bytes).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_raw::Test6 (field 0): \
failed decoding alloc::vec::Vec<alloc::string::String> (got FixPos(42)): the type decoded isn't match with the expected one"
);
let value = rmp_serde::encode::to_vec(&helper).unwrap();
let original = Test6(vec!["hello".into(), "world".into()], value, 42);
let bytes = encode(&original);
assert_value(
&bytes,
Value::Array(vec![
Value::Array(vec![Value::from("hello"), Value::from("world")]),
Value::Array(vec![
Value::from(42),
Value::Array(vec![Value::from("nothing"), Value::from("here")]),
Value::from(52),
]),
Value::from(42),
]),
);
let decoded = decode::<Test6>(&bytes).unwrap();
assert_eq!(decoded, original);
#[derive(Clone, Serialize, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum Test7 {
Something(Vec<u8>),
}
#[derive(Clone, Serialize, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum Test8 {
Something {
foo: i32,
#[encode(as_raw)]
bar: Vec<u8>,
},
}
let mut value = Vec::new();
rmp_serde::encode::write(&mut value, &42).unwrap();
let original = Test7::Something(value.clone());
let bytes = encode(&original);
assert_value(
&bytes,
Value::Map(vec![(
Value::from("Something"),
Value::Array(vec![Value::Array(vec![Value::from(42)])]),
)]),
);
let decoded = decode::<Test7>(&bytes).unwrap();
assert_eq!(decoded, original);
let original = Test8::Something {
foo: 52,
bar: value,
};
let bytes = encode(&original);
assert_value(
&bytes,
Value::Map(vec![(
Value::from("Something"),
Value::Array(vec![Value::from(52), Value::from(42)]),
)]),
);
let decoded = decode::<Test8>(&bytes).unwrap();
assert_eq!(decoded, original);
let err = decode::<Test7>(&bytes).unwrap_err();
assert_eq!(
err.to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_raw::Test7 (field 0): failed decoding alloc::vec::Vec<u8> (got FixPos(52)): the type decoded isn't match with the expected one"
);
let decoded = Test8::decode(&mut bytes.as_slice(), &ctx).unwrap();
assert_eq!(
decoded,
Test8::Something {
foo: 52,
bar: vec![42]
}
);
}
#[test]
fn encode_nested_struct() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
#[encode(as_map)]
struct Outer {
i: usize,
s: String,
inner: Inner,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Inner {
i: usize,
s: String,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
#[encode(as_map)]
struct OuterDeep {
i: usize,
s: String,
inner: Inner1Deep,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Inner1Deep {
i: usize,
s: String,
inner: Inner2Deep,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Inner2Deep {
i: usize,
s: String,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
#[encode(as_map)]
struct OuterMismatch {
i: usize,
s: String,
inner: Inner1Mismatch,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Inner1Mismatch {
i: usize,
s: String,
inner: Inner2Mismatch,
}
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Inner2Mismatch {
i: f32,
s: String,
}
let test = Outer {
i: 1,
s: "abc".into(),
inner: Inner {
i: 2,
s: "def".into(),
},
};
let bytes = encode(&test);
assert_value(
&bytes,
Value::Map(vec![
(Value::from("i"), Value::from(1)),
(Value::from("s"), Value::from("abc")),
(
Value::from("inner"),
Value::Array(vec![Value::from(2), Value::from("def")]),
),
]),
);
let test_dec: Outer = decode(bytes.as_slice()).unwrap();
assert_eq!(test_dec, test);
let ctx_as_array = Context::default().with_struct_style(StructStyle::ForceAsArray);
let mut bytes = vec![];
test.encode(&mut bytes, &ctx_as_array).unwrap();
assert_value(
&bytes,
Value::Array(vec![
Value::from(1),
Value::from("abc"),
Value::Array(vec![Value::from(2), Value::from("def")]),
]),
);
let e = Outer::decode(&mut bytes.as_slice(), &Context::default()).unwrap_err();
assert_eq!(e.to_string(), "failed decoding tarantool::msgpack::encode::tests::encode_nested_struct::Outer (got FixArray(3)): the type decoded isn't match with the expected one");
let test_dec = Outer::decode(&mut bytes.as_slice(), &ctx_as_array).unwrap();
assert_eq!(test_dec, test);
let mut bytes = vec![];
test.encode(&mut bytes, MAP_CTX).unwrap();
assert_value(
&bytes,
Value::Map(vec![
(Value::from("i"), Value::from(1)),
(Value::from("s"), Value::from("abc")),
(
Value::from("inner"),
Value::Map(vec![
(Value::from("i"), Value::from(2)),
(Value::from("s"), Value::from("def")),
]),
),
]),
);
let e = Outer::decode(&mut bytes.as_slice(), &Context::default()).unwrap_err();
assert_eq!(e.to_string(), "failed decoding tarantool::msgpack::encode::tests::encode_nested_struct::Outer (field inner): failed decoding tarantool::msgpack::encode::tests::encode_nested_struct::Inner (got FixMap(2) in field i): the type decoded isn't match with the expected one");
let test_dec = Outer::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(test_dec, test);
let mut bytes = vec![];
let test_deep = OuterDeep {
i: 1,
s: "abc".into(),
inner: Inner1Deep {
i: 2,
s: "def".into(),
inner: Inner2Deep {
i: 3,
s: "ghi".into(),
},
},
};
test_deep.encode(&mut bytes, MAP_CTX).unwrap();
let e = OuterMismatch::decode(&mut bytes.as_slice(), MAP_CTX).unwrap_err();
assert_eq!(e.to_string(), "failed decoding tarantool::msgpack::encode::tests::encode_nested_struct::OuterMismatch (field inner): failed decoding tarantool::msgpack::encode::tests::encode_nested_struct::Inner1Mismatch (field inner): failed decoding tarantool::msgpack::encode::tests::encode_nested_struct::Inner2Mismatch (field i): failed decoding f32 (got FixPos(3)): the type decoded isn't match with the expected one")
}
#[test]
fn encode_tuple_struct() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test(u32, bool);
let original = Test(0, true);
let bytes = encode(&original);
assert_value(
&bytes,
rmpv::Value::Array(vec![
rmpv::Value::Integer(0.into()),
rmpv::Value::Boolean(true),
]),
);
let decoded: Test = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn encode_unit_struct() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Test;
let original = Test;
let bytes = encode(&original);
assert_value(&bytes, rmpv::Value::Nil);
let decoded: Test = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[allow(clippy::let_unit_value)]
#[test]
fn encode_enum() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum Foo {
BarUnit,
BarTuple1(bool),
BarTupleN(i32, f64, String),
BarStruct1 {
bar: bool,
},
BarStructN {
bar1: usize,
bar2: [u8; 3],
bar3: Box<Foo>,
},
}
let original = Foo::BarUnit;
let bytes = encode(&original);
assert_value(
&bytes,
rmpv::Value::Map(vec![(
rmpv::Value::String("BarUnit".into()),
rmpv::Value::Nil,
)]),
);
let decoded: Foo = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = rmpv::Value::Map(vec![(
rmpv::Value::String("BarNotHere".into()),
rmpv::Value::Nil,
)]);
let mut bytes = vec![];
rmpv::encode::write_value(&mut bytes, &original).unwrap();
let res: Result<Foo, _> = decode(bytes.as_slice());
assert_eq!(
res.unwrap_err().to_string(),
"failed decoding tarantool::msgpack::encode::tests::encode_enum::Foo: enum variant BarNotHere does not exist",
);
let original = Foo::BarTuple1(true);
let bytes = encode(&original);
assert_value(
&bytes,
rmpv::Value::Map(vec![(
rmpv::Value::String("BarTuple1".into()),
rmpv::Value::Array(vec![rmpv::Value::Boolean(true)]),
)]),
);
let decoded: Foo = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = Foo::BarTupleN(13, 0.37, "hello".into());
let bytes = encode(&original);
assert_value(
&bytes,
rmpv::Value::Map(vec![(
rmpv::Value::String("BarTupleN".into()),
rmpv::Value::Array(vec![
rmpv::Value::from(13),
rmpv::Value::from(0.37),
rmpv::Value::from("hello"),
]),
)]),
);
let decoded: Foo = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = Foo::BarStruct1 { bar: false };
let bytes = encode(&original);
assert_value(
&bytes,
rmpv::Value::Map(vec![(
rmpv::Value::String("BarStruct1".into()),
rmpv::Value::Array(vec![rmpv::Value::Boolean(false)]),
)]),
);
let decoded: Foo = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = Foo::BarStructN {
bar1: 420,
bar2: [b'a', b'b', b'c'],
bar3: Box::new(Foo::BarUnit),
};
let bytes = encode(&original);
assert_value(
&bytes,
rmpv::Value::Map(vec![(
rmpv::Value::String("BarStructN".into()),
rmpv::Value::Array(vec![
rmpv::Value::from(420),
rmpv::Value::Array(vec![
rmpv::Value::from(b'a'),
rmpv::Value::from(b'b'),
rmpv::Value::from(b'c'),
]),
rmpv::Value::Map(vec![(
rmpv::Value::String("BarUnit".into()),
rmpv::Value::Nil,
)]),
]),
)]),
);
let decoded: Foo = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn encode_enum_untagged() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate", untagged)]
enum Foo {
BarUnit,
BarTuple1(bool),
BarStruct2 { bar1: bool, bar2: String },
BarTupleN(usize, [u8; 3], Box<Foo>),
}
let original = Foo::BarUnit;
let bytes = encode(&original);
assert_value(&bytes, Value::Nil);
let decoded_arr = Foo::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_arr, original);
let decoded_map = Foo::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(decoded_map, original);
let original = Foo::BarTuple1(true);
let bytes = encode(&original);
assert_value(&bytes, Value::Array(vec![Value::from(true)]));
let decoded_arr = Foo::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_arr, original);
let decoded_map = Foo::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(decoded_map, original);
let original = Foo::BarStruct2 {
bar1: false,
bar2: "welcome".to_owned(),
};
let bytes = encode(&original);
assert_value(
&bytes,
Value::Array(vec![Value::from(false), Value::from("welcome")]),
);
let decoded_arr = Foo::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_arr, original);
let decoded_map = Foo::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(decoded_map, original);
let original = Foo::BarTupleN(52, [37, 13, 42], Box::new(Foo::BarTuple1(true)));
let bytes = encode(&original);
assert_value(
&bytes,
Value::Array(vec![
Value::from(52),
Value::Array(vec![Value::from(37), Value::from(13), Value::from(42)]),
Value::Array(vec![Value::from(true)]),
]),
);
let decoded_arr = Foo::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_arr, original);
let decoded_map = Foo::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(decoded_map, original);
let mut bytes = Vec::new();
rmp::encode::write_str(&mut bytes, "0xDEADBEEF").unwrap();
let err = Foo::decode(&mut bytes.as_slice(), ARR_CTX).unwrap_err();
assert_eq!(err.to_string(), "failed decoding tarantool::msgpack::encode::tests::encode_enum_untagged::Foo: received stream didn't match any enum variant");
let err = Foo::decode(&mut bytes.as_slice(), MAP_CTX).unwrap_err();
assert_eq!(err.to_string(), "failed decoding tarantool::msgpack::encode::tests::encode_enum_untagged::Foo: received stream didn't match any enum variant");
}
#[test]
fn encode_named_with_raw_ident() {
#[derive(Clone, Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate", as_map)]
struct Test {
r#fn: u32,
}
let original = Test { r#fn: 1 };
let bytes = encode(&original);
let mut bytes = Cursor::new(bytes);
let marker = rmp::decode::read_marker(&mut bytes).unwrap();
assert!(matches!(marker, rmp::Marker::FixMap(1)));
let mut key_bytes = vec![0; 10];
let key = rmp::decode::read_str(&mut bytes, key_bytes.as_mut_slice()).unwrap();
assert_eq!(key, "fn");
}
#[test]
fn encode_vec() {
let original = vec![1u32];
let bytes = encode(&original);
let decoded: Vec<u32> = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = vec![1, 2, 3, 4, 5];
let bytes = encode(&original);
let decoded: Vec<i32> = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = Vec::<i32>::new();
let bytes = encode(&original);
let decoded: Vec<i32> = decode(bytes.as_slice()).unwrap();
assert_eq!(&original, &decoded);
}
#[test]
fn encode_array() {
let original = [1u32];
let bytes = encode(&original);
let decoded: [u32; 1] = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = [1, 2, 3, 4, 5];
let bytes = encode(&original);
let decoded: [u32; 5] = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let original = [0_u32; 0];
let bytes = encode(&original);
let decoded: [u32; 0] = decode(bytes.as_slice()).unwrap();
assert_eq!(&original, &decoded);
static mut DROP_COUNT: usize = 0;
#[derive(Decode, Debug)]
#[encode(tarantool = "crate")]
struct DropChecker;
impl Drop for DropChecker {
fn drop(&mut self) {
unsafe { DROP_COUNT += 1 }
}
}
let err = decode::<[DropChecker; 4]>(b"\x93\xc0\xc0\xc0").unwrap_err();
assert_eq!(unsafe { DROP_COUNT }, 0);
assert_eq!(err.to_string(), "failed decoding [tarantool::msgpack::encode::tests::encode_array::DropChecker; 4]: expected array count 4, got 3");
let err = decode::<[DropChecker; 4]>(b"\x94\xc0\xc0\x01\xc0").unwrap_err();
assert_eq!(unsafe { DROP_COUNT }, 2);
assert_eq!(err.to_string(), "failed decoding [tarantool::msgpack::encode::tests::encode_array::DropChecker; 4] (element 2): failed decoding () (got FixPos(1)): the type decoded isn't match with the expected one");
}
#[test]
fn encode_set() {
let mut original = BTreeSet::new();
original.insert(30);
original.insert(10);
original.insert(20);
let bytes = encode(&original);
assert_value(
&bytes,
Value::Array(vec![Value::from(10), Value::from(20), Value::from(30)]),
);
assert_eq!(original, decode::<BTreeSet<i32>>(&bytes).unwrap());
let mut original = HashSet::new();
original.insert(30);
original.insert(10);
original.insert(20);
let bytes = encode(&original);
let len = rmp::decode::read_array_len(&mut &bytes[..]).unwrap();
assert_eq!(len, 3);
assert_eq!(original, decode::<HashSet<i32>>(&bytes).unwrap());
}
#[test]
fn encode_map() {
let mut original = BTreeMap::new();
original.insert(1, "abc".to_string());
original.insert(2, "def".to_string());
let bytes = encode(&original);
let decoded: BTreeMap<u32, String> = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
let mut original = HashMap::new();
original.insert(1, "abc".to_string());
original.insert(2, "def".to_string());
let bytes = encode(&original);
let decoded: HashMap<u32, String> = decode(bytes.as_slice()).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn encode_str() {
let original = "hello";
let bytes = encode(&original);
let decoded: String = decode(&bytes).unwrap();
assert_eq!(original, decoded);
let decoded: &str = decode(&bytes).unwrap();
assert_eq!(original, decoded);
let bytes = encode(&Cow::Borrowed(original));
assert_eq!(original, decode::<String>(&bytes).unwrap());
let bytes = encode(&String::from(original));
assert_eq!(original, decode::<String>(&bytes).unwrap());
let bytes = encode(&Cow::<str>::Owned(original.to_owned()));
assert_eq!(original, decode::<String>(&bytes).unwrap());
}
#[test]
fn decode_borrowed_str_slice() {
#[derive(Debug, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct TestSingle<'a> {
a: &'a str,
b: Option<&'a str>,
c: Vec<&'a str>,
}
#[derive(Debug, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct TestMultiple<'a, 'b>
where
'a: 'b,
{
a: &'a str,
b: Option<&'b str>,
c: Vec<&'a str>,
}
let original = Value::Array(vec![
Value::from("one"),
Value::from("and"),
Value::Array(vec![Value::from("only")]),
]);
let mut bytes = Vec::new();
rmpv::encode::write_value(&mut bytes, &original).unwrap();
let decoded_single = TestSingle::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_single,
TestSingle {
a: "one",
b: Some("and"),
c: vec!["only"]
}
);
let decoded_multiple = TestMultiple::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(
decoded_multiple,
TestMultiple {
a: "one",
b: Some("and"),
c: vec!["only"]
}
);
let original = Value::Map(vec![
(Value::from("a"), Value::from("one")),
(Value::from("b"), Value::from("and")),
(Value::from("c"), Value::Array(vec![Value::from("only")])),
]);
let mut bytes = Vec::new();
rmpv::encode::write_value(&mut bytes, &original).unwrap();
let decoded_single = TestSingle::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(
decoded_single,
TestSingle {
a: "one",
b: Some("and"),
c: vec!["only"]
}
);
let decoded_multiple = TestMultiple::decode(&mut bytes.as_slice(), MAP_CTX).unwrap();
assert_eq!(
decoded_multiple,
TestMultiple {
a: "one",
b: Some("and"),
c: vec!["only"]
}
);
}
#[test]
fn encode_char() {
let bytes = encode(&'a');
assert_eq!(bytes, b"\xa1a");
assert_eq!('a', decode::<char>(&bytes).unwrap());
assert_eq!("a", decode::<String>(&bytes).unwrap());
let bytes = encode(&'я');
assert_eq!(bytes, b"\xa2\xd1\x8f");
assert_eq!('я', decode::<char>(&bytes).unwrap());
assert_eq!("я", decode::<String>(&bytes).unwrap());
let bytes = encode(&'☺');
assert_eq!(bytes, b"\xa3\xe2\x98\xba");
assert_eq!('☺', decode::<char>(&bytes).unwrap());
assert_eq!("☺", decode::<String>(&bytes).unwrap());
let e = decode::<char>(b"").unwrap_err();
assert_eq!(
e.to_string(),
"failed decoding char: failed to read MessagePack marker"
);
let e = decode::<char>(b"\xa0").unwrap_err();
assert_eq!(
e.to_string(),
"failed decoding char: expected a msgpack non-empty string, got string length 0"
);
let e = decode::<char>(b"\xa1\xff").unwrap_err();
assert_eq!(
e.to_string(),
"failed decoding char: invalid utf-8 sequence of 1 bytes from index 0"
);
let e = decode::<char>(b"\xa2hi").unwrap_err();
assert_eq!(
e.to_string(),
"failed decoding char: expected a single unicode character, got sequence of length 2"
);
let e = decode::<char>(b"\xa5aaaaa").unwrap_err();
assert_eq!(
e.to_string(),
"failed decoding char: expected a msgpack string not longer than 4 characters, got length 5"
);
}
#[test]
#[rustfmt::skip]
fn encode_integer() {
assert_eq!(&encode(&i8::MAX), &b"\x7f"[..]);
assert_eq!(&encode(&(i8::MAX as i64)), &b"\x7f"[..]);
assert_eq!(&encode(&i16::MAX), &b"\xcd\x7f\xff"[..]);
assert_eq!(&encode(&i32::MAX), &b"\xce\x7f\xff\xff\xff"[..]);
assert_eq!(&encode(&i64::MAX), &b"\xcf\x7f\xff\xff\xff\xff\xff\xff\xff"[..]);
assert_eq!(&encode(&u8::MAX), &b"\xcc\xff"[..]);
assert_eq!(&encode(&(u8::MAX as i64)), &b"\xcc\xff"[..]);
assert_eq!(&encode(&u16::MAX), &b"\xcd\xff\xff"[..]);
assert_eq!(&encode(&u32::MAX), &b"\xce\xff\xff\xff\xff"[..]);
assert_eq!(&encode(&u64::MAX), &b"\xcf\xff\xff\xff\xff\xff\xff\xff\xff"[..]);
assert_eq!(decode::<i8>(b"\x7f").unwrap(), i8::MAX);
assert_eq!(decode::<i16>(b"\xcd\x7f\xff").unwrap(), i16::MAX);
assert_eq!(decode::<i32>(b"\xce\x7f\xff\xff\xff").unwrap(), i32::MAX);
assert_eq!(decode::<i64>(b"\xcf\x7f\xff\xff\xff\xff\xff\xff\xff").unwrap(), i64::MAX);
assert_eq!(decode::<u8>(b"\xcc\xff").unwrap(), u8::MAX);
assert_eq!(decode::<u16>(b"\xcd\xff\xff").unwrap(), u16::MAX);
assert_eq!(decode::<u32>(b"\xce\xff\xff\xff\xff").unwrap(), u32::MAX);
assert_eq!(decode::<u64>(b"\xcf\xff\xff\xff\xff\xff\xff\xff\xff").unwrap(), u64::MAX);
}
#[test]
fn decode_tuple() {
let value: (Option<i8>, Vec<u8>, String) = (None, vec![0, 1, 2], "hello".to_string());
let encoded = rmp_serde::encode::to_vec(&value).unwrap();
let actual: (Option<i8>, Vec<u8>, String) = decode(&encoded).unwrap();
assert_eq!(actual, value);
}
#[test]
fn default_ambiguous_with_map() {
#[derive(Encode, Decode, PartialEq)]
#[encode(tarantool = "crate")]
#[encode(as_map)]
struct OldStruct {
old_value_1: u64,
old_value_2: String,
old_value_3: Vec<bool>,
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
#[encode(as_map)]
struct NewStruct {
old_value_1: u64,
#[encode(default)]
new_value: String,
old_value_2: String,
old_value_3: Vec<bool>,
}
let old = OldStruct {
old_value_1: 69,
old_value_2: String::from("kek"),
old_value_3: vec![true, false, true, true],
};
let bytes = encode(&old);
let mut new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(
NewStruct {
old_value_1: old.old_value_1,
old_value_2: old.old_value_2,
old_value_3: old.old_value_3,
new_value: Default::default(),
},
new
);
new.new_value = String::from("here's a new string");
let bytes = encode(&new);
let new_new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(new, new_new);
}
#[test]
fn default_simple() {
#[derive(Encode, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct OldStruct {
old_value_1: u64,
old_value_2: Vec<bool>,
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct NewStruct {
old_value_1: u64,
other_value: Vec<bool>,
#[encode(default)]
new_value: String,
}
let old = OldStruct {
old_value_1: 69,
old_value_2: vec![true, false, true, true],
};
let bytes = encode(&old);
let mut new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(
NewStruct {
old_value_1: old.old_value_1,
other_value: old.old_value_2,
new_value: Default::default(),
},
new
);
new.new_value = String::from("here's a new string");
let bytes = encode(&new);
let new_new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(new, new_new);
}
#[test]
fn default_fail() {
#[derive(Encode, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct OldStruct {
old_value_1: u64,
old_value_2: Vec<u8>,
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct NewStruct {
old_value_1: u64,
#[encode(default)]
new_value: Vec<u8>,
other_value: Vec<u8>,
}
let old = OldStruct {
old_value_1: 69,
old_value_2: vec![2, 5, 3, 1, 2],
};
let bytes = encode(&old);
let err = decode::<NewStruct>(&bytes).unwrap_err();
assert_eq!(err.to_string(), "failed decoding tarantool::msgpack::encode::tests::default_fail::NewStruct (field other_value): \
failed decoding alloc::vec::Vec<u8>: failed to read MessagePack marker");
}
#[test]
fn default_different_types() {
#[derive(Encode, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct OldStruct {
old_value_1: u64,
old_value_2: u16,
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct NewStruct {
old_value_1: u64,
#[encode(default)]
new_value: String,
other_value: u16,
}
let old = OldStruct {
old_value_1: 69,
old_value_2: 25,
};
let bytes = encode(&old);
let mut new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(
NewStruct {
old_value_1: old.old_value_1,
other_value: old.old_value_2,
new_value: Default::default(),
},
new
);
new.new_value = String::from("hello world");
let bytes = encode(&new);
let new_new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(new, new_new);
}
#[test]
fn default_enums() {
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum MyEnum {
Two(u64, usize),
Unit,
One(String),
}
impl Default for MyEnum {
fn default() -> Self {
Self::Two(123, 456)
}
}
#[derive(Encode, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct OldStruct {
old_value_1: u64,
old_value_2: String,
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct NewStruct {
old_value_1: u64,
#[encode(default)]
new_value: MyEnum,
other_value: String,
}
let old = OldStruct {
old_value_1: 69,
old_value_2: String::from("value"),
};
let bytes = encode(&old);
let mut new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(
NewStruct {
old_value_1: old.old_value_1,
other_value: old.old_value_2,
new_value: Default::default(),
},
new
);
new.new_value = MyEnum::Unit;
let bytes = encode(&new);
let new_new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(new, new_new);
}
#[test]
fn decode_rename_default_enums() {
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum MyEnum {
#[encode(rename = "not_two")]
Two(u64, usize),
#[encode(rename = "ultra_unit")]
Unit,
#[encode(rename = "one")]
One(String),
}
impl Default for MyEnum {
fn default() -> Self {
Self::Two(123, 456)
}
}
#[derive(Encode, Decode, PartialEq)]
#[encode(tarantool = "crate")]
struct OldStruct {
old_value_1: u64,
old_value_2: String,
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct NewStruct {
old_value_1: u64,
#[encode(default)]
new_value: MyEnum,
other_value: String,
}
let old = OldStruct {
old_value_1: 69,
old_value_2: String::from("value"),
};
let bytes = encode(&old);
let mut new = decode::<NewStruct>(&bytes).unwrap();
assert_eq!(
NewStruct {
old_value_1: old.old_value_1,
other_value: old.old_value_2.clone(),
new_value: Default::default(),
},
new
);
fn check_serde(ns: &NewStruct, msgpack: Value) {
let bytes = encode(&ns);
let mut encoded = Vec::new();
rmpv::encode::write_value(&mut encoded, &msgpack).unwrap();
assert_eq!(bytes, encoded);
let decoded_new = NewStruct::decode(&mut bytes.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_new, *ns);
let decoded_new_manual = NewStruct::decode(&mut encoded.as_slice(), ARR_CTX).unwrap();
assert_eq!(decoded_new_manual, *ns);
}
check_serde(
&new,
Value::Array(vec![
Value::Integer(old.old_value_1.into()),
Value::Map(vec![(
Value::String("not_two".into()),
Value::Array(vec![Value::Integer(123.into()), Value::Integer(456.into())]),
)]),
Value::String(old.old_value_2.clone().into()),
]),
);
new.new_value = MyEnum::Unit;
check_serde(
&new,
Value::Array(vec![
Value::Integer(old.old_value_1.into()),
Value::Map(vec![(Value::String("ultra_unit".into()), Value::Nil)]),
Value::String(old.old_value_2.clone().into()),
]),
);
new.new_value = MyEnum::One(String::from("useless"));
check_serde(
&new,
Value::Array(vec![
Value::Integer(old.old_value_1.into()),
Value::Map(vec![(
Value::String("one".into()),
Value::Array(vec![Value::String("useless".into())]),
)]),
Value::String(old.old_value_2.into()),
]),
);
}
#[test]
fn default_enum_values() {
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum UnnamedFields {
Variant(u64, #[encode(default)] u32, String),
}
let expected_msgpack = Value::Map(vec![(
Value::String("Variant".into()),
Value::Array(vec![
Value::Integer(123.into()),
Value::String("Hello!".into()),
]),
)]);
let mut expected_msgpack_bytes = vec![];
rmpv::encode::write_value(&mut expected_msgpack_bytes, &expected_msgpack).unwrap();
let new = UnnamedFields::decode(&mut expected_msgpack_bytes.as_slice(), ARR_CTX).unwrap();
let expected = UnnamedFields::Variant(123, 0, String::from("Hello!"));
assert_eq!(new, expected);
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
enum NamedFields {
Variant {
a: u64,
#[encode(default)]
c: u32,
b: String,
},
}
let expected_msgpack = Value::Map(vec![(
Value::String("Variant".into()),
Value::Array(vec![
Value::Integer(123.into()),
Value::String("Hello!".into()),
]),
)]);
let mut expected_msgpack_bytes = vec![];
rmpv::encode::write_value(&mut expected_msgpack_bytes, &expected_msgpack).unwrap();
let new = NamedFields::decode(&mut expected_msgpack_bytes.as_slice(), ARR_CTX).unwrap();
let expected = NamedFields::Variant {
a: 123,
c: 0,
b: String::from("Hello!"),
};
assert_eq!(new, expected);
}
#[test]
fn default_named_struct() {
#[derive(Encode, Decode, PartialEq, Debug)]
#[encode(tarantool = "crate")]
struct Variant {
a: u64,
#[encode(default)]
c: u32,
b: String,
}
let expected_msgpack = Value::Array(vec![
Value::Integer(123.into()),
Value::String("Hello!".into()),
]);
let mut expected_msgpack_bytes = vec![];
rmpv::encode::write_value(&mut expected_msgpack_bytes, &expected_msgpack).unwrap();
let new = Variant::decode(&mut expected_msgpack_bytes.as_slice(), ARR_CTX).unwrap();
let expected = Variant {
a: 123,
c: 0,
b: String::from("Hello!"),
};
assert_eq!(new, expected);
let expected_msgpack = Value::Map(vec![
(Value::String("a".into()), Value::Integer(123.into())),
(Value::String("b".into()), Value::String("Hello!".into())),
]);
let mut expected_msgpack_bytes = vec![];
rmpv::encode::write_value(&mut expected_msgpack_bytes, &expected_msgpack).unwrap();
let new = Variant::decode(&mut expected_msgpack_bytes.as_slice(), MAP_CTX).unwrap();
let expected = Variant {
a: 123,
c: 0,
b: String::from("Hello!"),
};
assert_eq!(new, expected);
}
}