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

919 lines
32 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
expr::{
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
Valueless,
ops::{ArrayLiteral, BundleLiteral},
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
},
int::{Bool, DynSize},
intern::{Intern, InternSlice, Interned},
sim::value::{SimValue, SimValueEq, ToSimValue, ToSimValueWithType},
source_location::SourceLocation,
ty::{
CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties, TypeWithDeref, impl_match_variant_as_self,
},
util::HashMap,
};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, fmt, marker::PhantomData};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct BundleField {
pub name: Interned<str>,
pub flipped: bool,
pub ty: CanonicalType,
}
impl BundleField {
pub fn fmt_debug_in_struct(self, field_offset: usize) -> FmtDebugInStruct {
FmtDebugInStruct {
field: self,
field_offset,
}
}
}
#[derive(Copy, Clone)]
pub struct FmtDebugInStruct {
field: BundleField,
field_offset: usize,
}
impl fmt::Debug for FmtDebugInStruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
field: BundleField { name, flipped, ty },
field_offset,
} = *self;
if flipped {
write!(f, "#[hdl(flip)] ")?;
}
if f.alternate() {
writeln!(f, "/* offset = {field_offset} */")?;
}
write!(f, "{name}: ")?;
ty.fmt(f)
}
}
impl fmt::Display for FmtDebugInStruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Clone, Eq)]
struct BundleImpl {
fields: Interned<[BundleField]>,
name_indexes: HashMap<Interned<str>, usize>,
field_offsets: Interned<[OpaqueSimValueSize]>,
type_properties: TypeProperties,
}
impl std::hash::Hash for BundleImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.fields.hash(state);
}
}
impl PartialEq for BundleImpl {
fn eq(&self, other: &Self) -> bool {
self.fields == other.fields
}
}
impl std::fmt::Debug for BundleImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Bundle ")?;
f.debug_set()
.entries(self.fields.iter().enumerate().map(|(index, field)| {
field.fmt_debug_in_struct(self.field_offsets[index].bit_width)
}))
.finish()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Bundle(Interned<BundleImpl>);
impl std::fmt::Debug for Bundle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Clone)]
pub struct BundleTypePropertiesBuilder(TypeProperties);
impl BundleTypePropertiesBuilder {
#[must_use]
pub const fn new() -> Self {
Self(TypeProperties {
is_passive: true,
is_storable: true,
is_castable_from_bits: true,
bit_width: 0,
sim_only_values_len: 0,
})
}
pub const fn clone(&self) -> Self {
Self(self.0)
}
#[must_use]
pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self {
let Some(OpaqueSimValueSize {
bit_width,
sim_only_values_len,
}) = self.0.size().checked_add(field_props.size())
else {
panic!("bundle is too big: size overflowed");
};
if flipped {
Self(TypeProperties {
is_passive: false,
is_storable: false,
is_castable_from_bits: false,
bit_width,
sim_only_values_len,
})
} else {
Self(TypeProperties {
is_passive: self.0.is_passive & field_props.is_passive,
is_storable: self.0.is_storable & field_props.is_storable,
is_castable_from_bits: self.0.is_castable_from_bits
& field_props.is_castable_from_bits,
bit_width,
sim_only_values_len,
})
}
}
pub const fn finish(self) -> TypeProperties {
self.0
}
}
impl Default for BundleTypePropertiesBuilder {
fn default() -> Self {
Self::new()
}
}
impl Bundle {
#[track_caller]
pub fn new(fields: Interned<[BundleField]>) -> Self {
let mut name_indexes = HashMap::with_capacity_and_hasher(fields.len(), Default::default());
let mut field_offsets = Vec::with_capacity(fields.len());
let mut type_props_builder = BundleTypePropertiesBuilder::new();
for (index, &BundleField { name, flipped, ty }) in fields.iter().enumerate() {
if let Some(old_index) = name_indexes.insert(name, index) {
panic!("duplicate field name {name:?}: at both index {old_index} and {index}");
}
field_offsets.push(type_props_builder.0.size());
type_props_builder = type_props_builder.field(flipped, ty.type_properties());
}
Self(Intern::intern_sized(BundleImpl {
fields,
name_indexes,
field_offsets: Intern::intern_owned(field_offsets),
type_properties: type_props_builder.finish(),
}))
}
pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
&self.0.name_indexes
}
pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> {
Some(self.0.fields[*self.0.name_indexes.get(&name)?])
}
pub fn field_offsets(self) -> Interned<[OpaqueSimValueSize]> {
self.0.field_offsets
}
pub fn type_properties(self) -> TypeProperties {
self.0.type_properties
}
pub fn can_connect(self, rhs: Self) -> bool {
if self.0.fields.len() != rhs.0.fields.len() {
return false;
}
for (
&BundleField {
name: lhs_name,
flipped: lhs_flipped,
ty: lhs_ty,
},
&BundleField {
name: rhs_name,
flipped: rhs_flipped,
ty: rhs_ty,
},
) in self.0.fields.iter().zip(rhs.0.fields.iter())
{
if lhs_name != rhs_name || lhs_flipped != rhs_flipped || !lhs_ty.can_connect(rhs_ty) {
return false;
}
}
true
}
}
impl Type for Bundle {
type BaseType = Bundle;
type MaskType = Bundle;
type SimValue = OpaqueSimValue;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
Self::new(Interned::from_iter(self.0.fields.into_iter().map(
|BundleField { name, flipped, ty }| BundleField {
name,
flipped,
ty: ty.mask_type(),
},
)))
}
fn canonical(&self) -> CanonicalType {
CanonicalType::Bundle(*self)
}
#[track_caller]
fn from_canonical(canonical_type: CanonicalType) -> Self {
let CanonicalType::Bundle(bundle) = canonical_type else {
panic!("expected bundle");
};
bundle
}
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())
}
}
pub trait BundleType: Type<BaseType = Bundle> {
type Builder: Default;
fn fields(&self) -> Interned<[BundleField]>;
}
pub struct BundleSimValueFromOpaque<'a> {
fields: std::slice::Iter<'static, BundleField>,
opaque: OpaqueSimValueSlice<'a>,
}
impl<'a> BundleSimValueFromOpaque<'a> {
#[track_caller]
pub fn new<T: BundleType>(bundle_ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self {
let fields = bundle_ty.fields();
assert_eq!(
opaque.size(),
fields
.iter()
.map(|BundleField { ty, .. }| ty.size())
.sum::<OpaqueSimValueSize>()
);
Self {
fields: Interned::into_inner(fields).iter(),
opaque,
}
}
#[track_caller]
fn field_ty_and_opaque<T: Type>(&mut self) -> (T, OpaqueSimValueSlice<'a>) {
let Some(&BundleField {
name: _,
flipped: _,
ty,
}) = self.fields.next()
else {
panic!("tried to read too many fields from BundleSimValueFromBits");
};
let (field_opaque, rest) = self.opaque.split_at(ty.size());
self.opaque = rest;
(T::from_canonical(ty), field_opaque)
}
#[track_caller]
pub fn field_from_opaque<T: Type>(&mut self) -> SimValue<T> {
let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
SimValue::from_opaque(field_ty, field_opaque.to_owned())
}
#[track_caller]
pub fn field_clone_from_opaque<T: Type>(&mut self, field_value: &mut SimValue<T>) {
let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
assert_eq!(field_ty, field_value.ty());
SimValue::opaque_mut(field_value).clone_from_slice(field_opaque);
}
}
pub struct BundleSimValueToOpaque<'a> {
fields: std::slice::Iter<'static, BundleField>,
writer: OpaqueSimValueWriter<'a>,
}
impl<'a> BundleSimValueToOpaque<'a> {
#[track_caller]
pub fn new<T: BundleType>(bundle_ty: T, writer: OpaqueSimValueWriter<'a>) -> Self {
let fields = bundle_ty.fields();
assert_eq!(
writer.size(),
fields
.iter()
.map(|BundleField { ty, .. }| ty.size())
.sum::<OpaqueSimValueSize>()
);
Self {
fields: Interned::into_inner(fields).iter(),
writer,
}
}
#[track_caller]
pub fn field<T: Type>(&mut self, field_value: &SimValue<T>) {
let Some(&BundleField {
name: _,
flipped: _,
ty,
}) = self.fields.next()
else {
panic!("tried to write too many fields with BundleSimValueToOpaque");
};
assert_eq!(T::from_canonical(ty), field_value.ty());
self.writer.fill_prefix_with(ty.size(), |writer| {
writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice())
});
}
#[track_caller]
pub fn finish(mut self) -> OpaqueSimValueWritten<'a> {
assert_eq!(
self.fields.next(),
None,
"wrote too few fields with BundleSimValueToOpaque"
);
self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
}
}
#[derive(Default)]
pub struct NoBuilder;
impl BundleType for Bundle {
type Builder = NoBuilder;
fn fields(&self) -> Interned<[BundleField]> {
self.0.fields
}
}
#[derive(Default)]
pub struct TupleBuilder<T>(T);
macro_rules! impl_tuple_builder_fields {
(
@impl
{
}
[
$({
#[type_var($head_type_var:ident)]
#[field($head_field:ident)]
#[var($head_var:ident)]
})*
]
{
#[type_var($cur_type_var:ident)]
#[field($cur_field:ident)]
#[var($cur_var:ident)]
}
[
$({
#[type_var($tail_type_var:ident)]
#[field($tail_field:ident)]
#[var($tail_var:ident)]
})*
]
) => {
impl<
$($head_type_var,)*
$($tail_type_var,)*
> TupleBuilder<(
$($head_type_var,)*
(),
$($tail_type_var,)*
)>
{
pub fn $cur_field<$cur_type_var: Type>(self, $cur_var: impl ToExpr<Type = $cur_type_var>) -> TupleBuilder<(
$($head_type_var,)*
Expr<$cur_type_var>,
$($tail_type_var,)*
)>
{
let ($($head_var,)* _, $($tail_var,)*) = self.0;
TupleBuilder(($($head_var,)* $cur_var.to_expr(), $($tail_var,)*))
}
}
};
($global:tt [$($head:tt)*] $cur:tt [$next:tt $($tail:tt)*]) => {
impl_tuple_builder_fields!(@impl $global [$($head)*] $cur [$next $($tail)*]);
impl_tuple_builder_fields!($global [$($head)* $cur] $next [$($tail)*]);
};
($global:tt [$($head:tt)*] $cur:tt []) => {
impl_tuple_builder_fields!(@impl $global [$($head)*] $cur []);
};
($global:tt [$cur:tt $($tail:tt)*]) => {
impl_tuple_builder_fields!($global [] $cur [$($tail)*]);
};
($global:tt []) => {};
}
macro_rules! get_unit_ty {
($($tt:tt)*) => {
()
};
}
macro_rules! impl_tuples {
(
[$({
#[
num = $num:tt,
field = $field:ident,
ty = $ty_var:ident: $Ty:ident,
lhs = $lhs_var:ident: $Lhs:ident,
rhs = $rhs_var:ident: $Rhs:ident
]
$var:ident: $T:ident
})*]
[]
) => {
impl_tuple_builder_fields! {
{}
[$({
#[type_var($T)]
#[field($field)]
#[var($var)]
})*]
}
impl<$($T: Type,)*> Type for ($($T,)*) {
type BaseType = Bundle;
type MaskType = ($($T::MaskType,)*);
type SimValue = ($(SimValue<$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 _ = this;
let _ = source_location;
std::iter::once(MatchVariantWithoutScope(($(Expr::field(this, stringify!($num)),)*)))
}
fn mask_type(&self) -> Self::MaskType {
#![allow(clippy::unused_unit)]
let ($($var,)*) = self;
($($var.mask_type(),)*)
}
fn canonical(&self) -> CanonicalType {
Bundle::new(self.fields()).canonical()
}
#[track_caller]
fn from_canonical(canonical_type: CanonicalType) -> Self {
#![allow(clippy::unused_unit)]
let CanonicalType::Bundle(bundle) = canonical_type else {
panic!("expected bundle");
};
let [$($var,)*] = *bundle.fields() else {
panic!("bundle has wrong number of fields");
};
$(let BundleField { name, flipped, ty } = $var;
assert_eq!(&*name, stringify!($num));
assert!(!flipped);
let $var = $T::from_canonical(ty);)*
($($var,)*)
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
#![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueFromOpaque::new(*self, opaque);
$(let $var = v.field_from_opaque();)*
($($var,)*)
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueFromOpaque::new(*self, opaque);
let ($($var,)*) = value;
$(v.field_clone_from_opaque($var);)*
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
#![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueToOpaque::new(*self, writer);
let ($($var,)*) = value;
$(v.field($var);)*
v.finish()
}
}
impl<$($T: Type,)*> BundleType for ($($T,)*) {
type Builder = TupleBuilder<($(get_unit_ty!($T),)*)>;
fn fields(&self) -> Interned<[BundleField]> {
let ($($var,)*) = self;
[$(BundleField { name: stringify!($num).intern(), flipped: false, ty: $var.canonical() }),*].intern_slice()
}
}
impl<$($T: Type,)*> TypeWithDeref for ($($T,)*) {
fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant {
let _ = this;
Interned::into_inner(($(Expr::field(*this, stringify!($num)),)*).intern_sized())
}
}
impl<$($T: StaticType,)*> StaticType for ($($T,)*) {
const TYPE: Self = ($($T::TYPE,)*);
const MASK_TYPE: Self::MaskType = ($($T::MASK_TYPE,)*);
const TYPE_PROPERTIES: TypeProperties = {
let builder = BundleTypePropertiesBuilder::new();
$(let builder = builder.field(false, $T::TYPE_PROPERTIES);)*
builder.finish()
};
const MASK_TYPE_PROPERTIES: TypeProperties = {
let builder = BundleTypePropertiesBuilder::new();
$(let builder = builder.field(false, $T::MASK_TYPE_PROPERTIES);)*
builder.finish()
};
}
impl<'a, $($T: ToSimValue,)*> ToSimValueInner<'a> for ($($T,)*)
where
Self: ValueType<Type = ($($T::Type,)*)>,
{
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
let ($($var,)*) = this;
Cow::Owned(($($var.to_sim_value(),)*))
}
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
let ($($var,)*) = this;
Cow::Owned(($($var.into_sim_value(),)*))
}
}
impl<$($T: ValueType,)*> ValueType for ($($T,)*)
where
ValueCategoryValue: ValueCategoryCommon<($($T::ValueCategory,)*)>,
{
type Type = ($($T::Type,)*);
type ValueCategory = <ValueCategoryValue as ValueCategoryCommon<($($T::ValueCategory,)*)>>::Common;
fn ty(&self) -> Self::Type {
let ($($var,)*) = self;
($($var.ty(),)*)
}
}
impl<$($T: ToExpr,)*> ToExpr for ($($T,)*)
where
Self: ValueType<Type = ($($T::Type,)*)>,
{
fn to_expr(&self) -> Expr<Self::Type> {
let ($($var,)*) = self;
$(let $var = $var.to_expr();)*
let ty = ($($var.ty(),)*);
let field_values = [$(Expr::canonical($var)),*];
BundleLiteral::new(ty, field_values.intern_slice()).to_expr()
}
}
impl<$($T: Type,)*> ValueType for TupleBuilder<($(Expr<$T>,)*)> {
type Type = ($($T,)*);
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
let ($($var,)*) = self.0;
($($var.ty(),)*)
}
}
impl<$($T: Type,)*> ToExpr for TupleBuilder<($(Expr<$T>,)*)> {
fn to_expr(&self) -> Expr<Self::Type> {
let ($($var,)*) = self.0;
let ty = ($($var.ty(),)*);
let field_values = [$(Expr::canonical($var)),*];
BundleLiteral::new(ty, field_values.intern_slice()).to_expr()
}
}
impl<$($T: ToSimValueWithType<CanonicalType>,)*> ToSimValueWithType<CanonicalType> for ($($T,)*) {
#[track_caller]
fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
SimValue::into_canonical(ToSimValueWithType::<Bundle>::to_sim_value_with_type(self, Bundle::from_canonical(ty)))
}
#[track_caller]
fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue<CanonicalType>
{
SimValue::into_canonical(ToSimValueWithType::<Bundle>::into_sim_value_with_type(self, Bundle::from_canonical(ty)))
}
}
impl<$($T: ToSimValueWithType<CanonicalType>,)*> ToSimValueWithType<Bundle> for ($($T,)*) {
#[track_caller]
fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> {
let ($($var,)*) = self;
let [$($ty_var,)*] = *ty.fields() else {
panic!("bundle has wrong number of fields");
};
$(let $var = $var.to_sim_value_with_type($ty_var.ty);)*
ToSimValueWithType::into_sim_value_with_type(($($var,)*), ty)
}
#[track_caller]
fn into_sim_value_with_type(self, ty: Bundle) -> SimValue<Bundle> {
#![allow(unused_mut)]
#![allow(clippy::unused_unit)]
let ($($var,)*) = self;
let [$($ty_var,)*] = *ty.fields() else {
panic!("bundle has wrong number of fields");
};
let mut opaque = OpaqueSimValue::empty();
$(let $var = $var.into_sim_value_with_type($ty_var.ty);
assert_eq!($var.ty(), $ty_var.ty);
opaque.extend_from_slice(SimValue::opaque(&$var).as_slice());
)*
SimValue::from_opaque(ty, opaque)
}
}
impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) {
#[track_caller]
fn to_sim_value_with_type(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
let ($($var,)*) = self;
let ($($ty_var,)*) = ty;
$(let $var = $var.to_sim_value_with_type($ty_var);)*
SimValue::from_value(ty, ($($var,)*))
}
#[track_caller]
fn into_sim_value_with_type(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
let ($($var,)*) = self;
let ($($ty_var,)*) = ty;
$(let $var = $var.into_sim_value_with_type($ty_var);)*
SimValue::from_value(ty, ($($var,)*))
}
}
impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*)
where
Self: ValueType<Type = ($($T::Type,)*)>,
{
#[track_caller]
fn to_sim_value(&self) -> SimValue<Self::Type> {
let ($($var,)*) = self;
$(let $var = $var.to_sim_value();)*
SimValue::from_value(($($var.ty(),)*), ($($var,)*))
}
#[track_caller]
fn into_sim_value(self) -> SimValue<Self::Type> {
let ($($var,)*) = self;
$(let $var = $var.to_sim_value();)*
SimValue::from_value(($($var.ty(),)*), ($($var,)*))
}
}
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
#[track_caller]
fn cmp_value_eq(
lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
rhs: ($($Rhs,)*),
rhs_value: Cow<'_, <($($Rhs,)*) as Type>::SimValue>,
) -> bool {
#![allow(unused_variables)]
let ($($lhs_var,)*) = &*lhs_value;
let ($($rhs_var,)*) = &*rhs_value;
let retval = true;
$(let retval = retval && $Lhs::cmp_value_eq(lhs.$num, Cow::Borrowed($lhs_var), rhs.$num, Cow::Borrowed($rhs_var));)*
retval
}
#[track_caller]
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
let ($($lhs_var,)*) = *lhs;
let ($($rhs_var,)*) = *rhs;
ArrayLiteral::<Bool, DynSize>::new(
Bool,
FromIterator::from_iter([$(Expr::canonical($Lhs::cmp_expr_eq($lhs_var, $rhs_var)),)*]),
)
.cast_to_bits()
.all_one_bits()
}
#[track_caller]
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
let ($($lhs_var,)*) = *lhs;
let ($($rhs_var,)*) = *rhs;
ArrayLiteral::<Bool, DynSize>::new(
Bool,
FromIterator::from_iter([$(Expr::canonical($Lhs::cmp_expr_ne($lhs_var, $rhs_var)),)*]),
)
.cast_to_bits()
.any_one_bits()
}
#[track_caller]
fn cmp_valueless_eq(lhs: Valueless<Self>, rhs: Valueless<($($Rhs,)*)>) -> Valueless<Bool> {
let ($($lhs_var,)*) = lhs.ty();
let ($($rhs_var,)*) = rhs.ty();
// let them check that the types can be compared
$($Lhs::cmp_valueless_eq(Valueless::new($lhs_var), Valueless::new($rhs_var));)*
Valueless::new(Bool)
}
#[track_caller]
fn cmp_valueless_ne(lhs: Valueless<Self>, rhs: Valueless<($($Rhs,)*)>) -> Valueless<Bool> {
let ($($lhs_var,)*) = lhs.ty();
let ($($rhs_var,)*) = rhs.ty();
// let them check that the types can be compared
$($Lhs::cmp_valueless_ne(Valueless::new($lhs_var), Valueless::new($rhs_var));)*
Valueless::new(Bool)
}
}
impl<$($T: SimValueEq + HdlPartialEqImpl<$T>,)*> SimValueEq for ($($T,)*) {}
};
([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => {
impl_tuples!([$($lhs)*] []);
impl_tuples!([$($lhs)* $rhs_first] [$($rhs)*]);
};
}
impl_tuples! {
[] [
{#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0}
{#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1}
{#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2}
{#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3}
{#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4}
{#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5}
{#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6}
{#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7}
{#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8}
{#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9}
{#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10}
{#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11}
]
}
impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
type BaseType = Bundle;
type MaskType = ();
type SimValue = PhantomData<T>;
type MatchVariant = PhantomData<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 _ = this;
let _ = source_location;
std::iter::once(MatchVariantWithoutScope(PhantomData))
}
fn mask_type(&self) -> Self::MaskType {
()
}
fn canonical(&self) -> CanonicalType {
Bundle::new(self.fields()).canonical()
}
#[track_caller]
fn from_canonical(canonical_type: CanonicalType) -> Self {
let CanonicalType::Bundle(bundle) = canonical_type else {
panic!("expected bundle");
};
assert!(
bundle.fields().is_empty(),
"bundle has wrong number of fields"
);
PhantomData
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert!(opaque.is_empty());
*self
}
fn sim_value_clone_from_opaque(
&self,
_value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert!(opaque.is_empty());
}
fn sim_value_to_opaque<'w>(
&self,
_value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
}
}
pub struct PhantomDataBuilder<T: ?Sized + Send + Sync + 'static>(PhantomData<T>);
impl<T: ?Sized + Send + Sync + 'static> Default for PhantomDataBuilder<T> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<T: ?Sized + Send + Sync + 'static> ValueType for PhantomDataBuilder<T> {
type Type = PhantomData<T>;
type ValueCategory = ValueCategoryValue;
fn ty(&self) -> Self::Type {
PhantomData
}
}
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomDataBuilder<T> {
fn to_expr(&self) -> Expr<Self::Type> {
PhantomData.to_expr()
}
}
impl<T: ?Sized + Send + Sync + 'static> BundleType for PhantomData<T> {
type Builder = PhantomDataBuilder<T>;
fn fields(&self) -> Interned<[BundleField]> {
Interned::default()
}
}
impl<T: ?Sized + Send + Sync + 'static> TypeWithDeref for PhantomData<T> {
fn expr_deref(_this: &Expr<Self>) -> &Self::MatchVariant {
&PhantomData
}
}
impl<T: ?Sized + Send + Sync + 'static> StaticType for PhantomData<T> {
const TYPE: Self = PhantomData;
const MASK_TYPE: Self::MaskType = ();
const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
}
impl<T: ?Sized + Send + Sync + 'static> ValueType for PhantomData<T> {
type Type = PhantomData<T>;
type ValueCategory = ValueCategoryValue;
fn ty(&self) -> Self::Type {
PhantomData
}
}
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
fn to_expr(&self) -> Expr<Self::Type> {
BundleLiteral::new(PhantomData, Interned::default()).to_expr()
}
}
impl<T: ?Sized + Send + Sync + 'static> ToSimValue for PhantomData<T> {
#[track_caller]
fn to_sim_value(&self) -> SimValue<Self> {
SimValue::from_value(*self, *self)
}
}
impl<T: ?Sized + Send + Sync + 'static> ToSimValueWithType<Self> for PhantomData<T> {
#[track_caller]
fn to_sim_value_with_type(&self, ty: Self) -> SimValue<Self> {
SimValue::from_value(ty, *self)
}
}
impl<T: ?Sized> ToSimValueWithType<Bundle> for PhantomData<T> {
#[track_caller]
fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> {
assert!(ty.fields().is_empty());
SimValue::from_opaque(ty, OpaqueSimValue::empty())
}
}
impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> {
#[track_caller]
fn to_sim_value_with_type(&self, canonical_ty: CanonicalType) -> SimValue<CanonicalType> {
let ty = Bundle::from_canonical(canonical_ty);
assert!(ty.fields().is_empty());
SimValue::from_opaque(canonical_ty, OpaqueSimValue::empty())
}
}