Skip to content

Commit

Permalink
Shortened zimpl.zig improving clarity
Browse files Browse the repository at this point in the history
  • Loading branch information
permutationlock committed Nov 24, 2023
1 parent fa03944 commit 49a503a
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 62 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ The `zimpl` module is ~30 lines of code and exposes one public
declaration: `Impl`.

```Zig
pub fn Impl(comptime Type: type, comptime Ifc: fn (type) type) type { ... }
pub fn Impl(comptime T: type, comptime Ifc: fn (type) type) type { ... }
```

## Arguments

The function `Ifc` must always return a struct type.
The function `Ifc` must always return a struct type.

If `T` has a declaration matching the name of a field from
`Ifc(T)` that cannot coerce to the type of the field, then a
compile error will occur.

## Return value

The return value `Impl(Type, Ifc)` is a struct type with the same fields
as `Ifc(Type)`, but with the default value of each field set equal to
the declaration of `Unwrap(Type)` of the same name, if such a declaration
The type `Impl(T, Ifc)` is a struct type with the same fields
as `Ifc(T)`, but with the default value of each field set equal to
the declaration of `Unwrap(T)` of the same name, if such a declaration
exists. The `Unwrap` function removes all layers of `*`, `?`, or `!`
wrapping a type, e.g. `Unwrap(!?*u32)` is `u32`.

If `Type` has a declaration matching the name of a field from
`Ifc(Type)` that cannot coerce to the type of the field, then a
compile error will occur.

## Example

