Skip to content

Commit c8f0b33

Browse files
committed
Add "const-generics" feature
1 parent be7d0e7 commit c8f0b33

File tree

8 files changed

+152
-2
lines changed

8 files changed

+152
-2
lines changed

serde/Cargo.toml

+3
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

+7
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::{
@@ -943,6 +946,7 @@ impl<A> ArrayVisitor<A> {
943946
}
944947
}
945948

949+
#[cfg(not(feature = "const-generics"))]
946950
impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
947951
type Value = [T; 0];
948952

@@ -960,6 +964,7 @@ impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
960964
}
961965

962966
// Does not require T: Deserialize<'de>.
967+
#[cfg(not(feature = "const-generics"))]
963968
impl<'de, T> Deserialize<'de> for [T; 0] {
964969
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
965970
where
@@ -969,6 +974,7 @@ impl<'de, T> Deserialize<'de> for [T; 0] {
969974
}
970975
}
971976

977+
#[cfg(not(feature = "const-generics"))]
972978
macro_rules! array_impls {
973979
($($len:expr => ($($n:tt)+))+) => {
974980
$(
@@ -1047,6 +1053,7 @@ macro_rules! array_impls {
10471053
}
10481054
}
10491055

1056+
#[cfg(not(feature = "const-generics"))]
10501057
array_impls! {
10511058
1 => (0)
10521059
2 => (0 1)
+106
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/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@
134134
must_use_candidate,
135135
)
136136
)]
137+
// Constant generics
138+
#![cfg_attr(feature = "const-generics", feature(min_const_generics))]
137139
// Rustc lints.
138-
#![forbid(unsafe_code)]
139-
#![deny(missing_docs, unused_imports)]
140+
#![deny(missing_docs, unused_imports, unsafe_code)]
140141

141142
////////////////////////////////////////////////////////////////////////////////
142143

serde/src/ser/impls.rs

+6
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
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

+1
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

+7
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ fn test_gen() {
347347
#[serde(deny_unknown_fields)]
348348
struct UnitDenyUnknown;
349349

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

0 commit comments

Comments
 (0)