Skip to content

Commit d7ffcdf

Browse files
author
Ralph Küpper
committed
refactor(perry-stdlib, perry): split 6 large files into submodules
Pure code moves; both crates compile, workspace clean, fmt clean, perry tests pass (one pre-existing unrelated broken test target, blocklist_addsubnet_prefix, left as-is): - perry-stdlib/sqlite.rs 4726->388 (9 siblings: options/backup/connection/bind/better/node_db/node_tag_store/node_stmt_session/dispatch) - perry-stdlib/common/dispatch.rs 3504->136 (emitter_als/method/property/fastify_net_zlib/sqlite/init) - perry-stdlib/container/mod.rs 2119->396, perry-stdlib/events.rs 2202->1409 - perry/commands/compile.rs 6114->173: split into compile/ siblings; the one remaining oversized unit is run_pipeline.rs (a single ~5,650-LOC `run_with_parse_cache` par_iter pipeline), now isolated and allowlisted - perry/commands/compile/optimized_libs.rs 2137->101 Allowlist now holds two genuine exceptions: perry-hir/src/ir/expr.rs (an irreducible ~2,560-line `enum Expr`) and the run_pipeline.rs pipeline function.
1 parent a9c711f commit d7ffcdf

38 files changed

Lines changed: 19027 additions & 18442 deletions

crates/perry-stdlib/src/common/dispatch.rs

