Function write [src]

Renders the given Zig value as JSON. Supported types: Zig bool -> JSON true or false. Zig ?T -> null or the rendering of T. Zig i32, u64, etc. -> JSON number or string. When option emit_nonportable_numbers_as_strings is true, if the value is outside the range +-1<<53 (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number. Zig floats -> JSON number or string. If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number. TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00". Zig []const u8, []u8, *[N]u8, @Vector(N, u8), and similar -> JSON string. See Options.emit_strings_as_arrays. If the content is not valid UTF-8, rendered as an array of numbers instead. Zig []T, [N]T, *[N]T, @Vector(N, T), and similar -> JSON array of the rendering of each item. Zig tuple -> JSON array of the rendering of each item. Zig struct -> JSON object with each field in declaration order. If the struct declares a method pub fn jsonStringify(self: *@This(), jw: anytype) !void, it is called to do the serialization instead of the default behavior. The given jw is a pointer to this Stringify. See std.json.Value for an example. See Options.emit_null_optional_fields. Zig union(enum) -> JSON object with one field named for the active tag and a value representing the payload. If the payload is void, then the emitted value is {}. If the union declares a method pub fn jsonStringify(self: *@This(), jw: anytype) !void, it is called to do the serialization instead of the default behavior. The given jw is a pointer to this Stringify. Zig enum -> JSON string naming the active tag. If the enum declares a method pub fn jsonStringify(self: *@This(), jw: anytype) !void, it is called to do the serialization instead of the default behavior. The given jw is a pointer to this Stringify. If the enum is non-exhaustive, unnamed values are rendered as integers. Zig untyped enum literal -> JSON string naming the active tag. Zig error -> JSON string naming the error. Zig *T -> the rendering of T. Note there is no guard against circular-reference infinite recursion. See also alternative functions print and beginWriteRaw. For writing object field names, use objectField instead.

Prototype

pub fn write(self: *Stringify, v: anytype) Error!void

Parameters

self: *Stringify

Possible Errors

WriteFailed Error

See the Writer implementation for detailed diagnostics.

Source

pub fn write(self: *Stringify, v: anytype) Error!void { if (build_mode_has_safety) assert(self.raw_streaming_mode == .none); const T = @TypeOf(v); switch (@typeInfo(T)) { .int => { try self.valueStart(); if (self.options.emit_nonportable_numbers_as_strings and (v <= -(1 << 53) or v >= (1 << 53))) { try self.writer.print("\"{}\"", .{v}); } else { try self.writer.print("{}", .{v}); } self.valueDone(); return; }, .comptime_int => { return self.write(@as(std.math.IntFittingRange(v, v), v)); }, .float, .comptime_float => { if (@as(f64, @floatCast(v)) == v) { try self.valueStart(); try self.writer.print("{}", .{@as(f64, @floatCast(v))}); self.valueDone(); return; } try self.valueStart(); try self.writer.print("\"{}\"", .{v}); self.valueDone(); return; }, .bool => { try self.valueStart(); try self.writer.writeAll(if (v) "true" else "false"); self.valueDone(); return; }, .null => { try self.valueStart(); try self.writer.writeAll("null"); self.valueDone(); return; }, .optional => { if (v) |payload| { return try self.write(payload); } else { return try self.write(null); } }, .@"enum" => |enum_info| { if (std.meta.hasFn(T, "jsonStringify")) { return v.jsonStringify(self); } if (!enum_info.is_exhaustive) { inline for (enum_info.fields) |field| { if (v == @field(T, field.name)) { break; } } else { return self.write(@intFromEnum(v)); } } return self.stringValue(@tagName(v)); }, .enum_literal => { return self.stringValue(@tagName(v)); }, .@"union" => { if (std.meta.hasFn(T, "jsonStringify")) { return v.jsonStringify(self); } const info = @typeInfo(T).@"union"; if (info.tag_type) |UnionTagType| { try self.beginObject(); inline for (info.fields) |u_field| { if (v == @field(UnionTagType, u_field.name)) { try self.objectField(u_field.name); if (u_field.type == void) { // void v is {} try self.beginObject(); try self.endObject(); } else { try self.write(@field(v, u_field.name)); } break; } } else { unreachable; // No active tag? } try self.endObject(); return; } else { @compileError("Unable to stringify untagged union '" ++ @typeName(T) ++ "'"); } }, .@"struct" => |S| { if (std.meta.hasFn(T, "jsonStringify")) { return v.jsonStringify(self); } if (S.is_tuple) { try self.beginArray(); } else { try self.beginObject(); } 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 (self.options.emit_null_optional_fields == false) { if (@field(v, Field.name) == null) { emit_field = false; } } } if (emit_field) { if (!S.is_tuple) { try self.objectField(Field.name); } try self.write(@field(v, Field.name)); } } if (S.is_tuple) { try self.endArray(); } else { try self.endObject(); } return; }, .error_set => return self.stringValue(@errorName(v)), .pointer => |ptr_info| switch (ptr_info.size) { .one => switch (@typeInfo(ptr_info.child)) { .array => { // Coerce `*[N]T` to `[]const T`. const Slice = []const std.meta.Elem(ptr_info.child); return self.write(@as(Slice, v)); }, else => { return self.write(v.*); }, }, .many, .slice => { if (ptr_info.size == .many and ptr_info.sentinel() == null) @compileError("unable to stringify type '" ++ @typeName(T) ++ "' without sentinel"); const slice = if (ptr_info.size == .many) std.mem.span(v) else v; if (ptr_info.child == u8) { // This is a []const u8, or some similar Zig string. if (!self.options.emit_strings_as_arrays and std.unicode.utf8ValidateSlice(slice)) { return self.stringValue(slice); } } try self.beginArray(); for (slice) |x| { try self.write(x); } try self.endArray(); return; }, else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), }, .array => { // Coerce `[N]T` to `*const [N]T` (and then to `[]const T`). return self.write(&v); }, .vector => |info| { const array: [info.len]info.child = v; return self.write(&array); }, else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), } unreachable; }