Skip to content

Commit 7b753e1

Browse files
committed
Removing serde's derive feature
This set of changes started as an experiment in removing the derive feature from serde after having seen some interesting analysis of build parallelization due to crates usage of the derive macro. In the process of this, the examples started looking ugly due to the split `use` statements for the two crates. I realized one area of API cleanup I hadn't done yet was make more ergonomic serialize/deserialize functions for the SymbolMaps. After I did this, the examples no longer needed the traits, and only needed the derive macros.
1 parent c9fb4bd commit 7b753e1

File tree

9 files changed

+99
-75
lines changed

9 files changed

+99
-75
lines changed

CHANGELOG.md

+16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3434
in the atom.
3535
- `SymbolMapRef` is now a struct with private contents.
3636
- `Error` is now `#[non_exhaustive]`.
37+
- `format::Float` and `format::Integer` no longer implement
38+
`Serialize`/`Deserialize`. These implementations were derived but never
39+
actually used. To improve this crate's build parallelization, a decision was
40+
made to remove these usages of serde's derive macro. Implementing these traits
41+
would be trivial, but the crate maintainer doesn't believe anyone is actually
42+
using these implementations, so they were intentionally skipped. Please file
43+
an issue if this affected you and you would like to see these implementations
44+
added again.
3745

3846
### Changed
3947

@@ -44,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4452
chosen at the time due to dependencies also requiring this MSRV.
4553
- Tracing instrumentation has been changed from the default level of INFO to
4654
TRACE.
55+
- This crate no longer activates the `derive` feature of `serde`.
4756

4857
### Added
4958

@@ -55,6 +64,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5564
- `de::SymbolMap` and `ser::SymbolMap` now both implement `Serialize` and
5665
`Deserialize` using the same serialization strategy. This allows preshared
5766
dictionaries to be used, and for state to be saved and restored.
67+
- `de::SymbolMap` and `ser::SymbolMap` have new convenience methods that allow
68+
serializing and deserializing values directly:
69+
70+
- `de::SymbolMap::deserialize_slice`
71+
- `de::SymbolMap::deserialize_from`
72+
- `ser::SymbolMap::serialize_to_vec`
73+
- `ser::SymbolMap::serialize_to`
5874

5975
[9]: https://github.com/khonsulabs/pot/issues/9
6076

