Internos
Funções e estruturas não exportadas, documentadas para quem quiser estender o pacote (ou entender o pipeline). Nada aqui é API estável.
Pipeline de leitura
MicroSUS.canal_registros — Function
canal_registros(caminho, cab; lote = 4096) -> Channel{Vector{Vector{UInt8}}}Produz lotes de registros brutos (cada um com tamanho_registro bytes, já sem registros deletados), lendo .dbc (descompressão em task separada) ou .dbf (leitura direta). A montagem lida com registros que atravessam a fronteira dos chunks de 4 KiB da janela DCL.
MicroSUS.abre_dbc — Function
abre_dbc(caminho) -> (io, CabecalhoDBF)Abre um .dbc, lê o cabeçalho DBF em claro e posiciona io no início do fluxo comprimido (cabeçalho + 4 bytes de CRC).
MicroSUS.le_cabecalho_dbf — Function
le_cabecalho_dbf(bytes::Vector{UInt8}) -> CabecalhoDBFInterpreta os primeiros bytes de um DBF (ou o cabeçalho em claro de um .dbc): contagem de registros, tamanhos, language driver e descritores de campo (32 bytes cada, terminados por 0x0D).
MicroSUS.RegistroDBF — Type
RegistroDBFVisão leve sobre os bytes de um registro. r[:CAMPO] devolve o texto do campo (trim + transcodificação), parseando só o que for pedido — é o objeto passado ao filtro de ler.
O fluxo completo: MicroSUS.abre_dbc lê o cabeçalho em claro e posiciona o IO no fluxo DCL; dcl_descomprime emite chunks de ≤ 4 KiB; MicroSUS.canal_registros monta registros de largura fixa atravessando fronteiras de chunk e emite lotes de registros brutos por um Channel; MicroSUS._canal_lotes (em src/tables.jl) aplica filtro e parse e emite NamedTuples prontos.
Helpers de padronização
Usados por process_sim, process_sinasc e process_sih; são o que você reaproveita ao escrever a rotina de uma fonte ainda não coberta.
MicroSUS.processar_fonte — Function
processar_fonte(id::Symbol, df::DataFrame; verbose = true) -> DataFrameDespacha para a rotina de padronização da fonte, se existir. Fontes sem rotina implementada devolvem o DataFrame inalterado (com um aviso).
MicroSUS.rotular! — Function
rotular!(df, col, labels) -> dfSubstitui os códigos da coluna col pelos rótulos do dicionário labels. Códigos ausentes do dicionário (ex.: "9" = ignorado) viram missing. Não faz nada se a coluna não existir no DataFrame — o layout dos arquivos do DATASUS varia entre anos.
MicroSUS.para_data! — Function
para_data!(df, col; formato = dateformat"ddmmyyyy") -> dfConverte uma coluna de datas em texto ("01072026") para Date. Valores inválidos, vazios ou zerados viram missing. Colunas que o leitor já tipou como Date (schemas :data_ddmmyyyy/:data_yyyymmdd) passam intactas.
MicroSUS.para_int! — Function
para_int!(df, col) / para_float!(df, col) -> dfConverte colunas numéricas armazenadas como texto. Valores já numéricos passam intactos; texto inválido vira missing.
rotular! converte código não mapeado em missing. É deliberado — "9", "99" e afins significam "ignorado" —, mas implica que um dicionário incompleto apaga dados válidos em silêncio. Ao escrever um dicionário novo, cubra o domínio inteiro ou deixe a coluna crua.
Encoding
MicroSUS.decodifica_texto — Function
decodifica_texto(bytes, lo, hi, encoding::Symbol) -> StringConverte bytes[lo:hi] para String UTF-8, removendo espaços à direita. encoding ∈ (:cp850, :latin1, :cp1252, :utf8, :raw). Fast path: se todos os bytes forem ASCII (caso da imensa maioria dos campos do DATASUS), não há tabela envolvida.
MicroSUS.encoding_do_ldid — Function
encoding_do_ldid(ldid::UInt8) -> SymbolEncoding a partir do language driver ID (byte 29 do cabeçalho DBF). 0x00 (não especificado) cai em :cp850, que é a prática do DATASUS.
As tabelas MicroSUS._CP850_ALTA (128 caracteres da metade alta do CP850) e MicroSUS._CP1252_80_9F vivem em src/encoding.jl. O fast path ASCII evita qualquer lookup quando o campo não tem byte ≥ 0x80.
O descompressor DCL
O porte do blast.c está em src/dcl.jl, isolado do resto — pode ser usado para qualquer fluxo PKWare DCL, não só DATASUS:
MicroSUS._Huffman/MicroSUS._constroi: tabelas canônicas a partir da representação compacta do formato (byte = repetições − 1 no nibble alto, comprimento no baixo);MicroSUS._decodifica: decodificação bit a bit com os códigos invertidos (peculiaridade do PKWare);MicroSUS._bits: buffer de bits LSB-first;- janela circular de 4 KiB (
_MAXWIN) com flush aosink— a razão da memória O(1).
Os parâmetros do formato: lit (literais crus vs. codificados), dict ∈ 4..6 (log₂ do dicionário − 6), comprimentos via _LEN_BASE/_LEN_EXTRA, fim de fluxo em len == 519.
Parsers de bytes
Em src/schema.jl: MicroSUS._parse_int, MicroSUS._parse_float e MicroSUS._parse_data operam direto no Vector{UInt8} do registro (offsets do CampoDBF), sem String intermediária. Vazio, não-dígito ou data impossível → missing, nunca exceção.
O compressor dos testes
test/runtests.jl contém um compressor DCL mínimo (comprime_dcl): literais crus, matches e o código de fim, com os códigos canônicos computados das mesmas tabelas do descompressor e emitidos MSB-first invertidos. Ele existe só para permitir round-trip real nos testes — não é um compressor de verdade (não procura matches), e por isso vive fora de src/.
Invariantes úteis para PRs
- Nenhum estágio do pipeline pode reter mais que O(
tamanho_lote). filtronunca deve disparar parse de campo não consultado.- Campo fora do schema precisa continuar legível (tipagem do DBF).
] test MicroSUSroda sem rede.