use std::io::{Read, Write};
use std::marker::PhantomData;
use anchor_lang::prelude::*;
#[derive(Clone, Debug, Default)]
pub struct SmallVec<L, T>(Vec<T>, PhantomData<L>);
impl<L, T> SmallVec<L, T> {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<L, T> From<SmallVec<L, T>> for Vec<T> {
fn from(val: SmallVec<L, T>) -> Self {
val.0
}
}
impl<L, T> From<Vec<T>> for SmallVec<L, T> {
fn from(val: Vec<T>) -> Self {
Self(val, PhantomData)
}
}
impl<T: AnchorSerialize> AnchorSerialize for SmallVec<u8, T> {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
let len = u8::try_from(self.len()).map_err(|_| std::io::ErrorKind::InvalidInput)?;
writer.write_all(&len.to_le_bytes())?;
serialize_slice(&self.0, writer)
}
}
impl<T: AnchorSerialize> AnchorSerialize for SmallVec<u16, T> {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
let len = u16::try_from(self.len()).map_err(|_| std::io::ErrorKind::InvalidInput)?;
writer.write_all(&len.to_le_bytes())?;
serialize_slice(&self.0, writer)
}
}
impl<L, T> AnchorDeserialize for SmallVec<L, T>
where
L: AnchorDeserialize + Into<u32>,
T: AnchorDeserialize,
{
fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
let len: u32 = L::deserialize_reader(reader)?.into();
let vec = if len == 0 {
Vec::new()
} else if let Some(vec_bytes) = T::vec_from_reader(len, reader)? {
vec_bytes
} else {
let mut result = Vec::with_capacity(hint::cautious::<T>(len));
for _ in 0..len {
result.push(T::deserialize_reader(reader)?);
}
result
};
Ok(SmallVec(vec, PhantomData))
}
}
mod hint {
#[inline]
pub fn cautious<T>(hint: u32) -> usize {
let el_size = core::mem::size_of::<T>() as u32;
core::cmp::max(core::cmp::min(hint, 4096 / el_size), 1) as usize
}
}
#[inline]
fn serialize_slice<T: AnchorSerialize, W: Write>(
data: &[T],
writer: &mut W,
) -> std::io::Result<()> {
if let Some(u8_slice) = T::u8_slice(data) {
writer.write_all(u8_slice)?;
} else {
for item in data {
item.serialize(writer)?;
}
}
Ok(())
}