parent
bd4520d96d
commit
43f77303bb
|
@ -30,11 +30,11 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- target:
|
- target:
|
||||||
os: linux
|
os: linux
|
||||||
builder: ubuntu-18.04
|
builder: ubuntu-20.04
|
||||||
shell: bash
|
shell: bash
|
||||||
- target:
|
- target:
|
||||||
os: macos
|
os: macos
|
||||||
builder: macos-10.15
|
builder: macos-12
|
||||||
shell: bash
|
shell: bash
|
||||||
- target:
|
- target:
|
||||||
os: windows
|
os: windows
|
||||||
|
@ -96,7 +96,7 @@ jobs:
|
||||||
- name: Restore Nim DLLs dependencies (Windows) from cache
|
- name: Restore Nim DLLs dependencies (Windows) from cache
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
id: windows-dlls-cache
|
id: windows-dlls-cache
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: external/dlls-${{ matrix.target.cpu }}
|
path: external/dlls-${{ matrix.target.cpu }}
|
||||||
key: 'dlls-${{ matrix.target.cpu }}'
|
key: 'dlls-${{ matrix.target.cpu }}'
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
name: Conformance Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
types: [run]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency: # Cancel stale PR builds (but not push builds)
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- os: linux
|
||||||
|
cpu: amd64
|
||||||
|
- os: linux
|
||||||
|
cpu: i386
|
||||||
|
|
||||||
|
branch: [version-1-4, version-1-6, devel]
|
||||||
|
include:
|
||||||
|
- target:
|
||||||
|
os: linux
|
||||||
|
builder: ubuntu-20.04
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: ${{ matrix.shell }}
|
||||||
|
|
||||||
|
name: '${{ matrix.target.os }}-${{ matrix.target.cpu }} (Nim ${{ matrix.branch }})'
|
||||||
|
runs-on: ${{ matrix.builder }}
|
||||||
|
continue-on-error: ${{ matrix.branch == 'devel' }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install build dependencies (Linux i386)
|
||||||
|
if: runner.os == 'Linux' && matrix.target.cpu == 'i386'
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-fast update -qq
|
||||||
|
sudo DEBIAN_FRONTEND='noninteractive' apt-fast install \
|
||||||
|
--no-install-recommends -yq gcc-multilib g++-multilib \
|
||||||
|
libssl-dev:i386
|
||||||
|
mkdir -p external/bin
|
||||||
|
cat << EOF > external/bin/gcc
|
||||||
|
#!/bin/bash
|
||||||
|
exec $(which gcc) -m32 "\$@"
|
||||||
|
EOF
|
||||||
|
cat << EOF > external/bin/g++
|
||||||
|
#!/bin/bash
|
||||||
|
exec $(which g++) -m32 "\$@"
|
||||||
|
EOF
|
||||||
|
chmod 755 external/bin/gcc external/bin/g++
|
||||||
|
echo '${{ github.workspace }}/external/bin' >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Derive environment variables
|
||||||
|
run: |
|
||||||
|
if [[ '${{ matrix.target.cpu }}' == 'amd64' ]]; then
|
||||||
|
PLATFORM=x64
|
||||||
|
else
|
||||||
|
PLATFORM=x86
|
||||||
|
fi
|
||||||
|
echo "PLATFORM=$PLATFORM" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
ncpu=
|
||||||
|
MAKE_CMD="make"
|
||||||
|
case '${{ runner.os }}' in
|
||||||
|
'Linux')
|
||||||
|
ncpu=$(nproc)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
|
||||||
|
echo "ncpu=$ncpu" >> $GITHUB_ENV
|
||||||
|
echo "MAKE_CMD=${MAKE_CMD}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install CMake
|
||||||
|
run: |
|
||||||
|
if [ "${{ runner.os }}" == "Linux" ]; then
|
||||||
|
sudo apt-get install cmake
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build Nim and Nimble
|
||||||
|
run: |
|
||||||
|
curl -O -L -s -S https://raw.githubusercontent.com/status-im/nimbus-build-system/master/scripts/build_nim.sh
|
||||||
|
env MAKE="${MAKE_CMD} -j${ncpu}" ARCH_OVERRIDE=${PLATFORM} NIM_COMMIT=${{ matrix.branch }} \
|
||||||
|
QUICK_AND_DIRTY_COMPILER=1 QUICK_AND_DIRTY_NIMBLE=1 CC=gcc \
|
||||||
|
bash build_nim.sh nim csources dist/nimble NimBinaries
|
||||||
|
echo '${{ github.workspace }}/nim/bin' >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
nim --version
|
||||||
|
nimble --version
|
||||||
|
nimble install -y --depsOnly
|
||||||
|
env NIMLANG="c" nimble conformance_test
|
||||||
|
env NIMLANG="cpp" nimble conformance_test
|
|
@ -50,3 +50,20 @@ task test, "Run all tests":
|
||||||
echo " \x1B[0;31m[FAILED]\x1B[0;37m ", path.split(DirSep)[^1]
|
echo " \x1B[0;31m[FAILED]\x1B[0;37m ", path.split(DirSep)[^1]
|
||||||
exec "exit 1"
|
exec "exit 1"
|
||||||
|
|
||||||
|
task conformance_test, "Run conformance tests":
|
||||||
|
let
|
||||||
|
pwd = thisDir()
|
||||||
|
conformance = pwd / "conformance"
|
||||||
|
test = pwd / "tests" / "conformance"
|
||||||
|
|
||||||
|
if not system.dirExists(conformance):
|
||||||
|
exec "git clone -b v22.0 --recurse-submodules https://github.com/protocolbuffers/protobuf/ " & conformance
|
||||||
|
|
||||||
|
withDir conformance:
|
||||||
|
exec "cmake . -Dprotobuf_BUILD_CONFORMANCE=ON"
|
||||||
|
exec "make conformance_test_runner"
|
||||||
|
|
||||||
|
exec "cp " & conformance / "conformance_test_runner" & " " & test
|
||||||
|
withDir test:
|
||||||
|
exec "nim c -d:ConformanceTest conformance_nim.nim"
|
||||||
|
exec "./conformance_test_runner --failure_list failure_list.txt conformance_nim"
|
||||||
|
|
|
@ -31,6 +31,8 @@ type
|
||||||
# EndGroup = 4 # Not used
|
# EndGroup = 4 # Not used
|
||||||
Fixed32 = 5
|
Fixed32 = 5
|
||||||
|
|
||||||
|
SomePBInt* = int32 | int64 | uint32 | uint64
|
||||||
|
|
||||||
FieldHeader* = distinct uint32
|
FieldHeader* = distinct uint32
|
||||||
|
|
||||||
# Scalar types used in `.proto` files
|
# Scalar types used in `.proto` files
|
||||||
|
@ -54,19 +56,20 @@ type
|
||||||
sfixed64* = distinct int64 ## fixed-width signed integer
|
sfixed64* = distinct int64 ## fixed-width signed integer
|
||||||
|
|
||||||
pbool* = distinct bool
|
pbool* = distinct bool
|
||||||
|
penum* = distinct int32
|
||||||
|
|
||||||
pstring* = distinct string ## UTF-8-encoded string
|
pstring* = distinct string ## UTF-8-encoded string
|
||||||
pbytes* = distinct seq[byte] ## byte sequence
|
pbytes* = distinct seq[byte] ## byte sequence
|
||||||
|
|
||||||
SomeScalar* =
|
SomeScalar* =
|
||||||
pint32 | pint64 | puint32 | puint64 | sint32 | sint64 | pbool |
|
pint32 | pint64 | puint32 | puint64 | sint32 | sint64 | pbool | penum |
|
||||||
fixed64 | sfixed64 | pdouble |
|
fixed64 | sfixed64 | pdouble |
|
||||||
pstring | pbytes |
|
pstring | pbytes |
|
||||||
fixed32 | sfixed32 | pfloat
|
fixed32 | sfixed32 | pfloat
|
||||||
|
|
||||||
# Mappings of proto type to wire type
|
# Mappings of proto type to wire type
|
||||||
SomeVarint* =
|
SomeVarint* =
|
||||||
pint32 | pint64 | puint32 | puint64 | sint32 | sint64 | pbool
|
pint32 | pint64 | puint32 | puint64 | sint32 | sint64 | pbool | penum
|
||||||
SomeFixed64* = fixed64 | sfixed64 | pdouble
|
SomeFixed64* = fixed64 | sfixed64 | pdouble
|
||||||
SomeLengthDelim* = pstring | pbytes # Also messages and packed repeated fields
|
SomeLengthDelim* = pstring | pbytes # Also messages and packed repeated fields
|
||||||
SomeFixed32* = fixed32 | sfixed32 | pfloat
|
SomeFixed32* = fixed32 | sfixed32 | pfloat
|
||||||
|
@ -116,6 +119,7 @@ func toUleb(x: sint32): uint32 =
|
||||||
template toUleb(x: pint64): uint64 = cast[uint64](x)
|
template toUleb(x: pint64): uint64 = cast[uint64](x)
|
||||||
template toUleb(x: pint32): uint32 = cast[uint32](x)
|
template toUleb(x: pint32): uint32 = cast[uint32](x)
|
||||||
template toUleb(x: pbool): uint8 = cast[uint8](x)
|
template toUleb(x: pbool): uint8 = cast[uint8](x)
|
||||||
|
template toUleb(x: penum): uint64 = cast[uint32](x)
|
||||||
|
|
||||||
template fromUleb(x: uint64, T: type puint64): T = puint64(x)
|
template fromUleb(x: uint64, T: type puint64): T = puint64(x)
|
||||||
template fromUleb(x: uint64, T: type pbool): T = pbool(x != 0)
|
template fromUleb(x: uint64, T: type pbool): T = pbool(x != 0)
|
||||||
|
@ -130,6 +134,7 @@ template fromUleb(x: uint64, T: type sint32): T =
|
||||||
|
|
||||||
template fromUleb(x: uint64, T: type pint64): T = cast[T](x)
|
template fromUleb(x: uint64, T: type pint64): T = cast[T](x)
|
||||||
template fromUleb(x: uint64, T: type pint32): T = cast[T](x)
|
template fromUleb(x: uint64, T: type pint32): T = cast[T](x)
|
||||||
|
template fromUleb(x: uint64, T: type penum): T = cast[T](x)
|
||||||
|
|
||||||
template toBytes*(x: SomeVarint): openArray[byte] =
|
template toBytes*(x: SomeVarint): openArray[byte] =
|
||||||
toBytes(toUleb(x), Leb128).toOpenArray()
|
toBytes(toUleb(x), Leb128).toOpenArray()
|
||||||
|
|
|
@ -26,7 +26,7 @@ type
|
||||||
ReservedType* = enum
|
ReservedType* = enum
|
||||||
String, Number, Range
|
String, Number, Range
|
||||||
ProtoType* = enum
|
ProtoType* = enum
|
||||||
Field, Enum, EnumVal, ReservedBlock, Reserved, Message, File, Imported, Oneof, Package, ProtoDef
|
Field, Enum, EnumVal, ReservedBlock, Reserved, Message, File, Imported, Oneof, Package, ProtoDef, Extend
|
||||||
Presence* = enum
|
Presence* = enum
|
||||||
Singular, Repeated, Optional, Required
|
Singular, Repeated, Optional, Required
|
||||||
ProtoNode* = ref object
|
ProtoNode* = ref object
|
||||||
|
@ -62,6 +62,9 @@ type
|
||||||
definedEnums*: seq[ProtoNode]
|
definedEnums*: seq[ProtoNode]
|
||||||
fields*: seq[ProtoNode]
|
fields*: seq[ProtoNode]
|
||||||
nested*: seq[ProtoNode]
|
nested*: seq[ProtoNode]
|
||||||
|
of Extend:
|
||||||
|
extending*: string
|
||||||
|
extendedFields*: seq[ProtoNode]
|
||||||
of Package:
|
of Package:
|
||||||
packageName*: string
|
packageName*: string
|
||||||
messages*: seq[ProtoNode]
|
messages*: seq[ProtoNode]
|
||||||
|
@ -148,6 +151,14 @@ proc `$`*(node: ProtoNode): string =
|
||||||
messages &= $message & "\n"
|
messages &= $message & "\n"
|
||||||
data &= messages[0..^2].indent(1, " ")
|
data &= messages[0..^2].indent(1, " ")
|
||||||
result &= data.indent(1, " ")
|
result &= data.indent(1, " ")
|
||||||
|
of Extend:
|
||||||
|
result = "Extension of $1 with fields:".format(node.extending)
|
||||||
|
var data = ""
|
||||||
|
var fields = "\n"
|
||||||
|
for field in node.extendedFields:
|
||||||
|
fields &= $field & "\n"
|
||||||
|
data &= fields[0..^2].indent(1, " ")
|
||||||
|
result &= data.indent(1, " ")
|
||||||
of File:
|
of File:
|
||||||
result = "Protobuf file with syntax $1\n".format(
|
result = "Protobuf file with syntax $1\n".format(
|
||||||
node.syntax)
|
node.syntax)
|
||||||
|
|
|
@ -9,6 +9,7 @@ type
|
||||||
typ: TokenType
|
typ: TokenType
|
||||||
text: string
|
text: string
|
||||||
index: int
|
index: int
|
||||||
|
filePos: int
|
||||||
|
|
||||||
proc `$`(t: Token): string =
|
proc `$`(t: Token): string =
|
||||||
$t.typ & ": " & t.text
|
$t.typ & ": " & t.text
|
||||||
|
@ -22,12 +23,13 @@ proc `==`(t: Token, tt: TokenType): bool =
|
||||||
proc `==`(t: Token, c: char): bool =
|
proc `==`(t: Token, c: char): bool =
|
||||||
t.typ == Symbol and t.text[0] == c
|
t.typ == Symbol and t.text[0] == c
|
||||||
|
|
||||||
proc tokenize(text: string): seq[Token] =
|
proc tokenize(filename, text: string): seq[Token] =
|
||||||
let lexer = peg(tokens, res: seq[Token]):
|
let lexer = peg(tokens, res: seq[Token]):
|
||||||
space <- +Space
|
space <- +Space
|
||||||
comment <- "//" * *(1 - '\n')
|
comment <- "//" * *(1 - '\n')
|
||||||
comment2 <- "/*" * @"*/"
|
comment2 <- "/*" * @"*/"
|
||||||
|
|
||||||
|
decDigit <- {'0'..'9'}
|
||||||
octDigit <- {'0'..'7'}
|
octDigit <- {'0'..'7'}
|
||||||
hexDigit <- {'0'..'9', 'a'..'f', 'A'..'F'}
|
hexDigit <- {'0'..'9', 'a'..'f', 'A'..'F'}
|
||||||
octEscape <- '\\' * octDigit[3]
|
octEscape <- '\\' * octDigit[3]
|
||||||
|
@ -35,21 +37,27 @@ proc tokenize(text: string): seq[Token] =
|
||||||
charEscape <- '\\' * {'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"'}
|
charEscape <- '\\' * {'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"'}
|
||||||
escapes <- hexEscape | octEscape | charEscape
|
escapes <- hexEscape | octEscape | charEscape
|
||||||
dblstring <- '"' * *(escapes | 1 - '"') * '"':
|
dblstring <- '"' * *(escapes | 1 - '"') * '"':
|
||||||
res.add Token(typ: String, text: ($0).unescape)
|
res.add Token(typ: String, text: ($0).unescape, filePos: @0)
|
||||||
regstring <- '\'' * *(escapes | 1 - '\'') * '\'':
|
regstring <- '\'' * *(escapes | 1 - '\'') * '\'':
|
||||||
res.add Token(typ: String, text: ($0).unescape(prefix = "'", suffix = "'"))
|
res.add Token(typ: String, text: ($0).unescape(prefix = "'", suffix = "'"), filePos: @0)
|
||||||
string <- dblstring | regstring
|
string <- dblstring | regstring
|
||||||
sym <- {'=', ';', '{', '}', '[', ']', '<', '>', ','}:
|
sym <- {'=', ';', '{', '}', '[', ']', '<', '>', ','}:
|
||||||
res.add Token(typ: Symbol, text: $0)
|
res.add Token(typ: Symbol, text: $0, filePos: @0)
|
||||||
# according to the official syntax, this is correct.
|
# according to the official syntax, this is correct.
|
||||||
# but in reality, leading underscores are accepted
|
# but in reality, leading underscores are accepted
|
||||||
#ident <- Alpha * *(Alpha | '_' | Digit)
|
#ident <- Alpha * *(Alpha | '_' | Digit)
|
||||||
ident <- (Alpha | '_') * *(Alpha | '_' | Digit)
|
ident <- (Alpha | '_') * *(Alpha | '_' | Digit)
|
||||||
fullIdent <- ?'.' * ident * *('.' * ident):
|
fullIdent <- ?'.' * ident * *('.' * ident):
|
||||||
res.add Token(typ: Ident, text: $0)
|
res.add Token(typ: Ident, text: $0, filePos: @0)
|
||||||
|
|
||||||
|
decimals <- +decDigit
|
||||||
|
exponent <- {'e', 'E'} * ?('+' | '-') * decimals
|
||||||
|
floatLit <- ((decimals * '.' * ?decimals * ?exponent) | (decimals * exponent) | ('.' * decimals * ?exponent)):
|
||||||
|
# TODO: find a way to add "inf" and "nan", currently if a Field name starts with nan or inf, it will fail to parse
|
||||||
|
res.add Token(typ: Float, text: $0, filePos: @0)
|
||||||
int <- ?('-' | '+') * +(Digit):
|
int <- ?('-' | '+') * +(Digit):
|
||||||
res.add Token(typ: Integer, text: $0)
|
res.add Token(typ: Integer, text: $0, filePos: @0)
|
||||||
tokens <- *(comment | comment2 | space | string | sym | int | fullIdent)
|
tokens <- *(comment | comment2 | space | string | sym | floatLit | int | fullIdent)
|
||||||
|
|
||||||
let
|
let
|
||||||
match = lexer.match(text, result)
|
match = lexer.match(text, result)
|
||||||
|
@ -58,11 +66,13 @@ proc tokenize(text: string): seq[Token] =
|
||||||
tok.index = index
|
tok.index = index
|
||||||
|
|
||||||
if match.matchLen != text.len:
|
if match.matchLen != text.len:
|
||||||
var msg = "Failed to lex: '" & text[match.matchMax] & "'\n"
|
let line = text[0..<match.matchMax].count('\n') + 1
|
||||||
let
|
var msg = filename & ":" & $line & " Failed to lex '" & text[match.matchMax] & "'\n"
|
||||||
minToShow = max(0, match.matchMax - 20)
|
var
|
||||||
maxToShow = min(text.len, match.matchMax + 20)
|
minToShow = text.rfind('\n', 0, match.matchMax) + 1
|
||||||
msg &= text[minToShow .. maxToShow]
|
maxToShow = text.find('\n', match.matchMax)
|
||||||
|
if maxToShow == -1: maxToShow = text.len
|
||||||
|
msg &= text[minToShow ..< maxToShow]
|
||||||
raise newException(CatchableError, msg)
|
raise newException(CatchableError, msg)
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -92,21 +102,25 @@ proc extract(x: var seq[(Token, ProtoNode)], s: Token): seq[ProtoNode] =
|
||||||
x.keepItIf(it[0].index < s.index)
|
x.keepItIf(it[0].index < s.index)
|
||||||
|
|
||||||
proc parseProtoPackage(file: string, toImport: var HashSet[string]): ProtoNode =
|
proc parseProtoPackage(file: string, toImport: var HashSet[string]): ProtoNode =
|
||||||
let tokens = file.readFile.tokenize
|
let
|
||||||
|
fileContent = file.readFile
|
||||||
|
filename = file.extractFilename
|
||||||
|
tokens = tokenize(filename, fileContent)
|
||||||
|
|
||||||
let parser = peg(g, Token, ps: ParseState):
|
let parser = peg(g, Token, ps: ParseState):
|
||||||
ident <- [Ident]
|
ident <- [Ident]
|
||||||
string <- [String]
|
string <- [String]
|
||||||
int <- [Integer]
|
int <- [Integer]
|
||||||
|
float <- [Float]
|
||||||
|
|
||||||
pkg <- ["package"] * >ident * [';']:
|
pkg <- ["package"] * >ident * [';']:
|
||||||
ps.currentPackage = ProtoNode(kind: Package, packageName: ($1).text)
|
ps.currentPackage = ProtoNode(kind: Package, packageName: ($1).text)
|
||||||
option <- ["option"] * ident * ['='] * (ident | string) * [';']
|
option <- ["option"] * ident * ['='] * (ident | string | int | float) * [';']
|
||||||
syntax <- ["syntax"] * ['='] * string * [';']
|
syntax <- ["syntax"] * ['='] * string * [';']
|
||||||
impor <- ["import"] * >string * [';']:
|
impor <- ["import"] * >string * [';']:
|
||||||
ps.imports.add ProtoNode(kind: Imported, filename: ($1).text)
|
ps.imports.add ProtoNode(kind: Imported, filename: ($1).text)
|
||||||
|
|
||||||
fieldopt <- ident * ['='] * ident
|
fieldopt <- ident * ['='] * (ident | int | string | float)
|
||||||
fieldopts <- ['['] * fieldopt * *([','] * fieldopt) * [']']
|
fieldopts <- ['['] * fieldopt * *([','] * fieldopt) * [']']
|
||||||
|
|
||||||
oneoffield <- >ident * >ident * ['='] * >int * ?fieldopts * [';']:
|
oneoffield <- >ident * >ident * ['='] * >int * ?fieldopts * [';']:
|
||||||
|
@ -186,7 +200,42 @@ proc parseProtoPackage(file: string, toImport: var HashSet[string]): ProtoNode =
|
||||||
number: parseInt(fieldValue),
|
number: parseInt(fieldValue),
|
||||||
protoType: fieldType,
|
protoType: fieldType,
|
||||||
name: fieldName)))
|
name: fieldName)))
|
||||||
msg <- ["message"] * >ident * ['{'] * *(typedecl | mapfield | oneof2 | msgfield | reserved | extensions) * ['}']:
|
|
||||||
|
# protobuf2
|
||||||
|
groupfield <- ?multiple * >["group"] * >ident * ['='] * >int * msgbody:
|
||||||
|
let fields = ps.fields.extract($0)
|
||||||
|
ps.messages.add(($0, ProtoNode(
|
||||||
|
messageName: ($2).text,
|
||||||
|
kind: Message,
|
||||||
|
nested: ps.messages.extract($0),
|
||||||
|
definedEnums: ps.enums.extract($0),
|
||||||
|
reserved: ps.reservedBlocks.extract($0),
|
||||||
|
fields: fields
|
||||||
|
)))
|
||||||
|
|
||||||
|
let
|
||||||
|
fieldType = ($2).text
|
||||||
|
fieldName = ($2).text
|
||||||
|
fieldValue = ($3).text
|
||||||
|
let node = ProtoNode(
|
||||||
|
kind: Field,
|
||||||
|
number: parseInt(fieldValue),
|
||||||
|
protoType: fieldType,
|
||||||
|
name: fieldName)
|
||||||
|
if @1 != @2:
|
||||||
|
node.presence = parseEnum[Presence](($0).text.toUpper)
|
||||||
|
ps.fields.add (($0, node))
|
||||||
|
|
||||||
|
extend2 <- ["extend"] * >ident * msgbody:
|
||||||
|
let fields = ps.fields.extract($0)
|
||||||
|
ps.messages.add(($0, ProtoNode(
|
||||||
|
extending: ($1).text,
|
||||||
|
kind: Extend,
|
||||||
|
extendedFields: fields
|
||||||
|
)))
|
||||||
|
|
||||||
|
msgbody <- ['{'] * *(typedecl | mapfield | oneof2 | msgfield | reserved | extensions | groupfield | option | extend2) * ['}']
|
||||||
|
msg <- ["message"] * >ident * msgbody:
|
||||||
let fields = ps.fields.extract($0)
|
let fields = ps.fields.extract($0)
|
||||||
ps.messages.add(($0, ProtoNode(
|
ps.messages.add(($0, ProtoNode(
|
||||||
messageName: ($1).text,
|
messageName: ($1).text,
|
||||||
|
@ -197,6 +246,7 @@ proc parseProtoPackage(file: string, toImport: var HashSet[string]): ProtoNode =
|
||||||
fields: fields
|
fields: fields
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
|
||||||
enumfield <- >ident * ['='] * >int * [';']:
|
enumfield <- >ident * ['='] * >int * [';']:
|
||||||
let
|
let
|
||||||
fieldName = ($1).text
|
fieldName = ($1).text
|
||||||
|
@ -212,17 +262,21 @@ proc parseProtoPackage(file: string, toImport: var HashSet[string]): ProtoNode =
|
||||||
values: ps.fields.extract($0)
|
values: ps.fields.extract($0)
|
||||||
)))
|
)))
|
||||||
typedecl <- (msg | enumdecl)
|
typedecl <- (msg | enumdecl)
|
||||||
onething <- (pkg | option | syntax | impor | typedecl)
|
onething <- (pkg | option | syntax | impor | typedecl | extend2)
|
||||||
g <- +onething
|
g <- +onething
|
||||||
|
|
||||||
var state = ParseState(currentPackage: ProtoNode(kind: Package))
|
var state = ParseState(currentPackage: ProtoNode(kind: Package))
|
||||||
let match = parser.match(tokens, state)
|
let match = parser.match(tokens, state)
|
||||||
if match.matchLen != tokens.len:
|
if match.matchLen != tokens.len:
|
||||||
var msg = "Failed to parse: '" & tokens[match.matchMax].text & "'\n"
|
|
||||||
let
|
let
|
||||||
minToShow = max(0, match.matchMax - 2)
|
tokenPos = tokens[match.matchMax].filePos
|
||||||
maxToShow = min(tokens.len, match.matchMax + 2)
|
line = fileContent[0..<tokenPos].count('\n') + 1
|
||||||
msg &= tokens[minToShow .. maxToShow].mapIt(it.text).join(" ")
|
var msg = filename & ":" & $line & " Failed to parse: '" & tokens[match.matchMax].text & "'\n"
|
||||||
|
var
|
||||||
|
minToShow = fileContent.rfind('\n', 0, tokenPos) + 1
|
||||||
|
maxToShow = fileContent.find('\n', tokenPos)
|
||||||
|
if maxToShow == -1: maxToShow = msg.len
|
||||||
|
msg &= fileContent[minToShow ..< maxToShow]
|
||||||
raise newException(CatchableError, msg)
|
raise newException(CatchableError, msg)
|
||||||
|
|
||||||
result = state.currentPackage
|
result = state.currentPackage
|
||||||
|
|
|
@ -1,12 +1,75 @@
|
||||||
import os
|
import os, algorithm, strutils, tables
|
||||||
import macros
|
import macros
|
||||||
|
import stew/shims/macros as stewmacros
|
||||||
import decldef
|
import decldef
|
||||||
export decldef
|
export decldef, tables
|
||||||
import proto_parser
|
import proto_parser
|
||||||
|
|
||||||
|
proc getTypeAndPragma(strVal: string): (NimNode, NimNode) =
|
||||||
|
result[0] = ident(strVal.split('.')[^1]) # TODO: Find a better way to handle namespaces
|
||||||
|
case strVal:
|
||||||
|
of "double":
|
||||||
|
result[0] = ident("float64")
|
||||||
|
of "int32":
|
||||||
|
result[1] = ident("pint")
|
||||||
|
of "int64":
|
||||||
|
result[1] = ident("pint")
|
||||||
|
of "uint32":
|
||||||
|
result[1] = ident("pint")
|
||||||
|
of "uint64":
|
||||||
|
result[1] = ident("pint")
|
||||||
|
of "sint32":
|
||||||
|
result[1] = ident("sint")
|
||||||
|
result[0] = ident("int32")
|
||||||
|
of "sint64":
|
||||||
|
result[1] = ident("sint")
|
||||||
|
result[0] = ident("int64")
|
||||||
|
of "fixed32":
|
||||||
|
result[1] = ident("fixed")
|
||||||
|
result[0] = ident("uint32")
|
||||||
|
of "fixed64":
|
||||||
|
result[1] = ident("fixed")
|
||||||
|
result[0] = ident("uint64")
|
||||||
|
of "sfixed32":
|
||||||
|
result[1] = ident("fixed")
|
||||||
|
result[0] = ident("int32")
|
||||||
|
of "sfixed64":
|
||||||
|
result[1] = ident("fixed")
|
||||||
|
result[0] = ident("int64")
|
||||||
|
of "bytes":
|
||||||
|
result[0] = newNimNode(nnkBracketExpr).add(
|
||||||
|
ident("seq"),
|
||||||
|
ident("byte")
|
||||||
|
)
|
||||||
|
|
||||||
|
proc getMessage(name: string, messages: seq[ProtoNode]): ProtoNode =
|
||||||
|
for msg in messages:
|
||||||
|
if msg.kind == ProtoType.Extend:
|
||||||
|
continue
|
||||||
|
if name == msg.messageName:
|
||||||
|
return msg
|
||||||
|
let res = name.getMessage(msg.nested)
|
||||||
|
if not res.isNil():
|
||||||
|
return res
|
||||||
|
return nil
|
||||||
|
|
||||||
|
proc isNested(base: string, currentName: string, messages: seq[ProtoNode]): bool =
|
||||||
|
let msg = currentName.getMessage(messages)
|
||||||
|
if msg.isNil():
|
||||||
|
return false
|
||||||
|
for field in msg.fields:
|
||||||
|
if field.kind == ProtoType.Field:
|
||||||
|
if field.presence == Repeated: continue
|
||||||
|
if base == field.protoType or base.isNested(field.protoType, messages):
|
||||||
|
return true
|
||||||
|
elif field.kind == ProtoType.Oneof:
|
||||||
|
for f in field.oneof:
|
||||||
|
if f.presence == Repeated: continue
|
||||||
|
if base == f.protoType or base.isNested(f.protoType, messages):
|
||||||
|
return true
|
||||||
|
|
||||||
# Exported for the tests.
|
# Exported for the tests.
|
||||||
proc protoToTypesInternal*(filepath: string): NimNode =
|
proc protoToTypesInternal*(filepath: string): NimNode {.compileTime.} =
|
||||||
var
|
var
|
||||||
packages: seq[ProtoNode] = parseProtobuf(filepath).packages
|
packages: seq[ProtoNode] = parseProtobuf(filepath).packages
|
||||||
queue: seq[ProtoNode] = @[]
|
queue: seq[ProtoNode] = @[]
|
||||||
|
@ -23,21 +86,24 @@ proc protoToTypesInternal*(filepath: string): NimNode =
|
||||||
name: string
|
name: string
|
||||||
value: NimNode
|
value: NimNode
|
||||||
if next.kind == ProtoType.Enum:
|
if next.kind == ProtoType.Enum:
|
||||||
|
# TODO: allow_alias
|
||||||
|
var alreadySeen: seq[int] = @[]
|
||||||
name = next.enumName
|
name = next.enumName
|
||||||
value = newNimNode(nnkEnumTy).add(newEmptyNode())
|
value = newNimNode(nnkEnumTy).add(newEmptyNode())
|
||||||
for enumField in next.values:
|
for enumField in next.values.sortedByIt(it.num):
|
||||||
|
if enumField.num in alreadySeen:
|
||||||
|
continue
|
||||||
|
alreadySeen.add(enumField.num)
|
||||||
value.add(newNimNode(nnkEnumFieldDef).add(
|
value.add(newNimNode(nnkEnumFieldDef).add(
|
||||||
ident(enumField.fieldName),
|
ident(enumField.fieldName),
|
||||||
newIntLitNode(enumField.num)
|
newIntLitNode(enumField.num)
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
|
if next.kind == ProtoType.Extend:
|
||||||
|
continue
|
||||||
if (next.definedEnums.len != 0) or (next.nested.len != 0):
|
if (next.definedEnums.len != 0) or (next.nested.len != 0):
|
||||||
queue.add(next)
|
|
||||||
for nestee in (next.definedEnums & next.nested):
|
for nestee in (next.definedEnums & next.nested):
|
||||||
queue.add(nestee)
|
queue.add(nestee)
|
||||||
next.definedEnums = @[]
|
|
||||||
next.nested = @[]
|
|
||||||
continue
|
|
||||||
|
|
||||||
name = next.messageName
|
name = next.messageName
|
||||||
value = newNimNode(nnkObjectTy).add(
|
value = newNimNode(nnkObjectTy).add(
|
||||||
|
@ -45,8 +111,16 @@ proc protoToTypesInternal*(filepath: string): NimNode =
|
||||||
newEmptyNode(),
|
newEmptyNode(),
|
||||||
newNimNode(nnkRecList)
|
newNimNode(nnkRecList)
|
||||||
)
|
)
|
||||||
|
var fieldsQueue: seq[ProtoNode] = @[]
|
||||||
for field in next.fields:
|
for field in next.fields:
|
||||||
|
fieldsQueue.add(field)
|
||||||
|
while fieldsQueue.len != 0:
|
||||||
|
let field = fieldsQueue.pop()
|
||||||
|
if field.kind == Oneof:
|
||||||
|
# TODO: ATM the oneof is ignored. Find a way to make it work
|
||||||
|
for f in field.oneof:
|
||||||
|
fieldsQueue.add(f)
|
||||||
|
continue
|
||||||
value[2].add(newNimNode(nnkIdentDefs).add(
|
value[2].add(newNimNode(nnkIdentDefs).add(
|
||||||
newNimNode(nnkPragmaExpr).add(
|
newNimNode(nnkPragmaExpr).add(
|
||||||
newNimNode(nnkPostfix).add(
|
newNimNode(nnkPostfix).add(
|
||||||
|
@ -64,69 +138,49 @@ proc protoToTypesInternal*(filepath: string): NimNode =
|
||||||
newEmptyNode()
|
newEmptyNode()
|
||||||
))
|
))
|
||||||
|
|
||||||
var repeated: int = 0
|
var isReference = false
|
||||||
|
for parsed in packages:
|
||||||
|
if next.messageName.isNested(field.protoType, parsed.messages):
|
||||||
|
isReference = true
|
||||||
|
break
|
||||||
|
|
||||||
|
if value[2][^1][1].strVal.startsWith("map<"):
|
||||||
|
var matches = value[2][^1][1].strVal.split({'<', '>', ','})
|
||||||
|
let (typ1, _) = getTypeAndPragma(matches[1])
|
||||||
|
let (typ2, _) = getTypeAndPragma(matches[2])
|
||||||
|
value[2][^1][1] = nnkBracketExpr.newTree(newIdentNode("Table"), typ1, typ2)
|
||||||
|
else:
|
||||||
|
let (typ, pragma) = getTypeAndPragma(value[2][^1][1].strVal)
|
||||||
|
value[2][^1][1] = typ
|
||||||
|
if not pragma.isNil():
|
||||||
|
value[2][^1][0][1].add(pragma)
|
||||||
|
|
||||||
if field.presence == Repeated:
|
if field.presence == Repeated:
|
||||||
repeated = 1
|
|
||||||
|
|
||||||
case value[2][^1][1].strVal:
|
|
||||||
of "double":
|
|
||||||
value[2][^1][0][1].add(ident("pfloat64"))
|
|
||||||
value[2][^1][1] = ident("float32")
|
|
||||||
of "float32":
|
|
||||||
value[2][^1][0][1].add(ident("pfloat32"))
|
|
||||||
of "int32":
|
|
||||||
value[2][^1][0][1].add(ident("pint"))
|
|
||||||
of "int64":
|
|
||||||
value[2][^1][0][1].add(ident("pint"))
|
|
||||||
of "uint32":
|
|
||||||
value[2][^1][0][1].add(ident("pint"))
|
|
||||||
of "uint64":
|
|
||||||
value[2][^1][0][1].add(ident("pint"))
|
|
||||||
of "sint32":
|
|
||||||
value[2][^1][0][1].add(ident("sint"))
|
|
||||||
value[2][^1][1] = ident("int32")
|
|
||||||
of "sint64":
|
|
||||||
value[2][^1][0][1].add(ident("sint"))
|
|
||||||
value[2][^1][1] = ident("int64")
|
|
||||||
of "fixed32":
|
|
||||||
value[2][^1][0][1].add(ident("fixed"))
|
|
||||||
value[2][^1][1] = ident("uint32")
|
|
||||||
of "fixed64":
|
|
||||||
value[2][^1][0][1].add(ident("fixed"))
|
|
||||||
value[2][^1][1] = ident("uint64")
|
|
||||||
of "sfixed32":
|
|
||||||
value[2][^1][0][1].add(ident("fixed"))
|
|
||||||
value[2][^1][1] = ident("int32")
|
|
||||||
of "sfixed64":
|
|
||||||
value[2][^1][0][1].add(ident("fixed"))
|
|
||||||
value[2][^1][1] = ident("int64")
|
|
||||||
of "bool":
|
|
||||||
discard
|
|
||||||
of "string":
|
|
||||||
discard
|
|
||||||
of "bytes":
|
|
||||||
repeated += 1
|
|
||||||
value[2][^1][1] = ident("byte")
|
|
||||||
|
|
||||||
for _ in 0 ..< repeated:
|
|
||||||
value[2][^1][1] = newNimNode(nnkBracketExpr).add(
|
value[2][^1][1] = newNimNode(nnkBracketExpr).add(
|
||||||
ident("seq"),
|
ident("seq"),
|
||||||
value[2][^1][1]
|
value[2][^1][1]
|
||||||
)
|
)
|
||||||
|
elif isReference:
|
||||||
|
value[2][^1][1] = newNimNode(nnkRefTy).add(value[2][^1][1])
|
||||||
if value[2].len == 0:
|
if value[2].len == 0:
|
||||||
value[2] = newEmptyNode()
|
value[2] = newEmptyNode()
|
||||||
|
|
||||||
|
|
||||||
result.add(
|
result.add(
|
||||||
newNimNode(nnkTypeDef).add(
|
newNimNode(nnkTypeDef).add(
|
||||||
newNimNode(nnkPragmaExpr).add(
|
newNimNode(nnkPragmaExpr).add(
|
||||||
newNimNode(nnkPostfix).add(ident("*"), ident(name)),
|
newNimNode(nnkPostfix).add(ident("*"), ident(name)),
|
||||||
|
if next.kind == ProtoType.Enum:
|
||||||
|
newNimNode(nnkPragma).add(ident("pure"), ident("proto3"))
|
||||||
|
else:
|
||||||
newNimNode(nnkPragma).add(ident("proto3"))
|
newNimNode(nnkPragma).add(ident("proto3"))
|
||||||
),
|
),
|
||||||
newEmptyNode(),
|
newEmptyNode(),
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
when defined(LogGeneratedTypes):
|
||||||
|
result.storeMacroResult(true)
|
||||||
|
|
||||||
macro protoToTypes*(filepath: static[string]): untyped =
|
macro protoToTypes*(filepath: static[string]): untyped =
|
||||||
result = protoToTypesInternal(filepath)
|
result = protoToTypesInternal(filepath)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#Variables needed by the Reader and Writer which should NOT be exported outside of this library.
|
#Variables needed by the Reader and Writer which should NOT be exported outside of this library.
|
||||||
|
|
||||||
import std/[options, sets]
|
import std/[options, sets, tables]
|
||||||
import stew/shims/macros
|
import stew/shims/macros
|
||||||
#Depending on the situation, one of these two are used.
|
#Depending on the situation, one of these two are used.
|
||||||
#Sometimes, one works where the other doesn't.
|
#Sometimes, one works where the other doesn't.
|
||||||
|
@ -115,12 +115,16 @@ template protoType*(InnerType, RootType, FieldType: untyped, fieldName: untyped)
|
||||||
type InnerType = pstring
|
type InnerType = pstring
|
||||||
elif FlatType is seq[byte]:
|
elif FlatType is seq[byte]:
|
||||||
type InnerType = pbytes
|
type InnerType = pbytes
|
||||||
elif FlatType is object:
|
elif FlatType is enum:
|
||||||
|
type InnerType = penum
|
||||||
|
elif FlatType is object or FlatType is ref:
|
||||||
type InnerType = FieldType
|
type InnerType = FieldType
|
||||||
else:
|
else:
|
||||||
type InnerType = UnsupportedType[FieldType, RootType, fieldName]
|
type InnerType = UnsupportedType[FieldType, RootType, fieldName]
|
||||||
|
|
||||||
template elementType[T](_: type seq[T]): type = typeof(T)
|
template elementType[T](_: type seq[T]): type = typeof(T)
|
||||||
|
template elementTypeKey[K, V](_: type Table[K, V]): type = typeof(K)
|
||||||
|
template elementTypeVal[K, V](_: type Table[K, V]): type = typeof(V)
|
||||||
|
|
||||||
func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =
|
func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =
|
||||||
type FlatType = flatType(default(T))
|
type FlatType = flatType(default(T))
|
||||||
|
@ -128,7 +132,18 @@ func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =
|
||||||
{.fatal: $T & ": Serializing a number requires specifying the amount of bits via the type.".}
|
{.fatal: $T & ": Serializing a number requires specifying the amount of bits via the type.".}
|
||||||
elif FlatType is seq:
|
elif FlatType is seq:
|
||||||
when FlatType isnot seq[byte]:
|
when FlatType isnot seq[byte]:
|
||||||
|
when defined(ConformanceTest):
|
||||||
|
return # TODO make it work in case of recursivity
|
||||||
|
# type List = object (value: Value)
|
||||||
|
# type Value = object (list: List)
|
||||||
|
else:
|
||||||
verifySerializable(elementType(FlatType))
|
verifySerializable(elementType(FlatType))
|
||||||
|
elif FlatType is Table and defined(ConformanceTest):
|
||||||
|
return # TODO make it work in case of recursivity
|
||||||
|
# type Struct = object (map: Table[..., Value])
|
||||||
|
# type Value = object (struct: Struct)
|
||||||
|
# verifySerializable(elementTypeKey(FlatType))
|
||||||
|
# verifySerializable(elementTypeVal(FlatType))
|
||||||
elif FlatType is object and T isnot PBOption:
|
elif FlatType is object and T isnot PBOption:
|
||||||
var
|
var
|
||||||
inst: T
|
inst: T
|
||||||
|
@ -138,7 +153,7 @@ func verifySerializable*[T](ty: typedesc[T]) {.compileTime.} =
|
||||||
isProto2 = T.isProto2()
|
isProto2 = T.isProto2()
|
||||||
isProto3 = T.isProto3()
|
isProto3 = T.isProto3()
|
||||||
when isProto2 == isProto3:
|
when isProto2 == isProto3:
|
||||||
{.fatal: $T & ": missing {.proto2.} or {.proto3}".}
|
{.fatal: $T & ": missing {.proto2.} or {.proto3.}".}
|
||||||
|
|
||||||
enumInstanceSerializedFields(inst, fieldName, fieldVar):
|
enumInstanceSerializedFields(inst, fieldName, fieldVar):
|
||||||
when isProto2 and not T.isRequired(fieldName):
|
when isProto2 and not T.isRequired(fieldName):
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#Parses the Protobuf binary wire protocol into the specified type.
|
#Parses the Protobuf binary wire protocol into the specified type.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[typetraits, sets],
|
std/[typetraits, sets, tables],
|
||||||
stew/assign2,
|
stew/assign2,
|
||||||
|
stew/objects,
|
||||||
stew/shims/macros,
|
stew/shims/macros,
|
||||||
faststreams/inputs,
|
faststreams/inputs,
|
||||||
serialization,
|
serialization,
|
||||||
|
@ -22,7 +23,7 @@ template requireKind(header: FieldHeader, expected: WireKind) =
|
||||||
msg: "Unexpected data kind " & $(header.number()) & ": " & $header.kind() &
|
msg: "Unexpected data kind " & $(header.number()) & ": " & $header.kind() &
|
||||||
", exprected " & $expected)
|
", exprected " & $expected)
|
||||||
|
|
||||||
proc readFieldInto[T: object](
|
proc readFieldInto[T: object and not Table](
|
||||||
stream: InputStream,
|
stream: InputStream,
|
||||||
value: var T,
|
value: var T,
|
||||||
header: FieldHeader,
|
header: FieldHeader,
|
||||||
|
@ -42,7 +43,54 @@ proc readFieldInto[T: object](
|
||||||
raise (ref ValueError)(msg: "not enough bytes")
|
raise (ref ValueError)(msg: "not enough bytes")
|
||||||
memoryInput(tmp).readValueInternal(value)
|
memoryInput(tmp).readValueInternal(value)
|
||||||
|
|
||||||
proc readFieldInto[T: not object and (seq[byte] or not seq)](
|
when defined(ConformanceTest):
|
||||||
|
proc readFieldInto[T: enum](
|
||||||
|
stream: InputStream,
|
||||||
|
value: var T,
|
||||||
|
header: FieldHeader,
|
||||||
|
ProtoType: type
|
||||||
|
) =
|
||||||
|
# TODO: This function doesn't work for proto2 edge cases. Make it work
|
||||||
|
when 0 notin T and T.isProto3():
|
||||||
|
{.fatal: $T & " definition must contain a constant that maps to zero".}
|
||||||
|
header.requireKind(WireKind.Varint)
|
||||||
|
let enumValue = stream.readValue(ProtoType)
|
||||||
|
if not checkedEnumAssign(value, enumValue.int32):
|
||||||
|
discard checkedEnumAssign(value, 0)
|
||||||
|
|
||||||
|
proc readFieldInto[K, V](
|
||||||
|
stream: InputStream,
|
||||||
|
value: var Table[K, V],
|
||||||
|
header: FieldHeader,
|
||||||
|
ProtoType: type
|
||||||
|
) =
|
||||||
|
# I know it's ugly, but I cannot find a clean way to do it
|
||||||
|
# ... And nobody cares about map
|
||||||
|
when K is SomePBInt and V is SomePBInt:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1, pint.}: K
|
||||||
|
value {.fieldNumber: 2, pint.}: V
|
||||||
|
elif K is SomePBInt:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1, pint.}: K
|
||||||
|
value {.fieldNumber: 2.}: V
|
||||||
|
elif V is SomePBInt:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1.}: K
|
||||||
|
value {.fieldNumber: 2, pint.}: V
|
||||||
|
else:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1.}: K
|
||||||
|
value {.fieldNumber: 2.}: V
|
||||||
|
var tmp = default(TableObject)
|
||||||
|
stream.readFieldInto(tmp, header, ProtoType)
|
||||||
|
value[tmp.key] = tmp.value
|
||||||
|
|
||||||
|
proc readFieldInto[T: not object and not enum and (seq[byte] or not seq)](
|
||||||
stream: InputStream,
|
stream: InputStream,
|
||||||
value: var T,
|
value: var T,
|
||||||
header: FieldHeader,
|
header: FieldHeader,
|
||||||
|
@ -98,8 +146,7 @@ proc readFieldPackedInto[T](
|
||||||
elif ProtoType is SomeFixed32:
|
elif ProtoType is SomeFixed32:
|
||||||
WireKind.Fixed32
|
WireKind.Fixed32
|
||||||
else:
|
else:
|
||||||
static: doAssert ProtoType is SomeFixed64
|
WireKind.Fixed64
|
||||||
ProtoType.SomeFixed64
|
|
||||||
|
|
||||||
inner.readFieldInto(value[^1], FieldHeader.init(header.number, kind), ProtoType)
|
inner.readFieldInto(value[^1], FieldHeader.init(header.number, kind), ProtoType)
|
||||||
|
|
||||||
|
@ -137,6 +184,9 @@ proc readValueInternal[T: object](stream: InputStream, value: var T, silent: boo
|
||||||
stream.readFieldPackedInto(fieldVar, header, ProtoType)
|
stream.readFieldPackedInto(fieldVar, header, ProtoType)
|
||||||
else:
|
else:
|
||||||
stream.readFieldInto(fieldVar, header, ProtoType)
|
stream.readFieldInto(fieldVar, header, ProtoType)
|
||||||
|
elif ProtoType is ref and defined(ConformanceTest):
|
||||||
|
fieldVar = new ProtoType
|
||||||
|
stream.readFieldInto(fieldVar[], header, ProtoType)
|
||||||
else:
|
else:
|
||||||
stream.readFieldInto(fieldVar, header, ProtoType)
|
stream.readFieldInto(fieldVar, header, ProtoType)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#Writes the specified type into a buffer using the Protobuf binary wire format.
|
#Writes the specified type into a buffer using the Protobuf binary wire format.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/typetraits,
|
std/[typetraits, tables],
|
||||||
stew/shims/macros,
|
stew/shims/macros,
|
||||||
|
stew/objects,
|
||||||
faststreams/outputs,
|
faststreams/outputs,
|
||||||
serialization,
|
serialization,
|
||||||
"."/[codec, internal, types]
|
"."/[codec, internal, types]
|
||||||
|
@ -28,7 +29,7 @@ proc writeField[T: object and not PBOption](
|
||||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||||
stream.writeField(fieldNum, fieldVal)
|
stream.writeField(fieldNum, fieldVal)
|
||||||
|
|
||||||
proc writeField[T: not object](
|
proc writeField[T: not object and not enum](
|
||||||
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||||
stream.writeField(fieldNum, ProtoType(fieldVal))
|
stream.writeField(fieldNum, ProtoType(fieldVal))
|
||||||
|
|
||||||
|
@ -67,6 +68,43 @@ proc writeFieldPacked*[T: not byte, ProtoType: SomePrimitive](
|
||||||
for value in values:
|
for value in values:
|
||||||
output.write(toBytes(ProtoType(value)))
|
output.write(toBytes(ProtoType(value)))
|
||||||
|
|
||||||
|
when defined(ConformanceTest):
|
||||||
|
proc writeField[T: enum](
|
||||||
|
stream: OutputStream, fieldNum: int, fieldVal: T, ProtoType: type) =
|
||||||
|
when 0 notin T:
|
||||||
|
{.fatal: $T & " definition must contain a constant that maps to zero".}
|
||||||
|
stream.writeField(fieldNum, pint32(fieldVal.ord()))
|
||||||
|
|
||||||
|
proc writeField*[K, V](
|
||||||
|
stream: OutputStream,
|
||||||
|
fieldNum: int,
|
||||||
|
value: Table[K, V],
|
||||||
|
ProtoType: type
|
||||||
|
) =
|
||||||
|
when K is SomePBInt and V is SomePBInt:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1, pint.}: K
|
||||||
|
value {.fieldNumber: 2, pint.}: V
|
||||||
|
elif K is SomePBInt:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1, pint.}: K
|
||||||
|
value {.fieldNumber: 2.}: V
|
||||||
|
elif V is SomePBInt:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1.}: K
|
||||||
|
value {.fieldNumber: 2, pint.}: V
|
||||||
|
else:
|
||||||
|
type
|
||||||
|
TableObject {.proto3.} = object
|
||||||
|
key {.fieldNumber: 1.}: K
|
||||||
|
value {.fieldNumber: 2.}: V
|
||||||
|
for k, v in value.pairs():
|
||||||
|
let tmp = TableObject(key: k, value: v)
|
||||||
|
stream.writeField(fieldNum, tmp, ProtoType)
|
||||||
|
|
||||||
proc writeValue*[T: object](stream: OutputStream, value: T) =
|
proc writeValue*[T: object](stream: OutputStream, value: T) =
|
||||||
const
|
const
|
||||||
isProto2: bool = T.isProto2()
|
isProto2: bool = T.isProto2()
|
||||||
|
@ -94,6 +132,9 @@ proc writeValue*[T: object](stream: OutputStream, value: T) =
|
||||||
elif FlatType is object:
|
elif FlatType is object:
|
||||||
# TODO avoid writing empty objects in proto3
|
# TODO avoid writing empty objects in proto3
|
||||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
stream.writeField(fieldNum, fieldVal, ProtoType)
|
||||||
|
elif FlatType is ref and defined(ConformanceTest):
|
||||||
|
if not fieldVal.isNil():
|
||||||
|
stream.writeField(fieldNum, fieldVal[], ProtoType)
|
||||||
else:
|
else:
|
||||||
when isProto2:
|
when isProto2:
|
||||||
stream.writeField(fieldNum, fieldVal, ProtoType)
|
stream.writeField(fieldNum, fieldVal, ProtoType)
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package conformance;
|
||||||
|
|
||||||
|
option java_package = "com.google.protobuf.conformance";
|
||||||
|
option objc_class_prefix = "Conformance";
|
||||||
|
|
||||||
|
// This defines the conformance testing protocol. This protocol exists between
|
||||||
|
// the conformance test suite itself and the code being tested. For each test,
|
||||||
|
// the suite will send a ConformanceRequest message and expect a
|
||||||
|
// ConformanceResponse message.
|
||||||
|
//
|
||||||
|
// You can either run the tests in two different ways:
|
||||||
|
//
|
||||||
|
// 1. in-process (using the interface in conformance_test.h).
|
||||||
|
//
|
||||||
|
// 2. as a sub-process communicating over a pipe. Information about how to
|
||||||
|
// do this is in conformance_test_runner.cc.
|
||||||
|
//
|
||||||
|
// Pros/cons of the two approaches:
|
||||||
|
//
|
||||||
|
// - running as a sub-process is much simpler for languages other than C/C++.
|
||||||
|
//
|
||||||
|
// - running as a sub-process may be more tricky in unusual environments like
|
||||||
|
// iOS apps, where fork/stdin/stdout are not available.
|
||||||
|
|
||||||
|
enum WireFormat {
|
||||||
|
UNSPECIFIED = 0;
|
||||||
|
PROTOBUF = 1;
|
||||||
|
JSON = 2;
|
||||||
|
JSPB = 3; // Only used inside Google. Opensource testees just skip it.
|
||||||
|
TEXT_FORMAT = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestCategory {
|
||||||
|
UNSPECIFIED_TEST = 0;
|
||||||
|
BINARY_TEST = 1; // Test binary wire format.
|
||||||
|
JSON_TEST = 2; // Test json wire format.
|
||||||
|
// Similar to JSON_TEST. However, during parsing json, testee should ignore
|
||||||
|
// unknown fields. This feature is optional. Each implementation can decide
|
||||||
|
// whether to support it. See
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json_options
|
||||||
|
// for more detail.
|
||||||
|
JSON_IGNORE_UNKNOWN_PARSING_TEST = 3;
|
||||||
|
// Test jspb wire format. Only used inside Google. Opensource testees just
|
||||||
|
// skip it.
|
||||||
|
JSPB_TEST = 4;
|
||||||
|
// Test text format. For cpp, java and python, testees can already deal with
|
||||||
|
// this type. Testees of other languages can simply skip it.
|
||||||
|
TEXT_FORMAT_TEST = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The conformance runner will request a list of failures as the first request.
|
||||||
|
// This will be known by message_type == "conformance.FailureSet", a conformance
|
||||||
|
// test should return a serialized FailureSet in protobuf_payload.
|
||||||
|
message FailureSet {
|
||||||
|
repeated string failure = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents a single test case's input. The testee should:
|
||||||
|
//
|
||||||
|
// 1. parse this proto (which should always succeed)
|
||||||
|
// 2. parse the protobuf or JSON payload in "payload" (which may fail)
|
||||||
|
// 3. if the parse succeeded, serialize the message in the requested format.
|
||||||
|
message ConformanceRequest {
|
||||||
|
// The payload (whether protobuf of JSON) is always for a
|
||||||
|
// protobuf_test_messages.proto3.TestAllTypes proto (as defined in
|
||||||
|
// src/google/protobuf/proto3_test_messages.proto).
|
||||||
|
oneof payload {
|
||||||
|
bytes protobuf_payload = 1;
|
||||||
|
string json_payload = 2;
|
||||||
|
// Only used inside Google. Opensource testees just skip it.
|
||||||
|
string jspb_payload = 7;
|
||||||
|
string text_payload = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Which format should the testee serialize its message to?
|
||||||
|
WireFormat requested_output_format = 3;
|
||||||
|
|
||||||
|
// The full name for the test message to use; for the moment, either:
|
||||||
|
// protobuf_test_messages.proto3.TestAllTypesProto3 or
|
||||||
|
// protobuf_test_messages.google.protobuf.TestAllTypesProto2.
|
||||||
|
string message_type = 4;
|
||||||
|
|
||||||
|
// Each test is given a specific test category. Some category may need
|
||||||
|
// specific support in testee programs. Refer to the definition of
|
||||||
|
// TestCategory for more information.
|
||||||
|
TestCategory test_category = 5;
|
||||||
|
|
||||||
|
// Specify details for how to encode jspb.
|
||||||
|
JspbEncodingConfig jspb_encoding_options = 6;
|
||||||
|
|
||||||
|
// This can be used in json and text format. If true, testee should print
|
||||||
|
// unknown fields instead of ignore. This feature is optional.
|
||||||
|
bool print_unknown_fields = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents a single test case's output.
|
||||||
|
message ConformanceResponse {
|
||||||
|
oneof result {
|
||||||
|
// This string should be set to indicate parsing failed. The string can
|
||||||
|
// provide more information about the parse error if it is available.
|
||||||
|
//
|
||||||
|
// Setting this string does not necessarily mean the testee failed the
|
||||||
|
// test. Some of the test cases are intentionally invalid input.
|
||||||
|
string parse_error = 1;
|
||||||
|
|
||||||
|
// If the input was successfully parsed but errors occurred when
|
||||||
|
// serializing it to the requested output format, set the error message in
|
||||||
|
// this field.
|
||||||
|
string serialize_error = 6;
|
||||||
|
|
||||||
|
// This should be set if the test program timed out. The string should
|
||||||
|
// provide more information about what the child process was doing when it
|
||||||
|
// was killed.
|
||||||
|
string timeout_error = 9;
|
||||||
|
|
||||||
|
// This should be set if some other error occurred. This will always
|
||||||
|
// indicate that the test failed. The string can provide more information
|
||||||
|
// about the failure.
|
||||||
|
string runtime_error = 2;
|
||||||
|
|
||||||
|
// If the input was successfully parsed and the requested output was
|
||||||
|
// protobuf, serialize it to protobuf and set it in this field.
|
||||||
|
bytes protobuf_payload = 3;
|
||||||
|
|
||||||
|
// If the input was successfully parsed and the requested output was JSON,
|
||||||
|
// serialize to JSON and set it in this field.
|
||||||
|
string json_payload = 4;
|
||||||
|
|
||||||
|
// For when the testee skipped the test, likely because a certain feature
|
||||||
|
// wasn't supported, like JSON input/output.
|
||||||
|
string skipped = 5;
|
||||||
|
|
||||||
|
// If the input was successfully parsed and the requested output was JSPB,
|
||||||
|
// serialize to JSPB and set it in this field. JSPB is only used inside
|
||||||
|
// Google. Opensource testees can just skip it.
|
||||||
|
string jspb_payload = 7;
|
||||||
|
|
||||||
|
// If the input was successfully parsed and the requested output was
|
||||||
|
// TEXT_FORMAT, serialize to TEXT_FORMAT and set it in this field.
|
||||||
|
string text_payload = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoding options for jspb format.
|
||||||
|
message JspbEncodingConfig {
|
||||||
|
// Encode the value field of Any as jspb array if true, otherwise binary.
|
||||||
|
bool use_jspb_array_any_format = 1;
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
import os
|
||||||
|
import ../../protobuf_serialization
|
||||||
|
import ../../protobuf_serialization/files/type_generator
|
||||||
|
import stew/byteutils
|
||||||
|
import_proto3 "conformance.proto"
|
||||||
|
import test_proto2
|
||||||
|
import test_proto3
|
||||||
|
|
||||||
|
proc readIntLE(): int32 =
|
||||||
|
if stdin.readBuffer(addr(result), 4) != 4:
|
||||||
|
raise newException(IOError, "readInt error")
|
||||||
|
|
||||||
|
proc writeIntLE(v: int32) =
|
||||||
|
var value = v
|
||||||
|
if stdout.writeBuffer(addr(value), 4) != 4:
|
||||||
|
raise newException(IOError, "writeInt error")
|
||||||
|
|
||||||
|
proc doTest() =
|
||||||
|
let length = readIntLE()
|
||||||
|
|
||||||
|
var serializedRequest = newSeq[byte](length)
|
||||||
|
if stdin.readBuffer(addr(serializedRequest[0]), length) != length:
|
||||||
|
raise newException(IOError, "IProtobuf./O error")
|
||||||
|
|
||||||
|
let request = Protobuf.decode(serializedRequest, ConformanceRequest)
|
||||||
|
|
||||||
|
var response = ConformanceResponse()
|
||||||
|
|
||||||
|
if request.requested_output_format != WireFormat.PROTOBUF or
|
||||||
|
request.protobuf_payload.len() == 0:
|
||||||
|
response.skipped = "skip not protobuf"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if request.message_type == "protobuf_test_messages.proto3.TestAllTypesProto3":
|
||||||
|
let x = Protobuf.decode(request.protobuf_payload, TestAllTypesProto3)
|
||||||
|
response.protobuf_payload = Protobuf.encode(x)
|
||||||
|
elif request.message_type == "protobuf_test_messages.proto2.TestAllTypesProto2":
|
||||||
|
let x = Protobuf.decode(request.protobuf_payload, TestAllTypesProto2)
|
||||||
|
response.protobuf_payload = Protobuf.encode(x)
|
||||||
|
else:
|
||||||
|
response.skipped = "skip unknown message type: " & request.message_type
|
||||||
|
except Exception as exc:
|
||||||
|
response.parse_error = exc.msg
|
||||||
|
|
||||||
|
let serializedResponse = Protobuf.encode(response)
|
||||||
|
|
||||||
|
writeIntLE(serializedResponse.len().int32)
|
||||||
|
|
||||||
|
stdout.write(string.fromBytes(serializedResponse))
|
||||||
|
stdout.flushFile()
|
||||||
|
|
||||||
|
while true:
|
||||||
|
try:
|
||||||
|
doTest()
|
||||||
|
except IOError as exc:
|
||||||
|
stderr.writeLine(exc.msg)
|
||||||
|
break
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,303 @@
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// Test schema for proto2 messages. This test schema is used by:
|
||||||
|
//
|
||||||
|
// - conformance tests
|
||||||
|
//
|
||||||
|
|
||||||
|
// LINT: ALLOW_GROUPS
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package protobuf_test_messages.proto2;
|
||||||
|
|
||||||
|
option java_package = "com.google.protobuf_test_messages.proto2";
|
||||||
|
option objc_class_prefix = "Proto2";
|
||||||
|
|
||||||
|
// This is the default, but we specify it here explicitly.
|
||||||
|
option optimize_for = SPEED;
|
||||||
|
|
||||||
|
option cc_enable_arenas = true;
|
||||||
|
|
||||||
|
// This proto includes every type of field in both singular and repeated
|
||||||
|
// forms.
|
||||||
|
//
|
||||||
|
// Also, crucially, all messages and enums in this file are eventually
|
||||||
|
// submessages of this message. So for example, a fuzz test of TestAllTypes
|
||||||
|
// could trigger bugs that occur in any message type in this file. We verify
|
||||||
|
// this stays true in a unit test.
|
||||||
|
message TestAllTypesProto2 {
|
||||||
|
message NestedMessage {
|
||||||
|
optional int32 a = 1;
|
||||||
|
optional TestAllTypesProto2 corecursive = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NestedEnum {
|
||||||
|
FOO = 0;
|
||||||
|
BAR = 1;
|
||||||
|
BAZ = 2;
|
||||||
|
NEG = -1; // Intentionally negative.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Singular
|
||||||
|
optional int32 optional_int32 = 1;
|
||||||
|
optional int64 optional_int64 = 2;
|
||||||
|
optional uint32 optional_uint32 = 3;
|
||||||
|
optional uint64 optional_uint64 = 4;
|
||||||
|
optional sint32 optional_sint32 = 5;
|
||||||
|
optional sint64 optional_sint64 = 6;
|
||||||
|
optional fixed32 optional_fixed32 = 7;
|
||||||
|
optional fixed64 optional_fixed64 = 8;
|
||||||
|
optional sfixed32 optional_sfixed32 = 9;
|
||||||
|
optional sfixed64 optional_sfixed64 = 10;
|
||||||
|
optional float optional_float = 11;
|
||||||
|
optional double optional_double = 12;
|
||||||
|
optional bool optional_bool = 13;
|
||||||
|
optional string optional_string = 14;
|
||||||
|
optional bytes optional_bytes = 15;
|
||||||
|
|
||||||
|
optional NestedMessage optional_nested_message = 18;
|
||||||
|
optional ForeignMessageProto2 optional_foreign_message = 19;
|
||||||
|
|
||||||
|
optional NestedEnum optional_nested_enum = 21;
|
||||||
|
optional ForeignEnumProto2 optional_foreign_enum = 22;
|
||||||
|
|
||||||
|
optional string optional_string_piece = 24 [ctype = STRING_PIECE];
|
||||||
|
optional string optional_cord = 25 [ctype = CORD];
|
||||||
|
|
||||||
|
optional TestAllTypesProto2 recursive_message = 27;
|
||||||
|
|
||||||
|
// Repeated
|
||||||
|
repeated int32 repeated_int32 = 31;
|
||||||
|
repeated int64 repeated_int64 = 32;
|
||||||
|
repeated uint32 repeated_uint32 = 33;
|
||||||
|
repeated uint64 repeated_uint64 = 34;
|
||||||
|
repeated sint32 repeated_sint32 = 35;
|
||||||
|
repeated sint64 repeated_sint64 = 36;
|
||||||
|
repeated fixed32 repeated_fixed32 = 37;
|
||||||
|
repeated fixed64 repeated_fixed64 = 38;
|
||||||
|
repeated sfixed32 repeated_sfixed32 = 39;
|
||||||
|
repeated sfixed64 repeated_sfixed64 = 40;
|
||||||
|
repeated float repeated_float = 41;
|
||||||
|
repeated double repeated_double = 42;
|
||||||
|
repeated bool repeated_bool = 43;
|
||||||
|
repeated string repeated_string = 44;
|
||||||
|
repeated bytes repeated_bytes = 45;
|
||||||
|
|
||||||
|
repeated NestedMessage repeated_nested_message = 48;
|
||||||
|
repeated ForeignMessageProto2 repeated_foreign_message = 49;
|
||||||
|
|
||||||
|
repeated NestedEnum repeated_nested_enum = 51;
|
||||||
|
repeated ForeignEnumProto2 repeated_foreign_enum = 52;
|
||||||
|
|
||||||
|
repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
|
||||||
|
repeated string repeated_cord = 55 [ctype = CORD];
|
||||||
|
|
||||||
|
// Packed
|
||||||
|
repeated int32 packed_int32 = 75 [packed = true];
|
||||||
|
repeated int64 packed_int64 = 76 [packed = true];
|
||||||
|
repeated uint32 packed_uint32 = 77 [packed = true];
|
||||||
|
repeated uint64 packed_uint64 = 78 [packed = true];
|
||||||
|
repeated sint32 packed_sint32 = 79 [packed = true];
|
||||||
|
repeated sint64 packed_sint64 = 80 [packed = true];
|
||||||
|
repeated fixed32 packed_fixed32 = 81 [packed = true];
|
||||||
|
repeated fixed64 packed_fixed64 = 82 [packed = true];
|
||||||
|
repeated sfixed32 packed_sfixed32 = 83 [packed = true];
|
||||||
|
repeated sfixed64 packed_sfixed64 = 84 [packed = true];
|
||||||
|
repeated float packed_float = 85 [packed = true];
|
||||||
|
repeated double packed_double = 86 [packed = true];
|
||||||
|
repeated bool packed_bool = 87 [packed = true];
|
||||||
|
repeated NestedEnum packed_nested_enum = 88 [packed = true];
|
||||||
|
|
||||||
|
// Unpacked
|
||||||
|
repeated int32 unpacked_int32 = 89 [packed = false];
|
||||||
|
repeated int64 unpacked_int64 = 90 [packed = false];
|
||||||
|
repeated uint32 unpacked_uint32 = 91 [packed = false];
|
||||||
|
repeated uint64 unpacked_uint64 = 92 [packed = false];
|
||||||
|
repeated sint32 unpacked_sint32 = 93 [packed = false];
|
||||||
|
repeated sint64 unpacked_sint64 = 94 [packed = false];
|
||||||
|
repeated fixed32 unpacked_fixed32 = 95 [packed = false];
|
||||||
|
repeated fixed64 unpacked_fixed64 = 96 [packed = false];
|
||||||
|
repeated sfixed32 unpacked_sfixed32 = 97 [packed = false];
|
||||||
|
repeated sfixed64 unpacked_sfixed64 = 98 [packed = false];
|
||||||
|
repeated float unpacked_float = 99 [packed = false];
|
||||||
|
repeated double unpacked_double = 100 [packed = false];
|
||||||
|
repeated bool unpacked_bool = 101 [packed = false];
|
||||||
|
repeated NestedEnum unpacked_nested_enum = 102 [packed = false];
|
||||||
|
|
||||||
|
// Map
|
||||||
|
map<int32, int32> map_int32_int32 = 56;
|
||||||
|
map<int64, int64> map_int64_int64 = 57;
|
||||||
|
map<uint32, uint32> map_uint32_uint32 = 58;
|
||||||
|
map<uint64, uint64> map_uint64_uint64 = 59;
|
||||||
|
map<sint32, sint32> map_sint32_sint32 = 60;
|
||||||
|
map<sint64, sint64> map_sint64_sint64 = 61;
|
||||||
|
map<fixed32, fixed32> map_fixed32_fixed32 = 62;
|
||||||
|
map<fixed64, fixed64> map_fixed64_fixed64 = 63;
|
||||||
|
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
|
||||||
|
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
|
||||||
|
map<int32, float> map_int32_float = 66;
|
||||||
|
map<int32, double> map_int32_double = 67;
|
||||||
|
map<bool, bool> map_bool_bool = 68;
|
||||||
|
map<string, string> map_string_string = 69;
|
||||||
|
map<string, bytes> map_string_bytes = 70;
|
||||||
|
map<string, NestedMessage> map_string_nested_message = 71;
|
||||||
|
map<string, ForeignMessageProto2> map_string_foreign_message = 72;
|
||||||
|
map<string, NestedEnum> map_string_nested_enum = 73;
|
||||||
|
map<string, ForeignEnumProto2> map_string_foreign_enum = 74;
|
||||||
|
|
||||||
|
oneof oneof_field {
|
||||||
|
uint32 oneof_uint32 = 111;
|
||||||
|
NestedMessage oneof_nested_message = 112;
|
||||||
|
string oneof_string = 113;
|
||||||
|
bytes oneof_bytes = 114;
|
||||||
|
bool oneof_bool = 115;
|
||||||
|
uint64 oneof_uint64 = 116;
|
||||||
|
float oneof_float = 117;
|
||||||
|
double oneof_double = 118;
|
||||||
|
NestedEnum oneof_enum = 119;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensions
|
||||||
|
extensions 120 to 200;
|
||||||
|
|
||||||
|
// groups
|
||||||
|
optional group Data = 201 {
|
||||||
|
optional int32 group_int32 = 202;
|
||||||
|
optional uint32 group_uint32 = 203;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default values
|
||||||
|
optional int32 default_int32 = 241 [default = -123456789];
|
||||||
|
optional int64 default_int64 = 242 [default = -9123456789123456789];
|
||||||
|
optional uint32 default_uint32 = 243 [default = 2123456789];
|
||||||
|
optional uint64 default_uint64 = 244 [default = 10123456789123456789];
|
||||||
|
optional sint32 default_sint32 = 245 [default = -123456789];
|
||||||
|
optional sint64 default_sint64 = 246 [default = -9123456789123456789];
|
||||||
|
optional fixed32 default_fixed32 = 247 [default = 2123456789];
|
||||||
|
optional fixed64 default_fixed64 = 248 [default = 10123456789123456789];
|
||||||
|
optional sfixed32 default_sfixed32 = 249 [default = -123456789];
|
||||||
|
optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789];
|
||||||
|
optional float default_float = 251 [default = 9e9];
|
||||||
|
optional double default_double = 252 [default = 7e22];
|
||||||
|
optional bool default_bool = 253 [default = true];
|
||||||
|
optional string default_string = 254 [default = "Rosebud"];
|
||||||
|
optional bytes default_bytes = 255 [default = "joshua"];
|
||||||
|
|
||||||
|
// Test field-name-to-JSON-name convention.
|
||||||
|
// (protobuf says names can be any valid C/C++ identifier.)
|
||||||
|
optional int32 fieldname1 = 401;
|
||||||
|
optional int32 field_name2 = 402;
|
||||||
|
optional int32 _field_name3 = 403;
|
||||||
|
optional int32 field__name4_ = 404;
|
||||||
|
optional int32 field0name5 = 405;
|
||||||
|
optional int32 field_0_name6 = 406;
|
||||||
|
optional int32 fieldName7 = 407;
|
||||||
|
optional int32 FieldName8 = 408;
|
||||||
|
optional int32 field_Name9 = 409;
|
||||||
|
optional int32 Field_Name10 = 410;
|
||||||
|
optional int32 FIELD_NAME11 = 411;
|
||||||
|
optional int32 FIELD_name12 = 412;
|
||||||
|
optional int32 __field_name13 = 413;
|
||||||
|
optional int32 __Field_name14 = 414;
|
||||||
|
optional int32 field__name15 = 415;
|
||||||
|
optional int32 field__Name16 = 416;
|
||||||
|
optional int32 field_name17__ = 417;
|
||||||
|
optional int32 Field_name18__ = 418;
|
||||||
|
|
||||||
|
// Reserved for unknown fields test.
|
||||||
|
reserved 1000 to 9999;
|
||||||
|
|
||||||
|
// message_set test case.
|
||||||
|
message MessageSetCorrect {
|
||||||
|
option message_set_wire_format = true;
|
||||||
|
|
||||||
|
extensions 4 to max;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageSetCorrectExtension1 {
|
||||||
|
extend MessageSetCorrect {
|
||||||
|
optional MessageSetCorrectExtension1 message_set_extension = 1547769;
|
||||||
|
}
|
||||||
|
optional string str = 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageSetCorrectExtension2 {
|
||||||
|
extend MessageSetCorrect {
|
||||||
|
optional MessageSetCorrectExtension2 message_set_extension = 4135312;
|
||||||
|
}
|
||||||
|
optional int32 i = 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message ForeignMessageProto2 {
|
||||||
|
optional int32 c = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ForeignEnumProto2 {
|
||||||
|
FOREIGN_FOO = 0;
|
||||||
|
FOREIGN_BAR = 1;
|
||||||
|
FOREIGN_BAZ = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend TestAllTypesProto2 {
|
||||||
|
optional int32 extension_int32 = 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UnknownToTestAllTypes {
|
||||||
|
optional int32 optional_int32 = 1001;
|
||||||
|
optional string optional_string = 1002;
|
||||||
|
optional ForeignMessageProto2 nested_message = 1003;
|
||||||
|
optional group OptionalGroup = 1004 {
|
||||||
|
optional int32 a = 1;
|
||||||
|
}
|
||||||
|
optional bool optional_bool = 1006;
|
||||||
|
repeated int32 repeated_int32 = 1011;
|
||||||
|
}
|
||||||
|
|
||||||
|
message NullHypothesisProto2 {}
|
||||||
|
|
||||||
|
message EnumOnlyProto2 {
|
||||||
|
enum Bool {
|
||||||
|
kFalse = 0;
|
||||||
|
kTrue = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message OneStringProto2 {
|
||||||
|
optional string data = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ProtoWithKeywords {
|
||||||
|
optional int32 inline = 1;
|
||||||
|
optional string concept = 2;
|
||||||
|
repeated string requires = 3;
|
||||||
|
}
|
|
@ -0,0 +1,288 @@
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// Test schema for proto3 messages. This test schema is used by:
|
||||||
|
//
|
||||||
|
// - benchmarks
|
||||||
|
// - fuzz tests
|
||||||
|
// - conformance tests
|
||||||
|
//
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package protobuf_test_messages.proto3;
|
||||||
|
|
||||||
|
option java_package = "com.google.protobuf_test_messages.proto3";
|
||||||
|
option objc_class_prefix = "Proto3";
|
||||||
|
|
||||||
|
// This is the default, but we specify it here explicitly.
|
||||||
|
option optimize_for = SPEED;
|
||||||
|
|
||||||
|
import "google/protobuf/any.proto";
|
||||||
|
import "google/protobuf/duration.proto";
|
||||||
|
import "google/protobuf/field_mask.proto";
|
||||||
|
import "google/protobuf/struct.proto";
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
import "google/protobuf/wrappers.proto";
|
||||||
|
|
||||||
|
option cc_enable_arenas = true;
|
||||||
|
|
||||||
|
// This proto includes every type of field in both singular and repeated
|
||||||
|
// forms.
|
||||||
|
//
|
||||||
|
// Also, crucially, all messages and enums in this file are eventually
|
||||||
|
// submessages of this message. So for example, a fuzz test of TestAllTypes
|
||||||
|
// could trigger bugs that occur in any message type in this file. We verify
|
||||||
|
// this stays true in a unit test.
|
||||||
|
message TestAllTypesProto3 {
|
||||||
|
message NestedMessage {
|
||||||
|
int32 a = 1;
|
||||||
|
TestAllTypesProto3 corecursive = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NestedEnum {
|
||||||
|
FOO = 0;
|
||||||
|
BAR = 1;
|
||||||
|
BAZ = 2;
|
||||||
|
NEG = -1; // Intentionally negative.
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AliasedEnum {
|
||||||
|
option allow_alias = true;
|
||||||
|
|
||||||
|
ALIAS_FOO = 0;
|
||||||
|
ALIAS_BAR = 1;
|
||||||
|
ALIAS_BAZ = 2;
|
||||||
|
MOO = 2;
|
||||||
|
moo = 2;
|
||||||
|
bAz = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Singular
|
||||||
|
int32 optional_int32 = 1;
|
||||||
|
int64 optional_int64 = 2;
|
||||||
|
uint32 optional_uint32 = 3;
|
||||||
|
uint64 optional_uint64 = 4;
|
||||||
|
sint32 optional_sint32 = 5;
|
||||||
|
sint64 optional_sint64 = 6;
|
||||||
|
fixed32 optional_fixed32 = 7;
|
||||||
|
fixed64 optional_fixed64 = 8;
|
||||||
|
sfixed32 optional_sfixed32 = 9;
|
||||||
|
sfixed64 optional_sfixed64 = 10;
|
||||||
|
float optional_float = 11;
|
||||||
|
double optional_double = 12;
|
||||||
|
bool optional_bool = 13;
|
||||||
|
string optional_string = 14;
|
||||||
|
bytes optional_bytes = 15;
|
||||||
|
|
||||||
|
NestedMessage optional_nested_message = 18;
|
||||||
|
ForeignMessage optional_foreign_message = 19;
|
||||||
|
|
||||||
|
NestedEnum optional_nested_enum = 21;
|
||||||
|
ForeignEnum optional_foreign_enum = 22;
|
||||||
|
AliasedEnum optional_aliased_enum = 23;
|
||||||
|
|
||||||
|
string optional_string_piece = 24 [ctype = STRING_PIECE];
|
||||||
|
string optional_cord = 25 [ctype = CORD];
|
||||||
|
|
||||||
|
TestAllTypesProto3 recursive_message = 27;
|
||||||
|
|
||||||
|
// Repeated
|
||||||
|
repeated int32 repeated_int32 = 31;
|
||||||
|
repeated int64 repeated_int64 = 32;
|
||||||
|
repeated uint32 repeated_uint32 = 33;
|
||||||
|
repeated uint64 repeated_uint64 = 34;
|
||||||
|
repeated sint32 repeated_sint32 = 35;
|
||||||
|
repeated sint64 repeated_sint64 = 36;
|
||||||
|
repeated fixed32 repeated_fixed32 = 37;
|
||||||
|
repeated fixed64 repeated_fixed64 = 38;
|
||||||
|
repeated sfixed32 repeated_sfixed32 = 39;
|
||||||
|
repeated sfixed64 repeated_sfixed64 = 40;
|
||||||
|
repeated float repeated_float = 41;
|
||||||
|
repeated double repeated_double = 42;
|
||||||
|
repeated bool repeated_bool = 43;
|
||||||
|
repeated string repeated_string = 44;
|
||||||
|
repeated bytes repeated_bytes = 45;
|
||||||
|
|
||||||
|
repeated NestedMessage repeated_nested_message = 48;
|
||||||
|
repeated ForeignMessage repeated_foreign_message = 49;
|
||||||
|
|
||||||
|
repeated NestedEnum repeated_nested_enum = 51;
|
||||||
|
repeated ForeignEnum repeated_foreign_enum = 52;
|
||||||
|
|
||||||
|
repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
|
||||||
|
repeated string repeated_cord = 55 [ctype = CORD];
|
||||||
|
|
||||||
|
// Packed
|
||||||
|
repeated int32 packed_int32 = 75 [packed = true];
|
||||||
|
repeated int64 packed_int64 = 76 [packed = true];
|
||||||
|
repeated uint32 packed_uint32 = 77 [packed = true];
|
||||||
|
repeated uint64 packed_uint64 = 78 [packed = true];
|
||||||
|
repeated sint32 packed_sint32 = 79 [packed = true];
|
||||||
|
repeated sint64 packed_sint64 = 80 [packed = true];
|
||||||
|
repeated fixed32 packed_fixed32 = 81 [packed = true];
|
||||||
|
repeated fixed64 packed_fixed64 = 82 [packed = true];
|
||||||
|
repeated sfixed32 packed_sfixed32 = 83 [packed = true];
|
||||||
|
repeated sfixed64 packed_sfixed64 = 84 [packed = true];
|
||||||
|
repeated float packed_float = 85 [packed = true];
|
||||||
|
repeated double packed_double = 86 [packed = true];
|
||||||
|
repeated bool packed_bool = 87 [packed = true];
|
||||||
|
repeated NestedEnum packed_nested_enum = 88 [packed = true];
|
||||||
|
|
||||||
|
// Unpacked
|
||||||
|
repeated int32 unpacked_int32 = 89 [packed = false];
|
||||||
|
repeated int64 unpacked_int64 = 90 [packed = false];
|
||||||
|
repeated uint32 unpacked_uint32 = 91 [packed = false];
|
||||||
|
repeated uint64 unpacked_uint64 = 92 [packed = false];
|
||||||
|
repeated sint32 unpacked_sint32 = 93 [packed = false];
|
||||||
|
repeated sint64 unpacked_sint64 = 94 [packed = false];
|
||||||
|
repeated fixed32 unpacked_fixed32 = 95 [packed = false];
|
||||||
|
repeated fixed64 unpacked_fixed64 = 96 [packed = false];
|
||||||
|
repeated sfixed32 unpacked_sfixed32 = 97 [packed = false];
|
||||||
|
repeated sfixed64 unpacked_sfixed64 = 98 [packed = false];
|
||||||
|
repeated float unpacked_float = 99 [packed = false];
|
||||||
|
repeated double unpacked_double = 100 [packed = false];
|
||||||
|
repeated bool unpacked_bool = 101 [packed = false];
|
||||||
|
repeated NestedEnum unpacked_nested_enum = 102 [packed = false];
|
||||||
|
|
||||||
|
// Map
|
||||||
|
map<int32, int32> map_int32_int32 = 56;
|
||||||
|
map<int64, int64> map_int64_int64 = 57;
|
||||||
|
map<uint32, uint32> map_uint32_uint32 = 58;
|
||||||
|
map<uint64, uint64> map_uint64_uint64 = 59;
|
||||||
|
map<sint32, sint32> map_sint32_sint32 = 60;
|
||||||
|
map<sint64, sint64> map_sint64_sint64 = 61;
|
||||||
|
map<fixed32, fixed32> map_fixed32_fixed32 = 62;
|
||||||
|
map<fixed64, fixed64> map_fixed64_fixed64 = 63;
|
||||||
|
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
|
||||||
|
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
|
||||||
|
map<int32, float> map_int32_float = 66;
|
||||||
|
map<int32, double> map_int32_double = 67;
|
||||||
|
map<bool, bool> map_bool_bool = 68;
|
||||||
|
map<string, string> map_string_string = 69;
|
||||||
|
map<string, bytes> map_string_bytes = 70;
|
||||||
|
map<string, NestedMessage> map_string_nested_message = 71;
|
||||||
|
map<string, ForeignMessage> map_string_foreign_message = 72;
|
||||||
|
map<string, NestedEnum> map_string_nested_enum = 73;
|
||||||
|
map<string, ForeignEnum> map_string_foreign_enum = 74;
|
||||||
|
|
||||||
|
oneof oneof_field {
|
||||||
|
uint32 oneof_uint32 = 111;
|
||||||
|
NestedMessage oneof_nested_message = 112;
|
||||||
|
string oneof_string = 113;
|
||||||
|
bytes oneof_bytes = 114;
|
||||||
|
bool oneof_bool = 115;
|
||||||
|
uint64 oneof_uint64 = 116;
|
||||||
|
float oneof_float = 117;
|
||||||
|
double oneof_double = 118;
|
||||||
|
NestedEnum oneof_enum = 119;
|
||||||
|
google.protobuf.NullValue oneof_null_value = 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Well-known types
|
||||||
|
google.protobuf.BoolValue optional_bool_wrapper = 201;
|
||||||
|
google.protobuf.Int32Value optional_int32_wrapper = 202;
|
||||||
|
google.protobuf.Int64Value optional_int64_wrapper = 203;
|
||||||
|
google.protobuf.UInt32Value optional_uint32_wrapper = 204;
|
||||||
|
google.protobuf.UInt64Value optional_uint64_wrapper = 205;
|
||||||
|
google.protobuf.FloatValue optional_float_wrapper = 206;
|
||||||
|
google.protobuf.DoubleValue optional_double_wrapper = 207;
|
||||||
|
google.protobuf.StringValue optional_string_wrapper = 208;
|
||||||
|
google.protobuf.BytesValue optional_bytes_wrapper = 209;
|
||||||
|
|
||||||
|
repeated google.protobuf.BoolValue repeated_bool_wrapper = 211;
|
||||||
|
repeated google.protobuf.Int32Value repeated_int32_wrapper = 212;
|
||||||
|
repeated google.protobuf.Int64Value repeated_int64_wrapper = 213;
|
||||||
|
repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214;
|
||||||
|
repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215;
|
||||||
|
repeated google.protobuf.FloatValue repeated_float_wrapper = 216;
|
||||||
|
repeated google.protobuf.DoubleValue repeated_double_wrapper = 217;
|
||||||
|
repeated google.protobuf.StringValue repeated_string_wrapper = 218;
|
||||||
|
repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219;
|
||||||
|
|
||||||
|
google.protobuf.Duration optional_duration = 301;
|
||||||
|
google.protobuf.Timestamp optional_timestamp = 302;
|
||||||
|
google.protobuf.FieldMask optional_field_mask = 303;
|
||||||
|
google.protobuf.Struct optional_struct = 304;
|
||||||
|
google.protobuf.Any optional_any = 305;
|
||||||
|
google.protobuf.Value optional_value = 306;
|
||||||
|
google.protobuf.NullValue optional_null_value = 307;
|
||||||
|
|
||||||
|
repeated google.protobuf.Duration repeated_duration = 311;
|
||||||
|
repeated google.protobuf.Timestamp repeated_timestamp = 312;
|
||||||
|
repeated google.protobuf.FieldMask repeated_fieldmask = 313;
|
||||||
|
repeated google.protobuf.Struct repeated_struct = 324;
|
||||||
|
repeated google.protobuf.Any repeated_any = 315;
|
||||||
|
repeated google.protobuf.Value repeated_value = 316;
|
||||||
|
repeated google.protobuf.ListValue repeated_list_value = 317;
|
||||||
|
|
||||||
|
// Test field-name-to-JSON-name convention.
|
||||||
|
// (protobuf says names can be any valid C/C++ identifier.)
|
||||||
|
int32 fieldname1 = 401;
|
||||||
|
int32 field_name2 = 402;
|
||||||
|
int32 _field_name3 = 403;
|
||||||
|
int32 field__name4_ = 404;
|
||||||
|
int32 field0name5 = 405;
|
||||||
|
int32 field_0_name6 = 406;
|
||||||
|
int32 fieldName7 = 407;
|
||||||
|
int32 FieldName8 = 408;
|
||||||
|
int32 field_Name9 = 409;
|
||||||
|
int32 Field_Name10 = 410;
|
||||||
|
int32 FIELD_NAME11 = 411;
|
||||||
|
int32 FIELD_name12 = 412;
|
||||||
|
int32 __field_name13 = 413;
|
||||||
|
int32 __Field_name14 = 414;
|
||||||
|
int32 field__name15 = 415;
|
||||||
|
int32 field__Name16 = 416;
|
||||||
|
int32 field_name17__ = 417;
|
||||||
|
int32 Field_name18__ = 418;
|
||||||
|
|
||||||
|
// Reserved for testing unknown fields
|
||||||
|
reserved 501 to 510;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ForeignMessage {
|
||||||
|
int32 c = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ForeignEnum {
|
||||||
|
FOREIGN_FOO = 0;
|
||||||
|
FOREIGN_BAR = 1;
|
||||||
|
FOREIGN_BAZ = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message NullHypothesisProto3 {}
|
||||||
|
|
||||||
|
message EnumOnlyProto3 {
|
||||||
|
enum Bool {
|
||||||
|
kFalse = 0;
|
||||||
|
kTrue = 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
import ../../protobuf_serialization
|
||||||
|
import ../../protobuf_serialization/files/type_generator
|
||||||
|
import_proto3 "test_messages_proto2.proto"
|
|
@ -0,0 +1,3 @@
|
||||||
|
import ../../protobuf_serialization
|
||||||
|
import ../../protobuf_serialization/files/type_generator
|
||||||
|
import_proto3 "test_messages_proto3.proto"
|
|
@ -10,23 +10,29 @@ macro test() =
|
||||||
parsed: NimNode = protoToTypesInternal(currentSourcePath.parentDir / "test.proto3")
|
parsed: NimNode = protoToTypesInternal(currentSourcePath.parentDir / "test.proto3")
|
||||||
vector: NimNode = quote do:
|
vector: NimNode = quote do:
|
||||||
type
|
type
|
||||||
TestEnum* {.proto3.} = enum
|
TestEnum* {.pure, proto3.} = enum
|
||||||
UNKNOWN = 0
|
UNKNOWN = 0
|
||||||
STARTED = 1
|
STARTED = 1
|
||||||
|
|
||||||
ErrorStatus* {.proto3.} = object
|
ErrorStatus* {.proto3.} = object
|
||||||
message* {.fieldNumber: 1.}: string
|
|
||||||
details* {.fieldNumber: 2.}: seq[seq[byte]]
|
details* {.fieldNumber: 2.}: seq[seq[byte]]
|
||||||
|
message* {.fieldNumber: 1.}: string
|
||||||
Result* {.proto3.} = object
|
|
||||||
url* {.fieldNumber: 1.}: string
|
|
||||||
title* {.fieldNumber: 2.}: string
|
|
||||||
snippets* {.fieldNumber: 3.}: seq[string]
|
|
||||||
|
|
||||||
SearchResponse* {.proto3.} = object
|
SearchResponse* {.proto3.} = object
|
||||||
results* {.fieldNumber: 1.}: seq[Result]
|
results* {.fieldNumber: 1.}: seq[Result]
|
||||||
|
|
||||||
Corpus* {.proto3.} = enum
|
Result* {.proto3.} = object
|
||||||
|
snippets* {.fieldNumber: 3.}: seq[string]
|
||||||
|
title* {.fieldNumber: 2.}: string
|
||||||
|
url* {.fieldNumber: 1.}: string
|
||||||
|
|
||||||
|
SearchRequest* {.proto3.} = object
|
||||||
|
corpus* {.fieldNumber: 4.}: Corpus
|
||||||
|
result_per_page* {.fieldNumber: 3, pint.}: int32
|
||||||
|
page_number* {.fieldNumber: 2, pint.}: int32
|
||||||
|
query* {.fieldNumber: 1.}: string
|
||||||
|
|
||||||
|
Corpus* {.pure, proto3.} = enum
|
||||||
UNIVERSAL = 0
|
UNIVERSAL = 0
|
||||||
WEB = 1
|
WEB = 1
|
||||||
IMAGES = 2
|
IMAGES = 2
|
||||||
|
@ -35,12 +41,6 @@ macro test() =
|
||||||
PRODUCTS = 5
|
PRODUCTS = 5
|
||||||
VIDEO = 6
|
VIDEO = 6
|
||||||
|
|
||||||
SearchRequest* {.proto3.} = object
|
|
||||||
query* {.fieldNumber: 1.}: string
|
|
||||||
page_number* {.fieldNumber: 2, pint.}: int32
|
|
||||||
result_per_page* {.fieldNumber: 3, pint.}: int32
|
|
||||||
corpus* {.fieldNumber: 4.}: Corpus
|
|
||||||
|
|
||||||
Foo* {.proto3.} = object
|
Foo* {.proto3.} = object
|
||||||
|
|
||||||
proc convertFromSym(parent: NimNode, i: int) =
|
proc convertFromSym(parent: NimNode, i: int) =
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import unittest2
|
||||||
|
|
||||||
|
import
|
||||||
|
../protobuf_serialization,
|
||||||
|
../protobuf_serialization/codec
|
||||||
|
|
||||||
|
type
|
||||||
|
Classic = enum
|
||||||
|
A1
|
||||||
|
B1
|
||||||
|
C1
|
||||||
|
|
||||||
|
WithHoles = enum
|
||||||
|
A2 = -10
|
||||||
|
B2 = 0
|
||||||
|
C2 = 10
|
||||||
|
D2
|
||||||
|
|
||||||
|
Limits = enum
|
||||||
|
A3 = int32.low()
|
||||||
|
B3 = 0
|
||||||
|
C3 = int32.high()
|
||||||
|
|
||||||
|
ObjClassicP2 {.proto2.} = object
|
||||||
|
x {.fieldNumber: 1, required.}: Classic
|
||||||
|
|
||||||
|
ObjWithHolesP2 {.proto2.} = object
|
||||||
|
x {.fieldNumber: 1, required.}: WithHoles
|
||||||
|
|
||||||
|
ObjLimitsP2 {.proto2.} = object
|
||||||
|
x {.fieldNumber: 1, required.}: Limits
|
||||||
|
|
||||||
|
ObjClassicP3 {.proto3.} = object
|
||||||
|
x {.fieldNumber: 1.}: Classic
|
||||||
|
|
||||||
|
ObjWithHolesP3 {.proto3.} = object
|
||||||
|
x {.fieldNumber: 1.}: WithHoles
|
||||||
|
|
||||||
|
ObjLimitsP3 {.proto3.} = object
|
||||||
|
x {.fieldNumber: 1.}: Limits
|
||||||
|
|
||||||
|
suite "Test Enum Encoding/Decoding":
|
||||||
|
test "Can encode/decode enum":
|
||||||
|
for x in @[A1, B1, C1]:
|
||||||
|
let
|
||||||
|
objp2 = ObjClassicP2(x: x)
|
||||||
|
objp3 = ObjClassicP3(x: x)
|
||||||
|
encodedp2 = Protobuf.encode(objp2)
|
||||||
|
encodedp3 = Protobuf.encode(objp3)
|
||||||
|
check Protobuf.decode(encodedp2, ObjClassicP2) == objp2
|
||||||
|
check Protobuf.decode(encodedp3, ObjClassicP3) == objp3
|
||||||
|
|
||||||
|
test "Can encode/decode enum with holes":
|
||||||
|
for x in @[A2, B2, C2, D2]:
|
||||||
|
let
|
||||||
|
objp2 = ObjWithHolesP2(x: x)
|
||||||
|
objp3 = ObjWithHolesP3(x: x)
|
||||||
|
encodedp2 = Protobuf.encode(objp2)
|
||||||
|
encodedp3 = Protobuf.encode(objp3)
|
||||||
|
check Protobuf.decode(encodedp2, ObjWithHolesP2) == objp2
|
||||||
|
check Protobuf.decode(encodedp3, ObjWithHolesP3) == objp3
|
||||||
|
|
||||||
|
test "Can encode/decode enum limits":
|
||||||
|
for x in @[A3, B3, C3]:
|
||||||
|
let
|
||||||
|
objp2 = ObjLimitsP2(x: x)
|
||||||
|
objp3 = ObjLimitsP3(x: x)
|
||||||
|
encodedp2 = Protobuf.encode(objp2)
|
||||||
|
encodedp3 = Protobuf.encode(objp3)
|
||||||
|
check Protobuf.decode(encodedp2, ObjLimitsP2) == objp2
|
||||||
|
check Protobuf.decode(encodedp3, ObjLimitsP3) == objp3
|
||||||
|
|
||||||
|
test "Decode out of range enum":
|
||||||
|
# TODO: Find a way to save the unrecognized value
|
||||||
|
check:
|
||||||
|
Protobuf.decode(@[8'u8, 4], ObjWithHolesP2) == ObjWithHolesP2() # Inside the hole
|
||||||
|
Protobuf.decode(@[8'u8, 4], ObjWithHolesP3) == ObjWithHolesP3() # Inside the hole
|
||||||
|
Protobuf.decode(@[8'u8, 24], ObjWithHolesP2) == ObjWithHolesP2() # Outside the hole
|
||||||
|
Protobuf.decode(@[8'u8, 24], ObjWithHolesP3) == ObjWithHolesP3() # Outside the hole
|
|
@ -5,6 +5,11 @@ import
|
||||||
../protobuf_serialization/codec
|
../protobuf_serialization/codec
|
||||||
|
|
||||||
type
|
type
|
||||||
|
# TestEnum = enum
|
||||||
|
# A1 = 0
|
||||||
|
# B1 = 1000
|
||||||
|
# C1 = 1000000
|
||||||
|
|
||||||
Basic {.proto3.} = object
|
Basic {.proto3.} = object
|
||||||
a {.fieldNumber: 1, pint.}: uint64
|
a {.fieldNumber: 1, pint.}: uint64
|
||||||
b {.fieldNumber: 2.}: string
|
b {.fieldNumber: 2.}: string
|
||||||
|
@ -16,6 +21,7 @@ type
|
||||||
f {.fieldNumber: 3.}: Basic
|
f {.fieldNumber: 3.}: Basic
|
||||||
g {.fieldNumber: 4.}: string
|
g {.fieldNumber: 4.}: string
|
||||||
h {.fieldNumber: 5.}: bool
|
h {.fieldNumber: 5.}: bool
|
||||||
|
#i {.fieldNumber: 6.}: TestEnum
|
||||||
|
|
||||||
discard Protobuf.supports(Basic)
|
discard Protobuf.supports(Basic)
|
||||||
discard Protobuf.supports(Wrapped)
|
discard Protobuf.supports(Wrapped)
|
||||||
|
@ -72,6 +78,7 @@ suite "Test Object Encoding/Decoding":
|
||||||
writer = memoryOutput()
|
writer = memoryOutput()
|
||||||
|
|
||||||
writer.writeField(3, obj.f)
|
writer.writeField(3, obj.f)
|
||||||
|
#writer.writeField(6, penum(obj.i))
|
||||||
writer.writeField(1, sint64(obj.d))
|
writer.writeField(1, sint64(obj.d))
|
||||||
writer.writeField(2, sint64(obj.e))
|
writer.writeField(2, sint64(obj.e))
|
||||||
writer.writeField(5, pbool(obj.h))
|
writer.writeField(5, pbool(obj.h))
|
||||||
|
|
Loading…
Reference in New Issue