blob: 73cc6e5119612c0e7abb5b2e6c3862ef4c02a6f0 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
const std = @import("std");
const gtk = @import("gtk");
const gobject = @import("gobject");
/// A lightweight wrapper around gobject.WeakRef to make it type-safe
/// to hold a single type of value.
pub fn WeakRef(comptime T: type) type {
return struct {
const Self = @This();
ref: gobject.WeakRef = std.mem.zeroes(gobject.WeakRef),
pub const empty: Self = .{};
/// Set the weak reference to the given object. This will not
/// increase the reference count of the object.
pub fn set(self: *Self, v_: ?*T) void {
if (v_) |v| {
self.ref.set(v.as(gobject.Object));
} else {
self.ref.set(null);
}
}
/// Release this weak reference.
///
/// You MUST call this before the memory holding this struct is freed,
/// which in practice means from the owner's `dispose`. The target keeps
/// a pointer to this `GWeakRef` so that it can clear it when the target
/// is finalized; if this memory is gone by then, the target walks into
/// whatever now occupies it. That is an invalid read at best, and can
/// hang: the target takes a lock inside each registered weak ref, and
/// reused memory with the low bit set is a lock nothing will release.
///
/// `set(null)` also unregisters and remains valid. This exists so the
/// requirement has a name at the use site rather than looking like an
/// ordinary assignment.
pub fn deinit(self: *Self) void {
self.ref.clear();
}
/// Get a strong reference to the object, or null if the object
/// has been finalized. This increases the reference count by one.
pub fn get(self: *Self) ?*T {
// We can't use `as` because `as` guarantees conversion and
// that can't be statically guaranteed.
return gobject.ext.cast(T, self.ref.get() orelse return null);
}
};
}
test WeakRef {
const testing = std.testing;
var ref: WeakRef(gtk.TextBuffer) = .empty;
const obj: *gtk.TextBuffer = .new(null);
ref.set(obj);
ref.get().?.unref(); // The "?" asserts non-null
obj.unref();
try testing.expect(ref.get() == null);
}
|