From 9b673b0ff39c3cd2553d4728ff576b788d484379 Mon Sep 17 00:00:00 2001 From: Simon Hartcher Date: Thu, 29 May 2025 16:01:12 +1000 Subject: [PATCH] fix: map to json --- codegen/src/main.zig | 57 +++++++++++++++++++++++++++++++------------ lib/json/src/json.zig | 5 ++-- src/aws.zig | 2 +- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/codegen/src/main.zig b/codegen/src/main.zig index c56cfbf..f5e15af 100644 --- a/codegen/src/main.zig +++ b/codegen/src/main.zig @@ -844,10 +844,10 @@ fn shapeIsLeaf(shape: Shape) bool { }; } -fn shapeIsOptional(member: smithy.TypeMember) bool { +fn shapeIsOptional(traits: []smithy.Trait) bool { var optional = true; - for (member.traits) |t| { + for (traits) |t| { if (t == .required) { optional = false; break; @@ -880,14 +880,14 @@ fn getMemberValueBlock(allocator: std.mem.Allocator, source: []const u8, member: if (shapeIsLeaf(member.shape_info.shape)) { const json_value_type = getShapeJsonValueType(member.shape_info.shape); - if (shapeIsOptional(member.type_member)) { + if (shapeIsOptional(member.type_member.traits)) { try writer.print("if ({s}) |{s}|", .{ member_value, member_value_name }); - try writer.writeAll(".{"); + try writer.writeAll("std.json.Value{"); try writer.writeAll(json_value_type); try writer.print(" = {s}", .{member_value_name}); try writer.writeAll("} else .{ .null = undefined }"); } else { - try writer.writeAll(".{"); + try writer.writeAll("std.json.Value{"); try writer.writeAll(json_value_type); try writer.print(" = {s}", .{member_value}); try writer.writeAll("}"); @@ -980,10 +980,34 @@ fn memberToJson(shape_id: []const u8, name: []const u8, value: []const u8, state try writer.writeAll("},\n"); }, .set => std.debug.panic("Set not implemented", .{}), - .map => { + .map => |m| { const map_name = try std.fmt.allocPrint(state.allocator, "{s}_object_map_{d}", .{ name, state.indent_level }); defer state.allocator.free(map_name); + const map_value_capture = try std.fmt.allocPrint(allocator, "{s}_kvp", .{map_name}); + defer allocator.free(map_value_capture); + + const map_value_capture_key = try std.fmt.allocPrint(allocator, "{s}.key", .{map_value_capture}); + defer allocator.free(map_value_capture_key); + + const value_name = try std.fmt.allocPrint(allocator, "{s}_value", .{map_value_capture}); + defer allocator.free(value_name); + + const map_value_block = try getMemberValueBlock(allocator, map_value_capture, .{ + .field_name = "value", + .json_key = undefined, + .shape_info = try shapeInfoForId(m.value, state), + .target = m.value, + .type_member = .{ + .name = undefined, + .target = undefined, + .traits = @constCast(&[_]smithy.Trait{ + smithy.Trait{ .required = .{} }, + }), + }, + }); + defer allocator.free(map_value_block); + const blk_name = try std.fmt.allocPrint(state.allocator, "{s}_blk", .{map_name}); defer state.allocator.free(blk_name); @@ -992,12 +1016,20 @@ fn memberToJson(shape_id: []const u8, name: []const u8, value: []const u8, state { try writer.print("var {s} = std.json.ObjectMap.init(allocator);\n", .{map_name}); - try writer.print("for ({s}) |kvp|", .{value}); + try writer.print("for ({s}) |{s}|", .{ value, map_value_capture }); try writer.writeAll("{\n"); - try writer.print("try {s}.put(kvp.key, kvp.value);\n", .{map_name}); + try writer.print("const {s} = {s};\n", .{ value_name, map_value_block }); + try writer.print("try {s}.put(\n", .{map_name}); + try memberToJson(m.key, "key", map_value_capture_key, state.indent(), writer); + try writer.writeAll(", "); + try memberToJson(m.value, "value", value_name, state.indent(), writer); + try writer.writeAll(");\n"); try writer.writeAll("}\n"); - try writer.print("break :{s} {s};", .{ blk_name, map_name }); + try writer.print("break :{s}", .{blk_name}); + try writer.writeAll(".{ .object = "); + try writer.writeAll(map_name); + try writer.writeAll("};\n"); } try writer.writeAll("},\n"); }, @@ -1270,19 +1302,12 @@ fn generateMapTypeFor(map: anytype, writer: anytype, state: GenerationState, com child_state.indent_level += 1; _ = try writer.write("key: "); - try writeOptional(map.traits, writer, null); - _ = try generateTypeFor(map.key, writer, child_state, options.endStructure(true)); - - try writeOptional(map.traits, writer, " = null"); _ = try writer.write(",\n"); _ = try writer.write("value: "); - try writeOptional(map.traits, writer, null); - _ = try generateTypeFor(map.value, writer, child_state, options.endStructure(true)); - try writeOptional(map.traits, writer, " = null"); _ = try writer.write(",\n"); _ = try writer.write("}"); } diff --git a/lib/json/src/json.zig b/lib/json/src/json.zig index e425615..8044f6b 100644 --- a/lib/json/src/json.zig +++ b/lib/json/src/json.zig @@ -55,12 +55,11 @@ pub fn serializeMapAsObject(map: anytype, options: anytype, out_stream: anytype) try out_stream.writeByte('\n'); for (map, 0..) |tag, i| { - if (tag.key == null or tag.value == null) continue; // TODO: Deal with escaping and general "json.stringify" the values... if (child_options.whitespace) |ws| try ws.outputIndent(out_stream); try out_stream.writeByte('"'); - try jsonEscape(tag.key.?, child_options, out_stream); + try jsonEscape(tag.key, child_options, out_stream); _ = try out_stream.write("\":"); if (child_options.whitespace) |ws| { if (ws.separator) { @@ -68,7 +67,7 @@ pub fn serializeMapAsObject(map: anytype, options: anytype, out_stream: anytype) } } try out_stream.writeByte('"'); - try jsonEscape(tag.value.?, child_options, out_stream); + try jsonEscape(tag.value, child_options, out_stream); try out_stream.writeByte('"'); if (i < map.len - 1) { try out_stream.writeByte(','); diff --git a/src/aws.zig b/src/aws.zig index 5ad8112..07d6143 100644 --- a/src/aws.zig +++ b/src/aws.zig @@ -2643,5 +2643,5 @@ test "toJson: map" { const request_json = try std.json.stringifyAlloc(std.testing.allocator, request_json_value, .{}); defer std.testing.allocator.free(request_json); - try testing.expectEqualStrings("{\"arn\":\"1234\"}", request_json); + try testing.expectEqualStrings("{\"arn\":\"1234\",\"tags\":{\"foo\":\"bar\"}}", request_json); }