use std::{
fmt,
num::NonZeroUsize,
ops::{Deref, Index, RangeFull},
};
use awint::{
awint_dag::{Lineage, PState},
awint_internals::USIZE_BITS,
};
use super::lazy_awi::format_auto_awi;
use crate::{
awi::{self, *},
dag,
ensemble::PExternal,
Delay, Error, EvalAwi, LazyAwi,
};
pub struct In<const W: usize>(LazyAwi);
impl<const W: usize> std::borrow::Borrow<LazyAwi> for In<W> {
fn borrow(&self) -> &LazyAwi {
&self.0
}
}
#[allow(clippy::from_over_into)]
impl<const W: usize> Into<LazyAwi> for In<W> {
fn into(self) -> LazyAwi {
self.0
}
}
macro_rules! retro_primitives {
($($f:ident $x:ident $w:expr);*;) => {
$(
impl In<$w> {
pub fn $f(&self, rhs: $x) -> Result<(), Error> {
self.0.$f(rhs)
}
}
)*
};
}
macro_rules! init {
($($f:ident);*;) => {
$(
#[track_caller]
pub fn $f() -> Self {
Self(LazyAwi::$f(bw(W)))
}
)*
};
}
macro_rules! retro {
($($f:ident);*;) => {
$(
pub fn $f(&self) -> Result<(), Error> {
self.0.$f()
}
)*
};
}
retro_primitives!(
retro_bool_ bool 1;
retro_u8_ u8 8;
retro_i8_ i8 8;
retro_u16_ u16 16;
retro_i16_ i16 16;
retro_u32_ u32 32;
retro_i32_ i32 32;
retro_u64_ u64 64;
retro_i64_ i64 64;
retro_u128_ u128 128;
retro_i128_ i128 128;
);
impl In<{ USIZE_BITS }> {
pub fn retro_usize_(&self, rhs: usize) -> Result<(), Error> {
self.0.retro_usize_(rhs)
}
pub fn retro_isize_(&self, rhs: isize) -> Result<(), Error> {
self.0.retro_isize_(rhs)
}
}
impl<const W: usize> In<W> {
init!(
zero;
umax;
imax;
imin;
uone;
);
retro!(
retro_zero_;
retro_umax_;
retro_imax_;
retro_imin_;
retro_uone_;
);
pub fn p_external(&self) -> PExternal {
self.0.p_external()
}
pub fn nzbw(&self) -> NonZeroUsize {
self.0.nzbw()
}
pub fn bw(&self) -> usize {
self.0.bw()
}
#[track_caller]
pub fn opaque() -> Self {
Self(LazyAwi::opaque(bw(W)))
}
pub fn retro_(&self, rhs: &awi::Bits) -> Result<(), Error> {
self.0.retro_(rhs)
}
pub fn retro_unknown_(&self) -> Result<(), Error> {
self.0.retro_unknown_()
}
pub fn retro_const_(&self, rhs: &awi::Bits) -> Result<(), Error> {
self.0.retro_const_(rhs)
}
pub fn retro_const_unknown_(&self) -> Result<(), Error> {
self.0.retro_const_unknown_()
}
pub fn drive<E: std::borrow::Borrow<EvalAwi>>(self, rhs: E) -> Result<(), Error> {
self.0.drive(rhs)
}
pub fn drive_with_delay<E: std::borrow::Borrow<EvalAwi>, D: Into<Delay>>(
self,
rhs: E,
delay: D,
) -> Result<(), Error> {
self.0.drive_with_delay(rhs, delay)
}
pub fn set_debug_name<S: AsRef<str>>(&self, debug_name: S) -> Result<(), Error> {
self.0.set_debug_name(debug_name)
}
}
impl<const W: usize> Deref for In<W> {
type Target = dag::Bits;
#[track_caller]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<const W: usize> Index<RangeFull> for In<W> {
type Output = dag::Bits;
#[track_caller]
fn index(&self, _i: RangeFull) -> &dag::Bits {
self
}
}
impl<const W: usize> std::borrow::Borrow<dag::Bits> for In<W> {
#[track_caller]
fn borrow(&self) -> &dag::Bits {
self
}
}
impl<const W: usize> AsRef<dag::Bits> for In<W> {
#[track_caller]
fn as_ref(&self) -> &dag::Bits {
self
}
}
impl<const W: usize> fmt::Debug for In<W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_auto_awi(&format!("In<{W}>"), self.p_external(), self.nzbw(), f)
}
}
pub struct Out<const W: usize>(EvalAwi);
impl<const W: usize> std::borrow::Borrow<EvalAwi> for Out<W> {
fn borrow(&self) -> &EvalAwi {
&self.0
}
}
#[allow(clippy::from_over_into)]
impl<const W: usize> Into<EvalAwi> for Out<W> {
fn into(self) -> EvalAwi {
self.0
}
}
macro_rules! from_impl {
($($fn:ident $t:ident $w:expr);*;) => {
$(
impl Out<$w> {
#[track_caller]
pub fn $fn(x: dag::$t) -> Self {
Self(EvalAwi::$fn(x))
}
}
)*
}
}
macro_rules! eval_primitives {
($($f:ident $x:ident $w:expr);*;) => {
$(
impl Out<{$w}> {
pub fn $f(&self) -> Result<$x, Error> {
self.0.$f()
}
}
)*
};
}
from_impl!(
from_bool bool 1;
from_u8 u8 8;
from_i8 i8 8;
from_u16 u16 16;
from_i16 i16 16;
from_u32 u32 32;
from_i32 i32 32;
from_u64 u64 64;
from_i64 i64 64;
from_u128 u128 128;
from_i128 i128 128;
);
eval_primitives!(
eval_bool bool 1;
eval_u8 u8 8;
eval_i8 i8 8;
eval_u16 u16 16;
eval_i16 i16 16;
eval_u32 u32 32;
eval_i32 i32 32;
eval_u64 u64 64;
eval_i64 i64 64;
eval_u128 u128 128;
eval_i128 i128 128;
);
impl Out<{ USIZE_BITS }> {
#[track_caller]
pub fn from_usize(x: dag::usize) -> Self {
Self(EvalAwi::from_usize(x))
}
#[track_caller]
pub fn from_isize(x: dag::isize) -> Self {
Self(EvalAwi::from_isize(x))
}
pub fn eval_usize(&self) -> Result<usize, Error> {
self.0.eval_usize()
}
pub fn eval_isize(&self) -> Result<isize, Error> {
self.0.eval_isize()
}
}
impl<const W: usize> Out<W> {
pub fn p_external(&self) -> PExternal {
self.0.p_external()
}
pub fn nzbw(&self) -> NonZeroUsize {
self.0.nzbw()
}
pub fn bw(&self) -> usize {
self.0.bw()
}
#[track_caller]
pub fn from_state(p_state: PState) -> Result<Self, Error> {
let eval = EvalAwi::from_state(p_state);
if eval.bw() != W {
Err(Error::ConstBitwidthMismatch(eval.bw(), W))
} else {
Ok(Self(eval))
}
}
#[track_caller]
pub fn from_bits(bits: &dag::Bits) -> Result<Self, Error> {
Self::from_state(bits.state())
}
pub fn eval(&self) -> Result<awi::Awi, Error> {
self.0.eval()
}
pub fn eval_is_all_unknown(&self) -> Result<bool, Error> {
self.0.eval_is_all_unknown()
}
pub fn set_debug_name<S: AsRef<str>>(&self, debug_name: S) -> Result<(), Error> {
self.0.set_debug_name(debug_name)
}
}
impl<const W: usize> fmt::Debug for Out<W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_auto_awi(&format!("Out<{W}>"), self.p_external(), self.nzbw(), f)
}
}