std.json Stringify — Serialização para JSON
A serialização JSON do Zig converte valores Zig (structs, arrays, slices, optionals, enums) em strings JSON válidas. O sistema usa os metadados de tipo do Zig em tempo de compilação para gerar código de serialização otimizado, sem reflexão em runtime. É possível controlar a formatação (compacta ou indentada), o tratamento de campos nulos e a emissão de campos opcionais.
Visão Geral
const std = @import("std");
const json = std.json;
Funções Principais
// Serializa para um Writer
pub fn stringify(
value: anytype,
options: StringifyOptions,
writer: anytype,
) !void
// Serializa para uma string alocada
pub fn stringifyAlloc(
allocator: Allocator,
value: anytype,
options: StringifyOptions,
) ![]u8
StringifyOptions
pub const StringifyOptions = struct {
// Controle de whitespace
whitespace: Whitespace = .minified,
// Emite campos opcionais como "null" ou omite
emit_null_optional_fields: bool = true,
pub const Whitespace = union(enum) {
minified,
indent_1,
indent_2,
indent_3,
indent_4,
indent_8,
indent_tab,
};
};
Mapeamento de Tipos
| Tipo Zig | JSON |
|---|---|
bool | true / false |
| inteiros | number |
| floats | number |
[]const u8 | string |
?T (null) | null |
?T (valor) | valor serializado |
| struct | object |
| array / slice | array |
| enum | string (nome do tag) |
Exemplo 1: Serialização de Struct Aninhada
const std = @import("std");
const Pedido = struct {
id: u64,
cliente: Cliente,
itens: []const Item,
total: f64,
status: Status,
observacao: ?[]const u8 = null,
const Cliente = struct {
nome: []const u8,
email: []const u8,
};
const Item = struct {
produto: []const u8,
quantidade: u32,
preco_unitario: f64,
};
const Status = enum {
pendente,
processando,
enviado,
entregue,
};
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const itens = [_]Pedido.Item{
.{ .produto = "Notebook", .quantidade = 1, .preco_unitario = 4500.00 },
.{ .produto = "Mouse", .quantidade = 2, .preco_unitario = 79.90 },
};
const pedido = Pedido{
.id = 12345,
.cliente = .{
.nome = "João da Silva",
.email = "joao@exemplo.com",
},
.itens = &itens,
.total = 4659.80,
.status = .processando,
.observacao = "Entregar no período da manhã",
};
const json_str = try std.json.stringifyAlloc(allocator, pedido, .{
.whitespace = .indent_2,
});
defer allocator.free(json_str);
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{json_str});
}
Exemplo 2: Serialização Direta para Writer
const std = @import("std");
const LogEntry = struct {
timestamp: u64,
nivel: []const u8,
mensagem: []const u8,
contexto: ?Contexto = null,
const Contexto = struct {
modulo: []const u8,
linha: u32,
};
};
fn emitirLog(writer: anytype, entry: LogEntry) !void {
try std.json.stringify(entry, .{
.emit_null_optional_fields = false,
}, writer);
try writer.writeByte('\n');
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Serializa diretamente no stdout (sem alocação)
try emitirLog(stdout, .{
.timestamp = 1708560000,
.nivel = "INFO",
.mensagem = "Servidor iniciado na porta 8080",
.contexto = null,
});
try emitirLog(stdout, .{
.timestamp = 1708560001,
.nivel = "ERROR",
.mensagem = "Falha na conexão com o banco",
.contexto = .{ .modulo = "database", .linha = 142 },
});
try emitirLog(stdout, .{
.timestamp = 1708560005,
.nivel = "WARN",
.mensagem = "Memória acima de 80%",
.contexto = .{ .modulo = "monitor", .linha = 57 },
});
}
Exemplo 3: Construindo JSON Dinamicamente
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Serialização de diferentes tipos
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const writer = buf.writer();
// Array de tipos mistos via struct
const dados = .{
.numeros = [_]i32{ 1, 2, 3, 4, 5 },
.nomes = [_][]const u8{ "Ana", "Bruno", "Carla" },
.config = .{
.ativo = true,
.limite = @as(u32, 100),
.descricao = @as(?[]const u8, null),
},
};
try std.json.stringify(dados, .{ .whitespace = .indent_2 }, writer);
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{buf.items});
// Serialização compacta (minified)
buf.clearRetainingCapacity();
try std.json.stringify(dados, .{}, writer);
try stdout.print("\nCompacto: {s}\n", .{buf.items});
}
Padrões Comuns
Omitir Campos Nulos
const opts = std.json.StringifyOptions{
.emit_null_optional_fields = false,
};
// Campos ?T com valor null não aparecerão no JSON
JSON para Respostas HTTP
fn handleRequest(writer: anytype) !void {
const resposta = .{
.status = @as(u16, 200),
.body = .{ .mensagem = "OK" },
};
try std.json.stringify(resposta, .{}, writer);
}
Serialização de Enums
Enums são serializadas como strings com o nome do tag:
const Status = enum { ativo, inativo, pendente };
// .ativo serializa como "ativo"
Módulos Relacionados
- std.json — Visão geral do módulo JSON
- std.json Parsing — Desserialização JSON
- std.fmt — Formatação de strings
- std.io.Writer — Interface Writer