#[macro_export]
macro_rules! jiminy_interface {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident for $owner:path {
$( $(#[$fmeta:meta])* $field:ident : $fty:ident = $fsize:expr ),+ $(,)?
}
) => {
$crate::jiminy_interface! {
@impl version = 1,
$(#[$meta])*
$vis struct $name for $owner {
$( $(#[$fmeta])* $field : $fty = $fsize ),+
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident for $owner:path, version = $ver:literal {
$( $(#[$fmeta:meta])* $field:ident : $fty:ident = $fsize:expr ),+ $(,)?
}
) => {
$crate::jiminy_interface! {
@impl version = $ver,
$(#[$meta])*
$vis struct $name for $owner {
$( $(#[$fmeta])* $field : $fty = $fsize ),+
}
}
};
(
@impl version = $ver:literal,
$(#[$meta:meta])*
$vis:vis struct $name:ident for $owner:path {
$( $(#[$fmeta:meta])* $field:ident : $fty:ident = $fsize:expr ),+ $(,)?
}
) => {
$(#[$meta])*
#[repr(C)]
#[derive(Clone, Copy)]
$vis struct $name {
$( $(#[$fmeta])* pub $field: $fty ),+
}
unsafe impl $crate::account::Pod for $name {}
impl $crate::account::FixedLayout for $name {
const SIZE: usize = 0 $( + $fsize )+;
}
const _: () = assert!(
core::mem::size_of::<$name>() == 0 $( + $fsize )+,
"size_of does not match declared LEN; check field sizes"
);
const _: () = assert!(
core::mem::align_of::<$name>() <= 8,
"layout alignment exceeds 8 bytes; use Le* wrappers for u128 fields"
);
impl $name {
pub const LEN: usize = 0 $( + $fsize )+;
pub const LAYOUT_ID: [u8; 8] = {
const INPUT: &str = concat!(
"jiminy:v1:",
stringify!($name), ":",
stringify!($ver), ":",
$( stringify!($field), ":", $crate::__canonical_type!($fty), ":", stringify!($fsize), ",", )+
);
const HASH: [u8; 32] = $crate::__sha256_const(INPUT.as_bytes());
[HASH[0], HASH[1], HASH[2], HASH[3], HASH[4], HASH[5], HASH[6], HASH[7]]
};
pub const OWNER: &'static $crate::Address = &$owner;
#[inline(always)]
pub fn overlay(data: &[u8]) -> Result<&Self, $crate::ProgramError> {
$crate::account::pod_from_bytes::<Self>(data)
}
#[inline(always)]
pub fn read(data: &[u8]) -> Result<Self, $crate::ProgramError> {
$crate::account::pod_read::<Self>(data)
}
#[inline(always)]
pub fn load_foreign<'a>(
account: &'a $crate::AccountView,
) -> Result<$crate::account::VerifiedAccount<'a, Self>, $crate::ProgramError> {
let data = $crate::account::view::validate_foreign(
account, &$owner, &Self::LAYOUT_ID, Self::LEN,
)?;
$crate::account::VerifiedAccount::new(data)
}
$crate::__gen_offsets!( $( $field = $fsize ),+ );
#[inline]
#[allow(unused_variables)]
pub fn split_fields(data: &[u8]) -> Result<( $( $crate::__field_ref_type!($field), )+ ), $crate::ProgramError> {
if data.len() < Self::LEN {
return Err($crate::ProgramError::AccountDataTooSmall);
}
let mut _pos = 0usize;
Ok(( $({
let start = _pos;
_pos += $fsize;
$crate::abi::FieldRef::new(&data[start..start + $fsize])
}, )+ ))
}
}
};
}
#[macro_export]
macro_rules! segmented_interface {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident for $owner:path {
$( $(#[$fmeta:meta])* $field:ident : $fty:ident = $fsize:expr ),+ $(,)?
} segments {
$( $seg_name:ident : $seg_ty:ident = $seg_elem_size:expr ),+ $(,)?
}
) => {
$crate::segmented_interface! {
@impl version = 1,
$(#[$meta])*
$vis struct $name for $owner {
$( $(#[$fmeta])* $field : $fty = $fsize ),+
} segments {
$( $seg_name : $seg_ty = $seg_elem_size ),+
}
}
};
(
$(#[$meta:meta])*
$vis:vis struct $name:ident for $owner:path, version = $ver:literal {
$( $(#[$fmeta:meta])* $field:ident : $fty:ident = $fsize:expr ),+ $(,)?
} segments {
$( $seg_name:ident : $seg_ty:ident = $seg_elem_size:expr ),+ $(,)?
}
) => {
$crate::segmented_interface! {
@impl version = $ver,
$(#[$meta])*
$vis struct $name for $owner {
$( $(#[$fmeta])* $field : $fty = $fsize ),+
} segments {
$( $seg_name : $seg_ty = $seg_elem_size ),+
}
}
};
(
@impl version = $ver:literal,
$(#[$meta:meta])*
$vis:vis struct $name:ident for $owner:path {
$( $(#[$fmeta:meta])* $field:ident : $fty:ident = $fsize:expr ),+ $(,)?
} segments {
$( $seg_name:ident : $seg_ty:ident = $seg_elem_size:expr ),+ $(,)?
}
) => {
$crate::jiminy_interface! {
@impl version = $ver,
$(#[$meta])*
$vis struct $name for $owner {
$( $(#[$fmeta])* $field : $fty = $fsize ),+
}
}
impl $name {
pub const SEGMENT_COUNT: usize = $crate::__count_segments!($($seg_name)+);
pub const FIXED_LEN: usize = Self::LEN;
pub const TABLE_OFFSET: usize = Self::LEN;
pub const DATA_START_OFFSET: usize =
Self::LEN + Self::SEGMENT_COUNT * $crate::account::segment::SEGMENT_DESC_SIZE;
pub const MIN_ACCOUNT_SIZE: usize = Self::DATA_START_OFFSET;
pub const SEGMENTED_LAYOUT_ID: [u8; 8] = {
const INPUT: &str = concat!(
"jiminy:v1:",
stringify!($name), ":",
stringify!($ver), ":",
$( stringify!($field), ":", $crate::__canonical_type!($fty), ":", stringify!($fsize), ",", )+
$( "seg:", stringify!($seg_name), ":", stringify!($seg_ty), ":", stringify!($seg_elem_size), ",", )+
);
const HASH: [u8; 32] = $crate::__sha256_const(INPUT.as_bytes());
[HASH[0], HASH[1], HASH[2], HASH[3], HASH[4], HASH[5], HASH[6], HASH[7]]
};
#[inline(always)]
pub const fn segment_sizes() -> &'static [u16] {
&[ $( $seg_elem_size as u16, )+ ]
}
#[inline(always)]
pub fn load_foreign_segmented<'a>(
account: &'a $crate::AccountView,
) -> Result<$crate::hopper_runtime::Ref<'a, [u8]>, $crate::ProgramError> {
$crate::account::view::validate_foreign_segmented(
account,
&$owner,
&Self::SEGMENTED_LAYOUT_ID,
Self::MIN_ACCOUNT_SIZE,
)
}
#[inline(always)]
pub fn segment_table(data: &[u8]) -> Result<$crate::account::segment::SegmentTable<'_>, $crate::ProgramError> {
if data.len() < Self::DATA_START_OFFSET {
return Err($crate::ProgramError::AccountDataTooSmall);
}
$crate::account::segment::SegmentTable::from_bytes(
&data[Self::TABLE_OFFSET..],
Self::SEGMENT_COUNT,
)
}
#[inline]
pub fn validate_segments(data: &[u8]) -> Result<(), $crate::ProgramError> {
let table = Self::segment_table(data)?;
table.validate(data.len(), Self::segment_sizes(), Self::DATA_START_OFFSET)
}
#[inline(always)]
pub fn segment<T: $crate::account::Pod + $crate::account::FixedLayout>(
data: &[u8],
index: usize,
) -> Result<$crate::account::segment::SegmentSlice<'_, T>, $crate::ProgramError> {
let desc = {
let table = Self::segment_table(data)?;
table.descriptor(index)?
};
$crate::account::segment::SegmentSlice::from_descriptor(data, &desc)
}
$crate::__gen_segment_indices!($($seg_name),+);
}
};
}