summaryrefslogtreecommitdiff
path: root/src/util.zig
diff options
context:
space:
mode:
authorChristian Segundo2023-06-15 19:54:16 +0200
committerChristian Segundo2023-06-15 19:54:16 +0200
commitdb5d7914d82d69021cf303e0ab02b46e0730bf48 (patch)
tree0b515caee3c355f02e3a1eb5df15784b4a62179f /src/util.zig
parent17f3a7b655938eb47efc2bbe884e68786bce6077 (diff)
downloadzmission-db5d7914d82d69021cf303e0ab02b46e0730bf48.tar.gz
one step closer
Diffstat (limited to 'src/util.zig')
-rw-r--r--src/util.zig119
1 files changed, 102 insertions, 17 deletions
diff --git a/src/util.zig b/src/util.zig
index 41c3584..c46dbe7 100644
--- a/src/util.zig
+++ b/src/util.zig
@@ -1,23 +1,108 @@
const std = @import("std");
-/// Returns an slice of all the fields in the given type replacing all '_' with '-'.
-pub fn enumFieldsToStringSlice(comptime E: type) []const []const u8 {
- @setEvalBranchQuota(10000);
- var names: []const []const u8 = &[_][]const u8{};
- for (std.meta.fields(E)) |field| {
- var name: [field.name.len]u8 = undefined;
- _ = std.mem.replace(u8, field.name, &[_]u8{'_'}, &[_]u8{'-'}, &name);
- names = names ++ &[_][]const u8{&name};
- }
- return names;
+const struct_util = @import("util/struct.zig");
+const enum_util = @import("util/enum.zig");
+pub const enumFieldsSlice = enum_util.enumFieldsSlice;
+
+// Builds a static map of fields in `T` using `F`.
+// to be used by our stringify
+pub fn JsonMap(
+ comptime T: type,
+ comptime F: ?fn (comptime []const u8) []const u8,
+) type {
+ return blk: {
+ switch (@typeInfo(T)) {
+ .Enum => {
+ break :blk struct {
+ const fields = enum_util.enumFieldsStringSlice(T, F);
+ pub fn get(field: T) []const u8 {
+ return fields[@enumToInt(field)];
+ }
+ };
+ },
+ .Struct => {
+ break :blk struct {
+ const map = struct_util.StructFieldsMap(
+ T,
+ struct_util.StructFieldsEnum(T, F),
+ );
+ pub fn get(field: []const u8) []const u8 {
+ return @tagName(map.get(field).?);
+ }
+ };
+ },
+ else => unreachable,
+ }
+ };
}
-pub fn enumFieldsToSlice(comptime T: type) []const T {
- var fields: []const T = &[_]T{};
- inline for (@typeInfo(T).Enum.fields) |enumField| {
- fields = fields ++ &[_]T{
- @field(T, enumField.name),
- };
+// copy of std.json.stringify to change field names
+// using JsonMap when serializing
+pub fn jsonStringify(
+ value: anytype,
+ options: std.json.StringifyOptions,
+ out_stream: anytype,
+) !void {
+ const T = @TypeOf(value);
+ switch (@typeInfo(T)) {
+ .Enum => {
+ const member_name = T.json_map.get(value);
+ try std.json.stringify(member_name, options, out_stream);
+ },
+ .Struct => |S| {
+ try out_stream.writeByte(if (S.is_tuple) '[' else '{');
+ var field_output = false;
+ var child_options = options;
+ child_options.whitespace.indent_level += 1;
+ inline for (S.fields) |Field| {
+ // don't include void fields
+ if (Field.type == void) continue;
+
+ var emit_field = true;
+
+ // don't include optional fields that are null when emit_null_optional_fields is set to false
+ if (@typeInfo(Field.type) == .Optional) {
+ if (options.emit_null_optional_fields == false) {
+ if (@field(value, Field.name) == null) {
+ emit_field = false;
+ }
+ }
+ }
+
+ if (emit_field) {
+ if (!field_output) {
+ field_output = true;
+ } else {
+ try out_stream.writeByte(',');
+ }
+ try child_options.whitespace.outputIndent(out_stream);
+ if (!S.is_tuple) {
+ try std.json.encodeJsonString(
+ T.json_map.get(Field.name),
+ options,
+ out_stream,
+ );
+ try out_stream.writeByte(':');
+ if (child_options.whitespace.separator) {
+ try out_stream.writeByte(' ');
+ }
+ }
+ try std.json.stringify(@field(value, Field.name), child_options, out_stream);
+ }
+ }
+ if (field_output) {
+ try options.whitespace.outputIndent(out_stream);
+ }
+ try out_stream.writeByte(if (S.is_tuple) ']' else '}');
+ return;
+ },
+ else => unreachable,
}
- return fields;
+}
+
+pub fn replaceUnderscores(comptime o: []const u8) []const u8 {
+ @setEvalBranchQuota(10000);
+ var name: [o.len]u8 = undefined;
+ _ = std.mem.replace(u8, o, &[_]u8{'_'}, &[_]u8{'-'}, &name);
+ return &name;
}