use std::io::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()
}
}
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<()> {
writer.write_all(
&(u8::try_from(self.len()).map_err(|_| std::io::ErrorKind::InvalidInput)?)
.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<()> {
writer.write_all(
&(u16::try_from(self.len()).map_err(|_| std::io::ErrorKind::InvalidInput)?)
.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(input: &mut &[u8]) -> std::io::Result<Self> {
let len: u32 = L::deserialize(input)?.into();
let vec = if len == 0 {
Vec::new()
} else if let Some(vec_bytes) = T::vec_from_bytes(len, input)? {
vec_bytes
} else {
let mut result = Vec::with_capacity(hint::cautious::<T>(len));
for _ in 0..len {
result.push(T::deserialize(input)?);
}
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(())
}
#[cfg(test)]
mod test {
use super::*;
mod deserialize {
use super::*;
#[test]
fn test_length_u8_type_u8() {
let mut input = &[
0x02, 0x05, 0x09, ][..];
let small_vec: SmallVec<u8, u8> = SmallVec::deserialize(&mut input).unwrap();
assert_eq!(small_vec.0, vec![5, 9]);
}
#[test]
fn test_length_u8_type_u32() {
let mut input = &[
0x02, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, ][..];
let small_vec: SmallVec<u8, u32> = SmallVec::deserialize(&mut input).unwrap();
assert_eq!(small_vec.0, vec![5, 9]);
}
#[test]
fn test_length_u8_type_pubkey() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let mut input = &[
&[0x02], &pubkey1.try_to_vec().unwrap()[..],
&pubkey2.try_to_vec().unwrap()[..],
]
.concat()[..];
let small_vec: SmallVec<u8, Pubkey> = SmallVec::deserialize(&mut input).unwrap();
assert_eq!(small_vec.0, vec![pubkey1, pubkey2]);
}
#[test]
fn test_length_u16_type_u8() {
let mut input = &[
0x02, 0x00, 0x05, 0x09, ][..];
let small_vec: SmallVec<u16, u8> = SmallVec::deserialize(&mut input).unwrap();
assert_eq!(small_vec.0, vec![5, 9]);
}
#[test]
fn test_length_u16_type_pubkey() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let mut input = &[
&[0x02, 0x00], &pubkey1.try_to_vec().unwrap()[..],
&pubkey2.try_to_vec().unwrap()[..],
]
.concat()[..];
let small_vec: SmallVec<u16, Pubkey> = SmallVec::deserialize(&mut input).unwrap();
assert_eq!(small_vec.0, vec![pubkey1, pubkey2]);
}
}
mod serialize {
use super::*;
#[test]
fn test_length_u8_type_u8() {
let small_vec = SmallVec::<u8, u8>::from(vec![3, 5]);
let mut output = vec![];
small_vec.serialize(&mut output).unwrap();
assert_eq!(
output,
vec![
0x02, 0x03, 0x05, ]
);
}
#[test]
fn test_length_u8_type_u32() {
let small_vec = SmallVec::<u8, u32>::from(vec![3, 5]);
let mut output = vec![];
small_vec.serialize(&mut output).unwrap();
assert_eq!(
output,
vec![
0x02, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, ]
);
}
#[test]
fn test_length_u8_type_pubkey() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let small_vec = SmallVec::<u8, Pubkey>::from(vec![pubkey1, pubkey2]);
let mut output = vec![];
small_vec.serialize(&mut output).unwrap();
assert_eq!(
output,
[
&[0x02], &pubkey1.to_bytes()[..],
&pubkey2.to_bytes()[..],
]
.concat()[..]
);
}
#[test]
fn test_length_u16_type_u8() {
let small_vec = SmallVec::<u16, u8>::from(vec![3, 5]);
let mut output = vec![];
small_vec.serialize(&mut output).unwrap();
assert_eq!(
output,
vec![
0x02, 0x00, 0x03, 0x05, ]
);
}
#[test]
fn test_length_u16_type_pubkey() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let small_vec = SmallVec::<u16, Pubkey>::from(vec![pubkey1, pubkey2]);
let mut output = vec![];
small_vec.serialize(&mut output).unwrap();
assert_eq!(
output,
[
&[0x02, 0x00], &pubkey1.to_bytes()[..],
&pubkey2.to_bytes()[..],
]
.concat()[..]
);
}
}
}