From dd254cfcb47ff01dd6c16d753d468e00b26d560d Mon Sep 17 00:00:00 2001
From: Paulo Matos
Date: Tue, 30 Jun 2026 12:13:46 +0000
Subject: [PATCH] refactor: collapse ObjectKind accessor boilerplate into
kind_accessor! macro
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The 17 standard ObjectKind accessor pairs (and immutable-only variants)
all followed an identical `if let ObjectKind::Variant(ref x) = self.kind
{ Some(x) } else { None }` pattern, repeated verbatim for both the
immutable and mutable form — ~30 method bodies in total.
Introduces a `kind_accessor!` declarative macro with two arms:
- `(name, mut_name, Variant, Type)` for immutable+mutable pairs
- `(name, Variant, Type)` for immutable-only
The three special-case methods that don't fit the pattern are kept as
hand-written impls with a comment explaining why:
- `intl_data` — boxed inner value requires an extra `.as_ref()` deref
- `finalization_registry{,_mut}` — struct variant with two named fields
- `shadow_realm_id` — Copy return type, not a reference
Adds 17 unit tests (kind_accessor_tests module) covering: Some/None
discrimination by kind, mutable access enables mutation, and mutual
exclusion between different kinds.
🤖 Generated with Claude Code
Claude-Session: https://claude.ai/code/session_012MbKtDLjpVxxY655NVhTSE
---
src/interpreter/types.rs | 448 +++++++++++++++++++--------------------
1 file changed, 214 insertions(+), 234 deletions(-)
diff --git a/src/interpreter/types.rs b/src/interpreter/types.rs
index 4246a48..dc6c5f7 100644
--- a/src/interpreter/types.rs
+++ b/src/interpreter/types.rs
@@ -1781,6 +1781,43 @@ impl ProxyData {
}
}
+/// Generate `pub(crate) fn $name(&self) -> Option<&$ty>` and optionally a
+/// paired `fn $mut_name(&mut self) -> Option<&mut $ty>` for the common
+/// `ObjectKind::$variant(T)` accessor pattern.
+///
+/// Avoids 30+ structurally identical methods; each variant that needs a
+/// different shape (boxed deref, struct variant, Copy return) is written out
+/// by hand below.
+macro_rules! kind_accessor {
+ // Immutable + mutable pair.
+ ($name:ident, $mut_name:ident, $variant:ident, $ty:ty) => {
+ pub(crate) fn $name(&self) -> Option<&$ty> {
+ if let ObjectKind::$variant(ref x) = self.kind {
+ Some(x)
+ } else {
+ None
+ }
+ }
+ pub(crate) fn $mut_name(&mut self) -> Option<&mut $ty> {
+ if let ObjectKind::$variant(ref mut x) = self.kind {
+ Some(x)
+ } else {
+ None
+ }
+ }
+ };
+ // Immutable-only.
+ ($name:ident, $variant:ident, $ty:ty) => {
+ pub(crate) fn $name(&self) -> Option<&$ty> {
+ if let ObjectKind::$variant(ref x) = self.kind {
+ Some(x)
+ } else {
+ None
+ }
+ }
+ };
+}
+
impl JsObjectData {
pub(crate) fn new() -> Self {
Self {
@@ -1807,14 +1844,33 @@ impl JsObjectData {
}
}
- /// Proxy slot data. `Some` for any proxy, active or revoked.
- pub(crate) fn proxy(&self) -> Option<&ProxyData> {
- if let ObjectKind::Proxy(ref p) = self.kind {
- Some(p)
- } else {
- None
- }
- }
+ kind_accessor!(proxy, Proxy, ProxyData);
+ kind_accessor!(arraybuffer, arraybuffer_mut, ArrayBuffer, ArrayBufferData);
+ kind_accessor!(data_view_info, DataView, DataViewInfo);
+ kind_accessor!(typed_array_info, TypedArray, TypedArrayInfo);
+ kind_accessor!(iterator_state, iterator_state_mut, Iterator, IteratorState);
+ kind_accessor!(promise_data, promise_data_mut, Promise, PromiseData);
+ kind_accessor!(parameter_map, parameter_map_mut, Arguments, HashMap);
+ kind_accessor!(array_elements, array_elements_mut, Array, Vec);
+ kind_accessor!(map_data, map_data_mut, Map, Vec