use tagged union

This commit is contained in:
Hamcha 2024-05-06 01:06:58 +02:00
parent c3ab5c0d41
commit 22e1bcccea
Signed by: hamcha
GPG key ID: 1669C533B8CF6D89

View file

@ -27,6 +27,7 @@ const Font = struct {
while (iterator.next()) |char| { while (iterator.next()) |char| {
char.deinit(allocator); char.deinit(allocator);
} }
allocator.free(self.name);
self.characters.deinit(); self.characters.deinit();
} }
}; };
@ -40,9 +41,13 @@ const Command = enum {
_IGNORED, _IGNORED,
}; };
const Line = struct { const ParsedCommand = union(Command) {
command: Command, FONT: []const u8,
params: []const u8, FONTBOUNDINGBOX: struct { width: u8, height: u8 },
ENCODING: u16,
BITMAP: void,
STARTCHAR: []const u8,
_IGNORED: void,
}; };
pub fn parse(allocator: std.mem.Allocator, bdf: anytype) !Font { pub fn parse(allocator: std.mem.Allocator, bdf: anytype) !Font {
@ -56,55 +61,77 @@ pub fn parse(allocator: std.mem.Allocator, bdf: anytype) !Font {
var bufferedReader = std.io.bufferedReader(bdf); var bufferedReader = std.io.bufferedReader(bdf);
var reader = bufferedReader.reader(); var reader = bufferedReader.reader();
var currentName: []const u8 = undefined; var arenaAllocator = std.heap.ArenaAllocator.init(allocator);
defer arenaAllocator.deinit();
var currentName: []u8 = undefined;
var currentCharacter: u16 = 0; var currentCharacter: u16 = 0;
while (true) { while (true) {
var lineBuffer: [1024]u8 = undefined; var lineBuffer: [1024]u8 = undefined;
const nextLine = try reader.readUntilDelimiterOrEof(&lineBuffer, '\n') orelse break; const nextLine = try reader.readUntilDelimiterOrEof(&lineBuffer, '\n') orelse break;
// Parse line // Parse line
const line = try parseLine(nextLine); const line = try parseLine(arenaAllocator.allocator(), nextLine);
switch (line.command) { switch (line) {
.FONT => { .FONT => |name| {
font.name = line.params; font.name = try allocator.dupe(u8, name);
std.log.debug("Font: {s}", .{font.name}); std.log.debug("Font: {s}", .{name});
}, },
.FONTBOUNDINGBOX => { .FONTBOUNDINGBOX => |box| {
var boundingBox = std.mem.splitScalar(u8, line.params, ' '); font.width = box.width;
font.width = try std.fmt.parseInt(u8, boundingBox.next().?, 10); font.height = box.height;
font.height = try std.fmt.parseInt(u8, boundingBox.next().?, 10); std.log.debug("Bounding box: {d}x{d}", .{ box.width, box.height });
},
std.log.debug("Bounding box: {d}x{d}", .{ font.width, font.height }); .STARTCHAR => |name| {
currentName = try allocator.dupe(u8, name);
},
.ENCODING => |num| {
currentCharacter = num;
}, },
.BITMAP => { .BITMAP => {
const bitmap = try readBitmap(allocator, font.width, font.height, reader); const bitmap = try readBitmap(allocator, font.width, font.height, reader);
try font.characters.put(currentCharacter, .{ try font.characters.put(currentCharacter, .{
.name = try allocator.dupe(u8, currentName), .name = currentName,
.bitmap = bitmap, .bitmap = bitmap,
}); });
}, },
.STARTCHAR => { ._IGNORED => {},
currentName = line.params;
},
.ENCODING => {
// This probably breaks with custom encodings, not doing anything for now
currentCharacter = try std.fmt.parseInt(u16, line.params, 10);
},
else => {},
} }
} }
return font; return font;
} }
fn parseLine(line: []const u8) !Line { fn parseLine(allocator: std.mem.Allocator, line: []const u8) !ParsedCommand {
const firstSpace = std.mem.indexOfScalar(u8, line, ' ') orelse line.len; const firstSpace = std.mem.indexOfScalar(u8, line, ' ') orelse line.len;
const command = line[0..firstSpace]; const command = std.meta.stringToEnum(Command, line[0..firstSpace]) orelse Command._IGNORED;
return .{ const rest = if (firstSpace == line.len) "" else line[firstSpace + 1 ..];
.command = std.meta.stringToEnum(Command, command) orelse Command._IGNORED,
.params = if (firstSpace == line.len) "" else line[firstSpace + 1 ..], switch (command) {
}; .ENCODING => {
return ParsedCommand{ .ENCODING = try std.fmt.parseInt(u16, rest, 10) };
},
.BITMAP => {
return ParsedCommand{ .BITMAP = {} };
},
.STARTCHAR => {
return ParsedCommand{ .STARTCHAR = try allocator.dupe(u8, rest) };
},
.FONT => {
return ParsedCommand{ .FONT = try allocator.dupe(u8, rest) };
},
.FONTBOUNDINGBOX => {
var boundingBox = std.mem.splitScalar(u8, rest, ' ');
return ParsedCommand{ .FONTBOUNDINGBOX = .{
.width = try std.fmt.parseInt(u8, boundingBox.next().?, 10),
.height = try std.fmt.parseInt(u8, boundingBox.next().?, 10),
} };
},
._IGNORED => {
return ParsedCommand{ ._IGNORED = {} };
},
}
} }
fn readBitmap( fn readBitmap(