Спецификация языка Protocol Buffers (Синтаксис Proto2)
Справочник по спецификации для синтаксиса proto2 и его связи с Редакциями Protobuf.
Синтаксис задается с использованием Расширенной формы Бэкуса-Наура (EBNF):
| альтернатива
() группировка
[] опция (ноль или один раз)
{} повторение (любое количество раз)
Для получения дополнительной информации об использовании proto2 см. руководство по языку.
Лексические элементы
Буквы и цифры
letter = "A" ... "Z" | "a" ... "z"
capitalLetter = "A" ... "Z"
decimalDigit = "0" ... "9"
octalDigit = "0" ... "7"
hexDigit = "0" ... "9" | "A" ... "F" | "a" ... "f"
Идентификаторы
ident = letter { letter | decimalDigit | "_" }
fullIdent = ident { "." ident }
messageName = ident
enumName = ident
fieldName = ident
oneofName = ident
mapName = ident
serviceName = ident
rpcName = ident
streamName = ident
messageType = [ "." ] { ident "." } messageName
enumType = [ "." ] { ident "." } enumName
groupName = capitalLetter { letter | decimalDigit | "_" }
Целочисленные литералы
intLit = decimalLit | octalLit | hexLit
decimalLit = [-] ( "1" ... "9" ) { decimalDigit }
octalLit = [-] "0" { octalDigit }
hexLit = [-] "0" ( "x" | "X" ) hexDigit { hexDigit }
Литералы с плавающей точкой
floatLit = [-] ( decimals "." [ decimals ] [ exponent ] | decimals exponent | "."decimals [ exponent ] ) | "inf" | "nan"
decimals = [-] decimalDigit { decimalDigit }
exponent = ( "e" | "E" ) [ "+" | "-" ] decimals
Логический тип
boolLit = "true" | "false"
Строковые литералы
strLit = strLitSingle { strLitSingle }
strLitSingle = ( "'" { charValue } "'" ) | ( '"' { charValue } '"' )
charValue = hexEscape | octEscape | charEscape | unicodeEscape | unicodeLongEscape | /[^\0\n\\]/
hexEscape = '\' ( "x" | "X" ) hexDigit [ hexDigit ]
octEscape = '\' octalDigit [ octalDigit [ octalDigit ] ]
charEscape = '\' ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | '\' | "'" | '"' )
unicodeEscape = '\' "u" hexDigit hexDigit hexDigit hexDigit
unicodeLongEscape = '\' "U" ( "000" hexDigit hexDigit hexDigit hexDigit hexDigit |
"0010" hexDigit hexDigit hexDigit hexDigit
Пустой оператор
emptyStatement = ";"
Константа
constant = fullIdent | ( [ "-" | "+" ] intLit ) | ( [ "-" | "+" ] floatLit ) |
strLit | boolLit | MessageValue
MessageValue определяется в
Спецификации языка текстового формата.
Синтаксис
Оператор syntax используется для определения версии protobuf. Если syntax
опущен, компилятор протокола будет использовать proto2. Для ясности
рекомендуется всегда явно включать оператор syntax в ваши .proto
файлы.
syntax = "syntax" "=" ("'" "proto2" "'" | '"' "proto2" '"') ";"
Оператор импорта
Оператор импорта используется для импорта определений из другого .proto-файла.
import = "import" [ "weak" | "public" ] strLit ";"
Пример:
import public "other.proto";
Пакет
Спецификатор пакета может использоваться для предотвращения конфликтов имен между типами сообщений протокола.
package = "package" fullIdent ";"
Пример:
package foo.bar;
Опция
Опции могут использоваться в proto-файлах, сообщениях, перечислениях и сервисах. Опция может быть предопределенной опцией protobuf или пользовательской опцией. Для получения дополнительной информации см. Опции в руководстве по языку.
option = "option" optionName "=" constant ";"
optionName = ( ident | bracedFullIdent ) { "." ( ident | bracedFullIdent ) }
bracedFullIdent = "(" ["."] fullIdent ")"
Примеры:
option java_package = "com.example.foo";
Поля
Поля — это основные элементы сообщения protobuf. Поля могут быть обычными
полями, групповыми полями, полями oneof или полями map. Поле имеет тип, имя и
номер поля. В proto2 поля также имеют метку (required, optional, или
repeated).
label = "required" | "optional" | "repeated"
type = "double" | "float" | "int32" | "int64" | "uint32" | "uint64"
| "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64"
| "bool" | "string" | "bytes" | messageType | enumType
fieldNumber = intLit;
Обычное поле
Каждое поле имеет тип, имя и номер поля. Оно может иметь опции поля. Обратите внимание, что метки являются опциональными только для полей oneof.
field = [ label ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
fieldOptions = fieldOption { "," fieldOption }
fieldOption = optionName "=" constant
Примеры:
optional foo.bar nested_message = 2;
repeated int32 samples = 4 [packed=true];
Групповое поле
Обратите внимание, что эта функция устарела и не должна использоваться при создании новых типов сообщений. Вместо этого используйте вложенные типы сообщений.
Группы — это один из способов вложения информации в определениях сообщений. Имя группы должно начинаться с заглавной буквы.
group = label "group" groupName "=" fieldNumber messageBody
Пример:
repeated group Result = 1 {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
Oneof и поле oneof
Oneof состоит из полей oneof и имени oneof. Поля oneof не имеют меток.
oneof = "oneof" oneofName "{" { option | oneofField } "}"
oneofField = type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
Пример:
oneof foo {
string name = 4;
SubMessage sub_message = 9;
}
Поле map
Поле map имеет тип ключа, тип значения, имя и номер поля. Тип ключа может быть любым целочисленным или строковым типом. Обратите внимание, что тип ключа не может быть перечислением.
mapField = "map" "<" keyType "," type ">" mapName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" |
"fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string"
Пример:
map<string, Project> projects = 3;
Расширения и Зарезервированные
Расширения и зарезервированные элементы — это элементы сообщения, которые объявляют диапазон номеров полей или имен полей.
Расширения
Расширения объявляют, что диапазон номеров полей в сообщении доступен для сторонних расширений. Другие пользователи могут объявлять новые поля для вашего типа сообщения с этими числовыми тегами в своих собственных .proto-файлах без необходимости редактирования оригинального файла.
extensions = "extensions" ranges ";"
ranges = range { "," range }
range = intLit [ "to" ( intLit | "max" ) ]
Примеры:
extensions 100 to 199;
extensions 4, 20 to max;
Для получения дополнительной информации по этой теме см. Объявления расширений.
Зарезервированные
Зарезервированные объявляют диапазон номеров полей или имен полей в сообщении, которые не могут быть использованы.
reserved = "reserved" ( ranges | strFieldNames ) ";"
strFieldNames = strFieldName { "," strFieldName }
strFieldName = "'" fieldName "'" | '"' fieldName '"'
Примеры:
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
Определения верхнего уровня
Определение перечисления
Определение перечисления состоит из имени и тела перечисления. Тело перечисления может содержать опции, поля перечисления и операторы reserved.
enum = "enum" enumName enumBody
enumBody = "{" { option | enumField | emptyStatement | reserved } "}"
enumField = ident "=" [ "-" ] intLit [ "[" enumValueOption { "," enumValueOption } "]" ]";"
enumValueOption = optionName "=" constant
Пример:
enum EnumAllowingAlias {
option allow_alias = true;
EAA_UNSPECIFIED = 0;
EAA_STARTED = 1;
EAA_RUNNING = 2 [(custom_option) = "hello world"];
}
Определение сообщения
Сообщение состоит из имени сообщения и тела сообщения. Тело сообщения может содержать поля, вложенные определения перечислений, вложенные определения сообщений, операторы extend, расширения, группы, опции, oneof, поля map и операторы reserved. Сообщение не может содержать два поля с одинаковым именем в одной схеме сообщения.
message = "message" messageName messageBody
messageBody = "{" { field | enum | message | extend | extensions | group |
option | oneof | mapField | reserved | emptyStatement } "}"
Пример:
message Outer {
option (my_option).a = true;
message Inner { // Уровень 2
required int64 ival = 1;
}
map<int32, string> my_map = 2;
extensions 20 to 30;
}
Ни один из элементов, объявленных внутри сообщения, не может иметь конфликтующих имен. Все следующее запрещено:
message MyMessage {
optional string foo = 1;
message foo {}
}
message MyMessage {
optional string foo = 1;
oneof foo {
string bar = 2;
}
}
message MyMessage {
optional string foo = 1;
extend Extendable {
optional string foo = 2;
}
}
message MyMessage {
optional string foo = 1;
enum E {
foo = 0;
}
}
Расширить (Extend)
Если сообщение в том же или импортированном .proto-файле зарезервировало диапазон для расширений, это сообщение может быть расширено.
extend = "extend" messageType "{" {field | group} "}"
Пример:
extend Foo {
optional int32 bar = 126;
}
Определение сервиса
service = "service" serviceName "{" { option | rpc | emptyStatement } "}"
rpc = "rpc" rpcName "(" [ "stream" ] messageType ")" "returns" "(" [ "stream" ]
messageType ")" (( "{" { option | emptyStatement } "}" ) | ";" )
Пример:
service SearchService {
rpc Search (SearchRequest) returns (SearchResponse);
}
Proto-файл
proto = [syntax] { import | package | option | topLevelDef | emptyStatement }
topLevelDef = message | enum | extend | service
Пример .proto файла:
syntax = "proto2";
import public "other.proto";
option java_package = "com.example.foo";
enum EnumAllowingAlias {
option allow_alias = true;
EAA_UNSPECIFIED = 0;
EAA_STARTED = 1;
EAA_RUNNING = 1;
EAA_FINISHED = 2 [(custom_option) = "hello world"];
}
message Outer {
option (my_option).a = true;
message Inner { // Уровень 2
required int64 ival = 1;
}
repeated Inner inner_message = 2;
optional EnumAllowingAlias enum_field = 3;
map<int32, string> my_map = 4;
extensions 20 to 30;
}
message Foo {
optional group GroupMessage = 1 {
optional bool a = 1;
}
}