use super::{
atomic::AtomicFixedVec,
traits::{Storable, Word},
FixedVec,
};
use dsi_bitstream::prelude::Endianness;
use num_traits::ToPrimitive;
use serde::{
de,
ser::{Serializer},
Deserialize, Deserializer, Serialize,
};
use std::sync::atomic::Ordering;
#[derive(Deserialize)]
#[serde(bound(deserialize = "B: Deserialize<'de>"))]
struct FixedVecProxy<B> {
bits: B,
len: usize,
bit_width: usize,
}
impl<T, W, E, B> Serialize for FixedVec<T, W, E, B>
where
T: Storable<W>,
W: Word,
E: Endianness,
B: AsRef<[W]>,
W: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Serialize)]
struct SerializeProxy<'a, W: Word> {
bits: &'a [W],
len: usize,
bit_width: usize,
}
let proxy = SerializeProxy {
bits: self.bits.as_ref(),
len: self.len,
bit_width: self.bit_width,
};
proxy.serialize(serializer)
}
}
impl<'de, T, W, E> Deserialize<'de> for FixedVec<T, W, E, Vec<W>>
where
T: Storable<W>,
W: Word + Deserialize<'de>,
E: Endianness,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let proxy = FixedVecProxy::<Vec<W>>::deserialize(deserializer)?;
let word_size_bits = std::mem::size_of::<W>() * 8;
if proxy.bit_width > word_size_bits {
return Err(de::Error::custom(format!(
"Deserialized bit_width ({}) cannot be greater than the word size ({})",
proxy.bit_width, word_size_bits
)));
}
let required_bits = proxy.len.saturating_mul(proxy.bit_width);
let required_data_words = required_bits.div_ceil(word_size_bits);
if proxy.bits.len() < required_data_words {
return Err(de::Error::custom(format!(
"Deserialized buffer is too small. It has {} words, but at least {} are required.",
proxy.bits.len(),
required_data_words
)));
}
Ok(unsafe { FixedVec::new_unchecked(proxy.bits, proxy.len, proxy.bit_width) })
}
}
#[derive(Serialize, Deserialize)]
struct AtomicFixedVecProxy {
storage: Vec<u64>,
len: usize,
bit_width: usize,
}
impl<T> Serialize for AtomicFixedVec<T>
where
T: Storable<u64> + Copy + ToPrimitive,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let storage_plain: Vec<u64> = self
.as_slice()
.iter()
.map(|atomic| atomic.load(Ordering::Relaxed))
.collect();
let proxy = AtomicFixedVecProxy {
storage: storage_plain,
len: self.len(),
bit_width: self.bit_width(),
};
proxy.serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for AtomicFixedVec<T>
where
T: Storable<u64> + Copy + ToPrimitive,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let proxy = AtomicFixedVecProxy::deserialize(deserializer)?;
let atomic_vec = AtomicFixedVec::<T>::new(proxy.bit_width, proxy.len)
.map_err(|err| de::Error::custom(err.to_string()))?;
let expected_words = atomic_vec.as_slice().len();
if proxy.storage.len() != expected_words {
return Err(de::Error::custom(format!(
"Mismatched storage length: expected {}, got {}",
expected_words,
proxy.storage.len()
)));
}
let storage_slice = atomic_vec.as_slice();
for (i, val) in proxy.storage.into_iter().enumerate() {
storage_slice[i].store(val, Ordering::Relaxed);
}
Ok(atomic_vec)
}
}