fayalite/crates/fayalite/src/expr.rs
Jacob Lifshay 9e803223d0
All checks were successful
/ test (pull_request) Successful in 3m59s
/ test (push) Successful in 4m38s
support operations directly on SimValue, UIntValue, and SIntValue, and shared references to those
2025-11-24 00:14:53 -08:00

1694 lines
52 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
array::{Array, ArrayType},
bundle::{Bundle, BundleType},
enum_::{Enum, EnumType},
expr::target::{GetTarget, Target},
int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
intern::{Intern, Interned},
memory::{DynPortType, MemPort, PortType},
module::{
Instance, ModuleIO,
transform::visit::{Fold, Folder, Visit, Visitor},
},
phantom_const::PhantomConst,
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
sim::value::{SimValue, ToSimValue, ToSimValueWithType},
ty::{CanonicalType, OpaqueSimValue, StaticType, Type, TypeWithDeref},
util::{ConstBool, ConstUsize},
wire::Wire,
};
use bitvec::slice::BitSlice;
use std::{borrow::Cow, convert::Infallible, fmt, ops::Deref};
pub mod ops;
pub mod target;
pub mod value_category;
macro_rules! expr_enum {
(
pub enum $ExprEnum:ident {
$($Variant:ident($VariantTy:ty),)*
}
) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum $ExprEnum {
$($Variant($VariantTy),)*
}
impl fmt::Debug for $ExprEnum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(Self::$Variant(v) => v.fmt(f),)*
}
}
}
$(impl From<$VariantTy> for $ExprEnum {
fn from(v: $VariantTy) -> Self {
Self::$Variant(v)
}
})*
impl<State: Folder + ?Sized> Fold<State> for $ExprEnum {
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
state.fold_expr_enum(self)
}
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
match self {
$(Self::$Variant(v) => Fold::fold(v, state).map(Self::$Variant),)*
}
}
}
impl<State: Visitor + ?Sized> Visit<State> for $ExprEnum {
fn visit(&self, state: &mut State) -> Result<(), State::Error> {
state.visit_expr_enum(self)
}
fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
match self {
$(Self::$Variant(v) => Visit::visit(v, state),)*
}
}
}
impl ValueType for $ExprEnum {
type Type = CanonicalType;
type ValueCategory = value_category::ValueCategoryExpr;
fn ty(&self) -> Self::Type {
match self {
$(Self::$Variant(v) => v.ty().canonical(),)*
}
}
}
impl ToExpr for $ExprEnum {
fn to_expr(&self) -> Expr<Self::Type> {
match self {
$(Self::$Variant(v) => Expr::canonical(v.to_expr()),)*
}
}
}
impl GetTarget for $ExprEnum {
fn target(&self) -> Option<Interned<Target>> {
match self {
$(Self::$Variant(v) => v.target(),)*
}
}
}
impl ToLiteralBits for $ExprEnum {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
match self {
$(Self::$Variant(v) => v.to_literal_bits(),)*
}
}
}
};
}
expr_enum! {
pub enum ExprEnum {
UIntLiteral(Interned<UIntValue>),
SIntLiteral(Interned<SIntValue>),
BoolLiteral(bool),
PhantomConst(PhantomConst),
BundleLiteral(ops::BundleLiteral),
ArrayLiteral(ops::ArrayLiteral<CanonicalType, DynSize>),
EnumLiteral(ops::EnumLiteral),
Uninit(ops::Uninit),
NotU(ops::NotU),
NotS(ops::NotS),
NotB(ops::NotB),
Neg(ops::Neg),
BitAndU(ops::BitAndU),
BitAndS(ops::BitAndS),
BitAndB(ops::BitAndB),
BitOrU(ops::BitOrU),
BitOrS(ops::BitOrS),
BitOrB(ops::BitOrB),
BitXorU(ops::BitXorU),
BitXorS(ops::BitXorS),
BitXorB(ops::BitXorB),
AddU(ops::AddU),
AddS(ops::AddS),
SubU(ops::SubU),
SubS(ops::SubS),
MulU(ops::MulU),
MulS(ops::MulS),
DivU(ops::DivU),
DivS(ops::DivS),
RemU(ops::RemU),
RemS(ops::RemS),
DynShlU(ops::DynShlU),
DynShlS(ops::DynShlS),
DynShrU(ops::DynShrU),
DynShrS(ops::DynShrS),
FixedShlU(ops::FixedShlU),
FixedShlS(ops::FixedShlS),
FixedShrU(ops::FixedShrU),
FixedShrS(ops::FixedShrS),
CmpLtB(ops::CmpLtB),
CmpLeB(ops::CmpLeB),
CmpGtB(ops::CmpGtB),
CmpGeB(ops::CmpGeB),
CmpEqB(ops::CmpEqB),
CmpNeB(ops::CmpNeB),
CmpLtU(ops::CmpLtU),
CmpLeU(ops::CmpLeU),
CmpGtU(ops::CmpGtU),
CmpGeU(ops::CmpGeU),
CmpEqU(ops::CmpEqU),
CmpNeU(ops::CmpNeU),
CmpLtS(ops::CmpLtS),
CmpLeS(ops::CmpLeS),
CmpGtS(ops::CmpGtS),
CmpGeS(ops::CmpGeS),
CmpEqS(ops::CmpEqS),
CmpNeS(ops::CmpNeS),
CastUIntToUInt(ops::CastUIntToUInt),
CastUIntToSInt(ops::CastUIntToSInt),
CastSIntToUInt(ops::CastSIntToUInt),
CastSIntToSInt(ops::CastSIntToSInt),
CastBoolToUInt(ops::CastBoolToUInt),
CastBoolToSInt(ops::CastBoolToSInt),
CastUIntToBool(ops::CastUIntToBool),
CastSIntToBool(ops::CastSIntToBool),
CastBoolToSyncReset(ops::CastBoolToSyncReset),
CastUIntToSyncReset(ops::CastUIntToSyncReset),
CastSIntToSyncReset(ops::CastSIntToSyncReset),
CastBoolToAsyncReset(ops::CastBoolToAsyncReset),
CastUIntToAsyncReset(ops::CastUIntToAsyncReset),
CastSIntToAsyncReset(ops::CastSIntToAsyncReset),
CastSyncResetToBool(ops::CastSyncResetToBool),
CastSyncResetToUInt(ops::CastSyncResetToUInt),
CastSyncResetToSInt(ops::CastSyncResetToSInt),
CastSyncResetToReset(ops::CastSyncResetToReset),
CastAsyncResetToBool(ops::CastAsyncResetToBool),
CastAsyncResetToUInt(ops::CastAsyncResetToUInt),
CastAsyncResetToSInt(ops::CastAsyncResetToSInt),
CastAsyncResetToReset(ops::CastAsyncResetToReset),
CastResetToBool(ops::CastResetToBool),
CastResetToUInt(ops::CastResetToUInt),
CastResetToSInt(ops::CastResetToSInt),
CastBoolToClock(ops::CastBoolToClock),
CastUIntToClock(ops::CastUIntToClock),
CastSIntToClock(ops::CastSIntToClock),
CastClockToBool(ops::CastClockToBool),
CastClockToUInt(ops::CastClockToUInt),
CastClockToSInt(ops::CastClockToSInt),
FieldAccess(ops::FieldAccess),
VariantAccess(ops::VariantAccess),
ArrayIndex(ops::ArrayIndex),
DynArrayIndex(ops::DynArrayIndex),
ReduceBitAndU(ops::ReduceBitAndU),
ReduceBitAndS(ops::ReduceBitAndS),
ReduceBitOrU(ops::ReduceBitOrU),
ReduceBitOrS(ops::ReduceBitOrS),
ReduceBitXorU(ops::ReduceBitXorU),
ReduceBitXorS(ops::ReduceBitXorS),
SliceUInt(ops::SliceUInt),
SliceSInt(ops::SliceSInt),
CastToBits(ops::CastToBits),
CastBitsTo(ops::CastBitsTo),
ModuleIO(ModuleIO<CanonicalType>),
Instance(Instance<Bundle>),
Wire(Wire<CanonicalType>),
Reg(Reg<CanonicalType, Reset>),
RegSync(Reg<CanonicalType, SyncReset>),
RegAsync(Reg<CanonicalType, AsyncReset>),
MemPort(MemPort<DynPortType>),
}
}
impl From<UIntValue> for ExprEnum {
fn from(value: UIntValue) -> Self {
ExprEnum::UIntLiteral(Intern::intern_sized(value))
}
}
impl From<SIntValue> for ExprEnum {
fn from(value: SIntValue) -> Self {
ExprEnum::SIntLiteral(Intern::intern_sized(value))
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct NotALiteralExpr;
impl fmt::Display for NotALiteralExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Not a literal expression")
}
}
impl std::error::Error for NotALiteralExpr {}
pub trait ToLiteralBits {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr>;
}
impl ToLiteralBits for Result<Interned<BitSlice>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
*self
}
}
impl ToLiteralBits for Interned<BitSlice> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Ok(*self)
}
}
impl ToLiteralBits for NotALiteralExpr {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(*self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Expr<T: Type> {
__enum: Interned<ExprEnum>,
__ty: T,
__flow: Flow,
}
impl<T: Type + fmt::Debug> fmt::Debug for Expr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(debug_assertions)]
{
let Self {
__enum,
__ty,
__flow,
} = self;
let expr_ty = __ty.canonical();
let enum_ty = __enum.to_expr().ty();
assert_eq!(
expr_ty, enum_ty,
"expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}"
);
}
self.__enum.fmt(f)
}
}
impl<T: Type> Expr<T> {
pub fn expr_enum(this: Self) -> Interned<ExprEnum> {
this.__enum
}
pub fn flow(this: Self) -> Flow {
this.__flow
}
pub fn canonical(this: Self) -> Expr<CanonicalType> {
Expr {
__enum: this.__enum,
__ty: this.ty().canonical(),
__flow: this.__flow,
}
}
pub fn from_canonical(this: Expr<CanonicalType>) -> Self {
Expr {
__enum: this.__enum,
__ty: T::from_canonical(this.ty()),
__flow: this.__flow,
}
}
pub fn from_dyn_int(this: Expr<T::Dyn>) -> Self
where
T: IntType,
{
Expr {
__enum: this.__enum,
__ty: T::from_dyn_int(this.ty()),
__flow: this.__flow,
}
}
pub fn as_dyn_int(this: Self) -> Expr<T::Dyn>
where
T: IntType,
{
Expr {
__enum: this.__enum,
__ty: this.ty().as_dyn_int(),
__flow: this.__flow,
}
}
pub fn as_bundle(this: Self) -> Expr<Bundle>
where
T: BundleType,
{
Expr {
__enum: this.__enum,
__ty: Bundle::new(this.ty().fields()),
__flow: this.__flow,
}
}
pub fn from_bundle(this: Expr<Bundle>) -> Self
where
T: BundleType,
{
Expr {
__enum: this.__enum,
__ty: T::from_canonical(CanonicalType::Bundle(this.ty())),
__flow: this.__flow,
}
}
#[track_caller]
pub fn field<FieldType: Type>(this: Self, name: &str) -> Expr<FieldType>
where
T: BundleType,
{
ops::FieldAccess::new_by_name(Self::as_bundle(this), name.intern()).to_expr()
}
pub fn as_enum(this: Self) -> Expr<Enum>
where
T: EnumType,
{
Expr {
__enum: this.__enum,
__ty: Enum::new(this.ty().variants()),
__flow: this.__flow,
}
}
pub fn from_enum(this: Expr<Enum>) -> Self
where
T: EnumType,
{
Expr {
__enum: this.__enum,
__ty: T::from_canonical(CanonicalType::Enum(this.ty())),
__flow: this.__flow,
}
}
}
impl<T: Type> ToLiteralBits for Expr<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.__enum.to_literal_bits()
}
}
impl<T: Type> GetTarget for Expr<T> {
fn target(&self) -> Option<Interned<Target>> {
self.__enum.target()
}
}
impl<T: TypeWithDeref> Deref for Expr<T> {
type Target = T::MatchVariant;
fn deref(&self) -> &Self::Target {
T::expr_deref(self)
}
}
impl<T: Type, Len: Size> Expr<ArrayType<T, Len>> {
pub fn as_dyn_array(this: Self) -> Expr<Array> {
Expr {
__enum: this.__enum,
__ty: this.ty().as_dyn_array(),
__flow: this.__flow,
}
}
}
impl<T: Type, State: Folder + ?Sized> Fold<State> for Expr<T> {
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
state.fold_expr(self)
}
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
Ok(Expr::from_canonical(self.__enum.fold(state)?.to_expr()))
}
}
impl<T: Type, State: Visitor + ?Sized> Visit<State> for Expr<T> {
fn visit(&self, state: &mut State) -> Result<(), State::Error> {
state.visit_expr(self)
}
fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
self.__enum.visit(state)
}
}
pub trait ToExpr: ValueType + ToValueless {
fn to_expr(&self) -> Expr<Self::Type>;
}
impl<T: Type> ToExpr for Expr<T> {
fn to_expr(&self) -> Expr<Self::Type> {
*self
}
}
impl<T: ?Sized + ToExpr> ToExpr for &'_ T {
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<T: ?Sized + ToExpr> ToExpr for &'_ mut T {
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<T: ?Sized + ToExpr> ToExpr for Box<T> {
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<T: ?Sized + ToExpr + Send + Sync + 'static> ToExpr for Interned<T> {
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<Width: Size> ToExpr for UIntValue<Width> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::UIntLiteral(self.clone().as_dyn_int().intern()).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl<Width: Size> ToExpr for SIntValue<Width> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::SIntLiteral(self.clone().as_dyn_int().intern()).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl ValueType for bool {
type Type = Bool;
type ValueCategory = value_category::ValueCategoryValue;
fn ty(&self) -> Self::Type {
Bool
}
}
impl ToExpr for bool {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::BoolLiteral(*self).intern(),
__ty: Bool,
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Flow {
Source,
Sink,
Duplex,
}
impl Flow {
pub const fn flip(self) -> Flow {
match self {
Flow::Source => Flow::Sink,
Flow::Sink => Flow::Source,
Flow::Duplex => Flow::Duplex,
}
}
pub const fn flip_if(self, flipped: bool) -> Flow {
if flipped { self.flip() } else { self }
}
}
impl<T: Type> ToExpr for ModuleIO<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ModuleIO(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: Type> ToLiteralBits for ModuleIO<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: Type> GetTarget for ModuleIO<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: BundleType> ToExpr for Instance<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::Instance(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: BundleType> ToLiteralBits for Instance<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: BundleType> GetTarget for Instance<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: Type> ToExpr for Wire<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::Wire(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: Type> ToLiteralBits for Wire<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: Type> GetTarget for Wire<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: Type, R: ResetType> ToExpr for Reg<T, R> {
fn to_expr(&self) -> Expr<Self::Type> {
struct Dispatch;
impl ResetTypeDispatch for Dispatch {
type Input<T: ResetType> = Reg<CanonicalType, T>;
type Output<T: ResetType> = ExprEnum;
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
ExprEnum::Reg(input)
}
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
ExprEnum::RegSync(input)
}
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
ExprEnum::RegAsync(input)
}
}
Expr {
__enum: R::dispatch(self.canonical(), Dispatch).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: Type, R: ResetType> ToLiteralBits for Reg<T, R> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: Type, R: ResetType> GetTarget for Reg<T, R> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: PortType> ToExpr for MemPort<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::MemPort(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: PortType> ToLiteralBits for MemPort<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: PortType> GetTarget for MemPort<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
macro_rules! impl_hdl_cmp {
(
#[
impl_helper = $HdlCmpImplHelper:ident,
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
]
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
{
$(type $Output:ident: ValueType<Type = Bool>;)?
$(#[
helper = $cmp_fn_helper:ident;
value = $cmp_value_fn:ident(
$cmp_value_lhs:ident,
$cmp_value_lhs_value:ident,
$cmp_value_rhs:ident,
$cmp_value_rhs_value:ident $(,)?
) $cmp_value_body:tt
sim_value = $cmp_sim_value_fn:ident;
expr = $cmp_expr_fn:ident($cmp_expr_lhs:ident, $cmp_expr_rhs:ident) $cmp_expr_body:tt
valueless = $cmp_valueless_fn:ident;
]
fn $cmp_fn:ident(&self, rhs: Rhs) -> Self::Output;)+
}
) => {
$vis trait $HdlCmp<$Rhs: ValueType>:
ValueType<Type: $HdlCmpImpl<$Rhs::Type>> $(+ $HdlCmpBase<$Rhs>)?
{
$(type $Output: ValueType<Type = Bool>;)?
$(fn $cmp_fn(&self, rhs: $Rhs) -> Self::Output;)+
}
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
$(#[track_caller]
fn $cmp_value_fn(
$cmp_value_lhs: Self,
$cmp_value_lhs_value: Cow<'_, Self::SimValue>,
$cmp_value_rhs: $Rhs,
$cmp_value_rhs_value: Cow<'_, $Rhs::SimValue>,
) -> bool
$cmp_value_body)+
$(#[track_caller]
fn $cmp_sim_value_fn(lhs: Cow<'_, SimValue<Self>>, rhs: Cow<'_, SimValue<$Rhs>>) -> SimValue<Bool> {
let lhs_ty = lhs.ty();
let rhs_ty = rhs.ty();
let lhs = match lhs {
Cow::Borrowed(v) => Cow::Borrowed(&**v),
Cow::Owned(v) => Cow::Owned(SimValue::into_value(v)),
};
let rhs = match rhs {
Cow::Borrowed(v) => Cow::Borrowed(&**v),
Cow::Owned(v) => Cow::Owned(SimValue::into_value(v)),
};
Self::$cmp_value_fn(lhs_ty, lhs, rhs_ty, rhs).to_sim_value()
})+
$(#[track_caller]
fn $cmp_expr_fn($cmp_expr_lhs: Expr<Self>, $cmp_expr_rhs: Expr<$Rhs>) -> Expr<Bool>
$cmp_expr_body)+
$(#[track_caller]
fn $cmp_valueless_fn(lhs: Valueless<Self>, rhs: Valueless<$Rhs>) -> Valueless<Bool> {
let _ = lhs;
let _ = rhs;
Valueless::new(Bool)
})+
}
trait $HdlCmpImplHelperSealed<$Rhs, Common> {}
#[expect(private_bounds)]
$vis trait $HdlCmpImplHelper<$Rhs: ValueType, Common: value_category::ValueCategory>:
$HdlCmpImplHelperSealed<$Rhs, Common>
+ ValueType<Type: $HdlCmpImpl<$Rhs::Type>>
$(+ $HdlCmpImplHelperBase<$Rhs, Common>)?
{
$(type $Output: ValueType<Type = Bool>;)?
$(#[track_caller]
fn $cmp_fn_helper(&self, rhs: $Rhs) -> Self::Output;)+
}
impl<Lhs, $Rhs, LTy, RTy, LC, RC, Common> $HdlCmp<$Rhs> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy, ValueCategory = LC> $(+ $HdlCmpBase<$Rhs>)?,
$Rhs: ValueType<Type = RTy, ValueCategory = RC>,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
LC: value_category::ValueCategory + value_category::ValueCategoryCommon<(RC,), Common = Common>,
RC: value_category::ValueCategory,
Common: value_category::ValueCategory,
Lhs: $HdlCmpImplHelper<$Rhs, Common> $(+ $HdlCmpImplHelperBase<$Rhs, Common, Output = Self::Output>)?,
{
$(type $Output = <Lhs as $HdlCmpImplHelper<$Rhs, Common>>::Output;)?
$(#[track_caller]
fn $cmp_fn(&self, rhs: $Rhs) -> Self::Output {
<Lhs as $HdlCmpImplHelper<$Rhs, Common>>::$cmp_fn_helper(self, rhs)
})+
}
impl<'l, 'r, Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelperSealed<$Rhs, value_category::ValueCategoryValue> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy> + ToSimValueInner<'l>
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategoryValue, Output = bool>)?,
$Rhs: ValueType<Type = RTy> + ToSimValueInner<'r>,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
}
impl<'l, 'r, Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelper<$Rhs, value_category::ValueCategoryValue> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy> + ToSimValueInner<'l>
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategoryValue, Output = bool>)?,
$Rhs: ValueType<Type = RTy> + ToSimValueInner<'r>,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
$(type $Output = bool;)?
$(#[track_caller]
fn $cmp_fn_helper(&self, rhs: Rhs) -> Self::Output {
$HdlCmpImpl::$cmp_value_fn(
self.ty(),
Lhs::to_sim_value_inner(self),
rhs.ty(),
$Rhs::into_sim_value_inner(rhs),
)
})+
}
impl<Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelperSealed<$Rhs, value_category::ValueCategorySimValue> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy> + ToSimValue
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategorySimValue, Output = SimValue<Bool>>)?,
$Rhs: ValueType<Type = RTy> + ToSimValue,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
}
impl<Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelper<$Rhs, value_category::ValueCategorySimValue> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy> + ToSimValue
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategorySimValue, Output = SimValue<Bool>>)?,
$Rhs: ValueType<Type = RTy> + ToSimValue,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
$(type $Output = SimValue<Bool>;)?
$(#[track_caller]
fn $cmp_fn_helper(&self, rhs: Rhs) -> Self::Output {
$HdlCmpImpl::$cmp_sim_value_fn(Cow::Owned(Lhs::to_sim_value(self)), Cow::Owned($Rhs::into_sim_value(rhs)))
})+
}
impl<Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelperSealed<$Rhs, value_category::ValueCategoryExpr> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy> + ToExpr
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategoryExpr, Output = Expr<Bool>>)?,
$Rhs: ValueType<Type = RTy> + ToExpr,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
}
impl<Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelper<$Rhs, value_category::ValueCategoryExpr> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy> + ToExpr
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategoryExpr, Output = Expr<Bool>>)?,
$Rhs: ValueType<Type = RTy> + ToExpr,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
$(type $Output = Expr<Bool>;)?
$(#[track_caller]
fn $cmp_fn_helper(&self, rhs: Rhs) -> Self::Output {
$HdlCmpImpl::$cmp_expr_fn(Lhs::to_expr(self), $Rhs::to_expr(&rhs))
})+
}
impl<Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelperSealed<$Rhs, value_category::ValueCategoryValueless> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy>
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategoryValueless, Output = Valueless<Bool>>)?,
$Rhs: ValueType<Type = RTy>,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
}
impl<Lhs, $Rhs, LTy, RTy> $HdlCmpImplHelper<$Rhs, value_category::ValueCategoryValueless> for Lhs
where
Lhs: ?Sized + ValueType<Type = LTy>
$(+ $HdlCmpImplHelperBase<$Rhs, value_category::ValueCategoryValueless, Output = Valueless<Bool>>)?,
$Rhs: ValueType<Type = RTy>,
LTy: Type + $HdlCmpImpl<RTy>,
RTy: Type,
{
$(type $Output = Valueless<Bool>;)?
$(#[track_caller]
fn $cmp_fn_helper(&self, rhs: Rhs) -> Self::Output {
$HdlCmpImpl::$cmp_valueless_fn(Lhs::to_valueless(self), $Rhs::to_valueless(&rhs))
})+
}
};
}
impl_hdl_cmp! {
#[
impl_helper = HdlPartialEqImplHelper,
impl_helper_sealed = HdlPartialEqImplHelperSealed,
]
pub trait HdlPartialEq<Rhs: ValueType>:
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
{
type Output: ValueType<Type = Bool>;
#[
helper = cmp_eq_helper;
value = cmp_value_eq(lhs, lhs_value, rhs, rhs_value);
sim_value = cmp_sim_value_eq;
expr = cmp_expr_eq(lhs, rhs);
valueless = cmp_valueless_eq;
]
fn cmp_eq(&self, rhs: Rhs) -> Self::Output;
#[
helper = cmp_ne_helper;
value = cmp_value_ne(lhs, lhs_value, rhs, rhs_value) {
!Self::cmp_value_eq(lhs, lhs_value, rhs, rhs_value)
}
sim_value = cmp_sim_value_ne;
expr = cmp_expr_ne(lhs, rhs) {
!Self::cmp_expr_eq(lhs, rhs)
}
valueless = cmp_valueless_ne;
]
fn cmp_ne(&self, rhs: Rhs) -> Self::Output;
}
}
impl_hdl_cmp! {
#[
impl_helper = HdlPartialOrdImplHelper,
impl_helper_base = HdlPartialEqImplHelper,
impl_helper_sealed = HdlPartialOrdImplHelperSealed,
]
pub trait HdlPartialOrd<Rhs: ValueType>:
ValueType<Type: HdlPartialOrdImpl<Rhs::Type> + HdlPartialEqImpl<Rhs::Type> >
+ HdlPartialEq<Rhs>
{
#[
helper = cmp_lt_helper;
value = cmp_value_lt(lhs, lhs_value, rhs, rhs_value);
sim_value = cmp_sim_value_lt;
expr = cmp_expr_lt(lhs, rhs);
valueless = cmp_valueless_lt;
]
fn cmp_lt(&self, rhs: Rhs) -> Self::Output;
#[
helper = cmp_le_helper;
value = cmp_value_le(lhs, lhs_value, rhs, rhs_value);
sim_value = cmp_sim_value_le;
expr = cmp_expr_le(lhs, rhs);
valueless = cmp_valueless_le;
]
fn cmp_le(&self, rhs: Rhs) -> Self::Output;
#[
helper = cmp_gt_helper;
value = cmp_value_gt(lhs, lhs_value, rhs, rhs_value);
sim_value = cmp_sim_value_gt;
expr = cmp_expr_gt(lhs, rhs);
valueless = cmp_valueless_gt;
]
fn cmp_gt(&self, rhs: Rhs) -> Self::Output;
#[
helper = cmp_ge_helper;
value = cmp_value_ge(lhs, lhs_value, rhs, rhs_value);
sim_value = cmp_sim_value_ge;
expr = cmp_expr_ge(lhs, rhs);
valueless = cmp_valueless_ge;
]
fn cmp_ge(&self, rhs: Rhs) -> Self::Output;
}
}
macro_rules! make_reduce_bits_traits {
(
$vis:vis trait $ReduceBits:ident {
$(type $Output:ident: ValueType<Type = $OutputTy:ty>;)*
$(#[
ty = $ty:ty,
value_ty = $value_ty:ty,
value = $value_f:ident($value_this:ident, $value_value:ident) $value_body:tt
sim_value = $sim_value_f:ident,
expr = $expr_f:ident($expr_this:ident) $expr_body:tt
valueless = $valueless_f:ident,
]
fn $f:ident(&self) -> Self::$FnOutput:ident;)*
}
) => {
$vis trait $ReduceBits {
$(type $Output: ValueType<Type = $OutputTy>;)*
$(fn $f(&self) -> Self::$FnOutput;)*
}
trait ReduceBitsImplHelperSealed<C> {}
#[expect(private_bounds)]
$vis trait ReduceBitsImplHelper<C: value_category::ValueCategory>: ReduceBitsImplHelperSealed<C> {
$(type $Output: ValueType<Type = $OutputTy>;)*
$(fn $f(this: &Self) -> Self::$FnOutput;)*
}
impl<T: ?Sized + ValueType + ReduceBitsImplHelper<<T as ValueType>::ValueCategory>> $ReduceBits for T {
$(type $Output = <T as ReduceBitsImplHelper<<T as ValueType>::ValueCategory>>::$Output;)*
$(fn $f(&self) -> Self::$FnOutput {
<T as ReduceBitsImplHelper<<T as ValueType>::ValueCategory>>::$f(self)
})*
}
$vis trait ReduceBitsImpl: Type {
$(fn $value_f($value_this: Self, $value_value: Cow<'_, Self::SimValue>) -> $value_ty $value_body)*
$(fn $sim_value_f(this: Cow<'_, SimValue<Self>>) -> SimValue<$ty> {
let ty = this.ty();
let value = match this {
Cow::Borrowed(v) => Cow::Borrowed(SimValue::value(v)),
Cow::Owned(v) => Cow::Owned(SimValue::into_value(v)),
};
Self::$value_f(ty, value).into_sim_value()
})*
$(fn $expr_f($expr_this: Expr<Self>) -> Expr<$ty> $expr_body)*
$(fn $valueless_f(_this: Valueless<Self>) -> Valueless<$ty> {
Valueless::new(StaticType::TYPE)
})*
}
impl<'a, T> ReduceBitsImplHelperSealed<value_category::ValueCategoryValue> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategoryValue> + ToSimValueInner<'a>,
{
}
impl<'a, T> ReduceBitsImplHelper<value_category::ValueCategoryValue> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategoryValue> + ToSimValueInner<'a>,
{
type UIntOutput = UIntValue<ConstUsize<1>>;
type BoolOutput = bool;
$(fn $f(this: &Self) -> Self::$FnOutput {
T::Type::$value_f(this.ty(), Self::to_sim_value_inner(this))
})*
}
impl<'a, T> ReduceBitsImplHelperSealed<value_category::ValueCategorySimValue> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategorySimValue> + ToSimValue,
{
}
impl<'a, T> ReduceBitsImplHelper<value_category::ValueCategorySimValue> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategorySimValue> + ToSimValue,
{
type UIntOutput = SimValue<UInt<1>>;
type BoolOutput = SimValue<Bool>;
$(fn $f(this: &Self) -> Self::$FnOutput {
T::Type::$sim_value_f(Cow::Owned(this.to_sim_value()))
})*
}
impl<'a, T> ReduceBitsImplHelperSealed<value_category::ValueCategoryExpr> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategoryExpr> + ToExpr,
{
}
impl<'a, T> ReduceBitsImplHelper<value_category::ValueCategoryExpr> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategoryExpr> + ToExpr,
{
type UIntOutput = Expr<UInt<1>>;
type BoolOutput = Expr<Bool>;
$(fn $f(this: &Self) -> Self::$FnOutput {
T::Type::$expr_f(this.to_expr())
})*
}
impl<'a, T> ReduceBitsImplHelperSealed<value_category::ValueCategoryValueless> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategoryValueless>,
{
}
impl<'a, T> ReduceBitsImplHelper<value_category::ValueCategoryValueless> for T
where
T: ?Sized + ValueType<Type: ReduceBitsImpl, ValueCategory = value_category::ValueCategoryValueless>,
{
type UIntOutput = Valueless<UInt<1>>;
type BoolOutput = Valueless<Bool>;
$(fn $f(this: &Self) -> Self::$FnOutput {
T::Type::$valueless_f(this.to_valueless())
})*
}
};
}
make_reduce_bits_traits! {
pub trait ReduceBits {
type UIntOutput: ValueType<Type = UInt<1>>;
type BoolOutput: ValueType<Type = Bool>;
#[
ty = UInt<1>,
value_ty = UIntValue<ConstUsize<1>>,
value = value_reduce_bitand(this, value);
sim_value = sim_value_reduce_bitand,
expr = expr_reduce_bitand(this);
valueless = valueless_reduce_bitand,
]
fn reduce_bitand(&self) -> Self::UIntOutput;
#[
ty = UInt<1>,
value_ty = UIntValue<ConstUsize<1>>,
value = value_reduce_bitor(this, value);
sim_value = sim_value_reduce_bitor,
expr = expr_reduce_bitor(this);
valueless = valueless_reduce_bitor,
]
fn reduce_bitor(&self) -> Self::UIntOutput;
#[
ty = UInt<1>,
value_ty = UIntValue<ConstUsize<1>>,
value = value_reduce_bitxor(this, value);
sim_value = sim_value_reduce_bitxor,
expr = expr_reduce_bitxor(this);
valueless = valueless_reduce_bitxor,
]
fn reduce_bitxor(&self) -> Self::UIntOutput;
#[
ty = Bool,
value_ty = bool,
value = value_any_one_bits(this, value) {
Self::value_reduce_bitor(this, value).bits()[0]
}
sim_value = sim_value_any_one_bits,
expr = expr_any_one_bits(this) {
this.reduce_bitor().cast_to_static()
}
valueless = valueless_any_one_bits,
]
fn any_one_bits(&self) -> Self::BoolOutput;
#[
ty = Bool,
value_ty = bool,
value = value_any_zero_bits(this, value) {
!Self::value_reduce_bitand(this, value).bits()[0]
}
sim_value = sim_value_any_zero_bits,
expr = expr_any_zero_bits(this) {
(!this.reduce_bitand()).cast_to_static()
}
valueless = valueless_any_zero_bits,
]
fn any_zero_bits(&self) -> Self::BoolOutput;
#[
ty = Bool,
value_ty = bool,
value = value_all_one_bits(this, value) {
Self::value_reduce_bitand(this, value).bits()[0]
}
sim_value = sim_value_all_one_bits,
expr = expr_all_one_bits(this) {
this.reduce_bitand().cast_to_static()
}
valueless = valueless_all_one_bits,
]
fn all_one_bits(&self) -> Self::BoolOutput;
#[
ty = Bool,
value_ty = bool,
value = value_all_zero_bits(this, value) {
!Self::value_reduce_bitor(this, value).bits()[0]
}
sim_value = sim_value_all_zero_bits,
expr = expr_all_zero_bits(this) {
(!this.reduce_bitor()).cast_to_static()
}
valueless = valueless_all_zero_bits,
]
fn all_zero_bits(&self) -> Self::BoolOutput;
#[
ty = Bool,
value_ty = bool,
value = value_parity_odd(this, value) {
Self::value_reduce_bitxor(this, value).bits()[0]
}
sim_value = sim_value_parity_odd,
expr = expr_parity_odd(this) {
this.reduce_bitxor().cast_to_static()
}
valueless = valueless_parity_odd,
]
fn parity_odd(&self) -> Self::BoolOutput;
#[
ty = Bool,
value_ty = bool,
value = value_parity_even(this, value) {
!Self::value_reduce_bitxor(this, value).bits()[0]
}
sim_value = sim_value_parity_even,
expr = expr_parity_even(this) {
(!this.reduce_bitxor()).cast_to_static()
}
valueless = valueless_parity_even,
]
fn parity_even(&self) -> Self::BoolOutput;
}
}
pub trait CastToBits: ValueType {
type Output: ValueType<Type = UInt, ValueCategory = Self::ValueCategory>;
fn cast_to_bits(&self) -> Self::Output;
}
impl<T: ?Sized + ValueType + CastToBitsImpl<Self::ValueCategory>> CastToBits for T {
type Output = T::ImplOutput;
fn cast_to_bits(&self) -> Self::Output {
Self::cast_to_bits_impl(self)
}
}
pub trait CastToBitsImpl<C: value_category::ValueCategory> {
type ImplOutput: ValueType<Type = UInt, ValueCategory = C>;
fn cast_to_bits_impl(this: &Self) -> Self::ImplOutput;
}
impl<T: ?Sized + ValueType + crate::sim::value::ToSimValue>
CastToBitsImpl<value_category::ValueCategoryValue> for T
{
type ImplOutput = UIntValue;
fn cast_to_bits_impl(this: &Self) -> Self::ImplOutput {
crate::sim::value::SimValue::bits(&this.to_sim_value()).clone()
}
}
impl<T: ?Sized + ValueType + crate::sim::value::ToSimValue>
CastToBitsImpl<value_category::ValueCategorySimValue> for T
{
type ImplOutput = SimValue<UInt>;
fn cast_to_bits_impl(this: &Self) -> Self::ImplOutput {
crate::sim::value::SimValue::bits(&this.to_sim_value()).to_sim_value()
}
}
impl<T: ?Sized + ValueType + ToExpr> CastToBitsImpl<value_category::ValueCategoryExpr> for T {
type ImplOutput = Expr<UInt>;
fn cast_to_bits_impl(this: &Self) -> Self::ImplOutput {
ops::CastToBits::new(Expr::canonical(this.to_expr())).to_expr()
}
}
impl<T: ?Sized + ValueType> CastToBitsImpl<value_category::ValueCategoryValueless> for T {
type ImplOutput = Valueless<UInt>;
fn cast_to_bits_impl(this: &Self) -> Self::ImplOutput {
Valueless::new(UInt::new_dyn(this.ty().canonical().bit_width()))
}
}
pub trait CastBitsTo: ValueType<Type: IntType<Signed = ConstBool<false>>> {
type Output<T: Type>: ValueType<Type = T>;
#[track_caller]
fn cast_bits_to<T: Type>(&self, ty: T) -> Self::Output<T>;
}
impl<
This: ?Sized + ValueType<Type = UIntType<Width>> + CastBitsToImpl<Self::ValueCategory>,
Width: Size,
> CastBitsTo for This
{
type Output<T: Type> = This::ImplOutput<T>;
#[track_caller]
fn cast_bits_to<T: Type>(&self, ty: T) -> Self::Output<T> {
Self::cast_bits_to_impl(self, ty)
}
}
pub trait CastBitsToImpl<C: value_category::ValueCategory> {
type ImplOutput<T: Type>: ValueType<Type = T>;
#[track_caller]
fn cast_bits_to_impl<T: Type>(this: &Self, ty: T) -> Self::ImplOutput<T>;
}
impl<
'a,
This: ?Sized + ValueType<Type = UIntType<Width>> + ToSimValueInner<'a>,
Width: Size,
C: value_category::ValueCategoryIsValueOrSimValue,
> CastBitsToImpl<C> for This
{
type ImplOutput<T: Type> = SimValue<T>;
#[track_caller]
fn cast_bits_to_impl<T: Type>(this: &Self, ty: T) -> Self::ImplOutput<T> {
let ty_props = ty.canonical().type_properties();
assert!(ty_props.is_castable_from_bits);
assert_eq!(this.ty().width(), ty_props.bit_width);
crate::sim::value::SimValue::from_opaque(
ty,
OpaqueSimValue::from_bits(Self::to_sim_value_inner(this).into_owned().as_dyn_int()),
)
}
}
impl<This: ?Sized + ValueType<Type = UIntType<Width>> + ToExpr, Width: Size>
CastBitsToImpl<value_category::ValueCategoryExpr> for This
{
type ImplOutput<T: Type> = Expr<T>;
#[track_caller]
fn cast_bits_to_impl<T: Type>(this: &Self, ty: T) -> Self::ImplOutput<T> {
ops::CastBitsTo::new(Expr::as_dyn_int(this.to_expr()), ty).to_expr()
}
}
impl<This: ?Sized + ValueType<Type = UIntType<Width>>, Width: Size>
CastBitsToImpl<value_category::ValueCategoryValueless> for This
{
type ImplOutput<T: Type> = Valueless<T>;
#[track_caller]
fn cast_bits_to_impl<T: Type>(this: &Self, ty: T) -> Self::ImplOutput<T> {
let ty_props = ty.canonical().type_properties();
assert!(ty_props.is_castable_from_bits);
assert_eq!(this.ty().width(), ty_props.bit_width);
Valueless::new(ty)
}
}
pub trait CastToImpl<ToType: Type>: Type {
type ValueOutput: ValueType<Type = ToType, ValueCategory: value_category::ValueCategoryIsValueOrSimValue>
+ ToSimValueWithType<ToType>;
#[track_caller]
fn cast_value_to(
this: Self,
value: Cow<'_, Self::SimValue>,
to_type: ToType,
) -> Self::ValueOutput;
#[track_caller]
fn cast_sim_value_to(value: Cow<'_, SimValue<Self>>, to_type: ToType) -> SimValue<ToType> {
let ty = value.ty();
let value = match value {
Cow::Borrowed(value) => Cow::Borrowed(&**value),
Cow::Owned(value) => Cow::Owned(SimValue::into_value(value)),
};
Self::cast_value_to(ty, value, to_type).into_sim_value_with_type(to_type)
}
#[track_caller]
fn cast_expr_to(value: Expr<Self>, to_type: ToType) -> Expr<ToType>;
#[track_caller]
fn cast_valueless_to(value: Valueless<Self>, to_type: ToType) -> Valueless<ToType> {
let _ = value;
Valueless::new(to_type)
}
}
trait CastToImplHelperSealed<C> {}
#[expect(private_bounds)]
pub trait CastToImplHelper<C: value_category::ValueCategory>:
ValueType<ValueCategory = C> + CastToImplHelperSealed<C>
{
type Output<ToType: Type>: ValueType<Type = ToType>
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to_impl_helper<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>;
}
impl<
'a,
This: ?Sized + ValueType<ValueCategory = value_category::ValueCategoryValue> + ToSimValueInner<'a>,
> CastToImplHelperSealed<value_category::ValueCategoryValue> for This
{
}
impl<
'a,
This: ?Sized + ValueType<ValueCategory = value_category::ValueCategoryValue> + ToSimValueInner<'a>,
> CastToImplHelper<value_category::ValueCategoryValue> for This
{
type Output<ToType: Type>
= <Self::Type as CastToImpl<ToType>>::ValueOutput
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to_impl_helper<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>,
{
Self::Type::cast_value_to(self.ty(), Self::to_sim_value_inner(self), to_type)
}
}
impl<This: ?Sized + ValueType<ValueCategory = value_category::ValueCategorySimValue> + ToSimValue>
CastToImplHelperSealed<value_category::ValueCategorySimValue> for This
{
}
impl<This: ?Sized + ValueType<ValueCategory = value_category::ValueCategorySimValue> + ToSimValue>
CastToImplHelper<value_category::ValueCategorySimValue> for This
{
type Output<ToType: Type>
= SimValue<ToType>
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to_impl_helper<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>,
{
Self::Type::cast_sim_value_to(Cow::Owned(self.to_sim_value()), to_type)
}
}
impl<This: ?Sized + ValueType<ValueCategory = value_category::ValueCategoryExpr> + ToExpr>
CastToImplHelperSealed<value_category::ValueCategoryExpr> for This
{
}
impl<This: ?Sized + ValueType<ValueCategory = value_category::ValueCategoryExpr> + ToExpr>
CastToImplHelper<value_category::ValueCategoryExpr> for This
{
type Output<ToType: Type>
= Expr<ToType>
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to_impl_helper<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>,
{
Self::Type::cast_expr_to(self.to_expr(), to_type)
}
}
impl<This: ?Sized + ValueType<ValueCategory = value_category::ValueCategoryValueless>>
CastToImplHelperSealed<value_category::ValueCategoryValueless> for This
{
}
impl<This: ?Sized + ValueType<ValueCategory = value_category::ValueCategoryValueless>>
CastToImplHelper<value_category::ValueCategoryValueless> for This
{
type Output<ToType: Type>
= Valueless<ToType>
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to_impl_helper<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>,
{
Self::Type::cast_valueless_to(self.to_valueless(), to_type)
}
}
pub trait CastTo: ValueType {
type Output<ToType: Type>: ValueType<Type = ToType>
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>;
#[track_caller]
fn cast_to_static<ToType: StaticType>(&self) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>,
{
self.cast_to(ToType::TYPE)
}
}
impl<
T: ValueType<ValueCategory = C> + CastToImplHelper<C> + ?Sized,
C: value_category::ValueCategory,
> CastTo for T
{
type Output<ToType: Type>
= <Self as CastToImplHelper<C>>::Output<ToType>
where
Self::Type: CastToImpl<ToType>;
fn cast_to<ToType: Type>(&self, to_type: ToType) -> Self::Output<ToType>
where
Self::Type: CastToImpl<ToType>,
{
Self::cast_to_impl_helper(self, to_type)
}
}
#[doc(hidden)]
pub fn check_match_expr<T: Type>(
_expr: Expr<T>,
_check_fn: impl FnOnce(T::MatchVariant, Infallible),
) {
}
pub trait MakeUninitExpr: Type {
fn uninit(self) -> Expr<Self>;
}
impl<T: Type> MakeUninitExpr for T {
fn uninit(self) -> Expr<Self> {
ops::Uninit::new(self).to_expr()
}
}
pub fn repeat<T: Type, L: SizeType>(
element: impl ToExpr<Type = T>,
len: L,
) -> Expr<ArrayType<T, L::Size>> {
let element = element.to_expr();
let canonical_element = Expr::canonical(element);
ops::ArrayLiteral::new(
element.ty(),
std::iter::repeat(canonical_element)
.take(L::Size::as_usize(len))
.collect(),
)
.to_expr()
}
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ValueType for PhantomConst<T> {
type Type = Self;
type ValueCategory = value_category::ValueCategoryValue;
fn ty(&self) -> Self::Type {
*self
}
}
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToExpr for PhantomConst<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(),
__ty: *self,
__flow: Flow::Source,
}
}
}
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> GetTarget for PhantomConst<T> {
fn target(&self) -> Option<Interned<Target>> {
None
}
}
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToLiteralBits for PhantomConst<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Ok(Interned::default())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Valueless<T: Type>(T);
impl<T: Type> Valueless<T> {
pub const fn new(ty: T) -> Self {
Self(ty)
}
pub const fn ty(self) -> T {
self.0
}
}
impl<T: StaticType> Default for Valueless<T> {
fn default() -> Self {
Self(T::TYPE)
}
}
pub trait ValueType {
type Type: Type;
type ValueCategory: value_category::ValueCategory;
fn ty(&self) -> Self::Type;
}
trait ToValuelessSealed {}
#[expect(private_bounds)]
pub trait ToValueless: ValueType + ToValuelessSealed {
fn to_valueless(&self) -> Valueless<Self::Type> {
Valueless::new(self.ty())
}
}
impl<T: ?Sized + ValueType> ToValuelessSealed for T {}
impl<T: ?Sized + ValueType> ToValueless for T {}
impl<T: Type> ValueType for Valueless<T> {
type Type = T;
type ValueCategory = value_category::ValueCategoryValueless;
fn ty(&self) -> Self::Type {
self.0
}
}
impl<'a, T: ?Sized + ValueType> ValueType for &'a T {
type Type = T::Type;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
T::ty(self)
}
}
impl<'a, T: ?Sized + ValueType> ValueType for &'a mut T {
type Type = T::Type;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
T::ty(self)
}
}
impl<T: ?Sized + ValueType> ValueType for Box<T> {
type Type = T::Type;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
T::ty(self)
}
}
impl<T: ?Sized + ValueType> ValueType for std::sync::Arc<T> {
type Type = T::Type;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
T::ty(self)
}
}
impl<T: ?Sized + ValueType> ValueType for std::rc::Rc<T> {
type Type = T::Type;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
T::ty(self)
}
}
impl<T: ?Sized + ValueType + 'static + Send + Sync> ValueType for Interned<T> {
type Type = T::Type;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
T::ty(self)
}
}
impl<T: Type> ValueType for Expr<T> {
type Type = T;
type ValueCategory = value_category::ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.__ty
}
}
pub trait ToSimValueInner<'a>: ValueType {
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue>;
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue>
where
Self: Sized;
}
impl<'a, T: Type> ToSimValueInner<'a> for SimValue<T> {
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
Cow::Borrowed(&**this)
}
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
Cow::Owned(SimValue::into_value(this))
}
}
impl<'a, T: Type> ToSimValueInner<'a> for &'a SimValue<T> {
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
Cow::Borrowed(&***this)
}
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
Cow::Borrowed(&**this)
}
}