Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/stdx/src/macros.rs')
-rw-r--r--crates/stdx/src/macros.rs82
1 files changed, 80 insertions, 2 deletions
diff --git a/crates/stdx/src/macros.rs b/crates/stdx/src/macros.rs
index 880e2da70f..907746888f 100644
--- a/crates/stdx/src/macros.rs
+++ b/crates/stdx/src/macros.rs
@@ -30,15 +30,93 @@ macro_rules! format_to_acc {
};
}
-/// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums
+/// Generates `From` impls that wrap values in, or map variants between, enums.
///
-/// # Example
+/// Enum mappings with `Source => Target` rename the variant and convert its payload with `.into()`.
+///
+/// # Examples
///
/// ```ignore
/// impl_from!(Struct, Union, Enum for Adt);
+/// impl_from!(impl<'db> Item, InternedItem<'db> for ItemId<'db>);
+/// impl_from!(AssocItem { Function, Const, TypeAlias } for Item);
+/// impl_from!(AdtId { StructId => Struct, EnumId => Enum } for Adt);
/// ```
#[macro_export]
macro_rules! impl_from {
+ (
+ impl<$lifetime:lifetime>
+ $source:ident $(<$source_lifetime:lifetime>)?
+ { $($source_variant:ident $(=> $target_variant:ident)?),* $(,)? }
+ for $target:ident<$target_lifetime:lifetime>
+ ) => {
+ impl<$lifetime> From<$source$(<$source_lifetime>)?> for $target<$target_lifetime> {
+ fn from(value: $source$(<$source_lifetime>)?) -> Self {
+ match value {
+ $(
+ $source::$source_variant(value) => $crate::impl_from!(
+ @map_enum_variant $target, value, $source_variant
+ $(=> $target_variant)?
+ ),
+ )*
+ }
+ }
+ }
+ };
+ (
+ $source:ident
+ { $($source_variant:ident $(=> $target_variant:ident)?),* $(,)? }
+ for $target:ident
+ ) => {
+ impl From<$source> for $target {
+ fn from(value: $source) -> Self {
+ match value {
+ $(
+ $source::$source_variant(value) => $crate::impl_from!(
+ @map_enum_variant $target, value, $source_variant
+ $(=> $target_variant)?
+ ),
+ )*
+ }
+ }
+ }
+ };
+ (@map_enum_variant $target:ident, $value:ident, $variant:ident) => {
+ $target::$variant($value)
+ };
+ (
+ @map_enum_variant $target:ident, $value:ident,
+ $source_variant:ident => $target_variant:ident
+ ) => {
+ $target::$target_variant($value.into())
+ };
+ (
+ impl<$lifetime:lifetime>
+ $(
+ $variant:ident $(<$variant_lifetime:lifetime>)?
+ $(($($sub_variant:ident $(<$sub_variant_lifetime:lifetime>)?),*))?
+ ),*
+ for $enum:ident<$enum_lifetime:lifetime>
+ ) => {
+ $(
+ impl<$lifetime> From<$variant$(<$variant_lifetime>)?> for $enum<$enum_lifetime> {
+ fn from(it: $variant$(<$variant_lifetime>)?) -> $enum<$enum_lifetime> {
+ $enum::$variant(it)
+ }
+ }
+ $($(
+ impl<$lifetime> From<$sub_variant$(<$sub_variant_lifetime>)?>
+ for $enum<$enum_lifetime>
+ {
+ fn from(
+ it: $sub_variant$(<$sub_variant_lifetime>)?,
+ ) -> $enum<$enum_lifetime> {
+ $enum::$variant($variant::$sub_variant(it))
+ }
+ }
+ )*)?
+ )*
+ };
($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => {
$(
impl From<$variant> for $enum {