use crate::Error;
use alloc::vec::Vec;
use core::fmt;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PackedI16<const N: usize>(Vec<i16>);
impl<const N: usize> PackedI16<N> {
pub fn new(values: Vec<i16>) -> Result<Self, Error> {
if values.len() > N {
Err(Error::Limit)
} else {
Ok(Self(values))
}
}
pub fn as_slice(&self) -> &[i16] {
&self.0
}
pub fn into_vec(self) -> Vec<i16> {
self.0
}
}
impl<const N: usize> Serialize for PackedI16<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[cfg(target_endian = "little")]
{
serializer.serialize_bytes(bytemuck::must_cast_slice(&self.0))
}
#[cfg(target_endian = "big")]
{
let mut bytes = Vec::new();
bytes
.try_reserve_exact(self.0.len() * 2)
.map_err(|_| serde::ser::Error::custom("allocation"))?;
bytes.extend(self.0.iter().flat_map(|value| value.to_le_bytes()));
serializer.serialize_bytes(&bytes)
}
}
}
impl<'de, const N: usize> Deserialize<'de> for PackedI16<N> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor<const N: usize>;
impl<const N: usize> de::Visitor<'_> for Visitor<N> {
type Value = PackedI16<N>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("bounded packed little-endian i16 words")
}
fn visit_bytes<E: de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
if !bytes.len().is_multiple_of(2) || bytes.len() / 2 > N {
return Err(E::custom("invalid packed length"));
}
let mut values = Vec::new();
values
.try_reserve_exact(bytes.len() / 2)
.map_err(|_| E::custom("allocation"))?;
values.extend(
bytes
.as_chunks::<2>()
.0
.iter()
.map(|word| i16::from_le_bytes(*word)),
);
Ok(PackedI16(values))
}
}
deserializer.deserialize_bytes(Visitor::<N>)
}
}