Skip to content

Commit c6e5021

Browse files
committed
Add "const-generics" feature
1 parent 53b9871 commit c6e5021

File tree

6 files changed

+150
-2
lines changed

6 files changed

+150
-2
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: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,7 @@ impl<A> ArrayVisitor<A> {
943943
}
944944
}
945945

946+
#[cfg(not(feature = "const-generics"))]
946947
impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
947948
type Value = [T; 0];
948949

@@ -960,6 +961,7 @@ impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> {
960961
}
961962

962963
// Does not require T: Deserialize<'de>.
964+
#[cfg(not(feature = "const-generics"))]
963965
impl<'de, T> Deserialize<'de> for [T; 0] {
964966
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
965967
where
@@ -969,6 +971,7 @@ impl<'de, T> Deserialize<'de> for [T; 0] {
969971
}
970972
}
971973

974+
#[cfg(not(feature = "const-generics"))]
972975
macro_rules! array_impls {
973976
($($len:expr => ($($n:tt)+))+) => {
974977
$(
@@ -1047,6 +1050,7 @@ macro_rules! array_impls {
10471050
}
10481051
}
10491052

1053+
#[cfg(not(feature = "const-generics"))]
10501054
array_impls! {
10511055
1 => (0)
10521056
2 => (0 1)
@@ -1082,6 +1086,117 @@ array_impls! {
10821086
32 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)
10831087
}
10841088

1089+
#[cfg(feature = "const-generics")]
1090+
struct ArrayGuard<T, const N: usize> {
1091+
dst: *mut T,
1092+
initialized: usize,
1093+
}
1094+
1095+
#[cfg(feature = "const-generics")]
1096+
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
1097+
fn drop(&mut self) {
1098+
debug_assert!(self.initialized <= N);
1099+
let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
1100+
#[allow(unsafe_code)]
1101+
unsafe {
1102+
core::ptr::drop_in_place(initialized_part);
1103+
}
1104+
}
1105+
}
1106+
1107+
#[cfg(feature = "const-generics")]
1108+
fn try_create_array<E, F, T, const N: usize>(mut cb: F) -> Result<[T; N], E>
1109+
where
1110+
F: FnMut(usize) -> Result<T, E>,
1111+
{
1112+
let mut array: core::mem::MaybeUninit<[T; N]> = core::mem::MaybeUninit::uninit();
1113+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
1114+
dst: array.as_mut_ptr() as _,
1115+
initialized: 0,
1116+
};
1117+
#[allow(unsafe_code)]
1118+
unsafe {
1119+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
1120+
core::ptr::write(value_ptr, cb(idx)?);
1121+
guard.initialized += 1;
1122+
}
1123+
core::mem::forget(guard);
1124+
Ok(array.assume_init())
1125+
}
1126+
}
1127+
1128+
#[cfg(feature = "const-generics")]
1129+
impl<'de, T, const N: usize> Visitor<'de> for ArrayVisitor<[T; N]>
1130+
where
1131+
T: Deserialize<'de>,
1132+
{
1133+
type Value = [T; N];
1134+
1135+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1136+
formatter.write_str("array")
1137+
}
1138+
1139+
#[inline]
1140+
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
1141+
where
1142+
S: SeqAccess<'de>,
1143+
{
1144+
try_create_array(|idx| {
1145+
seq.next_element()?.ok_or(Error::invalid_length(idx, &self))
1146+
})
1147+
}
1148+
}
1149+
1150+
#[cfg(feature = "const-generics")]
1151+
impl<'a, 'de, T, const N: usize> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; N]>
1152+
where
1153+
T: Deserialize<'de>,
1154+
{
1155+
type Value = ();
1156+
1157+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1158+
formatter.write_str("array")
1159+
}
1160+
1161+
#[inline]
1162+
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1163+
where
1164+
A: SeqAccess<'de>,
1165+
{
1166+
let mut fail_idx = None;
1167+
for (idx, dest) in self.0[..].iter_mut().enumerate() {
1168+
if seq.next_element_seed(InPlaceSeed(dest))?.is_none() {
1169+
fail_idx = Some(idx);
1170+
break;
1171+
}
1172+
}
1173+
if let Some(idx) = fail_idx {
1174+
return Err(Error::invalid_length(idx, &self));
1175+
}
1176+
Ok(())
1177+
}
1178+
}
1179+
1180+
#[cfg(feature = "const-generics")]
1181+
impl<'de, T, const N: usize> Deserialize<'de> for [T; N]
1182+
where
1183+
T: Deserialize<'de>,
1184+
{
1185+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1186+
where
1187+
D: Deserializer<'de>,
1188+
{
1189+
deserializer.deserialize_tuple(N, ArrayVisitor::<[T; N]>::new())
1190+
}
1191+
1192+
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
1193+
where
1194+
D: Deserializer<'de>,
1195+
{
1196+
deserializer.deserialize_tuple(N, ArrayInPlaceVisitor(place))
1197+
}
1198+
}
1199+
10851200
////////////////////////////////////////////////////////////////////////////////
10861201

10871202
macro_rules! tuple_impls {

serde/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@
134134
)
135135
)]
136136
// Rustc lints.
137-
#![forbid(unsafe_code)]
138-
#![deny(missing_docs, unused_imports)]
137+
#![deny(missing_docs, unused_imports, unsafe_code)]
138+
// Constant generics
139+
#![cfg_attr(feature = "const-generics", feature(min_const_generics))]
139140

140141
////////////////////////////////////////////////////////////////////////////////
141142

serde/src/ser/impls.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ impl<T: ?Sized> Serialize for PhantomData<T> {
127127
////////////////////////////////////////////////////////////////////////////////
128128

129129
// Does not require T: Serialize.
130+
#[cfg(not(feature = "const-generics"))]
130131
impl<T> Serialize for [T; 0] {
131132
#[inline]
132133
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -137,6 +138,7 @@ impl<T> Serialize for [T; 0] {
137138
}
138139
}
139140

141+
#[cfg(not(feature = "const-generics"))]
140142
macro_rules! array_impls {
141143
($($len:tt)+) => {
142144
$(
@@ -160,13 +162,32 @@ macro_rules! array_impls {
160162
}
161163
}
162164

165+
#[cfg(not(feature = "const-generics"))]
163166
array_impls! {
164167
01 02 03 04 05 06 07 08 09 10
165168
11 12 13 14 15 16 17 18 19 20
166169
21 22 23 24 25 26 27 28 29 30
167170
31 32
168171
}
169172

173+
#[cfg(feature = "const-generics")]
174+
impl<T, const N: usize> Serialize for [T; N]
175+
where
176+
T: Serialize,
177+
{
178+
#[inline]
179+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
180+
where
181+
S: Serializer,
182+
{
183+
let mut seq = serializer.serialize_tuple(N)?;
184+
for e in self.iter() {
185+
seq.serialize_element(e)?;
186+
}
187+
seq.end()
188+
}
189+
}
190+
170191
////////////////////////////////////////////////////////////////////////////////
171192

172193
impl<T> Serialize for [T]

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
@@ -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)