151 lines
5.3 KiB
Rust
151 lines
5.3 KiB
Rust
#[cfg(not(feature = "std"))]
|
|
use core as std;
|
|
|
|
use crate::{Block, FixedBitSet, BYTES};
|
|
use alloc::vec::Vec;
|
|
use core::{convert::TryFrom, fmt};
|
|
use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
|
|
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
|
|
|
struct BitSetByteSerializer<'a>(&'a FixedBitSet);
|
|
|
|
impl Serialize for FixedBitSet {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut struct_serializer = serializer.serialize_struct("FixedBitset", 2)?;
|
|
struct_serializer.serialize_field("length", &(self.length as u64))?;
|
|
struct_serializer.serialize_field("data", &BitSetByteSerializer(self))?;
|
|
struct_serializer.end()
|
|
}
|
|
}
|
|
|
|
impl<'a> Serialize for BitSetByteSerializer<'a> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let len = self.0.as_slice().len() * BYTES;
|
|
// PERF: Figure out a way to do this without allocating.
|
|
let mut temp = Vec::with_capacity(len);
|
|
for block in self.0.as_slice() {
|
|
temp.extend(&block.to_le_bytes());
|
|
}
|
|
serializer.serialize_bytes(&temp)
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for FixedBitSet {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
enum Field {
|
|
Length,
|
|
Data,
|
|
}
|
|
|
|
fn bytes_to_data(length: usize, input: &[u8]) -> Vec<Block> {
|
|
let block_len = length / BYTES + 1;
|
|
let mut data = Vec::with_capacity(block_len);
|
|
for chunk in input.chunks(BYTES) {
|
|
match <&[u8; BYTES]>::try_from(chunk) {
|
|
Ok(bytes) => data.push(usize::from_le_bytes(*bytes)),
|
|
Err(_) => {
|
|
let mut bytes = [0u8; BYTES];
|
|
bytes[0..BYTES].copy_from_slice(chunk);
|
|
data.push(usize::from_le_bytes(bytes));
|
|
}
|
|
}
|
|
}
|
|
data
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Field {
|
|
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct FieldVisitor;
|
|
|
|
impl<'de> Visitor<'de> for FieldVisitor {
|
|
type Value = Field;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("`length` or `data`")
|
|
}
|
|
|
|
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
match value {
|
|
"length" => Ok(Field::Length),
|
|
"data" => Ok(Field::Data),
|
|
_ => Err(de::Error::unknown_field(value, FIELDS)),
|
|
}
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_identifier(FieldVisitor)
|
|
}
|
|
}
|
|
|
|
struct FixedBitSetVisitor;
|
|
|
|
impl<'de> Visitor<'de> for FixedBitSetVisitor {
|
|
type Value = FixedBitSet;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("struct Duration")
|
|
}
|
|
|
|
fn visit_seq<V>(self, mut seq: V) -> Result<FixedBitSet, V::Error>
|
|
where
|
|
V: SeqAccess<'de>,
|
|
{
|
|
let length = seq
|
|
.next_element()?
|
|
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
|
let data: &[u8] = seq
|
|
.next_element()?
|
|
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
|
let data = bytes_to_data(length, data);
|
|
Ok(FixedBitSet::with_capacity_and_blocks(length, data))
|
|
}
|
|
|
|
fn visit_map<V>(self, mut map: V) -> Result<FixedBitSet, V::Error>
|
|
where
|
|
V: MapAccess<'de>,
|
|
{
|
|
let mut length = None;
|
|
let mut temp: Option<&[u8]> = None;
|
|
while let Some(key) = map.next_key()? {
|
|
match key {
|
|
Field::Length => {
|
|
if length.is_some() {
|
|
return Err(de::Error::duplicate_field("length"));
|
|
}
|
|
length = Some(map.next_value()?);
|
|
}
|
|
Field::Data => {
|
|
if temp.is_some() {
|
|
return Err(de::Error::duplicate_field("data"));
|
|
}
|
|
temp = Some(map.next_value()?);
|
|
}
|
|
}
|
|
}
|
|
let length = length.ok_or_else(|| de::Error::missing_field("length"))?;
|
|
let data = temp.ok_or_else(|| de::Error::missing_field("data"))?;
|
|
let data = bytes_to_data(length, data);
|
|
Ok(FixedBitSet::with_capacity_and_blocks(length, data))
|
|
}
|
|
}
|
|
|
|
const FIELDS: &'static [&'static str] = &["length", "data"];
|
|
deserializer.deserialize_struct("Duration", FIELDS, FixedBitSetVisitor)
|
|
}
|
|
}
|