feat(pretty_print): handle union and pointer (including slices)
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 37s
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 37s
This commit is contained in:
88
README.md
88
README.md
@@ -1,20 +1,36 @@
|
|||||||
# zlog
|
# zlog
|
||||||
|
|
||||||
Standard Library log wrapper. `zlog` provides adjusted `std.log` output and a pretty print function for easy overwriting of user defined types (`struct`, `enum`, `union` and `vector`).
|
Standard Library log wrapper. `zlog` provides adjusted `std.log` output and a pretty print function for easy overwriting of user defined types.
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Only builds using the zig master version are tested to work.
|
> Only builds using the zig master version are tested to work.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
The following snippet shows an example usage of `zlog` to change the default log format and add pretty printing to both user defined types (`Options` and `Struct`):
|
The following snippet shows an example usage of `zlog` to change the default log format and add pretty printing to the user defined types:
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
const std = @import("std");
|
const Union = union {
|
||||||
const zlog = @import("zlog");
|
int: i32,
|
||||||
|
boolean: bool,
|
||||||
|
|
||||||
// use this to overwrite the default log format of `std.log`
|
// copy and paste this function into your user defined types to enable pretty printing for these types
|
||||||
pub const std_options = zlog.std_options;
|
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
try zlog.pretty_format(value, fmt, options, writer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const TaggedUnion = union(enum) {
|
||||||
|
one: i16,
|
||||||
|
two: u32,
|
||||||
|
three: []const u8,
|
||||||
|
nothing,
|
||||||
|
|
||||||
|
// copy and paste this function into your user defined types to enable pretty printing for these types
|
||||||
|
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
try zlog.pretty_format(value, fmt, options, writer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const Options = enum {
|
const Options = enum {
|
||||||
a,
|
a,
|
||||||
@@ -32,7 +48,8 @@ const Struct = struct {
|
|||||||
b: bool = true,
|
b: bool = true,
|
||||||
c: [5]u16 = .{ 1, 2, 3, 4, 5 },
|
c: [5]u16 = .{ 1, 2, 3, 4, 5 },
|
||||||
d: []const u8 = "string",
|
d: []const u8 = "string",
|
||||||
e: Options = Options.b,
|
e: Options = .b,
|
||||||
|
f: TaggedUnion = .{ .one = -5 },
|
||||||
|
|
||||||
// same function as above...
|
// same function as above...
|
||||||
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
@@ -43,15 +60,20 @@ const Struct = struct {
|
|||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
// initialize zlog with the scope of `main`
|
// initialize zlog with the scope of `main`
|
||||||
const log = std.log.scoped(.main);
|
const log = std.log.scoped(.main);
|
||||||
// NOTE: the scope of `default` will result in no scoping being printed in
|
// NOTE the scope of `default` will result in no scoping being printed in
|
||||||
// the resulting output (default behavior of `std.log.defaultLog`)
|
// the resulting output (default behavior of `std.log.defaultLog`)
|
||||||
|
|
||||||
// some variables to log
|
// some variables to log
|
||||||
const int_var = 42;
|
const int_var = 42;
|
||||||
const array_var = [_]i32{ 1, 2, 3, 4 };
|
const array_var = [_]i32{ 1, 2, 3, 4 };
|
||||||
const string_var = "This is a test";
|
const string_var = "This is a test";
|
||||||
const option_var = Options.a;
|
const option_var: Options = .a;
|
||||||
const struct_var: Struct = .{};
|
const struct_var: Struct = .{};
|
||||||
|
const tagged_union: TaggedUnion = .{
|
||||||
|
.three = "Three",
|
||||||
|
};
|
||||||
|
const void_tagged_union: TaggedUnion = .nothing;
|
||||||
|
const uniun: Union = .{ .boolean = true };
|
||||||
|
|
||||||
// NOTE: Depending on the optimization target some of these log messages
|
// NOTE: Depending on the optimization target some of these log messages
|
||||||
// will not show, which is inline with the behavior of `std.log`.
|
// will not show, which is inline with the behavior of `std.log`.
|
||||||
@@ -59,32 +81,62 @@ pub fn main() void {
|
|||||||
log.info("Info message {any}", .{array_var});
|
log.info("Info message {any}", .{array_var});
|
||||||
log.info("Info message \"{s}\"", .{string_var});
|
log.info("Info message \"{s}\"", .{string_var});
|
||||||
log.warn("Warning message {any}", .{option_var});
|
log.warn("Warning message {any}", .{option_var});
|
||||||
|
log.warn("Warning message {any}", .{void_tagged_union});
|
||||||
|
log.warn("Warning message {any}", .{uniun});
|
||||||
log.err("Error message {any}", .{struct_var});
|
log.err("Error message {any}", .{struct_var});
|
||||||
|
log.err("Error message {any}", .{tagged_union});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const std_options = zlog.std_options;
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const zlog = @import("zlog");
|
||||||
```
|
```
|
||||||
|
|
||||||
This will result in the following output:
|
This will result in the following output:
|
||||||
|
|
||||||
```
|
```
|
||||||
[[1m2025-02-24 13:00:08[0m] [[38;5;12mdebug[0m]([2mmain[0m): Debug message 42
|
[[1m2025-07-17 19:41:43[0m] [[38;5;12mdebug[0m]([2mmain[0m): Debug message 42
|
||||||
[[1m2025-02-24 13:00:08[0m] [[38;5;10minfo[0m]([2mmain[0m): Info message { 1, 2, 3, 4 }
|
[[1m2025-07-17 19:41:43[0m] [[38;5;10minfo[0m]([2mmain[0m): Info message { 1, 2, 3, 4 }
|
||||||
[[1m2025-02-24 13:00:08[0m] [[38;5;10minfo[0m]([2mmain[0m): Info message "This is a test"
|
[[1m2025-07-17 19:41:43[0m] [[38;5;10minfo[0m]([2mmain[0m): Info message "This is a test"
|
||||||
[[1m2025-02-24 13:00:08[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.Options = enum {
|
[[1m2025-07-17 19:41:43[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.Options = enum {
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
c,
|
c,
|
||||||
} = a
|
} = .a
|
||||||
[[1m2025-02-24 13:00:08[0m] [[38;5;9merror[0m]([2mmain[0m): Error message main.Struct = struct {
|
[[1m2025-07-17 19:41:43[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.TaggedUnion = union(enum) {
|
||||||
|
one: i16,
|
||||||
|
two: u32,
|
||||||
|
three: []const u8,
|
||||||
|
nothing,
|
||||||
|
} = .{ .nothing = void }
|
||||||
|
[[1m2025-07-17 19:41:43[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.Union = union {
|
||||||
|
int: i32,
|
||||||
|
boolean: bool,
|
||||||
|
} = @7fffd1c71048
|
||||||
|
[[1m2025-07-17 19:41:43[0m] [[38;5;9merror[0m]([2mmain[0m): Error message main.Struct = struct {
|
||||||
.a = 42,
|
.a = 42,
|
||||||
.b = true,
|
.b = true,
|
||||||
.c = []u16: { 1, 2, 3, 4, 5 },
|
.c = []u16: { 1, 2, 3, 4, 5 },
|
||||||
.d = { 115, 116, 114, 105, 110, 103 },
|
.d = "string",
|
||||||
.e = main.Options = enum {
|
.e = main.Options = enum {
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
c,
|
c,
|
||||||
} = b,
|
} = .b,
|
||||||
|
.f = main.TaggedUnion = union(enum) {
|
||||||
|
one: i16,
|
||||||
|
two: u32,
|
||||||
|
three: []const u8,
|
||||||
|
nothing,
|
||||||
|
} = .{ .one = -5 },
|
||||||
}
|
}
|
||||||
|
[[1m2025-07-17 19:41:43[0m] [[38;5;9merror[0m]([2mmain[0m): Error message main.TaggedUnion = union(enum) {
|
||||||
|
one: i16,
|
||||||
|
two: u32,
|
||||||
|
three: []const u8,
|
||||||
|
nothing,
|
||||||
|
} = .{ .three = "Three" }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customization
|
## Customization
|
||||||
@@ -112,4 +164,4 @@ The following list shows some tips on how to use logging more effectively. These
|
|||||||
break :port try fmt.parseInt(u16, buf[0 .. len -| 1], 10);
|
break :port try fmt.parseInt(u16, buf[0 .. len -| 1], 10);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
- When looking through the output of the log (i.e. written to disk by `program 2> log`) the `log` file contains control code characters (*ansi*) for the colored outputs. You can still see them correctly with the following command `less -rf log`
|
- When looking through the output of the log (i.e. written to disk by `program 2> log` when using the _stderr_ build option) the `log` file contains control code characters (*ansi*) for the colored outputs. You can still see them correctly with the following command `less -R log`.
|
||||||
|
|||||||
43
src/main.zig
43
src/main.zig
@@ -1,7 +1,24 @@
|
|||||||
const std = @import("std");
|
const Union = union {
|
||||||
const zlog = @import("zlog");
|
int: i32,
|
||||||
|
boolean: bool,
|
||||||
|
|
||||||
pub const std_options = zlog.std_options;
|
// copy and paste this function into your user defined types to enable pretty printing for these types
|
||||||
|
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
try zlog.pretty_format(value, fmt, options, writer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const TaggedUnion = union(enum) {
|
||||||
|
one: i16,
|
||||||
|
two: u32,
|
||||||
|
three: []const u8,
|
||||||
|
nothing,
|
||||||
|
|
||||||
|
// copy and paste this function into your user defined types to enable pretty printing for these types
|
||||||
|
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
try zlog.pretty_format(value, fmt, options, writer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const Options = enum {
|
const Options = enum {
|
||||||
a,
|
a,
|
||||||
@@ -19,7 +36,8 @@ const Struct = struct {
|
|||||||
b: bool = true,
|
b: bool = true,
|
||||||
c: [5]u16 = .{ 1, 2, 3, 4, 5 },
|
c: [5]u16 = .{ 1, 2, 3, 4, 5 },
|
||||||
d: []const u8 = "string",
|
d: []const u8 = "string",
|
||||||
e: Options = Options.b,
|
e: Options = .b,
|
||||||
|
f: TaggedUnion = .{ .one = -5 },
|
||||||
|
|
||||||
// same function as above...
|
// same function as above...
|
||||||
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
@@ -30,15 +48,20 @@ const Struct = struct {
|
|||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
// initialize zlog with the scope of `main`
|
// initialize zlog with the scope of `main`
|
||||||
const log = std.log.scoped(.main);
|
const log = std.log.scoped(.main);
|
||||||
// NOTE: the scope of `default` will result in no scoping being printed in
|
// NOTE the scope of `default` will result in no scoping being printed in
|
||||||
// the resulting output (default behavior of `std.log.defaultLog`)
|
// the resulting output (default behavior of `std.log.defaultLog`)
|
||||||
|
|
||||||
// some variables to log
|
// some variables to log
|
||||||
const int_var = 42;
|
const int_var = 42;
|
||||||
const array_var = [_]i32{ 1, 2, 3, 4 };
|
const array_var = [_]i32{ 1, 2, 3, 4 };
|
||||||
const string_var = "This is a test";
|
const string_var = "This is a test";
|
||||||
const option_var = Options.a;
|
const option_var: Options = .a;
|
||||||
const struct_var: Struct = .{};
|
const struct_var: Struct = .{};
|
||||||
|
const tagged_union: TaggedUnion = .{
|
||||||
|
.three = "Three",
|
||||||
|
};
|
||||||
|
const void_tagged_union: TaggedUnion = .nothing;
|
||||||
|
const uniun: Union = .{ .boolean = true };
|
||||||
|
|
||||||
// NOTE: Depending on the optimization target some of these log messages
|
// NOTE: Depending on the optimization target some of these log messages
|
||||||
// will not show, which is inline with the behavior of `std.log`.
|
// will not show, which is inline with the behavior of `std.log`.
|
||||||
@@ -46,5 +69,13 @@ pub fn main() void {
|
|||||||
log.info("Info message {any}", .{array_var});
|
log.info("Info message {any}", .{array_var});
|
||||||
log.info("Info message \"{s}\"", .{string_var});
|
log.info("Info message \"{s}\"", .{string_var});
|
||||||
log.warn("Warning message {any}", .{option_var});
|
log.warn("Warning message {any}", .{option_var});
|
||||||
|
log.warn("Warning message {any}", .{void_tagged_union});
|
||||||
|
log.warn("Warning message {any}", .{uniun});
|
||||||
log.err("Error message {any}", .{struct_var});
|
log.err("Error message {any}", .{struct_var});
|
||||||
|
log.err("Error message {any}", .{tagged_union});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const std_options = zlog.std_options;
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const zlog = @import("zlog");
|
||||||
|
|||||||
153
src/zlog.zig
153
src/zlog.zig
@@ -1,23 +1,14 @@
|
|||||||
const build_options = @import("build_options");
|
/// *zlog* defaultLog function replacement, which adjusts the surrounding contents of every `std.log` message.
|
||||||
const std = @import("std");
|
|
||||||
const ztime = if (build_options.timestamp) @import("ztime") else null;
|
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
|
||||||
.logFn = logFn,
|
|
||||||
};
|
|
||||||
|
|
||||||
// zlog defaultLog function replacement, which adjusts the surrounding contents of every std.log message.
|
|
||||||
fn logFn(
|
fn logFn(
|
||||||
comptime message_level: std.log.Level,
|
comptime message_level: log.Level,
|
||||||
comptime scope: @Type(.enum_literal),
|
comptime scope: @Type(.enum_literal),
|
||||||
comptime format: []const u8,
|
comptime format: []const u8,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) void {
|
) void {
|
||||||
// TODO: provide build time configuration to allow tweaking corresponding output
|
// TODO provide build time configuration to allow tweaking corresponding output
|
||||||
// - change output file for writing messages to (default `stderr`)
|
// - change output file for writing messages to (default `stderr`)
|
||||||
// write into own file for each level?
|
// - write into own file for each level?
|
||||||
|
|
||||||
// TODO: make the level text colored according to the level!
|
|
||||||
const prefix = if (scope == .default) ": " else "(\x1b[2m" ++ @tagName(scope) ++ "\x1b[0m): ";
|
const prefix = if (scope == .default) ": " else "(\x1b[2m" ++ @tagName(scope) ++ "\x1b[0m): ";
|
||||||
const level_txt = switch (comptime message_level) {
|
const level_txt = switch (comptime message_level) {
|
||||||
.err => "[\x1b[38;5;9merror\x1b[0m]",
|
.err => "[\x1b[38;5;9merror\x1b[0m]",
|
||||||
@@ -25,10 +16,10 @@ fn logFn(
|
|||||||
.info => "[\x1b[38;5;10minfo\x1b[0m]",
|
.info => "[\x1b[38;5;10minfo\x1b[0m]",
|
||||||
.debug => "[\x1b[38;5;12mdebug\x1b[0m]",
|
.debug => "[\x1b[38;5;12mdebug\x1b[0m]",
|
||||||
};
|
};
|
||||||
const fmt = level_txt ++ prefix ++ format ++ "\n";
|
const complete_format = level_txt ++ prefix ++ format ++ "\n";
|
||||||
if (comptime build_options.file.len != 0) {
|
if (comptime build_options.file.len != 0) {
|
||||||
// TODO: handle errors accordingly (i.e. panic?)
|
// TODO handle errors accordingly (i.e. panic?)
|
||||||
// NOTE: with zig 0.13.0 there is currently no way to open files to append (except to use libc or talk directly to posix, which this lib should not have to do)
|
// NOTE with zig 0.13.0 there is currently no way to open files to append (except to use libc or talk directly to posix, which this lib should not have to do)
|
||||||
const file = std.fs.openFileAbsolute(build_options.file, .{
|
const file = std.fs.openFileAbsolute(build_options.file, .{
|
||||||
.mode = .read_write,
|
.mode = .read_write,
|
||||||
}) catch std.fs.createFileAbsolute(build_options.file, .{
|
}) catch std.fs.createFileAbsolute(build_options.file, .{
|
||||||
@@ -36,7 +27,7 @@ fn logFn(
|
|||||||
}) catch @panic("Failed to open and/or create configured log file");
|
}) catch @panic("Failed to open and/or create configured log file");
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
var buffer = std.io.bufferedWriter(file.writer());
|
var buffer = io.bufferedWriter(file.writer());
|
||||||
defer buffer.flush() catch {};
|
defer buffer.flush() catch {};
|
||||||
|
|
||||||
const writer = buffer.writer();
|
const writer = buffer.writer();
|
||||||
@@ -44,21 +35,21 @@ fn logFn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (comptime build_options.stderr) {
|
if (comptime build_options.stderr) {
|
||||||
var buffer = std.io.bufferedWriter(std.io.getStdErr().writer());
|
var buffer = io.bufferedWriter(io.getStdErr().writer());
|
||||||
defer buffer.flush() catch {};
|
defer buffer.flush() catch {};
|
||||||
|
|
||||||
std.debug.lockStdErr();
|
std.debug.lockStdErr();
|
||||||
defer std.debug.unlockStdErr();
|
defer std.debug.unlockStdErr();
|
||||||
|
|
||||||
const writer = buffer.writer();
|
const writer = buffer.writer();
|
||||||
log_writing(writer, fmt, args);
|
log_writing(writer, complete_format, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn log_writing(writer: anytype, comptime fmt: []const u8, args: anytype) void {
|
inline fn log_writing(writer: anytype, comptime format: []const u8, args: anytype) void {
|
||||||
nosuspend {
|
nosuspend {
|
||||||
if (build_options.timestamp) log_timestamp(writer);
|
if (build_options.timestamp) log_timestamp(writer);
|
||||||
writer.print(fmt, args) catch return;
|
writer.print(format, args) catch return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,14 +57,14 @@ inline fn log_timestamp(writer: anytype) void {
|
|||||||
writer.print("[\x1b[1m{any}\x1b[0m] ", .{ztime.DateTime.now()}) catch return;
|
writer.print("[\x1b[1m{any}\x1b[0m] ", .{ztime.DateTime.now()}) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pretty_format(object: anytype, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn pretty_format(object: anytype, comptime format: []const u8, options: fmt.FormatOptions, writer: anytype) !void {
|
||||||
try inner_format(object, fmt, options, writer, 0);
|
try inner_format(object, format, options, writer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_format(object: anytype, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, comptime depth: u8) !void {
|
fn inner_format(object: anytype, comptime format: []const u8, options: fmt.FormatOptions, writer: anytype, comptime depth: u8) !void {
|
||||||
// TODO: here `std.meta` might be useful
|
|
||||||
const Object = @TypeOf(object);
|
const Object = @TypeOf(object);
|
||||||
const object_info = @typeInfo(Object);
|
const object_info = @typeInfo(Object);
|
||||||
|
|
||||||
switch (object_info) {
|
switch (object_info) {
|
||||||
.@"struct" => |s| {
|
.@"struct" => |s| {
|
||||||
try writer.writeAll(@typeName(Object));
|
try writer.writeAll(@typeName(Object));
|
||||||
@@ -84,8 +75,8 @@ fn inner_format(object: anytype, comptime fmt: []const u8, options: std.fmt.Form
|
|||||||
try writer.writeAll(field.name);
|
try writer.writeAll(field.name);
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
// TODO check corresponding type and try to adapt fmt accordingly!
|
// TODO check corresponding type and try to adapt fmt accordingly!
|
||||||
// TODO: pass along the already parsed formatting options too
|
// TODO pass along the already parsed formatting options too
|
||||||
try inner_format(@field(object, field.name), fmt, options, writer, depth + 1);
|
try inner_format(@field(object, field.name), format, options, writer, depth + 1);
|
||||||
try writer.writeAll(",\n");
|
try writer.writeAll(",\n");
|
||||||
}
|
}
|
||||||
try writer.writeAll("\t" ** depth);
|
try writer.writeAll("\t" ** depth);
|
||||||
@@ -100,27 +91,109 @@ fn inner_format(object: anytype, comptime fmt: []const u8, options: std.fmt.Form
|
|||||||
try writer.writeAll(",\n");
|
try writer.writeAll(",\n");
|
||||||
}
|
}
|
||||||
try writer.writeAll("\t" ** depth);
|
try writer.writeAll("\t" ** depth);
|
||||||
try writer.writeAll("} = ");
|
try writer.writeAll("} = .");
|
||||||
try writer.writeAll(@tagName(object));
|
try writer.writeAll(@tagName(object));
|
||||||
},
|
},
|
||||||
// TODO: implement prett_printing for other user defined types (`union` and `vector`)
|
.@"union" => |u| {
|
||||||
// TODO: recognize []const u8 types and print them as strings
|
try writer.writeAll(@typeName(Object));
|
||||||
.array => |a| {
|
try writer.writeAll(" = union");
|
||||||
if (a.child == @TypeOf([:0]const u8)) {
|
if (u.tag_type) |Tag| {
|
||||||
try std.fmt.format(writer, "\"{s}\"", .{object});
|
_ = Tag;
|
||||||
|
try writer.writeAll("(enum)");
|
||||||
|
}
|
||||||
|
try writer.writeAll(" {\n");
|
||||||
|
inline for (u.fields) |field| {
|
||||||
|
try writer.writeAll("\t" ** (depth + 1));
|
||||||
|
try writer.writeAll(field.name);
|
||||||
|
if (@typeInfo(field.type) != .void) {
|
||||||
|
try writer.writeAll(": ");
|
||||||
|
try writer.writeAll(@typeName(field.type));
|
||||||
|
}
|
||||||
|
try writer.writeAll(",\n");
|
||||||
|
}
|
||||||
|
try writer.writeAll("\t" ** depth);
|
||||||
|
try writer.writeAll("} = ");
|
||||||
|
if (u.tag_type) |Tag| {
|
||||||
|
try writer.writeAll(".{ .");
|
||||||
|
try writer.writeAll(@tagName(object));
|
||||||
|
try writer.writeAll(" = ");
|
||||||
|
inline for (u.fields) |u_field| if (object == @field(Tag, u_field.name)) {
|
||||||
|
try inner_format(@field(object, u_field.name), format, options, writer, depth + 1);
|
||||||
|
};
|
||||||
|
try writer.writeAll(" }");
|
||||||
} else {
|
} else {
|
||||||
try std.fmt.format(writer, "[]{s}: {any}", .{ @typeName(a.child), object });
|
// NOTE the value of a union (untagged) is displayed like this also in the standard library,
|
||||||
|
// not sure if you can reflect the used variant (and its value)
|
||||||
|
try fmt.format(writer, "@{x}", .{@intFromPtr(&object)});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.vector => |v| {
|
.pointer => |p| switch (p.size) {
|
||||||
if (v.child == @TypeOf([:0]const u8)) {
|
.slice => switch (@typeInfo(p.child)) {
|
||||||
try std.fmt.format(writer, "\"{s}\"", .{object});
|
.int => |num| {
|
||||||
|
if (num.signedness != .unsigned) {
|
||||||
|
try fmt.format(writer, "[]{s}: {any}", .{ @typeName(p.child), object });
|
||||||
} else {
|
} else {
|
||||||
try std.fmt.format(writer, "[]{s}: {any}", .{ @typeName(v.child), object });
|
switch (num.bits) {
|
||||||
|
8 => try fmt.format(writer, "\"{s}\"", .{object}),
|
||||||
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(p.child), object }),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(p.child), object }),
|
||||||
try std.fmt.format(writer, "{any}", .{object});
|
|
||||||
},
|
},
|
||||||
|
.c => switch (@typeInfo(p.child)) {
|
||||||
|
.int => |num| {
|
||||||
|
if (num.signedness != .unsigned) {
|
||||||
|
try fmt.format(writer, "[*c]{s}: {any}", .{ @typeName(p.child), object });
|
||||||
|
} else {
|
||||||
|
switch (num.bits) {
|
||||||
|
8 => try fmt.format(writer, "\"{s}\"", .{object}),
|
||||||
|
else => try fmt.format(writer, "[*c]{s}: {any}", .{ @typeName(p.child), object }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(p.child), object }),
|
||||||
|
},
|
||||||
|
.many => try fmt.format(writer, "[*]{s}: {any}", .{ @typeName(p.child), object }),
|
||||||
|
.one => try fmt.format(writer, "[1]{s}: {any}", .{ @typeName(p.child), object }),
|
||||||
|
},
|
||||||
|
.array => |a| switch (@typeInfo(a.child)) {
|
||||||
|
.int => |num| {
|
||||||
|
if (num.signedness != .unsigned) {
|
||||||
|
try fmt.format(writer, "[]{s}: {any}", .{ @typeName(a.child), object });
|
||||||
|
} else {
|
||||||
|
switch (num.bits) {
|
||||||
|
8 => try fmt.format(writer, "\"{s}\"", .{object}),
|
||||||
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(a.child), object }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(a.child), object }),
|
||||||
|
},
|
||||||
|
.vector => |v| switch (@typeInfo(v.child)) {
|
||||||
|
.int => |num| {
|
||||||
|
if (num.signedness != .unsigned) {
|
||||||
|
try fmt.format(writer, "[]{s}: {any}", .{ @typeName(v.child), object });
|
||||||
|
} else {
|
||||||
|
switch (num.bits) {
|
||||||
|
8 => try fmt.format(writer, "\"{s}\"", .{object}),
|
||||||
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(v.child), object }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => try fmt.format(writer, "[]{s}: {any}", .{ @typeName(v.child), object }),
|
||||||
|
},
|
||||||
|
else => try fmt.format(writer, "{any}", .{object}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const std_options: std.Options = .{
|
||||||
|
.logFn = logFn,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const io = std.io;
|
||||||
|
const log = std.log;
|
||||||
|
const fmt = std.fmt;
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
const ztime = if (build_options.timestamp) @import("ztime") else null;
|
||||||
|
|||||||
Reference in New Issue
Block a user