1694 lines
52 KiB
Rust
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)
|
|
}
|
|
}
|