diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs index ca06c0b..605f662 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs @@ -1096,11 +1096,9 @@ impl Visitor<'_> { let (#(#bindings,)*) = { type __MatchTy = ::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 = ::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)* } diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs index 8d70d21..065e5de 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs @@ -95,7 +95,23 @@ //! } //! //! #[hdl] -//! fn destructure_to_sim_value<'a, T: Type>(v: impl ToSimValue>) { +//! fn destructure_inner(v: as Type>::SimValue) { +//! #[hdl(sim)] +//! let MyStruct:: { +//! a, +//! mut b, +//! c, +//! } = v; +//! +//! // that gives these types: +//! let _: SimValue> = a; +//! let _: SimValue = b; +//! let _: SimValue = c; +//! *b = false; // can modify b since mut was used +//! } +//! +//! #[hdl] +//! fn destructure_inner_ref<'a, T: Type>(v: &'a as Type>::SimValue) { //! #[hdl(sim)] //! let MyStruct:: { //! a, @@ -104,8 +120,25 @@ //! } = v; //! //! // that gives these types: -//! let _: SimValue> = a; -//! let _: SimValue = b; -//! let _: SimValue = c; +//! let _: &'a SimValue> = a; +//! let _: &'a SimValue = b; +//! let _: &'a SimValue = c; +//! } +//! +//! #[hdl] +//! fn destructure_inner_mut<'a, T: Type>(v: &'a mut as Type>::SimValue) { +//! #[hdl(sim)] +//! let MyStruct:: { +//! 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> = a; +//! let _: &'a mut SimValue = b; +//! let _: &'a mut SimValue = c; //! } //! ``` diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs index accd3d7..9e2d41d 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs @@ -72,15 +72,47 @@ //! } //! //! #[hdl] -//! fn match_to_sim_value<'a, T: Type>(v: impl ToSimValue>) { +//! fn match_inner_move(v: as Type>::SimValue) -> String { //! #[hdl(sim)] //! match v { -//! MyEnum::::A => println!("got A"), -//! MyEnum::::B(b) => { +//! MyEnum::::A => String::from("got A"), +//! MyEnum::::B(mut b) => { //! let _: SimValue = 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 as Type>::SimValue) -> u32 { +//! #[hdl(sim)] +//! match v { +//! MyEnum::::A => 1, +//! MyEnum::::B(b) => { +//! let _: &'a SimValue = b; // b has this type +//! println!("got B({b})"); +//! 5 +//! } +//! _ => 42, +//! } +//! } +//! +//! #[hdl] +//! fn match_inner_mut<'a, T: Type>(v: &'a mut as Type>::SimValue) -> Option<&'a mut SimValue> { +//! #[hdl(sim)] +//! match v { +//! MyEnum::::A => None, +//! MyEnum::::B(b) => { +//! println!("got B({b})"); +//! **b = true; // you can modify v by modifying b which borrows from it +//! let _: &'a mut SimValue = b; // b has this type +//! None +//! } +//! MyEnum::::C(v) => Some(v), // you can return matched values +//! _ => None, // HDL enums can have invalid discriminants, so we need this extra match arm //! } //! } //! ``` diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index a127878..eaa3f8d 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -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(MatchSimValueHelperCheckMutSimValue); + pub struct MatchSimValueHelperCheckMutSimValue(MatchSimValueHelperCheckRefSimValue); + pub struct MatchSimValueHelperCheckRefSimValue(MatchSimValueHelperCheckRefRefSimValue); + pub struct MatchSimValueHelperCheckRefRefSimValue(MatchSimValueHelperCheckRefMutSimValue); + pub struct MatchSimValueHelperCheckRefMutSimValue(MatchSimValueHelperCheckMutRefSimValue); + pub struct MatchSimValueHelperCheckMutRefSimValue(MatchSimValueHelperCheckMutMutSimValue); + pub struct MatchSimValueHelperCheckMutMutSimValue(MatchSimValueHelperIdentity); + } + + impl MatchSimValueHelperCheckSimValue> { + #[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> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue { + self.take() + } + } + + impl<'a, T: Type> MatchSimValueHelperCheckRefSimValue<&'a SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue { + self.take() + } + } + + impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefRefSimValue<&'a &'b SimValue> { + #[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> { + #[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> { + #[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> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue { + self.take() + } + } #[doc(hidden)] - pub struct MatchSimValueHelper(Option); + pub struct MatchSimValueHelperIdentity(Option); - impl MatchSimValueHelper { - pub fn new(v: T) -> Self { + impl MatchSimValueHelperIdentity { + 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 MatchSimValue for MatchSimValueHelper> { - 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> { - 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> { - 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 = 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 = 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 = 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 = 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 MatchSimValueFallback for MatchSimValueHelper { - type MatchValue = ::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 = MatchSimValueHelperCheckSimValue; } pub trait ToSimValue: ToSimValueWithType<::Type> + ValueType {