Application Context Implementation #4
|
@ -21,7 +21,7 @@ test {
|
||||||
_ = sys;
|
_ = sys;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(app: *sys.App, graphics: *sys.GraphicsContext) anyerror!void {
|
fn run(app: *sys.AppContext, graphics: *sys.GraphicsContext) anyerror!void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
|
|
107
src/sys.zig
107
src/sys.zig
|
@ -12,7 +12,7 @@ const std = @import("std");
|
||||||
///
|
///
|
||||||
/// A thread-safe platform abstraction over multiplexing system I/O processing and event handling.
|
/// A thread-safe platform abstraction over multiplexing system I/O processing and event handling.
|
||||||
///
|
///
|
||||||
pub const App = opaque {
|
pub const AppContext = opaque {
|
||||||
///
|
///
|
||||||
/// Linked list of asynchronous messages chained together to be processed by the work processor.
|
/// Linked list of asynchronous messages chained together to be processed by the work processor.
|
||||||
///
|
///
|
||||||
|
@ -71,13 +71,13 @@ pub const App = opaque {
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Casts `app` to a [Implementation] reference.
|
/// Casts `app_context` to a [Implementation] reference.
|
||||||
///
|
///
|
||||||
/// *Note* that if `app` does not have the same alignment as [Implementation], safety-
|
/// *Note* that if `app_context` does not have the same alignment as [Implementation], safety-
|
||||||
/// checked undefined behavior will occur.
|
/// checked undefined behavior will occur.
|
||||||
///
|
///
|
||||||
fn cast(app: *App) *Implementation {
|
fn cast(app_context: *AppContext) *Implementation {
|
||||||
return @ptrCast(*Implementation, @alignCast(@alignOf(Implementation), app));
|
return @ptrCast(*Implementation, @alignCast(@alignOf(Implementation), app_context));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -90,7 +90,7 @@ pub const App = opaque {
|
||||||
.kind = .quit,
|
.kind = .quit,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ptrCast(*App, implementation).schedule(&message);
|
@ptrCast(*AppContext, implementation).schedule(&message);
|
||||||
|
|
||||||
{
|
{
|
||||||
var status = @as(c_int, 0);
|
var status = @as(c_int, 0);
|
||||||
|
@ -132,7 +132,7 @@ pub const App = opaque {
|
||||||
/// occured.
|
/// occured.
|
||||||
///
|
///
|
||||||
fn processTasks(userdata: ?*anyopaque) callconv(.C) c_int {
|
fn processTasks(userdata: ?*anyopaque) callconv(.C) c_int {
|
||||||
const implementation = Implementation.cast(@ptrCast(*App, userdata orelse unreachable));
|
const implementation = Implementation.cast(@ptrCast(*AppContext, userdata orelse unreachable));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
_ = ext.SDL_LockMutex(implementation.message_mutex);
|
_ = ext.SDL_LockMutex(implementation.message_mutex);
|
||||||
|
@ -164,7 +164,9 @@ pub const App = opaque {
|
||||||
fn start(implementation: *Implementation) StartError!void {
|
fn start(implementation: *Implementation) StartError!void {
|
||||||
if (implementation.message_thread != null) return error.AlreadyStarted;
|
if (implementation.message_thread != null) return error.AlreadyStarted;
|
||||||
|
|
||||||
implementation.message_thread = ext.SDL_CreateThread(processTasks, "File System Worker", implementation) orelse {
|
implementation.message_thread = ext.SDL_CreateThread(processTasks,
|
||||||
|
"File System Worker", implementation) orelse {
|
||||||
|
|
||||||
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION,
|
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to create file-system work processor");
|
"Failed to create file-system work processor");
|
||||||
|
|
||||||
|
@ -176,16 +178,16 @@ pub const App = opaque {
|
||||||
///
|
///
|
||||||
/// Returns a reference to the currently loaded data file-system.
|
/// Returns a reference to the currently loaded data file-system.
|
||||||
///
|
///
|
||||||
pub fn data(app: *App) *const FileSystem {
|
pub fn data(app_context: *AppContext) *const FileSystem {
|
||||||
return &Implementation.cast(app).data_file_system;
|
return &Implementation.cast(app_context).data_file_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Enqueues `message` to the message processor of `app` to be processed at a later, non-
|
/// Enqueues `message` to the message processor of `app_context` to be processed at a later, non-
|
||||||
/// deterministic point.
|
/// deterministic point.
|
||||||
///
|
///
|
||||||
pub fn schedule(app: *App, message: *Message) void {
|
pub fn schedule(app_context: *AppContext, message: *Message) void {
|
||||||
const implementation = Implementation.cast(app);
|
const implementation = Implementation.cast(app_context);
|
||||||
|
|
||||||
// TODO: Error check these.
|
// TODO: Error check these.
|
||||||
_ = ext.SDL_LockMutex(implementation.message_mutex);
|
_ = ext.SDL_LockMutex(implementation.message_mutex);
|
||||||
|
@ -205,8 +207,8 @@ pub const App = opaque {
|
||||||
///
|
///
|
||||||
/// Returns a reference to the currently loaded user file-system.
|
/// Returns a reference to the currently loaded user file-system.
|
||||||
///
|
///
|
||||||
pub fn user(app: *App) *const FileSystem {
|
pub fn user(app_context: *AppContext) *const FileSystem {
|
||||||
return &Implementation.cast(app).user_file_system;
|
return &Implementation.cast(app_context).user_file_system;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ pub const FileAccess = opaque {
|
||||||
/// Freeing an invalid `file_access` has no effect on the file and logs a warning over the
|
/// Freeing an invalid `file_access` has no effect on the file and logs a warning over the
|
||||||
/// wasted effort.
|
/// wasted effort.
|
||||||
///
|
///
|
||||||
pub fn close(file_access: *FileAccess, app: *App) void {
|
pub fn close(file_access: *FileAccess, app_context: *AppContext) void {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
file_access: *FileAccess,
|
file_access: *FileAccess,
|
||||||
|
|
||||||
|
@ -253,7 +255,7 @@ pub const FileAccess = opaque {
|
||||||
|
|
||||||
var task = Task{.file_access = file_access};
|
var task = Task{.file_access = file_access};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -262,7 +264,7 @@ pub const FileAccess = opaque {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -271,7 +273,7 @@ pub const FileAccess = opaque {
|
||||||
/// Returns the number of bytes into the file that the cursor is relative to its beginning or a
|
/// Returns the number of bytes into the file that the cursor is relative to its beginning or a
|
||||||
/// [Error] on failure.
|
/// [Error] on failure.
|
||||||
///
|
///
|
||||||
pub fn queryCursor(file_access: *FileAccess, app: *App) Error!u64 {
|
pub fn queryCursor(file_access: *FileAccess, app_context: *AppContext) Error!u64 {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
file_access: *FileAccess,
|
file_access: *FileAccess,
|
||||||
result: Error!u64,
|
result: Error!u64,
|
||||||
|
@ -300,7 +302,7 @@ pub const FileAccess = opaque {
|
||||||
.result = error.FileInaccessible,
|
.result = error.FileInaccessible,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -309,7 +311,7 @@ pub const FileAccess = opaque {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
|
|
||||||
return task.result;
|
return task.result;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +322,7 @@ pub const FileAccess = opaque {
|
||||||
/// Returns the current length of the file at the time of the operation or a [Error] if the file
|
/// Returns the current length of the file at the time of the operation or a [Error] if the file
|
||||||
/// failed to be queried.
|
/// failed to be queried.
|
||||||
///
|
///
|
||||||
pub fn queryLength(file_access: *FileAccess, app: *App) Error!u64 {
|
pub fn queryLength(file_access: *FileAccess, app_context: *AppContext) Error!u64 {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
file_access: *FileAccess,
|
file_access: *FileAccess,
|
||||||
result: Error!usize,
|
result: Error!usize,
|
||||||
|
@ -349,7 +351,7 @@ pub const FileAccess = opaque {
|
||||||
.result = error.FileInaccessible,
|
.result = error.FileInaccessible,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -358,18 +360,18 @@ pub const FileAccess = opaque {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
|
|
||||||
return task.result;
|
return task.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to read `file_access` from the its current position into `buffer`, while using
|
/// Attempts to read `file_access` from the its current position into `buffer`, while using
|
||||||
/// `app` as the execution context.
|
/// `app_context` as the execution context.
|
||||||
///
|
///
|
||||||
/// Returns the number of bytes that were available to be read, otherwise an [Error] on failure.
|
/// Returns the number of bytes that were available to be read, otherwise an [Error] on failure.
|
||||||
///
|
///
|
||||||
pub fn read(file_access: *FileAccess, app: *App, buffer: []u8) Error!usize {
|
pub fn read(file_access: *FileAccess, app_context: *AppContext, buffer: []u8) Error!usize {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
file_access: *FileAccess,
|
file_access: *FileAccess,
|
||||||
buffer: []u8,
|
buffer: []u8,
|
||||||
|
@ -401,7 +403,7 @@ pub const FileAccess = opaque {
|
||||||
.result = error.FileInaccessible,
|
.result = error.FileInaccessible,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -410,18 +412,18 @@ pub const FileAccess = opaque {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
|
|
||||||
return task.result;
|
return task.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to seek `file_access` from the beginning of the file to `cursor` bytes while using
|
/// Attempts to seek `file_access` from the beginning of the file to `cursor` bytes while using
|
||||||
/// `app` as the execution context.
|
/// `app_context` as the execution context.
|
||||||
///
|
///
|
||||||
/// Returns [Error] on failure.
|
/// Returns [Error] on failure.
|
||||||
///
|
///
|
||||||
pub fn seek(file_access: *FileAccess, app: *App, cursor: u64) Error!void {
|
pub fn seek(file_access: *FileAccess, app_context: *AppContext, cursor: u64) Error!void {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
file_access: *FileAccess,
|
file_access: *FileAccess,
|
||||||
cursor: u64,
|
cursor: u64,
|
||||||
|
@ -458,7 +460,7 @@ pub const FileAccess = opaque {
|
||||||
.result = error.FileInaccessible,
|
.result = error.FileInaccessible,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -467,18 +469,18 @@ pub const FileAccess = opaque {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
|
|
||||||
return task.result;
|
return task.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to seek `file_access` to the end of the file while using `app` as the execution
|
/// Attempts to seek `file_access` to the end of the file while using `app_context` as the execution
|
||||||
/// context.
|
/// context.
|
||||||
///
|
///
|
||||||
/// Returns [Error] on failure.
|
/// Returns [Error] on failure.
|
||||||
///
|
///
|
||||||
pub fn seekToEnd(file_access: *FileAccess, app: *App) Error!void {
|
pub fn seekToEnd(file_access: *FileAccess, app_context: *AppContext) Error!void {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
file_access: *FileAccess,
|
file_access: *FileAccess,
|
||||||
result: Error!void,
|
result: Error!void,
|
||||||
|
@ -505,7 +507,7 @@ pub const FileAccess = opaque {
|
||||||
.result = error.FileInaccessible,
|
.result = error.FileInaccessible,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -514,7 +516,7 @@ pub const FileAccess = opaque {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
|
|
||||||
return task.result;
|
return task.result;
|
||||||
}
|
}
|
||||||
|
@ -593,15 +595,15 @@ pub const FileSystem = union(enum) {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to open the file identified by `path` with `mode` as the mode for opening the
|
/// Attempts to open the file identified by `path` with `mode` as the mode for opening the
|
||||||
/// file and `app` as the execution context.
|
/// file and `app_context` as the execution context.
|
||||||
///
|
///
|
||||||
/// Returns a [FileAccess] reference that provides access to the file referenced by `path`
|
/// Returns a [FileAccess] reference that provides access to the file referenced by `path`
|
||||||
/// or a [OpenError] if it failed.
|
/// or a [OpenError] if it failed.
|
||||||
///
|
///
|
||||||
pub fn open(path: Path, app: *App, mode: OpenMode) OpenError!*FileAccess {
|
pub fn open(path: Path, app_context: *AppContext, mode: OpenMode) OpenError!*FileAccess {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
path: *const FileSystem.Path,
|
path: *const FileSystem.Path,
|
||||||
app: *App,
|
app_context: *AppContext,
|
||||||
mode: OpenMode,
|
mode: OpenMode,
|
||||||
result: OpenError!*FileAccess,
|
result: OpenError!*FileAccess,
|
||||||
|
|
||||||
|
@ -738,11 +740,11 @@ pub const FileSystem = union(enum) {
|
||||||
var task = Task{
|
var task = Task{
|
||||||
.mode = mode,
|
.mode = mode,
|
||||||
.path = &path,
|
.path = &path,
|
||||||
.app = app,
|
.app_context = app_context,
|
||||||
.result = error.FileNotFound,
|
.result = error.FileNotFound,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -751,7 +753,7 @@ pub const FileSystem = union(enum) {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
|
|
||||||
return task.result;
|
return task.result;
|
||||||
}
|
}
|
||||||
|
@ -863,7 +865,7 @@ pub const GraphicsContext = opaque {
|
||||||
/// Returns a graphics runner that uses `Errors` as its error set.
|
/// Returns a graphics runner that uses `Errors` as its error set.
|
||||||
///
|
///
|
||||||
pub fn GraphicsRunner(comptime Errors: type) type {
|
pub fn GraphicsRunner(comptime Errors: type) type {
|
||||||
return fn (*App, *GraphicsContext) callconv(.Async) Errors!void;
|
return fn (*AppContext, *GraphicsContext) callconv(.Async) Errors!void;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -882,10 +884,10 @@ pub const Log = enum(u32) {
|
||||||
warning = ext.SDL_LOG_PRIORITY_WARN,
|
warning = ext.SDL_LOG_PRIORITY_WARN,
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Writes `utf8_message` as the log kind identified by `log` with `app` as the execution
|
/// Writes `utf8_message` as the log kind identified by `log` with `app_context` as the execution
|
||||||
/// context.
|
/// context.
|
||||||
///
|
///
|
||||||
pub fn write(log: Log, app: *App, utf8_message: []const u8) void {
|
pub fn write(log: Log, app_context: *AppContext, utf8_message: []const u8) void {
|
||||||
const Task = struct {
|
const Task = struct {
|
||||||
log: Log,
|
log: Log,
|
||||||
utf8_message: []const u8,
|
utf8_message: []const u8,
|
||||||
|
@ -905,7 +907,7 @@ pub const Log = enum(u32) {
|
||||||
.utf8_message = utf8_message,
|
.utf8_message = utf8_message,
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = App.Message{
|
var message = AppContext.Message{
|
||||||
.frame = @frame(),
|
.frame = @frame(),
|
||||||
|
|
||||||
.kind = .{.task = .{
|
.kind = .{.task = .{
|
||||||
|
@ -914,7 +916,7 @@ pub const Log = enum(u32) {
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
|
|
||||||
suspend app.schedule(&message);
|
suspend app_context.schedule(&message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -972,15 +974,14 @@ pub fn runGraphics(comptime Error: anytype,
|
||||||
defer ext.SDL_DestroyRenderer(renderer);
|
defer ext.SDL_DestroyRenderer(renderer);
|
||||||
|
|
||||||
const user_path_prefix = ext.SDL_GetPrefPath("ona", "ona") orelse {
|
const user_path_prefix = ext.SDL_GetPrefPath("ona", "ona") orelse {
|
||||||
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION,
|
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, "Failed to load user path");
|
||||||
"Failed to load user path");
|
|
||||||
|
|
||||||
return error.InitFailure;
|
return error.InitFailure;
|
||||||
};
|
};
|
||||||
|
|
||||||
defer ext.SDL_free(user_path_prefix);
|
defer ext.SDL_free(user_path_prefix);
|
||||||
|
|
||||||
var app = App.Implementation.init("./data.oar", user_path_prefix
|
var app_context = AppContext.Implementation.init("./data.oar", user_path_prefix
|
||||||
[0 .. std.mem.len(user_path_prefix)]) catch |err| {
|
[0 .. std.mem.len(user_path_prefix)]) catch |err| {
|
||||||
|
|
||||||
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, switch (err) {
|
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, switch (err) {
|
||||||
|
@ -992,9 +993,9 @@ pub fn runGraphics(comptime Error: anytype,
|
||||||
return error.InitFailure;
|
return error.InitFailure;
|
||||||
};
|
};
|
||||||
|
|
||||||
defer app.deinit();
|
defer app_context.deinit();
|
||||||
|
|
||||||
app.start() catch |err| {
|
app_context.start() catch |err| {
|
||||||
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, switch (err) {
|
ext.SDL_LogCritical(ext.SDL_LOG_CATEGORY_APPLICATION, switch (err) {
|
||||||
// Not possible for it to have already been started.
|
// Not possible for it to have already been started.
|
||||||
error.AlreadyStarted => unreachable,
|
error.AlreadyStarted => unreachable,
|
||||||
|
@ -1010,5 +1011,5 @@ pub fn runGraphics(comptime Error: anytype,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return run(@ptrCast(*App, &app), @ptrCast(*GraphicsContext, &graphics_context));
|
return run(@ptrCast(*AppContext, &app_context), @ptrCast(*GraphicsContext, &graphics_context));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue