Last active
June 12, 2022 19:01
-
-
Save andreadipersio/2f8f4599d6924cd2b94f952805a0d3bc to your computer and use it in GitHub Desktop.
Zig Examples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const io = std.io; | |
const assert = std.debug.assert; | |
// This example shows one possible way to approach Polymorphism in Zig | |
// using dynamic dispatch. | |
// | |
// Largely inspired by: | |
// - std/mem/Allocator.zig | |
// https://github.com/ziglang/zig/blob/77836e08a2384450b5e7933094511b61e3c22140/lib/std/mem/Allocator.zig#L55 | |
// | |
// - the allocgate article: | |
// https://pithlessly.github.io/allocgate.html | |
// | |
// For more in depth examples: | |
// https://revivalizer.xyz/post/the-missing-zig-polymorphism-reference/ | |
pub const Dog = struct { | |
ptr: *anyopaque, | |
vtable: *const VTable, | |
pub const VTable = struct { | |
bark: fn (ptr: *anyopaque) anyerror!void, | |
}; | |
pub fn init( | |
pointer: anytype, | |
comptime barkFn: fn (ptr: @TypeOf(pointer)) anyerror!void, | |
) Dog { | |
const Ptr = @TypeOf(pointer); | |
const ptr_info = @typeInfo(Ptr); | |
assert(ptr_info == .Pointer); | |
assert(ptr_info.Pointer.size == .One); | |
const alignment = ptr_info.Pointer.alignment; | |
const gen = struct { | |
fn barkImpl(ptr: *anyopaque) anyerror!void { | |
const self = @ptrCast(Ptr, @alignCast(alignment, ptr)); | |
return @call(.{ .modifier = .always_inline }, barkFn, .{self}); | |
} | |
const vtable = VTable{ | |
.bark = barkImpl, | |
}; | |
}; | |
return .{ | |
.ptr = pointer, | |
.vtable = &gen.vtable, | |
}; | |
} | |
pub fn bark(self: Dog) anyerror!void { | |
return self.vtable.bark(self.ptr); | |
} | |
}; | |
pub const Pug = struct { | |
name: []const u8, | |
pub fn dog(self: *Pug) Dog { | |
return Dog.init(self, bark); | |
} | |
fn bark(self: *Pug) anyerror!void { | |
std.debug.print("{s}: Derp Derp!\n", .{self.name}); | |
} | |
}; | |
pub const Husky = struct { | |
name: []const u8, | |
pub fn dog(self: *Husky) Dog { | |
return Dog.init(self, bark); | |
} | |
fn bark(self: *Husky) anyerror!void { | |
std.debug.print("{s}: Woof Woof!\n", .{self.name}); | |
} | |
}; | |
fn bark_twice(doggo: *Dog) anyerror!void { | |
try doggo.bark(); | |
try doggo.bark(); | |
} | |
pub fn main() anyerror!void { | |
var pug = Pug{ .name = "Frank" }; | |
var husky = Husky{ .name = "Saskia" }; | |
try bark_twice(&pug.dog()); | |
try bark_twice(&husky.dog()); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const io = std.io; | |
const testing = std.testing; | |
// The goal of this example is being able to do dependency injection of | |
// Stdin and Stdout. | |
// When writing tests we can replace Stdin and Stdout with buffers. | |
// Stdin -> Write to a buffer | |
// Stdout -> Read from a buffer | |
pub const EchoMachine = struct { | |
// | |
// io.StreamSource allow us to use either a file or a buffer | |
// | |
in: io.StreamSource.Reader, | |
out: io.StreamSource.Writer, | |
pub fn echo(self: EchoMachine) !void { | |
var buf: [64]u8 = undefined; | |
const user_input = try self.in.readUntilDelimiterOrEof(&buf, '\n'); | |
try self.out.print("{s}\n", .{user_input}); | |
} | |
}; | |
pub fn main() anyerror!void { | |
var em = EchoMachine{ | |
// | |
// In the command line implementation we use Stdin and Stdout | |
// | |
.in = (io.StreamSource{ .file = io.getStdIn() }).reader(), | |
.out = (io.StreamSource{ .file = io.getStdOut() }).writer(), | |
}; | |
try em.echo(); | |
} | |
test "test the echo machine" { | |
var in_buf: [64]u8 = undefined; | |
var out_buf: [64]u8 = undefined; | |
var in_stream = io.fixedBufferStream(&in_buf); | |
var out_stream = io.fixedBufferStream(&out_buf); | |
var em = EchoMachine{ | |
// | |
// In our test we use buffers instead | |
// | |
.in = (io.StreamSource{ .buffer = in_stream }).reader(), | |
.out = (io.StreamSource{ .buffer = out_stream }).writer(), | |
}; | |
const expected = "This is a test!\n"; | |
try in_stream.writer().writeAll(expected); | |
try em.echo(); | |
var result_buf: [64]u8 = undefined; | |
_ = try out_stream.reader().readAll(&result_buf); | |
try testing.expectEqualSlices(u8, expected, result_buf[0..expected.len]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment