const std = @import("std"); 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, } }; } // 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, } } 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; }