Compare commits
	
		
			10 Commits
		
	
	
		
			71ab200325
			...
			3a0da39b3e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3a0da39b3e | ||
| 37bd0f10ac | |||
| c91630d6da | |||
| 074a62807b | |||
| c4775e27d8 | |||
| a36b3bc321 | |||
| e01b19cd68 | |||
| 774536fd58 | |||
| af1976b69c | |||
| 49557f32bc | 
| @ -5,4 +5,5 @@ steps: | |||||||
| - name: build & test | - name: build & test | ||||||
|   image: euantorano/zig:0.9.1 |   image: euantorano/zig:0.9.1 | ||||||
|   commands: |   commands: | ||||||
|   - zig test src/main.zig |   - zig build test | ||||||
|  |   - $(find zig-cache -name test) main.zig | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @ -44,7 +44,7 @@ | |||||||
| 		{ | 		{ | ||||||
| 			"label": "Test", | 			"label": "Test", | ||||||
| 			"type": "shell", | 			"type": "shell", | ||||||
| 			"command": "zig test src/main.zig", | 			"command": "$(find zig-cache -name test) src/main.zig", | ||||||
| 			"group": { | 			"group": { | ||||||
| 				"kind": "test", | 				"kind": "test", | ||||||
| 				"isDefault": true | 				"isDefault": true | ||||||
|  | |||||||
							
								
								
									
										75
									
								
								src/io.zig
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								src/io.zig
									
									
									
									
									
								
							| @ -10,7 +10,7 @@ pub const Writer = struct { | |||||||
|     writeContext: fn (*anyopaque, []const u8) usize, |     writeContext: fn (*anyopaque, []const u8) usize, | ||||||
| 
 | 
 | ||||||
|     /// |     /// | ||||||
|     /// |     /// Radices supported by [writeInt]. | ||||||
|     /// |     /// | ||||||
|     pub const Radix = enum { |     pub const Radix = enum { | ||||||
|         binary, |         binary, | ||||||
| @ -79,39 +79,45 @@ pub const Writer = struct { | |||||||
|         const Int = @TypeOf(value); |         const Int = @TypeOf(value); | ||||||
|         const type_info = @typeInfo(Int); |         const type_info = @typeInfo(Int); | ||||||
| 
 | 
 | ||||||
|         if (type_info != .Int) @compileError("value must be of type int"); |         switch (type_info) { | ||||||
|  |             .Int => { | ||||||
|  |                 if (value == 0) return writer.writeByte('0'); | ||||||
| 
 | 
 | ||||||
|         if (value == 0) return writer.writeByte('0'); |                 // TODO: Unhardcode this as it will break with large ints. | ||||||
|  |                 var buffer = std.mem.zeroes([28]u8); | ||||||
|  |                 var buffer_count = @as(usize, 0); | ||||||
|  |                 var n1 = value; | ||||||
| 
 | 
 | ||||||
|         // TODO: Unhardcode this as it will break with large ints. |                 if ((type_info.Int.signedness == .signed) and (value < 0)) { | ||||||
|         var buffer = std.mem.zeroes([28]u8); |                     // Negative value. | ||||||
|         var buffer_count = @as(usize, 0); |                     n1 = -value; | ||||||
|         var n1 = value; |                     buffer[0] = '-'; | ||||||
|  |                     buffer_count += 1; | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|         if ((type_info.Int.signedness == .signed) and (value < 0)) { |                 while (n1 != 0) { | ||||||
|             // Negative value. |                     const base = @enumToInt(radix); | ||||||
|             n1 = -value; | 
 | ||||||
|             buffer[0] = '-'; |                     buffer[buffer_count] = @intCast(u8, (n1 % base) + '0'); | ||||||
|             buffer_count += 1; |                     n1 = (n1 / base); | ||||||
|  |                     buffer_count += 1; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 for (buffer[0 .. (buffer_count / 2)]) |_, i| | ||||||
|  |                     std.mem.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]); | ||||||
|  | 
 | ||||||
|  |                 return (writer.write(buffer[0 .. buffer_count]) == buffer_count); | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             // Cast comptime int into known-size integer and try again. | ||||||
|  |             .ComptimeInt => return writer. | ||||||
|  |                 writeInt(radix, @intCast(std.math.IntFittingRange(value, value), value)), | ||||||
|  | 
 | ||||||
|  |             else => @compileError("value must be of type int"), | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         while (n1 != 0) { |  | ||||||
|             const base = @enumToInt(radix); |  | ||||||
| 
 |  | ||||||
|             buffer[buffer_count] = @intCast(u8, (n1 % base) + '0'); |  | ||||||
|             n1 = (n1 / base); |  | ||||||
|             buffer_count += 1; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for (buffer[0 .. (buffer_count / 2)]) |_, i| |  | ||||||
|             std.mem.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]); |  | ||||||
| 
 |  | ||||||
|         return (writer.write(buffer[0 .. buffer_count]) == buffer_count); |  | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| var null_context = @as(usize, 0); |  | ||||||
| 
 |  | ||||||
| /// | /// | ||||||
| /// Writer that silently throws consumed data away and never fails. | /// Writer that silently throws consumed data away and never fails. | ||||||
| /// | /// | ||||||
| @ -119,13 +125,10 @@ var null_context = @as(usize, 0); | |||||||
| /// sent somewhere for whatever reason. | /// sent somewhere for whatever reason. | ||||||
| /// | /// | ||||||
| pub const null_writer = Writer{ | pub const null_writer = Writer{ | ||||||
|     .context = (&null_context), |     .context = undefined, | ||||||
| 
 |  | ||||||
|     .operation = struct { |  | ||||||
|         fn write(context: *anyopaque, buffer: []const u8) usize { |  | ||||||
|             // Validate context canary value. |  | ||||||
|             std.debug.assert(@ptrCast(*usize, @alignCast(@alignOf(usize), context)).* == 0); |  | ||||||
| 
 | 
 | ||||||
|  |     .writeContext = struct { | ||||||
|  |         fn write(_: *anyopaque, buffer: []const u8) usize { | ||||||
|             return buffer.len; |             return buffer.len; | ||||||
|         } |         } | ||||||
|     }.write, |     }.write, | ||||||
| @ -137,9 +140,9 @@ test { | |||||||
|     { |     { | ||||||
|         const sequence = "foo"; |         const sequence = "foo"; | ||||||
| 
 | 
 | ||||||
|         testing.expectEqual(null_writer.write(sequence), sequence.len); |         try testing.expectEqual(null_writer.write(sequence), sequence.len); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     testing.expect(null_writer.writeByte(0)); |     try testing.expect(null_writer.writeByte(0)); | ||||||
|     testing.expect(null_writer.writeInt(.decimal, 420)); |     try testing.expect(null_writer.writeInt(.decimal, 420)); | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,7 +15,10 @@ pub fn main() anyerror!void { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| test { | test { | ||||||
| 
 |     _ = io; | ||||||
|  |     _ = stack; | ||||||
|  |     _ = std; | ||||||
|  |     _ = sys; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn run(event_loop: *sys.EventLoop, graphics: *sys.GraphicsContext) anyerror!void { | fn run(event_loop: *sys.EventLoop, graphics: *sys.GraphicsContext) anyerror!void { | ||||||
| @ -38,7 +41,7 @@ fn run(event_loop: *sys.EventLoop, graphics: *sys.GraphicsContext) anyerror!void | |||||||
|         if ((try event_loop.readFile(file_access, buffer)) != file_size) |         if ((try event_loop.readFile(file_access, buffer)) != file_size) | ||||||
|             return error.ScriptLoadFailure; |             return error.ScriptLoadFailure; | ||||||
| 
 | 
 | ||||||
|         event_loop.log(buffer); |         event_loop.log(.debug, buffer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     while (graphics.poll()) |_| { |     while (graphics.poll()) |_| { | ||||||
|  | |||||||
| @ -91,7 +91,7 @@ pub const FixedPushError = error { | |||||||
|     Overflow, |     Overflow, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| test "fixed stack" { | test { | ||||||
|     const testing = std.testing; |     const testing = std.testing; | ||||||
|     var buffer = std.mem.zeroes([4]u8); |     var buffer = std.mem.zeroes([4]u8); | ||||||
|     var stack = Fixed(u8){.buffer = &buffer}; |     var stack = Fixed(u8){.buffer = &buffer}; | ||||||
|  | |||||||
							
								
								
									
										104
									
								
								src/sys.zig
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/sys.zig
									
									
									
									
									
								
							| @ -8,7 +8,7 @@ const stack = @import("./stack.zig"); | |||||||
| const std = @import("std"); | const std = @import("std"); | ||||||
| 
 | 
 | ||||||
| /// | /// | ||||||
| /// | /// A thread-safe platform abstraction over multiplexing system I/O processing and event handling. | ||||||
| /// | /// | ||||||
| pub const EventLoop = opaque { | pub const EventLoop = opaque { | ||||||
|     /// |     /// | ||||||
| @ -23,7 +23,7 @@ pub const EventLoop = opaque { | |||||||
|             exit, |             exit, | ||||||
| 
 | 
 | ||||||
|             close: struct { |             close: struct { | ||||||
|                 file_system_path: *FileAccess, |                 file_access: *FileAccess, | ||||||
|             }, |             }, | ||||||
| 
 | 
 | ||||||
|             log: struct { |             log: struct { | ||||||
| @ -33,7 +33,7 @@ pub const EventLoop = opaque { | |||||||
| 
 | 
 | ||||||
|             open: struct { |             open: struct { | ||||||
|                 mode: OpenMode, |                 mode: OpenMode, | ||||||
|                 path: *const FileSystem.Path, |                 file_system_path: *const FileSystem.Path, | ||||||
|                 result: OpenError!*FileAccess = error.NotFound, |                 result: OpenError!*FileAccess = error.NotFound, | ||||||
|             }, |             }, | ||||||
| 
 | 
 | ||||||
| @ -138,13 +138,15 @@ pub const EventLoop = opaque { | |||||||
|     /// |     /// | ||||||
|     /// Closes access to the file referenced by `file_access` via `event_loop`. |     /// Closes access to the file referenced by `file_access` via `event_loop`. | ||||||
|     /// |     /// | ||||||
|  |     /// *Note* that nothing happens to `file_access` if it is already closed. | ||||||
|  |     /// | ||||||
|     pub fn close(event_loop: *EventLoop, file_access: *FileAccess) void { |     pub fn close(event_loop: *EventLoop, file_access: *FileAccess) void { | ||||||
|         var message = FileSystemMessage{ |         var file_system_message = FileSystemMessage{ | ||||||
|             .frame = @frame(), |             .frame = @frame(), | ||||||
|             .request = .{.close = .{.file_access = file_access}}, |             .request = .{.close = .{.file_access = file_access}}, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         suspend event_loop.enqueueFileSystemMessage(&message); |         suspend event_loop.enqueueFileSystemMessage(&file_system_message); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// |     /// | ||||||
| @ -174,7 +176,7 @@ pub const EventLoop = opaque { | |||||||
|     /// *Note* that `message` is not guaranteed to be partly, wholely, or at all written. |     /// *Note* that `message` is not guaranteed to be partly, wholely, or at all written. | ||||||
|     /// |     /// | ||||||
|     pub fn log(event_loop: *EventLoop, kind: LogKind, message: []const u8) void { |     pub fn log(event_loop: *EventLoop, kind: LogKind, message: []const u8) void { | ||||||
|         var message = FileSystemMessage{ |         var file_system_message = FileSystemMessage{ | ||||||
|             .frame = @frame(), |             .frame = @frame(), | ||||||
| 
 | 
 | ||||||
|             .request = .{.log = .{ |             .request = .{.log = .{ | ||||||
| @ -183,7 +185,7 @@ pub const EventLoop = opaque { | |||||||
|             }}, |             }}, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         suspend event_loop.enqueueFileSystemMessage(&message); |         suspend event_loop.enqueueFileSystemMessage(&file_system_message); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// |     /// | ||||||
| @ -199,24 +201,26 @@ pub const EventLoop = opaque { | |||||||
|     pub fn open(event_loop: *EventLoop, mode: OpenMode, |     pub fn open(event_loop: *EventLoop, mode: OpenMode, | ||||||
|         file_system_path: FileSystem.Path) OpenError!*FileAccess { |         file_system_path: FileSystem.Path) OpenError!*FileAccess { | ||||||
| 
 | 
 | ||||||
|         var message = FileSystemMessage{ |         var file_system_message = FileSystemMessage{ | ||||||
|             .frame = @frame(), |             .frame = @frame(), | ||||||
| 
 | 
 | ||||||
|             .request = .{ |             .request = .{.open = .{ | ||||||
|                 .open = .{ |                 .mode = mode, | ||||||
|                     .mode = mode, |                 .file_system_path = &file_system_path, | ||||||
|                     .file_system_path = &file_system_path, |             }}, | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         suspend event_loop.enqueueFileSystemMessage(&message); |         suspend event_loop.enqueueFileSystemMessage(&file_system_message); | ||||||
| 
 | 
 | ||||||
|         return message.request.open.result; |         return file_system_message.request.open.result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// |     /// | ||||||
|  |     /// [FileSystemMessage] processing function used by a dedicated worker thread, where `data` is | ||||||
|  |     /// a type-erased reference to a [EventLoop]. | ||||||
|     /// |     /// | ||||||
|  |     /// The processor returns `0` if it exited normally or any other value if an erroneous exit | ||||||
|  |     /// occured. | ||||||
|     /// |     /// | ||||||
|     fn processFileSystemMessages(data: ?*anyopaque) callconv(.C) c_int { |     fn processFileSystemMessages(data: ?*anyopaque) callconv(.C) c_int { | ||||||
|         const implementation = Implementation.cast(@ptrCast(*EventLoop, data orelse unreachable)); |         const implementation = Implementation.cast(@ptrCast(*EventLoop, data orelse unreachable)); | ||||||
| @ -266,20 +270,23 @@ pub const EventLoop = opaque { | |||||||
|                     }, |                     }, | ||||||
| 
 | 
 | ||||||
|                     .close => |*close_request| { |                     .close => |*close_request| { | ||||||
|                         // Don't care if this doesn't work. |                         // TODO: Use this result somehow. | ||||||
|                         _ = ext.SDL_RWclose(@ptrCast(*ext.SDL_RWops, @alignCast( |                         _ = ext.SDL_RWclose(@ptrCast(*ext.SDL_RWops, @alignCast( | ||||||
|                                 @alignOf(ext.SDL_RWops), close_request.file_access))); |                                 @alignOf(ext.SDL_RWops), close_request.file_access))); | ||||||
|                     }, |                     }, | ||||||
| 
 | 
 | ||||||
|                     .read_file => |read_request| { |                     .read_file => |read_request| { | ||||||
|  |                         // TODO: Implement. | ||||||
|                         _ = read_request; |                         _ = read_request; | ||||||
|                     }, |                     }, | ||||||
| 
 | 
 | ||||||
|                     .seek_file => |seek_request| { |                     .seek_file => |seek_request| { | ||||||
|  |                         // TODO: Implement. | ||||||
|                         _ = seek_request; |                         _ = seek_request; | ||||||
|                     }, |                     }, | ||||||
| 
 | 
 | ||||||
|                     .tell_file => |tell_request| { |                     .tell_file => |tell_request| { | ||||||
|  |                         // TODO: Implement. | ||||||
|                         _ = tell_request; |                         _ = tell_request; | ||||||
|                     }, |                     }, | ||||||
|                 } |                 } | ||||||
| @ -304,29 +311,45 @@ pub const EventLoop = opaque { | |||||||
|     pub fn readFile(event_loop: *EventLoop, file_access: *FileAccess, |     pub fn readFile(event_loop: *EventLoop, file_access: *FileAccess, | ||||||
|         buffer: []const u8) FileError!usize { |         buffer: []const u8) FileError!usize { | ||||||
| 
 | 
 | ||||||
|         var message = FileSystemMessage{ |         var file_system_message = FileSystemMessage{ | ||||||
|             .frame = @frame(), |             .frame = @frame(), | ||||||
| 
 | 
 | ||||||
|             .request = .{ |             .request = .{.read_file = .{ | ||||||
|                 .read_file = .{ |                 .file_access = file_access, | ||||||
|                     .file_access = file_access, |                 .buffer = buffer, | ||||||
|                     .buffer = buffer, |             }}, | ||||||
|                 }, |  | ||||||
|             }, |  | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         suspend event_loop.enqueueFileSystemMessage(&message); |         suspend event_loop.enqueueFileSystemMessage(&file_system_message); | ||||||
| 
 | 
 | ||||||
|         return message.request.read_file.result; |         return file_system_message.request.read_file.result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// |     /// | ||||||
|  |     /// Attempts to tell the current file cursor position for the file referenced by `file_access`. | ||||||
|     /// |     /// | ||||||
|  |     /// Returns the number of bytes into the file that the cursor is relative to its beginning or a | ||||||
|  |     /// [FileError] if the file failed to be queried. | ||||||
|  |     /// | ||||||
|  |     pub fn queryFile(event_loop: *EventLoop, file_access: *FileAccess) FileError!usize { | ||||||
|  |         var file_system_message = FileSystemMessage{ | ||||||
|  |             .frame = @frame(), | ||||||
|  |             .request = .{.tell_file = .{.file_access = file_access}}, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         suspend event_loop.enqueueFileSystemMessage(&file_system_message); | ||||||
|  | 
 | ||||||
|  |         return file_system_message.request.tell_file.result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// | ||||||
|  |     /// Attempts to seek the file cursor through the file referenced by `file_access` from `origin` | ||||||
|  |     /// to `offset` via `event_loop`, returning a [FileError] if the file failed to be sought. | ||||||
|     /// |     /// | ||||||
|     pub fn seekFile(event_loop: *EventLoop, file_access: *FileAccess, |     pub fn seekFile(event_loop: *EventLoop, file_access: *FileAccess, | ||||||
|         origin: SeekOrigin, offset: usize) FileError!void { |         origin: SeekOrigin, offset: usize) FileError!void { | ||||||
| 
 | 
 | ||||||
|         var message = FileSystemMessage{ |         var file_system_message = FileSystemMessage{ | ||||||
|             .frame = @frame(), |             .frame = @frame(), | ||||||
| 
 | 
 | ||||||
|             .request = .{ |             .request = .{ | ||||||
| @ -338,23 +361,9 @@ pub const EventLoop = opaque { | |||||||
|             }, |             }, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         suspend event_loop.enqueueFileSystemMessage(&message); |         suspend event_loop.enqueueFileSystemMessage(&file_system_message); | ||||||
| 
 | 
 | ||||||
|         return message.request.seek_file.result; |         return file_system_message.request.seek_file.result; | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// |  | ||||||
|     /// |  | ||||||
|     pub fn tellFile(event_loop: *EventLoop, file_access: *FileAccess) FileError!usize { |  | ||||||
|         var message = FileSystemMessage{ |  | ||||||
|             .frame = @frame(), |  | ||||||
|             .request = .{.tell_file = .{.file_access = file_access}}, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         suspend event_loop.enqueueFileSystemMessage(&message); |  | ||||||
| 
 |  | ||||||
|         return message.request.tell_file.result; |  | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -368,11 +377,11 @@ pub const FileAccess = opaque { | |||||||
|     /// |     /// | ||||||
|     pub fn size(file_access: *FileAccess, event_loop: *EventLoop) FileError!usize { |     pub fn size(file_access: *FileAccess, event_loop: *EventLoop) FileError!usize { | ||||||
|         // Save cursor to return to it later. |         // Save cursor to return to it later. | ||||||
|         const origin_cursor = try event_loop.tellFile(file_access); |         const origin_cursor = try event_loop.queryFile(file_access); | ||||||
| 
 | 
 | ||||||
|         try event_loop.seekFile(file_access, .tail, 0); |         try event_loop.seekFile(file_access, .tail, 0); | ||||||
| 
 | 
 | ||||||
|         const ending_cursor = try event_loop.tellFile(file_access); |         const ending_cursor = try event_loop.queryFile(file_access); | ||||||
| 
 | 
 | ||||||
|         // Return to original cursor. |         // Return to original cursor. | ||||||
|         try event_loop.seekFile(file_access, .head, origin_cursor); |         try event_loop.seekFile(file_access, .head, origin_cursor); | ||||||
| @ -391,14 +400,15 @@ pub const FileError = error { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// | /// | ||||||
| /// | /// Platform-agnostic mechanism for working with an abstraction of the underlying file-system(s) | ||||||
|  | /// available to the application in a sandboxed environment. | ||||||
| /// | /// | ||||||
| pub const FileSystem = enum { | pub const FileSystem = enum { | ||||||
|     data, |     data, | ||||||
|     user, |     user, | ||||||
| 
 | 
 | ||||||
|     /// |     /// | ||||||
|     /// Platform-agnostic mechanism for referencing files and directories on a [FileSystem] |     /// Platform-agnostic mechanism for referencing files and directories on a [FileSystem]. | ||||||
|     /// |     /// | ||||||
|     pub const Path = struct { |     pub const Path = struct { | ||||||
|         file_system: FileSystem, |         file_system: FileSystem, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user