diff --git a/src/main.zig b/src/main.zig index 8265a8e..763bc7b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -11,76 +11,26 @@ const sys = @import("./sys.zig"); /// Entry point. /// pub fn main() anyerror!void { - if (ext.SDL_Init(ext.SDL_INIT_EVERYTHING) != 0) { - ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize SDL2 runtime"); + return sys.runGraphics(anyerror, run); +} - return error.InitFailure; +fn run(event_loop: *sys.EventLoop, graphics: *sys.GraphicalContext) anyerror!void { + var gpa = std.heap.GeneralPurposeAllocator(){}; + + { + const file = event_loop.open(.readonly, sys.Path.get(.data, &.{"ona.lua"})); + + defer _ = event_loop.closeFile(file); + + const file_size = try file.size(event_loop); + var buffer = try gpa.allocator().alloc(u8, file_size); + + if (try event_loop.readFile(buffer) != file_size) return error.ScriptLoadError; + + sys.log(buffer); } - defer ext.SDL_Quit(); - - const pref_path = create_pref_path: { - const path = ext.SDL_GetPrefPath("ona", "ona") orelse { - ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, "Failed to load user path"); - - return error.InitFailure; - }; - - break: create_pref_path path[0 .. std.mem.len(path)]; - }; - - defer ext.SDL_free(pref_path.ptr); - - const window = create_window: { - const pos = ext.SDL_WINDOWPOS_UNDEFINED; - var flags = @as(u32, 0); - - break: create_window ext.SDL_CreateWindow("Ona", pos, pos, 640, 480, flags) orelse { - ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, "Failed to load SDL2 window"); - - return error.InitFailure; - }; - }; - - defer ext.SDL_DestroyWindow(window); - - const renderer = create_renderer: { - var flags = @as(u32, 0); - - break: create_renderer ext.SDL_CreateRenderer(window, -1, flags) orelse { - ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, "Failed to load SDL2 renderer"); - - return error.InitFailure; - }; - }; - - defer ext.SDL_DestroyRenderer(renderer); - - var event_loop = sys.EventLoop{}; - var is_running = true; - - while (is_running) { - var event = std.mem.zeroes(ext.SDL_Event); - - while (ext.SDL_PollEvent(&event) != 0) { - switch (event.type) { - ext.SDL_QUIT => is_running = false, - else => {}, - } - } - - if (ext.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255) != 0) { - ext.SDL_LogError(ext.SDL_LOG_CATEGORY_VIDEO, ext.SDL_GetError()); - ext.SDL_ClearError(); - } - - if (ext.SDL_RenderClear(renderer) != 0) { - ext.SDL_LogError(ext.SDL_LOG_CATEGORY_VIDEO, ext.SDL_GetError()); - ext.SDL_ClearError(); - } - - ext.SDL_RenderPresent(renderer); - event_loop.tick(); - ext.SDL_Delay(1); + while (graphics.poll()) |_| { + graphics.present(); } } diff --git a/src/sys.zig b/src/sys.zig index 5ced8ef..83e8b19 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -10,162 +10,30 @@ const std = @import("std"); /// /// /// -pub const EventLoop = packed struct { - current_request: ?*Request = null, +pub const EventLoop = struct { - /// - /// [OpenError.NotFound] is used as a catch-all for any hardware or software-specific reason for - /// failing to open a given file. This includes file-system restrictions surrounding a specific - /// file as well as it simply not existing. - /// - /// [OpenError.OutOfFiles] occurs when there are no more resources available to open further - /// files. As a result, some open files must be closed before more may be opened. - /// - pub const OpenError = error { - NotFound, - OutOfFiles, - }; - - /// - /// Indicates what kind of access the consumer logic has to a file. - /// - /// [OpenMode.read] is for reading from an existing file from the start. - /// - /// [OpenMode.overwrite] is for deleting the contents of a file, or creating an empty one if no - /// such file exists, and writing to it from the start. - /// - /// [OpenMode.append] is for writing additional contents to a file, creating an empty one if no - /// such file exists, on the end of whatever it already contains. - /// - pub const OpenMode = enum { - readonly, - overwrite, - append, - }; - - const Request = struct { - next: ?*Request = null, - frame: anyframe, - - message: union(enum) { - close: struct { - file: *FileAccess, - }, - - open: struct { - file_system: FileSystem, - path: *const Path, - mode: OpenMode, - file: OpenError!*FileAccess = error.OutOfFiles, - }, - }, - }; - - const max_files = 512; - - /// - /// Asynchronously closes `file_access` via `event_loop`. - /// - /// *Note* that `file_access` must have been opened by `event_loop` for it to be closed by it, - /// otherwise it will cause undefined behavior. - /// - pub fn close(event_loop: *EventLoop, file_access: *FileAccess) void { - var request = Request{ - .frame = @frame(), - .message = .{.close = @ptrCast(*ext.SDL_RWops, file_access)}, - }; - - suspend if (event_loop.current_request) |current_request| { - current_request.next = &request; - } else { - event_loop.current_request = &request; - }; - } - - /// - /// - /// - pub fn open(event_loop: *EventLoop, file_system: FileSystem, - path: Path, mode: OpenMode) OpenError!*FileAccess { - - var request = Request{ - .frame = @frame(), - - .message = .{ - .open = .{ - .file_system = file_system, - .path = &path, - .mode = mode, - }, - }, - }; - - suspend if (event_loop.current_request) |current_request| { - current_request.next = &request; - } else { - event_loop.current_request = &request; - }; - - return @ptrCast(*FileAccess, try request.message.open.file); - } - - /// - /// - /// - pub fn tick(event_loop: *EventLoop) void { - while (event_loop.current_request) |request| { - switch (request.message) { - .close => |*close| { - // Swallow file close errors. - _ = ext.SDL_RWclose(@ptrCast(*ext.SDL_RWops, @alignCast(@alignOf(ext.SDL_RWops), close.file))); - }, - - .open => |*open| { - switch (open.file_system) { - .data => { - var zeroed_path_buffer = std.mem.zeroes([4096]u8); - var zeroed_path = stack.Fixed(u8){.buffer = &zeroed_path_buffer}; - - zeroed_path.push('.') catch continue; - - _ = open.path.write(zeroed_path.asWriter()); - - zeroed_path.push(0) catch continue; - - // TODO: Access TAR file. - }, - - .user => { - var zeroed_path_buffer = std.mem.zeroes([4096]u8); - var zeroed_path = stack.Fixed(u8){.buffer = &zeroed_path_buffer}; - - zeroed_path.pushAll("/home/kayomn/.local/share") catch continue; - - _ = open.path.write(zeroed_path.asWriter()); - - zeroed_path.push(0) catch continue; - - open.file = @ptrCast(?*FileAccess, ext.SDL_RWFromFile(&zeroed_path_buffer, switch (open.mode) { - .readonly => "rb", - .overwrite => "wb", - .append => "ab", - })) orelse error.NotFound; - }, - } - }, - } - - resume request.frame; - - event_loop.current_request = request.next; - } - } }; /// /// /// -pub const FileAccess = opaque {}; +pub const FileAccess = opaque { + /// + /// Scans the number of bytes in the file referenced by `file_access` via `event_loop`, returing + /// its byte size or a [FileError] if it failed. + /// + pub fn size(file_access: *FileAccess, event_loop: *EventLoop) FileError!usize { + const origin_cursor = try app.tellFile(file_access); + + try app.seekFile(file_access, .tail, 0); + + const ending_cursor = try app.tellFile(file_access); + + try app.seekFile(file_access, .head, origin_cursor); + + return ending_cursor; + } +}; /// /// With files typically being backed by a block device, they can produce a variety of errors - @@ -176,14 +44,6 @@ pub const FileError = error { Inaccessible, }; -/// -/// -/// -pub const FileSystem = enum { - data, - user, -}; - /// /// Platform-agnostic mechanism for accessing files on any of the virtual file-systems supported by /// Ona. @@ -199,6 +59,13 @@ pub const Path = struct { TooLong, }; + /// + /// + /// + pub fn isComplete(path: Path) bool { + return (path.length != 0) and (path.buffer[0] == '/'); + } + /// /// Returns `true` if the length of `path` is empty, otherwise `false`. /// @@ -213,6 +80,80 @@ pub const Path = struct { return std.mem.eql(u8, this.buffer[0 .. this.length], that.buffer[0 .. that.length]); } + /// + /// Creates and returns a [Path] value in the file system indicated by `file_system` from the + /// path components in `component_groups`. + /// + pub fn from(file_system: FileSystem, component_groups: []const []const u8) Error!Path { + var path = Path{ + .file_system = file_system, + .buffer = std.mem.zeroes([max]u8), + .length = 0, + }; + + for (component_groups) |first_component_group, + first_component_group_index| if (first_component_group.len != 0) { + + var first_component_root_offset = @as(usize, 0); + + if (component_group[0] == '/') { + comptime if (max < 1) unreachable; + + path.buffer[path.length] = '/'; + path.length += 1; + first_component_root_offset = 1; + } + + var first_components = mem.Spliterator(u8){ + .source = first_component_group[first_component_root_offset .. + (first_component_group.len - first_component_root_offset)], + + .delimiter = "/", + }; + + while (first_components.next()) |component| if (component.len != 0) { + for (component) |byte| { + if (path.length == max) return error.TooLong; + + path.buffer[path.length] = byte; + path.length += 1; + } + + if (path.length == max) return error.TooLong; + + path.buffer[path.length] = '/'; + path.length += 1; + }; + + const second_component_group_index = (first_component_group_index + 1); + + for (component_groups[second_component_group_index .. (component_groups.len - + second_component_group_index)]) |component_group| if (component_group.len != 0) { + + var components = mem.Spliterator(u8){ + .source = component_group, + .delimiter = "/", + }; + + while (components.next()) |component| if (component.len != 0) { + for (component) |byte| { + if (path.length == max) return error.TooLong; + + path.buffer[path.length] = byte; + path.length += 1; + } + + if (path.length == max) return error.TooLong; + + path.buffer[path.length] = '/'; + path.length += 1; + }; + }; + }; + + return path; + } + /// /// The maximum possible byte-length of a [Path]. /// @@ -222,31 +163,17 @@ pub const Path = struct { /// pub const max = 1000; - /// - /// - /// - pub fn parseJoins(path: Path, joins: []const []const u8) Error!Path { - _ = path; - _ = joins; - - return Path{ - .buffer = std.mem.zeroes([max]u8), - .length = 0 - }; - } - /// /// /// pub fn write(path: Path, writer: io.Writer) bool { return (writer.write(path.buffer[0 .. path.length]) == path.length); } - - /// - /// - /// - pub const root = Path{ - .buffer = [_]u8{'/'} ** max, - .length = 1, - }; }; + +/// +/// +/// +pub fn runGraphics(comptime ErrorUnion: anytype, run: fn (*App) ErrorUnion!void) void { + +}