WIP switched to OpaqueSimValueWriter

This commit is contained in:
Jacob Lifshay 2025-09-01 04:46:24 -07:00
parent 6d36698adf
commit ab21db4103
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
13 changed files with 1546 additions and 131 deletions

View file

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

View file

@ -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
}

View file

@ -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);
}

View file

@ -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());

View file

@ -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);
}

View file

@ -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()]);
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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)),
);
}

View 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
}
}

View file

@ -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,12 +505,85 @@ 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 {
bits: UIntValue::new(Arc::new(v.to_bitvec())),
Self::from_bitslice_and_sim_only_values(v, Vec::new())
}
pub fn from_bitslice_and_sim_only_values(
bits: &BitSlice,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self {
bits: UIntValue::new(Arc::new(bits.to_bitvec())),
sim_only_values,
}
}
pub fn from_bits_and_sim_only_values(
bits: UIntValue,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self {
bits,
sim_only_values,
}
}
pub fn into_parts(self) -> (UIntValue, Vec<DynSimOnlyValue>) {
let Self {
bits,
sim_only_values,
} = self;
(bits, sim_only_values)
}
pub fn parts_mut(&mut self) -> (&mut UIntValue, &mut Vec<DynSimOnlyValue>) {
let Self {
bits,
sim_only_values,
} = self;
(bits, sim_only_values)
}
pub fn sim_only_values(&self) -> &[DynSimOnlyValue] {
&self.sim_only_values
}
pub fn sim_only_values_mut(&mut self) -> &mut Vec<DynSimOnlyValue> {
&mut self.sim_only_values
}
pub fn as_slice(&self) -> OpaqueSimValueSlice<'_> {
OpaqueSimValueSlice {
bits: self.bits.bits(),
sim_only_values: &self.sim_only_values,
}
}
pub fn slice<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());
}
}
@ -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;

View file

@ -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;

View 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",
)
})?))
}
}