Standard library · Encoding and data

encoding/protobuf

Reading .proto files, the Protocol Buffers wire encoding, and generating Salam code from them.

import encoding.protobuf

Protocol Buffers is Google's binary format for structured messages. The shape of the messages is defined in a .proto file, and this package reads it, generates Salam code for the messages and services, and also carries the low level tools for writing and reading fields.

In the bytes, every field comes as a tag, the field number and the wire type, followed by its value. Numbers are usually written as a varint: each byte holds 7 bits of the number and its top bit says whether another byte follows.

Types

PTokenStream

struct PTokenStream
The tokens of a text.
NameTypeDescription
toksVectorThe tokens.
encoding-protobuf-Parse.salam
import encoding.protobuf

func main:
    src := "syntax = \"proto3\";\npackage shop;\n\nenum Status { OPEN = 0; DONE = 1; }\n\nmessage Order {\n  int64 id = 1;\n  repeated string items = 2;\n  map<string, int32> counts = 3;\n  Status status = 4;\n  oneof pay { string card = 5; bool cash = 6; }\n}\n\nservice Orders {\n  rpc Get (Order) returns (Order);\n  rpc Watch (Order) returns (stream Order);\n}\n"
    mut ok := false
    p := protobuf.ParseFile(src, ok)
    println ok, p.packageName, p.messages.len(), p.enums.len(), p.services.len(), p.imports.len()
    msg := p.messages[0]
    println msg.name, msg.fields.len(), msg.oneofs[0].name, msg.oneofs[0].fieldIndices
    each f in msg.fields:
        println f.number, f.name, protobuf.FieldKindName(f.kind), f.typeName, f.repeated, f.oneofIndex
    end
    m := msg.fields[2]
    println m.kind == protobuf.FK_MAP, protobuf.FieldKindName(m.keyKind), protobuf.FieldKindName(m.mapValueKind)
    e := p.enums[0]
    println e.name, e.values[1].name, e.values[1].number
    s := p.services[0]
    println s.name, s.methods[1].name, s.methods[1].inputType, s.methods[1].serverStream, s.methods[1].clientStream
    println protobuf.ScalarKindFromName("sint64") == protobuf.FK_SINT64, protobuf.ScalarKindFromName("Order")
    mut toks := protobuf.Tokenize("message A { int32 x = 1; }", ok)
    println ok, toks.toks.len(), toks.toks[0].lexeme, toks.toks[0].kind == protobuf.PTK_IDENT, toks.toks[2].kind == protobuf.PTK_LBRACE
    println toks.toks[6].ival, toks.toks[6].line
    _ := protobuf.ParseFile("message {", ok)
    println ok
end
Outputtrue shop 1 1 1 0 Order 6 pay [4, 5] 1 id int64 false -1 2 items string true -1 3 counts map false -1 4 status message Status false -1 5 card string false 0 6 cash bool false 0 true string int32 Status DONE 1 Orders Watch Order true false true 0 true 10 message true true 1 1 false

PField

struct PField
One message field.
NameTypeDescription
namestr = ""The name.
kindint = 0The field kind; one of the FK_ constants.
typeNamestr = ""The type name for a message and an enum. The parser does not resolve names, so an enum comes out as a message kind too.
keyKindint = 0The key kind of a map.
mapValueKindint = 0The value kind of a map.
mapValueTypeNamestr = ""The type name of the map value.
numberint = 0The field number.
repeatedbool = falseThe field is repeated.
packedOptbool = trueRepeated numbers are written packed.
oneofIndexint = -1The index of the oneof group; -1 when there is none.
is_deprecatedbool = falseThe field is marked deprecated.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

POneof

struct POneof
One oneof group: only one of its fields has a value.
NameTypeDescription
namestr = ""The name.
fieldIndicesVectorThe indices of the member fields in the message.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PEnumValue

struct PEnumValue
One enum value.
NameTypeDescription
namestr = ""The name.
numberint = 0The number.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PEnum

struct PEnum
One enum.
NameTypeDescription
namestr = ""The name.
valuesVectorThe values.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PMessage

struct PMessage
One message.
NameTypeDescription
namestr = ""The name.
fieldsVectorThe fields in the order they were defined.
oneofsVectorThe oneof groups.
nestedMessagesVectorThe nested messages.
nestedEnumsVectorThe nested enums.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PMethod

struct PMethod
One service method.
NameTypeDescription
namestr = ""The name.
inputTypestr = ""The input type.
outputTypestr = ""The output type.
clientStreambool = falseThe input is a stream.
serverStreambool = falseThe output is a stream.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PService

struct PService
One gRPC service.
NameTypeDescription
namestr = ""The name.
methodsVectorThe methods.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PFile

struct PFile
One parsed .proto file.
NameTypeDescription
packageNamestr = ""The package name.
messagesVectorThe messages.
enumsVectorThe top level enums.
importsVectorThe imported files.
servicesVectorThe services.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

PToken

