Skip to content

Commit

Permalink
Serialize nested arrays
Browse files Browse the repository at this point in the history
First step toward full support for nested arrays, and a small step
toward supporting arbitrary nesting.

refs #2
  • Loading branch information
Kromey committed May 11, 2021
1 parent 5a69ec5 commit 98f8253
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ use serde::{
};
use std::{fmt, marker::PhantomData, mem::MaybeUninit};

pub mod nested;

/// Serialize const generic or arbitrarily-large arrays
///
/// For any array up to length `usize::MAX`, this function will allow Serde to properly serialize
Expand Down
96 changes: 96 additions & 0 deletions src/nested.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2021 Travis Veazey
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// https://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Serialize const generic or large arrays nested within arrays or `Vec`s
//!
//! This module extends the functionality of [`serde_arrays`][crate] to additionally support const generic
//! and large arrays that are nested within const generic or large arrays, or `Vec`s.
//!
//! ```
//! use serde::{Serialize};
//! use serde_json;
//!
//! #[derive(Serialize, Debug, PartialEq, Eq)]
//! struct NestedArray<const N: usize, const M: usize> {
//! #[serde(with = "serde_arrays::nested")]
//! arr: [[u32; N]; M],
//! }
//!
//! let data = NestedArray{ arr: [[1; 16]; 64] };
//! let json = serde_json::to_string(&data)?;
//! # //let de_data = serde_json::from_str(&json)?;
//!
//! # //assert_eq!(data, de_data);
//! # Ok::<(), serde_json::Error>(())
//! ```
//!
use serde::ser::{Serialize, Serializer, SerializeTuple, SerializeSeq};

struct ArrayWrap<'a, T: Serialize, const N: usize> {
inner: &'a [T; N],
}

impl<'a, T: Serialize, const N: usize> ArrayWrap<'a, T, N> {
pub fn new(array: &'a [T; N]) -> ArrayWrap<'a, T, N> {
ArrayWrap {
inner: array,
}
}
}

impl<'a, T: Serialize, const N: usize> Serialize for ArrayWrap<'a, T, N> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
super::serialize(self.inner, serializer)
}
}

pub trait NestedArray<T: Serialize, const N: usize> {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer;
}
impl<T: Serialize, const N: usize, const M: usize> NestedArray<T, N> for [[T; N]; M] {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
// Fixed-length structures, including arrays, are supported in Serde as tuples
// See: https://serde.rs/impl-serialize.html#serializing-a-tuple
let mut s = ser.serialize_tuple(N)?;
for item in self {
let wrapped = ArrayWrap::new(item);
s.serialize_element(&wrapped)?;
}
s.end()
}
}
impl<T: Serialize, const N: usize> NestedArray<T, N> for Vec<[T; N]> {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
let mut s = ser.serialize_seq(Some(self.len()))?;
for item in self {
let wrapped = ArrayWrap::new(item);
s.serialize_element(&wrapped)?;
}
s.end()
}
}

pub fn serialize<A, S, T, const N: usize>(data: &A, ser: S) -> Result<S::Ok, S::Error>
where
A: NestedArray<T, N>,
S: Serializer,
T: Serialize,
{
data.serialize(ser)
}
2 changes: 2 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

use serde::{Deserialize, Serialize};

pub mod nested;

/// A simple struct containing a const generic array
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct GenericArray<const N: usize> {
Expand Down
26 changes: 26 additions & 0 deletions tests/common/nested.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2021 Travis Veazey
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// https://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use serde::{Serialize};

#[derive(Serialize, Debug, PartialEq, Eq)]
pub struct NestedArray<const N: usize> {
#[serde(with = "serde_arrays::nested")]
pub arr: [[u32; N]; 2],
}

#[derive(Serialize, Debug, PartialEq, Eq)]
pub struct GenericNestedArray<const N: usize, const M: usize> {
#[serde(with = "serde_arrays::nested")]
pub arr: [[u32; N]; M],
}

#[derive(Serialize, Debug, PartialEq, Eq)]
pub struct VecArray<const N: usize> {
#[serde(with = "serde_arrays::nested")]
pub arr: Vec<[u32; N]>,
}
25 changes: 25 additions & 0 deletions tests/serialize_nested.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2021 Travis Veazey
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// https://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

mod common;
use common::nested::*;

#[test]
fn serialize_nested_array() {
let nested = NestedArray{ arr: [[1; 3]; 2] };
let generic = GenericNestedArray{ arr: [[1; 3]; 2] };
let vecced = VecArray{ arr: vec![[1; 3]; 2] };

let j_nested = serde_json::to_string(&nested).unwrap();
let j_generic = serde_json::to_string(&generic).unwrap();
let j_vecced = serde_json::to_string(&vecced).unwrap();

let json = "{\"arr\":[[1,1,1],[1,1,1]]}";
assert_eq!(json, &j_nested);
assert_eq!(json, &j_generic);
assert_eq!(json, &j_vecced);
}

0 comments on commit 98f8253

Please sign in to comment.