Application Context Implementation #4
							
								
								
									
										138
									
								
								src/core/io.zig
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								src/core/io.zig
									
									
									
									
									
								
							| @ -7,102 +7,6 @@ const std = @import("std"); | |||||||
| /// | /// | ||||||
| pub const Allocator = std.mem.Allocator; | pub const Allocator = std.mem.Allocator; | ||||||
| 
 | 
 | ||||||
| /// |  | ||||||
| /// File-system agnostic abstraction for manipulating a file. |  | ||||||
| /// |  | ||||||
| pub const FileAccess = struct { |  | ||||||
|     context: *anyopaque, |  | ||||||
|     implementation: *const Implementation, |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Provides a set of implementation-specific behaviors to a [FileAccess] instance. |  | ||||||
|     /// |  | ||||||
|     pub const Implementation = struct { |  | ||||||
|         close: fn (*anyopaque) void, |  | ||||||
|         queryCursor: fn (*anyopaque) Error!u64, |  | ||||||
|         queryLength: fn (*anyopaque) Error!u64, |  | ||||||
|         read: fn (*anyopaque, []u8) Error!usize, |  | ||||||
|         seek: fn (*anyopaque, u64) Error!void, |  | ||||||
|         seekToEnd: fn (*anyopaque) Error!void, |  | ||||||
|         skip: fn (*anyopaque, i64) Error!void, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// [Error.FileInaccessible] is a generic catch-all for a [FileAccess] reference no longer |  | ||||||
|     /// pointing to a file or the file becomming invalid for whatever reason. |  | ||||||
|     /// |  | ||||||
|     pub const Error = error { |  | ||||||
|         FileInaccessible, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Close the file referenced by `file_access` on the main thread, invalidating the reference to |  | ||||||
|     /// it and releasing any associated resources. |  | ||||||
|     /// |  | ||||||
|     /// Freeing an invalid `file_access` has no effect on the file and logs a warning over the |  | ||||||
|     /// wasted effort. |  | ||||||
|     /// |  | ||||||
|     pub fn close(file_access: FileAccess) void { |  | ||||||
|         return file_access.implementation.close(file_access.context); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Attempts to query the current 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 |  | ||||||
|     /// [Error] on failure. |  | ||||||
|     /// |  | ||||||
|     pub fn queryCursor(file_access: FileAccess) Error!u64 { |  | ||||||
|         return file_access.implementation.queryCursor(file_access.context); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Attempts to query the current length for the file referenced by `file_access`. |  | ||||||
|     /// |  | ||||||
|     /// Returns the current length of the file at the time of the operation or a [Error] if the file |  | ||||||
|     /// failed to be queried. |  | ||||||
|     /// |  | ||||||
|     pub fn queryLength(file_access: FileAccess) Error!u64 { |  | ||||||
|         return file_access.implementation.queryLength(file_access.context); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Attempts to read `file_access` from the its current position into `buffer`. |  | ||||||
|     /// |  | ||||||
|     /// Returns the number of bytes that were available to be read, otherwise an [Error] on failure. |  | ||||||
|     /// |  | ||||||
|     pub fn read(file_access: FileAccess, buffer: []u8) Error!usize { |  | ||||||
|         return file_access.implementation.read(file_access.context, buffer); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Attempts to seek `file_access` from the beginning of the file to `cursor` bytes. |  | ||||||
|     /// |  | ||||||
|     /// Returns [Error] on failure. |  | ||||||
|     /// |  | ||||||
|     pub fn seek(file_access: FileAccess, cursor: u64) Error!void { |  | ||||||
|         return file_access.implementation.seek(file_access.context, cursor); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Attempts to seek `file_access` to the end of the file. |  | ||||||
|     /// |  | ||||||
|     /// Returns [Error] on failure. |  | ||||||
|     /// |  | ||||||
|     pub fn seekToEnd(file_access: FileAccess) Error!void { |  | ||||||
|         return file_access.implementation.seekToEnd(file_access.context); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// |  | ||||||
|     /// Attempts to seek `file_access` by `offset` from the current file position. |  | ||||||
|     /// |  | ||||||
|     /// Returns [Error] on failure; |  | ||||||
|     /// |  | ||||||
|     pub fn skip(file_access: FileAccess, offset: i64) Error!void { |  | ||||||
|         return file_access.implementation.skip(file_access.context, offset); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /// | /// | ||||||
| /// Closure that captures a reference to readable resources like block devices, memory buffers, | /// Closure that captures a reference to readable resources like block devices, memory buffers, | ||||||
| /// network sockets, and more. | /// network sockets, and more. | ||||||
| @ -161,7 +65,7 @@ test "Spliterating text" { | |||||||
|         var index = @as(usize, 0); |         var index = @as(usize, 0); | ||||||
| 
 | 
 | ||||||
|         while (spliterator.next()) |split| : (index += 1) { |         while (spliterator.next()) |split| : (index += 1) { | ||||||
|             try testing.expect(std.mem.eql(u8, split, components[index])); |             try testing.expect(equals(u8, split, components[index])); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -176,7 +80,7 @@ test "Spliterating text" { | |||||||
|         var index = @as(usize, 0); |         var index = @as(usize, 0); | ||||||
| 
 | 
 | ||||||
|         while (spliterator.next()) |split| : (index += 1) { |         while (spliterator.next()) |split| : (index += 1) { | ||||||
|             try testing.expect(std.mem.eql(u8, split, components[index])); |             try testing.expect(equals(u8, split, components[index])); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -209,7 +113,7 @@ test "Check memory begins with" { | |||||||
| /// | /// | ||||||
| /// **Note** that passing a slice will convert it to a byte slice. | /// **Note** that passing a slice will convert it to a byte slice. | ||||||
| /// | /// | ||||||
| pub fn bytes(pointer: anytype) switch (@typeInfo(@TypeOf(pointer))) { | pub fn bytesOf(pointer: anytype) switch (@typeInfo(@TypeOf(pointer))) { | ||||||
|     .Pointer => |info| if (info.is_const) []const u8 else []u8, |     .Pointer => |info| if (info.is_const) []const u8 else []u8, | ||||||
|     else => @compileError("`pointer` must be a pointer type"), |     else => @compileError("`pointer` must be a pointer type"), | ||||||
| } { | } { | ||||||
| @ -233,7 +137,35 @@ test "Bytes of types" { | |||||||
| 
 | 
 | ||||||
|     var foo: u32 = 10; |     var foo: u32 = 10; | ||||||
| 
 | 
 | ||||||
|     testing.expectEqual(bytes(&foo), 0x0a); |     testing.expectEqual(bytesOf(&foo), 0x0a); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// | ||||||
|  | /// Compares `this` to `that`, returning the difference between the first byte deviation in the two | ||||||
|  | /// sequences, otherwise `0` if they are identical. | ||||||
|  | /// | ||||||
|  | pub fn compareBytes(this: []const u8, that: []const u8) isize { | ||||||
|  |     var cursor: usize = 0; | ||||||
|  | 
 | ||||||
|  |     while (cursor != this.len) : (cursor += 1) { | ||||||
|  |         const this_byte = this[cursor]; | ||||||
|  | 
 | ||||||
|  |         if (cursor != that.len) return this_byte; | ||||||
|  | 
 | ||||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 | |||||||
|  |         const that_byte = that[cursor]; | ||||||
|  | 
 | ||||||
|  |         if (this_byte != that_byte) return (this_byte - that_byte); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | test "Compare bytes" { | ||||||
|  |     const testing = std.testing; | ||||||
|  | 
 | ||||||
|  |     try testing.expectEquals(compareBytes(&.{69, 42, 0}, &.{69, 42, 0}), 0); | ||||||
|  |     try testing.expectEquals(compareBytes(&.{69, 42, 0}, &.{69, 42}), 42); | ||||||
|  |     try testing.expectEquals(compareBytes(&.{69, 42}, &.{69, 42, 0}), -42); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// | /// | ||||||
| @ -243,11 +175,9 @@ test "Bytes of types" { | |||||||
| pub fn equals(comptime Element: type, this: []const Element, that: []const Element) bool { | pub fn equals(comptime Element: type, this: []const Element, that: []const Element) bool { | ||||||
|     if (this.len != that.len) return false; |     if (this.len != that.len) return false; | ||||||
| 
 | 
 | ||||||
|     { |     var i = std.mem.zeroes(usize); | ||||||
|         var i = std.mem.zeroes(usize); |  | ||||||
| 
 | 
 | ||||||
|         while (i < this.len) : (i += 1) if (this[i] != that[i]) return false; |     while (i < this.len) : (i += 1) if (this[i] != that[i]) return false; | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	
Comment needs clarify as it appears slightly misleading / ambiguous in its current wording.
On further thought, having the comment here to begin with only adds confusion.
While slices don't have as trivial of a memory layout as other pointer types, they're still language primitives and should reasonably be treated the same as other pointer kinds.