benchmarks/examples/logs.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,19 @@ fn main() -> anyhow::Result<()> {
6969
// so let's show the benefits by just encoding a single log entry.
7070
let mut sender_state = pot::ser::SymbolMap::default();
7171
let mut receiver_state = pot::de::SymbolMap::default();
72-
let mut payload_buffer = Vec::new();
73-
logs.entries[0].serialize(&mut sender_state.serializer_for(&mut payload_buffer)?)?;
72+
let mut payload_buffer = sender_state.serialize_to_vec(&logs.entries[0])?;
7473
let first_transmission_length = payload_buffer.len();
7574
{
7675
assert_eq!(
77-
&Log::deserialize(&mut receiver_state.deserializer_for_slice(&payload_buffer)?)?,
76+
&receiver_state.deserialize_slice::<Log>(&payload_buffer)?,
7877
&logs.entries[0]
7978
);
8079
}
81-
let mut payload_buffer = Vec::new();
82-
logs.entries[0].serialize(&mut sender_state.serializer_for(&mut payload_buffer)?)?;
80+
payload_buffer.clear();
81+
sender_state.serialize_to(&mut payload_buffer, &logs.entries[0])?;
8382
let subsequent_transmission_length = payload_buffer.len();
8483
assert_eq!(
85-
&Log::deserialize(&mut receiver_state.deserializer_for_slice(&payload_buffer)?)?,
84+
&receiver_state.deserialize_slice::<Log>(&payload_buffer)?,
8685
&logs.entries[0]
8786
);
8887

pot/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pot"
3-
version = "2.0.0"
3+
version = "3.0.0"
44
edition = "2021"
55
description = "A concise binary serialization format written for `BonsaiDb`."
66
license = "MIT OR Apache-2.0"
@@ -14,12 +14,13 @@ rust-version = "1.70.0"
1414
default = []
1515

1616
[dependencies]
17-
serde = { version = "1.0.136", features = ["derive"] }
17+
serde = { version = "1.0.136" }
1818
tracing = { version = "0.1.30", optional = true }
1919
byteorder = "1.4.3"
2020
half = "2.2.1"
2121

2222
[dev-dependencies]
23+
serde_derive = "1.0.136"
2324
tracing-subscriber = "0.3.8"
2425
tracing = "0.1.30"
2526
serde_bytes = "0.11.5"

pot/examples/preshared-symbols.rs

+5-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// begin rustme snippet: example
2-
use serde::{Deserialize, Serialize};
3-
2+
use serde_derive::{Deserialize, Serialize};
43
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Default)]
54
pub struct User {
65
id: u64,
@@ -22,10 +21,7 @@ fn main() {
2221
name: String::from("ecton"),
2322
};
2423
let encoded_without_map = pot::to_vec(&original_user).unwrap();
25-
let mut encoded_with_map = Vec::new();
26-
original_user
27-
.serialize(&mut preshared_map.serializer_for(&mut encoded_with_map).unwrap())
28-
.unwrap();
24+
let encoded_with_map = preshared_map.serialize_to_vec(&original_user).unwrap();
2925
println!(
3026
"Default User encoded without map: {} bytes",
3127
encoded_without_map.len()
@@ -42,12 +38,9 @@ fn main() {
4238
// Deserialize the symbol map.
4339
let mut deserializer_map: pot::de::SymbolMap = pot::from_slice(&preshared_map_bytes).unwrap();
4440
// Deserialize the payload using the map.
45-
let user = User::deserialize(
46-
&mut deserializer_map
47-
.deserializer_for_slice(&encoded_with_map)
48-
.unwrap(),
49-
)
50-
.unwrap();
41+
let user: User = deserializer_map
42+
.deserialize_slice(&encoded_with_map)
43+
.unwrap();
5144
assert_eq!(user, original_user);
5245
}
5346

pot/examples/simple.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// begin rustme snippet: example
2-
use serde::{Deserialize, Serialize};
3-
2+
use serde_derive::{Deserialize, Serialize};
43
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
54
pub struct User {
65
id: u64,

pot/src/de.rs

+22
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,28 @@ impl SymbolMap {
12101210
Deserializer::from_read(reader, self.persistent(), usize::MAX)
12111211
}
12121212

1213+
/// Deserializes `T` from `slice`.
1214+
///
1215+
/// This should only be used with data generated by using a persistent
1216+
/// [`ser::SymbolMap`](crate::ser::SymbolMap).
1217+
pub fn deserialize_slice<'de, T>(&mut self, slice: &'de [u8]) -> Result<T>
1218+
where
1219+
T: Deserialize<'de>,
1220+
{
1221+
T::deserialize(&mut self.deserializer_for_slice(slice)?)
1222+
}
1223+
1224+
/// Deserializes `T` from `reader`.
1225+
///
1226+
/// This should only be used with data generated by using a persistent
1227+
/// [`ser::SymbolMap`](crate::ser::SymbolMap).
1228+
pub fn deserialize_from<'de, T>(&mut self, reader: impl Read) -> Result<T>
1229+
where
1230+
T: Deserialize<'de>,
1231+
{
1232+
T::deserialize(&mut self.deserializer_for(reader)?)
1233+
}
1234+
12131235
#[must_use]
12141236
fn persistent<'de>(&mut self) -> SymbolMapRef<'_, 'de> {
12151237
SymbolMapRef(SymbolMapRefPrivate::Persistent(self))

pot/src/format.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::fmt::Display;
22

33
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
44
use half::f16;
5-
use serde::{Deserialize, Serialize};
65

76
pub(crate) const CURRENT_VERSION: u8 = 0;
87

@@ -546,11 +545,10 @@ pub fn write_bytes<W: WriteBytesExt>(mut writer: W, value: &[u8]) -> std::io::Re
546545
}
547546

548547
/// An integer type that can safely convert between other number types using compile-time evaluation.
549-
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
550-
#[serde(transparent)]
548+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
551549
pub struct Integer(pub(crate) InnerInteger);
552550

553-
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
551+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
554552
pub(crate) enum InnerInteger {
555553
/// An i8 value.
556554
I8(i8),
@@ -1131,11 +1129,10 @@ pub struct Atom<'de> {
11311129
}
11321130

11331131
/// A floating point number that can safely convert between other number types using compile-time evaluation when possible.
1134-
#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq)]
1135-
#[serde(transparent)]
1132+
#[derive(Debug, Copy, Clone, PartialEq)]
11361133
pub struct Float(pub(crate) InnerFloat);
11371134

1138-
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
1135+
#[derive(Debug, Copy, Clone)]
11391136
pub(crate) enum InnerFloat {
11401137
/// An f64 value.
11411138
F64(f64),

pot/src/lib.rs

+22-46
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ mod tests {
191191
use std::sync::OnceLock;
192192

193193
use serde::{Deserializer, Serializer};
194+
use serde_derive::{Deserialize, Serialize};
194195

195196
use super::*;
196197
use crate::format::{Float, Integer, CURRENT_VERSION};
@@ -814,24 +815,17 @@ mod tests {
814815
let mut sender = ser::SymbolMap::default();
815816
let mut receiver = de::SymbolList::default();
816817

817-
let mut bytes = Vec::new();
818-
NumbersStruct::default()
819-
.serialize(&mut sender.serializer_for(&mut bytes).unwrap())
820-
.unwrap();
821-
let _result =
822-
NumbersStruct::deserialize(&mut receiver.deserializer_for_slice(&bytes).unwrap())
823-
.unwrap();
818+
let mut bytes = sender.serialize_to_vec(&NumbersStruct::default()).unwrap();
819+
let _result = receiver.deserialize_slice::<NumbersStruct>(&bytes).unwrap();
824820
let symbol_count_after_first_send = receiver.len();
825821
let first_payload_len = bytes.len();
826822

827823
// Send again, confirm the symbol list didn't grow.
828824
bytes.clear();
829-
NumbersStruct::default()
830-
.serialize(&mut sender.serializer_for(&mut bytes).unwrap())
825+
sender
826+
.serialize_to(&mut bytes, &NumbersStruct::default())
831827
.unwrap();
832-
let _result =
833-
NumbersStruct::deserialize(&mut receiver.deserializer_for_slice(&bytes).unwrap())
834-
.unwrap();
828+
let _result = receiver.deserialize_slice::<NumbersStruct>(&bytes).unwrap();
835829
assert_eq!(symbol_count_after_first_send, receiver.len());
836830
println!(
837831
"First: {first_payload_len} bytes; Second: {} bytes",
@@ -845,24 +839,21 @@ mod tests {
845839
let mut sender = ser::SymbolMap::default();
846840
let mut receiver = de::SymbolList::default();
847841

848-
let mut bytes = Vec::new();
849-
NumbersStruct::default()
850-
.serialize(&mut sender.serializer_for(&mut bytes).unwrap())
842+
let mut bytes = sender.serialize_to_vec(&NumbersStruct::default()).unwrap();
843+
let _result = receiver
844+
.deserialize_from::<NumbersStruct>(&bytes[..])
851845
.unwrap();
852-
let _result =
853-
NumbersStruct::deserialize(&mut receiver.deserializer_for(&bytes[..]).unwrap())
854-
.unwrap();
855846
let symbol_count_after_first_send = receiver.len();
856847
let first_payload_len = bytes.len();
857848

858849
// Send again, confirm the symbol list didn't grow.
859850
bytes.clear();
860-
NumbersStruct::default()
861-
.serialize(&mut sender.serializer_for(&mut bytes).unwrap())
851+
sender
852+
.serialize_to(&mut bytes, &NumbersStruct::default())
853+
.unwrap();
854+
let _result = receiver
855+
.deserialize_from::<NumbersStruct>(&bytes[..])
862856
.unwrap();
863-
let _result =
864-
NumbersStruct::deserialize(&mut receiver.deserializer_for(&bytes[..]).unwrap())
865-
.unwrap();
866857
assert_eq!(symbol_count_after_first_send, receiver.len());
867858
println!(
868859
"First: {first_payload_len} bytes; Second: {} bytes",
@@ -883,16 +874,13 @@ mod tests {
883874
assert!(sender.is_empty());
884875
let mut receiver = crate::de::SymbolMap::new();
885876
assert!(receiver.is_empty());
886-
let mut bytes = Vec::new();
887877

888878
// Send the first payload, populating the map.
889-
Payload::default()
890-
.serialize(&mut sender.serializer_for(&mut bytes).unwrap())
891-
.unwrap();
879+
let mut bytes = sender.serialize_to_vec(&Payload::default()).unwrap();
892880
assert_eq!(sender.len(), 2);
893881

894882
assert_eq!(
895-
Payload::deserialize(&mut receiver.deserializer_for_slice(&bytes).unwrap()).unwrap(),
883+
receiver.deserialize_slice::<Payload>(&bytes).unwrap(),
896884
Payload::default()
897885
);
898886
assert_eq!(receiver.len(), 2);
@@ -913,31 +901,19 @@ mod tests {
913901
// by the serialized map and the original map are identical.
914902
let new_payload = Payload { a: 1, b: 2 };
915903
bytes.clear();
916-
new_payload
917-
.serialize(&mut sender.serializer_for(&mut bytes).unwrap())
918-
.unwrap();
919-
let mut from_serialized_sender = Vec::new();
920-
new_payload
921-
.serialize(
922-
&mut deserialized_sender
923-
.serializer_for(&mut from_serialized_sender)
924-
.unwrap(),
925-
)
926-
.unwrap();
904+
sender.serialize_to(&mut bytes, &new_payload).unwrap();
905+
let from_serialized_sender = deserialized_sender.serialize_to_vec(&new_payload).unwrap();
927906
assert_eq!(bytes, from_serialized_sender);
928907

929908
// Deserialize the payload
930909
assert_eq!(
931-
Payload::deserialize(&mut receiver.deserializer_for_slice(&bytes).unwrap()).unwrap(),
910+
receiver.deserialize_slice::<Payload>(&bytes).unwrap(),
932911
new_payload
933912
);
934913
assert_eq!(
935-
Payload::deserialize(
936-
&mut deserialized_receiver
937-
.deserializer_for_slice(&bytes)
938-
.unwrap()
939-
)
940-
.unwrap(),
914+
deserialized_receiver
915+
.deserialize_slice::<Payload>(&bytes)
916+
.unwrap(),
941917
new_payload
942918
);
943919
}

pot/src/ser.rs

+21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::borrow::Cow;
22
use std::cmp::Ordering;
33
use std::fmt::{Debug, Display};
4+
use std::io::Write;
45
use std::ops::Range;
56
use std::usize;
67

@@ -587,6 +588,26 @@ impl SymbolMap {
587588
Serializer::new_with_symbol_map(output, SymbolMapRef::Persistent(self))
588589
}
589590

591+
/// Serializes `value` into `writer` while persisting symbols into `self`.
592+
pub fn serialize_to<T, W>(&mut self, writer: W, value: &T) -> Result<()>
593+
where
594+
W: Write,
595+
T: Serialize,
596+
{
597+
value.serialize(&mut self.serializer_for(writer)?)
598+
}
599+
600+
/// Serializes `value` into a new `Vec<u8>` while persisting symbols into
601+
/// `self`.
602+
pub fn serialize_to_vec<T>(&mut self, value: &T) -> Result<Vec<u8>>
603+
where
604+
T: Serialize,
605+
{
606+
let mut output = Vec::new();
607+
self.serialize_to(&mut output, value)?;
608+
Ok(output)
609+
}
610+
590611
fn find_or_add(&mut self, symbol: &'static str) -> RegisteredSymbol {
591612
// Symbols have to be static strings, and so we can rely on the addres
592613
// not changing. To avoid string comparisons, we're going to use the

0 commit comments

Comments
 (0)