use {
crate::{
list::{ListView, ListViewMut, ListViewReadOnly},
primitives::PodU32,
},
bytemuck::Pod,
solana_program_error::ProgramError,
};
#[deprecated(
since = "0.6.0",
note = "This struct will be removed in the next major release (1.0.0). Please use `ListView` instead."
)]
#[allow(deprecated)]
pub struct PodSlice<'data, T: Pod> {
inner: ListViewReadOnly<'data, T, PodU32>,
}
#[allow(deprecated)]
impl<'data, T: Pod> PodSlice<'data, T> {
pub fn unpack<'a>(data: &'a [u8]) -> Result<Self, ProgramError>
where
'a: 'data,
{
let inner = ListView::<T, PodU32>::unpack(data)?;
Ok(Self { inner })
}
pub fn data(&self) -> &[T] {
let len = self.inner.len();
&self.inner.data[..len]
}
pub fn size_of(num_items: usize) -> Result<usize, ProgramError> {
ListView::<T, PodU32>::size_of(num_items)
}
}
#[deprecated(
since = "0.6.0",
note = "This struct will be removed in the next major release (1.0.0). Please use `ListView` instead."
)]
pub struct PodSliceMut<'data, T: Pod> {
inner: ListViewMut<'data, T, PodU32>,
}
#[allow(deprecated)]
impl<'data, T: Pod> PodSliceMut<'data, T> {
pub fn unpack<'a>(data: &'a mut [u8]) -> Result<Self, ProgramError>
where
'a: 'data,
{
let inner = ListView::<T, PodU32>::unpack_mut(data)?;
Ok(Self { inner })
}
pub fn init<'a>(data: &'a mut [u8]) -> Result<Self, ProgramError>
where
'a: 'data,
{
let inner = ListView::<T, PodU32>::init(data)?;
Ok(Self { inner })
}
pub fn push(&mut self, t: T) -> Result<(), ProgramError> {
self.inner.push(t)
}
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use {
super::*,
crate::{bytemuck::pod_slice_to_bytes, error::PodSliceError},
bytemuck_derive::{Pod, Zeroable},
};
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
struct TestStruct {
test_field: u8,
test_pubkey: [u8; 32],
}
const LENGTH_SIZE: usize = std::mem::size_of::<PodU32>();
#[test]
fn test_pod_slice() {
let test_field_bytes = [0];
let test_pubkey_bytes = [1; 32];
let len_bytes = [2, 0, 0, 0];
let mut data_bytes = [0; 66];
data_bytes[0..1].copy_from_slice(&test_field_bytes);
data_bytes[1..33].copy_from_slice(&test_pubkey_bytes);
data_bytes[33..34].copy_from_slice(&test_field_bytes);
data_bytes[34..66].copy_from_slice(&test_pubkey_bytes);
let mut pod_slice_bytes = [0; 70];
pod_slice_bytes[0..4].copy_from_slice(&len_bytes);
pod_slice_bytes[4..70].copy_from_slice(&data_bytes);
let pod_slice = PodSlice::<TestStruct>::unpack(&pod_slice_bytes).unwrap();
let pod_slice_data = pod_slice.data();
assert_eq!(pod_slice.inner.len(), 2);
assert_eq!(pod_slice_to_bytes(pod_slice.data()), data_bytes);
assert_eq!(pod_slice_data[0].test_field, test_field_bytes[0]);
assert_eq!(pod_slice_data[0].test_pubkey, test_pubkey_bytes);
assert_eq!(PodSlice::<TestStruct>::size_of(1).unwrap(), 37);
}
#[test]
fn test_pod_slice_buffer_too_large() {
let data_len = LENGTH_SIZE + std::mem::size_of::<TestStruct>() + 6;
let mut pod_slice_bytes = vec![1; data_len];
pod_slice_bytes[0..4].copy_from_slice(&[1, 0, 0, 0]);
let err = PodSlice::<TestStruct>::unpack(&pod_slice_bytes)
.err()
.unwrap();
assert!(matches!(err, ProgramError::InvalidArgument));
}
#[test]
fn test_pod_slice_buffer_larger_than_length_value() {
let length: u32 = 12;
let length_le = length.to_le_bytes();
let data_len = PodSlice::<TestStruct>::size_of(length as usize + 2).unwrap();
let mut data = vec![0; data_len];
data[..LENGTH_SIZE].copy_from_slice(&length_le);
let pod_slice = PodSlice::<TestStruct>::unpack(&data).unwrap();
let pod_slice_len = pod_slice.inner.len() as u32;
let data = pod_slice.data();
let data_vec = data.to_vec();
assert_eq!(pod_slice_len, length);
assert_eq!(data.len(), length as usize);
assert_eq!(data_vec.len(), length as usize);
}
#[test]
fn test_pod_slice_buffer_too_small() {
let pod_slice_bytes = [1; 36];
let err = PodSlice::<TestStruct>::unpack(&pod_slice_bytes)
.err()
.unwrap();
assert!(matches!(err, ProgramError::InvalidArgument));
}
#[test]
fn test_pod_slice_buffer_shorter_than_length_value() {
let length: u32 = 12;
let length_le = length.to_le_bytes();
for num_items in 0..length {
let data_len = PodSlice::<TestStruct>::size_of(num_items as usize).unwrap();
let mut data = vec![0; data_len];
data[..LENGTH_SIZE].copy_from_slice(&length_le);
let err = PodSlice::<TestStruct>::unpack(&data).err().unwrap();
assert_eq!(
err,
PodSliceError::BufferTooSmall.into(),
"Expected an `PodSliceError::BufferTooSmall` error"
);
}
}
#[test]
fn test_pod_slice_mut() {
let mut pod_slice_bytes = [0; 70];
let len_bytes = [1, 0, 0, 0];
pod_slice_bytes[0..4].copy_from_slice(&len_bytes);
let mut pod_slice = PodSliceMut::<TestStruct>::unpack(&mut pod_slice_bytes).unwrap();
assert_eq!(pod_slice.inner.len(), 1);
pod_slice.push(TestStruct::default()).unwrap();
assert_eq!(pod_slice.inner.len(), 2);
let err = pod_slice
.push(TestStruct::default())
.expect_err("Expected an `PodSliceError::BufferTooSmall` error");
assert_eq!(err, PodSliceError::BufferTooSmall.into());
}
}