forked from libre-chip/fayalite
485 lines
14 KiB
Rust
485 lines
14 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
|
|
use crate::{
|
|
expr::{
|
|
Expr, ToExpr,
|
|
ops::{ExprPartialEq, ExprPartialOrd},
|
|
},
|
|
int::Bool,
|
|
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
|
|
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
|
|
source_location::SourceLocation,
|
|
ty::{
|
|
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
|
|
StaticType, Type, TypeProperties, impl_match_variant_as_self,
|
|
serde_impls::{SerdeCanonicalType, SerdePhantomConst},
|
|
},
|
|
};
|
|
use serde::{
|
|
Deserialize, Deserializer, Serialize, Serializer,
|
|
de::{DeserializeOwned, Error},
|
|
};
|
|
use std::{
|
|
any::Any,
|
|
fmt,
|
|
hash::{Hash, Hasher},
|
|
marker::PhantomData,
|
|
ops::Index,
|
|
};
|
|
|
|
#[derive(Clone)]
|
|
pub struct PhantomConstCanonicalValue {
|
|
parsed: serde_json::Value,
|
|
serialized: Interned<str>,
|
|
}
|
|
|
|
impl PhantomConstCanonicalValue {
|
|
pub fn from_json_value(parsed: serde_json::Value) -> Self {
|
|
let serialized = Intern::intern_owned(
|
|
serde_json::to_string(&parsed)
|
|
.expect("conversion from json value to text shouldn't fail"),
|
|
);
|
|
Self { parsed, serialized }
|
|
}
|
|
pub fn as_json_value(&self) -> &serde_json::Value {
|
|
&self.parsed
|
|
}
|
|
pub fn as_str(&self) -> Interned<str> {
|
|
self.serialized
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for PhantomConstCanonicalValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(&self.serialized)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for PhantomConstCanonicalValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(&self.serialized)
|
|
}
|
|
}
|
|
|
|
impl PartialEq for PhantomConstCanonicalValue {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.serialized == other.serialized
|
|
}
|
|
}
|
|
|
|
impl Eq for PhantomConstCanonicalValue {}
|
|
|
|
impl Hash for PhantomConstCanonicalValue {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.serialized.hash(state);
|
|
}
|
|
}
|
|
|
|
impl Serialize for PhantomConstCanonicalValue {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
self.parsed.serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for PhantomConstCanonicalValue {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
Ok(Self::from_json_value(serde_json::Value::deserialize(
|
|
deserializer,
|
|
)?))
|
|
}
|
|
}
|
|
|
|
pub trait PhantomConstValue: Intern + InternedCompare + Serialize + fmt::Debug {
|
|
fn deserialize_value<'de, D>(deserializer: D) -> Result<Interned<Self>, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>;
|
|
}
|
|
|
|
impl<T> PhantomConstValue for T
|
|
where
|
|
T: ?Sized + Intern + InternedCompare + Serialize + fmt::Debug,
|
|
Interned<T>: DeserializeOwned,
|
|
{
|
|
fn deserialize_value<'de, D>(deserializer: D) -> Result<Interned<Self>, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
<Interned<T> as Deserialize<'de>>::deserialize(deserializer)
|
|
}
|
|
}
|
|
|
|
/// Wrapper type that allows any Rust value to be smuggled as a HDL [`Type`].
|
|
/// This only works for values that can be [serialized][Serialize] to and [deserialized][Deserialize] from [JSON][serde_json].
|
|
pub struct PhantomConst<T: ?Sized + PhantomConstValue = PhantomConstCanonicalValue> {
|
|
value: LazyInterned<T>,
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
|
|
pub struct PhantomConstWithoutGenerics;
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
pub const PhantomConst: PhantomConstWithoutGenerics = PhantomConstWithoutGenerics;
|
|
|
|
impl<T: Type + PhantomConstValue> Index<T> for PhantomConstWithoutGenerics {
|
|
type Output = PhantomConst<T>;
|
|
|
|
fn index(&self, value: T) -> &Self::Output {
|
|
Interned::into_inner(PhantomConst::new(value.intern()).intern_sized())
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> fmt::Debug for PhantomConst<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_tuple("PhantomConst").field(&self.get()).finish()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Clone for PhantomConst<T> {
|
|
fn clone(&self) -> Self {
|
|
*self
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Copy for PhantomConst<T> {}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> PartialEq for PhantomConst<T> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.get() == other.get()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Eq for PhantomConst<T> {}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Hash for PhantomConst<T> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.get().hash(state);
|
|
}
|
|
}
|
|
|
|
struct PhantomConstCanonicalMemoize<T: ?Sized, const IS_FROM_CANONICAL: bool>(PhantomData<T>);
|
|
|
|
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Copy
|
|
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
|
|
{
|
|
}
|
|
|
|
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Clone
|
|
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
|
|
{
|
|
fn clone(&self) -> Self {
|
|
*self
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Eq
|
|
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
|
|
{
|
|
}
|
|
|
|
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> PartialEq
|
|
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
|
|
{
|
|
fn eq(&self, _other: &Self) -> bool {
|
|
true
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Hash
|
|
for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
|
|
{
|
|
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Memoize for PhantomConstCanonicalMemoize<T, false> {
|
|
type Input = Interned<T>;
|
|
type InputOwned = Interned<T>;
|
|
type Output = Interned<PhantomConstCanonicalValue>;
|
|
|
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
|
Intern::intern_sized(PhantomConstCanonicalValue::from_json_value(
|
|
serde_json::to_value(input)
|
|
.expect("serialization failed when constructing a canonical PhantomConst"),
|
|
))
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Memoize for PhantomConstCanonicalMemoize<T, true> {
|
|
type Input = Interned<PhantomConstCanonicalValue>;
|
|
type InputOwned = Interned<PhantomConstCanonicalValue>;
|
|
type Output = Interned<T>;
|
|
|
|
fn inner(self, input: &Self::Input) -> Self::Output {
|
|
PhantomConstValue::deserialize_value(input.as_json_value())
|
|
.expect("deserialization failed ")
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> PhantomConst<T> {
|
|
pub fn new(value: Interned<T>) -> Self {
|
|
Self {
|
|
value: LazyInterned::Interned(value),
|
|
}
|
|
}
|
|
pub const fn new_lazy(v: &'static dyn LazyInternedTrait<T>) -> Self {
|
|
Self {
|
|
value: LazyInterned::new_lazy(v),
|
|
}
|
|
}
|
|
pub fn get(self) -> Interned<T> {
|
|
self.value.interned()
|
|
}
|
|
pub fn type_properties(self) -> TypeProperties {
|
|
<()>::TYPE_PROPERTIES
|
|
}
|
|
pub fn can_connect(self, other: Self) -> bool {
|
|
self == other
|
|
}
|
|
pub fn canonical_phantom_const(self) -> PhantomConst {
|
|
if let Some(&retval) = <dyn Any>::downcast_ref::<PhantomConst>(&self) {
|
|
return retval;
|
|
}
|
|
<PhantomConst>::new(
|
|
PhantomConstCanonicalMemoize::<T, false>(PhantomData).get_owned(self.get()),
|
|
)
|
|
}
|
|
pub fn from_canonical_phantom_const(canonical_type: PhantomConst) -> Self {
|
|
if let Some(&retval) = <dyn Any>::downcast_ref::<Self>(&canonical_type) {
|
|
return retval;
|
|
}
|
|
Self::new(
|
|
PhantomConstCanonicalMemoize::<T, true>(PhantomData).get_owned(canonical_type.get()),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
|
|
type BaseType = PhantomConst;
|
|
type MaskType = ();
|
|
type SimValue = PhantomConst<T>;
|
|
impl_match_variant_as_self!();
|
|
|
|
fn mask_type(&self) -> Self::MaskType {
|
|
()
|
|
}
|
|
|
|
fn canonical(&self) -> CanonicalType {
|
|
CanonicalType::PhantomConst(self.canonical_phantom_const())
|
|
}
|
|
|
|
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
|
let CanonicalType::PhantomConst(phantom_const) = canonical_type else {
|
|
panic!("expected PhantomConst");
|
|
};
|
|
Self::from_canonical_phantom_const(phantom_const)
|
|
}
|
|
|
|
fn source_location() -> SourceLocation {
|
|
SourceLocation::builtin()
|
|
}
|
|
|
|
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
|
|
assert!(opaque.is_empty());
|
|
*self
|
|
}
|
|
|
|
fn sim_value_clone_from_opaque(
|
|
&self,
|
|
value: &mut Self::SimValue,
|
|
opaque: OpaqueSimValueSlice<'_>,
|
|
) {
|
|
assert!(opaque.is_empty());
|
|
assert_eq!(*value, *self);
|
|
}
|
|
|
|
fn sim_value_to_opaque<'w>(
|
|
&self,
|
|
value: &Self::SimValue,
|
|
writer: OpaqueSimValueWriter<'w>,
|
|
) -> OpaqueSimValueWritten<'w> {
|
|
assert_eq!(*value, *self);
|
|
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Default for PhantomConst<T>
|
|
where
|
|
Interned<T>: Default,
|
|
{
|
|
fn default() -> Self {
|
|
Self::TYPE
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> StaticType for PhantomConst<T>
|
|
where
|
|
Interned<T>: Default,
|
|
{
|
|
const TYPE: Self = PhantomConst {
|
|
value: LazyInterned::new_lazy(&Interned::<T>::default),
|
|
};
|
|
const MASK_TYPE: Self::MaskType = ();
|
|
const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
|
|
const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
|
|
}
|
|
|
|
type SerdeType<T> = SerdeCanonicalType<CanonicalType, SerdePhantomConst<Interned<T>>>;
|
|
|
|
impl<T: ?Sized + PhantomConstValue> Serialize for PhantomConst<T> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
SerdeType::<T>::PhantomConst(SerdePhantomConst(self.get())).serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
match SerdeType::<T>::deserialize(deserializer)? {
|
|
SerdeCanonicalType::PhantomConst(SerdePhantomConst(value)) => Ok(Self::new(value)),
|
|
ty => Err(Error::invalid_value(
|
|
serde::de::Unexpected::Other(ty.as_serde_unexpected_str()),
|
|
&"a PhantomConst",
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> ExprPartialEq<Self> for PhantomConst<T> {
|
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
|
true.to_expr()
|
|
}
|
|
|
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
|
false.to_expr()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> ExprPartialOrd<Self> for PhantomConst<T> {
|
|
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
|
false.to_expr()
|
|
}
|
|
|
|
fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
|
true.to_expr()
|
|
}
|
|
|
|
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
|
false.to_expr()
|
|
}
|
|
|
|
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
|
true.to_expr()
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> SimValuePartialEq<Self> for PhantomConst<T> {
|
|
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
|
assert_eq!(SimValue::ty(this), SimValue::ty(other));
|
|
true
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> ToSimValue for PhantomConst<T> {
|
|
type Type = PhantomConst<T>;
|
|
|
|
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
|
SimValue::from_value(*self, *self)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<PhantomConst<T>> for PhantomConst<T> {
|
|
fn to_sim_value_with_type(&self, ty: PhantomConst<T>) -> SimValue<PhantomConst<T>> {
|
|
SimValue::from_value(ty, *self)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<CanonicalType> for PhantomConst<T> {
|
|
fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
|
SimValue::into_canonical(SimValue::from_value(Self::from_canonical(ty), *self))
|
|
}
|
|
}
|
|
|
|
mod sealed {
|
|
pub trait Sealed<T: ?Sized> {}
|
|
}
|
|
|
|
pub trait PhantomConstGet<T: ?Sized + PhantomConstValue>: sealed::Sealed<T> {
|
|
fn get(&self) -> Interned<T>;
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue, This: ?Sized + std::ops::Deref<Target: PhantomConstGet<T>>>
|
|
sealed::Sealed<T> for This
|
|
{
|
|
}
|
|
|
|
impl<T: ?Sized + PhantomConstValue, This: ?Sized + std::ops::Deref<Target: PhantomConstGet<T>>>
|
|
PhantomConstGet<T> for This
|
|
{
|
|
fn get(&self) -> Interned<T> {
|
|
This::Target::get(&**self)
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_phantom_const_get {
|
|
(
|
|
impl PhantomConstGet<$T:ident> for $ty:ty {
|
|
fn $get:ident(&$get_self:ident) -> _ $get_body:block
|
|
}
|
|
) => {
|
|
impl<$T: ?Sized + PhantomConstValue> sealed::Sealed<$T> for $ty {}
|
|
|
|
impl<$T: ?Sized + PhantomConstValue> PhantomConstGet<$T> for $ty {
|
|
fn $get(&$get_self) -> Interned<$T> $get_body
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_phantom_const_get! {
|
|
impl PhantomConstGet<T> for PhantomConst<T> {
|
|
fn get(&self) -> _ {
|
|
PhantomConst::get(*self)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl_phantom_const_get! {
|
|
impl PhantomConstGet<T> for Expr<PhantomConst<T>> {
|
|
fn get(&self) -> _ {
|
|
PhantomConst::get(Expr::ty(*self))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub trait ReturnSelfUnchanged<T: ?Sized> {
|
|
type Type: ?Sized;
|
|
}
|
|
|
|
impl<This: ?Sized, T: ?Sized> ReturnSelfUnchanged<T> for This {
|
|
type Type = This;
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub fn type_alias_phantom_const_get_helper<T: ?Sized + PhantomConstValue, R: Intern + Clone>(
|
|
param: impl PhantomConstGet<T>,
|
|
get: impl FnOnce(Interned<T>) -> R,
|
|
) -> &'static R {
|
|
Interned::into_inner(get(param.get()).intern_sized())
|
|
}
|