Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Public Function

write

Public Function
std.json.Stringify.write
pub fn write(self: *Stringify, v: anytype) Error!void

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.

Params

File

json/Stringify.zig:348
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
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.mode == .nonexhaustive) {
                inline for (enum_info.field_names) |field_name| {
                    if (v == @field(T, field_name)) {
                        break;
                    }
                } else {
                    return self.write(@backingInt(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.field_names, info.field_types) |u_field_name, u_field_type| {
                    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.field_names, S.field_types) |field_name, field_type| {
                // 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;
}