Add 'serde' feature for serializing and deserializing ArrayVec and ArrayString.

This implements serde support under the optional 'serde' feature, and adds unit tests to test said support.
https://serde.rs/unit-testing.html used as a guide for the unit tests - using 'serde_test' makes for much
less boilerplate here, but it does require that the project have a non-optional dev dependency on 'serde_test'.
This commit is contained in:
David Ross
2017-06-08 01:30:35 -07:00
parent adf08656cc
commit 21cd20ff26
5 changed files with 171 additions and 1 deletions
+3 -1
View File
@@ -1,5 +1,7 @@
language: rust
sudo: false
env:
- FEATURES='serde'
matrix:
include:
- rust: 1.12.0
@@ -15,7 +17,7 @@ matrix:
- NODROP_FEATURES='use_needs_drop'
- rust: nightly
env:
- FEATURES='use_union'
- FEATURES='serde use_union'
- NODROP_FEATURES='use_union'
branches:
only:
+8
View File
@@ -19,6 +19,14 @@ version = "0.1.8"
path = "nodrop"
default-features = false
[dependencies.serde]
version = "1.0"
optional = true
default-features = false
[dev-dependencies.serde_test]
version = "1.0"
[features]
default = ["std"]
std = ["odds/std", "nodrop/std"]
+48
View File
@@ -14,6 +14,9 @@ use array::Index;
use CapacityError;
use odds::char::encode_utf8;
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
/// A string with a fixed capacity.
///
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
@@ -324,3 +327,48 @@ impl<A: Array<Item=u8>> Ord for ArrayString<A> {
(**self).cmp(&**rhs)
}
}
#[cfg(feature="serde")]
impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_str(&*self)
}
}
#[cfg(feature="serde")]
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
use serde::de::{self, Visitor};
use std::marker::PhantomData;
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string with no more than {} elements", A::capacity())
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error,
{
ArrayString::from(v).map_err(|_| E::invalid_length(v.len(), &self))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: de::Error,
{
let s = try!(str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self)));
ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self))
}
}
deserializer.deserialize_str(ArrayStringVisitor::<A>(PhantomData))
}
}
+50
View File
@@ -18,6 +18,8 @@
#![cfg_attr(not(feature="std"), no_std)]
extern crate odds;
extern crate nodrop;
#[cfg(feature="serde")]
extern crate serde;
#[cfg(not(feature="std"))]
extern crate core as std;
@@ -46,6 +48,9 @@ use std::any::Any; // core but unused
use nodrop::NoDrop;
#[cfg(feature="serde")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
mod array;
mod array_string;
@@ -821,6 +826,51 @@ impl<A: Array<Item=u8>> io::Write for ArrayVec<A> {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(feature="serde")]
impl<T: Serialize, A: Array<Item=T>> Serialize for ArrayVec<A> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.collect_seq(self)
}
}
#[cfg(feature="serde")]
impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
use serde::de::{Visitor, SeqAccess, Error};
use std::marker::PhantomData;
struct ArrayVecVisitor<'de, T: Deserialize<'de>, A: Array<Item=T>>(PhantomData<(&'de (), T, A)>);
impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Visitor<'de> for ArrayVecVisitor<'de, T, A> {
type Value = ArrayVec<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an array with no more than {} elements", A::capacity())
}
fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
where SA: SeqAccess<'de>,
{
let mut values = ArrayVec::<A>::new();
while let Some(value) = try!(seq.next_element()) {
if let Some(_) = values.push(value) {
return Err(SA::Error::invalid_length(A::capacity() + 1, &self));
}
}
Ok(values)
}
}
deserializer.deserialize_seq(ArrayVecVisitor::<T, A>(PhantomData))
}
}
/// Error value indicating insufficient capacity
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub struct CapacityError<T = ()> {
+62
View File
@@ -0,0 +1,62 @@
#![cfg(feature = "serde")]
extern crate arrayvec;
extern crate serde_test;
mod array_vec {
use arrayvec::ArrayVec;
use serde_test::{Token, assert_tokens};
#[test]
fn test_ser_de_empty() {
let vec = ArrayVec::<[u32; 0]>::new();
assert_tokens(&vec, &[
Token::Seq { len: Some(0) },
Token::SeqEnd,
]);
}
#[test]
fn test_ser_de() {
let mut vec = ArrayVec::<[u32; 3]>::new();
vec.push(20);
vec.push(55);
vec.push(123);
assert_tokens(&vec, &[
Token::Seq { len: Some(3) },
Token::U32(20),
Token::U32(55),
Token::U32(123),
Token::SeqEnd,
]);
}
}
mod array_string {
use arrayvec::ArrayString;
use serde_test::{Token, assert_tokens};
#[test]
fn test_ser_de_empty() {
let string = ArrayString::<[u8; 0]>::new();
assert_tokens(&string, &[
Token::Str(""),
]);
}
#[test]
fn test_ser_de() {
let string = ArrayString::<[u8; 9]>::from("1234 abcd")
.expect("expected exact specified capacity to be enough");
assert_tokens(&string, &[
Token::Str("1234 abcd"),
]);
}
}