Lines changed: 80 additions & 3448 deletions
Large diffs are not rendered by default.
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
use super::super::handle::*;
2+
use super::*;
3+
4+
/// Dynamic dispatch for `AsyncLocalStorage` receivers whose static type the
5+
/// codegen lost (`any`-typed bindings, closure captures). Gated on registry
6+
/// type membership so no other subsystem's handle is claimed (#788).
7+
pub(crate) unsafe fn dispatch_async_local_storage_method(
8+
handle: i64,
9+
method: &str,
10+
args: &[f64],
11+
) -> Option<f64> {
12+
if !matches!(
13+
method,
14+
"run" | "getStore" | "enterWith" | "exit" | "disable"
15+
) {
16+
return None;
17+
}
18+
if get_handle_mut::<crate::async_local_storage::AsyncLocalStorageHandle>(handle).is_none() {
19+
return None;
20+
}
21+
Some(match method {
22+
"getStore" => crate::async_local_storage::js_async_local_storage_get_store(handle),
23+
"run" if args.len() >= 2 => {
24+
let rest = if args.len() > 2 { &args[2..] } else { &[] };
25+
let rest_array = if rest.is_empty() {
26+
0
27+
} else {
28+
pack_args_array(rest) as i64
29+
};
30+
crate::async_local_storage::js_async_local_storage_run(
31+
handle, args[0], args[1], rest_array,
32+
)
33+
}
34+
"enterWith" => {
35+
let store = args.first().copied().unwrap_or(TAG_UNDEFINED_F64);
36+
crate::async_local_storage::js_async_local_storage_enter_with(handle, store);
37+
TAG_UNDEFINED_F64
38+
}
39+
"exit" if !args.is_empty() => {
40+
let rest = if args.len() > 1 { &args[1..] } else { &[] };
41+
let rest_array = if rest.is_empty() {
42+
0
43+
} else {
44+
pack_args_array(rest) as i64
45+
};
46+
crate::async_local_storage::js_async_local_storage_exit(handle, args[0], rest_array)
47+
}
48+
"disable" => {
49+
crate::async_local_storage::js_async_local_storage_disable(handle);
50+
TAG_UNDEFINED_F64
51+
}
52+
_ => return None,
53+
})
54+
}
55+
56+
#[cfg(any(feature = "bundled-events", feature = "external-events-construct"))]
57+
pub(crate) unsafe fn dispatch_event_emitter_method(
58+
handle: i64,
59+
method: &str,
60+
args: &[f64],
61+
) -> Option<f64> {
62+
if !js_event_emitter_is_handle(handle) {
63+
return None;
64+
}
65+
66+
let event_bits = |index: usize| {
67+
args.get(index)
68+
.copied()
69+
.unwrap_or(TAG_UNDEFINED_F64)
70+
.to_bits() as i64
71+
};
72+
let nanbox_array = |ptr: *mut perry_runtime::ArrayHeader| {
73+
f64::from_bits(POINTER_TAG_BITS | (ptr as u64 & POINTER_MASK_BITS))
74+
};
75+
76+
// EventEmitterAsyncResource extras exist only in the bundled impl;
77+
// perry-ext-events has no async-resource constructor, so its handles
78+
// never satisfy this probe.
79+
#[cfg(feature = "bundled-events")]
80+
if crate::events::is_event_emitter_async_resource_handle(handle) {
81+
match method {
82+
"asyncId" => {
83+
return Some(crate::events::js_event_emitter_async_resource_async_id(
84+
handle,
85+
));
86+
}
87+
"triggerAsyncId" => {
88+
return Some(
89+
crate::events::js_event_emitter_async_resource_trigger_async_id(handle),
90+
);
91+
}
92+
"asyncResource" => {
93+
return Some(crate::events::js_event_emitter_async_resource_async_resource(handle));
94+
}
95+
"emitDestroy" => {
96+
return Some(crate::events::js_event_emitter_async_resource_emit_destroy(
97+
handle,
98+
));
99+
}
100+
_ => {}
101+
}
102+
}
103+
104+
let value = match method {
105+
"on" | "addListener" if args.len() >= 2 => {
106+
js_event_emitter_on(handle, event_bits(0), event_bits(1));
107+
nanbox_handle_value(handle)
108+
}
109+
"once" if args.len() >= 2 => {
110+
js_event_emitter_once(handle, event_bits(0), event_bits(1));
111+
nanbox_handle_value(handle)
112+
}
113+
"prependListener" if args.len() >= 2 => {
114+
js_event_emitter_prepend_listener(handle, event_bits(0), event_bits(1));
115+
nanbox_handle_value(handle)
116+
}
117+
"prependOnceListener" if args.len() >= 2 => {
118+
js_event_emitter_prepend_once_listener(handle, event_bits(0), event_bits(1));
119+
nanbox_handle_value(handle)
120+
}
121+
"off" | "removeListener" if args.len() >= 2 => {
122+
js_event_emitter_remove_listener(handle, event_bits(0), event_bits(1));
123+
nanbox_handle_value(handle)
124+
}
125+
"removeAllListeners" => {
126+
js_event_emitter_remove_all_listeners(handle, pack_args_array(args));
127+
nanbox_handle_value(handle)
128+
}
129+
"emit" => {
130+
let rest = if args.len() > 1 { &args[1..] } else { &[] };
131+
js_event_emitter_emit(handle, event_bits(0), pack_args_array(rest))
132+
}
133+
"listenerCount" if !args.is_empty() => js_event_emitter_listener_count(
134+
handle,
135+
event_bits(0),
136+
args.get(1)
137+
.copied()
138+
.map(|value| value.to_bits() as i64)
139+
.unwrap_or(TAG_UNDEFINED_BITS),
140+
),
141+
"listeners" if !args.is_empty() => {
142+
nanbox_array(js_event_emitter_listeners(handle, event_bits(0)))
143+
}
144+
"rawListeners" if !args.is_empty() => {
145+
nanbox_array(js_event_emitter_raw_listeners(handle, event_bits(0)))
146+
}
147+
"eventNames" => nanbox_array(js_event_emitter_event_names(handle)),
148+
"setMaxListeners" if !args.is_empty() => {
149+
js_event_emitter_set_max_listeners(handle, args[0]);
150+
nanbox_handle_value(handle)
151+
}
152+
"getMaxListeners" => js_event_emitter_get_max_listeners(handle),
153+
"domain" => js_event_emitter_domain_value(handle),
154+
_ => return None,
155+
};
156+
Some(value)
157+
}
158+
159+
#[cfg(any(feature = "bundled-events", feature = "external-events-construct"))]
160+
pub(crate) unsafe fn dispatch_event_emitter_property(handle: i64, property: &str) -> Option<f64> {
161+
if !js_event_emitter_is_handle(handle) {
162+
return None;
163+
}
164+
165+
let bind_method = |method: &[u8]| -> f64 {
166+
extern "C" {
167+
fn js_class_method_bind(
168+
instance: f64,
169+
method_name_ptr: *const u8,
170+
method_name_len: usize,
171+
) -> f64;
172+
}
173+
js_class_method_bind(nanbox_handle_value(handle), method.as_ptr(), method.len())
174+
};
175+
176+
#[cfg(feature = "bundled-events")]
177+
if crate::events::is_event_emitter_async_resource_handle(handle) {
178+
match property {
179+
"asyncId" => {
180+
return Some(crate::events::js_event_emitter_async_resource_async_id(
181+
handle,
182+
));
183+
}
184+
"triggerAsyncId" => {
185+
return Some(
186+
crate::events::js_event_emitter_async_resource_trigger_async_id(handle),
187+
);
188+
}
189+
"asyncResource" => {
190+
return Some(crate::events::js_event_emitter_async_resource_async_resource(handle));
191+
}
192+
"emitDestroy" => return Some(bind_method(b"emitDestroy")),
193+
_ => {}
194+
}
195+
}
196+
197+
let method = match property {
198+
"on"
199+
| "addListener"
200+
| "once"
201+
| "prependListener"
202+
| "prependOnceListener"
203+
| "off"
204+
| "removeListener"
205+
| "removeAllListeners"
206+
| "emit"
207+
| "listenerCount"
208+
| "listeners"
209+
| "rawListeners"
210+
| "eventNames"
211+
| "setMaxListeners"
212+
| "getMaxListeners" => Some(property.as_bytes()),
213+
_ => None,
214+
}?;
215+
216+
Some(bind_method(method))
217+
}
218+
219+
/// `AsyncLocalStorage` METHOD-VALUE reads (the property-read counterpart of
220+
/// `dispatch_async_local_storage_method`). `als.getStore()` (a direct call)
221+
/// already dispatched, but reading `als.getStore` AS A VALUE (`const gs =
222+
/// als.getStore`, `{ getStore } = als`, `typeof als.getStore`) returned
223+
/// `undefined` — there was no property-read dispatch for ALS handles (only
224+
/// EventEmitter had one, #4995). Next.js' server startup reads `getStore` as a
225+
/// value (cacheComponents / patch-fetch async-storage setup) and then calls it,
226+
/// so it threw `TypeError: getStore is not a function` BEFORE `✓ Ready`. Bind
227+
/// each method to the handle so the read yields a callable bound method, exactly
228+
/// like `dispatch_event_emitter_property`.
229+
pub(crate) unsafe fn dispatch_async_local_storage_property(
230+
handle: i64,
231+
property: &str,
232+
) -> Option<f64> {
233+
if !matches!(
234+
property,
235+
"run" | "getStore" | "enterWith" | "exit" | "disable"
236+
) {
237+
return None;
238+
}
239+
if get_handle_mut::<crate::async_local_storage::AsyncLocalStorageHandle>(handle).is_none() {
240+
return None;
241+
}
242+
extern "C" {
243+
fn js_class_method_bind(
244+
instance: f64,
245+
method_name_ptr: *const u8,
246+
method_name_len: usize,
247+
) -> f64;
248+
}
249+
let m = property.as_bytes();
250+
Some(js_class_method_bind(
251+
nanbox_handle_value(handle),
252+
m.as_ptr(),
253+
m.len(),
254+
))
255+
}

0 commit comments

Comments
 (0)