use crate::{
array::Array,
bundle::Bundle,
clock::Clock,
enum_::Enum,
expr::Expr,
int::{Bool, SInt, UInt},
intern::{Intern, Interned},
reset::{AsyncReset, Reset, SyncReset},
source_location::SourceLocation,
};
use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index};
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub struct TypeProperties {
pub is_passive: bool,
pub is_storable: bool,
pub is_castable_from_bits: bool,
pub bit_width: usize,
}
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum CanonicalType {
UInt(UInt),
SInt(SInt),
Bool(Bool),
Array(Array),
Enum(Enum),
Bundle(Bundle),
AsyncReset(AsyncReset),
SyncReset(SyncReset),
Reset(Reset),
Clock(Clock),
}
impl fmt::Debug for CanonicalType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UInt(v) => v.fmt(f),
Self::SInt(v) => v.fmt(f),
Self::Bool(v) => v.fmt(f),
Self::Array(v) => v.fmt(f),
Self::Enum(v) => v.fmt(f),
Self::Bundle(v) => v.fmt(f),
Self::AsyncReset(v) => v.fmt(f),
Self::SyncReset(v) => v.fmt(f),
Self::Reset(v) => v.fmt(f),
Self::Clock(v) => v.fmt(f),
}
}
}
impl CanonicalType {
pub fn type_properties(self) -> TypeProperties {
match self {
CanonicalType::UInt(v) => v.type_properties(),
CanonicalType::SInt(v) => v.type_properties(),
CanonicalType::Bool(v) => v.type_properties(),
CanonicalType::Array(v) => v.type_properties(),
CanonicalType::Enum(v) => v.type_properties(),
CanonicalType::Bundle(v) => v.type_properties(),
CanonicalType::AsyncReset(v) => v.type_properties(),
CanonicalType::SyncReset(v) => v.type_properties(),
CanonicalType::Reset(v) => v.type_properties(),
CanonicalType::Clock(v) => v.type_properties(),
}
}
pub fn is_passive(self) -> bool {
self.type_properties().is_passive
}
pub fn is_storable(self) -> bool {
self.type_properties().is_storable
}
pub fn is_castable_from_bits(self) -> bool {
self.type_properties().is_castable_from_bits
}
pub fn bit_width(self) -> usize {
self.type_properties().bit_width
}
pub fn can_connect(self, rhs: Self) -> bool {
match self {
CanonicalType::UInt(lhs) => {
let CanonicalType::UInt(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::SInt(lhs) => {
let CanonicalType::SInt(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::Bool(lhs) => {
let CanonicalType::Bool(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::Array(lhs) => {
let CanonicalType::Array(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::Enum(lhs) => {
let CanonicalType::Enum(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::Bundle(lhs) => {
let CanonicalType::Bundle(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::AsyncReset(lhs) => {
let CanonicalType::AsyncReset(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::SyncReset(lhs) => {
let CanonicalType::SyncReset(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::Reset(lhs) => {
let CanonicalType::Reset(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
CanonicalType::Clock(lhs) => {
let CanonicalType::Clock(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
}
}
}
pub trait MatchVariantAndInactiveScope: Sized {
type MatchVariant: 'static + Send + Sync;
type MatchActiveScope;
fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope);
}
#[derive(Debug)]
pub struct MatchVariantWithoutScope<T: 'static + Send + Sync>(pub T);
impl<T: 'static + Send + Sync> MatchVariantAndInactiveScope for MatchVariantWithoutScope<T> {
type MatchVariant = T;
type MatchActiveScope = ();
fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope) {
(self.0, ())
}
}
pub trait FillInDefaultedGenerics {
type Type: Type;
fn fill_in_defaulted_generics(self) -> Self::Type;
}
impl<T: Type> FillInDefaultedGenerics for T {
type Type = T;
fn fill_in_defaulted_generics(self) -> Self::Type {
self
}
}
mod sealed {
pub trait TypeOrDefaultSealed {}
pub trait BaseTypeSealed {}
}
macro_rules! impl_base_type {
($name:ident) => {
impl BaseType for $name {}
impl sealed::BaseTypeSealed for $name {}
impl From<$name> for CanonicalType {
fn from(ty: $name) -> Self {
Self::$name(ty)
}
}
};
}
impl_base_type!(UInt);
impl_base_type!(SInt);
impl_base_type!(Bool);
impl_base_type!(Array);
impl_base_type!(Enum);
impl_base_type!(Bundle);
impl_base_type!(AsyncReset);
impl_base_type!(SyncReset);
impl_base_type!(Reset);
impl_base_type!(Clock);
impl sealed::BaseTypeSealed for CanonicalType {}
impl BaseType for CanonicalType {}
pub trait TypeOrDefault<D: Type>:
sealed::TypeOrDefaultSealed + Copy + Eq + Hash + fmt::Debug
{
type Type: Type;
fn get<F: FnOnce() -> D>(self, default: F) -> Self::Type;
}
impl<T: Type> sealed::TypeOrDefaultSealed for T {}
impl<T: Type, D: Type> TypeOrDefault<D> for T {
type Type = T;
fn get<F: FnOnce() -> D>(self, _default: F) -> Self::Type {
self
}
}
impl sealed::TypeOrDefaultSealed for crate::__ {}
impl<D: Type> TypeOrDefault<D> for crate::__ {
type Type = D;
fn get<F: FnOnce() -> D>(self, default: F) -> Self::Type {
default()
}
}
pub trait Type:
Copy + Hash + Eq + fmt::Debug + Send + Sync + 'static + FillInDefaultedGenerics<Type = Self>
{
type BaseType: BaseType;
type MaskType: Type<MaskType = Self::MaskType>;
type MatchVariant: 'static + Send + Sync;
type MatchActiveScope;
type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope<
MatchVariant = Self::MatchVariant,
MatchActiveScope = Self::MatchActiveScope,
>;
type MatchVariantsIter: Iterator<Item = Self::MatchVariantAndInactiveScope>
+ ExactSizeIterator
+ FusedIterator
+ DoubleEndedIterator;
#[track_caller]
fn match_variants(this: Expr<Self>, source_location: SourceLocation)
-> Self::MatchVariantsIter;
fn mask_type(&self) -> Self::MaskType;
fn canonical(&self) -> CanonicalType;
fn from_canonical(canonical_type: CanonicalType) -> Self;
fn source_location() -> SourceLocation;
}
pub trait BaseType: Type<BaseType = Self> + sealed::BaseTypeSealed + Into<CanonicalType> {}
macro_rules! impl_match_variant_as_self {
() => {
type MatchVariant = crate::expr::Expr<Self>;
type MatchActiveScope = ();
type MatchVariantAndInactiveScope = crate::ty::MatchVariantWithoutScope<Self::MatchVariant>;
type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
fn match_variants(
this: crate::expr::Expr<Self>,
source_location: crate::source_location::SourceLocation,
) -> Self::MatchVariantsIter {
let _ = source_location;
std::iter::once(crate::ty::MatchVariantWithoutScope(this))
}
};
}
pub(crate) use impl_match_variant_as_self;
pub trait TypeWithDeref: Type {
fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant;
}
impl Type for CanonicalType {
type BaseType = CanonicalType;
type MaskType = CanonicalType;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
match self {
CanonicalType::UInt(v) => v.mask_type().canonical(),
CanonicalType::SInt(v) => v.mask_type().canonical(),
CanonicalType::Bool(v) => v.mask_type().canonical(),
CanonicalType::Array(v) => v.mask_type().canonical(),
CanonicalType::Enum(v) => v.mask_type().canonical(),
CanonicalType::Bundle(v) => v.mask_type().canonical(),
CanonicalType::AsyncReset(v) => v.mask_type().canonical(),
CanonicalType::SyncReset(v) => v.mask_type().canonical(),
CanonicalType::Reset(v) => v.mask_type().canonical(),
CanonicalType::Clock(v) => v.mask_type().canonical(),
}
}
fn canonical(&self) -> CanonicalType {
*self
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
canonical_type
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
}
pub trait StaticType: Type {
const TYPE: Self;
const MASK_TYPE: Self::MaskType;
const TYPE_PROPERTIES: TypeProperties;
const MASK_TYPE_PROPERTIES: TypeProperties;
}
pub type AsMask<T> = <T as Type>::MaskType;
pub struct AsMaskWithoutGenerics;
#[allow(non_upper_case_globals)]
pub const AsMask: AsMaskWithoutGenerics = AsMaskWithoutGenerics;
impl<T: Type> Index<T> for AsMaskWithoutGenerics {
type Output = T::MaskType;
fn index(&self, ty: T) -> &Self::Output {
Interned::into_inner(Intern::intern_sized(ty.mask_type()))
}
}