fayalite/crates/fayalite-proc-macros-impl/src/fold.rs

249 lines
7.3 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
pub(crate) trait DoFold<State: ?Sized + syn::fold::Fold> {
fn do_fold(self, state: &mut State) -> Self;
}
impl<T: DoFold<State>, State: ?Sized + syn::fold::Fold> DoFold<State> for Box<T> {
fn do_fold(mut self, state: &mut State) -> Self {
*self = T::do_fold(*self, state);
self
}
}
impl<T: DoFold<State>, State: ?Sized + syn::fold::Fold> DoFold<State> for Option<T> {
fn do_fold(self, state: &mut State) -> Self {
self.map(|v| T::do_fold(v, state))
}
}
impl<T: DoFold<State>, State: ?Sized + syn::fold::Fold> DoFold<State> for Vec<T> {
fn do_fold(self, state: &mut State) -> Self {
Vec::from_iter(self.into_iter().map(|v| T::do_fold(v, state)))
}
}
impl<T: DoFold<State>, P: DoFold<State>, State: ?Sized + syn::fold::Fold> DoFold<State>
for Punctuated<T, P>
{
fn do_fold(self, state: &mut State) -> Self {
Punctuated::from_iter(self.into_pairs().map(|v| {
let (v, p) = v.into_tuple().do_fold(state);
Pair::new(v, p)
}))
}
}
macro_rules! impl_fold_tuple {
($($var0:ident: $T0:ident, $($var:ident: $T:ident,)*)?) => {
$(impl_fold_tuple!($($var: $T,)*);)?
impl_fold_tuple!(@impl $($var0: $T0, $($var: $T,)*)?);
};
(@impl $($var:ident: $T:ident,)*) => {
impl<State: ?Sized + syn::fold::Fold, $($T: DoFold<State>,)*> DoFold<State> for ($($T,)*) {
#[allow(clippy::unused_unit)]
fn do_fold(self, state: &mut State) -> Self {
let _ = state;
let ($($var,)*) = self;
$(let $var = $var.do_fold(state);)*
($($var,)*)
}
}
};
}
impl_fold_tuple!(
v0: T0,
v1: T1,
v2: T2,
v3: T3,
v4: T4,
v5: T5,
v6: T6,
v7: T7,
v8: T8,
v9: T9,
v10: T10,
v11: T11,
);
macro_rules! no_op_fold {
($ty:ty) => {
impl<State: ?Sized + syn::fold::Fold> $crate::fold::DoFold<State> for $ty {
fn do_fold(self, _state: &mut State) -> Self {
self
}
}
};
}
pub(crate) use no_op_fold;
macro_rules! impl_fold {
(
struct $Struct:ident<$($T:ident,)*> $(where ($($where:tt)*))? {
$($field:ident: $field_ty:ty,)*
}
) => {
impl<State: ?Sized + syn::fold::Fold, $($T,)*> $crate::fold::DoFold<State> for $Struct<$($T,)*>
where
$($T: $crate::fold::DoFold<State>,)*
$($where)*
{
fn do_fold(self, state: &mut State) -> Self {
let _ = state;
let Self {
$($field,)*
} = self;
Self {
$($field: <$field_ty as $crate::fold::DoFold<State>>::do_fold($field, state),)*
}
}
}
};
(
struct $Struct:ident<$($T:ident,)*>(
$field0_ty:ty $(,)?
)
$(where ($($where:tt)*))?;
) => {
impl<State: ?Sized + syn::fold::Fold, $($T,)*> $crate::fold::DoFold<State> for $Struct<$($T,)*>
where
$($T: $crate::fold::DoFold<State>,)*
$($where)*
{
fn do_fold(self, state: &mut State) -> Self {
let _ = state;
let Self(
v0,
) = self;
Self(
<$field0_ty as $crate::fold::DoFold<State>>::do_fold(v0, state),
)
}
}
};
(
enum $Enum:ident<$($T:ident,)*> $(where ($($where:tt)*))? {
$($Variant:ident $({
$($brace_field:ident: $brace_field_ty:ty,)*
})?
$((
$($paren_field_ty:ty),* $(,)?
))?,)*
}
) => {
impl<State: ?Sized + syn::fold::Fold, $($T,)*> $crate::fold::DoFold<State> for $Enum<$($T,)*>
where
$($T: $crate::fold::DoFold<State>,)*
$($where)*
{
fn do_fold(self, state: &mut State) -> Self {
let _ = state;
$crate::fold::impl_fold! {
@enum_variants self, state => ()
$($Variant $({
$($brace_field: $brace_field_ty,)*
})?
$((
$($paren_field_ty,)*
))?,)*
}
}
}
};
(
@enum_variants $self:expr, $state:expr => ($($generated_arms:tt)*)
) => {
match $self {
$($generated_arms)*
}
};
(
@enum_variants $self:expr, $state:expr => ($($generated_arms:tt)*)
$Variant:ident {
$($field:tt: $field_ty:ty,)*
},
$($rest:tt)*
) => {
$crate::fold::impl_fold! {
@enum_variants $self, $state => (
$($generated_arms)*
Self::$Variant {
$($field,)*
} => Self::$Variant {
$($field: <$field_ty as $crate::fold::DoFold<State>>::do_fold($field, $state),)*
},
)
$($rest)*
}
};
(
@enum_variants $self:expr, $state:expr => ($($generated_arms:tt)*)
$Variant:ident(
$field0_ty:ty $(,)?
),
$($rest:tt)*
) => {
$crate::fold::impl_fold! {
@enum_variants $self, $state => (
$($generated_arms)*
Self::$Variant(v0) => Self::$Variant(
<$field0_ty as $crate::fold::DoFold<State>>::do_fold(v0, $state),
),
)
$($rest)*
}
};
}
pub(crate) use impl_fold;
use syn::punctuated::{Pair, Punctuated};
macro_rules! forward_fold {
($ty:ty => $fn:ident) => {
impl<State: syn::fold::Fold + ?Sized> DoFold<State> for $ty {
fn do_fold(self, state: &mut State) -> Self {
<State as syn::fold::Fold>::$fn(state, self)
}
}
};
}
forward_fold!(syn::Attribute => fold_attribute);
forward_fold!(syn::AttrStyle => fold_attr_style);
forward_fold!(syn::Expr => fold_expr);
forward_fold!(syn::ExprArray => fold_expr_array);
forward_fold!(syn::ExprCall => fold_expr_call);
forward_fold!(syn::ExprIf => fold_expr_if);
forward_fold!(syn::ExprMatch => fold_expr_match);
forward_fold!(syn::ExprPath => fold_expr_path);
forward_fold!(syn::ExprStruct => fold_expr_struct);
forward_fold!(syn::ExprTuple => fold_expr_tuple);
forward_fold!(syn::Ident => fold_ident);
forward_fold!(syn::Member => fold_member);
forward_fold!(syn::Path => fold_path);
forward_fold!(syn::Type => fold_type);
forward_fold!(syn::TypePath => fold_type_path);
forward_fold!(syn::WherePredicate => fold_where_predicate);
no_op_fold!(syn::parse::Nothing);
no_op_fold!(syn::token::Brace);
no_op_fold!(syn::token::Bracket);
no_op_fold!(syn::token::Paren);
no_op_fold!(syn::Token![_]);
no_op_fold!(syn::Token![,]);
no_op_fold!(syn::Token![;]);
no_op_fold!(syn::Token![:]);
no_op_fold!(syn::Token![..]);
no_op_fold!(syn::Token![.]);
no_op_fold!(syn::Token![#]);
no_op_fold!(syn::Token![=]);
no_op_fold!(syn::Token![=>]);
no_op_fold!(syn::Token![|]);
no_op_fold!(syn::Token![enum]);
no_op_fold!(syn::Token![extern]);
no_op_fold!(syn::Token![let]);
no_op_fold!(syn::Token![mut]);
no_op_fold!(syn::Token![struct]);
no_op_fold!(syn::Token![where]);