Pipeline em Zig
O padrão Pipeline processa dados através de uma série de estágios sequenciais, onde a saída de cada estágio alimenta a entrada do próximo. Em Zig, pipelines são elegantemente construídos com composição de funções, writers/readers encadeados e comptime para pipelines estáticos de custo zero.
Quando Usar
- Processamento de texto (ler, parsear, transformar, salvar)
- Pipelines de compilação (lexer, parser, otimizador, code gen)
- ETL (Extract, Transform, Load) de dados
- Processamento de imagem em estágios
- Middleware em servidores HTTP
Pipeline com Array de Funções
const std = @import("std");
const Estagio = *const fn ([]const u8) []const u8;
const TextPipeline = struct {
estagios: std.ArrayList(Estagio),
pub fn init(allocator: std.mem.Allocator) TextPipeline {
return .{ .estagios = std.ArrayList(Estagio).init(allocator) };
}
pub fn deinit(self: *TextPipeline) void {
self.estagios.deinit();
}
pub fn addEstagio(self: *TextPipeline, estagio: Estagio) !void {
try self.estagios.append(estagio);
}
pub fn executar(self: *const TextPipeline, entrada: []const u8) []const u8 {
var dados = entrada;
for (self.estagios.items) |estagio| {
dados = estagio(dados);
}
return dados;
}
};
fn removerEspacos(texto: []const u8) []const u8 {
return std.mem.trim(u8, texto, " \t");
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var pipeline = TextPipeline.init(gpa.allocator());
defer pipeline.deinit();
try pipeline.addEstagio(removerEspacos);
const resultado = pipeline.executar(" Olá Zig ");
std.debug.print("Resultado: '{s}'\n", .{resultado});
}
Pipeline comptime (Zero Overhead)
const std = @import("std");
fn pipeline(comptime estagios: anytype) fn (i32) i32 {
return struct {
fn executar(valor: i32) i32 {
var resultado = valor;
inline for (estagios) |estagio| {
resultado = estagio(resultado);
}
return resultado;
}
}.executar;
}
fn dobrar(x: i32) i32 { return x * 2; }
fn somar10(x: i32) i32 { return x + 10; }
fn quadrado(x: i32) i32 { return x * x; }
const processar = pipeline(.{ dobrar, somar10, quadrado });
pub fn main() void {
// (5 * 2 + 10)^2 = 400
const resultado = processar(5);
std.debug.print("Resultado: {d}\n", .{resultado}); // 400
}
Pipeline de I/O com Writers
const std = @import("std");
pub fn main() !void {
// Pipeline: stdout <- buffered <- contagem
const arquivo = try std.fs.cwd().createFile("/tmp/saida.txt", .{});
defer arquivo.close();
var buf_writer = std.io.bufferedWriter(arquivo.writer());
const writer = buf_writer.writer();
// Cada write passa por buffer antes de ir ao arquivo
try writer.print("Linha 1: {s}\n", .{"dados"});
try writer.print("Linha 2: {d}\n", .{42});
try buf_writer.flush();
}
Quando Evitar
- Processamento que não é naturalmente sequencial
- Quando os estágios têm dependências cruzadas
- Overhead de criar pipeline para uma única transformação
Veja Também
- Iterator — Processamento lazy de sequências
- Decorator — Composição de comportamentos
- Command — Encapsular operações como objetos
- Comptime — Pipelines de custo zero
- Operações I/O — Writers composíveis