Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/Byte Vec Deserialize Wrapper #68

Merged
merged 14 commits into from Dec 10, 2020
94 changes: 89 additions & 5 deletions serde_at/src/de/mod.rs
Expand Up @@ -4,10 +4,11 @@ use core::str::FromStr;
use core::{fmt, str};

use serde::de::{self, Visitor};
use serde::{export, Deserialize};

use self::enum_::VariantAccess;
use self::map::MapAccess;
use self::seq::SeqAccess;
use self::seq::{SeqAccess, SeqByteAccess};

mod enum_;
mod map;
Expand All @@ -16,6 +17,68 @@ mod seq;
/// Deserialization result
pub type Result<T> = core::result::Result<T, Error>;

/// Wrapper type to allow deserializing a number of chars as a char vector
///
/// Example:
/// ```
/// use heapless::{consts, String};
/// use serde_at::{to_string, Bytes, SerializeOptions};
/// use serde_derive::Serialize;
///
/// #[derive(Debug, Deserialize, PartialEq)]
/// struct CharVecStruct(CharVec<consts::U7>)
///
/// let vec: CharVecStruct = from_str("+CCID: IMP_MSG")
///
/// let stru = CharVecTest(CharVec(heapless::Vec::from_slice(&['I', 'M', 'P', '_', 'M', 'S', 'G']).unwrap()));
///
/// assert_eq!(vec, Ok(stru));
/// ```
#[derive(Debug, PartialEq)]
struct CharVec<T: heapless::ArrayLength<char>>(heapless::Vec<char, T>);

impl<'de, N> Deserialize<'de> for CharVec<N>
where
N: heapless::ArrayLength<char>,
{
fn deserialize<D>(deserializer: D) -> export::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ValueVisitor<'de, N>(core::marker::PhantomData<(&'de (), char, N)>);

impl<'de, N> de::Visitor<'de> for ValueVisitor<'de, N>
where
N: heapless::ArrayLength<char>,
{
type Value = CharVec<N>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence")
}

fn visit_seq<A>(self, mut seq: A) -> export::Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut values = heapless::Vec::new();

while let Some(value) = seq.next_element()? {
if values.push(value).is_err() {
return Err(<A::Error as serde::de::Error>::invalid_length(
values.capacity() + 1,
&self,
));
}
}

Ok(CharVec(values))
}
}
deserializer.deserialize_bytes(ValueVisitor(core::marker::PhantomData))
}
}

/// This type represents all possible errors that can occur when deserializing AT Command strings
#[allow(clippy::pub_enum_variant_names)]
#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -373,11 +436,13 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
deserialize_fromstr!(self, visitor, f64, visit_f64, b"0123456789+-.eE")
}

fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value>
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
unreachable!()
let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?;
self.eat_char();
unizippro marked this conversation as resolved.
Show resolved Hide resolved
visitor.visit_char(peek as char)
}

fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
Expand Down Expand Up @@ -410,11 +475,11 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}

/// Unsupported
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value>
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
unreachable!()
Ok(visitor.visit_seq(SeqByteAccess::new(self))?)
}

/// Unsupported
Expand Down Expand Up @@ -629,6 +694,7 @@ where

#[cfg(test)]
mod tests {
use super::CharVec;
use heapless::{consts, String, Vec};
use serde_derive::Deserialize;

Expand All @@ -654,6 +720,9 @@ mod tests {
#[derive(Clone, Debug, PartialEq, Deserialize)]
struct Handle(pub usize);

#[derive(Clone, Debug, PartialEq, Deserialize)]
struct CharHandle(pub char);

#[test]
fn simple_struct() {
assert_eq!(
Expand Down Expand Up @@ -737,8 +806,23 @@ mod tests {
);
}

#[test]
fn char_test() {
assert_eq!(crate::from_str("+CCID: B"), Ok(CharHandle('B')));
}

#[test]
fn newtype_struct() {
assert_eq!(crate::from_str("+CCID: 15"), Ok(Handle(15)));
}

#[test]
fn char_vec_struct() {
#[derive(Debug, Deserialize, PartialEq)]
struct CharVecTest(CharVec<consts::U4>);
let stru = CharVecTest(CharVec(
heapless::Vec::from_slice(&['I', 'M', 'P', '_']).unwrap(),
));
assert_eq!(crate::from_str("+CCID: IMP_"), Ok(stru));
unizippro marked this conversation as resolved.
Show resolved Hide resolved
unizippro marked this conversation as resolved.
Show resolved Hide resolved
}
}
29 changes: 29 additions & 0 deletions serde_at/src/de/seq.rs
Expand Up @@ -41,3 +41,32 @@ impl<'a, 'de> de::SeqAccess<'de> for SeqAccess<'a, 'de> {
Ok(Some(seed.deserialize(&mut *self.de)?))
}
}

#[allow(clippy::module_name_repetitions)]
unizippro marked this conversation as resolved.
Show resolved Hide resolved
pub struct SeqByteAccess<'a, 'b> {
unizippro marked this conversation as resolved.
Show resolved Hide resolved
de: &'a mut Deserializer<'b>,
}

impl<'a, 'b> SeqByteAccess<'a, 'b> {
pub(crate) fn new(de: &'a mut Deserializer<'b>) -> Self {
SeqByteAccess { de }
}
}

impl<'a, 'de> de::SeqAccess<'de> for SeqByteAccess<'a, 'de> {
type Error = Error;

fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: de::DeserializeSeed<'de>,
{
match self.de.parse_whitespace() {
Some(b',') | None => {
return Ok(None);
}
Some(_) => {}
};

Ok(Some(seed.deserialize(&mut *self.de)?))
}
}