use crate::{Error, SlotSpan};
use core::marker::PhantomData;
#[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)]
pub struct OutOfBoundsConst;
#[derive(Debug)]
pub struct Sign<T> {
pub(crate) is_positive: bool,
marker: PhantomData<fn() -> T>,
}
impl<T> Clone for Sign<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Sign<T> {}
impl<T> PartialEq for Sign<T> {
fn eq(&self, other: &Self) -> bool {
self.is_positive == other.is_positive
}
}
impl<T> Eq for Sign<T> {}
impl<T> Sign<T> {
pub(crate) fn new(is_positive: bool) -> Self {
Self {
is_positive,
marker: PhantomData,
}
}
pub fn pos() -> Self {
Self::new(true)
}
pub fn neg() -> Self {
Self::new(false)
}
pub(crate) fn is_positive(self) -> bool {
self.is_positive
}
}
macro_rules! impl_sign_for {
( $($ty:ty),* $(,)? ) => {
$(
impl From<$ty> for Sign<$ty> {
fn from(value: $ty) -> Self {
Self::new(value.is_sign_positive())
}
}
impl From<Sign<$ty>> for $ty {
fn from(sign: Sign<$ty>) -> Self {
match sign.is_positive {
true => 1.0,
false => -1.0,
}
}
}
)*
};
}
impl_sign_for!(f32, f64);
#[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 TryFrom<u64> for Address {
type Error = OutOfBoundsConst;
fn try_from(address: u64) -> Result<Self, OutOfBoundsConst> {
if usize::try_from(address).is_err() {
return Err(OutOfBoundsConst);
};
Ok(Self(address))
}
}
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(u16);
impl TryFrom<u64> for Offset16 {
type Error = OutOfBoundsConst;
fn try_from(address: u64) -> Result<Self, Self::Error> {
<u16>::try_from(address)
.map(Self)
.map_err(|_| OutOfBoundsConst)
}
}
impl From<u16> for Offset16 {
fn from(offset: u16) -> Self {
Self(offset)
}
}
impl From<Offset16> for u16 {
fn from(offset: Offset16) -> Self {
offset.0
}
}