forked from libre-chip/fayalite
WIP switched to OpaqueSimValueWriter
This commit is contained in:
parent
6d36698adf
commit
ab21db4103
13 changed files with 1546 additions and 131 deletions
|
@ -12,7 +12,8 @@ use crate::{
|
||||||
sim::value::{SimValue, SimValuePartialEq},
|
sim::value::{SimValue, SimValuePartialEq},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{
|
ty::{
|
||||||
CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref,
|
CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter,
|
||||||
|
OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref,
|
||||||
serde_impls::SerdeCanonicalType,
|
serde_impls::SerdeCanonicalType,
|
||||||
},
|
},
|
||||||
util::ConstUsize,
|
util::ConstUsize,
|
||||||
|
@ -48,6 +49,7 @@ impl<T: Type, Len: Size> ArrayType<T, Len> {
|
||||||
is_storable,
|
is_storable,
|
||||||
is_castable_from_bits,
|
is_castable_from_bits,
|
||||||
bit_width,
|
bit_width,
|
||||||
|
sim_only_value_types,
|
||||||
} = element;
|
} = element;
|
||||||
let Some(bit_width) = bit_width.checked_mul(len) else {
|
let Some(bit_width) = bit_width.checked_mul(len) else {
|
||||||
panic!("array too big");
|
panic!("array too big");
|
||||||
|
@ -194,42 +196,71 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), self.type_properties.bit_width);
|
assert_eq!(bits.len(), self.type_properties.bit_width);
|
||||||
let element = self.element();
|
let element = self.element();
|
||||||
let element_bit_width = element.canonical().bit_width();
|
let element_props = element.canonical().type_properties();
|
||||||
|
let element_bit_width = element_props.bit_width;
|
||||||
|
let element_sim_only_types_count = element_props.sim_only_value_types_ref().len();
|
||||||
TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| {
|
TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| {
|
||||||
SimValue::from_bitslice(element, &bits[i * element_bit_width..][..element_bit_width])
|
SimValue::from_bitslice_and_sim_only_values(
|
||||||
|
element,
|
||||||
|
&bits[i * element_props.bit_width..][..element_props.bit_width],
|
||||||
|
&sim_only_values[i * element_sim_only_types_count][..element_sim_only_types_count],
|
||||||
|
)
|
||||||
})))
|
})))
|
||||||
.ok()
|
.ok()
|
||||||
.expect("used correct length")
|
.expect("used correct length")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), self.type_properties.bit_width);
|
assert_eq!(bits.len(), self.type_properties.bit_width);
|
||||||
let element_ty = self.element();
|
let element_ty = self.element();
|
||||||
let element_bit_width = element_ty.canonical().bit_width();
|
let element_props = element_ty.canonical().type_properties();
|
||||||
|
let element_bit_width = element_props.bit_width;
|
||||||
|
let element_sim_only_types_count = element_props.sim_only_value_types_ref().len();
|
||||||
let value: &mut [SimValue<T>] = value.as_mut();
|
let value: &mut [SimValue<T>] = value.as_mut();
|
||||||
assert_eq!(self.len(), value.len());
|
assert_eq!(self.len(), value.len());
|
||||||
for (i, element_value) in value.iter_mut().enumerate() {
|
for (i, element_value) in value.iter_mut().enumerate() {
|
||||||
assert_eq!(SimValue::ty(element_value), element_ty);
|
assert_eq!(SimValue::ty(element_value), element_ty);
|
||||||
SimValue::bits_mut(element_value)
|
let (bits_mut, sim_only_values_mut) = SimValue::opaque_mut(element_value).parts_mut();
|
||||||
|
bits_mut
|
||||||
.bits_mut()
|
.bits_mut()
|
||||||
.copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]);
|
.copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]);
|
||||||
|
sim_only_values_mut.clone_from_slice(
|
||||||
|
&sim_only_values[i * element_sim_only_types_count..]
|
||||||
|
[..element_sim_only_types_count],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_opaque<'w>(
|
||||||
assert_eq!(bits.len(), self.type_properties.bit_width);
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
mut writer: OpaqueSimValueWriter<'w>,
|
||||||
|
) -> OpaqueSimValueWritten<'w> {
|
||||||
let element_ty = self.element();
|
let element_ty = self.element();
|
||||||
let element_bit_width = element_ty.canonical().bit_width();
|
let element_props = element_ty.canonical().type_properties();
|
||||||
let value: &[SimValue<T>] = value.as_ref();
|
let element_bit_width = element_props.bit_width;
|
||||||
|
let element_sim_only_types_count = element_props.sim_only_value_types_ref().len();
|
||||||
|
let value = AsRef::<[SimValue<T>]>::as_ref(&value);
|
||||||
assert_eq!(self.len(), value.len());
|
assert_eq!(self.len(), value.len());
|
||||||
for (i, element_value) in value.iter().enumerate() {
|
for element_value in value {
|
||||||
assert_eq!(SimValue::ty(element_value), element_ty);
|
assert_eq!(SimValue::ty(element_value), element_ty);
|
||||||
bits[i * element_bit_width..][..element_bit_width]
|
writer.fill_prefix_with(element_bit_width, element_sim_only_types_count, |writer| {
|
||||||
.copy_from_bitslice(SimValue::bits(element_value).bits());
|
writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,16 +241,30 @@ impl Type for Bundle {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), self.type_properties().bit_width);
|
assert_eq!(bits.len(), self.type_properties().bit_width);
|
||||||
OpaqueSimValue::from_bitslice(bits)
|
OpaqueSimValue::from_bitslice(bits)
|
||||||
}
|
}
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), self.type_properties().bit_width);
|
assert_eq!(bits.len(), self.type_properties().bit_width);
|
||||||
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
||||||
value.bits_mut().bits_mut().copy_from_bitslice(bits);
|
value.bits_mut().bits_mut().copy_from_bitslice(bits);
|
||||||
}
|
}
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
assert_eq!(bits.len(), self.type_properties().bit_width);
|
assert_eq!(bits.len(), self.type_properties().bit_width);
|
||||||
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
||||||
bits.copy_from_bitslice(value.bits().bits());
|
bits.copy_from_bitslice(value.bits().bits());
|
||||||
|
@ -495,19 +509,33 @@ macro_rules! impl_tuples {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
#![allow(unused_mut, unused_variables)]
|
#![allow(unused_mut, unused_variables)]
|
||||||
let mut v = BundleSimValueFromBits::new(*self, bits);
|
let mut v = BundleSimValueFromBits::new(*self, bits);
|
||||||
$(let $var = v.field_from_bits();)*
|
$(let $var = v.field_from_bits();)*
|
||||||
($($var,)*)
|
($($var,)*)
|
||||||
}
|
}
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
#![allow(unused_mut, unused_variables)]
|
#![allow(unused_mut, unused_variables)]
|
||||||
let mut v = BundleSimValueFromBits::new(*self, bits);
|
let mut v = BundleSimValueFromBits::new(*self, bits);
|
||||||
let ($($var,)*) = value;
|
let ($($var,)*) = value;
|
||||||
$(v.field_clone_from_bits($var);)*
|
$(v.field_clone_from_bits($var);)*
|
||||||
}
|
}
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
#![allow(unused_mut, unused_variables)]
|
#![allow(unused_mut, unused_variables)]
|
||||||
let mut v = BundleSimValueToBits::new(*self, bits);
|
let mut v = BundleSimValueToBits::new(*self, bits);
|
||||||
let ($($var,)*) = value;
|
let ($($var,)*) = value;
|
||||||
|
@ -723,7 +751,11 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert!(bits.is_empty());
|
assert!(bits.is_empty());
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,17 +39,31 @@ impl Type for Clock {
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits[0]
|
bits[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
*value = bits[0];
|
*value = bits[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits.set(0, *value);
|
bits.set(0, *value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,16 +381,30 @@ impl Type for Enum {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), self.type_properties().bit_width);
|
assert_eq!(bits.len(), self.type_properties().bit_width);
|
||||||
OpaqueSimValue::from_bitslice(bits)
|
OpaqueSimValue::from_bitslice(bits)
|
||||||
}
|
}
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), self.type_properties().bit_width);
|
assert_eq!(bits.len(), self.type_properties().bit_width);
|
||||||
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
||||||
value.bits_mut().bits_mut().copy_from_bitslice(bits);
|
value.bits_mut().bits_mut().copy_from_bitslice(bits);
|
||||||
}
|
}
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
assert_eq!(bits.len(), self.type_properties().bit_width);
|
assert_eq!(bits.len(), self.type_properties().bit_width);
|
||||||
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
assert_eq!(value.bit_width(), self.type_properties().bit_width);
|
||||||
bits.copy_from_bitslice(value.bits().bits());
|
bits.copy_from_bitslice(value.bits().bits());
|
||||||
|
|
|
@ -678,16 +678,30 @@ macro_rules! impl_int {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), self.width());
|
assert_eq!(bits.len(), self.width());
|
||||||
$value::new(Arc::new(bits.to_bitvec()))
|
$value::new(Arc::new(bits.to_bitvec()))
|
||||||
}
|
}
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), self.width());
|
assert_eq!(bits.len(), self.width());
|
||||||
assert_eq!(value.width(), self.width());
|
assert_eq!(value.width(), self.width());
|
||||||
value.bits_mut().copy_from_bitslice(bits);
|
value.bits_mut().copy_from_bitslice(bits);
|
||||||
}
|
}
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
assert_eq!(bits.len(), self.width());
|
assert_eq!(bits.len(), self.width());
|
||||||
assert_eq!(value.width(), self.width());
|
assert_eq!(value.width(), self.width());
|
||||||
bits.copy_from_bitslice(value.bits());
|
bits.copy_from_bitslice(value.bits());
|
||||||
|
@ -1252,15 +1266,29 @@ impl Type for Bool {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits[0]
|
bits[0]
|
||||||
}
|
}
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
*value = bits[0];
|
*value = bits[0];
|
||||||
}
|
}
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits.set(0, *value);
|
bits.set(0, *value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,15 +70,29 @@ impl Type for UIntInRangeMaskType {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
Bool.sim_value_from_bits(bits)
|
Bool.sim_value_from_bits(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
Bool.sim_value_clone_from_bits(value, bits);
|
Bool.sim_value_clone_from_bits(value, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
Bool.sim_value_to_bits(value, bits);
|
Bool.sim_value_to_bits(value, bits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,17 +367,31 @@ macro_rules! define_uint_in_range_type {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
let mut retval = 0usize;
|
let mut retval = 0usize;
|
||||||
retval.view_bits_mut::<Lsb0>()[..bits.len()].clone_from_bitslice(bits);
|
retval.view_bits_mut::<Lsb0>()[..bits.len()].clone_from_bitslice(bits);
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
*value = self.sim_value_from_bits(bits);
|
*value = self.sim_value_from_bits(bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
bits.clone_from_bitslice(&value.view_bits::<Lsb0>()[..bits.len()]);
|
bits.clone_from_bitslice(&value.view_bits::<Lsb0>()[..bits.len()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
int::Bool,
|
int::Bool,
|
||||||
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
|
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
|
||||||
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
|
sim::value::{
|
||||||
|
DynSimOnlyValue, DynSimOnlyValuesWriter, DynSimOnlyValuesWritten, SimValue,
|
||||||
|
SimValuePartialEq, ToSimValue, ToSimValueWithType, assert_matching_sim_values,
|
||||||
|
},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{
|
ty::{
|
||||||
CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self,
|
CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self,
|
||||||
|
@ -284,18 +287,32 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
assert!(bits.is_empty());
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
|
assert_matching_sim_values(0, &[], bits, sim_only_values);
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
assert!(bits.is_empty());
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
|
assert_matching_sim_values(0, &[], bits, sim_only_values);
|
||||||
assert_eq!(*value, *self);
|
assert_eq!(*value, *self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
assert!(bits.is_empty());
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
|
assert_matching_sim_values(0, &[], bits, sim_only_values);
|
||||||
assert_eq!(*value, *self);
|
assert_eq!(*value, *self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,17 +69,31 @@ macro_rules! reset_type {
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_bits(
|
||||||
|
&self,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits[0]
|
bits[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_bits(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
*value = bits[0];
|
*value = bits[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_bits<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
bits: &mut BitSlice,
|
||||||
|
sim_only_values: DynSimOnlyValuesWriter<'w>,
|
||||||
|
) -> DynSimOnlyValuesWritten<'w> {
|
||||||
assert_eq!(bits.len(), 1);
|
assert_eq!(bits.len(), 1);
|
||||||
bits.set(0, *value);
|
bits.set(0, *value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,61 +8,81 @@ use crate::{
|
||||||
enum_::{Enum, EnumType},
|
enum_::{Enum, EnumType},
|
||||||
expr::{CastBitsTo, Expr, ToExpr},
|
expr::{CastBitsTo, Expr, ToExpr},
|
||||||
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
|
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
|
||||||
|
intern::Interned,
|
||||||
reset::{AsyncReset, Reset, SyncReset},
|
reset::{AsyncReset, Reset, SyncReset},
|
||||||
ty::{CanonicalType, StaticType, Type},
|
source_location::SourceLocation,
|
||||||
|
ty::{
|
||||||
|
CanonicalType, OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, StaticType, Type,
|
||||||
|
TypeProperties, impl_match_variant_as_self,
|
||||||
|
},
|
||||||
util::{
|
util::{
|
||||||
ConstUsize,
|
ConstUsize,
|
||||||
alternating_cell::{AlternatingCell, AlternatingCellMethods},
|
alternating_cell::{AlternatingCell, AlternatingCellMethods},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bitvec::{slice::BitSlice, vec::BitVec};
|
use bitvec::{slice::BitSlice, vec::BitVec};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use hashbrown::{HashMap, hash_map::Entry};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
borrow::Cow,
|
||||||
|
fmt::{self, Write},
|
||||||
|
hash::{BuildHasher, Hash, Hasher, RandomState},
|
||||||
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::Arc,
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) mod sim_only_value_unsafe;
|
||||||
|
|
||||||
|
pub use sim_only_value_unsafe::{
|
||||||
|
DynSimOnlyValue, DynSimOnlyValueType, SimOnlyValue, SimOnlyValueTrait, SimOnlyValueType,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
enum ValidFlags {
|
enum ValidFlags {
|
||||||
BothValid = 0,
|
BothValid = 0,
|
||||||
OnlyValueValid = 1,
|
OnlyValueValid = 1,
|
||||||
OnlyBitsValid = 2,
|
OnlyOpaqueValid = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct SimValueInner<T: Type> {
|
struct SimValueInner<T: Type> {
|
||||||
value: T::SimValue,
|
value: T::SimValue,
|
||||||
bits: UIntValue,
|
opaque: OpaqueSimValue,
|
||||||
valid_flags: ValidFlags,
|
valid_flags: ValidFlags,
|
||||||
ty: T,
|
ty: T,
|
||||||
|
sim_only_values_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> SimValueInner<T> {
|
impl<T: Type> SimValueInner<T> {
|
||||||
fn fill_bits(&mut self) {
|
fn fill_opaque(&mut self) {
|
||||||
match self.valid_flags {
|
match self.valid_flags {
|
||||||
ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {}
|
ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {}
|
||||||
ValidFlags::OnlyValueValid => {
|
ValidFlags::OnlyValueValid => {
|
||||||
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut());
|
OpaqueSimValueWriter::rewrite_with(
|
||||||
|
self.sim_only_values_len,
|
||||||
|
&mut self.opaque,
|
||||||
|
|writer| self.ty.sim_value_to_opaque(&self.value, writer),
|
||||||
|
);
|
||||||
self.valid_flags = ValidFlags::BothValid;
|
self.valid_flags = ValidFlags::BothValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn into_bits(mut self) -> UIntValue {
|
fn into_opaque(mut self) -> OpaqueSimValue {
|
||||||
self.fill_bits();
|
self.fill_opaque();
|
||||||
self.bits
|
self.opaque
|
||||||
}
|
}
|
||||||
fn bits_mut(&mut self) -> &mut UIntValue {
|
fn opaque_mut(&mut self) -> &mut OpaqueSimValue {
|
||||||
self.fill_bits();
|
self.fill_opaque();
|
||||||
self.valid_flags = ValidFlags::OnlyBitsValid;
|
self.valid_flags = ValidFlags::OnlyOpaqueValid;
|
||||||
&mut self.bits
|
&mut self.opaque
|
||||||
}
|
}
|
||||||
fn fill_value(&mut self) {
|
fn fill_value(&mut self) {
|
||||||
match self.valid_flags {
|
match self.valid_flags {
|
||||||
ValidFlags::BothValid | ValidFlags::OnlyValueValid => {}
|
ValidFlags::BothValid | ValidFlags::OnlyValueValid => {}
|
||||||
ValidFlags::OnlyBitsValid => {
|
ValidFlags::OnlyOpaqueValid => {
|
||||||
self.ty
|
self.ty
|
||||||
.sim_value_clone_from_bits(&mut self.value, self.bits.bits());
|
.sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice());
|
||||||
self.valid_flags = ValidFlags::BothValid;
|
self.valid_flags = ValidFlags::BothValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,12 +102,14 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> {
|
||||||
fn unique_to_shared(&mut self) {
|
fn unique_to_shared(&mut self) {
|
||||||
match self.valid_flags {
|
match self.valid_flags {
|
||||||
ValidFlags::BothValid => return,
|
ValidFlags::BothValid => return,
|
||||||
ValidFlags::OnlyValueValid => {
|
ValidFlags::OnlyValueValid => OpaqueSimValueWriter::rewrite_with(
|
||||||
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut())
|
self.sim_only_values_len,
|
||||||
}
|
&mut self.opaque,
|
||||||
ValidFlags::OnlyBitsValid => self
|
|writer| self.ty.sim_value_to_opaque(&self.value, writer),
|
||||||
|
),
|
||||||
|
ValidFlags::OnlyOpaqueValid => self
|
||||||
.ty
|
.ty
|
||||||
.sim_value_clone_from_bits(&mut self.value, self.bits.bits()),
|
.sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()),
|
||||||
}
|
}
|
||||||
self.valid_flags = ValidFlags::BothValid;
|
self.valid_flags = ValidFlags::BothValid;
|
||||||
}
|
}
|
||||||
|
@ -143,13 +165,15 @@ impl<T: Type + Clone> Clone for SimValue<T> {
|
||||||
|
|
||||||
impl<T: Type> SimValue<T> {
|
impl<T: Type> SimValue<T> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn from_bits(ty: T, bits: UIntValue) -> Self {
|
pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self {
|
||||||
assert_eq!(ty.canonical().bit_width(), bits.width());
|
let type_properties = ty.canonical().type_properties();
|
||||||
|
type_properties.assert_matching_opaque_sim_value(opaque.as_slice());
|
||||||
let inner = SimValueInner {
|
let inner = SimValueInner {
|
||||||
value: ty.sim_value_from_bits(bits.bits()),
|
value: ty.sim_value_from_opaque(opaque.as_slice()),
|
||||||
bits,
|
opaque,
|
||||||
valid_flags: ValidFlags::BothValid,
|
valid_flags: ValidFlags::BothValid,
|
||||||
ty,
|
ty,
|
||||||
|
sim_only_values_len: type_properties.sim_only_values_len,
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
inner: AlternatingCell::new_shared(inner),
|
inner: AlternatingCell::new_shared(inner),
|
||||||
|
@ -157,14 +181,30 @@ impl<T: Type> SimValue<T> {
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self {
|
pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self {
|
||||||
Self::from_bits(ty, UIntValue::new(Arc::new(bits.to_bitvec())))
|
Self::from_bitslice_and_sim_only_values(ty, bits, Vec::new())
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub fn from_bitslice_and_sim_only_values(
|
||||||
|
ty: T,
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: Vec<DynSimOnlyValue>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_opaque(
|
||||||
|
ty,
|
||||||
|
OpaqueSimValue::from_bitslice_and_sim_only_values(bits, sim_only_values),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
pub fn from_value(ty: T, value: T::SimValue) -> Self {
|
pub fn from_value(ty: T, value: T::SimValue) -> Self {
|
||||||
|
let type_properties = ty.canonical().type_properties();
|
||||||
let inner = SimValueInner {
|
let inner = SimValueInner {
|
||||||
bits: UIntValue::new_dyn(Arc::new(BitVec::repeat(false, ty.canonical().bit_width()))),
|
opaque: OpaqueSimValue::from_bits_and_sim_only_values(
|
||||||
|
UIntValue::new_dyn(Arc::new(BitVec::repeat(false, type_properties.bit_width))),
|
||||||
|
Vec::with_capacity(type_properties.sim_only_values_len),
|
||||||
|
),
|
||||||
value,
|
value,
|
||||||
valid_flags: ValidFlags::OnlyValueValid,
|
valid_flags: ValidFlags::OnlyValueValid,
|
||||||
ty,
|
ty,
|
||||||
|
sim_only_values_len: type_properties.sim_only_values_len,
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
inner: AlternatingCell::new_unique(inner),
|
inner: AlternatingCell::new_unique(inner),
|
||||||
|
@ -173,18 +213,24 @@ impl<T: Type> SimValue<T> {
|
||||||
pub fn ty(this: &Self) -> T {
|
pub fn ty(this: &Self) -> T {
|
||||||
this.inner.share().ty
|
this.inner.share().ty
|
||||||
}
|
}
|
||||||
pub fn into_bits(this: Self) -> UIntValue {
|
pub fn into_opaque(this: Self) -> OpaqueSimValue {
|
||||||
this.inner.into_inner().into_bits()
|
this.inner.into_inner().into_opaque()
|
||||||
}
|
}
|
||||||
pub fn into_ty_and_bits(this: Self) -> (T, UIntValue) {
|
pub fn into_ty_and_opaque(this: Self) -> (T, OpaqueSimValue) {
|
||||||
let inner = this.inner.into_inner();
|
let inner = this.inner.into_inner();
|
||||||
(inner.ty, inner.into_bits())
|
(inner.ty, inner.into_opaque())
|
||||||
|
}
|
||||||
|
pub fn opaque(this: &Self) -> &OpaqueSimValue {
|
||||||
|
&this.inner.share().opaque
|
||||||
|
}
|
||||||
|
pub fn opaque_mut(this: &mut Self) -> &mut OpaqueSimValue {
|
||||||
|
&mut this.inner.unique().opaque
|
||||||
}
|
}
|
||||||
pub fn bits(this: &Self) -> &UIntValue {
|
pub fn bits(this: &Self) -> &UIntValue {
|
||||||
&this.inner.share().bits
|
Self::opaque(this).bits()
|
||||||
}
|
}
|
||||||
pub fn bits_mut(this: &mut Self) -> &mut UIntValue {
|
pub fn bits_mut(this: &mut Self) -> &mut UIntValue {
|
||||||
this.inner.unique().bits_mut()
|
Self::opaque_mut(this).bits_mut()
|
||||||
}
|
}
|
||||||
pub fn into_value(this: Self) -> T::SimValue {
|
pub fn into_value(this: Self) -> T::SimValue {
|
||||||
this.inner.into_inner().into_value()
|
this.inner.into_inner().into_value()
|
||||||
|
@ -197,59 +243,59 @@ impl<T: Type> SimValue<T> {
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn from_canonical(v: SimValue<CanonicalType>) -> Self {
|
pub fn from_canonical(v: SimValue<CanonicalType>) -> Self {
|
||||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||||
Self::from_bits(T::from_canonical(ty), bits)
|
Self::from_opaque(T::from_canonical(ty), opaque)
|
||||||
}
|
}
|
||||||
pub fn into_canonical(this: Self) -> SimValue<CanonicalType> {
|
pub fn into_canonical(this: Self) -> SimValue<CanonicalType> {
|
||||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||||
SimValue::from_bits(ty.canonical(), bits)
|
SimValue::from_opaque(ty.canonical(), opaque)
|
||||||
}
|
}
|
||||||
pub fn canonical(this: &Self) -> SimValue<CanonicalType> {
|
pub fn canonical(this: &Self) -> SimValue<CanonicalType> {
|
||||||
SimValue::from_bits(Self::ty(this).canonical(), Self::bits(this).clone())
|
SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone())
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
|
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
|
||||||
where
|
where
|
||||||
T: IntType,
|
T: IntType,
|
||||||
{
|
{
|
||||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||||
SimValue::from_bits(T::from_dyn_int(ty), bits)
|
SimValue::from_opaque(T::from_dyn_int(ty), opaque)
|
||||||
}
|
}
|
||||||
pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn>
|
pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn>
|
||||||
where
|
where
|
||||||
T: IntType,
|
T: IntType,
|
||||||
{
|
{
|
||||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||||
SimValue::from_bits(ty.as_dyn_int(), bits)
|
SimValue::from_opaque(ty.as_dyn_int(), opaque)
|
||||||
}
|
}
|
||||||
pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn>
|
pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn>
|
||||||
where
|
where
|
||||||
T: IntType,
|
T: IntType,
|
||||||
{
|
{
|
||||||
SimValue::from_bits(Self::ty(this).as_dyn_int(), Self::bits(&this).clone())
|
SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone())
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn from_bundle(v: SimValue<Bundle>) -> Self
|
pub fn from_bundle(v: SimValue<Bundle>) -> Self
|
||||||
where
|
where
|
||||||
T: BundleType,
|
T: BundleType,
|
||||||
{
|
{
|
||||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||||
SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits)
|
SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque)
|
||||||
}
|
}
|
||||||
pub fn into_bundle(this: Self) -> SimValue<Bundle>
|
pub fn into_bundle(this: Self) -> SimValue<Bundle>
|
||||||
where
|
where
|
||||||
T: BundleType,
|
T: BundleType,
|
||||||
{
|
{
|
||||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||||
SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits)
|
SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque)
|
||||||
}
|
}
|
||||||
pub fn to_bundle(this: &Self) -> SimValue<Bundle>
|
pub fn to_bundle(this: &Self) -> SimValue<Bundle>
|
||||||
where
|
where
|
||||||
T: BundleType,
|
T: BundleType,
|
||||||
{
|
{
|
||||||
SimValue::from_bits(
|
SimValue::from_opaque(
|
||||||
Bundle::from_canonical(Self::ty(this).canonical()),
|
Bundle::from_canonical(Self::ty(this).canonical()),
|
||||||
Self::bits(&this).clone(),
|
Self::opaque(&this).clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -257,23 +303,23 @@ impl<T: Type> SimValue<T> {
|
||||||
where
|
where
|
||||||
T: EnumType,
|
T: EnumType,
|
||||||
{
|
{
|
||||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||||
SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits)
|
SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque)
|
||||||
}
|
}
|
||||||
pub fn into_enum(this: Self) -> SimValue<Enum>
|
pub fn into_enum(this: Self) -> SimValue<Enum>
|
||||||
where
|
where
|
||||||
T: EnumType,
|
T: EnumType,
|
||||||
{
|
{
|
||||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||||
SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits)
|
SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque)
|
||||||
}
|
}
|
||||||
pub fn to_enum(this: &Self) -> SimValue<Enum>
|
pub fn to_enum(this: &Self) -> SimValue<Enum>
|
||||||
where
|
where
|
||||||
T: EnumType,
|
T: EnumType,
|
||||||
{
|
{
|
||||||
SimValue::from_bits(
|
SimValue::from_opaque(
|
||||||
Enum::from_canonical(Self::ty(this).canonical()),
|
Enum::from_canonical(Self::ty(this).canonical()),
|
||||||
Self::bits(&this).clone(),
|
Self::opaque(&this).clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,7 +354,11 @@ impl<T: Type> ToExpr for SimValue<T> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn to_expr(&self) -> Expr<Self::Type> {
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
let inner = self.inner.share();
|
let inner = self.inner.share();
|
||||||
inner.bits.cast_bits_to(inner.ty)
|
assert!(
|
||||||
|
inner.sim_only_value_types.is_empty(),
|
||||||
|
"can't convert sim-only values to Expr"
|
||||||
|
);
|
||||||
|
inner.opaque.bits().cast_bits_to(inner.ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,12 +493,15 @@ impl<T: Type> ToSimValueWithType<T> for BitVec {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> {
|
fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> {
|
||||||
SimValue::from_bits(ty, UIntValue::new_dyn(self))
|
SimValue::from_opaque(ty, OpaqueSimValue::from_bits(UIntValue::new_dyn(self)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> {
|
fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> {
|
||||||
SimValue::from_bits(ty, UIntValue::new_dyn(self.clone()))
|
SimValue::from_opaque(
|
||||||
|
ty,
|
||||||
|
OpaqueSimValue::from_bits(UIntValue::new_dyn(self.clone())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,16 +845,18 @@ impl ToSimValueWithType<CanonicalType> for bool {
|
||||||
| CanonicalType::Array(_)
|
| CanonicalType::Array(_)
|
||||||
| CanonicalType::Enum(_)
|
| CanonicalType::Enum(_)
|
||||||
| CanonicalType::Bundle(_)
|
| CanonicalType::Bundle(_)
|
||||||
| CanonicalType::PhantomConst(_) => {
|
| CanonicalType::PhantomConst(_)
|
||||||
|
| CanonicalType::DynSimOnlyValueType(_) => {
|
||||||
panic!("can't create SimValue from bool: expected value of type: {ty:?}");
|
panic!("can't create SimValue from bool: expected value of type: {ty:?}");
|
||||||
}
|
}
|
||||||
CanonicalType::Bool(_)
|
CanonicalType::Bool(_)
|
||||||
| CanonicalType::AsyncReset(_)
|
| CanonicalType::AsyncReset(_)
|
||||||
| CanonicalType::SyncReset(_)
|
| CanonicalType::SyncReset(_)
|
||||||
| CanonicalType::Reset(_)
|
| CanonicalType::Reset(_)
|
||||||
| CanonicalType::Clock(_) => {
|
| CanonicalType::Clock(_) => SimValue::from_opaque(
|
||||||
SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1))))
|
ty,
|
||||||
}
|
OpaqueSimValue::from_bits(UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,3 +966,445 @@ macro_rules! impl_to_sim_value_for_int_value {
|
||||||
|
|
||||||
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
|
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
|
||||||
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
|
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DynSimOnlyValueTypeSerdeTableRest {
|
||||||
|
from_serde: HashMap<DynSimOnlyValueTypeSerdeId, DynSimOnlyValueType>,
|
||||||
|
serde_id_random_state: RandomState,
|
||||||
|
buffer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSimOnlyValueTypeSerdeTableRest {
|
||||||
|
#[cold]
|
||||||
|
fn add_new(&mut self, ty: DynSimOnlyValueType) -> DynSimOnlyValueTypeSerdeId {
|
||||||
|
let mut try_number = 0u64;
|
||||||
|
let mut hasher = self.serde_id_random_state.build_hasher();
|
||||||
|
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
|
||||||
|
write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail");
|
||||||
|
self.buffer.hash(&mut hasher);
|
||||||
|
loop {
|
||||||
|
let mut hasher = hasher.clone();
|
||||||
|
try_number.hash(&mut hasher);
|
||||||
|
try_number += 1;
|
||||||
|
let retval = DynSimOnlyValueTypeSerdeId(std::array::from_fn(|i| {
|
||||||
|
let mut hasher = hasher.clone();
|
||||||
|
i.hash(&mut hasher);
|
||||||
|
hasher.finish() as u32
|
||||||
|
}));
|
||||||
|
match self.from_serde.entry(retval) {
|
||||||
|
Entry::Occupied(_) => continue,
|
||||||
|
Entry::Vacant(e) => {
|
||||||
|
e.insert(ty);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DynSimOnlyValueTypeSerdeTable {
|
||||||
|
to_serde: HashMap<DynSimOnlyValueType, DynSimOnlyValueTypeSerdeId>,
|
||||||
|
rest: DynSimOnlyValueTypeSerdeTableRest,
|
||||||
|
}
|
||||||
|
|
||||||
|
static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex<Option<DynSimOnlyValueTypeSerdeTable>> =
|
||||||
|
Mutex::new(None);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
struct DynSimOnlyValueTypeSerdeId([u32; 4]);
|
||||||
|
|
||||||
|
impl From<DynSimOnlyValueType> for DynSimOnlyValueTypeSerdeId {
|
||||||
|
fn from(ty: DynSimOnlyValueType) -> Self {
|
||||||
|
let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
|
||||||
|
.lock()
|
||||||
|
.expect("shouldn't be poison");
|
||||||
|
let DynSimOnlyValueTypeSerdeTable { to_serde, rest } = locked.get_or_insert_default();
|
||||||
|
match to_serde.entry(ty) {
|
||||||
|
Entry::Occupied(occupied_entry) => *occupied_entry.get(),
|
||||||
|
Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSimOnlyValueTypeSerdeId {
|
||||||
|
fn ty(self) -> Option<DynSimOnlyValueType> {
|
||||||
|
let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
|
||||||
|
.lock()
|
||||||
|
.expect("shouldn't be poison");
|
||||||
|
Some(*locked.as_ref()?.rest.from_serde.get(&self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
|
struct DynSimOnlyValueTypeSerde<'a> {
|
||||||
|
random_id: DynSimOnlyValueTypeSerdeId,
|
||||||
|
#[serde(borrow)]
|
||||||
|
type_name: Cow<'a, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for DynSimOnlyValueType {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
DynSimOnlyValueTypeSerde {
|
||||||
|
random_id: (*self).into(),
|
||||||
|
type_name: Cow::Borrowed(self.type_name()),
|
||||||
|
}
|
||||||
|
.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for DynSimOnlyValueType {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let deserialized = DynSimOnlyValueTypeSerde::deserialize(deserializer)?;
|
||||||
|
let retval = deserialized
|
||||||
|
.random_id
|
||||||
|
.ty()
|
||||||
|
.filter(|ty| ty.type_name() == deserialized.type_name);
|
||||||
|
retval.ok_or_else(|| D::Error::custom("doesn't match any DynSimOnlyValueType that was serialized this time this program was run"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSimOnlyValueType {
|
||||||
|
pub const fn type_properties(self) -> TypeProperties {
|
||||||
|
TypeProperties {
|
||||||
|
is_passive: true,
|
||||||
|
is_storable: true,
|
||||||
|
is_castable_from_bits: false,
|
||||||
|
bit_width: 0,
|
||||||
|
sim_only_values_len: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type for DynSimOnlyValueType {
|
||||||
|
type BaseType = DynSimOnlyValueType;
|
||||||
|
type MaskType = Bool;
|
||||||
|
type SimValue = DynSimOnlyValue;
|
||||||
|
|
||||||
|
impl_match_variant_as_self!();
|
||||||
|
|
||||||
|
fn mask_type(&self) -> Self::MaskType {
|
||||||
|
Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonical(&self) -> CanonicalType {
|
||||||
|
CanonicalType::DynSimOnlyValueType(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
||||||
|
let CanonicalType::DynSimOnlyValueType(v) = canonical_type else {
|
||||||
|
panic!("expected DynSimOnlyValueType");
|
||||||
|
};
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_location() -> SourceLocation {
|
||||||
|
SourceLocation::builtin()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
||||||
|
self.type_properties()
|
||||||
|
.assert_matching_opaque_sim_value(opaque);
|
||||||
|
opaque.sim_only_values()[0].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_clone_from_opaque(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
opaque: OpaqueSimValueSlice<'_>,
|
||||||
|
) {
|
||||||
|
self.type_properties()
|
||||||
|
.assert_matching_opaque_sim_value(opaque);
|
||||||
|
value.clone_from(&opaque.sim_only_values()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_to_opaque<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
writer: OpaqueSimValueWriter<'w>,
|
||||||
|
) -> crate::ty::OpaqueSimValueWritten<'w> {
|
||||||
|
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts(
|
||||||
|
BitSlice::empty(),
|
||||||
|
std::array::from_ref(value),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> Type for SimOnlyValueType<T> {
|
||||||
|
type BaseType = DynSimOnlyValueType;
|
||||||
|
type MaskType = Bool;
|
||||||
|
type SimValue = SimOnlyValue<T>;
|
||||||
|
|
||||||
|
impl_match_variant_as_self!();
|
||||||
|
|
||||||
|
fn mask_type(&self) -> Self::MaskType {
|
||||||
|
Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonical(&self) -> CanonicalType {
|
||||||
|
DynSimOnlyValueType::from(*self).canonical()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
||||||
|
DynSimOnlyValueType::from_canonical(canonical_type)
|
||||||
|
.downcast()
|
||||||
|
.expect("got wrong SimOnlyValueType")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_location() -> SourceLocation {
|
||||||
|
SourceLocation::builtin()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
||||||
|
DynSimOnlyValueType::from(*self)
|
||||||
|
.type_properties()
|
||||||
|
.assert_matching_opaque_sim_value(opaque);
|
||||||
|
SimOnlyValue::new(
|
||||||
|
opaque.sim_only_values()[0]
|
||||||
|
.downcast_ref::<T>()
|
||||||
|
.expect("type mismatch")
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_clone_from_opaque(
|
||||||
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
opaque: OpaqueSimValueSlice<'_>,
|
||||||
|
) {
|
||||||
|
DynSimOnlyValueType::from(*self)
|
||||||
|
.type_properties()
|
||||||
|
.assert_matching_opaque_sim_value(opaque);
|
||||||
|
(**value).clone_from(
|
||||||
|
&opaque.sim_only_values()[0]
|
||||||
|
.downcast_ref::<T>()
|
||||||
|
.expect("already checked type"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_to_opaque<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
writer: OpaqueSimValueWriter<'w>,
|
||||||
|
) -> crate::ty::OpaqueSimValueWritten<'w> {
|
||||||
|
SimOnlyValue::with_dyn_ref(value, |value| {
|
||||||
|
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts(
|
||||||
|
BitSlice::empty(),
|
||||||
|
std::array::from_ref(value),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> fmt::Debug for SimOnlyValue<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
Self::with_dyn_ref(self, |this| fmt::Debug::fmt(this, f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename = "SimOnlyValue")]
|
||||||
|
struct SerdeSimOnlyValue<'a> {
|
||||||
|
ty: DynSimOnlyValueType,
|
||||||
|
#[serde(borrow)]
|
||||||
|
value: Cow<'a, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for DynSimOnlyValue {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
SerdeSimOnlyValue {
|
||||||
|
ty: self.ty(),
|
||||||
|
value: Cow::Owned(self.serialize_to_json_string().map_err(S::Error::custom)?),
|
||||||
|
}
|
||||||
|
.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for DynSimOnlyValue {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let SerdeSimOnlyValue { ty, value } = Deserialize::deserialize(deserializer)?;
|
||||||
|
ty.deserialize_from_json_string(&value)
|
||||||
|
.map_err(D::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSimValueWithType<DynSimOnlyValueType> for DynSimOnlyValue {
|
||||||
|
#[track_caller]
|
||||||
|
fn to_sim_value_with_type(&self, ty: DynSimOnlyValueType) -> SimValue<DynSimOnlyValueType> {
|
||||||
|
assert_eq!(self.ty(), ty, "mismatched type");
|
||||||
|
SimValue::from_value(ty, self.clone())
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
fn into_sim_value_with_type(self, ty: DynSimOnlyValueType) -> SimValue<DynSimOnlyValueType> {
|
||||||
|
assert_eq!(self.ty(), ty, "mismatched type");
|
||||||
|
SimValue::from_value(ty, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> ToSimValueWithType<SimOnlyValueType<T>> for SimOnlyValue<T> {
|
||||||
|
fn to_sim_value_with_type(&self, ty: SimOnlyValueType<T>) -> SimValue<SimOnlyValueType<T>> {
|
||||||
|
SimValue::from_value(ty, self.clone())
|
||||||
|
}
|
||||||
|
fn into_sim_value_with_type(self, ty: SimOnlyValueType<T>) -> SimValue<SimOnlyValueType<T>> {
|
||||||
|
SimValue::from_value(ty, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSimValue for DynSimOnlyValue {
|
||||||
|
type Type = DynSimOnlyValueType;
|
||||||
|
|
||||||
|
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: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
||||||
|
type Type = SimOnlyValueType<T>;
|
||||||
|
|
||||||
|
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||||
|
SimValue::from_value(Default::default(), self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_sim_value(self) -> SimValue<Self::Type> {
|
||||||
|
SimValue::from_value(Default::default(), self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DynSimOnlyValuesWriter<'a> {
|
||||||
|
types: &'static [DynSimOnlyValueType],
|
||||||
|
values: &'a mut Vec<DynSimOnlyValue>,
|
||||||
|
values_offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DynSimOnlyValuesWritten<'a> {
|
||||||
|
_phantom: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DynSimOnlyValuesWriter<'a> {
|
||||||
|
pub fn rewrite_with<F>(
|
||||||
|
types: Interned<[DynSimOnlyValueType]>,
|
||||||
|
values: &mut Vec<DynSimOnlyValue>,
|
||||||
|
f: F,
|
||||||
|
) where
|
||||||
|
F: for<'b> FnOnce(DynSimOnlyValuesWriter<'b>) -> DynSimOnlyValuesWritten<'b>, // 'b is used as a brand
|
||||||
|
{
|
||||||
|
Self::rewrite_with_static(Interned::into_inner(types), values, f);
|
||||||
|
}
|
||||||
|
pub fn rewrite_with_static<F>(
|
||||||
|
types: &'static [DynSimOnlyValueType],
|
||||||
|
values: &mut Vec<DynSimOnlyValue>,
|
||||||
|
f: F,
|
||||||
|
) where
|
||||||
|
F: for<'b> FnOnce(DynSimOnlyValuesWriter<'b>) -> DynSimOnlyValuesWritten<'b>, // 'b is used as a brand
|
||||||
|
{
|
||||||
|
let DynSimOnlyValuesWritten {
|
||||||
|
_phantom: PhantomData,
|
||||||
|
} = f(DynSimOnlyValuesWriter::rewrite_helper(types, values));
|
||||||
|
}
|
||||||
|
pub(crate) fn rewrite_helper(
|
||||||
|
types: &'static [DynSimOnlyValueType],
|
||||||
|
values: &'a mut Vec<DynSimOnlyValue>,
|
||||||
|
) -> Self {
|
||||||
|
assert!(values.len() <= types.len(), "too many values");
|
||||||
|
values.reserve_exact(types.len() - values.len());
|
||||||
|
Self {
|
||||||
|
types,
|
||||||
|
values,
|
||||||
|
values_offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn types(&self) -> &'static [DynSimOnlyValueType] {
|
||||||
|
self.types
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.types.len()
|
||||||
|
}
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.types.is_empty()
|
||||||
|
}
|
||||||
|
pub fn fill_cloned_from_slice(self, values: &[DynSimOnlyValue]) -> DynSimOnlyValuesWritten<'a> {
|
||||||
|
assert_matching_sim_only_values(self.types, values);
|
||||||
|
let (clone_from_src, clone_src) =
|
||||||
|
values.split_at((self.values.len() - self.values_offset).min(values.len()));
|
||||||
|
self.values[self.values_offset..][..clone_from_src.len()].clone_from_slice(clone_from_src);
|
||||||
|
self.values.extend_from_slice(clone_src);
|
||||||
|
DynSimOnlyValuesWritten {
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn fill_prefix_with<F>(&mut self, prefix_len: usize, f: F)
|
||||||
|
where
|
||||||
|
F: for<'b> FnOnce(DynSimOnlyValuesWriter<'b>) -> DynSimOnlyValuesWritten<'b>, // 'b is used as a brand
|
||||||
|
{
|
||||||
|
let DynSimOnlyValuesWritten {
|
||||||
|
_phantom: PhantomData,
|
||||||
|
} = f(self.fill_prefix_setup(prefix_len));
|
||||||
|
self.fill_prefix_finish(prefix_len);
|
||||||
|
}
|
||||||
|
/// the first part of [`fill_prefix_with`]
|
||||||
|
pub(crate) fn fill_prefix_setup<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
prefix_len: usize,
|
||||||
|
) -> DynSimOnlyValuesWriter<'b> {
|
||||||
|
let prefix_types = &self.types[..prefix_len];
|
||||||
|
DynSimOnlyValuesWriter::<'b> {
|
||||||
|
types: prefix_types,
|
||||||
|
values: self.values,
|
||||||
|
values_offset: self.values_offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// the last part of [`fill_prefix_with`]
|
||||||
|
pub(crate) fn fill_prefix_finish(&mut self, prefix_len: usize) {
|
||||||
|
assert!(self.values.len() >= self.values_offset + prefix_len);
|
||||||
|
self.values_offset += prefix_len;
|
||||||
|
self.types = &self.types[prefix_len..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn assert_matching_sim_values(
|
||||||
|
bit_width: usize,
|
||||||
|
sim_only_value_types: &[DynSimOnlyValueType],
|
||||||
|
bits: &BitSlice,
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
|
assert_matching_sim_only_values(sim_only_value_types, sim_only_values);
|
||||||
|
assert_eq!(bit_width, bits.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn assert_matching_sim_only_values(
|
||||||
|
sim_only_value_types: &[DynSimOnlyValueType],
|
||||||
|
sim_only_values: &[DynSimOnlyValue],
|
||||||
|
) {
|
||||||
|
assert!(
|
||||||
|
sim_only_value_types
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.eq(sim_only_values.iter().map(DynSimOnlyValue::ty)),
|
||||||
|
"sim-only values don't match expected types: {:?} != {:?}",
|
||||||
|
sim_only_value_types,
|
||||||
|
Vec::from_iter(sim_only_values.iter().map(DynSimOnlyValue::ty)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
351
crates/fayalite/src/sim/value/sim_only_value_unsafe.rs
Normal file
351
crates/fayalite/src/sim/value/sim_only_value_unsafe.rs
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
//! `unsafe` parts of [`DynSimOnlyValue`]
|
||||||
|
|
||||||
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
|
use std::{
|
||||||
|
alloc::{Layout, alloc, dealloc, handle_alloc_error},
|
||||||
|
any::TypeId,
|
||||||
|
fmt,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
marker::PhantomData,
|
||||||
|
mem::ManuallyDrop,
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SimOnlyValueVTable {
|
||||||
|
layout: Layout,
|
||||||
|
// TODO: replace with TypeId once TypeId::of is const-stable
|
||||||
|
type_id: fn() -> TypeId,
|
||||||
|
type_name: fn() -> &'static str,
|
||||||
|
drop_in_place: unsafe fn(this: NonNull<()>),
|
||||||
|
eq: unsafe fn(this: NonNull<()>, other: NonNull<()>) -> bool,
|
||||||
|
hash: unsafe fn(this: NonNull<()>, hasher: &mut dyn Hasher),
|
||||||
|
debug_fmt: unsafe fn(this: NonNull<()>, f: &mut fmt::Formatter<'_>) -> fmt::Result,
|
||||||
|
serialize_to_json_string: unsafe fn(this: NonNull<()>) -> serde_json::Result<String>,
|
||||||
|
deserialize_into_uninit_from_json_string:
|
||||||
|
unsafe fn(this: NonNull<()>, json_str: &str) -> serde_json::Result<()>,
|
||||||
|
clone_into_uninit: unsafe fn(target: NonNull<()>, src: NonNull<()>),
|
||||||
|
clone_from: unsafe fn(this: NonNull<()>, src: NonNull<()>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SimOnlyValueTrait:
|
||||||
|
'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone> SimOnlyValueTrait
|
||||||
|
for T
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe trait GetSimOnlyValueVTable: SimOnlyValueTrait {
|
||||||
|
const VTABLE: &'static SimOnlyValueVTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: SimOnlyValueTrait> GetSimOnlyValueVTable for T {
|
||||||
|
const VTABLE: &'static SimOnlyValueVTable = &SimOnlyValueVTable {
|
||||||
|
layout: Layout::new::<T>(),
|
||||||
|
type_id: TypeId::of::<T>,
|
||||||
|
type_name: std::any::type_name::<T>,
|
||||||
|
drop_in_place: |this| unsafe {
|
||||||
|
this.cast::<T>().drop_in_place();
|
||||||
|
},
|
||||||
|
eq: |this, other| unsafe { this.cast::<T>().as_ref() == other.cast::<T>().as_ref() },
|
||||||
|
hash: |this, mut hasher| unsafe { this.cast::<T>().as_ref().hash(&mut hasher) },
|
||||||
|
debug_fmt: |this, f| unsafe { fmt::Debug::fmt(this.cast::<T>().as_ref(), f) },
|
||||||
|
serialize_to_json_string: |this| unsafe {
|
||||||
|
serde_json::to_string(this.cast::<T>().as_ref())
|
||||||
|
},
|
||||||
|
deserialize_into_uninit_from_json_string: |this, json_str| unsafe {
|
||||||
|
serde_json::from_str(json_str).map(|v| this.cast::<T>().write(v))
|
||||||
|
},
|
||||||
|
clone_into_uninit: |target, src| unsafe {
|
||||||
|
target
|
||||||
|
.cast::<T>()
|
||||||
|
.write(Clone::clone(src.cast::<T>().as_ref()));
|
||||||
|
},
|
||||||
|
clone_from: |this, src| unsafe {
|
||||||
|
Clone::clone_from(this.cast::<T>().as_mut(), src.cast::<T>().as_ref());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct DynSimOnlyValueType {
|
||||||
|
vtable: &'static SimOnlyValueVTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DynSimOnlyValueUninit {
|
||||||
|
ty: DynSimOnlyValueType,
|
||||||
|
value: NonNull<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSimOnlyValueUninit {
|
||||||
|
fn new(ty: DynSimOnlyValueType) -> Self {
|
||||||
|
let layout = ty.vtable.layout;
|
||||||
|
let value = if layout.size() == 0 {
|
||||||
|
ptr::without_provenance_mut(layout.align())
|
||||||
|
} else {
|
||||||
|
unsafe { alloc(layout).cast() }
|
||||||
|
};
|
||||||
|
let Some(value) = NonNull::new(value) else {
|
||||||
|
handle_alloc_error(layout)
|
||||||
|
};
|
||||||
|
Self { ty, value }
|
||||||
|
}
|
||||||
|
unsafe fn assume_init(self) -> DynSimOnlyValue {
|
||||||
|
let this = ManuallyDrop::new(self);
|
||||||
|
DynSimOnlyValue {
|
||||||
|
ty: this.ty,
|
||||||
|
value: this.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DynSimOnlyValueUninit {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let layout = self.ty.vtable.layout;
|
||||||
|
if layout.size() != 0 {
|
||||||
|
unsafe {
|
||||||
|
dealloc(self.value.as_ptr().cast(), layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSimOnlyValueType {
|
||||||
|
pub const fn of<T: SimOnlyValueTrait>() -> Self {
|
||||||
|
Self {
|
||||||
|
vtable: <T as GetSimOnlyValueVTable>::VTABLE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn type_id(self) -> TypeId {
|
||||||
|
(self.vtable.type_id)()
|
||||||
|
}
|
||||||
|
pub fn type_name(self) -> &'static str {
|
||||||
|
(self.vtable.type_name)()
|
||||||
|
}
|
||||||
|
pub fn is<T: SimOnlyValueTrait>(self) -> bool {
|
||||||
|
self.type_id() == TypeId::of::<T>()
|
||||||
|
}
|
||||||
|
pub fn downcast<T: SimOnlyValueTrait>(self) -> Option<SimOnlyValueType<T>> {
|
||||||
|
self.is::<T>().then_some(SimOnlyValueType::default())
|
||||||
|
}
|
||||||
|
pub fn deserialize_from_json_string(
|
||||||
|
self,
|
||||||
|
json_str: &str,
|
||||||
|
) -> serde_json::Result<DynSimOnlyValue> {
|
||||||
|
let retval = DynSimOnlyValueUninit::new(self);
|
||||||
|
unsafe {
|
||||||
|
(self.vtable.deserialize_into_uninit_from_json_string)(retval.value, json_str)?;
|
||||||
|
Ok(retval.assume_init())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for DynSimOnlyValueType {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
if ptr::eq(self.vtable, other.vtable) {
|
||||||
|
true
|
||||||
|
} else if self.vtable.layout != other.vtable.layout {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
(self.vtable.type_id)() == (other.vtable.type_id)()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for DynSimOnlyValueType {}
|
||||||
|
|
||||||
|
impl Hash for DynSimOnlyValueType {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
(self.vtable.type_id)().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for DynSimOnlyValueType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "SimOnlyValueType<{}>", (self.vtable.type_name)())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> From<SimOnlyValueType<T>> for DynSimOnlyValueType {
|
||||||
|
fn from(value: SimOnlyValueType<T>) -> Self {
|
||||||
|
let SimOnlyValueType(PhantomData) = value;
|
||||||
|
Self {
|
||||||
|
vtable: <T as GetSimOnlyValueVTable>::VTABLE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
|
pub struct SimOnlyValueType<T: SimOnlyValueTrait>(PhantomData<fn(T) -> T>);
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> Copy for SimOnlyValueType<T> {}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> Default for SimOnlyValueType<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)]
|
||||||
|
pub struct SimOnlyValue<T: SimOnlyValueTrait>(Box<T>);
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> SimOnlyValue<T> {
|
||||||
|
pub fn with_dyn_ref<F: FnOnce(&DynSimOnlyValue) -> R, R>(&self, f: F) -> R {
|
||||||
|
let dyn_ref = ManuallyDrop::new(DynSimOnlyValue {
|
||||||
|
ty: SimOnlyValueType::<T>::default().into(),
|
||||||
|
value: NonNull::<T>::from_ref(&self.0).cast(),
|
||||||
|
});
|
||||||
|
f(&dyn_ref)
|
||||||
|
}
|
||||||
|
pub fn from_box(v: Box<T>) -> Self {
|
||||||
|
Self(v)
|
||||||
|
}
|
||||||
|
pub fn new(v: T) -> Self {
|
||||||
|
Self(Box::new(v))
|
||||||
|
}
|
||||||
|
pub fn into_inner(this: Self) -> T {
|
||||||
|
*this.0
|
||||||
|
}
|
||||||
|
pub fn into_inner_box(this: Self) -> Box<T> {
|
||||||
|
this.0
|
||||||
|
}
|
||||||
|
pub fn into_dyn(this: Self) -> DynSimOnlyValue {
|
||||||
|
DynSimOnlyValue::from(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> std::ops::Deref for SimOnlyValue<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> std::ops::DerefMut for SimOnlyValue<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DynSimOnlyValue {
|
||||||
|
ty: DynSimOnlyValueType,
|
||||||
|
value: NonNull<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DebugDynSimOnlyValueInner<'a>(&'a DynSimOnlyValue);
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for DebugDynSimOnlyValueInner<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
unsafe { (self.0.ty.vtable.debug_fmt)(self.0.value, f) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for DynSimOnlyValue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "SimOnlyValue<{}>", self.ty.type_name())?;
|
||||||
|
f.debug_tuple("")
|
||||||
|
.field(&DebugDynSimOnlyValueInner(self))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for DynSimOnlyValue {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ty == other.ty && unsafe { (self.ty.vtable.eq)(self.value, other.value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for DynSimOnlyValue {}
|
||||||
|
|
||||||
|
impl Hash for DynSimOnlyValue {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.ty.hash(state);
|
||||||
|
unsafe { (self.ty.vtable.hash)(self.value, state) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for DynSimOnlyValue {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let retval = DynSimOnlyValueUninit::new(self.ty);
|
||||||
|
unsafe {
|
||||||
|
(self.ty.vtable.clone_into_uninit)(retval.value, self.value);
|
||||||
|
retval.assume_init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn clone_from(&mut self, source: &Self) {
|
||||||
|
if self.ty == source.ty {
|
||||||
|
unsafe { (self.ty.vtable.clone_from)(self.value, source.value) };
|
||||||
|
} else {
|
||||||
|
*self = source.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DynSimOnlyValue {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
ptr::read(self).drop_in_place_and_keep_alloc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue {
|
||||||
|
fn from(value: SimOnlyValue<T>) -> Self {
|
||||||
|
unsafe {
|
||||||
|
Self {
|
||||||
|
ty: SimOnlyValueType::<T>::default().into(),
|
||||||
|
value: NonNull::new_unchecked(Box::into_raw(value.0)).cast::<()>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSimOnlyValue {
|
||||||
|
pub fn ty(&self) -> DynSimOnlyValueType {
|
||||||
|
self.ty
|
||||||
|
}
|
||||||
|
pub fn type_id(&self) -> TypeId {
|
||||||
|
self.ty.type_id()
|
||||||
|
}
|
||||||
|
pub fn is<T: SimOnlyValueTrait>(&self) -> bool {
|
||||||
|
self.ty.is::<T>()
|
||||||
|
}
|
||||||
|
pub fn downcast<T: SimOnlyValueTrait>(self) -> Result<SimOnlyValue<T>, DynSimOnlyValue> {
|
||||||
|
let Some(_) = self.ty.downcast::<T>() else {
|
||||||
|
return Err(self);
|
||||||
|
};
|
||||||
|
Ok(SimOnlyValue(unsafe {
|
||||||
|
Box::from_raw(ManuallyDrop::new(self).value.as_ptr().cast::<T>())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
pub fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
|
||||||
|
self.ty
|
||||||
|
.downcast::<T>()
|
||||||
|
.map(|_| unsafe { &*self.value.as_ptr().cast::<T>() })
|
||||||
|
}
|
||||||
|
pub fn downcast_mut<T: SimOnlyValueTrait>(&mut self) -> Option<&mut T> {
|
||||||
|
self.ty
|
||||||
|
.downcast::<T>()
|
||||||
|
.map(|_| unsafe { &mut *self.value.as_ptr().cast::<T>() })
|
||||||
|
}
|
||||||
|
pub fn serialize_to_json_string(&self) -> serde_json::Result<String> {
|
||||||
|
unsafe { (self.ty.vtable.serialize_to_json_string)(self.value) }
|
||||||
|
}
|
||||||
|
fn forget_and_keep_alloc(self) -> DynSimOnlyValueUninit {
|
||||||
|
let this = ManuallyDrop::new(self);
|
||||||
|
DynSimOnlyValueUninit {
|
||||||
|
ty: this.ty,
|
||||||
|
value: this.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn drop_in_place_and_keep_alloc(self) -> DynSimOnlyValueUninit {
|
||||||
|
let retval = self.forget_and_keep_alloc();
|
||||||
|
unsafe { (retval.ty.vtable.drop_in_place)(retval.value) };
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,16 @@ use crate::{
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
phantom_const::PhantomConst,
|
phantom_const::PhantomConst,
|
||||||
reset::{AsyncReset, Reset, SyncReset},
|
reset::{AsyncReset, Reset, SyncReset},
|
||||||
sim::value::{SimValue, ToSimValueWithType},
|
sim::value::{
|
||||||
|
DynSimOnlyValue, DynSimOnlyValueType, SimValue, ToSimValueWithType,
|
||||||
|
assert_matching_sim_values,
|
||||||
|
},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
util::ConstUsize,
|
util::ConstUsize,
|
||||||
};
|
};
|
||||||
use bitvec::slice::BitSlice;
|
use bitvec::slice::BitSlice;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
|
||||||
use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index, sync::Arc};
|
use std::{fmt, hash::Hash, iter::FusedIterator, marker::PhantomData, mem, ops::Index, sync::Arc};
|
||||||
|
|
||||||
pub(crate) mod serde_impls;
|
pub(crate) mod serde_impls;
|
||||||
|
|
||||||
|
@ -28,6 +31,20 @@ pub struct TypeProperties {
|
||||||
pub is_storable: bool,
|
pub is_storable: bool,
|
||||||
pub is_castable_from_bits: bool,
|
pub is_castable_from_bits: bool,
|
||||||
pub bit_width: usize,
|
pub bit_width: usize,
|
||||||
|
pub sim_only_values_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeProperties {
|
||||||
|
#[track_caller]
|
||||||
|
pub(crate) fn assert_matching_opaque_sim_value(self, opaque: OpaqueSimValueSlice<'_>) {
|
||||||
|
assert_eq!(self.bit_width, opaque.bit_width());
|
||||||
|
assert_eq!(self.sim_only_values_len, opaque.sim_only_values().len());
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub(crate) fn assert_matching_opaque_sim_value_writer(self, writer: &OpaqueSimValueWriter<'_>) {
|
||||||
|
assert_eq!(self.bit_width, writer.bit_width());
|
||||||
|
assert_eq!(self.sim_only_values_len, writer.sim_only_values_len());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
@ -43,6 +60,7 @@ pub enum CanonicalType {
|
||||||
Reset(Reset),
|
Reset(Reset),
|
||||||
Clock(Clock),
|
Clock(Clock),
|
||||||
PhantomConst(PhantomConst),
|
PhantomConst(PhantomConst),
|
||||||
|
DynSimOnlyValueType(DynSimOnlyValueType),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for CanonicalType {
|
impl fmt::Debug for CanonicalType {
|
||||||
|
@ -59,6 +77,7 @@ impl fmt::Debug for CanonicalType {
|
||||||
Self::Reset(v) => v.fmt(f),
|
Self::Reset(v) => v.fmt(f),
|
||||||
Self::Clock(v) => v.fmt(f),
|
Self::Clock(v) => v.fmt(f),
|
||||||
Self::PhantomConst(v) => v.fmt(f),
|
Self::PhantomConst(v) => v.fmt(f),
|
||||||
|
Self::DynSimOnlyValueType(v) => v.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +114,7 @@ impl CanonicalType {
|
||||||
CanonicalType::Reset(v) => v.type_properties(),
|
CanonicalType::Reset(v) => v.type_properties(),
|
||||||
CanonicalType::Clock(v) => v.type_properties(),
|
CanonicalType::Clock(v) => v.type_properties(),
|
||||||
CanonicalType::PhantomConst(v) => v.type_properties(),
|
CanonicalType::PhantomConst(v) => v.type_properties(),
|
||||||
|
CanonicalType::DynSimOnlyValueType(v) => v.type_properties(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_passive(self) -> bool {
|
pub fn is_passive(self) -> bool {
|
||||||
|
@ -177,6 +197,12 @@ impl CanonicalType {
|
||||||
};
|
};
|
||||||
lhs.can_connect(rhs)
|
lhs.can_connect(rhs)
|
||||||
}
|
}
|
||||||
|
CanonicalType::DynSimOnlyValueType(lhs) => {
|
||||||
|
let CanonicalType::DynSimOnlyValueType(rhs) = rhs else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
lhs.can_connect(rhs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn as_serde_unexpected_str(self) -> &'static str {
|
pub(crate) fn as_serde_unexpected_str(self) -> &'static str {
|
||||||
|
@ -287,6 +313,7 @@ impl_base_type!(SyncReset);
|
||||||
impl_base_type!(Reset);
|
impl_base_type!(Reset);
|
||||||
impl_base_type!(Clock);
|
impl_base_type!(Clock);
|
||||||
impl_base_type!(PhantomConst);
|
impl_base_type!(PhantomConst);
|
||||||
|
impl_base_type!(DynSimOnlyValueType);
|
||||||
|
|
||||||
impl_base_type_serde!(Bool, "a Bool");
|
impl_base_type_serde!(Bool, "a Bool");
|
||||||
impl_base_type_serde!(Enum, "an Enum");
|
impl_base_type_serde!(Enum, "an Enum");
|
||||||
|
@ -348,9 +375,17 @@ pub trait Type:
|
||||||
fn canonical(&self) -> CanonicalType;
|
fn canonical(&self) -> CanonicalType;
|
||||||
fn from_canonical(canonical_type: CanonicalType) -> Self;
|
fn from_canonical(canonical_type: CanonicalType) -> Self;
|
||||||
fn source_location() -> SourceLocation;
|
fn source_location() -> SourceLocation;
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue;
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue;
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice);
|
fn sim_value_clone_from_opaque(
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice);
|
&self,
|
||||||
|
value: &mut Self::SimValue,
|
||||||
|
opaque: OpaqueSimValueSlice<'_>,
|
||||||
|
);
|
||||||
|
fn sim_value_to_opaque<'w>(
|
||||||
|
&self,
|
||||||
|
value: &Self::SimValue,
|
||||||
|
writer: OpaqueSimValueWriter<'w>,
|
||||||
|
) -> OpaqueSimValueWritten<'w>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BaseType:
|
pub trait BaseType:
|
||||||
|
@ -405,6 +440,7 @@ impl Type for CanonicalType {
|
||||||
CanonicalType::Reset(v) => v.mask_type().canonical(),
|
CanonicalType::Reset(v) => v.mask_type().canonical(),
|
||||||
CanonicalType::Clock(v) => v.mask_type().canonical(),
|
CanonicalType::Clock(v) => v.mask_type().canonical(),
|
||||||
CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
|
CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
|
||||||
|
CanonicalType::DynSimOnlyValueType(v) => v.mask_type().canonical(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn canonical(&self) -> CanonicalType {
|
fn canonical(&self) -> CanonicalType {
|
||||||
|
@ -416,28 +452,46 @@ impl Type for CanonicalType {
|
||||||
fn source_location() -> SourceLocation {
|
fn source_location() -> SourceLocation {
|
||||||
SourceLocation::builtin()
|
SourceLocation::builtin()
|
||||||
}
|
}
|
||||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
||||||
assert_eq!(bits.len(), self.bit_width());
|
self.type_properties()
|
||||||
OpaqueSimValue::from_bitslice(bits)
|
.assert_matching_opaque_sim_value(opaque);
|
||||||
|
opaque.to_owned()
|
||||||
}
|
}
|
||||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
fn sim_value_clone_from_opaque(
|
||||||
assert_eq!(bits.len(), self.bit_width());
|
&self,
|
||||||
assert_eq!(value.bit_width(), self.bit_width());
|
value: &mut Self::SimValue,
|
||||||
value.bits_mut().bits_mut().copy_from_bitslice(bits);
|
opaque: OpaqueSimValueSlice<'_>,
|
||||||
|
) {
|
||||||
|
self.type_properties()
|
||||||
|
.assert_matching_opaque_sim_value(opaque);
|
||||||
|
value.clone_from_slice(opaque);
|
||||||
}
|
}
|
||||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
fn sim_value_to_opaque<'w>(
|
||||||
assert_eq!(bits.len(), self.bit_width());
|
&self,
|
||||||
assert_eq!(value.bit_width(), self.bit_width());
|
value: &Self::SimValue,
|
||||||
bits.copy_from_bitslice(value.bits().bits());
|
writer: OpaqueSimValueWriter<'w>,
|
||||||
|
) -> OpaqueSimValueWritten<'w> {
|
||||||
|
self.type_properties()
|
||||||
|
.assert_matching_opaque_sim_value_writer(&writer);
|
||||||
|
writer.fill_cloned_from_slice(value.as_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub struct OpaqueSimValue {
|
pub struct OpaqueSimValue {
|
||||||
bits: UIntValue,
|
bits: UIntValue,
|
||||||
|
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||||
|
sim_only_values: Vec<DynSimOnlyValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpaqueSimValue {
|
impl OpaqueSimValue {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
let Self {
|
||||||
|
bits,
|
||||||
|
sim_only_values,
|
||||||
|
} = self;
|
||||||
|
bits.bits().is_empty() && sim_only_values.is_empty()
|
||||||
|
}
|
||||||
pub fn bit_width(&self) -> usize {
|
pub fn bit_width(&self) -> usize {
|
||||||
self.bits.width()
|
self.bits.width()
|
||||||
}
|
}
|
||||||
|
@ -451,13 +505,86 @@ impl OpaqueSimValue {
|
||||||
self.bits
|
self.bits
|
||||||
}
|
}
|
||||||
pub fn from_bits(bits: UIntValue) -> Self {
|
pub fn from_bits(bits: UIntValue) -> Self {
|
||||||
Self { bits }
|
Self {
|
||||||
|
bits,
|
||||||
|
sim_only_values: Vec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn from_bitslice(v: &BitSlice) -> Self {
|
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 {
|
Self {
|
||||||
bits: UIntValue::new(Arc::new(v.to_bitvec())),
|
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<BitsRange, SOVRange>(
|
||||||
|
&self,
|
||||||
|
bits_range: BitsRange,
|
||||||
|
sim_only_values_range: SOVRange,
|
||||||
|
) -> OpaqueSimValueSlice<'_>
|
||||||
|
where
|
||||||
|
BitSlice: Index<BitsRange, Output = BitSlice>,
|
||||||
|
[DynSimOnlyValue]: Index<SOVRange, Output = [DynSimOnlyValue]>,
|
||||||
|
{
|
||||||
|
self.as_slice().slice(bits_range, sim_only_values_range)
|
||||||
|
}
|
||||||
|
pub fn rewrite_with<F>(&mut self, types: Interned<[DynSimOnlyValueType]>, f: F)
|
||||||
|
where
|
||||||
|
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
|
||||||
|
{
|
||||||
|
OpaqueSimValueWriter::rewrite_with(types, self, f);
|
||||||
|
}
|
||||||
|
pub fn rewrite_with_static<F>(&mut self, types: &'static [DynSimOnlyValueType], f: F)
|
||||||
|
where
|
||||||
|
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
|
||||||
|
{
|
||||||
|
OpaqueSimValueWriter::rewrite_with_static(types, self, f);
|
||||||
|
}
|
||||||
|
pub fn clone_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
|
||||||
|
self.bits.bits_mut().clone_from_bitslice(slice.bits());
|
||||||
|
self.sim_only_values
|
||||||
|
.clone_from_slice(slice.sim_only_values());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValue {
|
impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValue {
|
||||||
|
@ -469,6 +596,163 @@ impl<T: Type<SimValue = OpaqueSimValue>> ToSimValueWithType<T> for OpaqueSimValu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 empty() -> Self {
|
||||||
|
Self {
|
||||||
|
bits: BitSlice::empty(),
|
||||||
|
sim_only_values: &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_empty(self) -> bool {
|
||||||
|
let Self {
|
||||||
|
bits,
|
||||||
|
sim_only_values,
|
||||||
|
} = self;
|
||||||
|
bits.is_empty() && sim_only_values.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 to_owned(self) -> OpaqueSimValue {
|
||||||
|
OpaqueSimValue::from_bitslice_and_sim_only_values(self.bits, self.sim_only_values.to_vec())
|
||||||
|
}
|
||||||
|
pub fn slice<BitsRange, SOVRange>(
|
||||||
|
self,
|
||||||
|
bits_range: BitsRange,
|
||||||
|
sim_only_values_range: SOVRange,
|
||||||
|
) -> OpaqueSimValueSlice<'a>
|
||||||
|
where
|
||||||
|
BitSlice: Index<BitsRange, Output = BitSlice>,
|
||||||
|
[DynSimOnlyValue]: Index<SOVRange, Output = [DynSimOnlyValue]>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
bits: &self.bits[bits_range],
|
||||||
|
sim_only_values: &self.sim_only_values[sim_only_values_range],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 rewrite_with<F>(sim_only_values_len: usize, 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(
|
||||||
|
sim_only_values_len,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub(crate) fn rewrite_helper(
|
||||||
|
sim_only_values_len: usize,
|
||||||
|
value: &'a mut OpaqueSimValue,
|
||||||
|
) -> Self {
|
||||||
|
let (bits_mut, sim_only_values) = value.parts_mut();
|
||||||
|
sim_only_values.truncate(sim_only_values_len);
|
||||||
|
sim_only_values.reserve_exact(sim_only_values_len - sim_only_values.len());
|
||||||
|
Self {
|
||||||
|
bits: bits_mut.bits_mut(),
|
||||||
|
sim_only_values,
|
||||||
|
sim_only_values_range: 0..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 {
|
||||||
|
let Self {
|
||||||
|
bits,
|
||||||
|
sim_only_values: _,
|
||||||
|
sim_only_values_range,
|
||||||
|
} = self;
|
||||||
|
bits.is_empty() && sim_only_values_range.is_empty()
|
||||||
|
}
|
||||||
|
pub fn fill_cloned_from_slice(
|
||||||
|
self,
|
||||||
|
slice: OpaqueSimValueSlice<'_>,
|
||||||
|
) -> OpaqueSimValueWritten<'a> {
|
||||||
|
let Self {
|
||||||
|
bits,
|
||||||
|
sim_only_values,
|
||||||
|
sim_only_values_range,
|
||||||
|
} = self;
|
||||||
|
assert_eq!(slice.bit_width(), bits.len());
|
||||||
|
assert_eq!(slice.sim_only_values().len(), sim_only_values_range.len());
|
||||||
|
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][..clone_from_src.len()]
|
||||||
|
.clone_from_slice(clone_from_src);
|
||||||
|
sim_only_values.extend_from_slice(clone_src);
|
||||||
|
OpaqueSimValueWritten {
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn fill_prefix_with<F>(
|
||||||
|
&mut self,
|
||||||
|
prefix_bit_width: usize,
|
||||||
|
prefix_sim_only_values_len: usize,
|
||||||
|
f: F,
|
||||||
|
) where
|
||||||
|
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
|
||||||
|
{
|
||||||
|
assert!(prefix_bit_width <= self.bit_width());
|
||||||
|
assert!(prefix_sim_only_values_len <= self.sim_only_values_len());
|
||||||
|
let next_start = self.sim_only_values_range.start + prefix_sim_only_values_len;
|
||||||
|
let OpaqueSimValueWritten {
|
||||||
|
_phantom: PhantomData,
|
||||||
|
} = f(OpaqueSimValueWriter {
|
||||||
|
bits: &mut self.bits[..prefix_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)[prefix_bit_width..];
|
||||||
|
self.sim_only_values_range.start = next_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait StaticType: Type + Default {
|
pub trait StaticType: Type + Default {
|
||||||
const TYPE: Self;
|
const TYPE: Self;
|
||||||
const MASK_TYPE: Self::MaskType;
|
const MASK_TYPE: Self::MaskType;
|
||||||
|
|
|
@ -9,6 +9,7 @@ mod misc;
|
||||||
mod scoped_ref;
|
mod scoped_ref;
|
||||||
pub(crate) mod streaming_read_utf8;
|
pub(crate) mod streaming_read_utf8;
|
||||||
mod test_hasher;
|
mod test_hasher;
|
||||||
|
mod type_id_serde;
|
||||||
|
|
||||||
// allow easily switching the hasher crate-wide for testing
|
// allow easily switching the hasher crate-wide for testing
|
||||||
#[cfg(feature = "unstable-test-hasher")]
|
#[cfg(feature = "unstable-test-hasher")]
|
||||||
|
@ -39,6 +40,9 @@ pub use misc::{
|
||||||
iter_eq_by,
|
iter_eq_by,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use type_id_serde::TypeIdSerde;
|
||||||
|
|
||||||
pub mod job_server;
|
pub mod job_server;
|
||||||
pub mod prefix_sum;
|
pub mod prefix_sum;
|
||||||
pub mod ready_valid;
|
pub mod ready_valid;
|
||||||
|
|
101
crates/fayalite/src/util/type_id_serde.rs
Normal file
101
crates/fayalite/src/util/type_id_serde.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use hashbrown::{HashMap, hash_map::Entry};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
|
||||||
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
fmt::Write,
|
||||||
|
hash::{BuildHasher, Hash, Hasher, RandomState},
|
||||||
|
sync::Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
/// [`TypeId`] that implements [`Serialize`] and [`Deserialize`] for use only within a single running instance of a
|
||||||
|
/// single program. If you try to transfer the serialized value from one program to another, it should fail to
|
||||||
|
/// deserialize with extremely high probability since we use 128-bit random numbers from [`RandomState`] (though
|
||||||
|
/// they may be deterministic on some targets). Note that those 128-bit random numbers are *not* the same number as is
|
||||||
|
/// stored in the inner [`TypeId`].
|
||||||
|
pub struct TypeIdSerde(pub TypeId);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename = "TypeIdSerde")]
|
||||||
|
struct TypeIdSerdeId([u32; 4]);
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TypeIdSerdeIdMapInner {
|
||||||
|
serde_id_to_type_id: HashMap<TypeIdSerdeId, TypeId>,
|
||||||
|
serde_id_random_state: RandomState,
|
||||||
|
buffer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeIdSerdeIdMapInner {
|
||||||
|
#[cold]
|
||||||
|
fn new_serde_id(&mut self, type_id: TypeId) -> TypeIdSerdeId {
|
||||||
|
let mut try_number = 0u64;
|
||||||
|
let mut hasher = self.serde_id_random_state.build_hasher();
|
||||||
|
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
|
||||||
|
self.buffer.clear();
|
||||||
|
write!(self.buffer, "{type_id:?}").expect("shouldn't ever fail");
|
||||||
|
self.buffer.hash(&mut hasher);
|
||||||
|
loop {
|
||||||
|
let mut hasher = hasher.clone();
|
||||||
|
try_number.hash(&mut hasher);
|
||||||
|
try_number += 1;
|
||||||
|
let retval = TypeIdSerdeId(std::array::from_fn(|i| {
|
||||||
|
let mut hasher = hasher.clone();
|
||||||
|
i.hash(&mut hasher);
|
||||||
|
hasher.finish() as u32
|
||||||
|
}));
|
||||||
|
match self.serde_id_to_type_id.entry(retval) {
|
||||||
|
Entry::Occupied(_) => continue,
|
||||||
|
Entry::Vacant(e) => {
|
||||||
|
e.insert(type_id);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TypeIdSerdeIdMap {
|
||||||
|
type_id_to_serde_id: HashMap<TypeId, TypeIdSerdeId>,
|
||||||
|
inner: TypeIdSerdeIdMapInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
static TYPE_ID_SERDE_ID_MAP: Mutex<Option<TypeIdSerdeIdMap>> = Mutex::new(None);
|
||||||
|
|
||||||
|
impl Serialize for TypeIdSerde {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut type_id_serde_id_map = TYPE_ID_SERDE_ID_MAP.lock().unwrap();
|
||||||
|
let map = type_id_serde_id_map.get_or_insert_default();
|
||||||
|
let serde_id = match map.type_id_to_serde_id.entry(self.0) {
|
||||||
|
Entry::Occupied(e) => *e.get(),
|
||||||
|
Entry::Vacant(e) => *e.insert(map.inner.new_serde_id(self.0)),
|
||||||
|
};
|
||||||
|
drop(type_id_serde_id_map);
|
||||||
|
serde_id.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for TypeIdSerde {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let serde_id = TypeIdSerdeId::deserialize(deserializer)?;
|
||||||
|
let mut type_id_serde_id_map = TYPE_ID_SERDE_ID_MAP.lock().unwrap();
|
||||||
|
Ok(TypeIdSerde(*type_id_serde_id_map
|
||||||
|
.as_mut()
|
||||||
|
.and_then(|map| map.inner.serde_id_to_type_id.get(&serde_id))
|
||||||
|
.ok_or_else(|| {
|
||||||
|
D::Error::custom(
|
||||||
|
"TypeIdSerde value from a different invocation of this program which is not allowed",
|
||||||
|
)
|
||||||
|
})?))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue