1
0
Fork 0
fayalite/crates/fayalite/src/ty.rs

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()),
)
}
}