lib/alloc/observe/src/buffer.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const adapter = @import("allocator.zig");
3 const protocol = @import("protocol.zig");
4
5 /// A buffer-first allocator type that manages allocations from an initial
6 /// caller-provided buffer before falling back to a secondary allocator. In
7 /// disabled builds, this type aliases `std.heap.BufferFirstAllocator`. In
8 /// enabled builds, it wraps that allocator and exposes only `init` and
9 /// `allocator`, forwarding allocation calls through an internal
10 /// `ObservedAllocator` tagged with the `buffer_first` producer kind. The
11 /// wrapper acts solely as an allocator adapter and adds no lifecycle records.
12 pub const First = if (protocol.enabled)
13 ObservedFirst
14 else
15 std.heap.BufferFirstAllocator;
16
17 const ObservedFirst = struct {
18 inner: std.heap.BufferFirstAllocator,
19 observed: adapter.ObservedAllocator = undefined,
20 producer_id: u64,
21
22 const Self = @This();
23
24 /// Initializes the buffer-first allocator by passing the caller-supplied
25 /// initial buffer slice and fallback allocator to the underlying
26 /// implementation, assigning a unique producer identifier when observation
27 /// is enabled. The allocator borrows the buffer without copying or taking
28 /// ownership of it. Callers must ensure that both the initial memory buffer
29 /// and the fallback allocator remain valid and stable for the entire
30 /// operational lifetime of the instance.
31 pub fn init(buffer: []u8, fallback: std.mem.Allocator) Self {
32 return .{
33 .inner = std.heap.BufferFirstAllocator.init(buffer, fallback),
34 .producer_id = protocol.producerId(),
35 };
36 }
37
38 /// Returns a borrowed allocator handle backed by the stable instance. In
39 /// enabled builds, this call initializes an embedded adapter pointing to
40 /// the underlying buffer-first allocator. The method offers no
41 /// thread-safety guarantees for concurrent calls on the same instance, so
42 /// callers must serialize access or complete handle creation before
43 /// sharing.
44 pub fn allocator(self: *Self) std.mem.Allocator {
45 self.observed = adapter.ObservedAllocator.init(
46 self.inner.allocator(),
47 self.producer_id,
48 .buffer_first,
49 );
50 return self.observed.allocator();
51 }
52 };