Compare commits
2 Commits
ef2c6c3a3c
...
b698f18c4d
Author | SHA1 | Date |
---|---|---|
kayomn | b698f18c4d | |
kayomn | 461d9b7cf7 |
|
@ -14,7 +14,7 @@
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
"type": "gdb",
|
"type": "gdb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"target": "$(find zig-cache -name test) src/main.zig",
|
"target": "${workspaceFolder}/zig-cache/o/2c2b6e0f85a1dcd7caa00765b05ec679/test",
|
||||||
"arguments": "main.zig",
|
"arguments": "main.zig",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"valuesFormatting": "parseText",
|
"valuesFormatting": "parseText",
|
||||||
|
|
|
@ -171,9 +171,10 @@ test "Spliterating text" {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Opaque interface to a "writable" resource like a block device, memory buffer, or network socket.
|
/// Closure that captures a reference to writable resources like block devices, memory buffers,
|
||||||
|
/// network sockets, and more.
|
||||||
///
|
///
|
||||||
pub const Writer = meta.Function([]const u8, usize);
|
pub const Writer = meta.Function(@sizeOf(usize), []const u8, usize);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns `true` if `this_bytes` is the same length and contains the same data as `that_bytes`,
|
/// Returns `true` if `this_bytes` is the same length and contains the same data as `that_bytes`,
|
||||||
|
@ -212,19 +213,19 @@ test "Hashing bytes" {
|
||||||
try testing.expect(hashBytes(bytes_sequence) != hashBytes(&.{69, 42}));
|
try testing.expect(hashBytes(bytes_sequence) != hashBytes(&.{69, 42}));
|
||||||
}
|
}
|
||||||
|
|
||||||
var null_context: usize = undefined;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Writer that silently throws consumed data away and never fails.
|
/// Returns a [Writer] that silently consumes all given data without failure and throws it away.
|
||||||
///
|
///
|
||||||
/// This is commonly used for testing or redirected otherwise unwanted output data that can't not be
|
/// This is commonly used for testing or redirected otherwise unwanted output data that has to be
|
||||||
/// sent somewhere for whatever reason.
|
/// sent somewhere for whatever reason.
|
||||||
///
|
///
|
||||||
pub const null_writer = Writer.wrap(&null_context, struct {
|
pub fn nullWriter() Writer {
|
||||||
fn write(_: *@TypeOf(null_context), buffer: []const u8) usize {
|
return Writer.capture(std.mem.zeroes(usize), struct {
|
||||||
return buffer.len;
|
fn write(_: usize, buffer: []const u8) usize {
|
||||||
}
|
return buffer.len;
|
||||||
}.write);
|
}
|
||||||
|
}.write);
|
||||||
|
}
|
||||||
|
|
||||||
test "Null writing" {
|
test "Null writing" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
@ -232,7 +233,7 @@ test "Null writing" {
|
||||||
{
|
{
|
||||||
const sequence = "foo";
|
const sequence = "foo";
|
||||||
|
|
||||||
try testing.expectEqual(null_writer.apply(sequence), sequence.len);
|
try testing.expectEqual(nullWriter().apply(sequence), sequence.len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,5 +242,5 @@ test "Null writing" {
|
||||||
/// otherwise `false`.
|
/// otherwise `false`.
|
||||||
///
|
///
|
||||||
pub fn writeByte(writer: Writer, byte: u8) bool {
|
pub fn writeByte(writer: Writer, byte: u8) bool {
|
||||||
return (writer.call(.{@ptrCast([*]const u8, &byte)[0 .. 1]}) != 0);
|
return (writer.apply(std.mem.asBytes(&byte)) != 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns the return type of the function type `Fn`.
|
/// Returns the return type of the function type `Fn`.
|
||||||
///
|
///
|
||||||
|
@ -10,13 +12,14 @@ pub fn FnReturn(comptime Fn: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns single-input closure type where `Input` is the input type and `Output` is the output
|
/// Returns a single-input single-output closure type where `Input` represents the input type,
|
||||||
/// type.
|
/// `Output` represents the output type, and `captures_size` represents the size of the closure
|
||||||
|
/// context.
|
||||||
///
|
///
|
||||||
pub fn Function(comptime Input: type, comptime Output: type) type {
|
pub fn Function(comptime captures_size: usize, comptime Input: type, comptime Output: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
context: *anyopaque,
|
applyErased: fn (*anyopaque, Input) Output,
|
||||||
contextualApply: fn (*anyopaque, Input) Output,
|
context: [captures_size]u8,
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Function type.
|
/// Function type.
|
||||||
|
@ -24,38 +27,41 @@ pub fn Function(comptime Input: type, comptime Output: type) type {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Applies `input` to `self`, producing a result according to the type-erased
|
/// Applies `input` to `self`, producing a result according to the current context data.
|
||||||
/// implementation.
|
|
||||||
///
|
///
|
||||||
pub fn apply(self: Self, input: Input) Output {
|
pub fn apply(self: *Self, input: Input) Output {
|
||||||
return self.contextualApply(self.context, input);
|
return self.applyErased(&self.context, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Creates a new [Self] by wrapping `concrete_context` as a pointer to the implementation
|
/// Creates a new [Self] by capturing the `captures` value as the context and `call` as the
|
||||||
/// and `contextualApply` as the behavior executed when [apply] is called.
|
/// as the behavior executed when [apply] or [applyErased] is called.
|
||||||
///
|
///
|
||||||
/// The newly created [Self] is returned.
|
/// The newly created [Self] is returned.
|
||||||
///
|
///
|
||||||
pub fn wrap(
|
pub fn capture(captures: anytype, comptime call: fn (@TypeOf(captures), Input) Output) Self {
|
||||||
concrete_context: anytype,
|
const Captures = @TypeOf(captures);
|
||||||
comptime contextualApply: fn (@TypeOf(concrete_context), Input) Output
|
|
||||||
) Self {
|
|
||||||
const ConcreteContext = @TypeOf(concrete_context);
|
|
||||||
|
|
||||||
if (@typeInfo(ConcreteContext) != .Pointer)
|
if (@sizeOf(Captures) > captures_size)
|
||||||
@compileError("`concrete_context` must be a pointer type");
|
@compileError("`captures` must be smaller than or equal to " ++
|
||||||
|
std.fmt.comptimePrint("{d}", .{captures_size}) ++ " bytes");
|
||||||
|
|
||||||
return .{
|
const captures_align = @alignOf(Captures);
|
||||||
.context = concrete_context,
|
|
||||||
|
|
||||||
.contextualApply = struct {
|
var function = Self{
|
||||||
fn call(erased_context: *anyopaque, input: Input) Output {
|
.context = undefined,
|
||||||
return contextualApply(@ptrCast(ConcreteContext, @alignCast(
|
|
||||||
@alignOf(ConcreteContext), erased_context)), input);
|
.applyErased = struct {
|
||||||
|
fn do(erased: *anyopaque, input: Input) Output {
|
||||||
|
return call(@ptrCast(*Captures, @alignCast(
|
||||||
|
captures_align, erased)).*, input);
|
||||||
}
|
}
|
||||||
}.call,
|
}.do,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ptrCast(*Captures, @alignCast(captures_align, &function.context)).* = captures;
|
||||||
|
|
||||||
|
return function;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub fn Fixed(comptime Element: type) type {
|
||||||
if (Element != u8) @compileError("Cannot coerce fixed stack of type " ++
|
if (Element != u8) @compileError("Cannot coerce fixed stack of type " ++
|
||||||
@typeName(Element) ++ " into a Writer");
|
@typeName(Element) ++ " into a Writer");
|
||||||
|
|
||||||
return io.Writer.wrap(self, struct {
|
return io.Writer.capture(self, struct {
|
||||||
fn write(stack: *Self, buffer: []const u8) usize {
|
fn write(stack: *Self, buffer: []const u8) usize {
|
||||||
stack.pushAll(buffer) catch |err| switch (err) {
|
stack.pushAll(buffer) catch |err| switch (err) {
|
||||||
error.OutOfMemory => return 0,
|
error.OutOfMemory => return 0,
|
||||||
|
@ -109,8 +109,5 @@ test "Fixed stack manipulation" {
|
||||||
stack.clear();
|
stack.clear();
|
||||||
|
|
||||||
try testing.expectEqual(stack.count(), 0);
|
try testing.expectEqual(stack.count(), 0);
|
||||||
|
try testing.expectEqual(stack.writer().apply(&.{0, 0, 0, 0}), 4);
|
||||||
const writer = stack.writer();
|
|
||||||
|
|
||||||
try testing.expectEqual(writer.apply(&.{0, 0, 0, 0}), 4);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue