Files
bun.sh/src/ptr/weak_ptr.zig
Jarred Sumner 3ea6133c46 CI: Remove unused top-level decls in formatter in zig (#19879)
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-23 22:49:48 -07:00

70 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");