Skip to content

Commit c229b29

Browse files
committed
Add "const-generics" feature
1 parent e9270e5 commit c229b29

File tree

7 files changed

+149
-0
lines changed

7 files changed

+149
-0
lines changed

serde/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ targets = ["x86_64-unknown-linux-gnu"]
3131
[features]
3232
default = ["std"]
3333

34+
# Supports arrays of arbitrary length
35+
const-generics = []
36+
3437
# Provide derive(Serialize, Deserialize) macros.
3538
derive = ["serde_derive"]
3639

serde/src/de/impls.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[cfg(feature = "const-generics")]
2+
mod const_generics_impls;
3+
14
use lib::*;
25

36
use de::{
@@ -1002,6 +1005,7 @@ impl<A> ArrayVisitor<A> {
10021005
}
10031006
}
10041007

1008+
#[cfg(not(feature = "const-generics"))]
10051009
impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
10061010
type Value = [T; 0];
10071011

@@ -1019,6 +1023,7 @@ impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
10191023
}
10201024

10211025
// Does not require T: Deserialize<'de>.
1026+
#[cfg(not(feature = "const-generics"))]
10221027
impl<'de, T> Deserialize<'de> for [T; 0] {
10231028
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
10241029
where
@@ -1028,6 +1033,7 @@ impl<'de, T> Deserialize<'de> for [T; 0] {
10281033
}
10291034
}
10301035

1036+
#[cfg(not(feature = "const-generics"))]
10311037
macro_rules! array_impls {
10321038
($($len:expr => ($($n:tt)+))+) => {
10331039
$(
@@ -1106,6 +1112,7 @@ macro_rules! array_impls {
11061112
}
11071113
}
11081114

1115+
#[cfg(not(feature = "const-generics"))]
11091116
array_impls! {
11101117
1 => (0)
11111118
2 => (0 1)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use crate::de::impls::{ArrayInPlaceVisitor, ArrayVisitor, InPlaceSeed};
2+
use de::{Deserialize, Deserializer, Error, SeqAccess, Visitor};
3+
use lib::fmt;
4+
5+
struct ArrayGuard<T, const N: usize> {
6+
dst: *mut T,
7+
initialized: usize,
8+
}
9+
10+
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
11+
fn drop(&mut self) {
12+
debug_assert!(self.initialized <= N);
13+
let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
14+
#[allow(unsafe_code)]
15+
unsafe {
16+
core::ptr::drop_in_place(initialized_part);
17+
}
18+
}
19+
}
20+
21+
fn try_create_array<E, F, T, const N: usize>(mut cb: F) -> Result<[T; N], E>
22+
where
23+
F: FnMut(usize) -> Result<T, E>,
24+
{
25+
let mut array: core::mem::MaybeUninit<[T; N]> = core::mem::MaybeUninit::uninit();
26+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
27+
dst: array.as_mut_ptr() as _,
28+
initialized: 0,
29+
};
30+
#[allow(unsafe_code)]
31+
unsafe {
32+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
33+
core::ptr::write(value_ptr, cb(idx)?);
34+
guard.initialized += 1;
35+
}
36+
core::mem::forget(guard);
37+
Ok(array.assume_init())
38+
}
39+
}
40+
41+
impl<'de, T, const N: usize> Visitor<'de> for ArrayVisitor<[T; N]>
42+
where
43+
T: Deserialize<'de>,
44+
{
45+
type Value = [T; N];
46+
47+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
48+
formatter.write_str("array")
49+
}
50+
51+
#[inline]
52+
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
53+
where
54+
S: SeqAccess<'de>,
55+
{
56+
try_create_array(|idx| seq.next_element()?.ok_or(Error::invalid_length(idx, &self)))
57+
}
58+
}
59+
60+
impl<'a, 'de, T, const N: usize> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; N]>
61+
where
62+
T: Deserialize<'de>,
63+
{
64+
type Value = ();
65+
66+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
67+
formatter.write_str("array")
68+
}
69+
70+
#[inline]
71+
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
72+
where
73+
A: SeqAccess<'de>,
74+
{
75+
let mut fail_idx = None;
76+
for (idx, dest) in self.0[..].iter_mut().enumerate() {
77+
if seq.next_element_seed(InPlaceSeed(dest))?.is_none() {
78+
fail_idx = Some(idx);
79+
break;
80+
}
81+
}
82+
if let Some(idx) = fail_idx {
83+
return Err(Error::invalid_length(idx, &self));
84+
}
85+
Ok(())
86+
}
87+
}
88+
89+
impl<'de, T, const N: usize> Deserialize<'de> for [T; N]
90+
where
91+
T: Deserialize<'de>,
92+
{
93+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94+
where
95+
D: Deserializer<'de>,
96+
{
97+
deserializer.deserialize_tuple(N, ArrayVisitor::<[T; N]>::new())
98+
}
99+
100+
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
101+
where
102+
D: Deserializer<'de>,
103+
{
104+
deserializer.deserialize_tuple(N, ArrayInPlaceVisitor(place))
105+
}
106+
}

serde/src/ser/impls.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[cfg(feature = "const-generics")]
2+
mod const_generics_impls;
3+
14
use lib::*;
25

36
use ser::{Error, Serialize, SerializeTuple, Serializer};
@@ -127,6 +130,7 @@ impl<T: ?Sized> Serialize for PhantomData<T> {
127130
////////////////////////////////////////////////////////////////////////////////
128131

129132
// Does not require T: Serialize.
133+
#[cfg(not(feature = "const-generics"))]
130134
impl<T> Serialize for [T; 0] {
131135
#[inline]
132136
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -137,6 +141,7 @@ impl<T> Serialize for [T; 0] {
137141
}
138142
}
139143

144+
#[cfg(not(feature = "const-generics"))]
140145
macro_rules! array_impls {
141146
($($len:tt)+) => {
142147
$(
@@ -160,6 +165,7 @@ macro_rules! array_impls {
160165
}
161166
}
162167

168+
#[cfg(not(feature = "const-generics"))]
163169
array_impls! {
164170
01 02 03 04 05 06 07 08 09 10
165171
11 12 13 14 15 16 17 18 19 20
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use ser::{Serialize, SerializeTuple, Serializer};
2+
3+
#[cfg(feature = "const-generics")]
4+
impl<T, const N: usize> Serialize for [T; N]
5+
where
6+
T: Serialize,
7+
{
8+
#[inline]
9+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
10+
where
11+
S: Serializer,
12+
{
13+
let mut seq = serializer.serialize_tuple(N)?;
14+
for e in self.iter() {
15+
seq.serialize_element(e)?;
16+
}
17+
seq.end()
18+
}
19+
}

test_suite/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ publish = false
77
build = "build.rs"
88

99
[features]
10+
const-generics = ["serde/const-generics"]
1011
expandtest = []
1112
unstable = ["serde/unstable"]
1213

test_suite/tests/test_gen.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,13 @@ fn test_gen() {
348348
#[serde(deny_unknown_fields)]
349349
struct UnitDenyUnknown;
350350

351+
#[cfg(feature = "const-generics")]
352+
#[derive(Serialize, Deserialize)]
353+
struct ArbitraryArrayLength {
354+
empty: [u8; 123],
355+
}
356+
357+
#[cfg(not(feature = "const-generics"))]
351358
#[derive(Serialize, Deserialize)]
352359
struct EmptyArray {
353360
empty: [X; 0],

0 commit comments

Comments
 (0)