Skip to content

Commit

Permalink
Add an (experimental) const generics feature
Browse files Browse the repository at this point in the history
It requires nightly.
  • Loading branch information
est31 committed Jun 7, 2019
1 parent c32ab9c commit 9ece314
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ serde_derive = "1.0"

[dev-dependencies]
serde_json = "1.0"

[features]
const-generics = []
76 changes: 76 additions & 0 deletions src/const_generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use core::fmt;
use core::result;
use core::marker::PhantomData;
use serde::ser;
use serde::ser::{Serialize, Serializer, SerializeTuple};
use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error};

pub trait BigArray<'de>: Sized {
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
where S: Serializer;
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
where D: Deserializer<'de>;
}
impl<'de, T, const N: usize> BigArray<'de> for [T; N]
where T: Default + Copy + Serialize + Deserialize<'de>
{
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
where S: Serializer
{
let mut seq = serializer.serialize_tuple(self.len())?;
for elem in &self[..] {
seq.serialize_element(elem)?;
}
seq.end()
}

fn deserialize<D>(deserializer: D) -> result::Result<[T; N], D::Error>
where D: Deserializer<'de>
{
struct ArrayVisitor<T> {
element: PhantomData<T>,
}

impl<'de, T> Visitor<'de> for ArrayVisitor<T>
where T: Default + Copy + Deserialize<'de>
{
type Value = [T; N];

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
#[cfg(not(macros_literal))]
macro_rules! write_len {
($l:tt) => {
write!(formatter, "an array of length {}", $l)
};
}
#[cfg(macros_literal)]
macro_rules! write_len {
($l:literal) => {
write!(formatter, concat!("an array of length ", $l))
};
($l:tt) => {
write!(formatter, "an array of length {}", $l)
};
}

write_len!(N)
}

fn visit_seq<A>(self, mut seq: A) -> result::Result<[T; N], A::Error>
where A: SeqAccess<'de>
{
let mut arr = [T::default(); N];
for i in 0..N {
arr[i] = seq.next_element()?
.ok_or_else(|| Error::invalid_length(i, &self))?;
}
Ok(arr)
}
}

let visitor = ArrayVisitor { element: PhantomData };
// The allow is needed to support (32 + 33) like expressions
#[allow(unused_parens)]
deserializer.deserialize_tuple(N, visitor)
}
}
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![forbid(unsafe_code)]
#![cfg_attr(feature = "const-generics", feature(const_generics))]

/*!
Big array helper for serde.
Expand Down Expand Up @@ -48,6 +49,11 @@ pub mod reex {
pub use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error};
}

#[cfg(feature = "const-generics")]
mod const_generics;
#[cfg(feature = "const-generics")]
pub use const_generics::BigArray;

/**
Big array macro
Expand Down
19 changes: 19 additions & 0 deletions tests/const_generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![cfg(feature = "const-generics")]

extern crate serde_big_array;

use serde_big_array::BigArray;

#[derive(Serialize, Deserialize)]
struct S {
#[serde(with = "BigArray")]
arr: [u8; 64],
}

#[test]
fn test() {
let s = S { arr: [1; 64] };
let j = serde_json::to_string(&s).unwrap();
let s_back = serde_json::from_str::<S>(&j).unwrap();
assert!(&s.arr[..] == &s_back.arr[..]);
}

0 comments on commit 9ece314

Please sign in to comment.