Skip to content
This repository was archived by the owner on Aug 15, 2025. It is now read-only.

Commit b34ee95

Browse files
Made arrays never encode their length (#625)
* Made arrays with 32 elements or less never encode their length * Removed `write_fixed_array_length` and `skip_fixed_array_length` as this was based on incorrect assumptions on how serde and bincode 1 works --------- Co-authored-by: Victor Koenders <[email protected]>
1 parent ebc3b6b commit b34ee95

File tree

14 files changed

+146
-206
lines changed

14 files changed

+146
-206
lines changed

compatibility/src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,22 @@ where
2222
// This is what bincode 1 serializes to. This will be our comparison value.
2323
let encoded = bincode_1_options.serialize(t).unwrap();
2424

25-
println!("Encoded {:?} as {:?}", t, encoded);
25+
println!("Encoded {t:?} as {encoded:?}");
2626

2727
// Test bincode 2 encode
2828
let bincode_2_output = bincode_2::encode_to_vec(t, bincode_2_config).unwrap();
29-
assert_eq!(encoded, bincode_2_output, "{:?} serializes differently", t);
29+
assert_eq!(
30+
encoded,
31+
bincode_2_output,
32+
"{t:?} serializes differently\nbincode 2 config {:?}",
33+
core::any::type_name::<C>(),
34+
);
3035

3136
// Test bincode 2 serde serialize
3237
let bincode_2_serde_output = bincode_2::serde::encode_to_vec(t, bincode_2_config).unwrap();
3338
assert_eq!(
3439
encoded, bincode_2_serde_output,
35-
"{:?} serializes differently",
36-
t
40+
"{t:?} serializes differently"
3741
);
3842

3943
// Test bincode 1 deserialize

compatibility/src/misc.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,83 @@ fn test() {
1010
super::test_same(std::net::Ipv6Addr::LOCALHOST);
1111
}
1212

13+
#[test]
14+
fn test_arrays() {
15+
// serde is known to be weird with arrays
16+
// Arrays of length 32 and less are encoded as tuples, but arrays 33 and up are encoded as slices
17+
// we need to make sure we're compatible with this
18+
super::test_same([0u8; 0]);
19+
super::test_same([1u8; 1]);
20+
super::test_same([1u8, 2]);
21+
super::test_same([1u8, 2, 3]);
22+
super::test_same([1u8, 2, 3, 4]);
23+
super::test_same([1u8, 2, 3, 4, 5]);
24+
super::test_same([1u8, 2, 3, 4, 5, 6]);
25+
super::test_same([1u8, 2, 3, 4, 5, 6, 7]);
26+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8]);
27+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9]);
28+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
29+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
30+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
31+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
32+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]);
33+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
34+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
35+
super::test_same([1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]);
36+
super::test_same([
37+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
38+
]);
39+
super::test_same([
40+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
41+
]);
42+
super::test_same([
43+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
44+
]);
45+
super::test_same([
46+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
47+
]);
48+
super::test_same([
49+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
50+
]);
51+
super::test_same([
52+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
53+
]);
54+
super::test_same([
55+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
56+
]);
57+
super::test_same([
58+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
59+
]);
60+
super::test_same([
61+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
62+
25, 26,
63+
]);
64+
super::test_same([
65+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
66+
25, 26, 27,
67+
]);
68+
super::test_same([
69+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
70+
25, 26, 27, 28,
71+
]);
72+
super::test_same([
73+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
74+
25, 26, 27, 28, 29,
75+
]);
76+
super::test_same([
77+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
78+
25, 26, 27, 28, 29, 30,
79+
]);
80+
super::test_same([
81+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
82+
25, 26, 27, 28, 29, 30, 31,
83+
]);
84+
super::test_same([
85+
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
86+
25, 26, 27, 28, 29, 30, 31, 32,
87+
]);
88+
}
89+
1390
#[derive(
1491
bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq,
1592
)]

