// Copyright (c) 2026 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 #pragma once #include #include #include #include #include #include #include #include // Forward declarations needed by v8.rs.h namespace workerd::rust::jsg { using Isolate = v8::Isolate; using FunctionCallbackInfo = v8::FunctionCallbackInfo; struct ModuleRegistry; struct Local; struct MaybeLocal; struct Global; struct TracedReference; struct Realm; struct GcVisitor; enum class BackingStoreInitializationMode : ::std::uint8_t; enum class ExceptionType : ::std::uint8_t; // ModuleType enum is generated by CXX in v8.rs.h - forward declare it here enum class ModuleType : ::std::uint8_t; using ModuleCallback = ::rust::Fn; // Mirrors the CXX shared struct defined in v8.rs. Must be kept in sync. // The CXX-generated v8.rs.h provides the canonical definition; this is // only used when ffi.h is included before v8.rs.h (e.g. from ffi.c++ // before the CXX bridge is compiled). #ifndef CXXBRIDGE1_STRUCT_workerd$rust$jsg$TraitObjectPtr #define CXXBRIDGE1_STRUCT_workerd$rust$jsg$TraitObjectPtr struct TraitObjectPtr { uintptr_t data_ptr = 0; uintptr_t vtable_ptr = 0; uintptr_t type_id_lo = 0; uintptr_t type_id_hi = 0; }; #endif // A Wrappable subclass for Rust objects. // // Lives on the KJ heap (via kj::Refcounted through Wrappable) and integrates // with cppgc via the CppgcShim bridge pattern that Wrappable provides. // // The data[] field stores a Rust fat pointer (data + vtable) to `dyn GarbageCollected` // from a leaked Box. This lets us call back into Rust for tracing // and destruction without knowing the concrete type at compile time. class Wrappable: public ::workerd::jsg::Wrappable { public: ~Wrappable(); void jsgVisitForGc(::workerd::jsg::GcVisitor& visitor) override; kj::StringPtr jsgGetMemoryName() const override; size_t jsgGetMemorySelfSize() const override; // Returns a new kj::Rc reference to this Wrappable. kj::Rc toRc() { return addRefToThis(); } // Rust trait object pointer + TypeId, stored by Ref::new(). // Defined as a CXX shared struct in v8.rs; contains data_ptr, vtable_ptr, // type_id_lo, type_id_hi. TraitObjectPtr trait_object = {0, 0, 0, 0}; }; struct ResourceDescriptor; // Wrappable lifecycle — returns KjRc to Rust for reference-counted ownership. // Ref::clone calls wrappable_add_strong_ref; Ref::drop calls wrappable_remove_strong_ref. // wrappable_remove_strong_ref does addRef(+1) + maybeDeferDestruction(-1) = net 0 on kj::Rc; // the actual kj::Rc decrement happens when WrappableRc (KjRc) is dropped. kj::Rc wrappable_new(TraitObjectPtr ptr); kj::Rc wrappable_to_rc(Wrappable& wrappable); void wrappable_add_strong_ref(Wrappable& wrappable); void wrappable_remove_strong_ref(Wrappable& wrappable, bool is_strong); void wrappable_visit_ref( Wrappable& wrappable, uintptr_t* ref_parent, bool* ref_strong, GcVisitor* visitor); /// Visit a `v8::Global` field during GC tracing, implementing the same /// strong↔traced dual-mode switching as `jsg::Data` / `jsg::V8Ref`. /// /// `global` points to the `ptr` field of `ffi::Global` (the strong handle). /// `traced` is the `ffi::TracedReference` slot from `Global` on the Rust side. /// Both are mutated in-place by this function. void wrappable_visit_global(GcVisitor* visitor, uintptr_t* global, TracedReference& traced); /// Resets a `v8::TracedReference`, releasing the weak GC handle. /// Must be called when a `Global` is dropped in traced mode to avoid /// leaking a live `v8::TracedReference`. void traced_reference_reset(TracedReference& traced); // Local void local_drop(Local value); Local local_clone(const Local& value); Global local_to_global(Isolate* isolate, Local value); Local local_new_number(Isolate* isolate, double value); Local local_new_string(Isolate* isolate, ::rust::Str value); Local local_new_boolean(Isolate* isolate, bool value); Local local_new_object(Isolate* isolate); Local local_new_null(Isolate* isolate); Local local_new_undefined(Isolate* isolate); bool local_eq(const Local& lhs, const Local& rhs); bool local_has_value(const Local& val); bool local_is_string(const Local& val); bool local_is_boolean(const Local& val); bool local_is_number(const Local& val); bool local_is_null(const Local& val); bool local_is_undefined(const Local& val); bool local_is_null_or_undefined(const Local& val); bool local_is_object(const Local& val); bool local_is_native_error(const Local& val); bool local_is_array(const Local& val); bool local_is_uint8_array(const Local& val); bool local_is_uint16_array(const Local& val); bool local_is_uint32_array(const Local& val); bool local_is_int8_array(const Local& val); bool local_is_int16_array(const Local& val); bool local_is_int32_array(const Local& val); bool local_is_float32_array(const Local& val); bool local_is_float64_array(const Local& val); bool local_is_bigint64_array(const Local& val); bool local_is_biguint64_array(const Local& val); bool local_is_float16_array(const Local& val); bool local_is_uint8clamped_array(const Local& val); bool local_is_array_buffer(const Local& val); bool local_is_array_buffer_view(const Local& val); bool local_is_shared_array_buffer(const Local& val); bool local_is_function(const Local& val); bool local_is_symbol(const Local& val); bool local_is_name(const Local& val); ::rust::String local_type_of(Isolate* isolate, const Local& val); // Local Local local_string_empty(Isolate* isolate); int32_t local_string_length(const Local& value); bool local_string_is_one_byte(const Local& value); bool local_string_contains_only_one_byte(const Local& value); size_t local_string_utf8_length(Isolate* isolate, const Local& value); void local_string_write_v2(Isolate* isolate, const Local& value, uint32_t offset, uint32_t length, uint16_t* buffer, int32_t flags); void local_string_write_one_byte_v2(Isolate* isolate, const Local& value, uint32_t offset, uint32_t length, uint8_t* buffer, int32_t flags); size_t local_string_write_utf8_v2( Isolate* isolate, const Local& value, uint8_t* buffer, size_t capacity, int32_t flags); bool local_string_equals(const Local& value, const Local& other); bool local_string_is_flat(const Local& value); Local local_string_concat(Isolate* isolate, Local left, Local right); Local local_string_internalize(Isolate* isolate, const Local& value); MaybeLocal local_string_new_from_utf8( Isolate* isolate, const uint8_t* data, int32_t length, bool internalized); MaybeLocal local_string_new_from_one_byte( Isolate* isolate, const uint8_t* data, int32_t length, bool internalized); MaybeLocal local_string_new_from_two_byte( Isolate* isolate, const uint16_t* data, int32_t length, bool internalized); bool maybe_local_is_empty(const MaybeLocal& value); // Local int32_t local_name_get_identity_hash(const Local& value); // Local Local local_symbol_new(Isolate* isolate); Local local_symbol_new_with_description(Isolate* isolate, Local description); MaybeLocal local_symbol_description(Isolate* isolate, const Local& value); // Local Local local_function_call( Isolate* isolate, const Local& function, const Local& recv, ::rust::Slice args); // Local void local_object_set_property(Isolate* isolate, Local& object, ::rust::Str key, Local value); bool local_object_has_property(Isolate* isolate, const Local& object, ::rust::Str key); kj::Maybe local_object_get_property(Isolate* isolate, const Local& object, ::rust::Str key); // Local Local local_new_array(Isolate* isolate, size_t length); uint32_t local_array_length(Isolate* isolate, const Local& array); Local local_array_get(Isolate* isolate, const Local& array, uint32_t index); void local_array_set(Isolate* isolate, Local& array, uint32_t index, Local value); ::rust::Vec local_array_iterate(Isolate* isolate, Local value); // Local Local local_new_uint8_array(Isolate* isolate, const uint8_t* data, size_t length); Local local_new_uint16_array(Isolate* isolate, const uint16_t* data, size_t length); Local local_new_uint32_array(Isolate* isolate, const uint32_t* data, size_t length); Local local_new_int8_array(Isolate* isolate, const int8_t* data, size_t length); Local local_new_int16_array(Isolate* isolate, const int16_t* data, size_t length); Local local_new_int32_array(Isolate* isolate, const int32_t* data, size_t length); Local local_new_float32_array(Isolate* isolate, const float* data, size_t length); Local local_new_float64_array(Isolate* isolate, const double* data, size_t length); Local local_new_bigint64_array(Isolate* isolate, const int64_t* data, size_t length); Local local_new_biguint64_array(Isolate* isolate, const uint64_t* data, size_t length); size_t local_typed_array_length(Isolate* isolate, const Local& array); // Returns a raw pointer to the underlying ArrayBuffer's data (without byte offset). // Use local_typed_array_byte_offset to compute the start of this view's data. uintptr_t local_typed_array_buffer_data(Isolate* isolate, const Local& array); // Returns the byte offset of this TypedArray view within its backing ArrayBuffer. size_t local_typed_array_byte_offset(Isolate* isolate, const Local& array); // Returns the byte length of the TypedArray. size_t local_typed_array_byte_length(Isolate* isolate, const Local& array); uint8_t local_uint8_array_get(Isolate* isolate, const Local& array, size_t index); uint16_t local_uint16_array_get(Isolate* isolate, const Local& array, size_t index); uint32_t local_uint32_array_get(Isolate* isolate, const Local& array, size_t index); int8_t local_int8_array_get(Isolate* isolate, const Local& array, size_t index); int16_t local_int16_array_get(Isolate* isolate, const Local& array, size_t index); int32_t local_int32_array_get(Isolate* isolate, const Local& array, size_t index); float local_float32_array_get(Isolate* isolate, const Local& array, size_t index); double local_float64_array_get(Isolate* isolate, const Local& array, size_t index); int64_t local_bigint64_array_get(Isolate* isolate, const Local& array, size_t index); uint64_t local_biguint64_array_get(Isolate* isolate, const Local& array, size_t index); uint8_t local_uint8clamped_array_get(Isolate* isolate, const Local& array, size_t index); // Local Local local_new_array_buffer(Isolate* isolate, const uint8_t* data, size_t length); Local local_new_array_buffer_empty(Isolate* isolate, size_t byte_length); kj::Maybe array_buffer_new_with_mode( Isolate* isolate, size_t byte_length, BackingStoreInitializationMode mode); Local array_buffer_from_backing_store(Isolate* isolate, size_t store); size_t local_array_buffer_byte_length(Isolate* isolate, const Local& buffer); uint8_t* local_array_buffer_data(Isolate* isolate, const Local& buffer); size_t local_array_buffer_get_backing_store(Isolate* isolate, const Local& buffer); // Local size_t local_array_buffer_view_byte_offset(Isolate* isolate, const Local& view); size_t local_array_buffer_view_byte_length(Isolate* isolate, const Local& view); uint8_t* local_array_buffer_view_buffer_data(Isolate* isolate, const Local& view); Local local_array_buffer_view_get_buffer(Isolate* isolate, const Local& view); size_t local_array_buffer_view_element_size(Isolate* isolate, const Local& view); bool local_array_buffer_view_is_integer_type(Isolate* isolate, const Local& view); // BackingStore size_t backing_store_new_resizable(size_t byte_length, size_t max_byte_length); void backing_store_drop(size_t ptr); uint8_t* backing_store_data(size_t ptr); size_t backing_store_byte_length(size_t ptr); size_t backing_store_max_byte_length(size_t ptr); bool backing_store_is_shared(size_t ptr); bool backing_store_is_resizable_by_user_javascript(size_t ptr); // Global void global_reset(Global& value); Global global_clone(Isolate* isolate, const Global& value); Local global_to_local(Isolate* isolate, const Global& value); // Wrappable - data access const TraitObjectPtr& wrappable_get_trait_object(const Wrappable& wrappable); void wrappable_clear_trait_object(Wrappable& wrappable); kj::uint wrappable_strong_refcount(const Wrappable& wrappable); // Wrappers Local wrap_resource(Isolate* isolate, kj::Rc wrappable, const Global& tmpl); void wrappable_attach_wrapper(kj::Rc wrappable, FunctionCallbackInfo& args); // Unwrappers ::rust::String unwrap_string(Isolate* isolate, Local value); bool unwrap_boolean(Isolate* isolate, Local value); double unwrap_number(Isolate* isolate, Local value); kj::Rc unwrap_resource(Isolate* isolate, Local value); ::rust::Vec unwrap_uint8_array(Isolate* isolate, Local value); ::rust::Vec unwrap_uint16_array(Isolate* isolate, Local value); ::rust::Vec unwrap_uint32_array(Isolate* isolate, Local value); ::rust::Vec unwrap_int8_array(Isolate* isolate, Local value); ::rust::Vec unwrap_int16_array(Isolate* isolate, Local value); ::rust::Vec unwrap_int32_array(Isolate* isolate, Local value); ::rust::Vec unwrap_float32_array(Isolate* isolate, Local value); ::rust::Vec unwrap_float64_array(Isolate* isolate, Local value); ::rust::Vec unwrap_bigint64_array(Isolate* isolate, Local value); ::rust::Vec unwrap_biguint64_array(Isolate* isolate, Local value); // ArrayBuffer detach/detachable/was-detached void local_array_buffer_detach(Isolate* isolate, Local& buffer); bool local_array_buffer_was_detached(Isolate* isolate, const Local& buffer); bool local_array_buffer_is_detachable(Isolate* isolate, const Local& buffer); // Value-level shared check bool local_array_buffer_is_shared(const Local& value); // FunctionCallbackInfo Isolate* fci_get_isolate(FunctionCallbackInfo* args); Local fci_get_this(FunctionCallbackInfo* args); size_t fci_get_length(FunctionCallbackInfo* args); Local fci_get_arg(FunctionCallbackInfo* args, size_t index); void fci_set_return_value(FunctionCallbackInfo* args, Local value); // Utf8Value — ptr holds a heap-allocated v8::String::Utf8Value*. // The complete struct definition is generated by CXX from the shared struct in v8.rs. struct Utf8Value; // utf8_value_new converts `value` to a UTF-8 string, producing a heap-allocated copy // of the UTF-8 bytes that is independent of the V8 heap. The caller must call // utf8_value_drop to free it. // utf8_value_data returns a pointer into this copy (not into V8 memory); it is valid // for the lifetime of the Utf8Value and must not be used after utf8_value_drop. // utf8_value_length returns the number of bytes (excluding the null terminator). Utf8Value utf8_value_new(Isolate* isolate, Local value); void utf8_value_drop(Utf8Value value); size_t utf8_value_length(const Utf8Value& value); const uint8_t* utf8_value_data(const Utf8Value& value); struct ModuleRegistry { virtual ~ModuleRegistry() = default; virtual void addBuiltinModule( ::rust::Str specifier, ModuleCallback moduleCallback, ModuleType moduleType) = 0; }; inline void register_add_builtin_module(ModuleRegistry& registry, ::rust::Str specifier, ModuleCallback callback, ModuleType moduleType) { registry.addBuiltinModule(specifier, kj::mv(callback), moduleType); } Global create_resource_template(Isolate* isolate, const ResourceDescriptor& descriptor); // FunctionTemplate Local function_template_get_function(Isolate* isolate, const Global& tmpl); // Realm Realm* realm_from_isolate(Isolate* isolate); // Errors Local exception_create(Isolate* isolate, ExceptionType exception_type, ::rust::Str message); // Isolate void isolate_throw_exception(Isolate* isolate, Local exception); void isolate_throw_error(Isolate* isolate, ::rust::Str message); void isolate_throw_internal_error(Isolate* isolate, ::rust::Str internalMessage); void isolate_terminate_execution(Isolate* isolate); bool isolate_is_locked(Isolate* isolate); } // namespace workerd::rust::jsg