プロトコルバッファ Edition 2023 言語仕様

Protocol Buffers 言語の edition 2023 の言語仕様リファレンス。

構文は 拡張バッカス・ナウア記法 (EBNF) を用いて定義されます。

|   alternation
()  grouping
[]  option (zero or one time)
{}  repetition (any number of times)

字句要素

文字と数字

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テキスト形式言語仕様 で定義されています。

エディション

edition 文は従来の syntax キーワードを置き換えるもので、このファイルが使用しているエディションを定義するために使用されます。

edition = "edition" "=" [ ( "'" decimalLit "'" ) | ( '"' decimalLit '"' ) ] ";"

インポート文

import 文は、別の .proto ファイルの定義をインポートするために使用されます。

import = "import" [ "weak" | "public" ] strLit ";"

import public "other.proto";

パッケージ

package 指定子は、プロトコルメッセージタイプ間の名前の衝突を防ぐために使用できます。

package = "package" fullIdent ";"

package foo.bar;

オプション

オプションは、proto ファイル、メッセージ、enum、および service で使用できます。オプションには、protobuf 定義のオプションまたはカスタムオプションを使用できます。詳細については、言語ガイドの オプション を参照してください。オプションは、機能設定 を制御するためにも使用されます。

option = "option" optionName  "=" constant ";"
optionName = ( ident | "(" ["."] fullIdent ")" )

例として

option java_package = "com.example.foo";
option features.enum_type = CLOSED;

フィールド

フィールドは、プロトコルバッファメッセージの基本的な要素です。フィールドには、通常フィールド、グループフィールド、oneof フィールド、または map フィールドがあります。フィールドは、ラベル、型、およびフィールド番号を持ちます。

label = [ "repeated" ]
type = "double" | "float" | "int32" | "int64" | "uint32" | "uint64"
      | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64"
      | "bool" | "string" | "bytes" | messageType | enumType
fieldNumber = intLit;

通常フィールド

各フィールドには、ラベル、型、名前、およびフィールド番号があります。フィールドオプションを持つこともあります。

field = [label] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
fieldOptions = fieldOption { ","  fieldOption }
fieldOption = optionName "=" constant

foo.bar nested_message = 2;
repeated int32 samples = 4 [packed=true];

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 フィールドには、キーの型、値の型、名前、およびフィールド番号があります。キーの型には、任意の整数型または文字列型を使用できます。ただし、キーの型は enum にすることはできません。

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;

予約済み

予約済みは、メッセージまたは enum 内で使用できないフィールド番号または名前の範囲を宣言します。

reserved = "reserved" ( ranges | reservedIdent ) ";"
fieldNames = fieldName { "," fieldName }

reserved 2, 15, 9 to 11;
reserved foo, bar;

トップレベル定義

Enum 定義

enum 定義は、名前と enum 本体で構成されます。enum 本体には、オプション、enum フィールド、および予約済み文を含めることができます。

enum = "enum" enumName enumBody
enumBody = "{" { option | enumField | emptyStatement | reserved } "}"
enumField = fieldName "=" [ "-" ] 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"];
}

Message 定義

message は、メッセージ名とメッセージ本体で構成されます。メッセージ本体には、フィールド、ネストされた enum 定義、ネストされた message 定義、extend 文、拡張、group、オプション、oneof、map フィールド、および予約済み文を含めることができます。メッセージは、同じメッセージスキーマ内で同じ名前の 2 つのフィールドを含むことはできません。

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 {   // Level 2
    required int64 ival = 1;
  }
  map<int32, string> my_map = 2;
  extensions 20 to 30;
}

メッセージ内で宣言されたエンティティは、名前が競合してはなりません。以下のすべてが禁止されています。

message MyMessage {
  string foo = 1;
  message foo {}
}

message MyMessage {
  string foo = 1;
  oneof foo {
    string bar = 2;
  }
}

message MyMessage {
  string foo = 1;
  extend Extendable {
    string foo = 2;
  }
}

message MyMessage {
  string foo = 1;
  enum E {
    foo = 0;
  }
}

Extend (拡張)

同じまたはインポートされた .proto ファイル内のメッセージが拡張用の範囲を予約している場合、そのメッセージは拡張できます。

extend = "extend" messageType "{" {field | group} "}"

extend Foo {
  int32 bar = 126;
}

Service 定義

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 ファイルの例

edition = "2023";
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 {   // Level 2
    int64 ival = 1 [features.field_presence = LEGACY_REQUIRED];
  }
  repeated Inner inner_message = 2;
  EnumAllowingAlias enum_field = 3;
  map<int32, string> my_map = 4;
  extensions 20 to 30;
  reserved reserved_field;
}
message Foo {
  message GroupMessage {
    bool a = 1;
  }
  GroupMessage groupmessage = [features.message_encoding = DELIMITED];
}