From 0d0734e083de2350407e4d9f7f5d7a9385f27984 Mon Sep 17 00:00:00 2001
From: Jordan Woyak <jordan.woyak@gmail.com>
Date: Tue, 25 Feb 2025 01:26:04 -0600
Subject: [PATCH] WiimoteEmu: Clean up variant handling in
 DesiredExtensionState.

---
 .../HW/WiimoteEmu/DesiredWiimoteState.cpp     | 97 +++----------------
 .../Core/HW/WiimoteEmu/Extension/Classic.h    |  2 +
 .../Extension/DesiredExtensionState.h         | 46 +++------
 .../HW/WiimoteEmu/Extension/DrawsomeTablet.h  |  3 +-
 .../Core/HW/WiimoteEmu/Extension/Guitar.h     |  2 +
 .../Core/HW/WiimoteEmu/Extension/Nunchuk.h    |  2 +
 .../Core/HW/WiimoteEmu/Extension/TaTaCon.h    |  2 +
 .../Core/HW/WiimoteEmu/Extension/Turntable.h  |  2 +
 .../HW/WiimoteEmu/Extension/UDrawTablet.h     |  3 +-
 9 files changed, 37 insertions(+), 122 deletions(-)

diff --git a/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp b/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp
index b59d04606f..b9e68b2594 100644
--- a/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp
+++ b/Source/Core/Core/HW/WiimoteEmu/DesiredWiimoteState.cpp
@@ -10,16 +10,8 @@
 
 #include "Common/BitUtils.h"
 #include "Common/CommonTypes.h"
+#include "Common/VariantUtil.h"
 
-#include "Core/HW/WiimoteEmu/Extension/Classic.h"
-#include "Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h"
-#include "Core/HW/WiimoteEmu/Extension/Drums.h"
-#include "Core/HW/WiimoteEmu/Extension/Guitar.h"
-#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
-#include "Core/HW/WiimoteEmu/Extension/Shinkansen.h"
-#include "Core/HW/WiimoteEmu/Extension/TaTaCon.h"
-#include "Core/HW/WiimoteEmu/Extension/Turntable.h"
-#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
 #include "Core/HW/WiimoteEmu/MotionPlus.h"
 
 namespace WiimoteEmu
@@ -114,13 +106,9 @@ SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state)
     std::visit(
         [&s](const auto& arg) {
           using T = std::decay_t<decltype(arg)>;
-          if constexpr (!std::is_same_v<std::monostate, T>)
-          {
-            static_assert(sizeof(arg) <= 6);
-            static_assert(std::is_trivially_copyable_v<T>);
-            std::memcpy(&s.data[s.length], &arg, sizeof(arg));
-            s.length += sizeof(arg);
-          }
+          static_assert(sizeof(arg) <= 6);
+          Common::BitCastPtr<T>(&s.data[s.length]) = arg;
+          s.length += sizeof(arg);
         },
         state.extension.data);
   }
@@ -128,19 +116,6 @@ SerializedWiimoteState SerializeDesiredState(const DesiredWiimoteState& state)
   return s;
 }
 
-template <typename T>
-static bool DeserializeExtensionState(DesiredWiimoteState* state,
-                                      const SerializedWiimoteState& serialized, size_t offset)
-{
-  if (serialized.length < offset + sizeof(T))
-    return false;
-  auto& e = state->extension.data.emplace<T>();
-  static_assert(std::is_trivially_copyable_v<T>);
-  std::memcpy(static_cast<void*>(&e), static_cast<const void*>(&serialized.data[offset]),
-              sizeof(T));
-  return true;
-}
-
 bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimoteState& serialized)
 {
   // clear state
@@ -181,39 +156,10 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote
       s += 12;
     if (has_motion_plus)
       s += 6;
-    switch (extension)
+    if (extension)
     {
-    case ExtensionNumber::NONE:
-      break;
-    case ExtensionNumber::NUNCHUK:
-      s += sizeof(Nunchuk::DataFormat);
-      break;
-    case ExtensionNumber::CLASSIC:
-      s += sizeof(Classic::DataFormat);
-      break;
-    case ExtensionNumber::GUITAR:
-      s += sizeof(Guitar::DataFormat);
-      break;
-    case ExtensionNumber::DRUMS:
-      s += sizeof(Drums::DesiredState);
-      break;
-    case ExtensionNumber::TURNTABLE:
-      s += sizeof(Turntable::DataFormat);
-      break;
-    case ExtensionNumber::UDRAW_TABLET:
-      s += sizeof(UDrawTablet::DataFormat);
-      break;
-    case ExtensionNumber::DRAWSOME_TABLET:
-      s += sizeof(DrawsomeTablet::DataFormat);
-      break;
-    case ExtensionNumber::TATACON:
-      s += sizeof(TaTaCon::DataFormat);
-      break;
-    case ExtensionNumber::SHINKANSEN:
-      s += sizeof(Shinkansen::DesiredState);
-      break;
-    default:
-      break;
+      WithVariantAlternative<DesiredExtensionState::ExtensionData>(
+          extension, [&]<typename T>() { s += sizeof(T); });
     }
     return s;
   }();
