Exercício: Análise de Protobuf

Neste exercício, você construirá um analisador (parser) para a codificação binária de protobuf. Não se preocupe, é mais simples do que parece! Isso ilustra um padrão de análise comum, passando slices de dados. Os próprios dados subjacentes nunca são copiados.

Analisar (parse) completamente uma mensagem protobuf requer conhecer os tipos dos campos, indexados por seus números de campo. Isso é normalmente fornecido em um arquivo proto. Neste exercício, codificaremos essas informações em declarações match em funções que são chamadas para cada campo.

Usaremos o seguinte proto:

message PhoneNumber { optional string number = 1; optional string type = 2; } message Person { optional string name = 1; optional int32 id = 2; repeated PhoneNumber phones = 3; }

Uma mensagem proto é codificada como uma série de campos, um após o outro. Cada um é implementado como uma “tag” seguida pelo valor. A tag contém um número de campo (por exemplo, 2 para o campo id de uma mensagem Person) e um tipo de fio (wire type) definindo como a carga útil deve ser determinada a partir do fluxo (stream) de bytes.

Números inteiros, incluindo a tag, são representados com uma codificação de comprimento variável chamada VARINT. Felizmente, parse_varint é definido para você abaixo. O código fornecido também define callbacks para lidar com campos Person e PhoneNumber, e para analisar uma mensagem em uma série de chamadas para esses callbacks.

O que resta para você é implementar a função parse_field e o trait ProtoMessage para Person e PhoneNumber.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Speaker Notes

This slide and its sub-slides should take about 30 minutes.
  • Neste exercício, há vários casos em que a análise de protobuf pode falhar, por exemplo, se você tentar analisar um i32 quando houver menos de 4 bytes restantes no buffer de dados. Em código Rust normal, lidaríamos com isso com o enum Result, mas para simplicidade neste exercício, lançamos um pânico se ocorrerem erros. No dia 4, abordaremos o tratamento de erros em Rust com mais detalhes.