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; | ||||
| 
 | ||||
| /// | ||||
| /// 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, | ||||
| /// network sockets, and more. | ||||
| @ -161,7 +65,7 @@ test "Spliterating text" { | ||||
|         var index = @as(usize, 0); | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
|         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. | ||||
| /// | ||||
| 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, | ||||
|     else => @compileError("`pointer` must be a pointer type"), | ||||
| } { | ||||
| @ -233,7 +137,35 @@ test "Bytes of types" { | ||||
| 
 | ||||
|     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 { | ||||
|     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; | ||||
| } | ||||
|  | ||||
		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.