@@ -283,32 +229,13 @@ bool DeserializeDesiredState(DesiredWiimoteState* state, const SerializedWiimote
     pos += 6;
   }
 
-  switch (extension)
+  if (extension)
   {
-  case ExtensionNumber::NONE:
-    return true;
-  case ExtensionNumber::NUNCHUK:
-    return DeserializeExtensionState<Nunchuk::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::CLASSIC:
-    return DeserializeExtensionState<Classic::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::GUITAR:
-    return DeserializeExtensionState<Guitar::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::DRUMS:
-    return DeserializeExtensionState<Drums::DesiredState>(state, serialized, pos);
-  case ExtensionNumber::TURNTABLE:
-    return DeserializeExtensionState<Turntable::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::UDRAW_TABLET:
-    return DeserializeExtensionState<UDrawTablet::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::DRAWSOME_TABLET:
-    return DeserializeExtensionState<DrawsomeTablet::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::TATACON:
-    return DeserializeExtensionState<TaTaCon::DataFormat>(state, serialized, pos);
-  case ExtensionNumber::SHINKANSEN:
-    return DeserializeExtensionState<Shinkansen::DesiredState>(state, serialized, pos);
-  default:
-    break;
+    WithVariantAlternative<DesiredExtensionState::ExtensionData>(extension, [&]<typename T>() {
+      state->extension.data.emplace<T>(Common::BitCastPtr<T>(&d[pos]));
+    });
   }
 
-  return false;
+  return true;
 }
 }  // namespace WiimoteEmu
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h
index 02781ac8ee..5788fa3e62 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h
@@ -129,6 +129,8 @@ public:
   };
   static_assert(sizeof(DataFormat) == 6, "Wrong size");
 
+  using DesiredState = DataFormat;
+
   static constexpr int CAL_STICK_BITS = 8;
   static constexpr int CAL_TRIGGER_BITS = 8;
 
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h b/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h
index 4929c91cd1..a61da143bc 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h
@@ -3,7 +3,6 @@
 
 #pragma once
 
-#include <type_traits>
 #include <variant>
 
 #include "Common/BitUtils.h"
@@ -18,46 +17,23 @@
 #include "Core/HW/WiimoteEmu/Extension/TaTaCon.h"
 #include "Core/HW/WiimoteEmu/Extension/Turntable.h"
 #include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
