use crate::{error::ZeroPodError, pod::*};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayoutKind {
Fixed,
Compact,
}
pub trait ZcValidate: Copy {
fn validate_ref(value: &Self) -> Result<(), ZeroPodError>;
}
impl ZcValidate for u8 {
#[inline(always)]
fn validate_ref(_: &Self) -> Result<(), ZeroPodError> {
Ok(())
}
}
impl ZcValidate for i8 {
#[inline(always)]
fn validate_ref(_: &Self) -> Result<(), ZeroPodError> {
Ok(())
}
}
macro_rules! impl_zc_validate_trivial {
($($ty:ty),*) => {
$(
impl ZcValidate for $ty {
#[inline(always)]
fn validate_ref(_: &Self) -> Result<(), ZeroPodError> { Ok(()) }
}
)*
};
}
impl_zc_validate_trivial!(PodU16, PodU32, PodU64, PodU128, PodI16, PodI32, PodI64, PodI128);
impl<const N: usize> ZcValidate for [u8; N] {
#[inline(always)]
fn validate_ref(_: &Self) -> Result<(), ZeroPodError> {
Ok(())
}
}
impl ZcValidate for PodBool {
#[inline(always)]
fn validate_ref(value: &Self) -> Result<(), ZeroPodError> {
let byte = unsafe { *(value as *const PodBool as *const u8) };
if byte > 1 {
Err(ZeroPodError::InvalidBool)
} else {
Ok(())
}
}
}
impl<const N: usize, const PFX: usize> ZcValidate for PodString<N, PFX> {
#[inline(always)]
fn validate_ref(value: &Self) -> Result<(), ZeroPodError> {
let raw_len = value.decode_len();
if raw_len > N {
return Err(ZeroPodError::InvalidLength);
}
let bytes =
unsafe { core::slice::from_raw_parts(value.data.as_ptr() as *const u8, raw_len) };
if core::str::from_utf8(bytes).is_err() {
return Err(ZeroPodError::InvalidUtf8);
}
Ok(())
}
}
impl<T: ZcElem, const N: usize, const PFX: usize> ZcValidate for PodVec<T, N, PFX> {
#[inline(always)]
fn validate_ref(value: &Self) -> Result<(), ZeroPodError> {
if value.decode_len() > N {
return Err(ZeroPodError::InvalidLength);
}
for item in value.as_slice() {
T::validate_ref(item)?;
}
Ok(())
}
}
impl<T: Copy + ZcValidate, const PFX: usize> ZcValidate for PodOption<T, PFX> {
#[inline(always)]
fn validate_ref(value: &Self) -> Result<(), ZeroPodError> {
match value.raw_tag() {
0 => Ok(()),
1 => {
let inner = unsafe { value.assume_init_ref() };
T::validate_ref(inner)
}
_ => Err(ZeroPodError::InvalidTag),
}
}
}
pub unsafe trait ZcElem: Copy + ZcValidate {}
unsafe impl ZcElem for u8 {}
unsafe impl ZcElem for i8 {}
unsafe impl ZcElem for PodU16 {}
unsafe impl ZcElem for PodU32 {}
unsafe impl ZcElem for PodU64 {}
unsafe impl ZcElem for PodU128 {}
unsafe impl ZcElem for PodI16 {}
unsafe impl ZcElem for PodI32 {}
unsafe impl ZcElem for PodI64 {}
unsafe impl ZcElem for PodI128 {}
unsafe impl ZcElem for PodBool {}
unsafe impl<const N: usize> ZcElem for [u8; N] {}
unsafe impl<T: ZcElem, const PFX: usize> ZcElem for PodOption<T, PFX> {}
#[cfg(feature = "solana-address")]
mod solana_address_impls {
use super::*;
const _: () = assert!(core::mem::align_of::<solana_address::Address>() == 1);
impl ZcValidate for solana_address::Address {
#[inline(always)]
fn validate_ref(_: &Self) -> Result<(), ZeroPodError> {
Ok(())
}
}
unsafe impl ZcElem for solana_address::Address {}
impl ZcField for solana_address::Address {
type Pod = solana_address::Address;
const POD_SIZE: usize = 32;
}
}
pub trait ZeroPodSchema: Sized {
const LAYOUT: LayoutKind;
}
pub trait ZeroPodFixed: ZeroPodSchema {
type Zc: Copy;
const SIZE: usize;
fn from_bytes(data: &[u8]) -> Result<&Self::Zc, ZeroPodError>;
fn from_bytes_mut(data: &mut [u8]) -> Result<&mut Self::Zc, ZeroPodError>;
fn validate(data: &[u8]) -> Result<(), ZeroPodError>;
unsafe fn from_bytes_unchecked(data: &[u8]) -> &Self::Zc {
&*(data.as_ptr() as *const Self::Zc)
}
unsafe fn from_bytes_mut_unchecked(data: &mut [u8]) -> &mut Self::Zc {
&mut *(data.as_mut_ptr() as *mut Self::Zc)
}
}
pub trait ZeroPodCompact: ZeroPodSchema {
type Header: Copy;
const HEADER_SIZE: usize;
fn header(data: &[u8]) -> Result<&Self::Header, ZeroPodError>;
fn header_mut(data: &mut [u8]) -> Result<&mut Self::Header, ZeroPodError>;
fn validate(data: &[u8]) -> Result<(), ZeroPodError>;
}
pub trait ZcField: Sized {
type Pod: Copy;
const POD_SIZE: usize;
}
macro_rules! impl_zc_field {
($native:ty, $pod:ty, $size:expr) => {
impl ZcField for $native {
type Pod = $pod;
const POD_SIZE: usize = $size;
}
};
}
impl_zc_field!(u8, u8, 1);
impl_zc_field!(u16, PodU16, 2);
impl_zc_field!(u32, PodU32, 4);
impl_zc_field!(u64, PodU64, 8);
impl_zc_field!(u128, PodU128, 16);
impl_zc_field!(i8, i8, 1);
impl_zc_field!(i16, PodI16, 2);
impl_zc_field!(i32, PodI32, 4);
impl_zc_field!(i64, PodI64, 8);
impl_zc_field!(i128, PodI128, 16);
impl_zc_field!(bool, PodBool, 1);
impl<const N: usize> ZcField for [u8; N] {
type Pod = [u8; N];
const POD_SIZE: usize = N;
}
macro_rules! impl_zc_field_identity {
($($ty:ty),*) => {
$(
impl ZcField for $ty {
type Pod = Self;
const POD_SIZE: usize = core::mem::size_of::<Self>();
}
)*
};
}
impl_zc_field_identity!(PodU16, PodU32, PodU64, PodU128, PodI16, PodI32, PodI64, PodI128, PodBool);
impl<const N: usize, const PFX: usize> ZcField for PodString<N, PFX> {
type Pod = Self;
const POD_SIZE: usize = core::mem::size_of::<Self>();
}
impl<T: ZcElem, const N: usize, const PFX: usize> ZcField for PodVec<T, N, PFX> {
type Pod = Self;
const POD_SIZE: usize = core::mem::size_of::<Self>();
}
impl<T: Copy, const PFX: usize> ZcField for PodOption<T, PFX> {
type Pod = Self;
const POD_SIZE: usize = core::mem::size_of::<Self>();
}
impl<T> ZcField for Option<T>
where
T: ZcField,
T::Pod: Copy,
{
type Pod = PodOption<T::Pod, 1>;
const POD_SIZE: usize = core::mem::size_of::<PodOption<T::Pod, 1>>();
}