forked from libre-chip/fayalite
2120 lines
66 KiB
Rust
2120 lines
66 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
|
|
use crate::{
|
|
array::Array,
|
|
bundle::{Bundle, BundleField, BundleType},
|
|
clock::Clock,
|
|
enum_::{Enum, EnumType, EnumVariant},
|
|
expr::{Expr, HdlPartialEqImpl, HdlPartialOrdImpl, ToExpr, ValueType, Valueless, ops},
|
|
int::{Bool, SInt, UInt, UIntValue},
|
|
intern::{Intern, Interned, LazyInterned, Memoize, SupportsPtrEqWithTypeId},
|
|
module::transform::visit::{Fold, Folder, Visit, Visitor},
|
|
phantom_const::PhantomConst,
|
|
reset::{AsyncReset, Reset, SyncReset},
|
|
sim::value::{DynSimOnly, DynSimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
|
|
source_location::SourceLocation,
|
|
util::{
|
|
ConstUsize, iter_eq_by,
|
|
serde_by_id::{SerdeByIdProperties, SerdeByIdTable, SerdeByIdTrait},
|
|
slice_range, try_slice_range,
|
|
},
|
|
};
|
|
use bitvec::{slice::BitSlice, vec::BitVec};
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
|
|
use std::{
|
|
borrow::Cow,
|
|
fmt::{self, Write},
|
|
hash::Hash,
|
|
iter::{FusedIterator, Sum},
|
|
marker::PhantomData,
|
|
mem,
|
|
ops::{Add, AddAssign, Bound, Index, Mul, MulAssign, Range, Sub, SubAssign},
|
|
sync::Arc,
|
|
};
|
|
|
|
pub(crate) mod serde_impls;
|
|
|
|
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
|
|
#[non_exhaustive]
|
|
pub struct TypeProperties {
|
|
pub is_passive: bool,
|
|
pub is_storable: bool,
|
|
pub is_castable_from_bits: bool,
|
|
pub bit_width: usize,
|
|
pub sim_only_values_len: usize,
|
|
}
|
|
|
|
impl TypeProperties {
|
|
pub const fn size(self) -> OpaqueSimValueSize {
|
|
let Self {
|
|
is_passive: _,
|
|
is_storable: _,
|
|
is_castable_from_bits: _,
|
|
bit_width,
|
|
sim_only_values_len,
|
|
} = self;
|
|
OpaqueSimValueSize {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
|
pub enum CanonicalType {
|
|
UInt(UInt),
|
|
SInt(SInt),
|
|
Bool(Bool),
|
|
Array(Array),
|
|
Enum(Enum),
|
|
Bundle(Bundle),
|
|
AsyncReset(AsyncReset),
|
|
SyncReset(SyncReset),
|
|
Reset(Reset),
|
|
Clock(Clock),
|
|
PhantomConst(PhantomConst),
|
|
DynSimOnly(DynSimOnly),
|
|
TraceAsString(TraceAsString),
|
|
}
|
|
|
|
impl fmt::Debug for CanonicalType {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::UInt(v) => v.fmt(f),
|
|
Self::SInt(v) => v.fmt(f),
|
|
Self::Bool(v) => v.fmt(f),
|
|
Self::Array(v) => v.fmt(f),
|
|
Self::Enum(v) => v.fmt(f),
|
|
Self::Bundle(v) => v.fmt(f),
|
|
Self::AsyncReset(v) => v.fmt(f),
|
|
Self::SyncReset(v) => v.fmt(f),
|
|
Self::Reset(v) => v.fmt(f),
|
|
Self::Clock(v) => v.fmt(f),
|
|
Self::PhantomConst(v) => v.fmt(f),
|
|
Self::DynSimOnly(v) => v.fmt(f),
|
|
Self::TraceAsString(v) => v.fmt(f),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Serialize for CanonicalType {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
serde_impls::SerdeCanonicalType::from(*self).serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for CanonicalType {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
Ok(serde_impls::SerdeCanonicalType::deserialize(deserializer)?.into())
|
|
}
|
|
}
|
|
|
|
impl CanonicalType {
|
|
pub fn type_properties(self) -> TypeProperties {
|
|
match self {
|
|
CanonicalType::UInt(v) => v.type_properties(),
|
|
CanonicalType::SInt(v) => v.type_properties(),
|
|
CanonicalType::Bool(v) => v.type_properties(),
|
|
CanonicalType::Array(v) => v.type_properties(),
|
|
CanonicalType::Enum(v) => v.type_properties(),
|
|
CanonicalType::Bundle(v) => v.type_properties(),
|
|
CanonicalType::AsyncReset(v) => v.type_properties(),
|
|
CanonicalType::SyncReset(v) => v.type_properties(),
|
|
CanonicalType::Reset(v) => v.type_properties(),
|
|
CanonicalType::Clock(v) => v.type_properties(),
|
|
CanonicalType::PhantomConst(v) => v.type_properties(),
|
|
CanonicalType::DynSimOnly(v) => v.type_properties(),
|
|
CanonicalType::TraceAsString(v) => v.type_properties(),
|
|
}
|
|
}
|
|
pub fn is_passive(self) -> bool {
|
|
self.type_properties().is_passive
|
|
}
|
|
pub fn is_storable(self) -> bool {
|
|
self.type_properties().is_storable
|
|
}
|
|
pub fn is_castable_from_bits(self) -> bool {
|
|
self.type_properties().is_castable_from_bits
|
|
}
|
|
pub fn bit_width(self) -> usize {
|
|
self.type_properties().bit_width
|
|
}
|
|
pub fn sim_only_values_len(self) -> usize {
|
|
self.type_properties().sim_only_values_len
|
|
}
|
|
pub fn size(self) -> OpaqueSimValueSize {
|
|
self.type_properties().size()
|
|
}
|
|
pub fn can_connect(self, rhs: Self) -> bool {
|
|
match self {
|
|
CanonicalType::UInt(lhs) => {
|
|
let CanonicalType::UInt(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::SInt(lhs) => {
|
|
let CanonicalType::SInt(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::Bool(lhs) => {
|
|
let CanonicalType::Bool(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::Array(lhs) => {
|
|
let CanonicalType::Array(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::Enum(lhs) => {
|
|
let CanonicalType::Enum(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::Bundle(lhs) => {
|
|
let CanonicalType::Bundle(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::AsyncReset(lhs) => {
|
|
let CanonicalType::AsyncReset(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::SyncReset(lhs) => {
|
|
let CanonicalType::SyncReset(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::Reset(lhs) => {
|
|
let CanonicalType::Reset(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::Clock(lhs) => {
|
|
let CanonicalType::Clock(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::PhantomConst(lhs) => {
|
|
let CanonicalType::PhantomConst(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::DynSimOnly(lhs) => {
|
|
let CanonicalType::DynSimOnly(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
CanonicalType::TraceAsString(lhs) => {
|
|
let CanonicalType::TraceAsString(rhs) = rhs else {
|
|
return false;
|
|
};
|
|
lhs.can_connect(rhs)
|
|
}
|
|
}
|
|
}
|
|
pub(crate) fn as_serde_unexpected_str(self) -> &'static str {
|
|
serde_impls::SerdeCanonicalType::from(self).as_serde_unexpected_str()
|
|
}
|
|
/// Unwrap transparent types until reaching a non-transparent type. Currently [`TraceAsString`] is the only transparent type.
|
|
///
|
|
/// [`TraceAsString`]: struct@TraceAsString
|
|
pub fn unwrap_transparent_types(mut self) -> Self {
|
|
loop {
|
|
self = match self {
|
|
Self::UInt(_)
|
|
| Self::SInt(_)
|
|
| Self::Bool(_)
|
|
| Self::Array(_)
|
|
| Self::Enum(_)
|
|
| Self::Bundle(_)
|
|
| Self::AsyncReset(_)
|
|
| Self::SyncReset(_)
|
|
| Self::Reset(_)
|
|
| Self::Clock(_)
|
|
| Self::PhantomConst(_)
|
|
| Self::DynSimOnly(_) => return self,
|
|
Self::TraceAsString(ty) => ty.inner_ty(),
|
|
};
|
|
}
|
|
}
|
|
pub fn is_layout_equivalent(self, other: Self) -> bool {
|
|
fn is_bit(ty: CanonicalType) -> bool {
|
|
match ty {
|
|
CanonicalType::UInt(ty) => ty.width() == 1,
|
|
CanonicalType::SInt(_) => false, // SInt<1> doesn't count since it would be -1/0 instead of 1/0
|
|
CanonicalType::Bool(_)
|
|
| CanonicalType::AsyncReset(_)
|
|
| CanonicalType::SyncReset(_)
|
|
| CanonicalType::Reset(_)
|
|
| CanonicalType::Clock(_) => true,
|
|
CanonicalType::Array(_)
|
|
| CanonicalType::Enum(_)
|
|
| CanonicalType::Bundle(_)
|
|
| CanonicalType::PhantomConst(_)
|
|
| CanonicalType::DynSimOnly(_) => false,
|
|
CanonicalType::TraceAsString(_) => {
|
|
unreachable!("handled by unwrap_transparent_types")
|
|
}
|
|
}
|
|
}
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
struct MyMemoize;
|
|
impl Memoize for MyMemoize {
|
|
type Input = (CanonicalType, CanonicalType);
|
|
type InputOwned = (CanonicalType, CanonicalType);
|
|
type Output = bool;
|
|
|
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
|
let (this, other) = *input;
|
|
let this = this.unwrap_transparent_types();
|
|
let other = other.unwrap_transparent_types();
|
|
let this_is_bit = is_bit(this);
|
|
let other_is_bit = is_bit(other);
|
|
if this_is_bit || other_is_bit {
|
|
return this_is_bit && other_is_bit;
|
|
}
|
|
let this_is_empty = this.size().is_empty();
|
|
let other_is_empty = other.size().is_empty();
|
|
if this_is_empty || other_is_empty {
|
|
return this_is_empty && other_is_empty;
|
|
}
|
|
match this {
|
|
CanonicalType::UInt(_)
|
|
| CanonicalType::SInt(_)
|
|
| CanonicalType::DynSimOnly(_) => this == other,
|
|
CanonicalType::Array(this) => {
|
|
let CanonicalType::Array(other) = other else {
|
|
return false;
|
|
};
|
|
this.len() == other.len()
|
|
&& this.element().is_layout_equivalent(other.element())
|
|
}
|
|
CanonicalType::Enum(this) => {
|
|
let CanonicalType::Enum(other) = other else {
|
|
return false;
|
|
};
|
|
iter_eq_by(
|
|
this.variants(),
|
|
other.variants(),
|
|
|EnumVariant { name, ty }, other_variant| {
|
|
name == other_variant.name
|
|
&& ty.unwrap_or_else(|| ().canonical()).is_layout_equivalent(
|
|
other_variant.ty.unwrap_or_else(|| ().canonical()),
|
|
)
|
|
},
|
|
)
|
|
}
|
|
CanonicalType::Bundle(this) => {
|
|
let CanonicalType::Bundle(other) = other else {
|
|
return false;
|
|
};
|
|
iter_eq_by(
|
|
this.fields().iter().filter(|f| !f.ty.size().is_empty()),
|
|
other.fields().iter().filter(|f| !f.ty.size().is_empty()),
|
|
|&BundleField { name, flipped, ty }, other_field| {
|
|
name == other_field.name
|
|
&& flipped == other_field.flipped
|
|
&& ty.is_layout_equivalent(other_field.ty)
|
|
},
|
|
)
|
|
}
|
|
CanonicalType::Bool(_)
|
|
| CanonicalType::AsyncReset(_)
|
|
| CanonicalType::SyncReset(_)
|
|
| CanonicalType::Reset(_)
|
|
| CanonicalType::Clock(_) => unreachable!("handled by is_bit"),
|
|
CanonicalType::PhantomConst(_) => unreachable!("handled by is_empty"),
|
|
CanonicalType::TraceAsString(_) => {
|
|
unreachable!("handled by unwrap_transparent_types")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MyMemoize.get_owned((self, other))
|
|
}
|
|
}
|
|
|
|
pub trait MatchVariantAndInactiveScope: Sized {
|
|
type MatchVariant: 'static + Send + Sync;
|
|
type MatchActiveScope;
|
|
fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope);
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MatchVariantWithoutScope<T: 'static + Send + Sync>(pub T);
|
|
|
|
impl<T: 'static + Send + Sync> MatchVariantAndInactiveScope for MatchVariantWithoutScope<T> {
|
|
type MatchVariant = T;
|
|
type MatchActiveScope = ();
|
|
|
|
fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope) {
|
|
(self.0, ())
|
|
}
|
|
}
|
|
|
|
pub trait FillInDefaultedGenerics {
|
|
type Type;
|
|
fn fill_in_defaulted_generics(self) -> Self::Type;
|
|
}
|
|
|
|
impl<T: Type> FillInDefaultedGenerics for T {
|
|
type Type = T;
|
|
|
|
fn fill_in_defaulted_generics(self) -> Self::Type {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl FillInDefaultedGenerics for usize {
|
|
type Type = usize;
|
|
|
|
fn fill_in_defaulted_generics(self) -> Self::Type {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<const V: usize> FillInDefaultedGenerics for ConstUsize<V> {
|
|
type Type = ConstUsize<V>;
|
|
|
|
fn fill_in_defaulted_generics(self) -> Self::Type {
|
|
self
|
|
}
|
|
}
|
|
|
|
mod sealed {
|
|
pub trait TypeOrDefaultSealed {}
|
|
pub trait BaseTypeSealed {}
|
|
}
|
|
|
|
macro_rules! impl_base_type {
|
|
($name:ident) => {
|
|
impl BaseType for $name {}
|
|
impl sealed::BaseTypeSealed for $name {}
|
|
impl From<$name> for CanonicalType {
|
|
fn from(ty: $name) -> Self {
|
|
Self::$name(ty)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
macro_rules! impl_base_type_serde {
|
|
($name:ident, $expected:literal) => {
|
|
impl Serialize for $name {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
self.canonical().serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for $name {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
match CanonicalType::deserialize(deserializer)? {
|
|
CanonicalType::$name(retval) => Ok(retval),
|
|
ty => Err(serde::de::Error::invalid_value(
|
|
serde::de::Unexpected::Other(ty.as_serde_unexpected_str()),
|
|
&$expected,
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_base_type!(UInt);
|
|
impl_base_type!(SInt);
|
|
impl_base_type!(Bool);
|
|
impl_base_type!(Array);
|
|
impl_base_type!(Enum);
|
|
impl_base_type!(Bundle);
|
|
impl_base_type!(AsyncReset);
|
|
impl_base_type!(SyncReset);
|
|
impl_base_type!(Reset);
|
|
impl_base_type!(Clock);
|
|
impl_base_type!(PhantomConst);
|
|
impl_base_type!(DynSimOnly);
|
|
impl_base_type!(TraceAsString);
|
|
|
|
impl_base_type_serde!(Bool, "a Bool");
|
|
impl_base_type_serde!(Enum, "an Enum");
|
|
impl_base_type_serde!(Bundle, "a Bundle");
|
|
impl_base_type_serde!(AsyncReset, "an AsyncReset");
|
|
impl_base_type_serde!(SyncReset, "a SyncReset");
|
|
impl_base_type_serde!(Reset, "a Reset");
|
|
impl_base_type_serde!(Clock, "a Clock");
|
|
impl_base_type_serde!(TraceAsString, "a TraceAsString");
|
|
|
|
impl sealed::BaseTypeSealed for CanonicalType {}
|
|
|
|
impl BaseType for CanonicalType {}
|
|
|
|
pub trait TypeOrDefault<D: Type>:
|
|
sealed::TypeOrDefaultSealed + Copy + Eq + Hash + fmt::Debug
|
|
{
|
|
type Type: Type;
|
|
fn get<F: FnOnce() -> D>(self, default: F) -> Self::Type;
|
|
}
|
|
|
|
impl<T: Type> sealed::TypeOrDefaultSealed for T {}
|
|
|
|
impl<T: Type, D: Type> TypeOrDefault<D> for T {
|
|
type Type = T;
|
|
fn get<F: FnOnce() -> D>(self, _default: F) -> Self::Type {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl sealed::TypeOrDefaultSealed for crate::__ {}
|
|
|
|
impl<D: Type> TypeOrDefault<D> for crate::__ {
|
|
type Type = D;
|
|
fn get<F: FnOnce() -> D>(self, default: F) -> Self::Type {
|
|
default()
|
|
}
|
|
}
|
|
|
|
pub trait Type:
|
|
Copy
|
|
+ Hash
|
|
+ Eq
|
|
+ fmt::Debug
|
|
+ Send
|
|
+ Sync
|
|
+ 'static
|
|
+ FillInDefaultedGenerics<Type = Self>
|
|
+ SimValueDebug
|
|
{
|
|
type BaseType: BaseType;
|
|
type MaskType: Type<MaskType = Self::MaskType>;
|
|
type SimValue: fmt::Debug + Clone + 'static + ToSimValueWithType<Self>;
|
|
type MatchVariant: 'static + Send + Sync;
|
|
type MatchActiveScope;
|
|
type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope<
|
|
MatchVariant = Self::MatchVariant,
|
|
MatchActiveScope = Self::MatchActiveScope,
|
|
>;
|
|
type MatchVariantsIter: Iterator<Item = Self::MatchVariantAndInactiveScope>
|
|
+ ExactSizeIterator
|
|
+ FusedIterator
|
|
+ DoubleEndedIterator;
|
|
#[track_caller]
|
|
fn match_variants(this: Expr<Self>, source_location: SourceLocation)
|
|
-> Self::MatchVariantsIter;
|
|
fn mask_type(&self) -> Self::MaskType;
|
|
fn canonical(&self) -> CanonicalType;
|
|
fn from_canonical(canonical_type: CanonicalType) -> Self;
|
|
fn source_location() -> SourceLocation;
|
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue;
|
|
fn sim_value_clone_from_opaque(
|
|
&self,
|
|
value: &mut Self::SimValue,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
);
|
|
fn sim_value_to_opaque<'w>(
|
|
&self,
|
|
value: &Self::SimValue,
|
|
writer: OpaqueSimValueWriter<'w>,
|
|
) -> OpaqueSimValueWritten<'w>;
|
|
}
|
|
|
|
pub trait SimValueDebug {
|
|
fn sim_value_debug(value: &<Self as Type>::SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
where
|
|
Self: Type;
|
|
}
|
|
|
|
pub trait SimValueDisplay: Type {
|
|
fn sim_value_display(value: &Self::SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result;
|
|
}
|
|
|
|
pub trait BaseType:
|
|
Type<
|
|
BaseType = Self,
|
|
MaskType: Serialize + DeserializeOwned,
|
|
SimValue: Serialize + DeserializeOwned,
|
|
> + sealed::BaseTypeSealed
|
|
+ Into<CanonicalType>
|
|
+ Serialize
|
|
+ DeserializeOwned
|
|
{
|
|
}
|
|
|
|
macro_rules! impl_match_variant_as_self {
|
|
() => {
|
|
type MatchVariant = crate::expr::Expr<Self>;
|
|
type MatchActiveScope = ();
|
|
type MatchVariantAndInactiveScope = crate::ty::MatchVariantWithoutScope<Self::MatchVariant>;
|
|
type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
|
|
fn match_variants(
|
|
this: crate::expr::Expr<Self>,
|
|
source_location: crate::source_location::SourceLocation,
|
|
) -> Self::MatchVariantsIter {
|
|
let _ = source_location;
|
|
std::iter::once(crate::ty::MatchVariantWithoutScope(this))
|
|
}
|
|
};
|
|
}
|
|
|
|
pub(crate) use impl_match_variant_as_self;
|
|
|
|
pub trait TypeWithDeref: Type {
|
|
fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant;
|
|
}
|
|
|
|
impl Type for CanonicalType {
|
|
type BaseType = CanonicalType;
|
|
type MaskType = CanonicalType;
|
|
type SimValue = OpaqueSimValue;
|
|
impl_match_variant_as_self!();
|
|
fn mask_type(&self) -> Self::MaskType {
|
|
match self {
|
|
CanonicalType::UInt(v) => v.mask_type().canonical(),
|
|
CanonicalType::SInt(v) => v.mask_type().canonical(),
|
|
CanonicalType::Bool(v) => v.mask_type().canonical(),
|
|
CanonicalType::Array(v) => v.mask_type().canonical(),
|
|
CanonicalType::Enum(v) => v.mask_type().canonical(),
|
|
CanonicalType::Bundle(v) => v.mask_type().canonical(),
|
|
CanonicalType::AsyncReset(v) => v.mask_type().canonical(),
|
|
CanonicalType::SyncReset(v) => v.mask_type().canonical(),
|
|
CanonicalType::Reset(v) => v.mask_type().canonical(),
|
|
CanonicalType::Clock(v) => v.mask_type().canonical(),
|
|
CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
|
|
CanonicalType::DynSimOnly(v) => v.mask_type().canonical(),
|
|
CanonicalType::TraceAsString(v) => v.mask_type().canonical(),
|
|
}
|
|
}
|
|
fn canonical(&self) -> CanonicalType {
|
|
*self
|
|
}
|
|
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
|
canonical_type
|
|
}
|
|
fn source_location() -> SourceLocation {
|
|
SourceLocation::builtin()
|
|
}
|
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
|
assert_eq!(self.type_properties().size(), opaque.size());
|
|
opaque.to_owned()
|
|
}
|
|
fn sim_value_clone_from_opaque(
|
|
&self,
|
|
value: &mut Self::SimValue,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
) {
|
|
assert_eq!(self.type_properties().size(), opaque.size());
|
|
assert_eq!(value.size(), opaque.size());
|
|
value.clone_from_slice(opaque);
|
|
}
|
|
fn sim_value_to_opaque<'w>(
|
|
&self,
|
|
value: &Self::SimValue,
|
|
writer: OpaqueSimValueWriter<'w>,
|
|
) -> OpaqueSimValueWritten<'w> {
|
|
assert_eq!(self.type_properties().size(), writer.size());
|
|
assert_eq!(value.size(), writer.size());
|
|
writer.fill_cloned_from_slice(value.as_slice())
|
|
}
|
|
}
|
|
|
|
impl SimValueDebug for CanonicalType {
|
|
fn sim_value_debug(
|
|
value: &<Self as Type>::SimValue,
|
|
f: &mut fmt::Formatter<'_>,
|
|
) -> fmt::Result {
|
|
fmt::Debug::fmt(value, f)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)]
|
|
#[non_exhaustive]
|
|
pub struct OpaqueSimValueSizeRange {
|
|
pub bit_width: Range<usize>,
|
|
pub sim_only_values_len: Range<usize>,
|
|
}
|
|
|
|
impl OpaqueSimValueSizeRange {
|
|
pub fn start(&self) -> OpaqueSimValueSize {
|
|
OpaqueSimValueSize {
|
|
bit_width: self.bit_width.start,
|
|
sim_only_values_len: self.sim_only_values_len.start,
|
|
}
|
|
}
|
|
pub fn end(&self) -> OpaqueSimValueSize {
|
|
OpaqueSimValueSize {
|
|
bit_width: self.bit_width.end,
|
|
sim_only_values_len: self.sim_only_values_len.end,
|
|
}
|
|
}
|
|
pub fn is_empty(&self) -> bool {
|
|
let Self {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
} = self;
|
|
bit_width.is_empty() && sim_only_values_len.is_empty()
|
|
}
|
|
}
|
|
|
|
impl From<Range<OpaqueSimValueSize>> for OpaqueSimValueSizeRange {
|
|
fn from(value: Range<OpaqueSimValueSize>) -> Self {
|
|
Self {
|
|
bit_width: value.start.bit_width..value.end.bit_width,
|
|
sim_only_values_len: value.start.sim_only_values_len..value.end.sim_only_values_len,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<OpaqueSimValueSizeRange> for Range<OpaqueSimValueSize> {
|
|
fn from(value: OpaqueSimValueSizeRange) -> Self {
|
|
value.start()..value.end()
|
|
}
|
|
}
|
|
|
|
pub trait OpaqueSimValueSizeRangeBounds {
|
|
fn start_bound(&self) -> Bound<OpaqueSimValueSize>;
|
|
fn end_bound(&self) -> Bound<OpaqueSimValueSize>;
|
|
}
|
|
|
|
impl OpaqueSimValueSizeRangeBounds for OpaqueSimValueSizeRange {
|
|
fn start_bound(&self) -> Bound<OpaqueSimValueSize> {
|
|
Bound::Included(self.start())
|
|
}
|
|
|
|
fn end_bound(&self) -> Bound<OpaqueSimValueSize> {
|
|
Bound::Excluded(self.end())
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + std::ops::RangeBounds<OpaqueSimValueSize>> OpaqueSimValueSizeRangeBounds for T {
|
|
fn start_bound(&self) -> Bound<OpaqueSimValueSize> {
|
|
std::ops::RangeBounds::start_bound(self).cloned()
|
|
}
|
|
fn end_bound(&self) -> Bound<OpaqueSimValueSize> {
|
|
std::ops::RangeBounds::end_bound(self).cloned()
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)]
|
|
#[non_exhaustive]
|
|
pub struct OpaqueSimValueSize {
|
|
pub bit_width: usize,
|
|
pub sim_only_values_len: usize,
|
|
}
|
|
|
|
impl OpaqueSimValueSize {
|
|
pub const fn from_bit_width(bit_width: usize) -> Self {
|
|
Self::from_bit_width_and_sim_only_values_len(bit_width, 0)
|
|
}
|
|
pub const fn from_bit_width_and_sim_only_values_len(
|
|
bit_width: usize,
|
|
sim_only_values_len: usize,
|
|
) -> Self {
|
|
Self {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
}
|
|
}
|
|
pub const fn only_bit_width(self) -> Option<usize> {
|
|
if let Self {
|
|
bit_width,
|
|
sim_only_values_len: 0,
|
|
} = self
|
|
{
|
|
Some(bit_width)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
pub const fn empty() -> Self {
|
|
Self {
|
|
bit_width: 0,
|
|
sim_only_values_len: 0,
|
|
}
|
|
}
|
|
pub const fn is_empty(self) -> bool {
|
|
let Self {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
} = self;
|
|
bit_width == 0 && sim_only_values_len == 0
|
|
}
|
|
pub const fn checked_mul(self, factor: usize) -> Option<Self> {
|
|
let Some(bit_width) = self.bit_width.checked_mul(factor) else {
|
|
return None;
|
|
};
|
|
let Some(sim_only_values_len) = self.sim_only_values_len.checked_mul(factor) else {
|
|
return None;
|
|
};
|
|
Some(Self {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
})
|
|
}
|
|
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
|
|
let Some(bit_width) = self.bit_width.checked_add(rhs.bit_width) else {
|
|
return None;
|
|
};
|
|
let Some(sim_only_values_len) = self
|
|
.sim_only_values_len
|
|
.checked_add(rhs.sim_only_values_len)
|
|
else {
|
|
return None;
|
|
};
|
|
Some(Self {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
})
|
|
}
|
|
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
|
|
let Some(bit_width) = self.bit_width.checked_sub(rhs.bit_width) else {
|
|
return None;
|
|
};
|
|
let Some(sim_only_values_len) = self
|
|
.sim_only_values_len
|
|
.checked_sub(rhs.sim_only_values_len)
|
|
else {
|
|
return None;
|
|
};
|
|
Some(Self {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
})
|
|
}
|
|
pub fn try_slice_range<R: OpaqueSimValueSizeRangeBounds>(
|
|
self,
|
|
range: R,
|
|
) -> Option<OpaqueSimValueSizeRange> {
|
|
let start = range.start_bound();
|
|
let end = range.end_bound();
|
|
let bit_width = try_slice_range(
|
|
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
|
|
self.bit_width,
|
|
)?;
|
|
let sim_only_values_len = try_slice_range(
|
|
(
|
|
start.map(|v| v.sim_only_values_len),
|
|
end.map(|v| v.sim_only_values_len),
|
|
),
|
|
self.sim_only_values_len,
|
|
)?;
|
|
Some(OpaqueSimValueSizeRange {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
})
|
|
}
|
|
pub fn slice_range<R: OpaqueSimValueSizeRangeBounds>(
|
|
self,
|
|
range: R,
|
|
) -> OpaqueSimValueSizeRange {
|
|
self.try_slice_range(range).expect("range out of bounds")
|
|
}
|
|
}
|
|
|
|
impl Mul<usize> for OpaqueSimValueSize {
|
|
type Output = OpaqueSimValueSize;
|
|
|
|
fn mul(self, rhs: usize) -> Self::Output {
|
|
self.checked_mul(rhs).expect("multiplication overflowed")
|
|
}
|
|
}
|
|
|
|
impl Mul<OpaqueSimValueSize> for usize {
|
|
type Output = OpaqueSimValueSize;
|
|
|
|
fn mul(self, rhs: OpaqueSimValueSize) -> Self::Output {
|
|
rhs.checked_mul(self).expect("multiplication overflowed")
|
|
}
|
|
}
|
|
|
|
impl Add for OpaqueSimValueSize {
|
|
type Output = OpaqueSimValueSize;
|
|
|
|
fn add(self, rhs: OpaqueSimValueSize) -> Self::Output {
|
|
rhs.checked_add(self).expect("addition overflowed")
|
|
}
|
|
}
|
|
|
|
impl Sub for OpaqueSimValueSize {
|
|
type Output = OpaqueSimValueSize;
|
|
|
|
fn sub(self, rhs: OpaqueSimValueSize) -> Self::Output {
|
|
rhs.checked_sub(self).expect("subtraction underflowed")
|
|
}
|
|
}
|
|
|
|
impl MulAssign<usize> for OpaqueSimValueSize {
|
|
fn mul_assign(&mut self, rhs: usize) {
|
|
*self = *self * rhs;
|
|
}
|
|
}
|
|
|
|
impl AddAssign for OpaqueSimValueSize {
|
|
fn add_assign(&mut self, rhs: OpaqueSimValueSize) {
|
|
*self = *self + rhs;
|
|
}
|
|
}
|
|
|
|
impl SubAssign for OpaqueSimValueSize {
|
|
fn sub_assign(&mut self, rhs: OpaqueSimValueSize) {
|
|
*self = *self - rhs;
|
|
}
|
|
}
|
|
|
|
impl Sum for OpaqueSimValueSize {
|
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
|
iter.fold(OpaqueSimValueSize::empty(), Add::add)
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
|
pub struct OpaqueSimValue {
|
|
bits: UIntValue,
|
|
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
|
sim_only_values: Vec<DynSimOnlyValue>,
|
|
}
|
|
|
|
impl Clone for OpaqueSimValue {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
bits: self.bits.clone(),
|
|
sim_only_values: self.sim_only_values.clone(),
|
|
}
|
|
}
|
|
fn clone_from(&mut self, source: &Self) {
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
} = self;
|
|
if let Some(bits) = Arc::get_mut(bits.arc_bitvec_mut()) {
|
|
bits.clone_from(source.bits.bits());
|
|
} else {
|
|
*bits = source.bits.clone();
|
|
}
|
|
sim_only_values.clone_from(&source.sim_only_values);
|
|
}
|
|
}
|
|
|
|
impl OpaqueSimValue {
|
|
pub fn empty() -> Self {
|
|
Self {
|
|
bits: UIntValue::new(Default::default()),
|
|
sim_only_values: Vec::new(),
|
|
}
|
|
}
|
|
pub fn with_capacity(capacity: OpaqueSimValueSize) -> Self {
|
|
Self {
|
|
bits: UIntValue::new(Arc::new(BitVec::with_capacity(capacity.bit_width))),
|
|
sim_only_values: Vec::with_capacity(capacity.sim_only_values_len),
|
|
}
|
|
}
|
|
pub fn size(&self) -> OpaqueSimValueSize {
|
|
OpaqueSimValueSize {
|
|
bit_width: self.bits.width(),
|
|
sim_only_values_len: self.sim_only_values.len(),
|
|
}
|
|
}
|
|
pub fn is_empty(&self) -> bool {
|
|
self.size().is_empty()
|
|
}
|
|
pub fn bit_width(&self) -> usize {
|
|
self.bits.width()
|
|
}
|
|
pub fn bits(&self) -> &UIntValue {
|
|
&self.bits
|
|
}
|
|
pub fn bits_mut(&mut self) -> &mut UIntValue {
|
|
&mut self.bits
|
|
}
|
|
pub fn into_bits(self) -> UIntValue {
|
|
self.bits
|
|
}
|
|
pub fn from_bits(bits: UIntValue) -> Self {
|
|
Self {
|
|
bits,
|
|
sim_only_values: Vec::new(),
|
|
}
|
|
}
|
|
pub fn from_bitslice(v: &BitSlice) -> Self {
|
|
Self::from_bitslice_and_sim_only_values(v, Vec::new())
|
|
}
|
|
pub fn from_bitslice_and_sim_only_values(
|
|
bits: &BitSlice,
|
|
sim_only_values: Vec<DynSimOnlyValue>,
|
|
) -> Self {
|
|
Self {
|
|
bits: UIntValue::new(Arc::new(bits.to_bitvec())),
|
|
sim_only_values,
|
|
}
|
|
}
|
|
pub fn from_bits_and_sim_only_values(
|
|
bits: UIntValue,
|
|
sim_only_values: Vec<DynSimOnlyValue>,
|
|
) -> Self {
|
|
Self {
|
|
bits,
|
|
sim_only_values,
|
|
}
|
|
}
|
|
pub fn into_parts(self) -> (UIntValue, Vec<DynSimOnlyValue>) {
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
} = self;
|
|
(bits, sim_only_values)
|
|
}
|
|
pub fn parts_mut(&mut self) -> (&mut UIntValue, &mut Vec<DynSimOnlyValue>) {
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
} = self;
|
|
(bits, sim_only_values)
|
|
}
|
|
pub fn sim_only_values(&self) -> &[DynSimOnlyValue] {
|
|
&self.sim_only_values
|
|
}
|
|
pub fn sim_only_values_mut(&mut self) -> &mut Vec<DynSimOnlyValue> {
|
|
&mut self.sim_only_values
|
|
}
|
|
pub fn as_slice(&self) -> OpaqueSimValueSlice<'_> {
|
|
OpaqueSimValueSlice {
|
|
bits: self.bits.bits(),
|
|
sim_only_values: &self.sim_only_values,
|
|
}
|
|
}
|
|
pub fn slice<R: OpaqueSimValueSizeRangeBounds>(&self, range: R) -> OpaqueSimValueSlice<'_> {
|
|
self.as_slice().slice(range)
|
|
}
|
|
pub fn rewrite_with<F>(&mut self, target_size: OpaqueSimValueSize, f: F)
|
|
where
|
|
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
|
|
{
|
|
OpaqueSimValueWriter::rewrite_with(target_size, self, f);
|
|
}
|
|
pub fn clone_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
|
|
let OpaqueSimValueSlice {
|
|
bits,
|
|
sim_only_values,
|
|
} = slice;
|
|
self.bits.bits_mut().copy_from_bitslice(bits);
|
|
self.sim_only_values.clone_from_slice(sim_only_values);
|
|
}
|
|
pub fn extend_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
|
|
let OpaqueSimValueSlice {
|
|
bits,
|
|
sim_only_values,
|
|
} = slice;
|
|
self.bits.bitvec_mut().extend_from_bitslice(bits);
|
|
self.sim_only_values.extend_from_slice(sim_only_values);
|
|
}
|
|
}
|
|
|
|
impl<'a> Extend<OpaqueSimValueSlice<'a>> for OpaqueSimValue {
|
|
fn extend<T: IntoIterator<Item = OpaqueSimValueSlice<'a>>>(&mut self, iter: T) {
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
} = self;
|
|
let bits = bits.bitvec_mut();
|
|
for slice in iter {
|
|
bits.extend_from_bitslice(slice.bits);
|
|
sim_only_values.extend_from_slice(slice.sim_only_values);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Extend<OpaqueSimValue> for OpaqueSimValue {
|
|
fn extend<T: IntoIterator<Item = OpaqueSimValue>>(&mut self, iter: T) {
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
} = self;
|
|
let bits = bits.bitvec_mut();
|
|
for value in iter {
|
|
bits.extend_from_bitslice(value.bits().bits());
|
|
sim_only_values.extend_from_slice(value.sim_only_values());
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValue {
|
|
fn to_sim_value_with_type(&self, ty: T) -> SimValue<T> {
|
|
SimValue::from_value(ty, self.clone())
|
|
}
|
|
fn into_sim_value_with_type(self, ty: T) -> SimValue<T> {
|
|
SimValue::from_value(ty, self)
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct OpaqueSimValueSlice<'a> {
|
|
bits: &'a BitSlice,
|
|
sim_only_values: &'a [DynSimOnlyValue],
|
|
}
|
|
|
|
impl<'a> Default for OpaqueSimValueSlice<'a> {
|
|
fn default() -> Self {
|
|
Self::empty()
|
|
}
|
|
}
|
|
|
|
impl<'a> OpaqueSimValueSlice<'a> {
|
|
pub fn from_parts(bits: &'a BitSlice, sim_only_values: &'a [DynSimOnlyValue]) -> Self {
|
|
Self {
|
|
bits,
|
|
sim_only_values,
|
|
}
|
|
}
|
|
pub fn from_bitslice(bits: &'a BitSlice) -> Self {
|
|
Self::from_parts(bits, &[])
|
|
}
|
|
pub fn empty() -> Self {
|
|
Self {
|
|
bits: BitSlice::empty(),
|
|
sim_only_values: &[],
|
|
}
|
|
}
|
|
pub fn size(self) -> OpaqueSimValueSize {
|
|
OpaqueSimValueSize {
|
|
bit_width: self.bit_width(),
|
|
sim_only_values_len: self.sim_only_values_len(),
|
|
}
|
|
}
|
|
pub fn is_empty(self) -> bool {
|
|
self.size().is_empty()
|
|
}
|
|
pub fn bit_width(self) -> usize {
|
|
self.bits.len()
|
|
}
|
|
pub fn bits(self) -> &'a BitSlice {
|
|
self.bits
|
|
}
|
|
pub fn sim_only_values(self) -> &'a [DynSimOnlyValue] {
|
|
self.sim_only_values
|
|
}
|
|
pub fn sim_only_values_len(self) -> usize {
|
|
self.sim_only_values.len()
|
|
}
|
|
pub fn to_owned(self) -> OpaqueSimValue {
|
|
OpaqueSimValue::from_bitslice_and_sim_only_values(self.bits, self.sim_only_values.to_vec())
|
|
}
|
|
pub fn slice<R: OpaqueSimValueSizeRangeBounds>(self, range: R) -> OpaqueSimValueSlice<'a> {
|
|
let start = range.start_bound();
|
|
let end = range.end_bound();
|
|
let bits_range = slice_range(
|
|
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
|
|
self.bit_width(),
|
|
);
|
|
let sim_only_values_range = slice_range(
|
|
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
|
|
self.sim_only_values_len(),
|
|
);
|
|
Self {
|
|
bits: &self.bits[bits_range],
|
|
sim_only_values: &self.sim_only_values[sim_only_values_range],
|
|
}
|
|
}
|
|
pub fn split_at(self, index: OpaqueSimValueSize) -> (Self, Self) {
|
|
let bits = self.bits.split_at(index.bit_width);
|
|
let sim_only_values = self.sim_only_values.split_at(index.sim_only_values_len);
|
|
(
|
|
Self {
|
|
bits: bits.0,
|
|
sim_only_values: sim_only_values.0,
|
|
},
|
|
Self {
|
|
bits: bits.1,
|
|
sim_only_values: sim_only_values.1,
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct OpaqueSimValueWriter<'a> {
|
|
bits: &'a mut BitSlice,
|
|
sim_only_values: &'a mut Vec<DynSimOnlyValue>,
|
|
sim_only_values_range: std::ops::Range<usize>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct OpaqueSimValueWritten<'a> {
|
|
_phantom: PhantomData<&'a ()>,
|
|
}
|
|
|
|
impl<'a> OpaqueSimValueWriter<'a> {
|
|
pub fn sim_only_values_range(&self) -> std::ops::Range<usize> {
|
|
self.sim_only_values_range.clone()
|
|
}
|
|
pub fn rewrite_with<F>(target_size: OpaqueSimValueSize, value: &mut OpaqueSimValue, f: F)
|
|
where
|
|
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
|
|
{
|
|
let OpaqueSimValueWritten {
|
|
_phantom: PhantomData,
|
|
} = f(OpaqueSimValueWriter::rewrite_helper(target_size, value));
|
|
}
|
|
pub(crate) fn rewrite_helper(
|
|
target_size: OpaqueSimValueSize,
|
|
value: &'a mut OpaqueSimValue,
|
|
) -> Self {
|
|
let (bits, sim_only_values) = value.parts_mut();
|
|
let OpaqueSimValueSize {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
} = target_size;
|
|
let bits = bits.bitvec_mut();
|
|
bits.resize(bit_width, false);
|
|
sim_only_values.truncate(sim_only_values_len);
|
|
sim_only_values.reserve_exact(sim_only_values_len - sim_only_values.len());
|
|
Self {
|
|
bits,
|
|
sim_only_values,
|
|
sim_only_values_range: 0..sim_only_values_len,
|
|
}
|
|
}
|
|
pub fn size(&self) -> OpaqueSimValueSize {
|
|
OpaqueSimValueSize {
|
|
bit_width: self.bit_width(),
|
|
sim_only_values_len: self.sim_only_values_len(),
|
|
}
|
|
}
|
|
pub fn bit_width(&self) -> usize {
|
|
self.bits.len()
|
|
}
|
|
pub fn sim_only_values_len(&self) -> usize {
|
|
self.sim_only_values_range.len()
|
|
}
|
|
pub fn is_empty(&self) -> bool {
|
|
self.size().is_empty()
|
|
}
|
|
pub fn fill_cloned_from_slice(
|
|
self,
|
|
slice: OpaqueSimValueSlice<'_>,
|
|
) -> OpaqueSimValueWritten<'a> {
|
|
assert_eq!(self.size(), slice.size());
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
sim_only_values_range,
|
|
} = self;
|
|
bits.copy_from_bitslice(slice.bits);
|
|
let (clone_from_src, clone_src) = slice.sim_only_values.split_at(
|
|
(sim_only_values.len() - sim_only_values_range.start).min(slice.sim_only_values.len()),
|
|
);
|
|
sim_only_values[sim_only_values_range.start..][..clone_from_src.len()]
|
|
.clone_from_slice(clone_from_src);
|
|
sim_only_values.extend_from_slice(clone_src);
|
|
OpaqueSimValueWritten {
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
pub fn fill_with_bits_with<F: FnOnce(&mut BitSlice)>(self, f: F) -> OpaqueSimValueWritten<'a> {
|
|
assert!(self.size().only_bit_width().is_some());
|
|
let Self {
|
|
bits,
|
|
sim_only_values,
|
|
sim_only_values_range,
|
|
} = self;
|
|
f(bits);
|
|
assert_eq!(sim_only_values.len(), sim_only_values_range.end);
|
|
OpaqueSimValueWritten {
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
pub fn fill_with_zeros(self) -> OpaqueSimValueWritten<'a> {
|
|
assert!(
|
|
self.size().only_bit_width().is_some(),
|
|
"can't fill things other than bits with zeros",
|
|
);
|
|
self.fill_with_bits_with(|bits| bits.fill(false))
|
|
}
|
|
pub fn fill_prefix_with<F>(&mut self, prefix_size: OpaqueSimValueSize, f: F)
|
|
where
|
|
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
|
|
{
|
|
let OpaqueSimValueSize {
|
|
bit_width,
|
|
sim_only_values_len,
|
|
} = prefix_size;
|
|
assert!(bit_width <= self.bit_width());
|
|
assert!(sim_only_values_len <= self.sim_only_values_len());
|
|
let next_start = self.sim_only_values_range.start + sim_only_values_len;
|
|
let OpaqueSimValueWritten {
|
|
_phantom: PhantomData,
|
|
} = f(OpaqueSimValueWriter {
|
|
bits: &mut self.bits[..bit_width],
|
|
sim_only_values: self.sim_only_values,
|
|
sim_only_values_range: self.sim_only_values_range.start..next_start,
|
|
});
|
|
assert!(self.sim_only_values.len() >= next_start);
|
|
self.bits = &mut mem::take(&mut self.bits)[bit_width..];
|
|
self.sim_only_values_range.start = next_start;
|
|
}
|
|
}
|
|
|
|
pub trait StaticType: Type + Default {
|
|
const TYPE: Self;
|
|
const MASK_TYPE: Self::MaskType;
|
|
const TYPE_PROPERTIES: TypeProperties;
|
|
const MASK_TYPE_PROPERTIES: TypeProperties;
|
|
}
|
|
|
|
pub type AsMask<T> = <T as Type>::MaskType;
|
|
|
|
pub struct AsMaskWithoutGenerics;
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
pub const AsMask: AsMaskWithoutGenerics = AsMaskWithoutGenerics;
|
|
|
|
impl<T: Type> Index<T> for AsMaskWithoutGenerics {
|
|
type Output = T::MaskType;
|
|
|
|
fn index(&self, ty: T) -> &Self::Output {
|
|
Interned::into_inner(Intern::intern_sized(ty.mask_type()))
|
|
}
|
|
}
|
|
|
|
trait TraceAsStringTrait: fmt::Debug + 'static + Send + Sync + SupportsPtrEqWithTypeId {
|
|
fn trace_fmt(&self, opaque: OpaqueSimValueSlice<'_>, f: &mut fmt::Formatter<'_>)
|
|
-> fmt::Result;
|
|
fn serde_by_id_properties(&self) -> SerdeByIdProperties<Interned<dyn TraceAsStringTrait>> {
|
|
SerdeByIdProperties::of::<Self>()
|
|
}
|
|
fn can_substitute_type(&self, new_type: CanonicalType) -> bool;
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
|
struct TraceAsStringState<T: Type> {
|
|
ty: Interned<T>,
|
|
canonical_ty: CanonicalType,
|
|
}
|
|
|
|
impl<T: Type> TraceAsStringState<T> {
|
|
fn new(ty: Interned<T>) -> Interned<Self> {
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
struct MyMemoize<T: Type>(PhantomData<T>);
|
|
impl<T: Type> Memoize for MyMemoize<T> {
|
|
type Input = Interned<T>;
|
|
type InputOwned = Interned<T>;
|
|
type Output = Interned<TraceAsStringState<T>>;
|
|
|
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
|
TraceAsStringState {
|
|
ty: *input,
|
|
canonical_ty: input.canonical(),
|
|
}
|
|
.intern_sized()
|
|
}
|
|
}
|
|
MyMemoize(PhantomData).get_owned(ty)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> fmt::Debug for TraceAsStringState<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.ty.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> TraceAsStringTrait for TraceAsStringState<T> {
|
|
fn trace_fmt(
|
|
&self,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
f: &mut fmt::Formatter<'_>,
|
|
) -> fmt::Result {
|
|
fmt::Debug::fmt(&Type::sim_value_from_opaque(&*self.ty, opaque), f)
|
|
}
|
|
fn can_substitute_type(&self, new_type: CanonicalType) -> bool {
|
|
self.canonical_ty.is_layout_equivalent(new_type)
|
|
}
|
|
}
|
|
|
|
impl crate::intern::InternedCompare for dyn TraceAsStringTrait {
|
|
type InternedCompareKey = crate::intern::PtrEqWithTypeId;
|
|
|
|
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
|
|
this.get_ptr_eq_with_type_id()
|
|
}
|
|
}
|
|
|
|
impl SerdeByIdTrait for Interned<dyn TraceAsStringTrait> {
|
|
fn serde_by_id_properties(&self) -> SerdeByIdProperties<Self> {
|
|
TraceAsStringTrait::serde_by_id_properties(&**self)
|
|
}
|
|
|
|
fn static_table() -> &'static SerdeByIdTable<Self> {
|
|
static TABLE: SerdeByIdTable<Interned<dyn TraceAsStringTrait>> = SerdeByIdTable::new();
|
|
&TABLE
|
|
}
|
|
|
|
const NAME: &'static str = "dyn TraceAsStringTrait";
|
|
}
|
|
|
|
/// When running the fayalite simulator, outputs a single string signal containing a formatted version of the inner value (uses [`fmt::Debug`] by default).
|
|
/// This is a transparent type, meaning [`CanonicalType::unwrap_transparent_types`] will unwrap this type.
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
pub struct TraceAsString<T: Type = CanonicalType> {
|
|
inner_ty: LazyInterned<T>,
|
|
trace_as_string: LazyInterned<dyn TraceAsStringTrait>,
|
|
}
|
|
|
|
#[expect(non_upper_case_globals)]
|
|
pub const TraceAsString: TraceAsStringWithoutGenerics = TraceAsStringWithoutGenerics;
|
|
|
|
impl<T: Type> fmt::Debug for TraceAsString<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let Self {
|
|
inner_ty,
|
|
trace_as_string: _,
|
|
} = self;
|
|
f.debug_struct("TraceAsString")
|
|
.field("inner_ty", &inner_ty.interned())
|
|
.finish_non_exhaustive()
|
|
}
|
|
}
|
|
|
|
impl<T: Type> TraceAsString<T> {
|
|
pub fn new(inner_ty: T) -> Self {
|
|
Self::new_interned(inner_ty.intern_sized())
|
|
}
|
|
pub fn new_interned(inner_ty: Interned<T>) -> Self {
|
|
Self {
|
|
inner_ty: LazyInterned::Interned(inner_ty),
|
|
trace_as_string: LazyInterned::Interned(Interned::cast_unchecked(
|
|
TraceAsStringState::new(inner_ty),
|
|
|v| -> &dyn TraceAsStringTrait { v },
|
|
)),
|
|
}
|
|
}
|
|
pub fn interned_inner_ty(self) -> Interned<T> {
|
|
self.inner_ty.interned()
|
|
}
|
|
pub fn inner_ty(self) -> T {
|
|
*self.interned_inner_ty()
|
|
}
|
|
/// create a new `TraceAsString` but try to keep the old formatting method
|
|
pub fn with_new_inner_ty<U: Type>(self, inner_ty: Interned<U>) -> TraceAsString<U> {
|
|
if self
|
|
.trace_as_string
|
|
.can_substitute_type(inner_ty.canonical())
|
|
{
|
|
TraceAsString {
|
|
inner_ty: LazyInterned::Interned(inner_ty),
|
|
trace_as_string: self.trace_as_string,
|
|
}
|
|
} else {
|
|
TraceAsString::new_interned(inner_ty)
|
|
}
|
|
}
|
|
pub fn canonical_trace_as_string(self) -> TraceAsString<CanonicalType> {
|
|
let Self {
|
|
inner_ty,
|
|
trace_as_string,
|
|
} = self;
|
|
TraceAsString {
|
|
inner_ty: LazyInterned::Interned(inner_ty.interned().canonical().intern_sized()),
|
|
trace_as_string,
|
|
}
|
|
}
|
|
pub fn from_canonical_trace_as_string(canonical: TraceAsString<CanonicalType>) -> Self {
|
|
let TraceAsString {
|
|
inner_ty,
|
|
trace_as_string,
|
|
} = canonical;
|
|
Self {
|
|
inner_ty: LazyInterned::Interned(
|
|
T::from_canonical(*inner_ty.interned()).intern_sized(),
|
|
),
|
|
trace_as_string,
|
|
}
|
|
}
|
|
pub fn type_properties(self) -> TypeProperties {
|
|
self.interned_inner_ty().canonical().type_properties()
|
|
}
|
|
pub fn can_connect<T2: Type>(self, rhs: TraceAsString<T2>) -> bool {
|
|
self.interned_inner_ty()
|
|
.canonical()
|
|
.can_connect(rhs.interned_inner_ty().canonical())
|
|
}
|
|
pub fn trace_fmt(
|
|
self,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
f: &mut fmt::Formatter<'_>,
|
|
) -> fmt::Result {
|
|
self.trace_as_string.interned().trace_fmt(opaque, f)
|
|
}
|
|
pub fn trace_fmt_append_to_string(self, output: &mut String, opaque: OpaqueSimValueSlice<'_>) {
|
|
fn impl_fn(
|
|
trace_as_string: Interned<dyn TraceAsStringTrait>,
|
|
output: &mut String,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
) {
|
|
let initial_len = output.len();
|
|
if let Err(fmt::Error {}) = write!(
|
|
output,
|
|
"{}",
|
|
fmt::from_fn(|f| trace_as_string.trace_fmt(opaque, f))
|
|
) {
|
|
output.truncate(initial_len);
|
|
output.push_str("<!!!failed to format!!!>");
|
|
}
|
|
}
|
|
impl_fn(self.trace_as_string.interned(), output, opaque)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> SimValueDebug for TraceAsString<T> {
|
|
fn sim_value_debug(
|
|
value: &<Self as Type>::SimValue,
|
|
f: &mut fmt::Formatter<'_>,
|
|
) -> fmt::Result {
|
|
T::sim_value_debug(value.inner(), f)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> Type for TraceAsString<T> {
|
|
type BaseType = TraceAsString<CanonicalType>;
|
|
type MaskType = T::MaskType;
|
|
type SimValue = TraceAsStringSimValue<T>;
|
|
type MatchVariant = Expr<T>;
|
|
type MatchActiveScope = ();
|
|
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
|
|
type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
|
|
|
|
fn match_variants(
|
|
this: Expr<Self>,
|
|
source_location: SourceLocation,
|
|
) -> Self::MatchVariantsIter {
|
|
let _ = source_location;
|
|
std::iter::once(MatchVariantWithoutScope(
|
|
ops::TraceAsStringAsInner::new(this).to_expr(),
|
|
))
|
|
}
|
|
|
|
fn mask_type(&self) -> Self::MaskType {
|
|
self.inner_ty.mask_type()
|
|
}
|
|
|
|
fn canonical(&self) -> CanonicalType {
|
|
CanonicalType::TraceAsString(self.canonical_trace_as_string())
|
|
}
|
|
|
|
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
|
let CanonicalType::TraceAsString(canonical) = canonical_type else {
|
|
panic!("expected TraceAsString");
|
|
};
|
|
Self::from_canonical_trace_as_string(canonical)
|
|
}
|
|
|
|
fn source_location() -> SourceLocation {
|
|
SourceLocation::builtin()
|
|
}
|
|
|
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
|
TraceAsStringSimValue {
|
|
inner: SimValue::from_opaque(self.inner_ty(), opaque.to_owned()),
|
|
trace_as_string: self.trace_as_string.interned(),
|
|
}
|
|
}
|
|
|
|
fn sim_value_clone_from_opaque(
|
|
&self,
|
|
value: &mut Self::SimValue,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
) {
|
|
self.inner_ty
|
|
.sim_value_clone_from_opaque(&mut value.inner, opaque);
|
|
}
|
|
|
|
fn sim_value_to_opaque<'w>(
|
|
&self,
|
|
value: &Self::SimValue,
|
|
writer: OpaqueSimValueWriter<'w>,
|
|
) -> OpaqueSimValueWritten<'w> {
|
|
self.inner_ty.sim_value_to_opaque(&value.inner, writer)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> TypeWithDeref for TraceAsString<T> {
|
|
fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant {
|
|
Interned::into_inner(
|
|
ops::TraceAsStringAsInner::new(*this)
|
|
.to_expr()
|
|
.intern_sized(),
|
|
)
|
|
}
|
|
}
|
|
|
|
struct TraceAsStringStaticTypeHelper<T: StaticType>(PhantomData<T>);
|
|
|
|
impl<T: StaticType> Default for TraceAsStringStaticTypeHelper<T> {
|
|
fn default() -> Self {
|
|
Self(PhantomData)
|
|
}
|
|
}
|
|
|
|
impl<T: StaticType> From<TraceAsStringStaticTypeHelper<T>> for Interned<dyn TraceAsStringTrait> {
|
|
fn from(_value: TraceAsStringStaticTypeHelper<T>) -> Self {
|
|
Interned::cast_unchecked(
|
|
TraceAsStringState::new(T::TYPE.intern_sized()),
|
|
|v| -> &dyn TraceAsStringTrait { v },
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<T: StaticType> Default for TraceAsString<T> {
|
|
fn default() -> Self {
|
|
Self::TYPE
|
|
}
|
|
}
|
|
|
|
struct MakeType<T: StaticType>(Interned<T>);
|
|
|
|
impl<T: StaticType> From<MakeType<T>> for Interned<T> {
|
|
fn from(value: MakeType<T>) -> Self {
|
|
value.0
|
|
}
|
|
}
|
|
|
|
impl<T: StaticType> Default for MakeType<T> {
|
|
fn default() -> Self {
|
|
Self(T::TYPE.intern_sized())
|
|
}
|
|
}
|
|
|
|
impl<T: StaticType> StaticType for TraceAsString<T> {
|
|
const TYPE: Self = Self {
|
|
inner_ty: LazyInterned::new_const::<MakeType<T>>(),
|
|
trace_as_string: LazyInterned::new_const::<TraceAsStringStaticTypeHelper<T>>(),
|
|
};
|
|
const MASK_TYPE: Self::MaskType = T::MASK_TYPE;
|
|
const TYPE_PROPERTIES: TypeProperties = T::TYPE_PROPERTIES;
|
|
const MASK_TYPE_PROPERTIES: TypeProperties = T::MASK_TYPE_PROPERTIES;
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub struct TraceAsStringWithoutGenerics;
|
|
|
|
impl<T: Type> Index<T> for TraceAsStringWithoutGenerics {
|
|
type Output = TraceAsString<T>;
|
|
|
|
fn index(&self, inner_ty: T) -> &Self::Output {
|
|
Interned::into_inner(TraceAsString::new(inner_ty).intern_sized())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct TraceAsStringSimValue<T: Type> {
|
|
inner: SimValue<T>,
|
|
trace_as_string: Interned<dyn TraceAsStringTrait>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[serde(rename = "TraceAsStringSimValue")]
|
|
struct TraceAsStringSimValueSerde<T> {
|
|
inner: T,
|
|
trace_as_string: crate::util::serde_by_id::SerdeById<Interned<dyn TraceAsStringTrait>>,
|
|
}
|
|
|
|
impl<T: Type<SimValue: Serialize> + Serialize> Serialize for TraceAsStringSimValue<T> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let Self {
|
|
inner,
|
|
trace_as_string,
|
|
} = self;
|
|
TraceAsStringSimValueSerde {
|
|
inner,
|
|
trace_as_string: crate::util::serde_by_id::SerdeById {
|
|
inner: *trace_as_string,
|
|
},
|
|
}
|
|
.serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de, T: Type<SimValue: Deserialize<'de>> + Deserialize<'de>> Deserialize<'de>
|
|
for TraceAsStringSimValue<T>
|
|
{
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let TraceAsStringSimValueSerde {
|
|
inner,
|
|
trace_as_string:
|
|
crate::util::serde_by_id::SerdeById {
|
|
inner: trace_as_string,
|
|
},
|
|
} = Deserialize::deserialize(deserializer)?;
|
|
Ok(Self {
|
|
inner,
|
|
trace_as_string,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<T: Type> TraceAsStringSimValue<T> {
|
|
pub fn new_with_ty(inner: impl ToSimValueWithType<T>, ty: TraceAsString<T>) -> Self {
|
|
Self {
|
|
inner: inner.into_sim_value_with_type(ty.inner_ty()),
|
|
trace_as_string: ty.trace_as_string.interned(),
|
|
}
|
|
}
|
|
pub fn new(inner: impl ToSimValue<Type = T>) -> Self {
|
|
let inner = inner.into_sim_value();
|
|
Self {
|
|
trace_as_string: TraceAsString::new(inner.ty()).trace_as_string.interned(),
|
|
inner,
|
|
}
|
|
}
|
|
pub fn into_inner(self) -> SimValue<T> {
|
|
self.inner
|
|
}
|
|
pub fn inner(&self) -> &SimValue<T> {
|
|
&self.inner
|
|
}
|
|
pub fn inner_mut(&mut self) -> &mut SimValue<T> {
|
|
&mut self.inner
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ValueType for TraceAsStringSimValue<T> {
|
|
type Type = TraceAsString<T>;
|
|
type ValueCategory = crate::expr::value_category::ValueCategoryValue;
|
|
|
|
fn ty(&self) -> Self::Type {
|
|
let inner_ty = self.inner.ty().intern_sized();
|
|
if self
|
|
.trace_as_string
|
|
.can_substitute_type(inner_ty.canonical())
|
|
{
|
|
TraceAsString {
|
|
inner_ty: LazyInterned::Interned(inner_ty),
|
|
trace_as_string: LazyInterned::Interned(self.trace_as_string),
|
|
}
|
|
} else {
|
|
TraceAsString::new_interned(inner_ty)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToExpr for TraceAsStringSimValue<T> {
|
|
#[track_caller]
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
let inner = self.inner.to_expr();
|
|
let inner_canonical = Expr::canonical(inner);
|
|
let inner_ty = inner.ty().intern_sized();
|
|
let ty = if self
|
|
.trace_as_string
|
|
.can_substitute_type(inner_canonical.ty())
|
|
{
|
|
TraceAsString {
|
|
inner_ty: LazyInterned::Interned(inner_ty),
|
|
trace_as_string: LazyInterned::Interned(self.trace_as_string),
|
|
}
|
|
} else {
|
|
TraceAsString::new_interned(inner_ty)
|
|
};
|
|
ops::ToTraceAsString::new(inner_canonical, ty).to_expr()
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToSimValueWithType<TraceAsString<T>> for TraceAsStringSimValue<T> {
|
|
fn to_sim_value_with_type(&self, ty: TraceAsString<T>) -> SimValue<TraceAsString<T>> {
|
|
let inner = self.inner.to_sim_value_with_type(ty.inner_ty());
|
|
SimValue::from_value(
|
|
ty,
|
|
TraceAsStringSimValue {
|
|
inner,
|
|
trace_as_string: ty.trace_as_string.interned(),
|
|
},
|
|
)
|
|
}
|
|
fn into_sim_value_with_type(self, ty: TraceAsString<T>) -> SimValue<TraceAsString<T>> {
|
|
let inner = self.inner.into_sim_value_with_type(ty.inner_ty());
|
|
SimValue::from_value(
|
|
ty,
|
|
TraceAsStringSimValue {
|
|
inner,
|
|
trace_as_string: ty.trace_as_string.interned(),
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToSimValue for TraceAsStringSimValue<T> {
|
|
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
|
SimValue::from_value(self.ty(), self.clone())
|
|
}
|
|
fn into_sim_value(self) -> SimValue<Self::Type> {
|
|
SimValue::from_value(self.ty(), self)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> fmt::Debug for TraceAsStringSimValue<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt::Debug::fmt(&self.inner, f)
|
|
}
|
|
}
|
|
|
|
impl<T: Type<SimValue: fmt::Display>> fmt::Display for TraceAsStringSimValue<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt::Display::fmt(&self.inner, f)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> Ord for TraceAsStringSimValue<T>
|
|
where
|
|
SimValue<T>: Ord,
|
|
{
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.inner.cmp(&other.inner)
|
|
}
|
|
}
|
|
|
|
impl<T: Type, U: Type> PartialOrd<TraceAsStringSimValue<U>> for TraceAsStringSimValue<T>
|
|
where
|
|
SimValue<T>: PartialOrd<SimValue<U>>,
|
|
{
|
|
fn partial_cmp(&self, other: &TraceAsStringSimValue<U>) -> Option<std::cmp::Ordering> {
|
|
self.inner.partial_cmp(&other.inner)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> Eq for TraceAsStringSimValue<T> where SimValue<T>: Eq {}
|
|
|
|
impl<T: Type> Hash for TraceAsStringSimValue<T>
|
|
where
|
|
SimValue<T>: Hash,
|
|
{
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.inner.hash(state);
|
|
}
|
|
}
|
|
|
|
impl<T: Type> Default for TraceAsStringSimValue<T>
|
|
where
|
|
SimValue<T>: Default,
|
|
{
|
|
fn default() -> Self {
|
|
let inner = SimValue::default();
|
|
Self {
|
|
trace_as_string: TraceAsString::new(inner.ty()).trace_as_string.interned(),
|
|
inner,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type, U: Type> PartialEq<TraceAsStringSimValue<U>> for TraceAsStringSimValue<T>
|
|
where
|
|
SimValue<T>: PartialEq<SimValue<U>>,
|
|
{
|
|
fn eq(&self, other: &TraceAsStringSimValue<U>) -> bool {
|
|
self.inner == other.inner
|
|
}
|
|
}
|
|
|
|
impl<T: Type + Fold<State>, State: ?Sized + Folder> Fold<State> for TraceAsString<T> {
|
|
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
|
|
state.fold_trace_as_string(self)
|
|
}
|
|
|
|
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
|
|
Ok(self.with_new_inner_ty(self.interned_inner_ty().fold(state)?))
|
|
}
|
|
}
|
|
|
|
impl<T: Type + Visit<State>, State: ?Sized + Visitor> Visit<State> for TraceAsString<T> {
|
|
fn visit(&self, state: &mut State) -> Result<(), <State as Visitor>::Error> {
|
|
state.visit_trace_as_string(self)
|
|
}
|
|
|
|
fn default_visit(&self, state: &mut State) -> Result<(), <State as Visitor>::Error> {
|
|
self.interned_inner_ty().visit(state)
|
|
}
|
|
}
|
|
|
|
fn trace_as_string_cow_into_inner<T: Type>(
|
|
this: Cow<'_, SimValue<TraceAsString<T>>>,
|
|
) -> Cow<'_, SimValue<T>> {
|
|
match this {
|
|
Cow::Borrowed(v) => Cow::Borrowed(&v.inner),
|
|
Cow::Owned(v) => Cow::Owned(SimValue::into_value(v).inner),
|
|
}
|
|
}
|
|
|
|
fn trace_as_string_cow_into_inner_value<T: Type>(
|
|
this: Cow<'_, TraceAsStringSimValue<T>>,
|
|
) -> Cow<'_, T::SimValue> {
|
|
match this {
|
|
Cow::Borrowed(v) => Cow::Borrowed(&v.inner),
|
|
Cow::Owned(v) => Cow::Owned(SimValue::into_value(v.inner)),
|
|
}
|
|
}
|
|
|
|
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
|
|
#[track_caller]
|
|
fn cmp_value_eq(
|
|
lhs: Self,
|
|
lhs_value: Cow<'_, Self::SimValue>,
|
|
rhs: TraceAsString<U>,
|
|
rhs_value: Cow<'_, <TraceAsString<U> as Type>::SimValue>,
|
|
) -> bool {
|
|
HdlPartialEqImpl::cmp_value_eq(
|
|
lhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(lhs_value),
|
|
rhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(rhs_value),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_value_ne(
|
|
lhs: Self,
|
|
lhs_value: Cow<'_, Self::SimValue>,
|
|
rhs: TraceAsString<U>,
|
|
rhs_value: Cow<'_, <TraceAsString<U> as Type>::SimValue>,
|
|
) -> bool {
|
|
HdlPartialEqImpl::cmp_value_ne(
|
|
lhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(lhs_value),
|
|
rhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(rhs_value),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_sim_value_eq(
|
|
lhs: Cow<'_, SimValue<Self>>,
|
|
rhs: Cow<'_, SimValue<TraceAsString<U>>>,
|
|
) -> SimValue<Bool> {
|
|
HdlPartialEqImpl::cmp_sim_value_eq(
|
|
trace_as_string_cow_into_inner(lhs),
|
|
trace_as_string_cow_into_inner(rhs),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_sim_value_ne(
|
|
lhs: Cow<'_, SimValue<Self>>,
|
|
rhs: Cow<'_, SimValue<TraceAsString<U>>>,
|
|
) -> SimValue<Bool> {
|
|
HdlPartialEqImpl::cmp_sim_value_ne(
|
|
trace_as_string_cow_into_inner(lhs),
|
|
trace_as_string_cow_into_inner(rhs),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<TraceAsString<U>>) -> Expr<Bool> {
|
|
HdlPartialEqImpl::cmp_expr_eq(*lhs, *rhs)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<TraceAsString<U>>) -> Expr<Bool> {
|
|
HdlPartialEqImpl::cmp_expr_ne(*lhs, *rhs)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_valueless_eq(lhs: Valueless<Self>, rhs: Valueless<TraceAsString<U>>) -> Valueless<Bool> {
|
|
HdlPartialEqImpl::cmp_valueless_eq(
|
|
Valueless::new(lhs.ty().inner_ty()),
|
|
Valueless::new(rhs.ty().inner_ty()),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_valueless_ne(lhs: Valueless<Self>, rhs: Valueless<TraceAsString<U>>) -> Valueless<Bool> {
|
|
HdlPartialEqImpl::cmp_valueless_ne(
|
|
Valueless::new(lhs.ty().inner_ty()),
|
|
Valueless::new(rhs.ty().inner_ty()),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<T: HdlPartialOrdImpl<U>, U: Type> HdlPartialOrdImpl<TraceAsString<U>> for TraceAsString<T> {
|
|
#[track_caller]
|
|
fn cmp_value_lt(
|
|
lhs: Self,
|
|
lhs_value: Cow<'_, Self::SimValue>,
|
|
rhs: TraceAsString<U>,
|
|
rhs_value: Cow<'_, <TraceAsString<U> as Type>::SimValue>,
|
|
) -> bool {
|
|
HdlPartialOrdImpl::cmp_value_lt(
|
|
lhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(lhs_value),
|
|
rhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(rhs_value),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_value_le(
|
|
lhs: Self,
|
|
lhs_value: Cow<'_, Self::SimValue>,
|
|
rhs: TraceAsString<U>,
|
|
rhs_value: Cow<'_, <TraceAsString<U> as Type>::SimValue>,
|
|
) -> bool {
|
|
HdlPartialOrdImpl::cmp_value_le(
|
|
lhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(lhs_value),
|
|
rhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(rhs_value),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_value_gt(
|
|
lhs: Self,
|
|
lhs_value: Cow<'_, Self::SimValue>,
|
|
rhs: TraceAsString<U>,
|
|
rhs_value: Cow<'_, <TraceAsString<U> as Type>::SimValue>,
|
|
) -> bool {
|
|
HdlPartialOrdImpl::cmp_value_gt(
|
|
lhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(lhs_value),
|
|
rhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(rhs_value),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_value_ge(
|
|
lhs: Self,
|
|
lhs_value: Cow<'_, Self::SimValue>,
|
|
rhs: TraceAsString<U>,
|
|
rhs_value: Cow<'_, <TraceAsString<U> as Type>::SimValue>,
|
|
) -> bool {
|
|
HdlPartialOrdImpl::cmp_value_ge(
|
|
lhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(lhs_value),
|
|
rhs.inner_ty(),
|
|
trace_as_string_cow_into_inner_value(rhs_value),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_sim_value_lt(
|
|
lhs: Cow<'_, SimValue<Self>>,
|
|
rhs: Cow<'_, SimValue<TraceAsString<U>>>,
|
|
) -> SimValue<Bool> {
|
|
HdlPartialOrdImpl::cmp_sim_value_lt(
|
|
trace_as_string_cow_into_inner(lhs),
|
|
trace_as_string_cow_into_inner(rhs),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_sim_value_le(
|
|
lhs: Cow<'_, SimValue<Self>>,
|
|
rhs: Cow<'_, SimValue<TraceAsString<U>>>,
|
|
) -> SimValue<Bool> {
|
|
HdlPartialOrdImpl::cmp_sim_value_le(
|
|
trace_as_string_cow_into_inner(lhs),
|
|
trace_as_string_cow_into_inner(rhs),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_sim_value_gt(
|
|
lhs: Cow<'_, SimValue<Self>>,
|
|
rhs: Cow<'_, SimValue<TraceAsString<U>>>,
|
|
) -> SimValue<Bool> {
|
|
HdlPartialOrdImpl::cmp_sim_value_gt(
|
|
trace_as_string_cow_into_inner(lhs),
|
|
trace_as_string_cow_into_inner(rhs),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_sim_value_ge(
|
|
lhs: Cow<'_, SimValue<Self>>,
|
|
rhs: Cow<'_, SimValue<TraceAsString<U>>>,
|
|
) -> SimValue<Bool> {
|
|
HdlPartialOrdImpl::cmp_sim_value_ge(
|
|
trace_as_string_cow_into_inner(lhs),
|
|
trace_as_string_cow_into_inner(rhs),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_expr_lt(lhs: Expr<Self>, rhs: Expr<TraceAsString<U>>) -> Expr<Bool> {
|
|
HdlPartialOrdImpl::cmp_expr_lt(*lhs, *rhs)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_expr_le(lhs: Expr<Self>, rhs: Expr<TraceAsString<U>>) -> Expr<Bool> {
|
|
HdlPartialOrdImpl::cmp_expr_le(*lhs, *rhs)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_expr_gt(lhs: Expr<Self>, rhs: Expr<TraceAsString<U>>) -> Expr<Bool> {
|
|
HdlPartialOrdImpl::cmp_expr_gt(*lhs, *rhs)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_expr_ge(lhs: Expr<Self>, rhs: Expr<TraceAsString<U>>) -> Expr<Bool> {
|
|
HdlPartialOrdImpl::cmp_expr_ge(*lhs, *rhs)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_valueless_lt(lhs: Valueless<Self>, rhs: Valueless<TraceAsString<U>>) -> Valueless<Bool> {
|
|
HdlPartialOrdImpl::cmp_valueless_lt(
|
|
Valueless::new(lhs.ty().inner_ty()),
|
|
Valueless::new(rhs.ty().inner_ty()),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_valueless_le(lhs: Valueless<Self>, rhs: Valueless<TraceAsString<U>>) -> Valueless<Bool> {
|
|
HdlPartialOrdImpl::cmp_valueless_le(
|
|
Valueless::new(lhs.ty().inner_ty()),
|
|
Valueless::new(rhs.ty().inner_ty()),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_valueless_gt(lhs: Valueless<Self>, rhs: Valueless<TraceAsString<U>>) -> Valueless<Bool> {
|
|
HdlPartialOrdImpl::cmp_valueless_gt(
|
|
Valueless::new(lhs.ty().inner_ty()),
|
|
Valueless::new(rhs.ty().inner_ty()),
|
|
)
|
|
}
|
|
|
|
#[track_caller]
|
|
fn cmp_valueless_ge(lhs: Valueless<Self>, rhs: Valueless<TraceAsString<U>>) -> Valueless<Bool> {
|
|
HdlPartialOrdImpl::cmp_valueless_ge(
|
|
Valueless::new(lhs.ty().inner_ty()),
|
|
Valueless::new(rhs.ty().inner_ty()),
|
|
)
|
|
}
|
|
}
|