diff --git a/src/sys.zig b/src/sys.zig index 94a87ec..f6016ef 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -12,7 +12,8 @@ const std = @import("std"); /// pub const EventLoop = opaque { /// - /// + /// Linked list of messages chained together to be processed by the internal file system message + /// processor of an [EventLoop]. /// const FileSystemMessage = struct { next: ?*FileSystemMessage = null, @@ -22,7 +23,12 @@ pub const EventLoop = opaque { exit, close: struct { - file_access: *FileAccess, + file_system_path: *FileAccess, + }, + + log: struct { + message: []const u8, + kind: LogKind, }, open: struct { @@ -52,7 +58,7 @@ pub const EventLoop = opaque { }; /// - /// + /// Internal state of the event loop hidden from the API consumer. /// const Implementation = struct { user_prefix: []const u8, @@ -61,21 +67,51 @@ pub const EventLoop = opaque { file_system_thread: *ext.SDL_Thread, file_system_messages: ?*FileSystemMessage = null, + /// + /// Casts `event_loop` to a [Implementation] reference. + /// + /// *Note* that if `event_loop` does not have the same alignment as [Implementation], + /// safety-checked undefined behavior will occur. + /// fn cast(event_loop: *EventLoop) *Implementation { return @ptrCast(*Implementation, @alignCast(@alignOf(Implementation), event_loop)); } }; /// + /// [LogKind.info] represents a log message which is purely informative and does not indicate + /// any kind of issue. /// + /// [LogKind.debug] represents a log message which is purely for debugging purposes and will + /// only occurs in debug builds. /// - pub const OpenError = error { - NotFound, - BadFileSystem, + /// [LogKind.warning] represents a log message which is a warning about a issue that does not + /// break anything important but is not ideal. + /// + pub const LogKind = enum(c_int) { + info = ext.SDL_LOG_PRIORITY_INFO, + debug = ext.SDL_LOG_PRIORITY_DEBUG, + warning = ext.SDL_LOG_PRIORITY_WARN, }; /// + /// [OpenError.NotFound] is a catch-all for when a file could not be located to be opened. This + /// may be as simple as it doesn't exist or the because the underlying file-system will not / + /// cannot give access to it at this time. /// + pub const OpenError = error { + NotFound, + }; + + /// + /// [OpenMode.readonly] indicates that an existing file is opened in a read-only state, + /// disallowing write access. + /// + /// [OpenMode.overwrite] indicates that an empty file has been created or an existing file has + /// been completely overwritten into. + /// + /// [OpenMode.append] indicates that an existing file that has been opened for reading from and + /// writing to on the end of existing data. /// pub const OpenMode = enum { readonly, @@ -84,16 +120,23 @@ pub const EventLoop = opaque { }; /// + /// [SeekOrigin.head] indicates that a seek operation will seek from the offset origin of the + /// file beginning, or "head". /// + /// [SeekOrigin.tail] indicates that a seek operation will seek from the offset origin of the + /// file end, or "tail". + /// + /// [SeekOrigin.cursor] indicates that a seek operation will seek from the current position of + /// the file cursor. /// pub const SeekOrigin = enum { head, tail, - current, + cursor, }; /// - /// + /// Closes access to the file referenced by `file_access` via `event_loop`. /// pub fn close(event_loop: *EventLoop, file_access: *FileAccess) void { var message = FileSystemMessage{ @@ -105,9 +148,10 @@ pub const EventLoop = opaque { } /// + /// Enqueues `message` to the file system message processor to be processed at a later, non- + /// deterministic point. /// - /// - pub fn enqueueFileSystemMessage(event_loop: *EventLoop, message: *FileSystemMessage) void { + fn enqueueFileSystemMessage(event_loop: *EventLoop, message: *FileSystemMessage) void { const implementation = Implementation.cast(event_loop); // TODO: Error check this. @@ -125,19 +169,35 @@ pub const EventLoop = opaque { } /// + /// Writes `message` to the application log with `kind` via `event_loop`. /// + /// *Note* that `message` is not guaranteed to be partly, wholely, or at all written. /// - pub fn log(event_loop: *EventLoop, message: []const u8) void { - // TODO: Implement. - _ = event_loop; - _ = message; + pub fn log(event_loop: *EventLoop, kind: LogKind, message: []const u8) void { + var message = FileSystemMessage{ + .frame = @frame(), + + .request = .{.log = .{ + .message = message, + .kind = kind, + }}, + }; + + suspend event_loop.enqueueFileSystemMessage(&message); } /// + /// Attempts to open access to a file referenced at `file_system_path` using `mode` as the way + /// to open it via `event_loop`. /// + /// A [FileAccess] pointer is returned referencing the opened file or a [OpenError] if the file + /// could not be opened. + /// + /// *Note* that all files are opened in "binary-mode", or Unix-mode. There are no conversions + /// applied when data is accessed from a file. /// pub fn open(event_loop: *EventLoop, mode: OpenMode, - path: FileSystem.Path) OpenError!*FileAccess { + file_system_path: FileSystem.Path) OpenError!*FileAccess { var message = FileSystemMessage{ .frame = @frame(), @@ -145,7 +205,7 @@ pub const EventLoop = opaque { .request = .{ .open = .{ .mode = mode, - .path = &path, + .file_system_path = &file_system_path, }, }, }; @@ -166,6 +226,9 @@ pub const EventLoop = opaque { switch (messages.request) { .exit => return 0, + .log => |*log_request| ext.SDL_LogMessage(ext.SDL_LOG_CATEGORY_APPLICATION, + @enumToInt(log_request.priority), log_request.message), + .open => |*open_request| { switch (open_request.path.file_system) { .data => { @@ -232,7 +295,11 @@ pub const EventLoop = opaque { } /// + /// Attempts to read the contents of the file referenced by `file_access` at the current file + /// cursor position into `buffer`. /// + /// The number of bytes that could be read / fitted into `buffer` is returned or a [FileError] + /// if the file failed to be read. /// pub fn readFile(event_loop: *EventLoop, file_access: *FileAccess, buffer: []const u8) FileError!usize {