Cheatsheet: Pipeline em Zig

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

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.