#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be stored in a zero-copy Hopper layout",
label = "not `Zeroable`: this type has no all-zero, copyable byte form",
note = "layout fields are alignment-1 byte types: `u8`, `i8`, `[T; N]`, `Address`, the wire integers (`WireU16` to `WireU128`, `WireI16` to `WireI128`), `WireBool`, `EnumByte<E>`, `OptionByte<T>`, and other `#[hopper::state]` / `#[hopper::pod]` structs"
)]
pub unsafe trait Zeroable: Copy + Sized {}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be overlaid on account bytes",
label = "not `Pod`: some byte pattern or byte offset is invalid for this type",
note = "use the alignment-1 wire form instead: `WireU64` for `u64` (and `WireU16`, `WireU32`, `WireU128`, `WireI16` to `WireI128`), `WireBool` for `bool`, `EnumByte<E>` for a `#[hopper::unit_enum]` enum, `OptionByte<T>` for an optional value, `Address` for a key",
note = "a nested struct must itself be declared with `#[hopper::state]` or `#[hopper::pod]`; references, `Vec`, `String`, and `char` have no zero-copy form (see bounded `String<'a, N>` / `Vec<'a, T, N>` tail fields)"
)]
pub unsafe trait Pod: Zeroable {}
pub unsafe trait ValuePod: Copy + Sized {}
unsafe impl Zeroable for u8 {}
unsafe impl Pod for u8 {}
unsafe impl Zeroable for u16 {}
unsafe impl Zeroable for u32 {}
unsafe impl Zeroable for u64 {}
unsafe impl Zeroable for u128 {}
unsafe impl Zeroable for i8 {}
unsafe impl Pod for i8 {}
unsafe impl Zeroable for i16 {}
unsafe impl Zeroable for i32 {}
unsafe impl Zeroable for i64 {}
unsafe impl Zeroable for i128 {}
unsafe impl<T: Zeroable, const N: usize> Zeroable for [T; N] {}
unsafe impl<T: Pod, const N: usize> Pod for [T; N] {}
unsafe impl Zeroable for () {}
unsafe impl Pod for () {}
unsafe impl ValuePod for u8 {}
unsafe impl ValuePod for u16 {}
unsafe impl ValuePod for u32 {}
unsafe impl ValuePod for u64 {}
unsafe impl ValuePod for u128 {}
unsafe impl ValuePod for i8 {}
unsafe impl ValuePod for i16 {}
unsafe impl ValuePod for i32 {}
unsafe impl ValuePod for i64 {}
unsafe impl ValuePod for i128 {}
unsafe impl<T: ValuePod, const N: usize> ValuePod for [T; N] {}
#[inline]
pub fn read_unaligned_value<T: ValuePod>(
bytes: &[u8],
offset: usize,
) -> Result<T, crate::error::ProgramError> {
let end = offset
.checked_add(core::mem::size_of::<T>())
.ok_or(crate::error::ProgramError::ArithmeticOverflow)?;
if end > bytes.len() {
return Err(crate::error::ProgramError::AccountDataTooSmall);
}
Ok(unsafe { core::ptr::read_unaligned(bytes.as_ptr().add(offset) as *const T) })
}
#[cfg(test)]
mod tests {
use super::*;
fn require<T: Pod>() {}
fn require_value<T: ValuePod>() {}
#[test]
fn primitives_are_pod() {
require::<u8>();
require::<i8>();
require::<[u8; 32]>();
}
#[test]
fn multibyte_ints_are_value_pod_not_pod() {
require_value::<u64>();
require_value::<i128>();
require_value::<[u32; 4]>();
let bytes = [1u8, 0, 0, 0, 0, 0, 0, 0, 7, 0];
let v0: u64 = read_unaligned_value(&bytes, 0).unwrap();
assert_eq!(v0, 1); let v1: u64 = read_unaligned_value(&bytes, 1).unwrap();
assert_eq!(v1, 7 << 56); assert!(read_unaligned_value::<u64>(&bytes, 5).is_err());
}
#[test]
fn bool_is_not_pod() {
trait NotPod {}
impl<T> NotPod for T {}
fn _f<T: NotPod>() {}
_f::<bool>();
}
}