320 lines
8.8 KiB
Rust
320 lines
8.8 KiB
Rust
// 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::{
|
|
any::{self, TypeId},
|
|
fmt,
|
|
hash::{Hash, Hasher},
|
|
marker::PhantomData,
|
|
mem::ManuallyDrop,
|
|
rc::Rc,
|
|
};
|
|
|
|
pub trait SimOnlyValueTrait:
|
|
'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default
|
|
{
|
|
}
|
|
|
|
impl<T: 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default>
|
|
SimOnlyValueTrait for T
|
|
{
|
|
}
|
|
|
|
/// Safety: `type_id_dyn` must return `TypeId::of::<T>()` where `Self = SimOnly<T>`
|
|
unsafe trait DynSimOnlyTrait: 'static + Send + Sync {
|
|
fn type_id_dyn(&self) -> TypeId;
|
|
fn type_name(&self) -> &'static str;
|
|
fn default_value(&self) -> Rc<dyn DynSimOnlyValueTrait>;
|
|
fn deserialize_from_json_string(
|
|
&self,
|
|
json_str: &str,
|
|
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>>;
|
|
}
|
|
|
|
/// Safety: `type_id_dyn` is implemented correctly
|
|
unsafe impl<T: SimOnlyValueTrait> DynSimOnlyTrait for SimOnly<T> {
|
|
fn type_id_dyn(&self) -> TypeId {
|
|
TypeId::of::<T>()
|
|
}
|
|
|
|
fn type_name(&self) -> &'static str {
|
|
any::type_name::<T>()
|
|
}
|
|
|
|
fn default_value(&self) -> Rc<dyn DynSimOnlyValueTrait> {
|
|
Rc::new(T::default())
|
|
}
|
|
|
|
fn deserialize_from_json_string(
|
|
&self,
|
|
json_str: &str,
|
|
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>> {
|
|
Ok(Rc::<T>::new(serde_json::from_str(json_str)?))
|
|
}
|
|
}
|
|
|
|
/// Safety:
|
|
/// * `type_id_dyn()` must return `TypeId::of::<Self>()`.
|
|
/// * `ty().type_id()` must return `TypeId::of::<Self>()`.
|
|
unsafe trait DynSimOnlyValueTrait: 'static + fmt::Debug {
|
|
fn type_id_dyn(&self) -> TypeId;
|
|
fn ty(&self) -> DynSimOnly;
|
|
fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool;
|
|
fn serialize_to_json_string(&self) -> serde_json::Result<String>;
|
|
fn hash_dyn(&self, state: &mut dyn Hasher);
|
|
}
|
|
|
|
impl dyn DynSimOnlyValueTrait {
|
|
fn is<T: SimOnlyValueTrait>(&self) -> bool {
|
|
Self::type_id_dyn(self) == TypeId::of::<T>()
|
|
}
|
|
|
|
fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
|
|
if Self::is::<T>(self) {
|
|
// Safety: checked that `Self` is really `T`
|
|
Some(unsafe { &*(self as *const Self as *const T) })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn downcast_rc<T: SimOnlyValueTrait>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>> {
|
|
if Self::is::<T>(&*self) {
|
|
// Safety: checked that `Self` is really `T`
|
|
Ok(unsafe { Rc::from_raw(Rc::into_raw(self) as *const T) })
|
|
} else {
|
|
Err(self)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Safety:
|
|
/// * `type_id_dyn()` returns `TypeId::of::<Self>()`.
|
|
/// * `ty().type_id()` returns `TypeId::of::<Self>()`.
|
|
unsafe impl<T: SimOnlyValueTrait> DynSimOnlyValueTrait for T {
|
|
fn type_id_dyn(&self) -> TypeId {
|
|
TypeId::of::<T>()
|
|
}
|
|
|
|
fn ty(&self) -> DynSimOnly {
|
|
DynSimOnly::of::<T>()
|
|
}
|
|
|
|
fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool {
|
|
other.downcast_ref::<T>().is_some_and(|other| self == other)
|
|
}
|
|
|
|
fn serialize_to_json_string(&self) -> serde_json::Result<String> {
|
|
serde_json::to_string(self)
|
|
}
|
|
|
|
fn hash_dyn(&self, mut state: &mut dyn Hasher) {
|
|
self.hash(&mut state);
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub struct DynSimOnly {
|
|
ty: &'static dyn DynSimOnlyTrait,
|
|
}
|
|
|
|
impl DynSimOnly {
|
|
pub const fn of<T: SimOnlyValueTrait>() -> Self {
|
|
Self {
|
|
ty: &const { SimOnly::<T>::new() },
|
|
}
|
|
}
|
|
pub fn type_id(self) -> TypeId {
|
|
self.ty.type_id_dyn()
|
|
}
|
|
pub fn type_name(self) -> &'static str {
|
|
self.ty.type_name()
|
|
}
|
|
pub fn is<T: SimOnlyValueTrait>(self) -> bool {
|
|
self.type_id() == TypeId::of::<T>()
|
|
}
|
|
pub fn downcast<T: SimOnlyValueTrait>(self) -> Option<SimOnly<T>> {
|
|
self.is::<T>().then_some(SimOnly::default())
|
|
}
|
|
pub fn deserialize_from_json_string(
|
|
self,
|
|
json_str: &str,
|
|
) -> serde_json::Result<DynSimOnlyValue> {
|
|
self.ty
|
|
.deserialize_from_json_string(json_str)
|
|
.map(DynSimOnlyValue)
|
|
}
|
|
pub fn default_value(self) -> DynSimOnlyValue {
|
|
DynSimOnlyValue(self.ty.default_value())
|
|
}
|
|
}
|
|
|
|
impl PartialEq for DynSimOnly {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
Self::type_id(*self) == Self::type_id(*other)
|
|
}
|
|
}
|
|
|
|
impl Eq for DynSimOnly {}
|
|
|
|
impl Hash for DynSimOnly {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
Self::type_id(*self).hash(state);
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for DynSimOnly {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "SimOnly<{}>", self.ty.type_name())
|
|
}
|
|
}
|
|
|
|
impl<T: SimOnlyValueTrait> From<SimOnly<T>> for DynSimOnly {
|
|
fn from(value: SimOnly<T>) -> Self {
|
|
let SimOnly(PhantomData) = value;
|
|
Self::of::<T>()
|
|
}
|
|
}
|
|
|
|
/// the [`Type`][Type] for a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL
|
|
///
|
|
/// [Type]: crate::ty::Type
|
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
|
pub struct SimOnly<T: SimOnlyValueTrait>(PhantomData<fn(T) -> T>);
|
|
|
|
impl<T: SimOnlyValueTrait> fmt::Debug for SimOnly<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
DynSimOnly::of::<T>().fmt(f)
|
|
}
|
|
}
|
|
|
|
impl<T: SimOnlyValueTrait> SimOnly<T> {
|
|
pub const fn new() -> Self {
|
|
Self(PhantomData)
|
|
}
|
|
}
|
|
|
|
impl<T: SimOnlyValueTrait> Copy for SimOnly<T> {}
|
|
|
|
impl<T: SimOnlyValueTrait> Default for SimOnly<T> {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
/// a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL
|
|
#[derive(Clone, Eq, Hash, Default, Ord)]
|
|
pub struct SimOnlyValue<T: SimOnlyValueTrait>(Rc<T>);
|
|
|
|
impl<T: SimOnlyValueTrait + PartialEq<U>, U: SimOnlyValueTrait> PartialEq<SimOnlyValue<U>>
|
|
for SimOnlyValue<T>
|
|
{
|
|
fn eq(&self, other: &SimOnlyValue<U>) -> bool {
|
|
<T as PartialEq<U>>::eq(self, other)
|
|
}
|
|
}
|
|
|
|
impl<T: SimOnlyValueTrait + PartialOrd<U>, U: SimOnlyValueTrait> PartialOrd<SimOnlyValue<U>>
|
|
for SimOnlyValue<T>
|
|
{
|
|
fn partial_cmp(&self, other: &SimOnlyValue<U>) -> Option<std::cmp::Ordering> {
|
|
<T as PartialOrd<U>>::partial_cmp(self, other)
|
|
}
|
|
}
|
|
|
|
impl<T: SimOnlyValueTrait> SimOnlyValue<T> {
|
|
pub fn with_dyn_ref<F: FnOnce(&DynSimOnlyValue) -> R, R>(&self, f: F) -> R {
|
|
// Safety: creating a copied `Rc<T>` is safe as long as the copy isn't dropped and isn't changed
|
|
// to point somewhere else, `f` can't change `dyn_ref` because it's only given a shared reference.
|
|
let dyn_ref =
|
|
unsafe { ManuallyDrop::new(DynSimOnlyValue(Rc::<T>::from_raw(Rc::as_ptr(&self.0)))) };
|
|
f(&dyn_ref)
|
|
}
|
|
pub fn from_rc(v: Rc<T>) -> Self {
|
|
Self(v)
|
|
}
|
|
pub fn new(v: T) -> Self {
|
|
Self(Rc::new(v))
|
|
}
|
|
pub fn into_inner(this: Self) -> Rc<T> {
|
|
this.0
|
|
}
|
|
pub fn inner_mut(this: &mut Self) -> &mut Rc<T> {
|
|
&mut this.0
|
|
}
|
|
pub fn inner(this: &Self) -> &Rc<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 {
|
|
Rc::make_mut(&mut self.0)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
|
|
|
|
impl fmt::Debug for DynSimOnlyValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
<dyn DynSimOnlyValueTrait as fmt::Debug>::fmt(&*self.0, f)
|
|
}
|
|
}
|
|
|
|
impl PartialEq for DynSimOnlyValue {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
DynSimOnlyValueTrait::eq_dyn(&*self.0, &*other.0)
|
|
}
|
|
}
|
|
|
|
impl Eq for DynSimOnlyValue {}
|
|
|
|
impl Hash for DynSimOnlyValue {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
DynSimOnlyValueTrait::hash_dyn(&*self.0, state);
|
|
}
|
|
}
|
|
|
|
impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue {
|
|
fn from(value: SimOnlyValue<T>) -> Self {
|
|
Self(value.0)
|
|
}
|
|
}
|
|
|
|
impl DynSimOnlyValue {
|
|
pub fn ty(&self) -> DynSimOnly {
|
|
self.0.ty()
|
|
}
|
|
pub fn type_id(&self) -> TypeId {
|
|
self.0.type_id_dyn()
|
|
}
|
|
pub fn is<T: SimOnlyValueTrait>(&self) -> bool {
|
|
self.0.is::<T>()
|
|
}
|
|
pub fn downcast<T: SimOnlyValueTrait>(self) -> Result<SimOnlyValue<T>, DynSimOnlyValue> {
|
|
match <dyn DynSimOnlyValueTrait>::downcast_rc(self.0) {
|
|
Ok(v) => Ok(SimOnlyValue(v)),
|
|
Err(v) => Err(Self(v)),
|
|
}
|
|
}
|
|
pub fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
|
|
<dyn DynSimOnlyValueTrait>::downcast_ref(&*self.0)
|
|
}
|
|
pub fn serialize_to_json_string(&self) -> serde_json::Result<String> {
|
|
self.0.serialize_to_json_string()
|
|
}
|
|
}
|