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
100 changes: 95 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,76 @@ 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 CommandStruct{
/// id: u8,
/// vec: CharVec<consts::U7>
/// value: i32,
/// }
///
/// let incomming: CommandStruct = from_str("+CCID: 4,IMP_MSG,-12")
unizippro marked this conversation as resolved.
Show resolved Hide resolved
///
/// let expected = CommandStruct{
/// id: 4,
/// vec : CharVec(heapless::Vec::from_slice(&['I', 'M', 'P', '_', 'M', 'S', 'G']).unwrap()),
/// value: -12,
/// }
///
/// assert_eq!(incomming, Ok(expected));
unizippro marked this conversation as resolved.
Show resolved Hide resolved
/// ```
#[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 +444,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 +483,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 +702,7 @@ where

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

Expand All @@ -654,6 +728,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 +814,21 @@ 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() {
let expectation: CharVec<consts::U4> = CharVec(
heapless::Vec::from_slice(&['I', 'M', 'P', '_']).unwrap(),
);
assert_eq!(crate::from_str("+CCID: IMP_"), Ok(expectation));
}
}
28 changes: 28 additions & 0 deletions serde_at/src/de/seq.rs
Expand Up @@ -41,3 +41,31 @@ impl<'a, 'de> de::SeqAccess<'de> for SeqAccess<'a, 'de> {
Ok(Some(seed.deserialize(&mut *self.de)?))
}
}

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)?))
}
}