Modify Function type implementation to have customisable capture sizes
This commit is contained in:
		
							parent
							
								
									ef2c6c3a3c
								
							
						
					
					
						commit
						461d9b7cf7
					
				| @ -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 { | ||||||
|  |         fn write(_: usize, buffer: []const u8) usize { | ||||||
|             return buffer.len; |             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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user