use crate::account::{FixedLayout, Pod};
macro_rules! impl_le_unsigned {
($name:ident, $inner:ty, $size:literal) => {
#[doc = concat!("Alignment-1, little-endian `", stringify!($inner), "` for on-chain ABI fields.")]
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct $name(pub [u8; $size]);
const _: () = assert!(core::mem::size_of::<$name>() == $size);
const _: () = assert!(core::mem::align_of::<$name>() == 1);
impl $name {
pub const ZERO: Self = Self([0u8; $size]);
#[inline(always)]
pub const fn new(v: $inner) -> Self {
Self(v.to_le_bytes())
}
#[inline(always)]
pub const fn get(&self) -> $inner {
<$inner>::from_le_bytes(self.0)
}
#[inline(always)]
pub fn set(&mut self, v: $inner) {
self.0 = v.to_le_bytes();
}
}
impl Default for $name {
#[inline(always)]
fn default() -> Self {
Self::ZERO
}
}
impl core::fmt::Debug for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}({})", stringify!($name), self.get())
}
}
impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.get())
}
}
impl PartialOrd for $name {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for $name {
#[inline(always)]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.get().cmp(&other.get())
}
}
impl From<$inner> for $name {
#[inline(always)]
fn from(v: $inner) -> Self {
Self::new(v)
}
}
impl From<$name> for $inner {
#[inline(always)]
fn from(v: $name) -> Self {
v.get()
}
}
unsafe impl Pod for $name {}
impl FixedLayout for $name {
const SIZE: usize = $size;
}
};
}
macro_rules! impl_le_signed {
($name:ident, $inner:ty, $size:literal) => {
#[doc = concat!("Alignment-1, little-endian `", stringify!($inner), "` for on-chain ABI fields.")]
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct $name(pub [u8; $size]);
const _: () = assert!(core::mem::size_of::<$name>() == $size);
const _: () = assert!(core::mem::align_of::<$name>() == 1);
impl $name {
pub const ZERO: Self = Self([0u8; $size]);
#[inline(always)]
pub const fn new(v: $inner) -> Self {
Self(v.to_le_bytes())
}
#[inline(always)]
pub const fn get(&self) -> $inner {
<$inner>::from_le_bytes(self.0)
}
#[inline(always)]
pub fn set(&mut self, v: $inner) {
self.0 = v.to_le_bytes();
}
}
impl Default for $name {
#[inline(always)]
fn default() -> Self {
Self::ZERO
}
}
impl core::fmt::Debug for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}({})", stringify!($name), self.get())
}
}
impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.get())
}
}
impl PartialOrd for $name {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for $name {
#[inline(always)]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.get().cmp(&other.get())
}
}
impl From<$inner> for $name {
#[inline(always)]
fn from(v: $inner) -> Self {
Self::new(v)
}
}
impl From<$name> for $inner {
#[inline(always)]
fn from(v: $name) -> Self {
v.get()
}
}
unsafe impl Pod for $name {}
impl FixedLayout for $name {
const SIZE: usize = $size;
}
};
}
impl_le_unsigned!(LeU16, u16, 2);
impl_le_unsigned!(LeU32, u32, 4);
impl_le_unsigned!(LeU64, u64, 8);
impl_le_unsigned!(LeU128, u128, 16);
impl_le_signed!(LeI16, i16, 2);
impl_le_signed!(LeI32, i32, 4);
impl_le_signed!(LeI64, i64, 8);
impl_le_signed!(LeI128, i128, 16);
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct LeBool(pub [u8; 1]);
const _: () = assert!(core::mem::size_of::<LeBool>() == 1);
const _: () = assert!(core::mem::align_of::<LeBool>() == 1);
impl LeBool {
pub const FALSE: Self = Self([0]);
pub const TRUE: Self = Self([1]);
#[inline(always)]
pub const fn new(v: bool) -> Self {
Self([v as u8])
}
#[inline(always)]
pub const fn get(&self) -> bool {
self.0[0] != 0
}
#[inline(always)]
pub fn set(&mut self, v: bool) {
self.0[0] = v as u8;
}
}
impl Default for LeBool {
#[inline(always)]
fn default() -> Self {
Self::FALSE
}
}
impl core::fmt::Debug for LeBool {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "LeBool({})", self.get())
}
}
impl core::fmt::Display for LeBool {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.get())
}
}
impl From<bool> for LeBool {
#[inline(always)]
fn from(v: bool) -> Self {
Self::new(v)
}
}
impl From<LeBool> for bool {
#[inline(always)]
fn from(v: LeBool) -> Self {
v.get()
}
}
unsafe impl Pod for LeBool {}
impl FixedLayout for LeBool {
const SIZE: usize = 1;
}
pub struct FieldRef<'a> {
data: &'a [u8],
}
impl<'a> FieldRef<'a> {
#[inline(always)]
pub const fn new(data: &'a [u8]) -> Self {
Self { data }
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.data.len()
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline(always)]
pub const fn as_bytes(&self) -> &[u8] {
self.data
}
#[inline(always)]
pub fn read_address(&self) -> hopper_runtime::Address {
let mut addr = [0u8; 32];
addr.copy_from_slice(&self.data[..32]);
hopper_runtime::Address::from(addr)
}
#[inline(always)]
pub fn as_address(&self) -> &hopper_runtime::Address {
let ptr = self.data[..32].as_ptr() as *const hopper_runtime::Address;
unsafe { &*ptr }
}
#[inline(always)]
pub fn read_u64(&self) -> u64 {
u64::from_le_bytes([
self.data[0],
self.data[1],
self.data[2],
self.data[3],
self.data[4],
self.data[5],
self.data[6],
self.data[7],
])
}
#[inline(always)]
pub fn read_u32(&self) -> u32 {
u32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]])
}
#[inline(always)]
pub fn read_u16(&self) -> u16 {
u16::from_le_bytes([self.data[0], self.data[1]])
}
#[inline(always)]
pub fn read_u8(&self) -> u8 {
self.data[0]
}
#[inline(always)]
pub fn read_bool(&self) -> bool {
self.data[0] != 0
}
#[inline(always)]
pub fn read_i64(&self) -> i64 {
i64::from_le_bytes([
self.data[0],
self.data[1],
self.data[2],
self.data[3],
self.data[4],
self.data[5],
self.data[6],
self.data[7],
])
}
#[inline(always)]
pub fn read_i32(&self) -> i32 {
i32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]])
}
#[inline(always)]
pub fn read_i16(&self) -> i16 {
i16::from_le_bytes([self.data[0], self.data[1]])
}
#[inline(always)]
pub fn read_u128(&self) -> u128 {
u128::from_le_bytes([
self.data[0], self.data[1], self.data[2], self.data[3],
self.data[4], self.data[5], self.data[6], self.data[7],
self.data[8], self.data[9], self.data[10], self.data[11],
self.data[12], self.data[13], self.data[14], self.data[15],
])
}
#[inline(always)]
pub fn read_i128(&self) -> i128 {
i128::from_le_bytes([
self.data[0], self.data[1], self.data[2], self.data[3],
self.data[4], self.data[5], self.data[6], self.data[7],
self.data[8], self.data[9], self.data[10], self.data[11],
self.data[12], self.data[13], self.data[14], self.data[15],
])
}
#[inline(always)]
pub fn read_i8(&self) -> i8 {
self.data[0] as i8
}
}
pub struct FieldMut<'a> {
data: &'a mut [u8],
}
impl<'a> FieldMut<'a> {
#[inline(always)]
pub fn new(data: &'a mut [u8]) -> Self {
Self { data }
}
#[inline(always)]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline(always)]
pub fn as_bytes(&self) -> &[u8] {
self.data
}
#[inline(always)]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
self.data
}
#[inline(always)]
pub fn read_address(&self) -> hopper_runtime::Address {
let mut addr = [0u8; 32];
addr.copy_from_slice(&self.data[..32]);
hopper_runtime::Address::from(addr)
}
#[inline(always)]
pub fn as_address(&self) -> &hopper_runtime::Address {
let ptr = self.data[..32].as_ptr() as *const hopper_runtime::Address;
unsafe { &*ptr }
}
#[inline(always)]
pub fn write_address(&mut self, addr: &hopper_runtime::Address) {
self.data[..32].copy_from_slice(addr.as_ref());
}
#[inline(always)]
pub fn write_u64(&mut self, v: u64) {
self.data[..8].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_u32(&mut self, v: u32) {
self.data[..4].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_u16(&mut self, v: u16) {
self.data[..2].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_u8(&mut self, v: u8) {
self.data[0] = v;
}
#[inline(always)]
pub fn write_bool(&mut self, v: bool) {
self.data[0] = v as u8;
}
#[inline(always)]
pub fn write_i64(&mut self, v: i64) {
self.data[..8].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_i32(&mut self, v: i32) {
self.data[..4].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_i16(&mut self, v: i16) {
self.data[..2].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_i8(&mut self, v: i8) {
self.data[0] = v as u8;
}
#[inline(always)]
pub fn write_u128(&mut self, v: u128) {
self.data[..16].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn write_i128(&mut self, v: i128) {
self.data[..16].copy_from_slice(&v.to_le_bytes());
}
#[inline(always)]
pub fn read_u64(&self) -> u64 {
u64::from_le_bytes([
self.data[0],
self.data[1],
self.data[2],
self.data[3],
self.data[4],
self.data[5],
self.data[6],
self.data[7],
])
}
#[inline(always)]
pub fn read_u32(&self) -> u32 {
u32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]])
}
#[inline(always)]
pub fn read_u16(&self) -> u16 {
u16::from_le_bytes([self.data[0], self.data[1]])
}
#[inline(always)]
pub fn read_u8(&self) -> u8 {
self.data[0]
}
#[inline(always)]
pub fn read_bool(&self) -> bool {
self.data[0] != 0
}
#[inline(always)]
pub fn read_i64(&self) -> i64 {
i64::from_le_bytes([
self.data[0],
self.data[1],
self.data[2],
self.data[3],
self.data[4],
self.data[5],
self.data[6],
self.data[7],
])
}
#[inline(always)]
pub fn read_i32(&self) -> i32 {
i32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]])
}
#[inline(always)]
pub fn read_i16(&self) -> i16 {
i16::from_le_bytes([self.data[0], self.data[1]])
}
#[inline(always)]
pub fn read_i8(&self) -> i8 {
self.data[0] as i8
}
#[inline(always)]
pub fn read_u128(&self) -> u128 {
u128::from_le_bytes([
self.data[0], self.data[1], self.data[2], self.data[3],
self.data[4], self.data[5], self.data[6], self.data[7],
self.data[8], self.data[9], self.data[10], self.data[11],
self.data[12], self.data[13], self.data[14], self.data[15],
])
}
#[inline(always)]
pub fn read_i128(&self) -> i128 {
i128::from_le_bytes([
self.data[0], self.data[1], self.data[2], self.data[3],
self.data[4], self.data[5], self.data[6], self.data[7],
self.data[8], self.data[9], self.data[10], self.data[11],
self.data[12], self.data[13], self.data[14], self.data[15],
])
}
#[inline(always)]
pub fn copy_from(&mut self, src: &[u8]) {
self.data[..src.len()].copy_from_slice(src);
}
}