struct PToken
One token.
NameTypeDescription
kindintThe token kind.
lexemestr = ""The text of the token.
ivali64 = 0The integer value.
fvalf64 = 0The float value.
svalstr = ""The string value.
lineint = 0The line number.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

Constants and variables

Wire types WT_…

How a field value is written in the bytes: varint, 8 fixed bytes, length prefixed or 4 fixed bytes.
NameValue
WT_VARINT0
WT_FIXED641
WT_LEN2
WT_FIXED325
encoding-protobuf-Wire.salam
import encoding.protobuf
import compress

func main:
    mut b := compress.NewByteBuf()
    protobuf.WriteTag(b, 1, protobuf.WT_VARINT)
    protobuf.WriteVarint(b, 150 as u64)
    println compress.BufToBase64(b), protobuf.MakeTag(1, 0), protobuf.MakeTag(2, protobuf.WT_LEN)
    protobuf.WriteTag(b, 2, protobuf.WT_LEN)
    protobuf.WriteLenPrefixedStr(b, "hello")
    protobuf.WriteTag(b, 3, protobuf.WT_FIXED32)
    protobuf.WriteFixed32(b, 7 as u32)
    protobuf.WriteTag(b, 4, protobuf.WT_FIXED64)
    protobuf.WriteFixed64(b, 9 as u64)
    protobuf.WriteFloat(b, 0.5)
    protobuf.WriteDouble(b, 2.25)
    protobuf.WriteLenPrefixedBytes(b, b.data, 2)
    mut r := compress.ReaderFromBuf(b)
    mut good := true
    mut number := 0
    mut wire := 0
    protobuf.ReadTag(r, number, wire, good)
    println number, wire, protobuf.ReadVarint(r, good)
    protobuf.ReadTag(r, number, wire, good)
    println number, protobuf.ReadLenPrefixedStr(r, good)
    protobuf.ReadTag(r, number, wire, good)
    protobuf.SkipField(r, wire, good)
    protobuf.ReadTag(r, number, wire, good)
    println number, protobuf.ReadFixed64(r, good)
    println protobuf.ReadFloat(r, good), protobuf.ReadDouble(r, good)
    b2 := protobuf.ReadLenPrefixedBuf(r, good)
    println compress.BufLen(b2), good
    _ := protobuf.ReadVarint(r, good)
    println good
    println protobuf.ZigZagEncode32(-1), protobuf.ZigZagDecode32(3 as u32), protobuf.ZigZagEncode64(-2), protobuf.ZigZagDecode64(4 as u64)
    mut b3 := compress.NewByteBuf()
    protobuf.WriteFixed32(b3, 42 as u32)
    mut r3 := compress.ReaderFromBuf(b3)
    good = true
    println protobuf.ReadFixed32(r3, good)
    compress.BufFree(b)
    compress.BufFree(b3)
end
OutputCJYB 8 18 1 0 150 2 hello 4 9 0.5 2.25 2 true false 1 -2 3 2 42

Field kinds FK_…

The kind of a field: the plain protobuf types, message, enum and map.
NameValue
FK_DOUBLE1
FK_FLOAT2
FK_INT323
FK_INT644
FK_UINT325
FK_UINT646
FK_SINT327
FK_SINT648
FK_FIXED329
FK_FIXED6410
FK_SFIXED3211
FK_SFIXED6412
FK_BOOL13
FK_STRING14
FK_BYTES15
FK_MESSAGE16
FK_ENUM17
FK_MAP18

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

Token kinds PTK_…

The kind of the tokens from Tokenize.
NameValue
PTK_EOF0
PTK_IDENT1
PTK_INT2
PTK_FLOAT3
PTK_STRING4
PTK_SEMI5
PTK_LBRACE6
PTK_RBRACE7
PTK_LPAREN8
PTK_RPAREN9
PTK_LBRACKET10
PTK_RBRACKET11
PTK_LANGLE12
PTK_RANGLE13
PTK_EQ14
PTK_COMMA15
PTK_DOT16
PTK_MINUS17
PTK_ERROR18

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

Functions

ParseFile

func ParseFile(source: str, ok &: bool): PFile
Reads .proto text in the proto3 syntax.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

MakeTag

func MakeTag(fieldNum: int, wireType: int): u64
A field tag: the field number and the wire type in one number.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteVarint

func WriteVarint(buf &: compress.ByteBuf, n: u64)
Writes the number with variable length encoding (varint): 7 bits per byte, so small numbers are shorter.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadVarint

func ReadVarint(r &: compress.ByteReader, ok &: bool): u64
Reads one varint.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteTag

func WriteTag(buf &: compress.ByteBuf, fieldNum: int, wireType: int)
Writes the tag as a varint.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadTag

func ReadTag(r &: compress.ByteReader, fieldNum &: int, wireType &: int, ok &: bool)
Reads a tag and splits out the field number and the wire type.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ZigZagEncode32

func ZigZagEncode32(n: i32): u32
Zigzag encoding: it moves small negative numbers to small positive ones so they get a short varint.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ZigZagDecode32

func ZigZagDecode32(n: u32): i32
Undoes 32 bit zigzag.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ZigZagEncode64

