support Rust's default binding modes when destructuring with #[hdl(sim)] let/match
This commit is contained in:
parent
053c1b2b10
commit
2817cd3d58
6 changed files with 371 additions and 70 deletions
|
|
@ -88,6 +88,9 @@ impl Visitor<'_> {
|
|||
field.expr = parse_quote_spanned! {field.member.span()=>
|
||||
::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr))
|
||||
};
|
||||
field
|
||||
.colon_token
|
||||
.get_or_insert(Token));
|
||||
}
|
||||
return parse_quote_spanned! {name_span=>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt, format_ident, quote_spanned};
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::BTreeMap;
|
||||
use syn::{
|
||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr,
|
||||
PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment,
|
||||
|
|
@ -24,65 +24,65 @@ use syn::{
|
|||
|
||||
macro_rules! visit_trait {
|
||||
(
|
||||
$($vis:vis fn $fn:ident($state:ident: _, $value:ident: &$Value:ty) $block:block)*
|
||||
$($vis:vis fn $fn:ident($state:ident: _, $value:ident: &mut $Value:ty) $block:block)*
|
||||
) => {
|
||||
trait VisitMatchPat<'a> {
|
||||
$(fn $fn(&mut self, $value: &'a $Value) {
|
||||
$(fn $fn(&mut self, $value: &'a mut $Value) {
|
||||
$fn(self, $value);
|
||||
})*
|
||||
}
|
||||
|
||||
$($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a $Value) $block)*
|
||||
$($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a mut $Value) $block)*
|
||||
};
|
||||
}
|
||||
|
||||
visit_trait! {
|
||||
fn visit_match_pat_binding(_state: _, v: &MatchPatBinding) {
|
||||
let MatchPatBinding { ident: _ } = v;
|
||||
fn visit_match_pat_binding(_state: _, v: &mut MatchPatBinding) {
|
||||
let MatchPatBinding { mutability: _, ident: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_wild(_state: _, v: &MatchPatWild) {
|
||||
fn visit_match_pat_wild(_state: _, v: &mut MatchPatWild) {
|
||||
let MatchPatWild { underscore_token: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_rest(_state: _, v: &MatchPatRest) {
|
||||
fn visit_match_pat_rest(_state: _, v: &mut MatchPatRest) {
|
||||
let MatchPatRest { dot2_token: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_paren(state: _, v: &MatchPatParen<MatchPat>) {
|
||||
fn visit_match_pat_paren(state: _, v: &mut MatchPatParen<MatchPat>) {
|
||||
let MatchPatParen { paren_token: _, pat } = v;
|
||||
state.visit_match_pat(pat);
|
||||
}
|
||||
fn visit_match_pat_paren_simple(state: _, v: &MatchPatParen<MatchPatSimple>) {
|
||||
fn visit_match_pat_paren_simple(state: _, v: &mut MatchPatParen<MatchPatSimple>) {
|
||||
let MatchPatParen { paren_token: _, pat } = v;
|
||||
state.visit_match_pat_simple(pat);
|
||||
}
|
||||
fn visit_match_pat_or(state: _, v: &MatchPatOr<MatchPat>) {
|
||||
fn visit_match_pat_or(state: _, v: &mut MatchPatOr<MatchPat>) {
|
||||
let MatchPatOr { leading_vert: _, cases } = v;
|
||||
for v in cases {
|
||||
state.visit_match_pat(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_or_simple(state: _, v: &MatchPatOr<MatchPatSimple>) {
|
||||
fn visit_match_pat_or_simple(state: _, v: &mut MatchPatOr<MatchPatSimple>) {
|
||||
let MatchPatOr { leading_vert: _, cases } = v;
|
||||
for v in cases {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_struct_field(state: _, v: &MatchPatStructField) {
|
||||
fn visit_match_pat_struct_field(state: _, v: &mut MatchPatStructField) {
|
||||
let MatchPatStructField { field_name: _, colon_token: _, pat } = v;
|
||||
state.visit_match_pat_simple(pat);
|
||||
}
|
||||
fn visit_match_pat_struct(state: _, v: &MatchPatStruct) {
|
||||
fn visit_match_pat_struct(state: _, v: &mut MatchPatStruct) {
|
||||
let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v;
|
||||
for v in fields {
|
||||
state.visit_match_pat_struct_field(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_tuple(state: _, v: &MatchPatTuple) {
|
||||
fn visit_match_pat_tuple(state: _, v: &mut MatchPatTuple) {
|
||||
let MatchPatTuple { paren_token: _, fields } = v;
|
||||
for v in fields {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_enum_variant(state: _, v: &MatchPatEnumVariant) {
|
||||
fn visit_match_pat_enum_variant(state: _, v: &mut MatchPatEnumVariant) {
|
||||
let MatchPatEnumVariant {
|
||||
match_span:_,
|
||||
sim:_,
|
||||
|
|
@ -95,7 +95,7 @@ visit_trait! {
|
|||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_simple(state: _, v: &MatchPatSimple) {
|
||||
fn visit_match_pat_simple(state: _, v: &mut MatchPatSimple) {
|
||||
match v {
|
||||
MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v),
|
||||
MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v),
|
||||
|
|
@ -104,7 +104,7 @@ visit_trait! {
|
|||
MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v),
|
||||
}
|
||||
}
|
||||
fn visit_match_pat(state: _, v: &MatchPat) {
|
||||
fn visit_match_pat(state: _, v: &mut MatchPat) {
|
||||
match v {
|
||||
MatchPat::Simple(v) => state.visit_match_pat_simple(v),
|
||||
MatchPat::Or(v) => state.visit_match_pat_or(v),
|
||||
|
|
@ -118,13 +118,15 @@ visit_trait! {
|
|||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatBinding<> {
|
||||
mutability: Option<Token![mut]>,
|
||||
ident: Ident,
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPatBinding {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self { ident } = self;
|
||||
let Self { mutability, ident } = self;
|
||||
mutability.to_tokens(tokens);
|
||||
ident.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
|
@ -211,12 +213,20 @@ impl ToTokens for MatchPatStructField {
|
|||
colon_token,
|
||||
pat,
|
||||
} = self;
|
||||
field_name.to_tokens(tokens);
|
||||
if let (None, MatchPatSimple::Binding(MatchPatBinding { ident })) = (colon_token, pat) {
|
||||
if let (
|
||||
None,
|
||||
MatchPatSimple::Binding(MatchPatBinding {
|
||||
mutability: _,
|
||||
ident,
|
||||
}),
|
||||
) = (colon_token, pat)
|
||||
{
|
||||
if field_name == ident {
|
||||
pat.to_tokens(tokens);
|
||||
return;
|
||||
}
|
||||
}
|
||||
field_name.to_tokens(tokens);
|
||||
colon_token
|
||||
.unwrap_or_else(|| Token))
|
||||
.to_tokens(tokens);
|
||||
|
|
@ -450,7 +460,7 @@ trait ParseMatchPat: Sized {
|
|||
Pat::Ident(PatIdent {
|
||||
attrs: _,
|
||||
by_ref,
|
||||
mutability,
|
||||
mut mutability,
|
||||
ident,
|
||||
subpat,
|
||||
}) => {
|
||||
|
|
@ -459,10 +469,13 @@ trait ParseMatchPat: Sized {
|
|||
.errors
|
||||
.error(by_ref, "ref not allowed in #[hdl] patterns");
|
||||
}
|
||||
if let Some(mutability) = mutability {
|
||||
state
|
||||
.errors
|
||||
.error(mutability, "mut not allowed in #[hdl] patterns");
|
||||
if let Some(mut_token) = mutability {
|
||||
if state.sim.is_none() {
|
||||
state
|
||||
.errors
|
||||
.error(mut_token, "mut not allowed in #[hdl] patterns");
|
||||
mutability = None; // avoid duplicate errors
|
||||
}
|
||||
}
|
||||
if let Some((at_token, _)) = subpat {
|
||||
state
|
||||
|
|
@ -474,18 +487,26 @@ trait ParseMatchPat: Sized {
|
|||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
}) => Self::enum_variant(
|
||||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
),
|
||||
}) => {
|
||||
if let Some(mut_token) = mutability {
|
||||
state
|
||||
.errors
|
||||
.error(mut_token, "mut not allowed on unit variants");
|
||||
}
|
||||
Self::enum_variant(
|
||||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
Err(ident) => Ok(Self::simple(MatchPatSimple::Binding(MatchPatBinding {
|
||||
mutability,
|
||||
ident,
|
||||
}))),
|
||||
}
|
||||
|
|
@ -980,15 +1001,16 @@ struct HdlMatchParseState<'a> {
|
|||
|
||||
struct HdlLetPatVisitState<'a> {
|
||||
errors: &'a mut Errors,
|
||||
bindings: BTreeSet<&'a Ident>,
|
||||
bindings: BTreeMap<Ident, MatchPatBinding>,
|
||||
}
|
||||
|
||||
impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
||||
fn visit_match_pat_binding(&mut self, v: &'a MatchPatBinding) {
|
||||
self.bindings.insert(&v.ident);
|
||||
fn visit_match_pat_binding(&mut self, v: &'a mut MatchPatBinding) {
|
||||
self.bindings.insert(v.ident.clone(), v.clone());
|
||||
v.mutability = None;
|
||||
}
|
||||
|
||||
fn visit_match_pat_or(&mut self, v: &'a MatchPatOr<MatchPat>) {
|
||||
fn visit_match_pat_or(&mut self, v: &'a mut MatchPatOr<MatchPat>) {
|
||||
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||
self.errors.error(
|
||||
first_inner_vert,
|
||||
|
|
@ -998,7 +1020,7 @@ impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
|||
visit_match_pat_or(self, v);
|
||||
}
|
||||
|
||||
fn visit_match_pat_or_simple(&mut self, v: &'a MatchPatOr<MatchPatSimple>) {
|
||||
fn visit_match_pat_or_simple(&mut self, v: &'a mut MatchPatOr<MatchPatSimple>) {
|
||||
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||
self.errors.error(
|
||||
first_inner_vert,
|
||||
|
|
@ -1008,7 +1030,7 @@ impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
|||
visit_match_pat_or_simple(self, v);
|
||||
}
|
||||
|
||||
fn visit_match_pat_enum_variant(&mut self, v: &'a MatchPatEnumVariant) {
|
||||
fn visit_match_pat_enum_variant(&mut self, v: &'a mut MatchPatEnumVariant) {
|
||||
self.errors.error(v, "refutable pattern in let statement");
|
||||
}
|
||||
}
|
||||
|
|
@ -1048,7 +1070,7 @@ impl Visitor<'_> {
|
|||
.error(else_, "#[hdl] let ... else { ... } is not implemented");
|
||||
return empty_let();
|
||||
}
|
||||
let Ok(pat) = MatchPat::parse(
|
||||
let Ok(mut pat) = MatchPat::parse(
|
||||
&mut HdlMatchParseState {
|
||||
sim,
|
||||
match_span: span,
|
||||
|
|
@ -1060,20 +1082,27 @@ impl Visitor<'_> {
|
|||
};
|
||||
let mut state = HdlLetPatVisitState {
|
||||
errors: &mut self.errors,
|
||||
bindings: BTreeSet::new(),
|
||||
bindings: BTreeMap::new(),
|
||||
};
|
||||
state.visit_match_pat(&pat);
|
||||
state.visit_match_pat(&mut pat);
|
||||
let HdlLetPatVisitState {
|
||||
errors: _,
|
||||
bindings,
|
||||
} = state;
|
||||
let bindings_idents = bindings.keys();
|
||||
let bindings = bindings.values();
|
||||
let retval = if sim.is_some() {
|
||||
parse_quote_spanned! {span=>
|
||||
let (#(#bindings,)*) = {
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr));
|
||||
#let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token
|
||||
(#(#bindings,)*)
|
||||
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()
|
||||
};
|
||||
#let_token #pat #eq_token __match_value #semi_token
|
||||
(#(#bindings_idents,)*)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1105,7 +1134,7 @@ impl Visitor<'_> {
|
|||
__match_variant,
|
||||
);
|
||||
#let_token #pat #eq_token __match_variant #semi_token
|
||||
(#(#bindings,)* __scope,)
|
||||
(#(#bindings_idents,)* __scope,)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
@ -1142,8 +1171,13 @@ impl Visitor<'_> {
|
|||
quote_spanned! {span=>
|
||||
{
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr));
|
||||
#match_token ::fayalite::sim::value::SimValue::into_value(__match_expr) {
|
||||
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()
|
||||
};
|
||||
#match_token __match_value {
|
||||
#(#arms)*
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,3 +31,81 @@
|
|||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! You can also use `#[hdl(sim)] let` to destructure [`SimValue`]s (or anything that implements [`ToSimValue`]).
|
||||
//!
|
||||
//! [`SimValue`]: crate::sim::value::SimValue
|
||||
//! [`ToSimValue`]: crate::sim::value::ToSimValue
|
||||
//!
|
||||
//! ```
|
||||
//! # use fayalite::prelude::*;
|
||||
//! #[hdl]
|
||||
//! struct MyStruct<T> {
|
||||
//! a: UInt<8>,
|
||||
//! b: Bool,
|
||||
//! c: T,
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure<T: Type>(v: SimValue<MyStruct<T>>) {
|
||||
//! #[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_ref<'a, T: Type>(v: &'a SimValue<MyStruct<T>>) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: &'a SimValue<UInt<8>> = a;
|
||||
//! let _: &'a SimValue<Bool> = b;
|
||||
//! let _: &'a SimValue<T> = c;
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_mut<'a, T: Type>(v: &'a mut SimValue<MyStruct<T>>) {
|
||||
//! #[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;
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn destructure_to_sim_value<'a, T: Type>(v: impl ToSimValue<Type = MyStruct<T>>) {
|
||||
//! #[hdl(sim)]
|
||||
//! let MyStruct::<T> {
|
||||
//! a,
|
||||
//! b,
|
||||
//! c,
|
||||
//! } = v;
|
||||
//!
|
||||
//! // that gives these types:
|
||||
//! let _: SimValue<UInt<8>> = a;
|
||||
//! let _: SimValue<Bool> = b;
|
||||
//! let _: SimValue<T> = c;
|
||||
//! }
|
||||
//! ```
|
||||
|
|
|
|||
|
|
@ -9,3 +9,78 @@
|
|||
//!
|
||||
//! `#[hdl] match` statements can only match one level of struct/tuple/enum pattern for now,
|
||||
//! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`.
|
||||
//!
|
||||
//! You can also use `#[hdl(sim)] match` to match [`SimValue`]s (or anything that implements [`ToSimValue`]).
|
||||
//!
|
||||
//! `#[hdl(sim)] match` statements' bodies may have any type, unlike `#[hdl] match`.
|
||||
//!
|
||||
//! [`SimValue`]: crate::sim::value::SimValue
|
||||
//! [`ToSimValue`]: crate::sim::value::ToSimValue
|
||||
//!
|
||||
//! ```
|
||||
//! # use fayalite::prelude::*;
|
||||
//! #[hdl]
|
||||
//! enum MyEnum<T> {
|
||||
//! A,
|
||||
//! B(Bool),
|
||||
//! C(T),
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_move<T: Type>(v: SimValue<MyEnum<T>>) -> String {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => String::from("got A"),
|
||||
//! MyEnum::<T>::B(mut b) => {
|
||||
//! let _: SimValue<Bool> = b; // b has this type
|
||||
//! let text = format!("got B({b})");
|
||||
//! *b = true; // can modify b since mut was used
|
||||
//! text
|
||||
//! }
|
||||
//! _ => String::from("something else"),
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_ref<'a, T: Type>(v: &'a SimValue<MyEnum<T>>) -> 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_mut<'a, T: Type>(v: &'a mut SimValue<MyEnum<T>>) -> 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
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[hdl]
|
||||
//! fn match_to_sim_value<'a, T: Type>(v: impl ToSimValue<Type = MyEnum<T>>) {
|
||||
//! #[hdl(sim)]
|
||||
//! match v {
|
||||
//! MyEnum::<T>::A => println!("got A"),
|
||||
//! MyEnum::<T>::B(b) => {
|
||||
//! let _: SimValue<Bool> = b; // b has this type
|
||||
//! println!("got B({b})");
|
||||
//! }
|
||||
//! _ => println!("something else"),
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
|
|
|||
|
|
@ -492,6 +492,117 @@ impl SimValuePartialEq for AsyncReset {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod match_sim_value {
|
||||
use crate::{
|
||||
sim::value::{SimValue, ToSimValue},
|
||||
ty::Type,
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct MatchSimValueHelper<T>(Option<T>);
|
||||
|
||||
impl<T> MatchSimValueHelper<T> {
|
||||
pub 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"))
|
||||
}
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
#[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 trait ToSimValue: ToSimValueWithType<<Self as ToSimValue>::Type> {
|
||||
type Type: Type;
|
||||
|
||||
|
|
@ -624,7 +735,7 @@ impl<T: Type> ToSimValueWithType<T> for BitSlice {
|
|||
}
|
||||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue> ToSimValue for &'_ This {
|
||||
impl<'a, This: ?Sized + ToSimValue> ToSimValue for &'a This {
|
||||
type Type = This::Type;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
|
|
|
|||
|
|
@ -506,10 +506,10 @@ fn test_enums() {
|
|||
data_out: _,
|
||||
b_out: _,
|
||||
b2_out: _,
|
||||
} = expected;
|
||||
sim.write(sim.io().en, &en);
|
||||
sim.write(sim.io().which_in, &which_in);
|
||||
sim.write(sim.io().data_in, &data_in);
|
||||
} = &expected;
|
||||
sim.write(sim.io().en, en);
|
||||
sim.write(sim.io().which_in, which_in);
|
||||
sim.write(sim.io().data_in, data_in);
|
||||
let io = #[hdl(sim)]
|
||||
IO::<_> {
|
||||
en,
|
||||
|
|
@ -528,7 +528,7 @@ fn test_enums() {
|
|||
);
|
||||
// make sure matching on SimValue<SomeEnum> works
|
||||
#[hdl(sim)]
|
||||
match io.b_out {
|
||||
match &io.b_out {
|
||||
HdlNone => println!("io.b_out is HdlNone"),
|
||||
HdlSome(v) => println!("io.b_out is HdlSome(({:?}, {:?}))", *v.0, *v.1),
|
||||
}
|
||||
|
|
@ -706,13 +706,13 @@ fn test_memories() {
|
|||
w_en,
|
||||
w_data,
|
||||
w_mask,
|
||||
} = expected;
|
||||
sim.write(sim.io().r.addr, &r_addr);
|
||||
sim.write(sim.io().r.en, &r_en);
|
||||
sim.write(sim.io().w.addr, &w_addr);
|
||||
sim.write(sim.io().w.en, &w_en);
|
||||
sim.write(sim.io().w.data, &w_data);
|
||||
sim.write(sim.io().w.mask, &w_mask);
|
||||
} = &expected;
|
||||
sim.write(sim.io().r.addr, r_addr);
|
||||
sim.write(sim.io().r.en, r_en);
|
||||
sim.write(sim.io().w.addr, w_addr);
|
||||
sim.write(sim.io().w.en, w_en);
|
||||
sim.write(sim.io().w.data, w_data);
|
||||
sim.write(sim.io().w.mask, w_mask);
|
||||
let io = #[hdl(sim)]
|
||||
IO {
|
||||
r_addr,
|
||||
|
|
@ -1505,7 +1505,7 @@ fn test_many_memories() {
|
|||
w_en,
|
||||
w_data,
|
||||
w_mask,
|
||||
} = expected;
|
||||
} = &expected;
|
||||
for (((r, w), w_data), w_mask) in sim
|
||||
.io()
|
||||
.r
|
||||
|
|
@ -1514,10 +1514,10 @@ fn test_many_memories() {
|
|||
.zip(w_data.iter())
|
||||
.zip(w_mask.iter())
|
||||
{
|
||||
sim.write(r.addr, &r_addr);
|
||||
sim.write(r.en, &r_en);
|
||||
sim.write(w.addr, &w_addr);
|
||||
sim.write(w.en, &w_en);
|
||||
sim.write(r.addr, r_addr);
|
||||
sim.write(r.en, r_en);
|
||||
sim.write(w.addr, w_addr);
|
||||
sim.write(w.en, w_en);
|
||||
sim.write(w.data, w_data);
|
||||
sim.write(w.mask, w_mask);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue