1
0
Fork 0

fayalite::expr::ops: add and automatically generate ops::StructuralEq

This commit is contained in:
Jacob Lifshay 2026-06-08 23:36:26 -07:00
parent ffca1a279d
commit 98e7e91fc9
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
18 changed files with 1030 additions and 220 deletions

View file

@ -1133,6 +1133,7 @@ impl ToTokens for ParsedBundle {
let mut fields_expr_ne = vec![];
let mut fields_valueless_eq = vec![];
let mut fields_valueless_ne = vec![];
let mut fields_structural_eq = vec![];
for field in fields.named() {
let field_ident = field.ident();
let field_ty = field.ty();
@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle {
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
});
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
});
fields_value_eq.push(quote_spanned! {span=>
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
__lhs.#field_ident,
@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle {
let expr_ne_body;
let valueless_eq_body;
let valueless_ne_body;
let structural_eq;
if fields_len == 0 {
value_eq_body = quote_spanned! {span=>
true
@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle {
valueless_ne_body = quote_spanned! {span=>
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
};
structural_eq = quote_spanned! {span=>
true
};
} else {
value_eq_body = quote_spanned! {span=>
#(#fields_value_eq)&*
@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle {
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
#(#fields_valueless_ne)|*
};
structural_eq = quote_spanned! {span=>
#(#fields_structural_eq)&&*
};
};
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
#cmp_eq_where_clause
{
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
#[track_caller]
fn cmp_value_eq(
__lhs: Self,
@ -1261,6 +1274,16 @@ impl ToTokens for ParsedBundle {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
if let ::fayalite::__std::result::Result::Ok(__retval) =
::fayalite::expr::ops::StructuralEq::try_new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
)
{
return ::fayalite::expr::ToExpr::to_expr(&__retval);
}
}
#expr_eq_body
}
@ -1269,6 +1292,14 @@ impl ToTokens for ParsedBundle {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
return !::fayalite::expr::ToExpr::to_expr(
&::fayalite::expr::ops::StructuralEq::new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
),
);
}
#expr_ne_body
}

View file

@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum {
#where_clause
{
#[allow(non_snake_case, dead_code)]
#vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
#vis fn #ident(
#self_token,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(
#self_token.#sim_builder_ty_field_ident,
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
@ -929,8 +931,14 @@ impl ToTokens for ParsedEnum {
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
fn fmt(
&self,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(
self,
f,
)
}
}
}.to_tokens(tokens);
@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum {
let mut variants_value_eq = vec![];
let mut variants_expr_eq = vec![];
let mut fields_valueless_eq = vec![];
let mut structural_eq: Option<TokenStream> = None;
for (
variant_index,
ParsedVariant {
@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum {
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
});
match &mut structural_eq {
Some(structural_eq) => {
structural_eq.extend(quote_spanned! {cmp_eq.span=>
&& <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
});
}
None => {
structural_eq = Some(quote_spanned! {cmp_eq.span=>
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
});
}
}
variants_value_eq.push(quote_spanned! {span=>
(#sim_value_ident::#variant_ident(__lhs_field, _), #sim_value_ident::#variant_ident(__rhs_field, _)) => {
(
#sim_value_ident::#variant_ident(__lhs_field, _),
#sim_value_ident::#variant_ident(__rhs_field, _),
) => {
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
__lhs.#variant_ident,
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum {
else {
::fayalite::__std::unreachable!();
};
::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs));
::fayalite::module::connect(
__retval,
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
);
}
});
fields_valueless_eq.push(quote_spanned! {span=>
@ -1043,7 +1070,10 @@ impl ToTokens for ParsedEnum {
}
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
variants_value_eq.push(quote_spanned! {span=>
(#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => {
(
#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown),
#sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown),
) => {
__lhs_unknown == __rhs_unknown
}
});
@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum {
}
};
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
let structural_eq = structural_eq.unwrap_or_else(|| {
quote_spanned! {span=>
true
}
});
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
#cmp_eq_where_clause
{
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
#[track_caller]
fn cmp_value_eq(
__lhs: Self,
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
__lhs_value: ::fayalite::__std::borrow::Cow<'_,
<Self as ::fayalite::ty::Type>::SimValue>,
__rhs: Self,
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
__rhs_value: ::fayalite::__std::borrow::Cow<'_,
<Self as ::fayalite::ty::Type>::SimValue>,
) -> ::fayalite::__std::primitive::bool {
match (&*__lhs_value, &*__rhs_value) {
#(#variants_value_eq)*
@ -1083,7 +1122,20 @@ impl ToTokens for ParsedEnum {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
let __retval = ::fayalite::module::wire(::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), ::fayalite::int::Bool);
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
if let ::fayalite::__std::result::Result::Ok(__retval) =
::fayalite::expr::ops::StructuralEq::try_new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
)
{
return ::fayalite::expr::ToExpr::to_expr(&__retval);
}
}
let __retval = ::fayalite::module::wire(
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
::fayalite::int::Bool,
);
::fayalite::module::connect(__retval, false);
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
#(#variants_expr_eq)*
@ -1112,7 +1164,8 @@ impl ToTokens for ParsedEnum {
type SimValue = #sim_value_ident #type_generics;
type MatchVariant = #match_variant_ident #type_generics;
type MatchActiveScope = ::fayalite::module::Scope;
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
type MatchVariantAndInactiveScope =
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
fn match_variants(
@ -1125,7 +1178,9 @@ impl ToTokens for ParsedEnum {
::fayalite::int::Bool
}
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token)))
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(
::fayalite::enum_::EnumType::variants(#self_token),
))
}
#[track_caller]
#[allow(non_snake_case)]
@ -1134,7 +1189,11 @@ impl ToTokens for ParsedEnum {
::fayalite::__std::panic!("expected enum");
};
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants");
::fayalite::__std::assert_eq!(
#variants_token.len(),
#variants_len,
"enum has wrong number of variants",
);
Self {
#(#from_canonical_body_fields)*
}
@ -1180,7 +1239,10 @@ impl ToTokens for ParsedEnum {
type SimBuilder = #sim_builder_ident #type_generics;
fn match_activate_scope(
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
) -> (
<Self as ::fayalite::ty::Type>::MatchVariant,
<Self as ::fayalite::ty::Type>::MatchActiveScope,
) {
let (#variant_access_token, scope) = v.activate();
(
match #variant_access_token.variant_index() {
@ -1200,7 +1262,10 @@ impl ToTokens for ParsedEnum {
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
fn fmt(
&self,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
}
}
@ -1213,7 +1278,10 @@ impl ToTokens for ParsedEnum {
&self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
::fayalite::sim::value::SimValue::from_value(
ty,
::fayalite::__std::clone::Clone::clone(self),
)
}
fn into_sim_value_with_type(
self,