diff --git a/Cargo.lock b/Cargo.lock index 32f18c7..d945180 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -722,6 +722,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pinocchio" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b971851087bc3699b001954ad02389d50c41405ece3548cbcafc88b3e20017a" + [[package]] name = "polyval" version = "0.6.2" @@ -1571,6 +1577,7 @@ dependencies = [ "num-derive", "num-traits", "num_enum", + "pinocchio", "serde", "serde_json", "solana-program-error", diff --git a/pod/Cargo.toml b/pod/Cargo.toml index 543c622..351d683 100644 --- a/pod/Cargo.toml +++ b/pod/Cargo.toml @@ -18,6 +18,7 @@ bytemuck_derive = { version = "1.10.1" } num-derive = "0.4" num_enum = "0.7" num-traits = "0.2" +pinocchio = "0.9.2" serde = { version = "1.0.228", optional = true } solana-program-error = "3.0.0" solana-program-option = "3.0.0" diff --git a/pod/src/bytemuck.rs b/pod/src/bytemuck.rs index 744553d..5c86171 100644 --- a/pod/src/bytemuck.rs +++ b/pod/src/bytemuck.rs @@ -1,6 +1,6 @@ //! wrappers for `bytemuck` functions -use {bytemuck::Pod, solana_program_error::ProgramError}; +use {crate::error::SplPodError, bytemuck::Pod}; /// On-chain size of a `Pod` type pub const fn pod_get_packed_len() -> usize { @@ -13,8 +13,8 @@ pub fn pod_bytes_of(t: &T) -> &[u8] { } /// Convert a slice of bytes into a `Pod` (zero copy) -pub fn pod_from_bytes(bytes: &[u8]) -> Result<&T, ProgramError> { - bytemuck::try_from_bytes(bytes).map_err(|_| ProgramError::InvalidArgument) +pub fn pod_from_bytes(bytes: &[u8]) -> Result<&T, SplPodError> { + Ok(bytemuck::try_from_bytes(bytes)?) } /// Maybe convert a slice of bytes into a `Pod` (zero copy) @@ -22,29 +22,27 @@ pub fn pod_from_bytes(bytes: &[u8]) -> Result<&T, ProgramError> { /// Returns `None` if the slice is empty, or else `Err` if input length is not /// equal to `pod_get_packed_len::()`. /// This function exists primarily because `Option` is not a `Pod`. -pub fn pod_maybe_from_bytes(bytes: &[u8]) -> Result, ProgramError> { +pub fn pod_maybe_from_bytes(bytes: &[u8]) -> Result, SplPodError> { if bytes.is_empty() { Ok(None) } else { - bytemuck::try_from_bytes(bytes) - .map(Some) - .map_err(|_| ProgramError::InvalidArgument) + Ok(bytemuck::try_from_bytes(bytes).map(Some)?) } } /// Convert a slice of bytes into a mutable `Pod` (zero copy) -pub fn pod_from_bytes_mut(bytes: &mut [u8]) -> Result<&mut T, ProgramError> { - bytemuck::try_from_bytes_mut(bytes).map_err(|_| ProgramError::InvalidArgument) +pub fn pod_from_bytes_mut(bytes: &mut [u8]) -> Result<&mut T, SplPodError> { + Ok(bytemuck::try_from_bytes_mut(bytes)?) } /// Convert a slice of bytes into a `Pod` slice (zero copy) -pub fn pod_slice_from_bytes(bytes: &[u8]) -> Result<&[T], ProgramError> { - bytemuck::try_cast_slice(bytes).map_err(|_| ProgramError::InvalidArgument) +pub fn pod_slice_from_bytes(bytes: &[u8]) -> Result<&[T], SplPodError> { + Ok(bytemuck::try_cast_slice(bytes)?) } /// Convert a slice of bytes into a mutable `Pod` slice (zero copy) -pub fn pod_slice_from_bytes_mut(bytes: &mut [u8]) -> Result<&mut [T], ProgramError> { - bytemuck::try_cast_slice_mut(bytes).map_err(|_| ProgramError::InvalidArgument) +pub fn pod_slice_from_bytes_mut(bytes: &mut [u8]) -> Result<&mut [T], SplPodError> { + Ok(bytemuck::try_cast_slice_mut(bytes)?) } /// Convert a `Pod` slice into a single slice of bytes diff --git a/pod/src/error.rs b/pod/src/error.rs index 7e1a454..2619122 100644 --- a/pod/src/error.rs +++ b/pod/src/error.rs @@ -1,5 +1,7 @@ //! Error types +use pinocchio::program_error::ProgramError as PinocchioProgramError; use { + bytemuck::PodCastError, solana_program_error::{ProgramError, ToStr}, std::num::TryFromIntError, }; @@ -15,7 +17,7 @@ use { num_enum::TryFromPrimitive, num_derive::FromPrimitive, )] -pub enum PodSliceError { +pub enum SplPodError { /// Error in checked math operation #[error("Error in checked math operation")] CalculationFailure, @@ -25,30 +27,90 @@ pub enum PodSliceError { /// Provided byte buffer too large for expected type #[error("Provided byte buffer too large for expected type")] BufferTooLarge, + /// Index out of range for list operation + #[error("Index out of range for list operation")] + IndexOutOfRange, + /// Type used as a length prefix has invalid alignment + #[error("Type used as a length prefix has invalid alignment")] + InvalidLengthTypeAlignment, + /// A `PodCast` operation from `bytemuck` failed + #[error("A `PodCast` operation from `bytemuck` failed")] + PodCast, /// An integer conversion failed because the value was out of range for the target type #[error("An integer conversion failed because the value was out of range for the target type")] ValueOutOfRange, } -impl From for ProgramError { - fn from(e: PodSliceError) -> Self { +impl From for ProgramError { + fn from(e: SplPodError) -> Self { ProgramError::Custom(e as u32) } } -impl ToStr for PodSliceError { +impl ToStr for SplPodError { fn to_str(&self) -> &'static str { match self { - PodSliceError::CalculationFailure => "Error in checked math operation", - PodSliceError::BufferTooSmall => "Provided byte buffer too small for expected type", - PodSliceError::BufferTooLarge => "Provided byte buffer too large for expected type", - PodSliceError::ValueOutOfRange => "An integer conversion failed because the value was out of range for the target type" + SplPodError::CalculationFailure => "Error in checked math operation", + SplPodError::BufferTooSmall => "Provided byte buffer too small for expected type", + SplPodError::BufferTooLarge => "Provided byte buffer too large for expected type", + SplPodError::IndexOutOfRange => "Index out of range for list operation", + SplPodError::InvalidLengthTypeAlignment => "Type used as a length prefix has invalid alignment", + SplPodError::PodCast => "A `PodCast` operation from `bytemuck` failed", + SplPodError::ValueOutOfRange => "An integer conversion failed because the value was out of range for the target type", } } } -impl From for PodSliceError { +impl From for SplPodError { + fn from(_: PodCastError) -> Self { + SplPodError::PodCast + } +} + +impl From for SplPodError { fn from(_: TryFromIntError) -> Self { - PodSliceError::ValueOutOfRange + SplPodError::ValueOutOfRange + } +} + +impl From for PinocchioProgramError { + fn from(e: SplPodError) -> Self { + PinocchioProgramError::Custom(e as u32) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::list::ListView; + use pinocchio::program_error::ProgramError as PinocchioProgramError; + + fn raises_solana_err() -> Result<(), ProgramError> { + ListView::::size_of(usize::MAX)?; // raises err + Ok(()) + } + + fn raises_pino_err() -> Result<(), PinocchioProgramError> { + ListView::::size_of(usize::MAX)?; // raises err + Ok(()) + } + + #[test] + fn test_from_pod_slice_error_for_solana_program_error() { + let result = raises_solana_err(); + assert!(result.is_err()); + let solana_err = result.unwrap_err(); + let expected_err: ProgramError = SplPodError::CalculationFailure.into(); + assert_eq!(solana_err, expected_err); + } + + #[test] + fn test_from_pod_slice_error_for_pinocchio_program_error() { + let result = raises_pino_err(); + assert!(result.is_err()); + let pinocchio_err = result.unwrap_err(); + let expected_solana_err: ProgramError = SplPodError::CalculationFailure.into(); + let expected_pinocchio_err: PinocchioProgramError = u64::from(expected_solana_err).into(); + assert_eq!(pinocchio_err, expected_pinocchio_err); } } diff --git a/pod/src/list/list_trait.rs b/pod/src/list/list_trait.rs index c7ebf37..d2957ab 100644 --- a/pod/src/list/list_trait.rs +++ b/pod/src/list/list_trait.rs @@ -1,7 +1,6 @@ use { - crate::{list::ListView, pod_length::PodLength}, + crate::{error::SplPodError, list::ListView, pod_length::PodLength}, bytemuck::Pod, - solana_program_error::ProgramError, std::ops::Deref, }; @@ -17,12 +16,12 @@ pub trait List: Deref { fn capacity(&self) -> usize; /// Returns the number of **bytes currently occupied** by the live elements - fn bytes_used(&self) -> Result { + fn bytes_used(&self) -> Result { ListView::::size_of(self.len()) } /// Returns the number of **bytes reserved** by the entire backing buffer. - fn bytes_allocated(&self) -> Result { + fn bytes_allocated(&self) -> Result { ListView::::size_of(self.capacity()) } } diff --git a/pod/src/list/list_view.rs b/pod/src/list/list_view.rs index 23a6439..675f3a2 100644 --- a/pod/src/list/list_view.rs +++ b/pod/src/list/list_view.rs @@ -5,13 +5,12 @@ use { bytemuck::{ pod_from_bytes, pod_from_bytes_mut, pod_slice_from_bytes, pod_slice_from_bytes_mut, }, - error::PodSliceError, + error::SplPodError, list::{list_view_mut::ListViewMut, list_view_read_only::ListViewReadOnly}, pod_length::PodLength, primitives::PodU32, }, bytemuck::Pod, - solana_program_error::ProgramError, std::{ marker::PhantomData, mem::{align_of, size_of}, @@ -51,17 +50,17 @@ struct Layout { impl ListView { /// Calculate the total byte size for a `ListView` holding `num_items`. /// This includes the length prefix, padding, and data. - pub fn size_of(num_items: usize) -> Result { + pub fn size_of(num_items: usize) -> Result { let header_padding = Self::header_padding()?; size_of::() .checked_mul(num_items) .and_then(|curr| curr.checked_add(size_of::())) .and_then(|curr| curr.checked_add(header_padding)) - .ok_or_else(|| PodSliceError::CalculationFailure.into()) + .ok_or(SplPodError::CalculationFailure) } /// Unpack a read-only buffer into a `ListViewReadOnly` - pub fn unpack(buf: &[u8]) -> Result, ProgramError> { + pub fn unpack(buf: &[u8]) -> Result, SplPodError> { let layout = Self::calculate_layout(buf.len())?; // Slice the buffer to get the length prefix and the data. @@ -79,7 +78,7 @@ impl ListView { let capacity = data.len(); if (*length).into() > capacity { - return Err(PodSliceError::BufferTooSmall.into()); + return Err(SplPodError::BufferTooSmall); } Ok(ListViewReadOnly { @@ -90,16 +89,16 @@ impl ListView { } /// Unpack the mutable buffer into a mutable `ListViewMut` - pub fn unpack_mut(buf: &mut [u8]) -> Result, ProgramError> { + pub fn unpack_mut(buf: &mut [u8]) -> Result, SplPodError> { let view = Self::build_mut_view(buf)?; if (*view.length).into() > view.capacity { - return Err(PodSliceError::BufferTooSmall.into()); + return Err(SplPodError::BufferTooSmall); } Ok(view) } /// Initialize a buffer: sets `length = 0` and returns a mutable `ListViewMut`. - pub fn init(buf: &mut [u8]) -> Result, ProgramError> { + pub fn init(buf: &mut [u8]) -> Result, SplPodError> { let view = Self::build_mut_view(buf)?; *view.length = L::try_from(0)?; Ok(view) @@ -107,7 +106,7 @@ impl ListView { /// Internal helper to build a mutable view without validation or initialization. #[inline] - fn build_mut_view(buf: &mut [u8]) -> Result, ProgramError> { + fn build_mut_view(buf: &mut [u8]) -> Result, SplPodError> { let layout = Self::calculate_layout(buf.len())?; // Split the buffer to get the length prefix and the data. @@ -133,13 +132,13 @@ impl ListView { /// Calculate the byte ranges for the length and data sections of the buffer #[inline] - fn calculate_layout(buf_len: usize) -> Result { + fn calculate_layout(buf_len: usize) -> Result { let len_field_end = size_of::(); let header_padding = Self::header_padding()?; let data_start = len_field_end.saturating_add(header_padding); if buf_len < data_start { - return Err(PodSliceError::BufferTooSmall.into()); + return Err(SplPodError::BufferTooSmall); } Ok(Layout { @@ -153,10 +152,10 @@ impl ListView { /// The goal is to ensure that the data field `T` starts at a memory offset /// that is a multiple of its alignment requirement. #[inline] - fn header_padding() -> Result { + fn header_padding() -> Result { // Enforce that the length prefix type `L` itself does not have alignment requirements if align_of::() != 1 { - return Err(ProgramError::InvalidArgument); + return Err(SplPodError::InvalidLengthTypeAlignment); } let length_size = size_of::(); @@ -240,12 +239,12 @@ mod tests { // Case 1: Multiplication overflows. // `size_of::() * usize::MAX` will overflow. let err = ListView::::size_of(usize::MAX).unwrap_err(); - assert_eq!(err, PodSliceError::CalculationFailure.into()); + assert_eq!(err, SplPodError::CalculationFailure); // Case 2: Multiplication does not overflow, but subsequent addition does. // `size_of::() * usize::MAX` does not overflow, but adding `size_of` will. let err = ListView::::size_of(usize::MAX).unwrap_err(); - assert_eq!(err, PodSliceError::CalculationFailure.into()); + assert_eq!(err, SplPodError::CalculationFailure); } #[test] @@ -262,7 +261,7 @@ mod tests { } } impl TryFrom for TestPodU32 { - type Error = PodSliceError; + type Error = SplPodError; fn try_from(val: usize) -> Result { Ok(Self(u32::try_from(val)?)) } @@ -271,13 +270,13 @@ mod tests { let mut buf = [0u8; 100]; let err_size_of = ListView::::size_of(10).unwrap_err(); - assert_eq!(err_size_of, ProgramError::InvalidArgument); + assert_eq!(err_size_of, SplPodError::InvalidLengthTypeAlignment); let err_unpack = ListView::::unpack(&buf).unwrap_err(); - assert_eq!(err_unpack, ProgramError::InvalidArgument); + assert_eq!(err_unpack, SplPodError::InvalidLengthTypeAlignment); let err_init = ListView::::init(&mut buf).unwrap_err(); - assert_eq!(err_init, ProgramError::InvalidArgument); + assert_eq!(err_init, SplPodError::InvalidLengthTypeAlignment); } #[test] @@ -445,10 +444,10 @@ mod tests { let mut buf = vec![0u8; header_size - 1]; // 7 bytes let err = ListView::::unpack(&buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); let err = ListView::::unpack_mut(&mut buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); } #[test] @@ -465,10 +464,10 @@ mod tests { buf[0..len_size].copy_from_slice(bytemuck::bytes_of(&pod_len)); let err = ListView::::unpack(&buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); let err = ListView::::unpack_mut(&mut buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); } #[test] @@ -482,20 +481,20 @@ mod tests { // bytemuck::try_cast_slice returns an alignment error, which we map to InvalidArgument let err = ListView::::unpack(&buf).unwrap_err(); - assert_eq!(err, ProgramError::InvalidArgument); + assert_eq!(err, SplPodError::PodCast); let err = ListView::::unpack_mut(&mut buf).unwrap_err(); - assert_eq!(err, ProgramError::InvalidArgument); + assert_eq!(err, SplPodError::PodCast); } #[test] fn test_unpack_empty_buffer() { let mut buf = []; let err = ListView::::unpack(&buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); let err = ListView::::unpack_mut(&mut buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); } #[test] @@ -562,12 +561,12 @@ mod tests { // Header requires 4 bytes (size_of) let mut buf = vec![0u8; 3]; let err = ListView::::init(&mut buf).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); // With padding, header requires 8 bytes (4 for len, 4 for pad) let mut buf_padded = vec![0u8; 7]; let err_padded = ListView::::init(&mut buf_padded).unwrap_err(); - assert_eq!(err_padded, PodSliceError::BufferTooSmall.into()); + assert_eq!(err_padded, SplPodError::BufferTooSmall); } #[test] diff --git a/pod/src/list/list_view_mut.rs b/pod/src/list/list_view_mut.rs index 4f0ca49..8bbe790 100644 --- a/pod/src/list/list_view_mut.rs +++ b/pod/src/list/list_view_mut.rs @@ -2,10 +2,9 @@ use { crate::{ - error::PodSliceError, list::list_trait::List, pod_length::PodLength, primitives::PodU32, + error::SplPodError, list::list_trait::List, pod_length::PodLength, primitives::PodU32, }, bytemuck::Pod, - solana_program_error::ProgramError, std::ops::{Deref, DerefMut}, }; @@ -18,10 +17,10 @@ pub struct ListViewMut<'data, T: Pod, L: PodLength = PodU32> { impl ListViewMut<'_, T, L> { /// Add another item to the slice - pub fn push(&mut self, item: T) -> Result<(), ProgramError> { + pub fn push(&mut self, item: T) -> Result<(), SplPodError> { let length = (*self.length).into(); if length >= self.capacity { - Err(PodSliceError::BufferTooSmall.into()) + Err(SplPodError::BufferTooSmall) } else { self.data[length] = item; *self.length = L::try_from(length.saturating_add(1))?; @@ -31,10 +30,10 @@ impl ListViewMut<'_, T, L> { /// Remove and return the element at `index`, shifting all later /// elements one position to the left. - pub fn remove(&mut self, index: usize) -> Result { + pub fn remove(&mut self, index: usize) -> Result { let len = (*self.length).into(); if index >= len { - return Err(ProgramError::InvalidArgument); + return Err(SplPodError::IndexOutOfRange); } let removed_item = self.data[index]; @@ -42,7 +41,7 @@ impl ListViewMut<'_, T, L> { // Move the tail left by one let tail_start = index .checked_add(1) - .ok_or(ProgramError::ArithmeticOverflow)?; + .ok_or(SplPodError::CalculationFailure)?; self.data.copy_within(tail_start..len, index); // Store the new length (len - 1) @@ -147,7 +146,7 @@ mod tests { // Try to push beyond capacity let item4 = TestStruct::new(4, 40); let err = view.push(item4).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); // Ensure state is unchanged assert_eq!(view.len(), 3); @@ -207,12 +206,12 @@ mod tests { // Try to remove at index == len let err = view.remove(2).unwrap_err(); - assert_eq!(err, ProgramError::InvalidArgument); + assert_eq!(err, SplPodError::IndexOutOfRange); assert_eq!(view.len(), 2); // Unchanged // Try to remove at index > len let err = view.remove(100).unwrap_err(); - assert_eq!(err, ProgramError::InvalidArgument); + assert_eq!(err, SplPodError::IndexOutOfRange); assert_eq!(view.len(), 2); // Unchanged // Empty the view @@ -222,7 +221,7 @@ mod tests { // Try to remove from empty view let err = view.remove(0).unwrap_err(); - assert_eq!(err, ProgramError::InvalidArgument); + assert_eq!(err, SplPodError::IndexOutOfRange); } #[test] @@ -280,10 +279,10 @@ mod tests { assert!(view.is_empty()); let err = view.push(TestStruct::new(1, 1)).unwrap_err(); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + assert_eq!(err, SplPodError::BufferTooSmall); let err = view.remove(0).unwrap_err(); - assert_eq!(err, ProgramError::InvalidArgument); + assert_eq!(err, SplPodError::IndexOutOfRange); } #[test] diff --git a/pod/src/optional_keys.rs b/pod/src/optional_keys.rs index 82a0726..951f994 100644 --- a/pod/src/optional_keys.rs +++ b/pod/src/optional_keys.rs @@ -220,7 +220,7 @@ impl<'de> Deserialize<'de> for OptionalNonZeroElGamalPubkey { mod tests { use { super::*, - crate::bytemuck::pod_from_bytes, + crate::{bytemuck::pod_from_bytes, error::SplPodError}, base64::{prelude::BASE64_STANDARD, Engine}, solana_pubkey::PUBKEY_BYTES, }; @@ -241,15 +241,15 @@ mod tests { ); assert_eq!( pod_from_bytes::(&[]).unwrap_err(), - ProgramError::InvalidArgument + SplPodError::PodCast ); assert_eq!( pod_from_bytes::(&[0; 1]).unwrap_err(), - ProgramError::InvalidArgument + SplPodError::PodCast ); assert_eq!( pod_from_bytes::(&[1; 1]).unwrap_err(), - ProgramError::InvalidArgument + SplPodError::PodCast ); } diff --git a/pod/src/pod_length.rs b/pod/src/pod_length.rs index 0f46b57..a90f834 100644 --- a/pod/src/pod_length.rs +++ b/pod/src/pod_length.rs @@ -1,23 +1,23 @@ use { crate::{ - error::PodSliceError, + error::SplPodError, primitives::{PodU128, PodU16, PodU32, PodU64}, }, bytemuck::Pod, }; /// Marker trait for converting to/from Pod `uint`'s and `usize` -pub trait PodLength: Pod + Into + TryFrom {} +pub trait PodLength: Pod + Into + TryFrom {} /// Blanket implementation to automatically implement `PodLength` for any type /// that satisfies the required bounds. -impl PodLength for T where T: Pod + Into + TryFrom {} +impl PodLength for T where T: Pod + Into + TryFrom {} /// Implements the `TryFrom` and `From for usize` conversions for a Pod integer type macro_rules! impl_pod_length_for { ($PodType:ty, $PrimitiveType:ty) => { impl TryFrom for $PodType { - type Error = PodSliceError; + type Error = SplPodError; fn try_from(val: usize) -> Result { let primitive_val = <$PrimitiveType>::try_from(val)?; diff --git a/pod/src/slice.rs b/pod/src/slice.rs index a5b01e7..f15cff8 100644 --- a/pod/src/slice.rs +++ b/pod/src/slice.rs @@ -2,11 +2,11 @@ use { crate::{ + error::SplPodError, list::{ListView, ListViewMut, ListViewReadOnly}, primitives::PodU32, }, bytemuck::Pod, - solana_program_error::ProgramError, }; #[deprecated( @@ -22,7 +22,7 @@ pub struct PodSlice<'data, T: Pod> { #[allow(deprecated)] impl<'data, T: Pod> PodSlice<'data, T> { /// Unpack the buffer into a slice - pub fn unpack<'a>(data: &'a [u8]) -> Result + pub fn unpack<'a>(data: &'a [u8]) -> Result where 'a: 'data, { @@ -37,7 +37,7 @@ impl<'data, T: Pod> PodSlice<'data, T> { } /// Get the amount of bytes used by `num_items` - pub fn size_of(num_items: usize) -> Result { + pub fn size_of(num_items: usize) -> Result { ListView::::size_of(num_items) } } @@ -55,7 +55,7 @@ pub struct PodSliceMut<'data, T: Pod> { #[allow(deprecated)] impl<'data, T: Pod> PodSliceMut<'data, T> { /// Unpack the mutable buffer into a mutable slice - pub fn unpack<'a>(data: &'a mut [u8]) -> Result + pub fn unpack<'a>(data: &'a mut [u8]) -> Result where 'a: 'data, { @@ -65,7 +65,7 @@ impl<'data, T: Pod> PodSliceMut<'data, T> { /// Unpack the mutable buffer into a mutable slice, and initialize the /// slice to 0-length - pub fn init<'a>(data: &'a mut [u8]) -> Result + pub fn init<'a>(data: &'a mut [u8]) -> Result where 'a: 'data, { @@ -74,7 +74,7 @@ impl<'data, T: Pod> PodSliceMut<'data, T> { } /// Add another item to the slice - pub fn push(&mut self, t: T) -> Result<(), ProgramError> { + pub fn push(&mut self, t: T) -> Result<(), SplPodError> { self.inner.push(t) } } @@ -84,7 +84,7 @@ impl<'data, T: Pod> PodSliceMut<'data, T> { mod tests { use { super::*, - crate::{bytemuck::pod_slice_to_bytes, error::PodSliceError}, + crate::{bytemuck::pod_slice_to_bytes, error::SplPodError}, bytemuck_derive::{Pod, Zeroable}, }; @@ -134,7 +134,7 @@ mod tests { let err = PodSlice::::unpack(&pod_slice_bytes) .err() .unwrap(); - assert!(matches!(err, ProgramError::InvalidArgument)); + assert_eq!(err, SplPodError::PodCast); } #[test] @@ -171,7 +171,7 @@ mod tests { let err = PodSlice::::unpack(&pod_slice_bytes) .err() .unwrap(); - assert!(matches!(err, ProgramError::InvalidArgument)); + assert_eq!(err, SplPodError::PodCast); } #[test] @@ -193,8 +193,8 @@ mod tests { let err = PodSlice::::unpack(&data).err().unwrap(); assert_eq!( err, - PodSliceError::BufferTooSmall.into(), - "Expected an `PodSliceError::BufferTooSmall` error" + SplPodError::BufferTooSmall, + "Expected an `SplPodError::BufferTooSmall` error" ); } } @@ -215,7 +215,7 @@ mod tests { let err = pod_slice .push(TestStruct::default()) - .expect_err("Expected an `PodSliceError::BufferTooSmall` error"); - assert_eq!(err, PodSliceError::BufferTooSmall.into()); + .expect_err("Expected an `SplPodError::BufferTooSmall` error"); + assert_eq!(err, SplPodError::BufferTooSmall); } } diff --git a/tlv-account-resolution/src/state.rs b/tlv-account-resolution/src/state.rs index 2733a1e..fa88d36 100644 --- a/tlv-account-resolution/src/state.rs +++ b/tlv-account-resolution/src/state.rs @@ -196,7 +196,7 @@ impl ExtraAccountMetaList { tlv_state: &'a TlvStateBorrowed, ) -> Result, ProgramError> { let bytes = tlv_state.get_first_bytes::()?; - ListView::::unpack(bytes) + Ok(ListView::::unpack(bytes)?) } /// Get the byte size required to hold `num_items` items diff --git a/type-length-value/src/state.rs b/type-length-value/src/state.rs index 6bcbfbf..0da715c 100644 --- a/type-length-value/src/state.rs +++ b/type-length-value/src/state.rs @@ -214,7 +214,7 @@ pub trait TlvState { repetition_number: usize, ) -> Result<&V, ProgramError> { let data = get_bytes::(self.get_data(), repetition_number)?; - pod_from_bytes::(data) + Ok(pod_from_bytes::(data)?) } /// Unpack a portion of the TLV data as the desired Pod type for the first @@ -331,7 +331,7 @@ impl<'data> TlvStateMut<'data> { repetition_number: usize, ) -> Result<&mut V, ProgramError> { let data = self.get_bytes_with_repetition_mut::(repetition_number)?; - pod_from_bytes_mut::(data) + Ok(pod_from_bytes_mut::(data)?) } /// Unpack a portion of the TLV data as the desired type that allows @@ -612,6 +612,7 @@ mod test { use { super::*, bytemuck::{Pod, Zeroable}, + spl_pod::error::SplPodError, }; const TEST_BUFFER: &[u8] = &[ @@ -736,7 +737,7 @@ mod test { let state = TlvStateMut::unpack(&mut buffer).unwrap(); assert_eq!( state.get_first_value::(), - Err(ProgramError::InvalidArgument) + Err(SplPodError::PodCast.into()) ); // data buffer is too small for type @@ -979,7 +980,7 @@ mod test { let data = state.alloc::(tlv_size, false).unwrap().0; assert_eq!( pod_from_bytes_mut::(data).unwrap_err(), - ProgramError::InvalidArgument, + SplPodError::PodCast, ); // can't double alloc @@ -1002,7 +1003,7 @@ mod test { // not enough room assert_eq!( pod_from_bytes_mut::(data).unwrap_err(), - ProgramError::InvalidArgument, + SplPodError::PodCast, ); // Can alloc again!