Skip to content
File

Blob: src/rust/jsg/jsg.h

cpp101 lines
1// Copyright (c) 2026 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include <workerd/jsg/jsg.h>
8#include <workerd/jsg/modules-new.h>
9#include <workerd/jsg/modules.h>
10#include <workerd/rust/jsg/ffi-inl.h>
11#include <workerd/rust/jsg/ffi.h>
12#include <workerd/rust/jsg/v8.rs.h>
13 
14#include <kj-rs/kj-rs.h>
15#include <rust/cxx.h>
16 
17#include <kj/function.h>
18 
19namespace workerd::rust::jsg {
20 
21// Adapter for registering Rust-implemented modules into the OLD module registry
22// (jsg::ModuleRegistryImpl). Translates Rust ModuleCallback into ModuleInfo.
23template <typename Registry>
24struct RustModuleRegistry: public ::workerd::rust::jsg::ModuleRegistry {
25 virtual ~RustModuleRegistry() = default;
26 RustModuleRegistry(Registry& registry): registry(registry) {}
27 
28 void addBuiltinModule(
29 ::rust::Str specifier, ModuleCallback moduleCallback, ModuleType moduleType) override {
30 ::workerd::jsg::ModuleType jsgModuleType;
31 switch (moduleType) {
32 case ModuleType::Bundle:
33 jsgModuleType = ::workerd::jsg::ModuleType::BUNDLE;
34 break;
35 case ModuleType::Builtin:
36 jsgModuleType = ::workerd::jsg::ModuleType::BUILTIN;
37 break;
38 case ModuleType::Internal:
39 jsgModuleType = ::workerd::jsg::ModuleType::INTERNAL;
40 break;
41 default:
42 KJ_UNREACHABLE;
43 }
44 
45 registry.addBuiltinModule(kj::str(specifier),
46 [kj_specifier = kj::str(specifier), callback = kj::mv(moduleCallback)](
47 ::workerd::jsg::Lock& js, ::workerd::jsg::ModuleRegistry::ResolveMethod,
48 kj::Maybe<const kj::Path&>&) mutable
49 -> kj::Maybe<::workerd::jsg::ModuleRegistry::ModuleInfo> {
50 auto localValue = callback(js.v8Isolate);
51 auto value = local_from_ffi<v8::Value>(kj::mv(localValue));
52 KJ_DASSERT(value->IsObject());
53 
54 using ModuleInfo = ::workerd::jsg::ModuleRegistry::ModuleInfo;
55 using ObjectModuleInfo = ::workerd::jsg::ModuleRegistry::ObjectModuleInfo;
56 return kj::Maybe(
57 ModuleInfo(js, kj_specifier, kj::none, ObjectModuleInfo(js, value.As<v8::Object>())));
58 },
59 jsgModuleType);
60 }
61 
62 Registry& registry;
63};
64 
65// Adapter for registering Rust-implemented modules into the NEW module registry
66// (jsg::modules::ModuleBundle::BuiltinBuilder). Translates Rust ModuleCallback
67// into BuiltinBuilder::addSynthetic calls. Each Rust module callback receives a
68// v8::Isolate* and returns a v8::Local<v8::Value> (the module's default export).
69//
70// Usage:
71// RustBuiltinModuleAdapter adapter(builder);
72// ::workerd::rust::api::register_nodejs_modules(adapter);
73struct RustBuiltinModuleAdapter: public ::workerd::rust::jsg::ModuleRegistry {
74 ::workerd::jsg::modules::ModuleBundle::BuiltinBuilder& builder;
75 
76 explicit RustBuiltinModuleAdapter(::workerd::jsg::modules::ModuleBundle::BuiltinBuilder& builder)
77 : builder(builder) {}
78 
79 void addBuiltinModule(
80 ::rust::Str specifier, ModuleCallback moduleCallback, ModuleType moduleType) override {
81 // Convert ::rust::Str to kj::ArrayPtr<const char> for URL parsing.
82 auto specifierPtr = kj::ArrayPtr<const char>(specifier.data(), specifier.size());
83 KJ_IF_SOME(url, ::workerd::jsg::Url::tryParse(specifierPtr)) {
84 builder.addSynthetic(url,
85 [callback = kj::mv(moduleCallback)](::workerd::jsg::Lock& js, const ::workerd::jsg::Url&,
86 const ::workerd::jsg::modules::Module::ModuleNamespace& ns,
87 const ::workerd::jsg::CompilationObserver&) mutable {
88 auto localValue = callback(js.v8Isolate);
89 auto value = local_from_ffi<v8::Value>(kj::mv(localValue));
90 KJ_DASSERT(value->IsObject());
91 ns.setDefault(js, ::workerd::jsg::JsValue(value));
92 return true;
93 });
94 } else {
95 KJ_LOG(WARNING, "Ignoring Rust module with invalid specifier", specifierPtr);
96 }
97 }
98};
99 
100} // namespace workerd::rust::jsg