use crate::{Error, Slot, SlotSpan};
use core::{
any::type_name,
fmt::{Debug, Formatter, Write as _},
marker::PhantomData,
};
#[derive(Debug, Default, Copy, Clone)]
pub struct Local<const N: u16> {
marker: PhantomData<fn()>,
}
pub struct SlotAndReg<T> {
pub slot: Slot,
pub reg: Reg<T>,
}
impl<T> Copy for SlotAndReg<T> {}
impl<T> Clone for SlotAndReg<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> From<SlotAndReg<T>> for Slot {
fn from(value: SlotAndReg<T>) -> Self {
value.slot
}
}
impl<T> From<Slot> for SlotAndReg<T> {
fn from(slot: Slot) -> Self {
Self {
slot,
reg: Reg::default(),
}
}
}
impl<T> Debug for SlotAndReg<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SlotAndReg")
.field("slot", &self.slot)
.field("reg", &self.reg)
.finish()
}
}
pub struct Reg<T> {
marker: PhantomData<fn() -> T>,
}
impl<T> Copy for Reg<T> {}
impl<T> Clone for Reg<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Default for Reg<T> {
#[inline]
fn default() -> Self {
Self {
marker: PhantomData,
}
}
}
impl<T> Debug for Reg<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str("Reg<")?;
f.write_str(type_name::<T>())?;
f.write_char('>')?;
Ok(())
}
}
#[derive(Debug, Copy, Clone)]
pub struct BranchTableTarget {
pub results: SlotSpan,
pub offset: BranchOffset,
}
impl BranchTableTarget {
pub fn new(results: SlotSpan, offset: BranchOffset) -> Self {
Self { results, offset }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BranchOffset(i32);
impl From<i32> for BranchOffset {
fn from(index: i32) -> Self {
Self(index)
}
}
impl From<BranchOffset> for i32 {
fn from(offset: BranchOffset) -> Self {
offset.0
}
}
impl BranchOffset {
pub fn is_backwards(&self) -> bool {
self.0.is_negative()
}
pub fn is_forwards(&self) -> bool {
self.0.is_positive()
}
pub fn is_init(self) -> bool {
self.0 != 0
}
pub fn uninit() -> Self {
Self(0)
}
pub fn init(&mut self, valid_offset: BranchOffset) {
assert!(valid_offset.is_init());
assert!(!self.is_init());
*self = valid_offset;
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct BlockFuel(u64);
impl From<u64> for BlockFuel {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<BlockFuel> for u64 {
fn from(value: BlockFuel) -> Self {
value.0
}
}
impl BlockFuel {
pub fn bump_by(&mut self, amount: u64) -> Result<(), Error> {
self.0 = u64::from(*self)
.checked_add(amount)
.ok_or(Error::BlockFuelOutOfBounds)?;
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Address(u64);
impl Address {
pub fn new(addr: u64) -> Option<Self> {
if usize::try_from(addr).is_err() {
return None;
}
Some(Self(addr))
}
}
impl From<Address> for usize {
fn from(address: Address) -> Self {
debug_assert!(usize::try_from(address.0).is_ok());
address.0 as usize
}
}
impl From<Address> for u64 {
fn from(address: Address) -> Self {
address.0
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Offset16(pub(crate) u16);
impl Offset16 {
pub fn new(offset: Offset) -> Option<Self> {
u16::try_from(u64::from(offset)).ok().map(Self)
}
}
impl From<Offset16> for u64 {
#[inline]
fn from(offset: Offset16) -> Self {
u64::from(offset.0)
}
}
#[cfg(feature = "memory64")]
pub type OffsetRepr = u64;
#[cfg(not(feature = "memory64"))]
pub type OffsetRepr = u32;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Offset(pub(crate) OffsetRepr);
impl Offset {
pub fn new(offset: u64) -> Option<Self> {
OffsetRepr::try_from(offset).ok().map(Self)
}
}
impl From<Offset> for u64 {
#[inline]
fn from(offset: Offset) -> Self {
#[cfg(feature = "memory64")]
{
offset.0
}
#[cfg(not(feature = "memory64"))]
{
u64::from(offset.0)
}
}
}