use std::fmt;
use ::serde::de::value::{BorrowedStrDeserializer, UnitDeserializer};
use ::serde::de::{
self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor,
};
use ::serde::ser::{self, Serialize};
use ::serde::Deserialize;
use vitaminc_aead::frame::{ARRAY, OBJECT, PASSTHROUGH};
use vitaminc_aead::leaf::{self, Form};
use vitaminc_aead::plaintext::{Float, Int, Logical, Physical};
use vitaminc_aead::tags::{self, STORAGE_MAP, STORAGE_SOME};
use vitaminc_aead::Frame;
use vitaminc_protected::Buffer;
use crate::write::{write, AsTransport};
#[derive(Clone)]
pub struct Error {
message: String,
path: Vec<PathSegment>,
reason: Reason,
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum Reason {
Malformed,
UnreadRest,
Mismatch,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PathSegment {
Key(String),
Index(usize),
Entry(usize),
}
impl Error {
pub(crate) fn new(message: impl fmt::Display) -> Self {
Self::because(Reason::Mismatch, message)
}
fn because(reason: Reason, message: impl fmt::Display) -> Self {
Self {
message: message.to_string(),
path: Vec::new(),
reason,
}
}
pub(crate) fn reason(&self) -> Reason {
self.reason
}
pub fn message(&self) -> &str {
&self.message
}
pub fn path(&self) -> &[PathSegment] {
&self.path
}
pub fn field(&self) -> Option<&str> {
self.path.iter().find_map(|segment| match segment {
PathSegment::Key(key) => Some(key.as_str()),
PathSegment::Index(_) | PathSegment::Entry(_) => None,
})
}
pub(crate) fn at(mut self, segment: impl Into<PathSegment>) -> Self {
self.path.insert(0, segment.into());
self
}
}
#[derive(Clone, Copy)]
pub(crate) enum At {
Key(&'static str),
Index(usize),
Entry(usize),
}
impl From<At> for PathSegment {
fn from(at: At) -> Self {
match at {
At::Key(key) => PathSegment::Key(key.to_owned()),
At::Index(index) => PathSegment::Index(index),
At::Entry(index) => PathSegment::Entry(index),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.path.is_empty() {
return f.write_str(&self.message);
}
for (i, segment) in self.path.iter().enumerate() {
match segment {
PathSegment::Key(key) if i == 0 => write!(f, "{key}")?,
PathSegment::Key(key) => write!(f, ".{key}")?,
PathSegment::Index(index) => write!(f, "[{index}]")?,
PathSegment::Entry(index) => write!(f, "{{{index}}}")?,
}
}
write!(f, ": {}", self.message)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Error({self})")
}
}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
self.message == other.message && self.path == other.path
}
}
impl Eq for Error {}
impl std::error::Error for Error {}
fn kind(unexpected: &Unexpected<'_>) -> &'static str {
match unexpected {
Unexpected::Bool(_) => "a boolean",
Unexpected::Unsigned(_) | Unexpected::Signed(_) => "an integer",
Unexpected::Float(_) => "a float",
Unexpected::Char(_) | Unexpected::Str(_) => "a string",
Unexpected::Bytes(_) => "bytes",
Unexpected::Unit => "null",
Unexpected::Option => "an optional value",
Unexpected::NewtypeStruct => "a newtype struct",
Unexpected::Seq => "an array",
Unexpected::Map => "an object",
Unexpected::Enum => "an enum",
Unexpected::UnitVariant => "a unit variant",
Unexpected::NewtypeVariant => "a newtype variant",
Unexpected::TupleVariant => "a tuple variant",
Unexpected::StructVariant => "a struct variant",
Unexpected::Other(_) => "a value of another kind",
}
}
impl de::Error for Error {
fn custom<T: fmt::Display>(_msg: T) -> Self {
Self::new("a value its type does not accept")
}
fn missing_field(field: &'static str) -> Self {
Self::new(format_args!("missing field `{field}`"))
}
fn duplicate_field(field: &'static str) -> Self {
Self::new(format_args!("duplicate field `{field}`"))
}
fn invalid_length(len: usize, expected: &dyn de::Expected) -> Self {
Self::new(format_args!("expected {expected}, found a length of {len}"))
}
fn invalid_type(unexpected: Unexpected<'_>, expected: &dyn de::Expected) -> Self {
Self::new(format_args!(
"expected {expected}, found {}",
kind(&unexpected)
))
}
fn invalid_value(unexpected: Unexpected<'_>, expected: &dyn de::Expected) -> Self {
Self::new(format_args!("{} that is not {expected}", kind(&unexpected)))
}
fn unknown_variant(_variant: &str, expected: &'static [&'static str]) -> Self {
Self::new(format_args!("an unknown variant, {}", one_of(expected)))
}
fn unknown_field(_field: &str, expected: &'static [&'static str]) -> Self {
Self::new(format_args!("an unknown key, {}", one_of(expected)))
}
}
fn one_of(expected: &[&str]) -> String {
if expected.is_empty() {
"expected none".to_owned()
} else {
format!("expected one of {}", expected.join(", "))
}
}
impl ser::Error for Error {
fn custom<T: fmt::Display>(_msg: T) -> Self {
Self::new("a value its type could not write")
}
}
pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
let frame = Frame::parse(bytes).map_err(|_| malformed_frame())?;
from_frame(frame)
}
pub fn from_frame<'de, T: Deserialize<'de>>(frame: Frame<'de>) -> Result<T, Error> {
from_validated(frame.as_bytes(), Profile::Transport)
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum Profile {
Transport,
Storage,
}
pub(crate) fn from_validated<'de, T: Deserialize<'de>>(
bytes: &'de [u8],
profile: Profile,
) -> Result<T, Error> {
let mut de = Deserializer {
buf: bytes,
pos: 0,
profile,
};
let value = T::deserialize(&mut de)?;
if de.pos != de.buf.len() {
return Err(Error::because(
Reason::UnreadRest,
"the value did not read the whole frame",
));
}
Ok(value)
}
struct Deserializer<'de> {
buf: &'de [u8],
pos: usize,
profile: Profile,
}
pub(crate) fn malformed_frame() -> Error {
Error::because(Reason::Malformed, "malformed frame")
}
fn unread() -> Error {
Error::new("a value its type did not read")
}
impl<'de> Deserializer<'de> {
fn peek(&self) -> Result<u8, Error> {
self.buf.get(self.pos).copied().ok_or_else(malformed_frame)
}
fn take(&mut self, n: usize) -> Result<&'de [u8], Error> {
let end = self.pos.checked_add(n).ok_or_else(malformed_frame)?;
let bytes = self.buf.get(self.pos..end).ok_or_else(malformed_frame)?;
self.pos = end;
Ok(bytes)
}
fn count(&mut self) -> Result<usize, Error> {
let bytes: [u8; 4] = self.take(4)?.try_into().map_err(|_| malformed_frame())?;
Ok(u32::from_le_bytes(bytes) as usize)
}
fn key(&mut self) -> Result<&'de str, Error> {
let len = self.count()?;
core::str::from_utf8(self.take(len)?).map_err(|_| malformed_frame())
}
fn scalar(&mut self) -> Result<(Option<Logical>, Physical<'de>), Error> {
let rest = self.buf.get(self.pos..).ok_or_else(malformed_frame)?;
let (scalar, used) = leaf::read(rest, Form::Frame).map_err(|_| malformed_frame())?;
self.pos += used;
Ok(scalar)
}
fn skip(&mut self) -> Result<(), Error> {
match self.peek()? {
ARRAY => {
self.pos += 1;
for _ in 0..self.count()? {
self.skip()?;
}
}
OBJECT => {
self.pos += 1;
for _ in 0..self.count()? {
self.key()?;
self.skip()?;
}
}
STORAGE_MAP => {
self.pos += 1;
for _ in 0..self.count()? {
self.skip()?;
self.skip()?;
}
}
PASSTHROUGH | STORAGE_SOME => {
self.pos += 1;
self.skip()?;
}
_ => {
self.scalar()?;
}
}
Ok(())
}
fn next_is_null(&self) -> Result<bool, Error> {
Ok(matches!(self.peek()?, tags::NULL | tags::UNDEFINED))
}
fn text_node(&mut self) -> Result<Option<&'de str>, Error> {
let rest = self.buf.get(self.pos..).ok_or_else(malformed_frame)?;
match leaf::read(rest, Form::Frame).map_err(|_| malformed_frame())? {
((None, Physical::Text(text)), used) => {
self.pos += used;
Ok(Some(text))
}
_ => Ok(None),
}
}
fn found(&self) -> Result<Unexpected<'static>, Error> {
Ok(match self.peek()? {
ARRAY => Unexpected::Seq,
OBJECT | STORAGE_MAP => Unexpected::Map,
PASSTHROUGH => Unexpected::Other("a passthrough"),
STORAGE_SOME => Unexpected::Option,
tags::NULL => Unexpected::Unit,
tags::BOOL_FALSE | tags::BOOL_TRUE => Unexpected::Bool(false),
tags::INT8
| tags::INT16
| tags::INT32
| tags::INT64
| tags::INT128
| tags::UINT8
| tags::UINT16
| tags::UINT32
| tags::UINT64
| tags::UINT128 => Unexpected::Unsigned(0),
tags::FLOAT32 | tags::FLOAT64 => Unexpected::Float(0.0),
tags::STRING => Unexpected::Str(""),
tags::BYTES => Unexpected::Bytes(&[]),
tags::UNDEFINED | tags::DATE | tags::TIMESTAMP | tags::DECIMAL | tags::LOGICAL => {
Unexpected::Other("a value with a logical type")
}
_ => return Err(malformed_frame()),
})
}
fn only<V: Visitor<'de>>(
&mut self,
expected: fn(&Unexpected<'_>) -> bool,
visitor: V,
) -> Result<V::Value, Error> {
let found = self.found()?;
if expected(&found) || matches!(found, Unexpected::Other(_)) {
de::Deserializer::deserialize_any(self, visitor)
} else {
Err(de::Error::invalid_type(found, &visitor))
}
}
}
impl<'de> Deserializer<'de> {
fn array<V: Visitor<'de>>(&mut self, visitor: V) -> Result<V::Value, Error> {
self.pos += 1;
let len = self.count()?;
let mut seq = Seq {
de: self,
left: len,
index: 0,
};
let value = visitor.visit_seq(&mut seq)?;
if seq.left != 0 {
return Err(Error::new("an array longer than expected"));
}
Ok(value)
}
fn entries<V: Visitor<'de>>(
&mut self,
names: &'static [&'static str],
keys: Keys,
visitor: V,
) -> Result<V::Value, Error> {
self.pos += 1;
let len = self.count()?;
let mut map = Map {
de: self,
names,
keys,
left: len,
index: 0,
at: None,
};
let value = visitor.visit_map(&mut map)?;
if map.left != 0 || map.at.is_some() {
return Err(Error::new("an object with entries left unread"));
}
Ok(value)
}
}
fn visit_scalar<'de, V: Visitor<'de>>(
ty: Option<Logical>,
value: Physical<'de>,
visitor: V,
) -> Result<V::Value, Error> {
if !is_plain(ty) {
return Err(Error::new(
"a value with a logical type (a date, a timestamp, a decimal) is not supported",
));
}
match value {
Physical::Null => visitor.visit_unit(),
Physical::Bool(b) => visitor.visit_bool(b),
Physical::Int(int) => visit_int(int, visitor),
Physical::Float(Float::F32(v)) => visitor.visit_f32(v),
Physical::Float(Float::F64(v)) => visitor.visit_f64(v),
Physical::Text(text) => visitor.visit_borrowed_str(text),
Physical::Bytes(bytes) => visitor.visit_borrowed_bytes(bytes),
}
}
fn is_plain(ty: Option<Logical>) -> bool {
matches!(ty, None | Some(Logical::Undefined))
}
fn entry_at(names: &'static [&'static str], key: &str, index: usize) -> At {
match names.iter().find(|name| **name == key) {
Some(name) => At::Key(name),
None => At::Entry(index),
}
}
fn visit_int<'de, V: Visitor<'de>>(int: Int, visitor: V) -> Result<V::Value, Error> {
match int {
Int::I8(v) => visitor.visit_i8(v),
Int::I16(v) => visitor.visit_i16(v),
Int::I32(v) => visitor.visit_i32(v),
Int::I64(v) => visitor.visit_i64(v),
Int::I128(v) => visitor.visit_i128(v),
Int::U8(v) => visitor.visit_u8(v),
Int::U16(v) => visitor.visit_u16(v),
Int::U32(v) => visitor.visit_u32(v),
Int::U64(v) => visitor.visit_u64(v),
Int::U128(v) => visitor.visit_u128(v),
}
}
impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
match self.peek()? {
ARRAY => self.array(visitor),
OBJECT => self.entries(&[], Keys::Text, visitor),
STORAGE_MAP => self.entries(&[], Keys::Nodes, visitor),
PASSTHROUGH => Err(Error::new("a passthrough is not supported")),
STORAGE_SOME => {
self.pos += 1;
visitor.visit_some(self)
}
_ => {
let (ty, value) = self.scalar()?;
visit_scalar(ty, value, visitor)
}
}
}
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
if self.peek()? == STORAGE_SOME {
self.pos += 1;
return visitor.visit_some(self);
}
if self.next_is_null()? {
self.scalar()?;
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_newtype_struct<V: Visitor<'de>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Error> {
visitor.visit_newtype_struct(self)
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error> {
match self.peek()? {
OBJECT => self.entries(fields, Keys::Text, visitor),
STORAGE_MAP => self.entries(fields, Keys::Names, visitor),
_ => self.only(|found| matches!(found, Unexpected::Map), visitor),
}
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error> {
match self.peek()? {
OBJECT => {
self.pos += 1;
if self.count()? != 1 {
return Err(Error::new(
"expected an enum: a variant name, or an object of one entry",
));
}
let variant = self.key()?;
let payload = self.pos;
let value = visitor.visit_enum(Enum {
de: self,
variants,
variant,
})?;
if self.pos == payload {
return Err(unread());
}
Ok(value)
}
ARRAY | STORAGE_MAP | PASSTHROUGH | STORAGE_SOME => Err(Error::new(
"expected an enum: a variant name, or an object of one entry",
)),
_ => match self.scalar()? {
(None, Physical::Text(variant)) => {
visitor.visit_enum(BareVariant { variants, variant })
}
_ => Err(Error::new(
"expected an enum: a variant name, or an object of one entry",
)),
},
}
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
self.skip()?;
visitor.visit_unit()
}
fn is_human_readable(&self) -> bool {
false
}
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
self.only(|found| matches!(found, Unexpected::Map), visitor)
}
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
self.only(|found| matches!(found, Unexpected::Str(_)), visitor)
}
fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
de::Deserializer::deserialize_str(self, visitor)
}
fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
self.only(|found| matches!(found, Unexpected::Bytes(_)), visitor)
}
fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
de::Deserializer::deserialize_bytes(self, visitor)
}
::serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char
unit unit_struct seq tuple tuple_struct identifier
}
}
struct Seq<'a, 'de> {
de: &'a mut Deserializer<'de>,
left: usize,
index: usize,
}
impl<'de> SeqAccess<'de> for Seq<'_, 'de> {
type Error = Error;
fn next_element_seed<T: DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Error> {
if self.left == 0 {
return Ok(None);
}
self.left -= 1;
let index = self.index;
self.index += 1;
let start = self.de.pos;
let value = seed
.deserialize(&mut *self.de)
.map_err(|e| e.at(PathSegment::Index(index)))?;
if self.de.pos == start {
return Err(unread().at(PathSegment::Index(index)));
}
Ok(Some(value))
}
fn size_hint(&self) -> Option<usize> {
Some(self.left)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Keys {
Text,
Nodes,
Names,
}
struct Map<'a, 'de> {
de: &'a mut Deserializer<'de>,
names: &'static [&'static str],
keys: Keys,
left: usize,
index: usize,
at: Option<At>,
}
impl<'de> MapAccess<'de> for Map<'_, 'de> {
type Error = Error;
fn next_key_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, Error> {
if self.at.is_some() {
return Err(Error::new("a map key was read before the previous value"));
}
if self.left == 0 {
return Ok(None);
}
self.left -= 1;
let index = self.index;
self.index += 1;
let text = match self.keys {
Keys::Text => Some(self.de.key()?),
Keys::Nodes | Keys::Names => self.de.text_node()?,
};
if let Some(key) = text {
self.at = Some(entry_at(self.names, key, index));
return seed
.deserialize(KeyDeserializer(key, self.de.profile))
.map(Some);
}
if self.keys == Keys::Names {
return Err(de::Error::invalid_type(self.de.found()?, &"a field name"));
}
self.at = Some(At::Entry(index));
let start = self.de.pos;
let key = seed.deserialize(&mut *self.de)?;
if self.de.pos == start {
return Err(unread());
}
Ok(Some(key))
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
let at = self
.at
.take()
.ok_or_else(|| Error::new("a map value was read before its key"))?;
let start = self.de.pos;
let value = seed.deserialize(&mut *self.de).map_err(|e| e.at(at))?;
if self.de.pos == start {
return Err(unread().at(at));
}
Ok(value)
}
fn size_hint(&self) -> Option<usize> {
Some(self.left)
}
}
struct KeyDeserializer<'de>(&'de str, Profile);
impl<'de> de::Deserializer<'de> for KeyDeserializer<'de> {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
visitor.visit_borrowed_str(self.0)
}
fn deserialize_newtype_struct<V: Visitor<'de>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Error> {
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V: Visitor<'de>>(
self,
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error> {
BorrowedStrDeserializer::<Error>::new(self.0).deserialize_enum(name, variants, visitor)
}
fn is_human_readable(&self) -> bool {
self.1 == Profile::Transport
}
::serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct seq tuple tuple_struct map
struct identifier ignored_any
}
}
struct Enum<'a, 'de> {
de: &'a mut Deserializer<'de>,
variants: &'static [&'static str],
variant: &'de str,
}
impl<'a, 'de> EnumAccess<'de> for Enum<'a, 'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self), Error> {
let variant = seed.deserialize(BorrowedStrDeserializer::<Error>::new(self.variant))?;
Ok((variant, self))
}
}
impl<'de> VariantAccess<'de> for Enum<'_, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
let at = self.at();
de::Deserialize::deserialize(&mut *self.de).map_err(|e: Error| e.at(at))
}
fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value, Error> {
let at = self.at();
seed.deserialize(&mut *self.de).map_err(|e| e.at(at))
}
fn tuple_variant<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value, Error> {
let at = self.at();
de::Deserializer::deserialize_seq(&mut *self.de, visitor).map_err(|e| e.at(at))
}
fn struct_variant<V: Visitor<'de>>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error> {
let at = self.at();
de::Deserializer::deserialize_struct(&mut *self.de, "", fields, visitor)
.map_err(|e| e.at(at))
}
}
impl Enum<'_, '_> {
fn at(&self) -> At {
entry_at(self.variants, self.variant, 0)
}
}
struct BareVariant<'de> {
variants: &'static [&'static str],
variant: &'de str,
}
impl<'de> EnumAccess<'de> for BareVariant<'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self), Error> {
let variant = seed.deserialize(BorrowedStrDeserializer::<Error>::new(self.variant))?;
Ok((variant, self))
}
}
impl<'de> VariantAccess<'de> for BareVariant<'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
Ok(())
}
fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value, Error> {
seed.deserialize(UnitDeserializer::<Error>::new())
.map_err(|e| e.at(entry_at(self.variants, self.variant, 0)))
}
fn tuple_variant<V: Visitor<'de>>(self, _len: usize, _visitor: V) -> Result<V::Value, Error> {
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"a tuple variant",
))
}
fn struct_variant<V: Visitor<'de>>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Error> {
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"a struct variant",
))
}
}
pub fn to_vec<T: Serialize + ?Sized>(value: &T) -> Result<Buffer, Error> {
let mut out = Buffer::new();
write::<AsTransport, T>(value, &mut out)?;
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn refusals_are_equal_by_message_and_path_only() {
let at = |error: Error, key| error.at(At::Key(key));
assert_eq!(
at(Error::because(Reason::Malformed, "same"), "a"),
at(Error::because(Reason::Mismatch, "same"), "a"),
"a refusal's reason is not part of its equality",
);
assert_ne!(
at(Error::new("one"), "a"),
at(Error::new("other"), "a"),
"refusals with different messages differ",
);
assert_ne!(
at(Error::new("same"), "a"),
at(Error::new("same"), "b"),
"refusals at different places differ",
);
}
#[test]
fn every_unexpected_value_is_named_by_kind_only() {
let cases = [
(Unexpected::Bool(true), "a boolean"),
(Unexpected::Unsigned(41), "an integer"),
(Unexpected::Signed(-41), "an integer"),
(Unexpected::Float(4.1), "a float"),
(Unexpected::Char('Z'), "a string"),
(Unexpected::Str("s3cr3t"), "a string"),
(Unexpected::Bytes(b"s3cr3t"), "bytes"),
(Unexpected::Unit, "null"),
(Unexpected::Option, "an optional value"),
(Unexpected::NewtypeStruct, "a newtype struct"),
(Unexpected::Seq, "an array"),
(Unexpected::Map, "an object"),
(Unexpected::Enum, "an enum"),
(Unexpected::UnitVariant, "a unit variant"),
(Unexpected::NewtypeVariant, "a newtype variant"),
(Unexpected::TupleVariant, "a tuple variant"),
(Unexpected::StructVariant, "a struct variant"),
(Unexpected::Other("s3cr3t"), "a value of another kind"),
];
for (unexpected, expected) in cases {
assert_eq!(kind(&unexpected), expected);
let message = <Error as de::Error>::invalid_value(unexpected, &"x").to_string();
assert!(
!message.contains("s3cr3t") && !message.contains("41"),
"{message}"
);
}
}
#[test]
fn a_typed_null_is_refused() {
let null_u32 = [
vitaminc_aead::tags::TYPED_NULL,
vitaminc_aead::tags::UINT32,
0,
0,
0,
];
assert!(from_slice::<Option<u32>>(&null_u32).is_err());
assert!(from_slice::<()>(&null_u32).is_err());
assert!(from_slice::<u32>(&null_u32).is_err());
}
}