redo #[hdl(sim)] match/let destructuring to support matching values of type Type::SimValue #72
4 changed files with 183 additions and 116 deletions
|
|
@ -1096,11 +1096,9 @@ impl Visitor<'_> {
|
|||
let (#(#bindings,)*) = {
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_value = #expr;
|
||||
let __match_value = {
|
||||
use ::fayalite::sim::value::match_sim_value::*;
|
||||
// use method syntax to deduce the correct trait to call
|
||||
::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value()
|
||||
};
|
||||
// use method syntax to deduce what type to convert to
|
||||
let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value)
|
||||
.__fayalite_match_sim_value();
|
||||
#let_token #pat #eq_token __match_value #semi_token
|
||||
(#(#bindings_idents,)*)
|
||||
};
|
||||
|
|
@ -1172,11 +1170,9 @@ impl Visitor<'_> {
|
|||
{
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_value = #expr;
|
||||
let __match_value = {
|
||||
use ::fayalite::sim::value::match_sim_value::*;
|
||||
// use method syntax to deduce the correct trait to call
|
||||
::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value()
|
||||
};
|
||||
// use method syntax to deduce what type to convert to
|
||||
let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value)
|
||||
.__fayalite_match_sim_value();
|
||||
#match_token __match_value {
|
||||
#(#arms)*
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,23 @@
|
|||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_to_sim_value<'a, T: Type>(v: impl ToSimValue<Type = MyStruct<T>>) {
|
||||
//! fn destructure_inner<T: Type>(v: <MyStruct<T> as Type>::SimValue) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! mut b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: SimValue<UInt<8>> = a;
|
||||
//! let _: SimValue<Bool> = b;
|
||||
//! let _: SimValue<T> = c;
|
||||
//! *b = false; // can modify b since mut was used
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_inner_ref<'a, T: Type>(v: &'a <MyStruct<T> as Type>::SimValue) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
|
|
@ -104,8 +120,25 @@
|
|||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: SimValue<UInt<8>> = a;
|
||||
//! let _: SimValue<Bool> = b;
|
||||
//! let _: SimValue<T> = c;
|
||||
//! let _: &'a SimValue<UInt<8>> = a;
|
||||
//! let _: &'a SimValue<Bool> = b;
|
||||
//! let _: &'a SimValue<T> = c;
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_inner_mut<'a, T: Type>(v: &'a mut <MyStruct<T> as Type>::SimValue) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! **b = true; // you can modify v by modifying b which borrows from it
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: &'a mut SimValue<UInt<8>> = a;
|
||||
//! let _: &'a mut SimValue<Bool> = b;
|
||||
//! let _: &'a mut SimValue<T> = c;
|
||||
//! }
|
||||
//! ```
|
||||
|
|
|
|||
|
|
@ -72,15 +72,47 @@
|
|||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_to_sim_value<'a, T: Type>(v: impl ToSimValue<Type = MyEnum<T>>) {
|
||||
//! fn match_inner_move<T: Type>(v: <MyEnum<T> as Type>::SimValue) -> String {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => println!("got A"),
|
||||
//! MyEnum::<T>::B(b) => {
|
||||
//! MyEnum::<T>::A => String::from("got A"),
|
||||
//! MyEnum::<T>::B(mut b) => {
|
||||
//! let _: SimValue<Bool> = b; // b has this type
|
||||
//! println!("got B({b})");
|
||||
//! let text = format!("got B({b})");
|
||||
//! *b = true; // can modify b since mut was used
|
||||
//! text
|
||||
//! }
|
||||
//! _ => println!("something else"),
|
||||
//! _ => String::from("something else"),
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_inner_ref<'a, T: Type>(v: &'a <MyEnum<T> as Type>::SimValue) -> u32 {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => 1,
|
||||
//! MyEnum::<T>::B(b) => {
|
||||
//! let _: &'a SimValue<Bool> = b; // b has this type
|
||||
//! println!("got B({b})");
|
||||
//! 5
|
||||
//! }
|
||||
//! _ => 42,
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_inner_mut<'a, T: Type>(v: &'a mut <MyEnum<T> as Type>::SimValue) -> Option<&'a mut SimValue<T>> {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => None,
|
||||
//! MyEnum::<T>::B(b) => {
|
||||
//! println!("got B({b})");
|
||||
//! **b = true; // you can modify v by modifying b which borrows from it
|
||||
//! let _: &'a mut SimValue<Bool> = b; // b has this type
|
||||
//! None
|
||||
//! }
|
||||
//! MyEnum::<T>::C(v) => Some(v), // you can return matched values
|
||||
//! _ => None, // HDL enums can have invalid discriminants, so we need this extra match arm
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
|
|
|||
|
|
@ -552,113 +552,119 @@ impl_sim_value_cmp_as_bool!(AsyncReset);
|
|||
|
||||
#[doc(hidden)]
|
||||
pub mod match_sim_value {
|
||||
use crate::{
|
||||
sim::value::{SimValue, ToSimValue},
|
||||
ty::Type,
|
||||
};
|
||||
use crate::{sim::value::SimValue, ty::Type};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
macro_rules! wrapper {
|
||||
(
|
||||
$(pub struct $wrapper:ident<$T:ident>($inner:ty);)*
|
||||
) => {
|
||||
$(#[doc(hidden)]
|
||||
pub struct $wrapper<$T>($inner);
|
||||
|
||||
impl<$T> $wrapper<$T> {
|
||||
#[inline(always)]
|
||||
pub fn new(value: $T) -> Self {
|
||||
Self(<$inner>::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<$T> Deref for $wrapper<$T> {
|
||||
type Target = $inner;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<$T> DerefMut for $wrapper<$T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
wrapper! {
|
||||
pub struct MatchSimValueHelperCheckSimValue<T>(MatchSimValueHelperCheckMutSimValue<T>);
|
||||
pub struct MatchSimValueHelperCheckMutSimValue<T>(MatchSimValueHelperCheckRefSimValue<T>);
|
||||
pub struct MatchSimValueHelperCheckRefSimValue<T>(MatchSimValueHelperCheckRefRefSimValue<T>);
|
||||
pub struct MatchSimValueHelperCheckRefRefSimValue<T>(MatchSimValueHelperCheckRefMutSimValue<T>);
|
||||
pub struct MatchSimValueHelperCheckRefMutSimValue<T>(MatchSimValueHelperCheckMutRefSimValue<T>);
|
||||
pub struct MatchSimValueHelperCheckMutRefSimValue<T>(MatchSimValueHelperCheckMutMutSimValue<T>);
|
||||
pub struct MatchSimValueHelperCheckMutMutSimValue<T>(MatchSimValueHelperIdentity<T>);
|
||||
}
|
||||
|
||||
impl<T: Type> MatchSimValueHelperCheckSimValue<SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> T::SimValue {
|
||||
SimValue::into_value(self.take())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Type> MatchSimValueHelperCheckMutSimValue<&'a mut SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Type> MatchSimValueHelperCheckRefSimValue<&'a SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefRefSimValue<&'a &'b SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> &'b T::SimValue {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefMutSimValue<&'a &'b mut SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T: Type> MatchSimValueHelperCheckMutRefSimValue<&'a mut &'b SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> &'b T::SimValue {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T: Type> MatchSimValueHelperCheckMutMutSimValue<&'a mut &'b mut SimValue<T>> {
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct MatchSimValueHelper<T>(Option<T>);
|
||||
pub struct MatchSimValueHelperIdentity<T>(Option<T>);
|
||||
|
||||
impl<T> MatchSimValueHelper<T> {
|
||||
pub fn new(v: T) -> Self {
|
||||
impl<T> MatchSimValueHelperIdentity<T> {
|
||||
fn new(v: T) -> Self {
|
||||
Self(Some(v))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait MatchSimValue {
|
||||
type MatchValue;
|
||||
|
||||
/// use `self` so it comes first in the method resolution order
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<T: Type> MatchSimValue for MatchSimValueHelper<SimValue<T>> {
|
||||
type MatchValue = T::SimValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
SimValue::into_value(self.0.expect("should be Some"))
|
||||
#[inline(always)]
|
||||
fn take(&mut self) -> T {
|
||||
self.0.take().expect("known to be Some")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Type> MatchSimValue for MatchSimValueHelper<&'a SimValue<T>> {
|
||||
type MatchValue = &'a T::SimValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
SimValue::value(self.0.expect("should be Some"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Type> MatchSimValue for MatchSimValueHelper<&'a mut SimValue<T>> {
|
||||
type MatchValue = &'a mut T::SimValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
SimValue::value_mut(self.0.expect("should be Some"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'_ &'a T>
|
||||
where
|
||||
MatchSimValueHelper<&'a T>: MatchSimValue,
|
||||
{
|
||||
type MatchValue = <MatchSimValueHelper<&'a T> as MatchSimValue>::MatchValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| *v)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'_ mut &'a T>
|
||||
where
|
||||
MatchSimValueHelper<&'a T>: MatchSimValue,
|
||||
{
|
||||
type MatchValue = <MatchSimValueHelper<&'a T> as MatchSimValue>::MatchValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| *v)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'a &'_ mut T>
|
||||
where
|
||||
MatchSimValueHelper<&'a T>: MatchSimValue,
|
||||
{
|
||||
type MatchValue = <MatchSimValueHelper<&'a T> as MatchSimValue>::MatchValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| &**v)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'a mut &'_ mut T>
|
||||
where
|
||||
MatchSimValueHelper<&'a mut T>: MatchSimValue,
|
||||
{
|
||||
type MatchValue = <MatchSimValueHelper<&'a mut T> as MatchSimValue>::MatchValue;
|
||||
|
||||
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
|
||||
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| &mut **v)))
|
||||
#[inline(always)]
|
||||
pub fn __fayalite_match_sim_value(&mut self) -> T {
|
||||
self.take()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait MatchSimValueFallback {
|
||||
type MatchValue;
|
||||
|
||||
/// use `&mut self` so it comes later in the method resolution order than MatchSimValue
|
||||
fn __fayalite_match_sim_value(&mut self) -> Self::MatchValue;
|
||||
}
|
||||
|
||||
impl<T: ToSimValue> MatchSimValueFallback for MatchSimValueHelper<T> {
|
||||
type MatchValue = <T::Type as Type>::SimValue;
|
||||
|
||||
fn __fayalite_match_sim_value(&mut self) -> Self::MatchValue {
|
||||
SimValue::into_value(self.0.take().expect("should be Some").into_sim_value())
|
||||
}
|
||||
}
|
||||
pub type MatchSimValueHelper<T> = MatchSimValueHelperCheckSimValue<T>;
|
||||
}
|
||||
|
||||
pub trait ToSimValue: ToSimValueWithType<<Self as ValueType>::Type> + ValueType {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue