Large struct in a union
Description
A large struct travels in a union of events.
It is never copied.
When you need it
Small events travel by value in a tagged union.
A union field stores a copy of what you put in.
A large struct must not be copied.
What it does
- Call
setTypeIdon aDownload. Its 4 KB buffer is too large to copy. - Build three
Events: a tick, a resize and theDownload'sAny. - Copy the events into a second array, as a queue would.
- Handle each event.
- Get the
Downloadback withfromAny. - Check that it is the same
Download, not a copy.
What to notice
The union field is an Any: the address and the type id. Two words.
Each Event stays small.
The Download MUST stay alive while its event is in use.
Source
/// It is too large to copy. Events carry its address and type id.
const Download: type = struct {
tnode: paternitas.SinglyTypedNode = .{},
buffer: [4096]u8 = undefined,
received: usize = 0,
};
const TypedDownload: type = paternitas.Typed(Download);
const Event: type = union(enum) {
tick: u64,
resize: Size,
parent: paternitas.Any,
};
const Size: type = struct {
width: u16,
height: u16,
};
pub fn large_struct_in_union(allocator: std.mem.Allocator, io: std.Io) !void {
_ = allocator;
_ = io;
var download: Download = .{};
TypedDownload.setTypeId(&download);
const sent: [3]Event = .{
.{ .tick = 1 },
.{ .resize = .{ .width = 80, .height = 24 } },
.{ .parent = TypedDownload.toAny(&download) },
};
// Copy the events, as a queue would. Each Event is small. The Download
// is not in it.
var received: [sent.len]Event = undefined;
@memcpy(&received, &sent);
std.log.info("one Event: {d} bytes, one Download: {d} bytes", .{ @sizeOf(Event), @sizeOf(Download) });
for (received) |e| try handle(e);
if (download.received != 1) return error.NotTheSameDownload;
}
fn handle(e: Event) !void {
switch (e) {
.tick => |t| std.log.info("tick {d}", .{t}),
.resize => |s| std.log.info("resize {d}x{d}", .{ s.width, s.height }),
.parent => |any| {
const d: *Download = TypedDownload.fromAny(any) orelse return error.UnknownParent;
d.*.received += 1;
std.log.info("download, {d} bytes of buffer", .{d.*.buffer.len});
},
}
}
const paternitas = @import("paternitas");
const std = @import("std");