-#include "Core/HW/WiimoteEmu/ExtensionPort.h"
 
 namespace WiimoteEmu
 {
 struct DesiredExtensionState
 {
-  using ExtensionData =
-      std::variant<std::monostate, Nunchuk::DataFormat, Classic::DataFormat, Guitar::DataFormat,
-                   Drums::DesiredState, Turntable::DataFormat, UDrawTablet::DataFormat,
-                   DrawsomeTablet::DataFormat, TaTaCon::DataFormat, Shinkansen::DesiredState>;
-  ExtensionData data = std::monostate();
+private:
+  template <typename... Ts>
+  struct ExtDataImpl
+  {
+    using type = std::variant<std::monostate, typename Ts::DesiredState...>;
+  };
 
-  static_assert(std::is_same_v<std::monostate,
-                               std::variant_alternative_t<ExtensionNumber::NONE, ExtensionData>>);
-  static_assert(
-      std::is_same_v<Nunchuk::DataFormat,
-                     std::variant_alternative_t<ExtensionNumber::NUNCHUK, ExtensionData>>);
-  static_assert(
-      std::is_same_v<Classic::DataFormat,
-                     std::variant_alternative_t<ExtensionNumber::CLASSIC, ExtensionData>>);
-  static_assert(std::is_same_v<Guitar::DataFormat,
-                               std::variant_alternative_t<ExtensionNumber::GUITAR, ExtensionData>>);
-  static_assert(std::is_same_v<Drums::DesiredState,
-                               std::variant_alternative_t<ExtensionNumber::DRUMS, ExtensionData>>);
-  static_assert(
-      std::is_same_v<Turntable::DataFormat,
-                     std::variant_alternative_t<ExtensionNumber::TURNTABLE, ExtensionData>>);
-  static_assert(
-      std::is_same_v<UDrawTablet::DataFormat,
-                     std::variant_alternative_t<ExtensionNumber::UDRAW_TABLET, ExtensionData>>);
-  static_assert(
-      std::is_same_v<DrawsomeTablet::DataFormat,
-                     std::variant_alternative_t<ExtensionNumber::DRAWSOME_TABLET, ExtensionData>>);
-  static_assert(
-      std::is_same_v<TaTaCon::DataFormat,
-                     std::variant_alternative_t<ExtensionNumber::TATACON, ExtensionData>>);
-  static_assert(
-      std::is_same_v<Shinkansen::DesiredState,
-                     std::variant_alternative_t<ExtensionNumber::SHINKANSEN, ExtensionData>>);
-  static_assert(std::variant_size_v<DesiredExtensionState::ExtensionData> == ExtensionNumber::MAX);
+public:
+  using ExtensionData = ExtDataImpl<Nunchuk, Classic, Guitar, Drums, Turntable, UDrawTablet,
+                                    DrawsomeTablet, TaTaCon, Shinkansen>::type;
+
+  ExtensionData data = std::monostate{};
 };
 
 template <typename T>
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h b/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h
index fe4a213d09..184d0df250 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h
@@ -50,9 +50,10 @@ public:
       BitField<3, 5, u8> status;
     };
   };
-
   static_assert(6 == sizeof(DataFormat), "Wrong size.");
 
+  using DesiredState = DataFormat;
+
 private:
   ControllerEmu::AnalogStick* m_stylus;
   ControllerEmu::Triggers* m_touch;
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h
index 883d0bc2ed..1e36ef6ee4 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.h
@@ -48,6 +48,8 @@ public:
   };
   static_assert(sizeof(DataFormat) == 6, "Wrong size");
 
+  using DesiredState = DataFormat;
+
   Guitar();
 
   void BuildDesiredExtensionState(DesiredExtensionState* target_state) override;
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h
index 438b93c034..3251d83f92 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h
@@ -116,6 +116,8 @@ public:
   };
   static_assert(sizeof(DataFormat) == 6, "Wrong size");
 
+  using DesiredState = DataFormat;
+
   struct CalibrationData
   {
     using StickType = DataFormat::StickType;
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h b/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h
index 7ce54770bc..2342feacaf 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.h
@@ -29,6 +29,8 @@ public:
   };
   static_assert(sizeof(DataFormat) == 6, "Wrong size");
 
+  using DesiredState = DataFormat;
+
   TaTaCon();
 
   void BuildDesiredExtensionState(DesiredExtensionState* target_state) override;
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h
index 36cda37629..b3ddb0be90 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.h
@@ -54,6 +54,8 @@ public:
   };
   static_assert(sizeof(DataFormat) == 6, "Wrong size");
 
+  using DesiredState = DataFormat;
+
   Turntable();
 
   void BuildDesiredExtensionState(DesiredExtensionState* target_state) override;
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h b/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h
index 7052b55ede..8747100a7d 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/UDrawTablet.h
@@ -56,9 +56,10 @@ public:
     // 0x04 is always unset (neutral state is 0xfb)
     u8 buttons;
   };
-
   static_assert(6 == sizeof(DataFormat), "Wrong size.");
 
+  using DesiredState = DataFormat;
+
 private:
   ControllerEmu::Buttons* m_buttons;
   ControllerEmu::AnalogStick* m_stylus;