I just had plain c.sdl* functions and I decided that I want to strip them to sdl.*
Gnerally it is just about trying to find a way to create decls for comptime generated struct (As a probably a lot of people tried: example1, example2). And I found one way!
In zig you can do following:
// It is definitely not ofraid of runtime light...
const NotVampire = struct {
pub fn test_fn() void {}
// Just formally it could be runtime. We see it
// but now it is comptime only type because of this field
i_am_variable_i_swear: @TypeOf(test_fn) = test_fn,
variable: u8,
};
But you when try check the @typeInfo(NotVampire).@"struct".field_names you will see the i_am_variable_i_swear and will be able to check it is type and etc. So I understood that it can be abused used for my purposes
It creates kind of “illegal” and very restrained structs but it CREATES NEW STRUCTS WITH FUNCTIONS!. Because I am so excited it seems to me someone already did this before me (maybe even in the linked threads, I am not sure)…
Also if you are not following rules (won’t mention them) you are going to either scare the Maker process with horrible code or outright kill it and get SIGSEGV (this part probably should be reported as bug
)
const std = @import("std");
const Amogus = struct {
fn amogus_speech() void {
std.debug.print("Amogus speech: I am normal crewmate. Don't kill me\n", .{});
}
};
const Normal = struct {
pub fn test_fn() void {}
i_am_variable_i_swear: @TypeOf(test_fn) = test_fn,
arg: u8,
};
pub fn main(init: std.process.Init) !void {
// To show that main wasn't just wholly optimized to comptime
var buf: [1024]u8 = undefined;
var stdin_reader = std.Io.File.stdin().reader(init.io, &buf);
const stdin = &stdin_reader.interface;
const input = try stdin.takeByte();
// const amogus: Amogus = .{};
// amogus.amogus_speech(); // Illegal: amogus_speech is not a field or member function
// Amogus.amogus_speech(); // Legal
// Impostor().amogus_speech(); // Illegal: amogus_speech is actualy a field (which exist only for instances not for type itself)
// const impostor: Impostor() = .{ .variable = input }; // Illegal: comptime-only type can't store runtime value
const impostor: Impostor() = .{ .variable = 32 };
impostor.amogus_speech();
impostor.impostor_speech(input);
std.debug.print("{}\n", .{impostor.variable});
// Illegal, when you add any non `.@"comptime" = true` fields but you still can instanciate it
std.debug.print("Size of impostor: {}\n", .{@sizeOf(Impostor())});
}
fn Impostor() type {
const anon = struct {
fn impostor_speech(runtime: u8) void {
std.debug.print("It's not SIGSEGV. I am born! Muahahahahahaha!\n", .{});
std.debug.print("I had also ripped off a part of amogus: `amogus_speech()`\n", .{});
std.debug.print("I know runtime values: {c}\n", .{runtime});
std.debug.print("I have variables, but don't know how to access them\n", .{});
std.debug.print("And I don't know my runtime size\n", .{});
std.debug.print("I exist but I am crippled (ă… ďąŹă… )\n", .{});
}
};
const info = @typeInfo(struct {}).@"struct";
const new_names = [_][]const u8{ "amogus_speech", "impostor_speech", "variable" };
const new_types = [_]type{ @TypeOf(Amogus.amogus_speech), @TypeOf(anon.impostor_speech), u32 };
const new_attrs = [_]std.lang.Type.Struct.FieldAttributes{
.{ .@"comptime" = false, .default_value_ptr = Amogus.amogus_speech },
.{ .@"comptime" = false, .default_value_ptr = anon.impostor_speech },
.{ .@"comptime" = false },
};
return @Struct(info.layout, info.backing_integer, &new_names, @ptrCast(&new_types), @ptrCast(&new_attrs));
}
P.S It is more like “showcase” but I am not sure. It seems to be more suitable here… I found a way to not only shoot my legs but also legs of compiler
. And yeah, please tell me if it was really already known