Files
bun.sh/src/ptr/weak_ptr.zig
2025-04-17 12:32:47 -07:00

71 lines
2.0 KiB
Zig

pub const WeakPtrData = packed struct(u32) {
reference_count: u31,
finalized: bool,
pub const empty: @This() = .{
.reference_count = 0,
.finalized = false,
};
pub fn onFinalize(this: *WeakPtrData) bool {
bun.debugAssert(!this.finalized);
this.finalized = true;
return this.reference_count == 0;
}
};
/// Allow a type to be weakly referenced. This keeps a reference count of how
/// many weak-references exist, so that when the object is destroyed, the inner
/// contents can be freed, but the object itself is not destroyed until all
/// `WeakPtr`s are released. Even if the allocation is present, `WeakPtr(T).get`
/// will return null after the inner contents are freed.
pub fn WeakPtr(comptime T: type, data_field: []const u8) type {
return struct {
pub const Data = WeakPtrData;
raw_ptr: ?*T,
pub const empty: @This() = .{ .raw_ptr = null };
pub fn initRef(req: *T) @This() {
bun.debugAssert(!data(req).finalized);
data(req).reference_count += 1;
return .{ .raw_ptr = req };
}
pub fn deref(this: *@This()) void {
if (this.raw_ptr) |value| {
this.derefInternal(value);
}
}
pub fn get(this: *@This()) ?*T {
if (this.raw_ptr) |value| {
if (!data(value).finalized) {
return value;
}
this.derefInternal(value);
}
return null;
}
fn derefInternal(this: *@This(), value: *T) void {
const weak_data = data(value);
this.raw_ptr = null;
const count = weak_data.reference_count - 1;
weak_data.reference_count = count;
if (weak_data.finalized and count == 0) {
bun.destroy(value);
}
}
fn data(value: *T) *WeakPtrData {
return &@field(value, data_field);
}
};
}
pub const bun = @import("bun");
const std = @import("std");