Skip to content

Instantly share code, notes, and snippets.

@dadepo
Created August 31, 2024 19:42
Show Gist options
  • Save dadepo/a0c47dda6fc87aaf737260f1a5961a55 to your computer and use it in GitHub Desktop.
Save dadepo/a0c47dda6fc87aaf737260f1a5961a55 to your computer and use it in GitHub Desktop.
// Without printing comptime argument or anytype.
const std = @import("std");
const assert = std.debug.assert;
pub const Logger = ScopedLogger(null);
pub fn ScopedLogger(comptime maybe_scope: ?type) type {
return struct {
ptr: *anyopaque,
writeFn: *const fn (ptr: *anyopaque, buf: []const u8) void,
pub fn init(pointer: anytype, comptime writeFn: fn (ptr: @TypeOf(pointer), buf: []const u8) void) ScopedLogger(maybe_scope) {
const Ptr = @TypeOf(pointer);
assert(@typeInfo(Ptr) == .Pointer); // Must be a pointer
assert(@typeInfo(Ptr).Pointer.size == .One); // Must be a single-item pointer
assert(@typeInfo(@typeInfo(Ptr).Pointer.child) == .Struct); // Must point to a struct
const gen = struct {
fn write(ptr: *anyopaque, buf: []const u8) void {
const self: Ptr = @ptrCast(@alignCast(ptr));
writeFn(self, buf);
}
};
return .{
.ptr = pointer,
.writeFn = gen.write,
};
}
pub fn unscope(logger: *ScopedLogger(maybe_scope)) ScopedLogger(null) {
return .{
.ptr = logger,
.writeFn = logger.writeFn,
};
}
pub fn log(logger: ScopedLogger(maybe_scope), buf: []const u8) void {
if (maybe_scope) |scope| {
logger.writeFn(logger.ptr, @typeName(scope));
logger.writeFn(logger.ptr, "-");
logger.writeFn(logger.ptr, buf);
} else {
logger.writeFn(logger.ptr, "[ - ]");
logger.writeFn(logger.ptr, buf);
}
}
};
}
pub const StandardErrLoger = struct {
pub fn init() StandardErrLoger {
return .{};
}
pub fn scopedLogger(self: *StandardErrLoger, comptime scope: type) ScopedLogger(scope) {
return ScopedLogger(scope).init(self, write);
}
pub fn logger(self: *StandardErrLoger) ScopedLogger(null) {
return Logger.init(self, write);
}
fn write(_: *StandardErrLoger, buf: []const u8) void {
std.debug.print("{s}", .{buf});
}
};
// var std_logger = log.StandardErrLoger.init();
// var scopped_logger = std_logger.scopedLogger(@This());
// scopped_logger.log("Hello world\n");
// var unscopped_logger = scopped_logger.unscope();
// unscopped_logger.log("Hello world");
// zig run src/main.zig
// main-Hello world
// [ - ]Hello world%
// Trying to support printing comptime argument or anytype.
// To be able to print k/v fields
// var std_logger = log.StandardErrLoger.init();
// var scopped_logger = std_logger.scopedLogger(@This());
// scopped_logger.log("Hello world\n", .{.k1, "v2"});
// Implementation:
const std = @import("std");
const assert = std.debug.assert;
pub const Logger = ScopedLogger(null);
pub fn ScopedLogger(comptime maybe_scope: ?type) type {
return struct {
ptr: *anyopaque,
writeFn: *const fn (ptr: *anyopaque, buf: []const u8, maybe_fields: anytype) void,
pub fn init(pointer: anytype, comptime writeFn: fn (ptr: @TypeOf(pointer), buf: []const u8, maybe_fields: anytype) void) ScopedLogger(maybe_scope) {
const Ptr = @TypeOf(pointer);
assert(@typeInfo(Ptr) == .Pointer); // Must be a pointer
assert(@typeInfo(Ptr).Pointer.size == .One); // Must be a single-item pointer
assert(@typeInfo(@typeInfo(Ptr).Pointer.child) == .Struct); // Must point to a struct
const gen = struct {
fn write(ptr: *anyopaque, buf: []const u8, maybe_fields: anytype) void {
const self: Ptr = @ptrCast(@alignCast(ptr));
writeFn(self, buf, maybe_fields);
}
};
return .{
.ptr = pointer,
.writeFn = gen.write,
};
}
pub fn unscope(logger: *ScopedLogger(maybe_scope)) ScopedLogger(null) {
return .{
.ptr = logger,
.writeFn = logger.writeFn,
};
}
pub fn log(logger: ScopedLogger(maybe_scope), buf: []const u8, maybe_fields: anytype) void {
_ = &maybe_fields;
if (maybe_scope) |scope| {
logger.writeFn(logger.ptr, @typeName(scope));
logger.writeFn(logger.ptr, "-");
logger.writeFn(logger.ptr, buf);
} else {
logger.writeFn(logger.ptr, "[ - ]");
logger.writeFn(logger.ptr, buf);
}
}
};
}
pub const StandardErrLoger = struct {
pub fn init() StandardErrLoger {
return .{};
}
pub fn scopedLogger(self: *StandardErrLoger, comptime scope: type) ScopedLogger(scope) {
return ScopedLogger(scope).init(self, write);
}
pub fn logger(self: *StandardErrLoger) ScopedLogger(null) {
return Logger.init(self, write);
}
fn write(_: *StandardErrLoger, buf: []const u8, maybe_fields: anytype) void {
_ = &maybe_fields;
std.debug.print("{s}", .{buf});
}
};
// Compilation error
zig run src/main.zig
src/main.zig:159:36: error: unable to resolve comptime value
var scopped_logger = std_logger.scopedLogger(@This());
~~~~~~~~~~^~~~~~~~~~~~~
src/main.zig:159:36: note: argument to function being called at comptime must be comptime-known
src/log.zig:53:84: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type
pub fn scopedLogger(self: *StandardErrLoger, comptime scope: type) ScopedLogger(scope) {
~~~~~~~~~~~~^~~~~~~
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment