| ... | @@ -720,3 +720,48 @@ const Space = union(enum) { | ... | @@ -720,3 +720,48 @@ const Space = union(enum) { |
| 720 | }; | 720 | }; |
| 721 | } | 721 | } |
| 722 | }; | 722 | }; |
| | 723 | |
| | 724 | pub fn stringify(writer: anytype, value: anytype, options: std.json.StringifyOptions) extras.Pointee(@TypeOf(writer)).WriteError!void { |
| | 725 | const T = @TypeOf(value); |
| | 726 | if (comptime extras.isZigString(T)) { |
| | 727 | if (extras.matchesAll(u8, value, std.ascii.isAscii)) { |
| | 728 | try writer.writevAll(&.{ &.{'"'}, value, &.{'"'} }); |
| | 729 | } else { |
| | 730 | @panic("TODO"); |
| | 731 | } |
| | 732 | return; |
| | 733 | } |
| | 734 | if (comptime extras.isArrayOf(u8)(T)) { |
| | 735 | if (extras.matchesAll(u8, &value, std.ascii.isAscii)) { |
| | 736 | try writer.writevAll(&.{ &.{'"'}, &value, &.{'"'} }); |
| | 737 | } else { |
| | 738 | @panic("TODO"); |
| | 739 | } |
| | 740 | return; |
| | 741 | } |
| | 742 | switch (@typeInfo(T)) { |
| | 743 | .@"struct" => |info| { |
| | 744 | try writer.writeAll("{"); |
| | 745 | inline for (info.fields, 0..) |field, i| blk: { |
| | 746 | const field_value = @field(value, field.name); |
| | 747 | if (@typeInfo(field.type) == .optional and field_value == null and !options.emit_null_optional_fields) break :blk; |
| | 748 | if (i > 0) try writer.writeAll(","); |
| | 749 | try stringify(writer, field.name, options); |
| | 750 | try writer.writeAll(":"); |
| | 751 | try stringify(writer, field_value, options); |
| | 752 | } |
| | 753 | try writer.writeAll("}"); |
| | 754 | }, |
| | 755 | .comptime_int => { |
| | 756 | return nio.fmt.formatInt(value, 10, .lower, .{}, writer); |
| | 757 | }, |
| | 758 | .optional => { |
| | 759 | if (value) |v| { |
| | 760 | try stringify(writer, v, options); |
| | 761 | } else { |
| | 762 | try writer.writeAll("null"); |
| | 763 | } |
| | 764 | }, |
| | 765 | else => @compileError(@typeName(T)), |
| | 766 | } |
| | 767 | } |