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},
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref,
|
||||
CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter,
|
||||
OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref,
|
||||
serde_impls::SerdeCanonicalType,
|
||||
},
|
||||
util::ConstUsize,
|
||||
|
@ -48,6 +49,7 @@ impl<T: Type, Len: Size> ArrayType<T, Len> {
|
|||
is_storable,
|
||||
is_castable_from_bits,
|
||||
bit_width,
|
||||
sim_only_value_types,
|
||||
} = element;
|
||||
let Some(bit_width) = bit_width.checked_mul(len) else {
|
||||
panic!("array too big");
|
||||
|
@ -194,42 +196,71 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
|
|||
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);
|
||||
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| {
|
||||
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()
|
||||
.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);
|
||||
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();
|
||||
assert_eq!(self.len(), value.len());
|
||||
for (i, element_value) in value.iter_mut().enumerate() {
|
||||
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()
|
||||
.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) {
|
||||
assert_eq!(bits.len(), self.type_properties.bit_width);
|
||||
fn sim_value_to_opaque<'w>(
|
||||
&self,
|
||||
value: &Self::SimValue,
|
||||
mut writer: OpaqueSimValueWriter<'w>,
|
||||
) -> OpaqueSimValueWritten<'w> {
|
||||
let element_ty = self.element();
|
||||
let element_bit_width = element_ty.canonical().bit_width();
|
||||
let value: &[SimValue<T>] = value.as_ref();
|
||||
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 = AsRef::<[SimValue<T>]>::as_ref(&value);
|
||||
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);
|
||||
bits[i * element_bit_width..][..element_bit_width]
|
||||
.copy_from_bitslice(SimValue::bits(element_value).bits());
|
||||
writer.fill_prefix_with(element_bit_width, element_sim_only_types_count, |writer| {
|
||||
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 {
|
||||
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);
|
||||
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!(value.bit_width(), self.type_properties().bit_width);
|
||||
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!(value.bit_width(), self.type_properties().bit_width);
|
||||
bits.copy_from_bitslice(value.bits().bits());
|
||||
|
@ -495,19 +509,33 @@ macro_rules! impl_tuples {
|
|||
fn source_location() -> SourceLocation {
|
||||
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)]
|
||||
let mut v = BundleSimValueFromBits::new(*self, bits);
|
||||
$(let $var = v.field_from_bits();)*
|
||||
($($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)]
|
||||
let mut v = BundleSimValueFromBits::new(*self, bits);
|
||||
let ($($var,)*) = value;
|
||||
$(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)]
|
||||
let mut v = BundleSimValueToBits::new(*self, bits);
|
||||
let ($($var,)*) = value;
|
||||
|
@ -723,7 +751,11 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
|
|||
fn source_location() -> SourceLocation {
|
||||
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());
|
||||
*self
|
||||
}
|
||||
|
|
|
@ -39,17 +39,31 @@ impl Type for Clock {
|
|||
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);
|
||||
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);
|
||||
*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);
|
||||
bits.set(0, *value);
|
||||
}
|
||||
|
|
|
@ -381,16 +381,30 @@ impl Type for Enum {
|
|||
fn source_location() -> SourceLocation {
|
||||
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);
|
||||
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!(value.bit_width(), self.type_properties().bit_width);
|
||||
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!(value.bit_width(), self.type_properties().bit_width);
|
||||
bits.copy_from_bitslice(value.bits().bits());
|
||||
|
|
|
@ -678,16 +678,30 @@ macro_rules! impl_int {
|
|||
fn source_location() -> SourceLocation {
|
||||
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());
|
||||
$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!(value.width(), self.width());
|
||||
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!(value.width(), self.width());
|
||||
bits.copy_from_bitslice(value.bits());
|
||||
|
@ -1252,15 +1266,29 @@ impl Type for Bool {
|
|||
fn source_location() -> SourceLocation {
|
||||
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);
|
||||
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);
|
||||
*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);
|
||||
bits.set(0, *value);
|
||||
}
|
||||
|
|
|
@ -70,15 +70,29 @@ impl Type for UIntInRangeMaskType {
|
|||
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)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -353,17 +367,31 @@ macro_rules! define_uint_in_range_type {
|
|||
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;
|
||||
retval.view_bits_mut::<Lsb0>()[..bits.len()].clone_from_bitslice(bits);
|
||||
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);
|
||||
}
|
||||
|
||||
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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ use crate::{
|
|||
},
|
||||
int::Bool,
|
||||
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,
|
||||
ty::{
|
||||
CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self,
|
||||
|
@ -284,18 +287,32 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
|
|||
SourceLocation::builtin()
|
||||
}
|
||||
|
||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
||||
assert!(bits.is_empty());
|
||||
fn sim_value_from_bits(
|
||||
&self,
|
||||
bits: &BitSlice,
|
||||
sim_only_values: &[DynSimOnlyValue],
|
||||
) -> Self::SimValue {
|
||||
assert_matching_sim_values(0, &[], bits, sim_only_values);
|
||||
*self
|
||||
}
|
||||
|
||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
||||
assert!(bits.is_empty());
|
||||
fn sim_value_clone_from_bits(
|
||||
&self,
|
||||
value: &mut Self::SimValue,
|
||||
bits: &BitSlice,
|
||||
sim_only_values: &[DynSimOnlyValue],
|
||||
) {
|
||||
assert_matching_sim_values(0, &[], bits, sim_only_values);
|
||||
assert_eq!(*value, *self);
|
||||
}
|
||||
|
||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
||||
assert!(bits.is_empty());
|
||||
fn sim_value_to_bits<'w>(
|
||||
&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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,17 +69,31 @@ macro_rules! reset_type {
|
|||
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);
|
||||
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);
|
||||
*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);
|
||||
bits.set(0, *value);
|
||||
}
|
||||
|
|
|
@ -8,61 +8,81 @@ use crate::{
|
|||
enum_::{Enum, EnumType},
|
||||
expr::{CastBitsTo, Expr, ToExpr},
|
||||
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
|
||||
intern::Interned,
|
||||
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::{
|
||||
ConstUsize,
|
||||
alternating_cell::{AlternatingCell, AlternatingCellMethods},
|
||||
},
|
||||
};
|
||||
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::{
|
||||
fmt,
|
||||
borrow::Cow,
|
||||
fmt::{self, Write},
|
||||
hash::{BuildHasher, Hash, Hasher, RandomState},
|
||||
marker::PhantomData,
|
||||
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)]
|
||||
enum ValidFlags {
|
||||
BothValid = 0,
|
||||
OnlyValueValid = 1,
|
||||
OnlyBitsValid = 2,
|
||||
OnlyOpaqueValid = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SimValueInner<T: Type> {
|
||||
value: T::SimValue,
|
||||
bits: UIntValue,
|
||||
opaque: OpaqueSimValue,
|
||||
valid_flags: ValidFlags,
|
||||
ty: T,
|
||||
sim_only_values_len: usize,
|
||||
}
|
||||
|
||||
impl<T: Type> SimValueInner<T> {
|
||||
fn fill_bits(&mut self) {
|
||||
fn fill_opaque(&mut self) {
|
||||
match self.valid_flags {
|
||||
ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {}
|
||||
ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn into_bits(mut self) -> UIntValue {
|
||||
self.fill_bits();
|
||||
self.bits
|
||||
fn into_opaque(mut self) -> OpaqueSimValue {
|
||||
self.fill_opaque();
|
||||
self.opaque
|
||||
}
|
||||
fn bits_mut(&mut self) -> &mut UIntValue {
|
||||
self.fill_bits();
|
||||
self.valid_flags = ValidFlags::OnlyBitsValid;
|
||||
&mut self.bits
|
||||
fn opaque_mut(&mut self) -> &mut OpaqueSimValue {
|
||||
self.fill_opaque();
|
||||
self.valid_flags = ValidFlags::OnlyOpaqueValid;
|
||||
&mut self.opaque
|
||||
}
|
||||
fn fill_value(&mut self) {
|
||||
match self.valid_flags {
|
||||
ValidFlags::BothValid | ValidFlags::OnlyValueValid => {}
|
||||
ValidFlags::OnlyBitsValid => {
|
||||
ValidFlags::OnlyOpaqueValid => {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -82,12 +102,14 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> {
|
|||
fn unique_to_shared(&mut self) {
|
||||
match self.valid_flags {
|
||||
ValidFlags::BothValid => return,
|
||||
ValidFlags::OnlyValueValid => {
|
||||
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut())
|
||||
}
|
||||
ValidFlags::OnlyBitsValid => self
|
||||
ValidFlags::OnlyValueValid => OpaqueSimValueWriter::rewrite_with(
|
||||
self.sim_only_values_len,
|
||||
&mut self.opaque,
|
||||
|writer| self.ty.sim_value_to_opaque(&self.value, writer),
|
||||
),
|
||||
ValidFlags::OnlyOpaqueValid => 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;
|
||||
}
|
||||
|
@ -143,13 +165,15 @@ impl<T: Type + Clone> Clone for SimValue<T> {
|
|||
|
||||
impl<T: Type> SimValue<T> {
|
||||
#[track_caller]
|
||||
pub fn from_bits(ty: T, bits: UIntValue) -> Self {
|
||||
assert_eq!(ty.canonical().bit_width(), bits.width());
|
||||
pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self {
|
||||
let type_properties = ty.canonical().type_properties();
|
||||
type_properties.assert_matching_opaque_sim_value(opaque.as_slice());
|
||||
let inner = SimValueInner {
|
||||
value: ty.sim_value_from_bits(bits.bits()),
|
||||
bits,
|
||||
value: ty.sim_value_from_opaque(opaque.as_slice()),
|
||||
opaque,
|
||||
valid_flags: ValidFlags::BothValid,
|
||||
ty,
|
||||
sim_only_values_len: type_properties.sim_only_values_len,
|
||||
};
|
||||
Self {
|
||||
inner: AlternatingCell::new_shared(inner),
|
||||
|
@ -157,14 +181,30 @@ impl<T: Type> SimValue<T> {
|
|||
}
|
||||
#[track_caller]
|
||||
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 {
|
||||
let type_properties = ty.canonical().type_properties();
|
||||
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,
|
||||
valid_flags: ValidFlags::OnlyValueValid,
|
||||
ty,
|
||||
sim_only_values_len: type_properties.sim_only_values_len,
|
||||
};
|
||||
Self {
|
||||
inner: AlternatingCell::new_unique(inner),
|
||||
|
@ -173,18 +213,24 @@ impl<T: Type> SimValue<T> {
|
|||
pub fn ty(this: &Self) -> T {
|
||||
this.inner.share().ty
|
||||
}
|
||||
pub fn into_bits(this: Self) -> UIntValue {
|
||||
this.inner.into_inner().into_bits()
|
||||
pub fn into_opaque(this: Self) -> OpaqueSimValue {
|
||||
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();
|
||||
(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 {
|
||||
&this.inner.share().bits
|
||||
Self::opaque(this).bits()
|
||||
}
|
||||
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 {
|
||||
this.inner.into_inner().into_value()
|
||||
|
@ -197,59 +243,59 @@ impl<T: Type> SimValue<T> {
|
|||
}
|
||||
#[track_caller]
|
||||
pub fn from_canonical(v: SimValue<CanonicalType>) -> Self {
|
||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
||||
Self::from_bits(T::from_canonical(ty), bits)
|
||||
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||
Self::from_opaque(T::from_canonical(ty), opaque)
|
||||
}
|
||||
pub fn into_canonical(this: Self) -> SimValue<CanonicalType> {
|
||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
||||
SimValue::from_bits(ty.canonical(), bits)
|
||||
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||
SimValue::from_opaque(ty.canonical(), opaque)
|
||||
}
|
||||
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]
|
||||
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
|
||||
where
|
||||
T: IntType,
|
||||
{
|
||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
||||
SimValue::from_bits(T::from_dyn_int(ty), bits)
|
||||
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||
SimValue::from_opaque(T::from_dyn_int(ty), opaque)
|
||||
}
|
||||
pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn>
|
||||
where
|
||||
T: IntType,
|
||||
{
|
||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
||||
SimValue::from_bits(ty.as_dyn_int(), bits)
|
||||
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||
SimValue::from_opaque(ty.as_dyn_int(), opaque)
|
||||
}
|
||||
pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn>
|
||||
where
|
||||
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]
|
||||
pub fn from_bundle(v: SimValue<Bundle>) -> Self
|
||||
where
|
||||
T: BundleType,
|
||||
{
|
||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
||||
SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits)
|
||||
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||
SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque)
|
||||
}
|
||||
pub fn into_bundle(this: Self) -> SimValue<Bundle>
|
||||
where
|
||||
T: BundleType,
|
||||
{
|
||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
||||
SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits)
|
||||
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||
SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque)
|
||||
}
|
||||
pub fn to_bundle(this: &Self) -> SimValue<Bundle>
|
||||
where
|
||||
T: BundleType,
|
||||
{
|
||||
SimValue::from_bits(
|
||||
SimValue::from_opaque(
|
||||
Bundle::from_canonical(Self::ty(this).canonical()),
|
||||
Self::bits(&this).clone(),
|
||||
Self::opaque(&this).clone(),
|
||||
)
|
||||
}
|
||||
#[track_caller]
|
||||
|
@ -257,23 +303,23 @@ impl<T: Type> SimValue<T> {
|
|||
where
|
||||
T: EnumType,
|
||||
{
|
||||
let (ty, bits) = SimValue::into_ty_and_bits(v);
|
||||
SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits)
|
||||
let (ty, opaque) = SimValue::into_ty_and_opaque(v);
|
||||
SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque)
|
||||
}
|
||||
pub fn into_enum(this: Self) -> SimValue<Enum>
|
||||
where
|
||||
T: EnumType,
|
||||
{
|
||||
let (ty, bits) = Self::into_ty_and_bits(this);
|
||||
SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits)
|
||||
let (ty, opaque) = Self::into_ty_and_opaque(this);
|
||||
SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque)
|
||||
}
|
||||
pub fn to_enum(this: &Self) -> SimValue<Enum>
|
||||
where
|
||||
T: EnumType,
|
||||
{
|
||||
SimValue::from_bits(
|
||||
SimValue::from_opaque(
|
||||
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]
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
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]
|
||||
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]
|
||||
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::Enum(_)
|
||||
| CanonicalType::Bundle(_)
|
||||
| CanonicalType::PhantomConst(_) => {
|
||||
| CanonicalType::PhantomConst(_)
|
||||
| CanonicalType::DynSimOnlyValueType(_) => {
|
||||
panic!("can't create SimValue from bool: expected value of type: {ty:?}");
|
||||
}
|
||||
CanonicalType::Bool(_)
|
||||
| CanonicalType::AsyncReset(_)
|
||||
| CanonicalType::SyncReset(_)
|
||||
| CanonicalType::Reset(_)
|
||||
| CanonicalType::Clock(_) => {
|
||||
SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1))))
|
||||
}
|
||||
| CanonicalType::Clock(_) => SimValue::from_opaque(
|
||||
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!(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},
|
||||
phantom_const::PhantomConst,
|
||||
reset::{AsyncReset, Reset, SyncReset},
|
||||
sim::value::{SimValue, ToSimValueWithType},
|
||||
sim::value::{
|
||||
DynSimOnlyValue, DynSimOnlyValueType, SimValue, ToSimValueWithType,
|
||||
assert_matching_sim_values,
|
||||
},
|
||||
source_location::SourceLocation,
|
||||
util::ConstUsize,
|
||||
};
|
||||
use bitvec::slice::BitSlice;
|
||||
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;
|
||||
|
||||
|
@ -28,6 +31,20 @@ pub struct TypeProperties {
|
|||
pub is_storable: bool,
|
||||
pub is_castable_from_bits: bool,
|
||||
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)]
|
||||
|
@ -43,6 +60,7 @@ pub enum CanonicalType {
|
|||
Reset(Reset),
|
||||
Clock(Clock),
|
||||
PhantomConst(PhantomConst),
|
||||
DynSimOnlyValueType(DynSimOnlyValueType),
|
||||
}
|
||||
|
||||
impl fmt::Debug for CanonicalType {
|
||||
|
@ -59,6 +77,7 @@ impl fmt::Debug for CanonicalType {
|
|||
Self::Reset(v) => v.fmt(f),
|
||||
Self::Clock(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::Clock(v) => v.type_properties(),
|
||||
CanonicalType::PhantomConst(v) => v.type_properties(),
|
||||
CanonicalType::DynSimOnlyValueType(v) => v.type_properties(),
|
||||
}
|
||||
}
|
||||
pub fn is_passive(self) -> bool {
|
||||
|
@ -177,6 +197,12 @@ impl CanonicalType {
|
|||
};
|
||||
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 {
|
||||
|
@ -287,6 +313,7 @@ impl_base_type!(SyncReset);
|
|||
impl_base_type!(Reset);
|
||||
impl_base_type!(Clock);
|
||||
impl_base_type!(PhantomConst);
|
||||
impl_base_type!(DynSimOnlyValueType);
|
||||
|
||||
impl_base_type_serde!(Bool, "a Bool");
|
||||
impl_base_type_serde!(Enum, "an Enum");
|
||||
|
@ -348,9 +375,17 @@ pub trait Type:
|
|||
fn canonical(&self) -> CanonicalType;
|
||||
fn from_canonical(canonical_type: CanonicalType) -> Self;
|
||||
fn source_location() -> SourceLocation;
|
||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue;
|
||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice);
|
||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice);
|
||||
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue;
|
||||
fn sim_value_clone_from_opaque(
|
||||
&self,
|
||||
value: &mut Self::SimValue,
|
||||
opaque: OpaqueSimValueSlice<'_>,
|
||||
);
|
||||
fn sim_value_to_opaque<'w>(
|
||||
&self,
|
||||
value: &Self::SimValue,
|
||||
writer: OpaqueSimValueWriter<'w>,
|
||||
) -> OpaqueSimValueWritten<'w>;
|
||||
}
|
||||
|
||||
pub trait BaseType:
|
||||
|
@ -405,6 +440,7 @@ impl Type for CanonicalType {
|
|||
CanonicalType::Reset(v) => v.mask_type().canonical(),
|
||||
CanonicalType::Clock(v) => v.mask_type().canonical(),
|
||||
CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
|
||||
CanonicalType::DynSimOnlyValueType(v) => v.mask_type().canonical(),
|
||||
}
|
||||
}
|
||||
fn canonical(&self) -> CanonicalType {
|
||||
|
@ -416,28 +452,46 @@ impl Type for CanonicalType {
|
|||
fn source_location() -> SourceLocation {
|
||||
SourceLocation::builtin()
|
||||
}
|
||||
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
||||
assert_eq!(bits.len(), self.bit_width());
|
||||
OpaqueSimValue::from_bitslice(bits)
|
||||
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
||||
self.type_properties()
|
||||
.assert_matching_opaque_sim_value(opaque);
|
||||
opaque.to_owned()
|
||||
}
|
||||
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
||||
assert_eq!(bits.len(), self.bit_width());
|
||||
assert_eq!(value.bit_width(), self.bit_width());
|
||||
value.bits_mut().bits_mut().copy_from_bitslice(bits);
|
||||
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_slice(opaque);
|
||||
}
|
||||
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
||||
assert_eq!(bits.len(), self.bit_width());
|
||||
assert_eq!(value.bit_width(), self.bit_width());
|
||||
bits.copy_from_bitslice(value.bits().bits());
|
||||
fn sim_value_to_opaque<'w>(
|
||||
&self,
|
||||
value: &Self::SimValue,
|
||||
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)]
|
||||
pub struct OpaqueSimValue {
|
||||
bits: UIntValue,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
sim_only_values: Vec<DynSimOnlyValue>,
|
||||
}
|
||||
|
||||
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 {
|
||||
self.bits.width()
|
||||
}
|
||||
|
@ -451,13 +505,86 @@ impl OpaqueSimValue {
|
|||
self.bits
|
||||
}
|
||||
pub fn from_bits(bits: UIntValue) -> Self {
|
||||
Self { bits }
|
||||
Self {
|
||||
bits,
|
||||
sim_only_values: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn from_bitslice(v: &BitSlice) -> Self {
|
||||
Self::from_bitslice_and_sim_only_values(v, Vec::new())
|
||||
}
|
||||
pub fn from_bitslice_and_sim_only_values(
|
||||
bits: &BitSlice,
|
||||
sim_only_values: Vec<DynSimOnlyValue>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bits: UIntValue::new(Arc::new(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 {
|
||||
|
@ -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 {
|
||||
const TYPE: Self;
|
||||
const MASK_TYPE: Self::MaskType;
|
||||
|
|
|
@ -9,6 +9,7 @@ mod misc;
|
|||
mod scoped_ref;
|
||||
pub(crate) mod streaming_read_utf8;
|
||||
mod test_hasher;
|
||||
mod type_id_serde;
|
||||
|
||||
// allow easily switching the hasher crate-wide for testing
|
||||
#[cfg(feature = "unstable-test-hasher")]
|
||||
|
@ -39,6 +40,9 @@ pub use misc::{
|
|||
iter_eq_by,
|
||||
};
|
||||
|
||||
#[doc(inline)]
|
||||
pub use type_id_serde::TypeIdSerde;
|
||||
|
||||
pub mod job_server;
|
||||
pub mod prefix_sum;
|
||||
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