Application Context Implementation #4
|
@ -377,23 +377,19 @@ test "Data swapping" {
|
|||
}
|
||||
|
||||
///
|
||||
/// Returns a [Writer] that silently consumes all given data without failure and throws it away.
|
||||
/// [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 has to be
|
||||
/// sent somewhere for whatever reason.
|
||||
///
|
||||
pub fn nullWriter() Writer {
|
||||
var dummy: usize = 0;
|
||||
|
||||
return Writer.capture(&dummy, struct {
|
||||
fn write(_: *usize, buffer: []const u8) usize {
|
||||
pub const null_writer = Writer.from(struct {
|
||||
fn write(buffer: []const u8) usize {
|
||||
return buffer.len;
|
||||
}
|
||||
}.write);
|
||||
}
|
||||
|
||||
test "Null writing" {
|
||||
const sequence = "foo";
|
||||
|
||||
try testing.expect(nullWriter().call(sequence) == sequence.len);
|
||||
try testing.expect(null_writer.call(sequence) == sequence.len);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ pub fn Function(comptime In: type, comptime Out: type) type {
|
|||
callErased: fn (*anyopaque, In) Out,
|
||||
context: *anyopaque,
|
||||
|
||||
fn Invoker(comptime Context: type) type {
|
||||
return if (Context == void) fn (In) Out else fn (Context, In) Out;
|
||||
}
|
||||
|
||||
///
|
||||
/// Function type.
|
||||
///
|
||||
|
@ -26,23 +30,42 @@ pub fn Function(comptime In: type, comptime Out: type) type {
|
|||
///
|
||||
/// Invokes `self` with `input`, producing a result according to the current context data.
|
||||
///
|
||||
pub fn call(self: *Self, input: In) Out {
|
||||
pub fn call(self: Self, input: In) Out {
|
||||
return self.callErased(self.context, input);
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a new [Self] by capturing the `context` value as the capture context and
|
||||
/// Creates and returns a [Self] using the `invoke` as the behavior executed when [call] or
|
||||
/// [callErased] is called.
|
||||
///
|
||||
/// For creating a closure-style function, see [fromClosure].
|
||||
///
|
||||
pub fn from(comptime invoke: fn (In) Out) Self {
|
||||
return .{
|
||||
.context = undefined,
|
||||
|
||||
.callErased = struct {
|
||||
fn callErased(_: *anyopaque, input: In) Out {
|
||||
return invoke(input);
|
||||
}
|
||||
}.callErased,
|
||||
};
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates and returns a [Self] by capturing the `context` value as the capture context and
|
||||
/// `invoke` as the behavior executed when [call] or [callErased] is called.
|
||||
///
|
||||
/// The newly created [Self] is returned.
|
||||
///
|
||||
pub fn capture(context: anytype, comptime invoke: fn (@TypeOf(context), In) Out) Self {
|
||||
pub fn fromClosure(context: anytype, comptime invoke: fn (@TypeOf(context), In) Out) Self {
|
||||
const Context = @TypeOf(context);
|
||||
|
||||
switch (@typeInfo(Context)) {
|
||||
.Pointer => |info| if (info.size == .Slice)
|
||||
@compileError("`context` cannot be a slice"),
|
||||
|
||||
.Void => {},
|
||||
else => @compileError("`context` must be a pointer"),
|
||||
}
|
||||
|
||||
|
@ -51,8 +74,8 @@ pub fn Function(comptime In: type, comptime Out: type) type {
|
|||
|
||||
.callErased = struct {
|
||||
fn callErased(erased: *anyopaque, input: In) Out {
|
||||
return invoke(@ptrCast(*Context, @alignCast(
|
||||
@alignOf(Context), erased)).*, input);
|
||||
return if (Context == void) invoke(input) else invoke(@ptrCast(
|
||||
*Context, @alignCast(@alignOf(Context), erased)).*, input);
|
||||
}
|
||||
}.callErased,
|
||||
};
|
||||
|
|
|
@ -122,7 +122,7 @@ pub const PushError = io.Allocator.MakeError;
|
|||
/// referenced by `fixed_stack` until it is full.
|
||||
///
|
||||
pub fn fixedWriter(fixed_stack: *Fixed(u8)) io.Writer {
|
||||
return io.Writer.capture(fixed_stack, struct {
|
||||
return io.Writer.fromClosure(fixed_stack, struct {
|
||||
fn write(stack: *Fixed(u8), buffer: []const u8) usize {
|
||||
stack.pushAll(buffer) catch |err| switch (err) {
|
||||
error.OutOfMemory => return 0,
|
||||
|
|
Loading…
Reference in New Issue