Add ExternalShared and RawRefCount (#23013)

Add `bun.ptr.ExternalShared`, a shared pointer whose reference count is
managed externally; e.g., by extern functions. This can be used to work
with `RefCounted` C++ objects in Zig. For example:

```cpp
// C++:
struct MyType : RefCounted<MyType> { ... };
extern "C" void MyType__ref(MyType* self) { self->ref(); }
extern "C" void MyType__ref(MyType* self) { self->deref(); }
```

```zig
// Zig:
const MyType = opaque {
    extern fn MyType__ref(self: *MyType) void;
    extern fn MyType__deref(self: *MyType) void;

    pub const Ref = bun.ptr.ExternalShared(MyType);

    // This enables `ExternalShared` to work.
    pub const external_shared_descriptor = struct {
        pub const ref = MyType__ref;
        pub const deref = MyType__deref;
    };
};

// Now `MyType.Ref` behaves just like `Ref<MyType>` in C++:
var some_ref: MyType.Ref = someFunctionReturningMyTypeRef();
const ptr: *MyType = some_ref.get(); // gets the inner pointer
var some_other_ref = some_ref.clone(); // increments the ref count
some_ref.deinit(); // decrements the ref count
// decrements the ref count again; if no other refs exist, the object
// is destroyed
some_other_ref.deinit();
```

This commit also adds `RawRefCount`, a simple wrapper around an integer
reference count that can be used to implement the interface required by
`ExternalShared`. Generally, for reference-counted Zig types,
`bun.ptr.Shared` is preferred, but occasionally it is useful to have an
“intrusive” reference-counted type where the ref count is stored in the
type itself. For this purpose, `ExternalShared` + `RawRefCount` is more
flexible and less error-prone than the deprecated `bun.ptr.RefCounted`
type.

(For internal tracking: fixes STAB-1287, STAB-1288)
This commit is contained in:
taylor.fish
2025-09-26 15:15:58 -07:00
committed by GitHub
parent 9d01a7b91a
commit 266fca2e5c
4 changed files with 197 additions and 0 deletions

View File

@@ -217,8 +217,16 @@ pub const WTFStringImplStruct = extern struct {
pub fn hasPrefix(self: WTFStringImpl, text: []const u8) bool {
return bun.cpp.Bun__WTFStringImpl__hasPrefix(self, text.ptr, text.len);
}
pub const external_shared_descriptor = struct {
pub const ref = WTFStringImplStruct.ref;
pub const deref = WTFStringImplStruct.deref;
};
};
/// Behaves like `WTF::Ref<WTF::StringImpl>`.
pub const WTFString = bun.ptr.ExternalShared(WTFStringImplStruct);
pub const StringImplAllocator = struct {
fn alloc(ptr: *anyopaque, len: usize, _: std.mem.Alignment, _: usize) ?[*]u8 {
var this = bun.cast(WTFStringImpl, ptr);