```Zig
// An interface
pub fn Reader(comptime Type: type) type {
pub fn Reader(comptime T: type) type {
return struct {
ReadError: type = error{},
read: fn (reader_ctx: Type, buffer: []u8) anyerror!usize,
read: fn (reader_ctx: T, buffer: []u8) anyerror!usize,
};
}
Expand Down
6 changes: 3 additions & 3 deletions examples/count.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ const zimpl = @import("zimpl");
const Impl = zimpl.Impl;
const PtrChild = zimpl.PtrChild;

fn Counter(comptime Type: type) type {
fn Counter(comptime T: type) type {
return struct {
increment: fn (Type) void,
read: fn (Type) usize,
increment: fn (T) void,
read: fn (T) usize,
};
}

Expand Down
22 changes: 10 additions & 12 deletions examples/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ pub const countingWriter = @import("io/counting_writer.zig").countingWriter;
pub const null_writer = NullWriter{};

pub const NullWriter = struct {
pub const WriteError = error{};

pub fn write(_: NullWriter, data: []const u8) WriteError!usize {
pub fn write(_: NullWriter, data: []const u8) error{}!usize {
return data.len;
}
};
Expand All @@ -25,10 +23,10 @@ test "null_writer" {
writeAll(null_writer, .{}, "yay" ** 10) catch |err| switch (err) {};
}

pub fn Reader(comptime Type: type) type {
pub fn Reader(comptime T: type) type {
return struct {
ReadError: type = error{},
read: fn (reader_ctx: Type, buffer: []u8) anyerror!usize,
read: fn (reader_ctx: T, buffer: []u8) anyerror!usize,
};
}

Expand Down Expand Up @@ -256,10 +254,10 @@ pub inline fn readEnum(
return E.InvalidValue;
}

pub fn Writer(comptime Type: type) type {
pub fn Writer(comptime T: type) type {
return struct {
WriteError: type = error{},
write: fn (writer_ctx: Type, bytes: []const u8) anyerror!usize,
write: fn (writer_ctx: T, bytes: []const u8) anyerror!usize,
};
}

Expand Down Expand Up @@ -335,17 +333,17 @@ pub fn writeStruct(
return writeAll(writer_ctx, writer_impl, mem.asBytes(&value));
}

pub fn Seekable(comptime Type: type) type {
pub fn Seekable(comptime T: type) type {
return struct {
SeekError: type = error{},

seekTo: fn (seek_ctx: Type, pos: u64) anyerror!void,
seekBy: fn (seek_ctx: Type, amt: i64) anyerror!void,
seekTo: fn (seek_ctx: T, pos: u64) anyerror!void,
seekBy: fn (seek_ctx: T, amt: i64) anyerror!void,

GetSeekPosError: type = error{},

getPos: fn (seek_ctx: Type) anyerror!u64,
getEndPos: fn (seek_ctx: Type) anyerror!u64,
getPos: fn (seek_ctx: T) anyerror!u64,
getEndPos: fn (seek_ctx: T) anyerror!u64,
};
}

Expand Down
4 changes: 2 additions & 2 deletions examples/io/FixedBufferReader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ pub fn seekBy(self: *@This(), amt: i64) error{}!void {
}
}

pub fn getPos(self: *@This()) error{}!u64 {
pub fn getPos(self: *const @This()) error{}!u64 {
return self.pos;
}

pub fn getEndPos(self: *@This()) error{}!u64 {
pub fn getEndPos(self: *const @This()) error{}!u64 {
return self.buffer.len;
}

Expand Down
6 changes: 3 additions & 3 deletions examples/io/FixedBufferStream.zig
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ pub fn seekBy(self: *@This(), amt: i64) SeekError!void {
}
}

pub fn getPos(self: *@This()) GetSeekPosError!u64 {
pub fn getPos(self: *const @This()) GetSeekPosError!u64 {
return self.pos;
}

pub fn getEndPos(self: *@This()) GetSeekPosError!u64 {
pub fn getEndPos(self: *const @This()) GetSeekPosError!u64 {
return self.buffer.len;
}

pub fn getWritten(self: *@This()) []u8 {
pub fn getWritten(self: *const @This()) []u8 {
return self.buffer[0..self.pos];
}

Expand Down
4 changes: 2 additions & 2 deletions examples/iterator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const Impl = zimpl.Impl;

fn Iterator(comptime Data: type) fn (type) type {
return struct {
pub fn Ifc(comptime Type: type) type {
pub fn Ifc(comptime T: type) type {
return struct {
next: fn (*Type) ?*Data,
next: fn (*T) ?*Data,
};
}
}.Ifc;
Expand Down
43 changes: 19 additions & 24 deletions src/zimpl.zig
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
const std = @import("std");
const Type = @import("std").builtin.Type;

pub fn Impl(comptime Type: type, comptime Ifc: fn (type) type) type {
const ifc_fields = @typeInfo(Ifc(Type)).Struct.fields;
var fields: [ifc_fields.len]std.builtin.Type.StructField = undefined;
for (&fields, ifc_fields) |*fld, ifc_fld| {
fld.* = ifc_fld;
// infer default value from Unwrap(Type)
const UWType = Unwrap(Type);
switch (@typeInfo(UWType)) {
pub fn Impl(comptime T: type, comptime Ifc: fn (type) type) type {
const ifc = @typeInfo(Ifc(T)).Struct.fields;
var fields = @as(*const [ifc.len]Type.StructField, @ptrCast(ifc.ptr)).*;
for (&fields) |*field| {
switch (@typeInfo(Unwrap(T))) {
inline else => |info| if (@hasField(@TypeOf(info), "decls")) {
if (@hasDecl(UWType, ifc_fld.name)) {
const decl = @field(UWType, ifc_fld.name);
fld.*.default_value = &@as(ifc_fld.type, decl);
if (@hasDecl(Unwrap(T), field.name)) {
const decl = @field(Unwrap(T), field.name);
field.*.default_value = &@as(field.type, decl);
}
},
}
}
return @Type(std.builtin.Type{
.Struct = .{
.layout = .Auto,
.fields = &fields,
.decls = &[0]std.builtin.Type.Declaration{},
.is_tuple = false,
},
});
return @Type(Type{ .Struct = .{
.layout = .Auto,
.fields = &fields,
.decls = &[0]Type.Declaration{},
.is_tuple = false,
} });
}

fn Unwrap(comptime Type: type) type {
return switch (@typeInfo(Type)) {
.Pointer => |info| if (info.size == .One) Unwrap(info.child) else Type,
fn Unwrap(comptime T: type) type {
return switch (@typeInfo(T)) {
.Pointer => |info| if (info.size == .One) Unwrap(info.child) else T,
.Optional => |info| Unwrap(info.child),
.ErrorUnion => |info| Unwrap(info.payload),
else => Type,
else => T,
};
}
10 changes: 5 additions & 5 deletions why.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ the callback functions.
```Zig
const Server = struct {
// ...
pub fn Handler(comptime Type: type) type {
pub fn Handler(comptime T: type) type {
return struct {
onOpen: fn (Type, Handle) void,
onMessage: fn (Type, Handle, []const u8) void,
onClose: fn (Type, Handle) void,
onOpen: fn (T, Handle) void,
onMessage: fn (T, Handle, []const u8) void,
onClose: fn (T, Handle) void,
};
}
Expand Down Expand Up @@ -132,7 +132,7 @@ while (true) {
```

The Zimpl library provides the function `Impl` that infers the default
value for each member of `Handler(Type)` from the declarations of `Type`.
value for each member of `Handler(T)` from the declarations of `T`.

```Zig
const Server = struct {
Expand Down

0 comments on commit 49a503a

Please sign in to comment.