Skip to content

Commit fab28de

Browse files
authored
Fix Serde implementation (#99)
1 parent 84c1324 commit fab28de

7 files changed

Lines changed: 161 additions & 10 deletions

File tree

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
runs-on: ubuntu-latest
1818
strategy:
1919
matrix:
20-
rust: [1.39.0, stable, nightly]
20+
rust: [1.56.0, stable, nightly]
2121

2222
steps:
2323
- uses: actions/checkout@v2

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
target/
22
.idea/
33
Cargo.lock
4+
.vscode

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ version = "0.4.2"
44
authors = ["bluss"]
55
license = "MIT OR Apache-2.0"
66
readme = "README.md"
7+
rust-version = "1.56"
8+
edition = "2021"
79

810
description = "FixedBitSet is a simple bitset collection"
911
documentation = "https://docs.rs/fixedbitset/"
@@ -21,7 +23,7 @@ no-dev-version = true
2123
tag-name = "{{version}}"
2224

2325
[dependencies]
24-
serde = { version = "1.0", features = ["derive"], optional = true }
26+
serde = { version = "1.0", optional = true }
2527

2628
[dev-dependencies]
2729
serde_json = "1.0"

benches/benches/benches.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,12 @@ fn count_ones(c: &mut Criterion) {
195195

196196
criterion_group!(
197197
benches,
198-
bitchange,
199198
iter_ones_using_contains_all_zeros,
200199
iter_ones_using_contains_all_ones,
201200
iter_ones_all_zeros,
202201
iter_ones_sparse,
203202
iter_ones_all_ones,
203+
iter_ones_all_ones_rev,
204204
insert_range,
205205
insert,
206206
intersect_with,

src/lib.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mod range;
2828
#[cfg(feature = "serde")]
2929
extern crate serde;
3030
#[cfg(feature = "serde")]
31-
use serde::{Deserialize, Serialize};
31+
mod serde_impl;
3232

3333
use std::fmt::Write;
3434
use std::fmt::{Binary, Display, Error, Formatter};
@@ -38,7 +38,10 @@ use std::cmp::{Ord, Ordering};
3838
use std::iter::{Chain, ExactSizeIterator, FromIterator, FusedIterator};
3939
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index};
4040

41-
const BITS: usize = std::mem::size_of::<Block>() * 8;
41+
pub(crate) const BITS: usize = std::mem::size_of::<Block>() * 8;
42+
#[cfg(feature = "serde")]
43+
pub(crate) const BYTES: usize = std::mem::size_of::<Block>();
44+
4245
pub type Block = usize;
4346

4447
#[inline]
@@ -55,11 +58,10 @@ fn div_rem(x: usize) -> (usize, usize) {
5558
/// Derived traits depend on both the zeros and ones, so [0,1] is not equal to
5659
/// [0,1,0].
5760
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
58-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5961
pub struct FixedBitSet {
60-
data: Vec<Block>,
62+
pub(crate) data: Vec<Block>,
6163
/// length in bits
62-
length: usize,
64+
pub(crate) length: usize,
6365
}
6466

6567
impl FixedBitSet {
@@ -2022,16 +2024,17 @@ mod tests {
20222024
assert_eq!(format!("{:#}", fb), "0b00101000");
20232025
}
20242026

2027+
// TODO: Rewite this test to be platform agnostic.
20252028
#[test]
2026-
#[cfg(feature = "serde")]
2029+
#[cfg(all(feature = "serde", target_pointer_width = "64"))]
20272030
fn test_serialize() {
20282031
let mut fb = FixedBitSet::with_capacity(10);
20292032
fb.put(2);
20302033
fb.put(3);
20312034
fb.put(6);
20322035
fb.put(8);
20332036
let serialized = serde_json::to_string(&fb).unwrap();
2034-
assert_eq!(r#"{"data":[332],"length":10}"#, serialized);
2037+
assert_eq!(r#"{"length":10,"data":[76,1,0,0,0,0,0,0]}"#, serialized);
20352038
}
20362039
}
20372040

src/range.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(not(feature = "std"))]
2+
use core as std;
13
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
24

35
// Taken from https://github.com/bluss/odds/blob/master/src/range.rs.

src/serde_impl.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#[cfg(not(feature = "std"))]
2+
use core as std;
3+
4+
use crate::{FixedBitSet, BYTES};
5+
use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
6+
use serde::ser::{Serialize, SerializeStruct, Serializer};
7+
use std::{convert::TryFrom, fmt};
8+
9+
struct BitSetByteSerializer<'a>(&'a FixedBitSet);
10+
11+
impl Serialize for FixedBitSet {
12+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
13+
where
14+
S: Serializer,
15+
{
16+
let mut struct_serializer = serializer.serialize_struct("FixedBitset", 2)?;
17+
struct_serializer.serialize_field("length", &(self.length as u64))?;
18+
struct_serializer.serialize_field("data", &BitSetByteSerializer(self))?;
19+
struct_serializer.end()
20+
}
21+
}
22+
23+
impl<'a> Serialize for BitSetByteSerializer<'a> {
24+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25+
where
26+
S: Serializer,
27+
{
28+
let len = self.0.data.len() * BYTES;
29+
// PERF: Figure out a way to do this without allocating.
30+
let mut temp = Vec::with_capacity(len);
31+
for block in &self.0.data {
32+
temp.extend(&block.to_le_bytes());
33+
}
34+
serializer.serialize_bytes(&temp)
35+
}
36+
}
37+
38+
impl<'de> Deserialize<'de> for FixedBitSet {
39+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
40+
where
41+
D: Deserializer<'de>,
42+
{
43+
enum Field {
44+
Length,
45+
Data,
46+
}
47+
48+
impl<'de> Deserialize<'de> for Field {
49+
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
50+
where
51+
D: Deserializer<'de>,
52+
{
53+
struct FieldVisitor;
54+
55+
impl<'de> Visitor<'de> for FieldVisitor {
56+
type Value = Field;
57+
58+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
59+
formatter.write_str("`length` or `data`")
60+
}
61+
62+
fn visit_str<E>(self, value: &str) -> Result<Field, E>
63+
where
64+
E: de::Error,
65+
{
66+
match value {
67+
"length" => Ok(Field::Length),
68+
"data" => Ok(Field::Data),
69+
_ => Err(de::Error::unknown_field(value, FIELDS)),
70+
}
71+
}
72+
}
73+
74+
deserializer.deserialize_identifier(FieldVisitor)
75+
}
76+
}
77+
78+
struct FixedBitSetVisitor;
79+
80+
impl<'de> Visitor<'de> for FixedBitSetVisitor {
81+
type Value = FixedBitSet;
82+
83+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
84+
formatter.write_str("struct Duration")
85+
}
86+
87+
fn visit_seq<V>(self, mut seq: V) -> Result<FixedBitSet, V::Error>
88+
where
89+
V: SeqAccess<'de>,
90+
{
91+
let length = seq
92+
.next_element()?
93+
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
94+
let data = seq
95+
.next_element()?
96+
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
97+
Ok(FixedBitSet { length, data })
98+
}
99+
100+
fn visit_map<V>(self, mut map: V) -> Result<FixedBitSet, V::Error>
101+
where
102+
V: MapAccess<'de>,
103+
{
104+
let mut length = None;
105+
let mut temp: Option<&[u8]> = None;
106+
while let Some(key) = map.next_key()? {
107+
match key {
108+
Field::Length => {
109+
if length.is_some() {
110+
return Err(de::Error::duplicate_field("length"));
111+
}
112+
length = Some(map.next_value()?);
113+
}
114+
Field::Data => {
115+
if temp.is_some() {
116+
return Err(de::Error::duplicate_field("data"));
117+
}
118+
temp = Some(map.next_value()?);
119+
}
120+
}
121+
}
122+
let length = length.ok_or_else(|| de::Error::missing_field("length"))?;
123+
let temp = temp.ok_or_else(|| de::Error::missing_field("data"))?;
124+
let block_len = length / BYTES + 1;
125+
let mut data = Vec::with_capacity(block_len);
126+
for chunk in temp.chunks(BYTES) {
127+
match <&[u8; BYTES]>::try_from(chunk) {
128+
Ok(bytes) => data.push(usize::from_le_bytes(*bytes)),
129+
Err(_) => {
130+
let mut bytes = [0u8; BYTES];
131+
bytes[0..BYTES].copy_from_slice(chunk);
132+
data.push(usize::from_le_bytes(bytes));
133+
}
134+
}
135+
}
136+
Ok(FixedBitSet { length, data })
137+
}
138+
}
139+
140+
const FIELDS: &'static [&'static str] = &["length", "data"];
141+
deserializer.deserialize_struct("Duration", FIELDS, FixedBitSetVisitor)
142+
}
143+
}

0 commit comments

Comments
 (0)