func ZigZagEncode64(n: i64): u64
64 bit zigzag encoding.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ZigZagDecode64

func ZigZagDecode64(n: u64): i64
Undoes 64 bit zigzag.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteFixed32

func WriteFixed32(buf &: compress.ByteBuf, v: u32)
Writes a 32 bit number as 4 little-endian bytes.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadFixed32

func ReadFixed32(r &: compress.ByteReader, ok &: bool): u32
Reads 4 bytes.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteFixed64

func WriteFixed64(buf &: compress.ByteBuf, v: u64)
Writes a 64 bit number as 8 bytes.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadFixed64

func ReadFixed64(r &: compress.ByteReader, ok &: bool): u64
Reads 8 bytes.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteFloat

func WriteFloat(buf &: compress.ByteBuf, v: f64)
Writes a 32 bit float.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadFloat

func ReadFloat(r &: compress.ByteReader, ok &: bool): f64
Reads a 32 bit float.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteDouble

func WriteDouble(buf &: compress.ByteBuf, v: f64)
Writes a 64 bit float.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadDouble

func ReadDouble(r &: compress.ByteReader, ok &: bool): f64
Reads a 64 bit float.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteLenPrefixedBytes

func WriteLenPrefixedBytes(buf &: compress.ByteBuf, p: void*, n: int)
Writes the length and then the bytes; for bytes fields and nested messages.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

WriteLenPrefixedStr

func WriteLenPrefixedStr(buf &: compress.ByteBuf, s: str)
Writes the length and then the string.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadLenPrefixedBuf

func ReadLenPrefixedBuf(r &: compress.ByteReader, ok &: bool): compress.ByteBuf
Reads one length prefixed part into a buffer.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

ReadLenPrefixedStr

func ReadLenPrefixedStr(r &: compress.ByteReader, ok &: bool): str
Reads one length prefixed part into a string.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

SkipField

func SkipField(r &: compress.ByteReader, wireType: int, ok &: bool)
Steps over the value of a field of the given wire type; for unknown fields.

The example for this item is shown with the ones above: encoding-protobuf-Wire.salam

Tokenize

func Tokenize(source: str, ok &: bool): PTokenStream
Breaks the text into tokens.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

GenerateSingle

func GenerateSingle(protoSource: str, ok &: bool): str
Generates Salam code from .proto text: one struct per message, with its serialising functions.
encoding-protobuf-Generate.salam
import encoding.protobuf
import str

func main:
    src := "syntax = \"proto3\";\nmessage Ping { string text = 1; }\nservice Echo {\n  rpc Say (Ping) returns (Ping);\n  rpc Stream (stream Ping) returns (stream Ping);\n}\n"
    mut ok := false
    code := protobuf.GenerateSingle(src, ok)
    println ok, str.Contains(code, "struct Ping")
    p := protobuf.ParseFile(src, ok)
    println protobuf.ServiceCount(p), protobuf.ServiceNameAt(p, 0), protobuf.ServiceMethodCount(p, 0)
    println protobuf.ServiceMethodSignature(p, 0, 0)
    println protobuf.ServiceMethodSignature(p, 0, 1)
    println str.Contains(protobuf.GenerateServices(p), "Echo")
    all := protobuf.GenerateWithServices(src, ok)
    println ok, str.Len(all) > str.Len(code)
    println protobuf.ServiceSummary(src, ok)
end
Outputtrue true 1 Echo 2 Say(Ping) returns (Ping) Stream(stream Ping) returns (stream Ping) true true true service Echo (2 methods) rpc Say(Ping) returns (Ping) rpc Stream(stream Ping) returns (stream Ping)

FieldKindName

func FieldKindName(k: int): str
The name of a field kind, such as int64.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

ScalarKindFromName

func ScalarKindFromName(name: str): int
The field kind for a plain type name; zero for a message name.

The example for this item is shown with the ones above: encoding-protobuf-Parse.salam

ServiceNameAt

func ServiceNameAt(f: PFile, i: int): str
The name of service number i.

The example for this item is shown with the ones above: encoding-protobuf-Generate.salam

ServiceMethodCount

func ServiceMethodCount(f: PFile, i: int): int
The number of methods of a service.

The example for this item is shown with the ones above: encoding-protobuf-Generate.salam

ServiceMethodSignature

func ServiceMethodSignature(f: PFile, si: int, mi: int): str
The signature of one method, such as Say(Ping) returns (Ping).

The example for this item is shown with the ones above: encoding-protobuf-Generate.salam

GenerateServices

func GenerateServices(f: PFile): str
Generates the service interface code.

The example for this item is shown with the ones above: encoding-protobuf-Generate.salam

GenerateWithServices

func GenerateWithServices(protoSource: str, ok &: bool): str
Generates the message and service code together.

The example for this item is shown with the ones above: encoding-protobuf-Generate.salam

ServiceSummary

func ServiceSummary(protoSource: str, ok &: bool): str
A readable summary of the services and their methods.

The example for this item is shown with the ones above: encoding-protobuf-Generate.salam