Skip to content

Commit

Permalink
Switched to enforcing default values when names match to allow coerci…
Browse files Browse the repository at this point in the history
…on and give better errors.
  • Loading branch information
permutationlock committed Nov 21, 2023
1 parent 14fcb75 commit 328b8b5
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 22 deletions.
37 changes: 19 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const Server = struct {
// using the server library
var server = Server{};
var handler = MyHandler{};
try server.listen(port);
try server.listen(8080);
while (true) {
try server.poll(
&handler,
Expand All @@ -78,11 +78,9 @@ would need to be defined again separately.

The idea behind `zimpl` is to try and get the best of both worlds:
- Library writers define interfaces and require an interface
implementation to be passed alongside each generic parameter.
- Library consumers must define interface
implementations, but if a type has declarations matching
an interface then the implementation
can be inferred via a default constructor.
implementation alongside each generic parameter.
- Library consumers may infer interface implementations using the
default constructor.

```Zig
const Server = struct {
Expand All @@ -104,11 +102,7 @@ const Server = struct {
while (self.getEvent()) |evt| {
switch (evt) {
.open => |handle| handler_impl.onOpen(handler_ctx, handle),
.msg => |msg| handler_impl.onMessage(
handler_ctx,
msg.handle,
msg.bytes,
),
.msg => |msg| handler_impl.onMessage(handler_ctx, msg.handle, msg.bytes),
.close => |handle| handler_impl.onClose(handler_ctx, handle),
}
}
Expand All @@ -120,7 +114,7 @@ const Server = struct {
// using the server library
var server = Server{};
var handler = MyHandler{};
try server.listen(port);
try server.listen(8080);
while (true) {
// Impl(*MyHandler, Handler) can be default constructed because MyHandler
// has onOpen, onMessage, and onClose member functions of the correct types
Expand All @@ -143,17 +137,16 @@ pub fn Impl(comptime Type: type, comptime Ifc: fn (comptime type) type) type { .

#### Arguments

For all types `T`, the return type `Ifc(T)` must be a struct type and any public
declarations of `Ifc(T)` must be of type `type`.
For all types `T`, the type `Ifc(T)` must be a struct with only public
declarations of type `type`.

#### Return value

The return value is a struct type containing one field
The return value `Impl(Type, Ifc)` is a struct type containing one field
for each type valued declaration of `Ifc(Type)`.
The default value of each field is set to be the
declaration
of `Type` of the same name, if such a declaration exists
with a matching type[^1].
of `Type` of the same name, if such a declaration exists[^1].

If `Ifc(Type)` contains a declaration that isn't a type, then a compile
error is produced.
Expand Down Expand Up @@ -214,7 +207,7 @@ const FixedBufferReader = struct {
pub const ReadError = error{};
pub fn read(self: *@This(), out_buffer: []u8) anyerror!usize {
pub fn read(self: *@This(), out_buffer: []u8) ReadError!usize {
const len = @min(self.buffer[self.pos..].len, out_buffer.len);
@memcpy(
out_buffer[0..len],
Expand All @@ -235,6 +228,14 @@ test {
try testing.expectEqualSlices(u8, in_buf[0..len], out_buf[0..len]);
}
```
The concrete `Reader` implementation type generated for
`FixeBufferReader` in the example above is shown below.
```
Impl(*FixedBufferReader, Reader) = struct {
ReadError: type = FixeBufferError.ReadError,
read: fn (*FixedBufferReader, []u8) anyerror!void = FixedBufferError.read,
};
```
A more complete Zimpl implementation of the interfaces in
`std.io` is available in [examples/io.zig][6].

Expand Down
2 changes: 1 addition & 1 deletion examples/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ const FixedBufferStream = struct {

pub const ReadError = error{};

pub fn read(self: *@This(), out_buffer: []u8) anyerror!usize {
pub fn read(self: *@This(), out_buffer: []u8) ReadError!u64 {
const len = @min(self.buffer[self.pos..].len, out_buffer.len);
@memcpy(
out_buffer[0..len],
Expand Down
7 changes: 4 additions & 3 deletions src/zimpl.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ pub fn Impl(comptime Type: type, comptime Ifc: IfcFn) type {
switch (@typeInfo(UWType)) {
inline else => |info| if (@hasField(@TypeOf(info), "decls")) {
if (@hasDecl(UWType, decl.name)) {
if (@TypeOf(@field(UWType, decl.name)) == fld.*.type) {
fld.*.default_value = &@field(UWType, decl.name);
}
fld.*.default_value = &@as(fld_type, @field(
UWType,
decl.name,
));
}
},
}
Expand Down

0 comments on commit 328b8b5

Please sign in to comment.