docs/spec.md

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ assert_eq!(encoded.as_slice(), &[
126126

127127
# Arrays
128128

129-
Array length is encoded based on the `.write_fixed_array_length` and `.skip_fixed_array_length()` config. When an array length is written, it will be encoded as a `u64`.
129+
Array length is never encoded.
130130

131131
Note that `&[T]` is encoded as a [Collection](#collections).
132132

@@ -135,15 +135,9 @@ Note that `&[T]` is encoded as a [Collection](#collections).
135135
let arr: [u8; 5] = [10, 20, 30, 40, 50];
136136
let encoded = bincode::encode_to_vec(arr, bincode::config::legacy()).unwrap();
137137
assert_eq!(encoded.as_slice(), &[
138-
5, 0, 0, 0, 0, 0, 0, 0, // The length, as a u64
139138
10, 20, 30, 40, 50, // the bytes
140139
]);
141140

142-
let encoded = bincode::encode_to_vec(arr, bincode::config::legacy().skip_fixed_array_length()).unwrap();
143-
assert_eq!(encoded.as_slice(), &[
144-
// no length
145-
10, 20, 30, 40, 50, // the bytes
146-
]);
147141
```
148142

149143
This applies to any type `T` that implements `Encode`/`Decode`
@@ -168,14 +162,6 @@ let arr: [Foo; 2] = [
168162

169163
let encoded = bincode::encode_to_vec(&arr, bincode::config::legacy()).unwrap();
170164
assert_eq!(encoded.as_slice(), &[
171-
2, 0, 0, 0, 0, 0, 0, 0, // Length of the array
172-
10, 20, // First Foo
173-
30, 40, // Second Foo
174-
]);
175-
176-
let encoded = bincode::encode_to_vec(&arr, bincode::config::legacy().skip_fixed_array_length()).unwrap();
177-
assert_eq!(encoded.as_slice(), &[
178-
// no length
179165
10, 20, // First Foo
180166
30, 40, // Second Foo
181167
]);

src/config.rs

Lines changed: 17 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
//! .with_little_endian()
1212
//! // pick one of:
1313
//! .with_variable_int_encoding()
14-
//! .with_fixed_int_encoding()
15-
//! // pick one of:
16-
//! .skip_fixed_array_length()
17-
//! .write_fixed_array_length();
14+
//! .with_fixed_int_encoding();
1815
//! ```
1916
//!
2017
//! See [Configuration] for more information on the configuration options.
@@ -29,20 +26,16 @@ use core::marker::PhantomData;
2926
///
3027
/// - [with_little_endian] and [with_big_endian]
3128
/// - [with_fixed_int_encoding] and [with_variable_int_encoding]
32-
/// - [skip_fixed_array_length] and [write_fixed_array_length]
3329
///
3430
///
3531
/// [with_little_endian]: #method.with_little_endian
3632
/// [with_big_endian]: #method.with_big_endian
3733
/// [with_fixed_int_encoding]: #method.with_fixed_int_encoding
3834
/// [with_variable_int_encoding]: #method.with_variable_int_encoding
39-
/// [skip_fixed_array_length]: #method.skip_fixed_array_length
40-
/// [write_fixed_array_length]: #method.write_fixed_array_length
4135
#[derive(Copy, Clone)]
42-
pub struct Configuration<E = LittleEndian, I = Varint, A = WriteFixedArrayLength, L = NoLimit> {
36+
pub struct Configuration<E = LittleEndian, I = Varint, L = NoLimit> {
4337
_e: PhantomData<E>,
4438
_i: PhantomData<I>,
45-
_a: PhantomData<A>,
4639
_l: PhantomData<L>,
4740
}
4841

@@ -59,42 +52,39 @@ pub struct Configuration<E = LittleEndian, I = Varint, A = WriteFixedArrayLength
5952
/// The default config for bincode 2.0. By default this will be:
6053
/// - Little endian
6154
/// - Variable int encoding
62-
/// - Write fixed array length
6355
pub const fn standard() -> Configuration {
6456
generate()
6557
}
6658

6759
/// Creates the "legacy" default config. This is the default config that was present in bincode 1.0
6860
/// - Little endian
6961
/// - Fixed int length encoding
70-
/// - Write fixed array length
71-
pub const fn legacy() -> Configuration<LittleEndian, Fixint, WriteFixedArrayLength, NoLimit> {
62+
pub const fn legacy() -> Configuration<LittleEndian, Fixint, NoLimit> {
7263
generate()
7364
}
7465

75-
impl<E, I, A, L> Default for Configuration<E, I, A, L> {
66+
impl<E, I, L> Default for Configuration<E, I, L> {
7667
fn default() -> Self {
7768
generate()
7869
}
7970
}
8071

81-
const fn generate<E, I, A, L>() -> Configuration<E, I, A, L> {
72+
const fn generate<E, I, L>() -> Configuration<E, I, L> {
8273
Configuration {
8374
_e: PhantomData,
8475
_i: PhantomData,
85-
_a: PhantomData,
8676
_l: PhantomData,
8777
}
8878
}
8979

90-
impl<E, I, A, L> Configuration<E, I, A, L> {
80+
impl<E, I, L> Configuration<E, I, L> {
9181
/// Makes bincode encode all integer types in big endian.
92-
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, A, L> {
82+
pub const fn with_big_endian(self) -> Configuration<BigEndian, I, L> {
9383
generate()
9484
}
9585

9686
/// Makes bincode encode all integer types in little endian.
97-
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, A, L> {
87+
pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, L> {
9888
generate()
9989
}
10090

@@ -155,7 +145,7 @@ impl<E, I, A, L> Configuration<E, I, A, L> {
155145
///
156146
/// Note that u256 and the like are unsupported by this format; if and when they are added to the
157147
/// language, they may be supported via the extension point given by the 255 byte.
158-
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, A, L> {
148+
pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, L> {
159149
generate()
160150
}
161151

@@ -164,51 +154,29 @@ impl<E, I, A, L> Configuration<E, I, A, L> {
164154
/// * Fixed size integers are encoded directly
165155
/// * Enum discriminants are encoded as u32
166156
/// * Lengths and usize are encoded as u64
167-
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, A, L> {
168-
generate()
169-
}
170-
171-
/// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array
172-
///
173-
/// **NOTE:** This is not supported if you're using the `bincode::serde::*` functions, the `#[bincode(with_serde)]` attribute, or the `Compat` struct.
174-
pub const fn skip_fixed_array_length(self) -> Configuration<E, I, SkipFixedArrayLength, L> {
175-
generate()
176-
}
177-
178-
/// Write the length of fixed size arrays (`[u8; N]`) before writing the array
179-
pub const fn write_fixed_array_length(self) -> Configuration<E, I, WriteFixedArrayLength, L> {
157+
pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, L> {
180158
generate()
181159
}
182160

183161
/// Sets the byte limit to `limit`.
184-
pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, A, Limit<N>> {
162+
pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, Limit<N>> {
185163
generate()
186164
}
187165

188166
/// Clear the byte limit.
189-
pub const fn with_no_limit(self) -> Configuration<E, I, A, NoLimit> {
167+
pub const fn with_no_limit(self) -> Configuration<E, I, NoLimit> {
190168
generate()
191169
}
192170
}
193171

194172
/// Indicates a type is valid for controlling the bincode configuration
195173
pub trait Config:
196-
InternalEndianConfig
197-
+ InternalArrayLengthConfig
198-
+ InternalIntEncodingConfig
199-
+ InternalLimitConfig
200-
+ Copy
201-
+ Clone
174+
InternalEndianConfig + InternalIntEncodingConfig + InternalLimitConfig + Copy + Clone
202175
{
203176
}
204177

205178
impl<T> Config for T where
206-
T: InternalEndianConfig
207-
+ InternalArrayLengthConfig
208-
+ InternalIntEncodingConfig
209-
+ InternalLimitConfig
210-
+ Copy
211-
+ Clone
179+
T: InternalEndianConfig + InternalIntEncodingConfig + InternalLimitConfig + Copy + Clone
212180
{
213181
}
214182

@@ -244,22 +212,6 @@ impl InternalIntEncodingConfig for Varint {
244212
const INT_ENCODING: IntEncoding = IntEncoding::Variable;
245213
}
246214

247-
/// Skip writing the length of fixed size arrays (`[u8; N]`) before writing the array.
248-
#[derive(Copy, Clone)]
249-
pub struct SkipFixedArrayLength {}
250-
251-
impl InternalArrayLengthConfig for SkipFixedArrayLength {
252-
const SKIP_FIXED_ARRAY_LENGTH: bool = true;
253-
}
254-
255-
/// Write the length of fixed size arrays (`[u8; N]`) before writing the array.
256-
#[derive(Copy, Clone)]
257-
pub struct WriteFixedArrayLength {}
258-
259-
impl InternalArrayLengthConfig for WriteFixedArrayLength {
260-
const SKIP_FIXED_ARRAY_LENGTH: bool = false;
261-
}
262-
263215
/// Sets an unlimited byte limit.
264216
#[derive(Copy, Clone)]
265217
pub struct NoLimit {}
@@ -281,7 +233,7 @@ mod internal {
281233
const ENDIAN: Endian;
282234
}
283235

284-
impl<E: InternalEndianConfig, I, A, L> InternalEndianConfig for Configuration<E, I, A, L> {
236+
impl<E: InternalEndianConfig, I, L> InternalEndianConfig for Configuration<E, I, L> {
285237
const ENDIAN: Endian = E::ENDIAN;
286238
}
287239

@@ -295,9 +247,7 @@ mod internal {
295247
const INT_ENCODING: IntEncoding;
296248
}
297249

298-
impl<E, I: InternalIntEncodingConfig, A, L> InternalIntEncodingConfig
299-
for Configuration<E, I, A, L>
300-
{
250+
impl<E, I: InternalIntEncodingConfig, L> InternalIntEncodingConfig for Configuration<E, I, L> {
301251
const INT_ENCODING: IntEncoding = I::INT_ENCODING;
302252
}
303253

@@ -307,21 +257,11 @@ mod internal {
307257
Variable,
308258
}
309259

310-
pub trait InternalArrayLengthConfig {
311-
const SKIP_FIXED_ARRAY_LENGTH: bool;
312-
}
313-
314-
impl<E, I, A: InternalArrayLengthConfig, L> InternalArrayLengthConfig
315-
for Configuration<E, I, A, L>
316-
{
317-
const SKIP_FIXED_ARRAY_LENGTH: bool = A::SKIP_FIXED_ARRAY_LENGTH;
318-
}
319-
320260
pub trait InternalLimitConfig {
321261
const LIMIT: Option<usize>;
322262
}
323263

324-
impl<E, I, A, L: InternalLimitConfig> InternalLimitConfig for Configuration<E, I, A, L> {
264+
impl<E, I, L: InternalLimitConfig> InternalLimitConfig for Configuration<E, I, L> {
325265
const LIMIT: Option<usize> = L::LIMIT;
326266
}
327267
}

0 commit comments

Comments
 (0)