Application Context Implementation #4

Closed
kayomn wants to merge 93 commits from event-loop-dev into main
1 changed files with 34 additions and 104 deletions
Showing only changes of commit b4816a34f6 - Show all commits

View File

@ -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

Comment needs clarify as it appears slightly misleading / ambiguous in its current wording.

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.

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.
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;
}