From 9582f915791af730240ecee972429549f8b2a40a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 12:44:45 +0200 Subject: [PATCH 01/37] build(deps): bump github/codeql-action from 2.21.6 to 2.21.7 (#417) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.6 to 2.21.7. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/701f152f28d4350ad289a5e31435e9ab6169a7ca...04daf014b50eaf774287bf3f0f1869d4b4c4b913) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index a68c358f9..393ab293a 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -51,7 +51,7 @@ jobs: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/upload-sarif@701f152f28d4350ad289a5e31435e9ab6169a7ca # v2.21.6 + - uses: github/codeql-action/upload-sarif@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 if: ${{ success() }} || ${{ failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index a47c33359..532ce19d9 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,6 @@ jobs: results_format: sarif repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} publish_results: true - - uses: github/codeql-action/upload-sarif@701f152f28d4350ad289a5e31435e9ab6169a7ca # v2.21.6 + - uses: github/codeql-action/upload-sarif@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 with: sarif_file: scorecards.sarif diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 6853e071e..1796a9e7d 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -80,10 +80,10 @@ jobs: - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - - uses: github/codeql-action/init@701f152f28d4350ad289a5e31435e9ab6169a7ca # v2.21.6 + - uses: github/codeql-action/init@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 with: languages: cpp - run: | cmake --preset ContinuousIntegration -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build --preset ContinuousIntegration - - uses: github/codeql-action/analyze@701f152f28d4350ad289a5e31435e9ab6169a7ca # v2.21.6 + - uses: github/codeql-action/analyze@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 From 228d64534a9c5365d8dc6a48bee3982bc1cd70eb Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Wed, 20 Sep 2023 10:39:41 +0200 Subject: [PATCH 02/37] ci: consolidate configurations (#411) * ci: consolidate configurations * Change Package config into Host-Single-MinSizeRel, split Windows/MacOS workflows * Add Host-Single-Debug, use for MacOS ci * Disable sccache for Windows build * Consolidate Windows and MacOS builds * Explicitly enable tests * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Use the correct configuration for the test preset * Presets now start with a lower case character * Presets now start with a lower case character * Presets now start with a lower case character * Update CMakePresets.json Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * .github/workflows/ci.yml: small improvements --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .clusterfuzzlite/build.sh | 6 +- .github/workflows/ci.yml | 27 ++-- .github/workflows/release-please.yml | 4 +- .github/workflows/static-analysis.yml | 18 +-- CMakePresets.json | 171 +++++++++++++------------- 5 files changed, 114 insertions(+), 112 deletions(-) diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh index 5cfed44fe..b185aec90 100644 --- a/.clusterfuzzlite/build.sh +++ b/.clusterfuzzlite/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -eu -cmake --preset Fuzzing -cmake --build --preset Fuzzing +cmake --preset fuzzing +cmake --build --preset fuzzing -cp build/Fuzzing/infra/syntax/fuzz/infra.syntax_json_fuzzer $OUT/infra-syntax_json_fuzzer +cp build/fuzzing/infra/syntax/fuzz/infra.syntax_json_fuzzer $OUT/infra-syntax_json_fuzzer diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6c8f95ff..aa66ffdaf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,23 +29,24 @@ jobs: with: key: ${{ github.job }}-ubuntu-latest variant: sccache + - uses: seanmiddleditch/gha-setup-ninja@16b940825621068d98711680b6c3ff92201f8fc0 # v3 - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 with: - configurePreset: "ContinuousIntegration" - buildPreset: "ContinuousIntegrationWithPackage" - testPreset: "ContinuousIntegration" + configurePreset: "host" + buildPreset: "host-Debug-WithPackage" + testPreset: "host" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=sccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=sccache']" - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: emil - path: build/ContinuousIntegration/emil-*-Linux.tar.gz + path: build/host/emil-*-Linux.tar.gz if-no-files-found: error - name: Upload test logs if: ${{ failure() }} uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: test-logs - path: build/ContinuousIntegration/Testing/Temporary/ + path: build/host/Testing/Temporary/ host_build_test: name: Host Build & Test runs-on: ${{ matrix.os }} @@ -62,16 +63,16 @@ jobs: variant: sccache - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 with: - configurePreset: "ContinuousIntegration" - buildPreset: "ContinuousIntegration" - testPreset: "ContinuousIntegration" + configurePreset: "host-single-Debug" + buildPreset: "host-single-Debug" + testPreset: "host-single-Debug" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=sccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=sccache']" - name: Upload test logs if: ${{ failure() }} uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: test-logs - path: build/ContinuousIntegration/Testing/Temporary/ + path: build/host/Testing/Temporary/ embedded_build: name: Embedded Build runs-on: ubuntu-latest @@ -99,8 +100,8 @@ jobs: - run: mkdir install && mv emil-*/* install/ - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 with: - configurePreset: "Embedded" - buildPreset: "Embedded-${{ matrix.configuration }}" + configurePreset: "embedded" + buildPreset: "embedded-${{ matrix.configuration }}" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" rtos: name: Embedded Build - RTOS @@ -128,6 +129,6 @@ jobs: - run: mkdir install && mv emil-*/* install/ - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 with: - configurePreset: "Embedded-${{ matrix.rtos }}" - buildPreset: "Embedded-${{ matrix.rtos }}-RelWithDebInfo" + configurePreset: "embedded-${{ matrix.rtos }}" + buildPreset: "embedded-${{ matrix.rtos }}-RelWithDebInfo" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 0778da3c1..bcc5f69a3 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -52,8 +52,8 @@ jobs: variant: sccache - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 with: - configurePreset: "Package" - buildPreset: "Package" + configurePreset: "host-single-MinSizeRel" + buildPreset: "release-package" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=sccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=sccache']" - run: gh release upload ${{ needs.release_please.outputs.tag_name }} build/**/emil-*.zip --clobber shell: bash diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 1796a9e7d..23a5a8c9a 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -44,21 +44,21 @@ jobs: max-size: 2G - name: Build & Collect Coverage run: | - cmake --preset Coverage -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - cmake --build --preset Coverage - GTEST_OUTPUT="xml:${PWD}/testresults/" ctest --preset Coverage + cmake --preset coverage -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake --build --preset coverage + GTEST_OUTPUT="xml:${PWD}/testresults/" ctest --preset coverage gcovr --sonarqube=coverage.xml --exclude-lines-by-pattern '.*assert\(.*\);|.*really_assert\(.*\);|.*std::abort();' --exclude-unreachable-branches --exclude-throw-branches -j 2 --exclude=.*/generated/.* --exclude=.*/examples/.* --exclude=.*/external/.* --exclude=.*/lwip/.* --exclude=.*/tracing/.* --exclude=.*/test/.* - name: Build & Run Mutation Tests run: | - cmake --preset MutationTesting -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - cmake --build --preset MutationTesting - ctest --preset MutationTesting + cmake --preset mutation-testing -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake --build --preset mutation-testing + ctest --preset mutation-testing - name: Convert Results run: | { echo ''; xsltproc .github/formatters/gtest-to-generic-execution.xslt testresults/*.xml; echo ''; } | tee execution.xml > /dev/null jq -s 'reduce .[] as $item ({}; . * $item)' reports/mull/*.json > reports/mull/merged-mutation.json jq --arg workspace "$GITHUB_WORKSPACE" -f .github/formatters/mutation-report-to-generic-issue.jq reports/mull/merged-mutation.json > mutation-sonar.json - cp build/Coverage/compile_commands.json compile_commands.json + cp build/coverage/compile_commands.json compile_commands.json - name: Run Analysis # skip the analysis step for dependabot PRs since dependabot does not have access to secrets if: ${{ github.actor != 'dependabot[bot]' }} @@ -84,6 +84,6 @@ jobs: with: languages: cpp - run: | - cmake --preset ContinuousIntegration -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - cmake --build --preset ContinuousIntegration + cmake --preset host -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake --build --preset host-Debug - uses: github/codeql-action/analyze@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 diff --git a/CMakePresets.json b/CMakePresets.json index 99cdfaf78..01edcde73 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -12,39 +12,45 @@ } }, { - "name": "ContinuousIntegration", - "displayName": "Configuration for Continuous Integration", + "name": "host", + "displayName": "Configuration for Host Tooling and Tests", + "inherits": "defaults", + "cacheVariables": { + "CMAKE_CONFIGURATION_TYPES": "Debug;Release;RelWithDebInfo;MinSizeRel" + }, + "generator": "Ninja Multi-Config" + }, + { + "name": "host-single-Debug", + "displayName": "Configuration for Host Tooling and Tests, Single Config Generator, Debug", "inherits": "defaults", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "EMIL_ENABLE_DOCKER_TOOLS": "Off", - "EMIL_BUILD_EXAMPLES": "On" + "EMIL_ENABLE_DOCKER_TOOLS": "Off" } }, { - "name": "Package", - "displayName": "Configuration for CPack package generation", + "name": "host-single-MinSizeRel", + "displayName": "Configuration for Host Tooling and Tests, Single Config Generator, MinSizeRel", "inherits": "defaults", "cacheVariables": { "CMAKE_BUILD_TYPE": "MinSizeRel", - "EMIL_ENABLE_DOCKER_TOOLS": "Off", - "EMIL_BUILD_TESTS": "Off", - "EMIL_BUILD_EXAMPLES": "Off" + "EMIL_ENABLE_DOCKER_TOOLS": "Off" } }, { - "name": "Coverage", + "name": "coverage", "displayName": "Configuration for Code Coverage", - "inherits": "ContinuousIntegration", + "inherits": "host", "cacheVariables": { "EMIL_ENABLE_COVERAGE": "On" }, "generator": "Ninja" }, { - "name": "MutationTesting", + "name": "mutation-testing", "displayName": "Configuration for Mutation Testing", - "inherits": "ContinuousIntegration", + "inherits": "host", "cacheVariables": { "CMAKE_C_COMPILER": "clang-12", "CMAKE_CXX_COMPILER": "clang++-12", @@ -54,9 +60,9 @@ "generator": "Ninja" }, { - "name": "Fuzzing", + "name": "fuzzing", "displayName": "Configuration for Fuzzing", - "inherits": "ContinuousIntegration", + "inherits": "host", "cacheVariables": { "CMAKE_C_COMPILER": "clang", "CMAKE_CXX_COMPILER": "clang++", @@ -67,18 +73,7 @@ "generator": "Ninja" }, { - "name": "Host", - "displayName": "Configuration for Host Tooling", - "inherits": "defaults", - "cacheVariables": { - "CMAKE_CONFIGURATION_TYPES": "Debug;Release;RelWithDebInfo;MinSizeRel", - "EMIL_BUILD_TESTS": "Off", - "EMIL_BUILD_EXAMPLES": "Off" - }, - "generator": "Ninja Multi-Config" - }, - { - "name": "HostClangMsvc", + "name": "host-ClangMsvc", "displayName": "Configuration for Host Tooling using clang-cl to target Windows", "inherits": "defaults", "toolchainFile": "${sourceDir}/cmake/toolchain-clang-x86_64-pc-windows-msvc.cmake", @@ -91,8 +86,8 @@ "generator": "Ninja Multi-Config" }, { - "name": "Embedded", - "displayName": "Configuration for Embedded", + "name": "embedded", + "displayName": "Configuration for embedded", "inherits": "defaults", "toolchainFile": "${sourceDir}/cmake/toolchain-arm-gcc-m4-fpv4-sp-d16.cmake", "cacheVariables": { @@ -102,18 +97,18 @@ "generator": "Ninja Multi-Config" }, { - "name": "Embedded-FreeRTOS", - "displayName": "Configuration for Embedded with FreeRTOS", - "inherits": "Embedded", + "name": "embedded-FreeRTOS", + "displayName": "Configuration for embedded with FreeRTOS", + "inherits": "embedded", "cacheVariables": { "EMIL_INCLUDE_FREERTOS": "On", "FREERTOS_CONFIG_FILE_DIRECTORY": "${sourceDir}/examples/threading/config" } }, { - "name": "Embedded-ThreadX", - "displayName": "Configuration for Embedded with ThreadX", - "inherits": "Embedded", + "name": "embedded-ThreadX", + "displayName": "Configuration for embedded with ThreadX", + "inherits": "embedded", "cacheVariables": { "EMIL_INCLUDE_THREADX": "On" } @@ -121,96 +116,96 @@ ], "buildPresets": [ { - "name": "ContinuousIntegration", + "name": "host-Debug", "configuration": "Debug", - "configurePreset": "ContinuousIntegration" + "configurePreset": "host" }, { - "name": "ContinuousIntegrationWithPackage", + "name": "host-Debug-WithPackage", "configuration": "Debug", - "configurePreset": "ContinuousIntegration", + "configurePreset": "host", "targets": ["all", "package"] }, { - "name": "Package", - "configuration": "MinSizeRel", - "configurePreset": "Package", - "targets": ["package"] + "name": "host-Release", + "configuration": "Release", + "configurePreset": "host" }, { - "name": "Coverage", - "configuration": "Debug", - "configurePreset": "Coverage" + "name": "host-RelWithDebInfo", + "configuration": "RelWithDebInfo", + "configurePreset": "host" }, { - "name": "MutationTesting", - "configuration": "Debug", - "configurePreset": "MutationTesting" + "name": "host-MinSizeRel", + "configuration": "MinSizeRel", + "configurePreset": "host" }, { - "name": "Fuzzing", + "name": "host-single-Debug", "configuration": "Debug", - "configurePreset": "Fuzzing" + "configurePreset": "host-single-Debug" }, { - "name": "Host-Debug", - "configuration": "Debug", - "configurePreset": "Host" + "name": "release-package", + "configuration": "MinSizeRel", + "configurePreset": "host-single-MinSizeRel", + "targets": ["package"] }, { - "name": "Host-Release", - "configuration": "Release", - "configurePreset": "Host" + "name": "coverage", + "configuration": "Debug", + "configurePreset": "coverage" }, { - "name": "Host-RelWithDebInfo", - "configuration": "RelWithDebInfo", - "configurePreset": "Host" + "name": "mutation-testing", + "configuration": "Debug", + "configurePreset": "mutation-testing" }, { - "name": "Host-MinSizeRel", - "configuration": "MinSizeRel", - "configurePreset": "Host" + "name": "fuzzing", + "configuration": "Debug", + "configurePreset": "fuzzing" }, { - "name": "HostClangMsvc-Debug", + "name": "host-ClangMsvc-Debug", "configuration": "Debug", - "configurePreset": "HostClangMsvc" + "configurePreset": "host-ClangMsvc" }, { - "name": "HostClangMsvc-RelWithDebInfo", + "name": "host-ClangMsvc-RelWithDebInfo", "configuration": "RelWithDebInfo", - "configurePreset": "HostClangMsvc" + "configurePreset": "host-ClangMsvc" }, { - "name": "Embedded-Debug", + "name": "embedded-Debug", "configuration": "Debug", - "configurePreset": "Embedded" + "configurePreset": "embedded" }, { - "name": "Embedded-Release", + "name": "embedded-Release", "configuration": "Release", - "configurePreset": "Embedded" + "configurePreset": "embedded" }, { - "name": "Embedded-RelWithDebInfo", + "name": "embedded-RelWithDebInfo", "configuration": "RelWithDebInfo", - "configurePreset": "Embedded" + "configurePreset": "embedded" }, { - "name": "Embedded-MinSizeRel", + "name": "embedded-MinSizeRel", "configuration": "MinSizeRel", - "configurePreset": "Embedded" + "configurePreset": "embedded" }, { - "name": "Embedded-FreeRTOS-RelWithDebInfo", + "name": "embedded-FreeRTOS-RelWithDebInfo", "configuration": "RelWithDebInfo", - "configurePreset": "Embedded-FreeRTOS" + "configurePreset": "embedded-FreeRTOS" }, { - "name": "Embedded-ThreadX-RelWithDebInfo", + "name": "embedded-ThreadX-RelWithDebInfo", "configuration": "RelWithDebInfo", - "configurePreset": "Embedded-ThreadX" + "configurePreset": "embedded-ThreadX" } ], "testPresets": [ @@ -226,20 +221,26 @@ } }, { - "name": "ContinuousIntegration", - "configurePreset": "ContinuousIntegration", + "name": "host", + "configurePreset": "host", + "configuration": "Debug", + "inherits": "defaults" + }, + { + "name": "host-single-Debug", + "configurePreset": "host-single-Debug", "configuration": "Debug", "inherits": "defaults" }, { - "name": "Coverage", - "configurePreset": "Coverage", + "name": "coverage", + "configurePreset": "coverage", "configuration": "Debug", "inherits": "defaults" }, { - "name": "MutationTesting", - "configurePreset": "MutationTesting", + "name": "mutation-testing", + "configurePreset": "mutation-testing", "configuration": "Debug", "inherits": "defaults", "output": { From 1b8d421a53a9df37744b3571ccbfc643c3eafbb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 18:45:13 +0200 Subject: [PATCH 03/37] build(deps): bump actions/checkout from 4.0.0 to 4.1.0 (#420) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/3df4ab11eba7bda6032a0b82a6bb43b11571feac...8ade135a41bc03ea155e62e844d188df1ea18608) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/dependency-scanner.yml | 4 ++-- .github/workflows/documentation.yml | 6 +++--- .github/workflows/linting-formatting.yml | 4 ++-- .github/workflows/release-please.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa66ffdaf..485e695a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: name: Host Build & Test (ubuntu-latest) runs-on: ubuntu-latest steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 @@ -54,7 +54,7 @@ jobs: matrix: os: [macos-latest, windows-latest, windows-2019] steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 @@ -82,7 +82,7 @@ jobs: gcc: ["7-2018-q2", "8-2019-q3", "9-2020-q2", "10.3-2021.10"] configuration: ["RelWithDebInfo"] steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - name: Install GNU Arm Embedded Toolchain ${{ matrix.gcc }} @@ -111,7 +111,7 @@ jobs: matrix: rtos: ["FreeRTOS", "ThreadX"] steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - name: Install GNU Arm Embedded Toolchain "10.3-2021.10" diff --git a/.github/workflows/dependency-scanner.yml b/.github/workflows/dependency-scanner.yml index 36efe6a3c..1f584aaa8 100644 --- a/.github/workflows/dependency-scanner.yml +++ b/.github/workflows/dependency-scanner.yml @@ -16,7 +16,7 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - uses: philips-forks/cmake-dependency-submission@72880580a7cafc16145d82268f1892c0ece3da2a # main dependency-review: runs-on: ubuntu-latest @@ -25,7 +25,7 @@ jobs: permissions: pull-requests: write steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3.1.0 with: comment-summary-in-pr: true diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 7da7a10ac..7bd5a63db 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -16,7 +16,7 @@ jobs: if: ${{ github.ref == 'refs/heads/main' }} steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: fetch-depth: 0 persist-credentials: false @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: fetch-depth: 0 persist-credentials: false @@ -69,7 +69,7 @@ jobs: name: Publish to GitHub Pages steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Retrieve Antora Site uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 393ab293a..6120c124c 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -21,7 +21,7 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@a83a8fb7d371f66da7dd1c4f33a193023899494b # v0.16 @@ -42,7 +42,7 @@ jobs: pull-requests: write security-events: write steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index bcc5f69a3..9714fc9cc 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -43,7 +43,7 @@ jobs: matrix: os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 532ce19d9..aae5de189 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -21,7 +21,7 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - name: Analysis diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 23a5a8c9a..be08c9cc2 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -22,7 +22,7 @@ jobs: SONAR_SCANNER_VERSION: 4.7.0.2747 SONAR_SERVER_URL: "https://sonarcloud.io" steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: fetch-depth: 0 # Disable shallow clone to enable blame information persist-credentials: false @@ -73,7 +73,7 @@ jobs: permissions: security-events: write steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - run: sudo apt-get update && sudo apt-get install ninja-build From 1ac21b18f8744f3f5d0644f9cdf04aea90295110 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 09:31:07 +0200 Subject: [PATCH 04/37] build(deps): bump actions/first-interaction from 1.1.1 to 1.2.0 (#421) Bumps [actions/first-interaction](https://github.com/actions/first-interaction) from 1.1.1 to 1.2.0. - [Release notes](https://github.com/actions/first-interaction/releases) - [Commits](https://github.com/actions/first-interaction/compare/1d8459ca65b335265f1285568221e229d45a995e...1dbfe1ba5525b8257e1f259b09745bee346d62d8) --- updated-dependencies: - dependency-name: actions/first-interaction dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/social-interaction.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/social-interaction.yml b/.github/workflows/social-interaction.yml index f03c75c26..ab77aaa8c 100644 --- a/.github/workflows/social-interaction.yml +++ b/.github/workflows/social-interaction.yml @@ -14,7 +14,7 @@ jobs: pull-requests: write if: ${{ github.actor != 'dependabot[bot]' }} steps: - - uses: actions/first-interaction@1d8459ca65b335265f1285568221e229d45a995e + - uses: actions/first-interaction@1dbfe1ba5525b8257e1f259b09745bee346d62d8 continue-on-error: true with: repo-token: ${{ secrets.GITHUB_TOKEN }} From e55a9d614496cc403d1e97bb3ff49055d5352f1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 09:33:28 +0200 Subject: [PATCH 05/37] build(deps): bump github/codeql-action from 2.21.7 to 2.21.9 (#422) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.7 to 2.21.9. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/04daf014b50eaf774287bf3f0f1869d4b4c4b913...ddccb873888234080b77e9bc2d4764d5ccaaccf9) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 6120c124c..8c5a4c61d 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -51,7 +51,7 @@ jobs: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/upload-sarif@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + - uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 if: ${{ success() }} || ${{ failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index aae5de189..858a8e9bd 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,6 @@ jobs: results_format: sarif repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} publish_results: true - - uses: github/codeql-action/upload-sarif@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + - uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 with: sarif_file: scorecards.sarif diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index be08c9cc2..c7ad14689 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -80,10 +80,10 @@ jobs: - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - - uses: github/codeql-action/init@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + - uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 with: languages: cpp - run: | cmake --preset host -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build --preset host-Debug - - uses: github/codeql-action/analyze@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + - uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 From c249b3eac7cb4b6b58a9439e60c5c68ae64b303e Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:22:35 +0200 Subject: [PATCH 06/37] chore: switch static analysis to container (#423) * chore: update devcontainer * chore: switch static analysis to container * chore: use correct configurations * chore: remove workaround for missing symlinks When running into issues using mutation testing, please update your local devcontainer. * chore: use correct mutation-testing preset * chore: update CMakePresets.json * chore: update googletest * chore: use nproc for -j parameters * chore: revert version update in CMakePresets.json * deps: update mbedtls to 3.4.1 to silence warning See: https://github.com/Mbed-TLS/mbedtls/pull/7098 * chore: fix compilation with clang-15 * chore: fix remaining issues --- .devcontainer/devcontainer.json | 2 +- .github/workflows/static-analysis.yml | 35 +++++++++++------------- CMakePresets.json | 6 ++--- cmake/emil_test_helpers.cmake | 37 +++++++++----------------- external/crypto/mbedtls/CMakeLists.txt | 4 +++ 5 files changed, 37 insertions(+), 47 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index df9f970f3..b91420f74 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,7 @@ // This devcontainer has been set-up to run docker-from-docker scenarios as per // https://github.com/microsoft/vscode-dev-containers/tree/main/containers/docker-from-docker "name": "amp-devcontainer", - "image": "ghcr.io/philips-software/amp-devcontainer:2.2.0", + "image": "ghcr.io/philips-software/amp-devcontainer:2.5.0", "runArgs": ["--add-host=host.docker.internal:host-gateway"], "remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }, "mounts": [ diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index c7ad14689..e6af0dae3 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -18,26 +18,20 @@ jobs: sonar: name: SonarCloud runs-on: ubuntu-latest + container: ghcr.io/philips-software/amp-devcontainer:2.5.0 env: - SONAR_SCANNER_VERSION: 4.7.0.2747 + SONAR_SCANNER_VERSION: 5.0.1.3006 SONAR_SERVER_URL: "https://sonarcloud.io" steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: fetch-depth: 0 # Disable shallow clone to enable blame information persist-credentials: false - - run: sudo apt-get update && sudo apt-get install --no-install-recommends jq ninja-build xsltproc - - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - - uses: BSFishy/pip-action@8f2d471d809dc20b6ada98c91910b6ae6243f318 - with: - packages: gcovr==5.2 - - name: Install Sonar Scanner & Mull + - name: Install Sonar Scanner run: | wget -qN "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${{ env.SONAR_SCANNER_VERSION }}-linux.zip" unzip -qqo "sonar-scanner-cli-${{ env.SONAR_SCANNER_VERSION }}-linux.zip" echo "${PWD}/sonar-scanner-${{ env.SONAR_SCANNER_VERSION }}-linux/bin" >> "$GITHUB_PATH" - wget -qN https://github.com/mull-project/mull/releases/download/0.18.0/Mull-12-0.18.0-LLVM-12.0-ubuntu-20.04.deb - sudo dpkg -i Mull-12-0.18.0-LLVM-12.0-ubuntu-20.04.deb - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} @@ -47,12 +41,13 @@ jobs: cmake --preset coverage -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build --preset coverage GTEST_OUTPUT="xml:${PWD}/testresults/" ctest --preset coverage - gcovr --sonarqube=coverage.xml --exclude-lines-by-pattern '.*assert\(.*\);|.*really_assert\(.*\);|.*std::abort();' --exclude-unreachable-branches --exclude-throw-branches -j 2 --exclude=.*/generated/.* --exclude=.*/examples/.* --exclude=.*/external/.* --exclude=.*/lwip/.* --exclude=.*/tracing/.* --exclude=.*/test/.* - - name: Build & Run Mutation Tests - run: | - cmake --preset mutation-testing -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - cmake --build --preset mutation-testing - ctest --preset mutation-testing + gcovr --sonarqube=coverage.xml --exclude-lines-by-pattern '.*assert\(.*\);|.*really_assert\(.*\);|.*std::abort();' --exclude-unreachable-branches --exclude-throw-branches -j "$(nproc)" --exclude=.*/generated/.* --exclude=.*/examples/.* --exclude=.*/external/.* --exclude=.*/lwip/.* --exclude=.*/tracing/.* --exclude=.*/test/.* + - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + with: + configurePreset: "mutation-testing" + buildPreset: "mutation-testing" + testPreset: "mutation-testing" + configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" - name: Convert Results run: | { echo ''; xsltproc .github/formatters/gtest-to-generic-execution.xslt testresults/*.xml; echo ''; } | tee execution.xml > /dev/null @@ -70,20 +65,22 @@ jobs: codeql: name: CodeQL runs-on: ubuntu-latest + container: ghcr.io/philips-software/amp-devcontainer:2.5.0 permissions: security-events: write steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - - run: sudo apt-get update && sudo apt-get install ninja-build - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 with: languages: cpp - - run: | - cmake --preset host -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - cmake --build --preset host-Debug + - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + with: + configurePreset: "host" + buildPreset: "host-Debug" + configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" - uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 diff --git a/CMakePresets.json b/CMakePresets.json index 01edcde73..1442446cf 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -52,10 +52,10 @@ "displayName": "Configuration for Mutation Testing", "inherits": "host", "cacheVariables": { - "CMAKE_C_COMPILER": "clang-12", - "CMAKE_CXX_COMPILER": "clang++-12", + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++", "EMIL_ENABLE_MUTATION_TESTING": "On", - "EMIL_MUTATION_TESTING_RUNNER_ARGUMENTS": "--reporters;Elements;--report-dir;${sourceDir}/reports/mull" + "EMIL_MUTATION_TESTING_RUNNER_ARGUMENTS": "--allow-surviving;--reporters;Elements;--report-dir;${sourceDir}/reports/mull" }, "generator": "Ninja" }, diff --git a/cmake/emil_test_helpers.cmake b/cmake/emil_test_helpers.cmake index 5be8b44f7..3336f6ee7 100644 --- a/cmake/emil_test_helpers.cmake +++ b/cmake/emil_test_helpers.cmake @@ -2,12 +2,10 @@ option(EMIL_ENABLE_COVERAGE "Enable compiler flags for code coverage measurement option(EMIL_ENABLE_MUTATION_TESTING "Enable compiler flags for mutation testing" Off) set(EMIL_MUTATION_TESTING_RUNNER_ARGUMENTS "" CACHE STRING "Additional arguments for the mutation testing runner") -function(emil_enable_testing) - include(GoogleTest) - +function(emil_fetch_googletest) FetchContent_Declare( googletest - GIT_REPOSITORY https://github.com/google/googletest.git + GIT_REPOSITORY https://github.com/google/googletest GIT_TAG release-1.12.1 ) @@ -18,6 +16,12 @@ function(emil_enable_testing) set_target_properties(gtest gtest_main gmock gmock_main PROPERTIES FOLDER External/GoogleTest) mark_as_advanced(BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS gmock_build_tests gtest_build_samples test_build_tests gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols) +endfunction() + +function(emil_enable_testing) + include(GoogleTest) + + emil_fetch_googletest() if (EMIL_ENABLE_COVERAGE) add_compile_options( @@ -34,19 +38,10 @@ function(emil_enable_testing) if (EMIL_ENABLE_MUTATION_TESTING) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CLANG_VERSION) - - if(CLANG_VERSION VERSION_GREATER 15.0 OR CLANG_VERSION VERSION_EQUAL 15.0) - add_compile_options( - -g -O0 -grecord-command-line -fprofile-instr-generate -fcoverage-mapping - -fexperimental-new-pass-manager -fpass-plugin=/usr/lib/mull-ir-frontend - ) - else() - add_compile_options( - -g -O0 -grecord-command-line -fprofile-instr-generate -fcoverage-mapping - -fexperimental-new-pass-manager -fpass-plugin=/usr/lib/mull-ir-frontend-12 - ) - endif() + add_compile_options( + -g -O0 -grecord-command-line -fprofile-instr-generate -fcoverage-mapping + -fexperimental-new-pass-manager -fpass-plugin=/usr/lib/mull-ir-frontend + ) add_link_options(-fprofile-instr-generate) else() @@ -68,13 +63,7 @@ function(emil_add_test target) get_target_property(exclude ${target} EXCLUDE_FROM_ALL) if (NOT ${exclude}) if (EMIL_ENABLE_MUTATION_TESTING) - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CLANG_VERSION) - - if(CLANG_VERSION VERSION_GREATER 15.0 OR CLANG_VERSION VERSION_EQUAL 15.0) - add_test(NAME ${target} COMMAND mull-runner ${EMIL_MUTATION_TESTING_RUNNER_ARGUMENTS} $) - else() - add_test(NAME ${target} COMMAND mull-runner-12 ${EMIL_MUTATION_TESTING_RUNNER_ARGUMENTS} $) - endif() + add_test(NAME ${target} COMMAND mull-runner ${EMIL_MUTATION_TESTING_RUNNER_ARGUMENTS} $) else() add_test(NAME ${target} COMMAND ${target}) endif() diff --git a/external/crypto/mbedtls/CMakeLists.txt b/external/crypto/mbedtls/CMakeLists.txt index db0eb2144..b5514e418 100644 --- a/external/crypto/mbedtls/CMakeLists.txt +++ b/external/crypto/mbedtls/CMakeLists.txt @@ -17,6 +17,10 @@ function(add_mbedtls_target_properties) foreach(target ${ARGN}) target_compile_options(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/mbedtls_emil_config.h" + # see https://github.com/Mbed-TLS/mbedtls/pull/6966 + # mbedtls sets the -Wdocumentation flag, which is throwing warnings + # since clang-15 + $<$:-Wno-documentation> ) target_include_directories(${target} PUBLIC From 7b2ada0c54ff2402c360df4f700c8653d9ed65a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:01:46 +0000 Subject: [PATCH 07/37] build(deps): bump oxsecurity/megalinter from 7.3.0 to 7.4.0 (#419) * build(deps): bump oxsecurity/megalinter from 7.3.0 to 7.4.0 Bumps [oxsecurity/megalinter](https://github.com/oxsecurity/megalinter) from 7.3.0 to 7.4.0. - [Release notes](https://github.com/oxsecurity/megalinter/releases) - [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md) - [Commits](https://github.com/oxsecurity/megalinter/compare/fda6ac3a38be0e969820709ac16e442464e5a035...a87b2872713c6bdde46d2473c5d7ed23e5752dc2) --- updated-dependencies: - dependency-name: oxsecurity/megalinter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore: fix linter findings --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ron <45816308+rjaegers@users.noreply.github.com> --- .github/workflows/dependency-scanner.yml | 2 +- .github/workflows/linting-formatting.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dependency-scanner.yml b/.github/workflows/dependency-scanner.yml index 1f584aaa8..25ee4c5ce 100644 --- a/.github/workflows/dependency-scanner.yml +++ b/.github/workflows/dependency-scanner.yml @@ -20,7 +20,7 @@ jobs: - uses: philips-forks/cmake-dependency-submission@72880580a7cafc16145d82268f1892c0ece3da2a # main dependency-review: runs-on: ubuntu-latest - if: github.event_name == 'pull_request' + if: ${{ github.event_name == 'pull_request' }} needs: [dependency-submission] permissions: pull-requests: write diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 8c5a4c61d..21860556d 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -46,17 +46,17 @@ jobs: with: fetch-depth: 0 persist-credentials: false - - uses: oxsecurity/megalinter@fda6ac3a38be0e969820709ac16e442464e5a035 # v7.3.0 + - uses: oxsecurity/megalinter@a87b2872713c6bdde46d2473c5d7ed23e5752dc2 # v7.4.0 env: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 - if: ${{ success() }} || ${{ failure() }} + if: ${{ success() || failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - if: ${{ success() }} || ${{ failure() }} + if: ${{ success() || failure() }} with: name: linter path: | From f5260dd65ae4adfea14755dfef04a18074441951 Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Thu, 28 Sep 2023 18:23:50 +0200 Subject: [PATCH 08/37] feat: add protobuf/echo/ProtoMessageBuilder (#416) * feat: add protobuf/echo/ProtoMessageBuilder * ProtoCEchoPlugin: Fix superfluous typename * protobuf/echoProtoMessageBuilder: Parse a lot of different types * protobuf/echoProtoMessageBuilder: Parse enums, strings, extract BuferingStreamReader * Resolve code warnings, increase coverage * protobuf/echo: Add BufferingStreamWriter * protobuf/echo: Add half of ProtoMessageSender * protobuf/echo/ProtoMessageSender: Serialize lots of types * protobuf/echo/ProtoMessageSender: Fix missing template keyword * protobuf/echo/ProtoMessageSender: Serialize lots of types * protobuf/protoc_echo_plugin/ProtoCEchoPlugin: Modify result of MessageReference::Get() const to avoid a warning * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * protobuf/echo/BufferingStreamReader: Make BufferingStreamReader accept a stream reader instead of a byte range * protobuf/echo/BufferingStreamReader: Remove useless comment * Resolve Sonar warnings * Resolve Sonar warnings * Move BufferingSteamReader and BufferingStreamWriter to infra/stream * infra/stream/test: Add tests for BufferingStreamReader and BufferingStreamWriter * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Resolve Sonar warnings * Resolve Sonar warnings * Resolve Sonar warnings * Reduce duplication * Update services/network/test_doubles/Certificates.cpp --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Ron <45816308+rjaegers@users.noreply.github.com> --- infra/stream/BufferingStreamReader.cpp | 107 ++++ infra/stream/BufferingStreamReader.hpp | 39 ++ infra/stream/BufferingStreamWriter.cpp | 65 +++ infra/stream/BufferingStreamWriter.hpp | 36 ++ infra/stream/CMakeLists.txt | 4 + infra/stream/test/CMakeLists.txt | 2 + .../stream/test/TestBufferingStreamReader.cpp | 206 +++++++ .../stream/test/TestBufferingStreamWriter.cpp | 103 ++++ infra/syntax/ProtoFormatter.cpp | 6 + infra/syntax/ProtoFormatter.hpp | 2 + infra/syntax/ProtoParser.cpp | 35 +- infra/syntax/ProtoParser.hpp | 11 +- infra/syntax/test/TestProtoFormatter.cpp | 11 + infra/util/ConstructBin.cpp | 7 + infra/util/ConstructBin.hpp | 1 + infra/util/WithStorage.hpp | 9 + protobuf/CMakeLists.txt | 2 +- protobuf/echo/CMakeLists.txt | 5 + protobuf/echo/Echo.hpp | 373 +----------- protobuf/echo/Proto.hpp | 541 ++++++++++++++++++ protobuf/echo/ProtoMessageReceiver.cpp | 142 +++++ protobuf/echo/ProtoMessageReceiver.hpp | 173 ++++++ protobuf/echo/ProtoMessageSender.cpp | 132 +++++ protobuf/echo/ProtoMessageSender.hpp | 180 ++++++ protobuf/echo/test/CMakeLists.txt | 4 + .../test/TestMessages.proto | 13 +- .../echo/test/TestProtoMessageReceiver.cpp | 222 +++++++ protobuf/echo/test/TestProtoMessageSender.cpp | 222 +++++++ protobuf/echo/test_doubles/ServiceStub.cpp | 2 +- .../protoc_echo_plugin/ProtoCEchoPlugin.cpp | 62 +- .../protoc_echo_plugin/ProtoCEchoPlugin.hpp | 11 +- .../protoc_echo_plugin/test/CMakeLists.txt | 2 +- .../test/TestProtoCEchoPlugin.cpp | 73 +++ .../network/test_doubles/Certificates.cpp | 4 +- 34 files changed, 2393 insertions(+), 414 deletions(-) create mode 100644 infra/stream/BufferingStreamReader.cpp create mode 100644 infra/stream/BufferingStreamReader.hpp create mode 100644 infra/stream/BufferingStreamWriter.cpp create mode 100644 infra/stream/BufferingStreamWriter.hpp create mode 100644 infra/stream/test/TestBufferingStreamReader.cpp create mode 100644 infra/stream/test/TestBufferingStreamWriter.cpp create mode 100644 protobuf/echo/Proto.hpp create mode 100644 protobuf/echo/ProtoMessageReceiver.cpp create mode 100644 protobuf/echo/ProtoMessageReceiver.hpp create mode 100644 protobuf/echo/ProtoMessageSender.cpp create mode 100644 protobuf/echo/ProtoMessageSender.hpp rename protobuf/{protoc_echo_plugin => echo}/test/TestMessages.proto (92%) create mode 100644 protobuf/echo/test/TestProtoMessageReceiver.cpp create mode 100644 protobuf/echo/test/TestProtoMessageSender.cpp diff --git a/infra/stream/BufferingStreamReader.cpp b/infra/stream/BufferingStreamReader.cpp new file mode 100644 index 000000000..a2c2289ce --- /dev/null +++ b/infra/stream/BufferingStreamReader.cpp @@ -0,0 +1,107 @@ +#include "infra/stream/BufferingStreamReader.hpp" + +namespace infra +{ + BufferingStreamReader::BufferingStreamReader(infra::BoundedDeque& buffer, infra::StreamReaderWithRewinding& input) + : buffer(buffer) + , input(input) + {} + + BufferingStreamReader::~BufferingStreamReader() + { + StoreRemainder(); + } + + void BufferingStreamReader::Extract(infra::ByteRange range, infra::StreamErrorPolicy& errorPolicy) + { + if (index != buffer.size()) + { + Read(infra::Head(buffer.contiguous_range(buffer.begin() + index), range.size()), range); + // Perhaps the deque just wrapped around, try once more + Read(infra::Head(buffer.contiguous_range(buffer.begin() + index), range.size()), range); + } + + if (!range.empty()) + Read(input.ExtractContiguousRange(range.size()), range); + + errorPolicy.ReportResult(range.empty()); + } + + uint8_t BufferingStreamReader::Peek(infra::StreamErrorPolicy& errorPolicy) + { + auto range = PeekContiguousRange(0); + + errorPolicy.ReportResult(!range.empty()); + + if (range.empty()) + return 0; + else + return range.front(); + } + + infra::ConstByteRange BufferingStreamReader::ExtractContiguousRange(std::size_t max) + { + if (index < buffer.size()) + { + auto from = infra::Head(buffer.contiguous_range(buffer.begin() + index), max); + index += from.size(); + return from; + } + + return input.ExtractContiguousRange(max); + } + + infra::ConstByteRange BufferingStreamReader::PeekContiguousRange(std::size_t start) + { + if (index + start < buffer.size()) + return buffer.contiguous_range(buffer.begin() + index + start); + + return input.PeekContiguousRange(index + start - buffer.size()); + } + + bool BufferingStreamReader::Empty() const + { + return Available() == 0; + } + + std::size_t BufferingStreamReader::Available() const + { + return buffer.size() + input.Available(); + } + + std::size_t BufferingStreamReader::ConstructSaveMarker() const + { + return index; + } + + void BufferingStreamReader::Rewind(std::size_t marker) + { + if (index > buffer.size()) + { + auto rewindAmount = std::min(index - marker, index - buffer.size()); + input.Rewind(input.ConstructSaveMarker() - rewindAmount); + index -= rewindAmount; + } + + if (marker < buffer.size()) + index = marker; + } + + void BufferingStreamReader::Read(infra::ConstByteRange from, infra::ByteRange& to) + { + infra::Copy(from, infra::Head(to, from.size())); + to.pop_front(from.size()); + index += from.size(); + } + + void BufferingStreamReader::StoreRemainder() + { + std::size_t bufferDecrease = std::min(buffer.size(), index); + buffer.erase(buffer.begin(), buffer.begin() + bufferDecrease); + while (!input.Empty()) + { + auto range = input.ExtractContiguousRange(std::numeric_limits::max()); + buffer.insert(buffer.end(), range.begin(), range.end()); + } + } +} diff --git a/infra/stream/BufferingStreamReader.hpp b/infra/stream/BufferingStreamReader.hpp new file mode 100644 index 000000000..3df25964f --- /dev/null +++ b/infra/stream/BufferingStreamReader.hpp @@ -0,0 +1,39 @@ +#ifndef INFRA_BUFFERING_STREAM_READER_HPP +#define INFRA_BUFFERING_STREAM_READER_HPP + +#include "infra/stream/InputStream.hpp" +#include "infra/util/BoundedDeque.hpp" + +namespace infra +{ + // Usage: Everything that is not read from the inputData is stored into the buffer upon destruction of the BufferingStreamReader + // Any data already present in the buffer is read first from the reader + class BufferingStreamReader + : public infra::StreamReaderWithRewinding + { + public: + BufferingStreamReader(infra::BoundedDeque& buffer, infra::StreamReaderWithRewinding& input); + ~BufferingStreamReader() override; + + // Implementation of StreamReaderWithRewinding + void Extract(infra::ByteRange range, infra::StreamErrorPolicy& errorPolicy) override; + uint8_t Peek(infra::StreamErrorPolicy& errorPolicy) override; + infra::ConstByteRange ExtractContiguousRange(std::size_t max) override; + infra::ConstByteRange PeekContiguousRange(std::size_t start) override; + bool Empty() const override; + std::size_t Available() const override; + std::size_t ConstructSaveMarker() const override; + void Rewind(std::size_t marker) override; + + private: + void Read(infra::ConstByteRange range, infra::ByteRange& to); + void StoreRemainder(); + + private: + infra::BoundedDeque& buffer; + infra::StreamReaderWithRewinding& input; + std::size_t index = 0; + }; +} + +#endif diff --git a/infra/stream/BufferingStreamWriter.cpp b/infra/stream/BufferingStreamWriter.cpp new file mode 100644 index 000000000..c66445491 --- /dev/null +++ b/infra/stream/BufferingStreamWriter.cpp @@ -0,0 +1,65 @@ +#include "infra/stream/BufferingStreamWriter.hpp" + +namespace infra +{ + BufferingStreamWriter::BufferingStreamWriter(infra::BoundedDeque& buffer, infra::StreamWriter& output) + : buffer(buffer) + , output(output) + { + LoadRemainder(); + } + + void BufferingStreamWriter::Insert(infra::ConstByteRange range, infra::StreamErrorPolicy& errorPolicy) + { + auto first = infra::Head(range, output.Available()); + output.Insert(first, errorPolicy); + index += first.size(); + range.pop_front(first.size()); + + buffer.insert(buffer.end(), range.begin(), range.end()); + index += range.size(); + } + + std::size_t BufferingStreamWriter::Available() const + { + return output.Available() + buffer.max_size() - buffer.size(); + } + + std::size_t BufferingStreamWriter::ConstructSaveMarker() const + { + return index; + } + + std::size_t BufferingStreamWriter::GetProcessedBytesSince(std::size_t marker) const + { + return index - marker; + } + + [[noreturn]] infra::ByteRange BufferingStreamWriter::SaveState(std::size_t marker) + { + std::abort(); + } + + [[noreturn]] void BufferingStreamWriter::RestoreState(infra::ByteRange range) + { + std::abort(); + } + + [[noreturn]] infra::ByteRange BufferingStreamWriter::Overwrite(std::size_t marker) + { + std::abort(); + } + + void BufferingStreamWriter::LoadRemainder() + { + infra::StreamErrorPolicy errorPolicy; + auto from = infra::Head(buffer.contiguous_range(buffer.begin()), output.Available()); + output.Insert(from, errorPolicy); + buffer.erase(buffer.begin(), buffer.begin() + from.size()); + from = infra::Head(buffer.contiguous_range(buffer.begin()), output.Available()); + output.Insert(from, errorPolicy); + buffer.erase(buffer.begin(), buffer.begin() + from.size()); + + index = buffer.size(); + } +} diff --git a/infra/stream/BufferingStreamWriter.hpp b/infra/stream/BufferingStreamWriter.hpp new file mode 100644 index 000000000..79f2d4216 --- /dev/null +++ b/infra/stream/BufferingStreamWriter.hpp @@ -0,0 +1,36 @@ +#ifndef INFRA_BUFFERING_STREAM_WRITER_HPP +#define INFRA_BUFFERING_STREAM_WRITER_HPP + +#include "infra/stream/OutputStream.hpp" +#include "infra/util/BoundedDeque.hpp" + +namespace infra +{ + // Usage: Any data that does not fit into the output stream is written to the buffer + // Any data already present in the buffer is written to the output stream upon construction of BufferingStreamWriter + class BufferingStreamWriter + : public infra::StreamWriter + { + public: + BufferingStreamWriter(infra::BoundedDeque& buffer, infra::StreamWriter& output); + + // Implementation of StreamWriter + void Insert(infra::ConstByteRange range, infra::StreamErrorPolicy& errorPolicy) override; + std::size_t Available() const override; + std::size_t ConstructSaveMarker() const override; + std::size_t GetProcessedBytesSince(std::size_t marker) const override; + [[noreturn]] infra::ByteRange SaveState(std::size_t marker) override; + [[noreturn]] void RestoreState(infra::ByteRange range) override; + [[noreturn]] infra::ByteRange Overwrite(std::size_t marker) override; + + private: + void LoadRemainder(); + + private: + infra::BoundedDeque& buffer; + infra::StreamWriter& output; + std::size_t index = 0; + }; +} + +#endif diff --git a/infra/stream/CMakeLists.txt b/infra/stream/CMakeLists.txt index eab26fd3f..4b3537a71 100644 --- a/infra/stream/CMakeLists.txt +++ b/infra/stream/CMakeLists.txt @@ -13,6 +13,10 @@ target_sources(infra.stream PRIVATE BoundedVectorInputStream.hpp BoundedVectorOutputStream.cpp BoundedVectorOutputStream.hpp + BufferingStreamReader.cpp + BufferingStreamReader.hpp + BufferingStreamWriter.cpp + BufferingStreamWriter.hpp ByteInputStream.cpp ByteInputStream.hpp ByteOutputStream.cpp diff --git a/infra/stream/test/CMakeLists.txt b/infra/stream/test/CMakeLists.txt index 957be3ce4..c3bfcaece 100644 --- a/infra/stream/test/CMakeLists.txt +++ b/infra/stream/test/CMakeLists.txt @@ -12,6 +12,8 @@ target_sources(infra.stream_test PRIVATE StreamMock.hpp TestBoundedDequeInputStream.cpp TestBoundedVectorOutputStream.cpp + TestBufferingStreamReader.cpp + TestBufferingStreamWriter.cpp TestByteInputStream.cpp TestByteOutputStream.cpp TestCountingInputStream.cpp diff --git a/infra/stream/test/TestBufferingStreamReader.cpp b/infra/stream/test/TestBufferingStreamReader.cpp new file mode 100644 index 000000000..1d58c3b79 --- /dev/null +++ b/infra/stream/test/TestBufferingStreamReader.cpp @@ -0,0 +1,206 @@ +#include "infra/stream/BufferingStreamReader.hpp" +#include "infra/stream/test/StreamMock.hpp" +#include "gmock/gmock.h" + +class BufferingStreamReaderTest + : public testing::Test +{ +public: + ~BufferingStreamReaderTest() + { + EXPECT_CALL(input, Empty()).WillOnce(testing::Return(true)); + } + + void Extract(std::size_t amount) + { + std::vector data(amount, 0); + std::vector inputData; + EXPECT_CALL(input, ExtractContiguousRange(testing::_)).Times(testing::AnyNumber()).WillRepeatedly(testing::Invoke([&](std::size_t max) + { + inputData.resize(max); + return infra::MakeRange(inputData); + })); + reader.Extract(infra::MakeRange(data), errorPolicy); + } + + void ExpectBuffer(const std::vector contents) + { + EXPECT_EQ(infra::BoundedDeque::WithMaxSize<100>(contents.begin(), contents.end()), buffer); + } + + infra::BoundedDeque::WithMaxSize<4> buffer{ std::initializer_list{ 1, 2 } }; + testing::StrictMock input; + infra::StreamErrorPolicy errorPolicy{ infra::noFail }; + infra::BufferingStreamReader reader{ buffer, input }; +}; + +TEST_F(BufferingStreamReaderTest, Extract_from_empty_buffer) +{ + buffer.clear(); + std::array data; + EXPECT_CALL(input, ExtractContiguousRange(2)).WillOnce(testing::Return(infra::ConstByteRange())); + reader.Extract(data, errorPolicy); + EXPECT_TRUE(errorPolicy.Failed()); +} + +TEST_F(BufferingStreamReaderTest, Extract_from_buffer) +{ + std::array data; + reader.Extract(data, errorPolicy); + EXPECT_EQ((std::array{ 1, 2 }), data); + EXPECT_FALSE(errorPolicy.Failed()); +} + +TEST_F(BufferingStreamReaderTest, Extract_from_wrapped_buffer) +{ + buffer.push_back(3); + buffer.push_back(4); + buffer.pop_front(); + buffer.pop_front(); + buffer.push_back(5); + buffer.push_back(6); + + std::array data; + reader.Extract(data, errorPolicy); + EXPECT_EQ((std::array{ 3, 4, 5, 6 }), data); +} + +TEST_F(BufferingStreamReaderTest, Extract_from_buffer_and_input) +{ + std::array data; + std::array inputData{ 3, 4 }; + EXPECT_CALL(input, ExtractContiguousRange(2)).WillOnce(testing::Invoke([&](std::size_t max) + { + return infra::MakeRange(inputData); + })); + reader.Extract(data, errorPolicy); + EXPECT_EQ((std::array{ 1, 2, 3, 4 }), data); +} + +TEST_F(BufferingStreamReaderTest, PeekContiguous_range_from_buffer_head) +{ + EXPECT_EQ((std::array{ 1, 2 }), reader.PeekContiguousRange(0)); +} + +TEST_F(BufferingStreamReaderTest, PeekContiguous_range_from_buffer_1) +{ + EXPECT_EQ((std::array{ 2 }), reader.PeekContiguousRange(1)); +} + +TEST_F(BufferingStreamReaderTest, PeekContiguous_range_from_input) +{ + std::array inputData{ 3, 4 }; + EXPECT_CALL(input, PeekContiguousRange(0)).WillOnce(testing::Invoke([&](std::size_t start) + { + return infra::MakeRange(inputData); + })); + EXPECT_EQ((std::array{ 3, 4 }), reader.PeekContiguousRange(2)); +} + +TEST_F(BufferingStreamReaderTest, Peek_from_buffer) +{ + EXPECT_EQ(1, reader.Peek(errorPolicy)); + reader.ExtractContiguousRange(2); + + std::array inputData{ 3, 4 }; + EXPECT_CALL(input, PeekContiguousRange(0)).WillOnce(testing::Invoke([&](std::size_t start) + { + return infra::MakeRange(inputData); + })); + EXPECT_EQ(3, reader.Peek(errorPolicy)); +} + +TEST_F(BufferingStreamReaderTest, Available) +{ + EXPECT_CALL(input, Available()).WillOnce(testing::Return(1)); + EXPECT_EQ(3, reader.Available()); + + EXPECT_CALL(input, Available()).WillOnce(testing::Return(1)); + EXPECT_FALSE(reader.Empty()); +} + +TEST_F(BufferingStreamReaderTest, ConstructSaveMarker) +{ + EXPECT_EQ(0, reader.ConstructSaveMarker()); + + reader.ExtractContiguousRange(2); + EXPECT_EQ(2, reader.ConstructSaveMarker()); +} + +TEST_F(BufferingStreamReaderTest, Rewind_in_buffer) +{ + reader.ExtractContiguousRange(2); + reader.Rewind(1); + EXPECT_EQ(2, reader.Peek(errorPolicy)); +} + +TEST_F(BufferingStreamReaderTest, Rewind_from_input_to_input) +{ + Extract(4); + + EXPECT_CALL(input, ConstructSaveMarker()).WillOnce(testing::Return(100)); + EXPECT_CALL(input, Rewind(99)); + reader.Rewind(3); + std::array inputData2{ 4 }; + EXPECT_CALL(input, PeekContiguousRange(1)).WillOnce(testing::Invoke([&](std::size_t start) + { + return infra::MakeRange(inputData2); + })); + EXPECT_EQ(4, reader.Peek(errorPolicy)); +} + +TEST_F(BufferingStreamReaderTest, Rewind_from_input_to_buffer) +{ + Extract(4); + + EXPECT_CALL(input, ConstructSaveMarker()).WillOnce(testing::Return(100)); + EXPECT_CALL(input, Rewind(98)); + reader.Rewind(1); + EXPECT_EQ(2, reader.Peek(errorPolicy)); +} + +TEST_F(BufferingStreamReaderTest, destruction_reduces_buffer) +{ + Extract(1); + + EXPECT_CALL(input, Empty()).WillOnce(testing::Return(true)); + infra::ReConstruct(reader, buffer, input); + + ExpectBuffer({ 2 }); +} + +TEST_F(BufferingStreamReaderTest, destruction_consumes_buffer) +{ + Extract(3); + + EXPECT_CALL(input, Empty()).WillOnce(testing::Return(true)); + infra::ReConstruct(reader, buffer, input); + + ExpectBuffer({}); +} + +TEST_F(BufferingStreamReaderTest, destruction_stores_input) +{ + EXPECT_CALL(input, Empty()).WillOnce(testing::Return(false)).WillOnce(testing::Return(true)); + std::array inputData{ 3, 4 }; + EXPECT_CALL(input, ExtractContiguousRange(std::numeric_limits::max())).WillOnce(testing::Invoke([&](std::size_t max) + { + return infra::MakeRange(inputData); + })); + infra::ReConstruct(reader, buffer, input); + + ExpectBuffer({ 1, 2, 3, 4 }); +} + +TEST_F(BufferingStreamReaderTest, destruction_stores_input_until_empty) +{ + EXPECT_CALL(input, Empty()).WillOnce(testing::Return(false)).WillOnce(testing::Return(false)).WillOnce(testing::Return(true)); + std::array inputData{ 3 }; + EXPECT_CALL(input, ExtractContiguousRange(std::numeric_limits::max())).WillRepeatedly(testing::Invoke([&](std::size_t max) + { + return infra::MakeRange(inputData); + })); + infra::ReConstruct(reader, buffer, input); + + ExpectBuffer({ 1, 2, 3, 3 }); +} diff --git a/infra/stream/test/TestBufferingStreamWriter.cpp b/infra/stream/test/TestBufferingStreamWriter.cpp new file mode 100644 index 000000000..2bb6db290 --- /dev/null +++ b/infra/stream/test/TestBufferingStreamWriter.cpp @@ -0,0 +1,103 @@ +#include "infra/stream/BufferingStreamWriter.hpp" +#include "infra/stream/test/StreamMock.hpp" +#include "infra/util/test_helper/MemoryRangeMatcher.hpp" +#include "gmock/gmock.h" + +class BufferingStreamWriterTest + : public testing::Test +{ +public: + void ExpectBuffer(const std::vector contents) + { + EXPECT_EQ(infra::BoundedDeque::WithMaxSize<100>(contents.begin(), contents.end()), buffer); + } + + infra::BoundedDeque::WithMaxSize<4> buffer; + testing::StrictMock output; + infra::StreamErrorPolicy errorPolicy{ infra::noFail }; + infra::Execute execute{ [this]() + { + EXPECT_CALL(output, Available()).WillRepeatedly(testing::Return(0)); + EXPECT_CALL(output, Insert(testing::_, testing::_)).Times(2); + } }; + infra::BufferingStreamWriter writer{ buffer, output }; +}; + +TEST_F(BufferingStreamWriterTest, Insert_into_output) +{ + std::array data{ 3, 4 }; + EXPECT_CALL(output, Available()).WillOnce(testing::Return(10)); + EXPECT_CALL(output, Insert(infra::ContentsEqual(data), testing::Ref(errorPolicy))); + writer.Insert(data, errorPolicy); + + ExpectBuffer({}); + EXPECT_EQ(2, writer.ConstructSaveMarker()); +} + +TEST_F(BufferingStreamWriterTest, Insert_overflows_output) +{ + std::array data{ 3, 4 }; + EXPECT_CALL(output, Available()).WillOnce(testing::Return(1)); + EXPECT_CALL(output, Insert(infra::ByteRangeContentsEqual(infra::Head(infra::MakeRange(data), 1)), testing::Ref(errorPolicy))); + writer.Insert(data, errorPolicy); + + ExpectBuffer({ 4 }); + EXPECT_EQ(2, writer.ConstructSaveMarker()); +} + +TEST_F(BufferingStreamWriterTest, GetProcessedBytesSince) +{ + EXPECT_EQ(0, writer.GetProcessedBytesSince(0)); + + std::array data{ 3, 4 }; + EXPECT_CALL(output, Available()).WillOnce(testing::Return(10)); + EXPECT_CALL(output, Insert(infra::ContentsEqual(data), testing::Ref(errorPolicy))); + writer.Insert(data, errorPolicy); + + EXPECT_EQ(2, writer.GetProcessedBytesSince(0)); + EXPECT_EQ(1, writer.GetProcessedBytesSince(1)); +} + +TEST_F(BufferingStreamWriterTest, LoadRemainder_loads_from_buffer) +{ + std::array data{ 1, 2 }; + buffer.insert(buffer.end(), data.begin(), data.end()); + + EXPECT_CALL(output, Available()).WillOnce(testing::Return(2)).WillOnce(testing::Return(0)); + EXPECT_CALL(output, Insert(infra::ContentsEqual(data), testing::_)); + EXPECT_CALL(output, Insert(infra::ByteRangeContentsEqual(infra::ConstByteRange()), testing::_)); + infra::ReConstruct(writer, buffer, output); +} + +TEST_F(BufferingStreamWriterTest, LoadRemainder_loads_from_circular_buffer) +{ + std::array data1{ 1, 2 }; + std::array data2{ 3, 4 }; + std::array data3{ 5, 6 }; + buffer.insert(buffer.end(), data1.begin(), data1.end()); + buffer.insert(buffer.end(), data2.begin(), data2.end()); + buffer.pop_front(); + buffer.pop_front(); + buffer.insert(buffer.end(), data3.begin(), data3.end()); + + EXPECT_CALL(output, Available()).WillOnce(testing::Return(4)).WillOnce(testing::Return(2)); + EXPECT_CALL(output, Insert(infra::ContentsEqual(data2), testing::_)); + EXPECT_CALL(output, Insert(infra::ContentsEqual(data3), testing::_)); + infra::ReConstruct(writer, buffer, output); +} + +TEST_F(BufferingStreamWriterTest, LoadRemainder_constrained_by_output_writes_in_chunks) +{ + std::array data{ 1, 2 }; + buffer.insert(buffer.end(), data.begin(), data.end()); + + EXPECT_CALL(output, Available()).WillOnce(testing::Return(1)).WillOnce(testing::Return(0)); + EXPECT_CALL(output, Insert(infra::ByteRangeContentsEqual(infra::Head(infra::MakeRange(data), 1)), testing::_)); + EXPECT_CALL(output, Insert(infra::ByteRangeContentsEqual(infra::ConstByteRange()), testing::_)); + infra::ReConstruct(writer, buffer, output); + + EXPECT_CALL(output, Available()).WillOnce(testing::Return(1)).WillOnce(testing::Return(0)); + EXPECT_CALL(output, Insert(infra::ByteRangeContentsEqual(infra::DiscardHead(infra::MakeRange(data), 1)), testing::_)); + EXPECT_CALL(output, Insert(infra::ByteRangeContentsEqual(infra::ConstByteRange()), testing::_)); + infra::ReConstruct(writer, buffer, output); +} diff --git a/infra/syntax/ProtoFormatter.cpp b/infra/syntax/ProtoFormatter.cpp index efb630d04..7b3e9d99a 100644 --- a/infra/syntax/ProtoFormatter.cpp +++ b/infra/syntax/ProtoFormatter.cpp @@ -130,6 +130,12 @@ namespace infra PutBytes(bytes); } + void ProtoFormatter::PutLengthDelimitedSize(std::size_t size, uint32_t fieldNumber) + { + PutVarInt((fieldNumber << 3) | 2); + PutVarInt(size); + } + ProtoLengthDelimitedFormatter ProtoFormatter::LengthDelimitedFormatter(uint32_t fieldNumber) { return ProtoLengthDelimitedFormatter(*this, fieldNumber); diff --git a/infra/syntax/ProtoFormatter.hpp b/infra/syntax/ProtoFormatter.hpp index 45748075b..7c717ce3c 100644 --- a/infra/syntax/ProtoFormatter.hpp +++ b/infra/syntax/ProtoFormatter.hpp @@ -14,6 +14,7 @@ namespace infra { public: ProtoLengthDelimitedFormatter(ProtoFormatter& formatter, uint32_t fieldNumber); + ProtoLengthDelimitedFormatter(ProtoFormatter& formatter, uint32_t fieldNumber, std::size_t size); ProtoLengthDelimitedFormatter(const ProtoLengthDelimitedFormatter& other) = delete; ProtoLengthDelimitedFormatter(ProtoLengthDelimitedFormatter&& other) noexcept; ProtoLengthDelimitedFormatter& operator=(const ProtoLengthDelimitedFormatter& other) = delete; @@ -43,6 +44,7 @@ namespace infra void PutLengthDelimitedField(infra::ConstByteRange range, uint32_t fieldNumber); void PutStringField(infra::BoundedConstString string, uint32_t fieldNumber); void PutBytesField(infra::ConstByteRange bytes, uint32_t fieldNumber); + void PutLengthDelimitedSize(std::size_t size, uint32_t fieldNumber); ProtoLengthDelimitedFormatter LengthDelimitedFormatter(uint32_t fieldNumber); private: diff --git a/infra/syntax/ProtoParser.cpp b/infra/syntax/ProtoParser.cpp index 513ebf7a6..8b5e09fb5 100644 --- a/infra/syntax/ProtoParser.cpp +++ b/infra/syntax/ProtoParser.cpp @@ -116,7 +116,40 @@ namespace infra return result; } + struct MakeFullField + : infra::StaticVisitor + { + MakeFullField(infra::DataInputStream inputStream, infra::StreamErrorPolicy& formatErrorPolicy, uint32_t fieldNumber) + : inputStream(inputStream) + , formatErrorPolicy(formatErrorPolicy) + , fieldNumber(fieldNumber) + {} + + template + ProtoParser::Field operator()(T value) const + { + return { value, fieldNumber }; + } + + ProtoParser::Field operator()(PartialProtoLengthDelimited value) const + { + return { ProtoLengthDelimited(inputStream, formatErrorPolicy, value.length), fieldNumber }; + } + + private: + infra::DataInputStream inputStream; + infra::StreamErrorPolicy& formatErrorPolicy; + uint32_t fieldNumber; + }; + ProtoParser::Field ProtoParser::GetField() + { + auto [value, fieldNumber] = GetPartialField(); + MakeFullField visitor(input, formatErrorPolicy, fieldNumber); + return infra::ApplyVisitor(visitor, value); + } + + ProtoParser::PartialField ProtoParser::GetPartialField() { uint32_t x = static_cast(GetVarInt()); uint8_t type = x & 7; @@ -129,7 +162,7 @@ namespace infra case 1: return std::make_pair(GetFixed64(), fieldNumber); case 2: - return std::make_pair(ProtoLengthDelimited(input, formatErrorPolicy, static_cast(GetVarInt())), fieldNumber); + return std::make_pair(PartialProtoLengthDelimited{ static_cast(GetVarInt()) }, fieldNumber); case 5: return std::make_pair(GetFixed32(), fieldNumber); default: diff --git a/infra/syntax/ProtoParser.hpp b/infra/syntax/ProtoParser.hpp index 3cb6d8306..652041edc 100644 --- a/infra/syntax/ProtoParser.hpp +++ b/infra/syntax/ProtoParser.hpp @@ -34,10 +34,18 @@ namespace infra infra::StreamErrorPolicy& formatErrorPolicy; }; + struct PartialProtoLengthDelimited + { + uint32_t length; + }; + class ProtoParser { public: - using Field = std::pair, uint32_t>; + using FieldVariant = infra::Variant; + using Field = std::pair; + using PartialFieldVariant = infra::Variant; + using PartialField = std::pair; explicit ProtoParser(infra::DataInputStream inputStream); ProtoParser(infra::DataInputStream inputStream, infra::StreamErrorPolicy& formatErrorPolicy); @@ -48,6 +56,7 @@ namespace infra uint64_t GetFixed64(); Field GetField(); + PartialField GetPartialField(); void ReportFormatResult(bool ok); bool FormatFailed() const; diff --git a/infra/syntax/test/TestProtoFormatter.cpp b/infra/syntax/test/TestProtoFormatter.cpp index 6b34a148a..e42384893 100644 --- a/infra/syntax/test/TestProtoFormatter.cpp +++ b/infra/syntax/test/TestProtoFormatter.cpp @@ -76,6 +76,17 @@ TEST(ProtoFormatterTest, PutBytesField) EXPECT_EQ((std::array{ 4 << 3 | 2, 1, 5 }), stream.Writer().Processed()); } +TEST(ProtoFormatterTest, PutSubObjectOfKnownSize) +{ + infra::ByteOutputStream::WithStorage<20> stream; + infra::ProtoFormatter formatter(stream); + + formatter.PutLengthDelimitedSize(2, 4); + formatter.PutVarIntField(2, 4); + + EXPECT_EQ((std::array{ 4 << 3 | 2, 2, 4 << 3, 2 }), stream.Writer().Processed()); +} + TEST(ProtoFormatterTest, PutSubObject) { infra::ByteOutputStream::WithStorage<20> stream; diff --git a/infra/util/ConstructBin.cpp b/infra/util/ConstructBin.cpp index ce30b8fff..001ae1dce 100644 --- a/infra/util/ConstructBin.cpp +++ b/infra/util/ConstructBin.cpp @@ -32,6 +32,13 @@ namespace infra return *this; } + ConstructBin& ConstructBin::Repeat(std::size_t amount, std::initializer_list v) + { + for (size_t i = 0; i != amount; ++i) + contents.insert(contents.end(), v.begin(), v.end()); + return *this; + } + ConstructBin& ConstructBin::RepeatString(std::size_t amount, const std::string& v) { for (size_t i = 0; i != amount; ++i) diff --git a/infra/util/ConstructBin.hpp b/infra/util/ConstructBin.hpp index ba514fd4e..83631f5c4 100644 --- a/infra/util/ConstructBin.hpp +++ b/infra/util/ConstructBin.hpp @@ -17,6 +17,7 @@ namespace infra ConstructBin& operator()(std::initializer_list v); ConstructBin& Repeat(std::size_t amount, uint8_t v); + ConstructBin& Repeat(std::size_t amount, std::initializer_list v); ConstructBin& RepeatString(std::size_t amount, const std::string& v); template diff --git a/infra/util/WithStorage.hpp b/infra/util/WithStorage.hpp index 52f78eb9e..1b199ef7a 100644 --- a/infra/util/WithStorage.hpp +++ b/infra/util/WithStorage.hpp @@ -26,6 +26,8 @@ namespace infra WithStorage(); template WithStorage(InPlace, StorageArg&& storageArg, Args&&... args); + template + WithStorage(InPlace, std::initializer_list initializerList); template WithStorage(Arg&& arg, std::enable_if_t>>, std::nullptr_t> = nullptr); template @@ -89,6 +91,13 @@ namespace infra , Base(detail::StorageHolder::storage, std::forward(args)...) {} + template + template + WithStorage::WithStorage(InPlace, std::initializer_list initializerList) + : detail::StorageHolder(initializerList) + , Base(detail::StorageHolder::storage) + {} + template template WithStorage::WithStorage(Arg&& arg, std::enable_if_t>>, std::nullptr_t>) diff --git a/protobuf/CMakeLists.txt b/protobuf/CMakeLists.txt index da2d6f17d..e6fe5e065 100644 --- a/protobuf/CMakeLists.txt +++ b/protobuf/CMakeLists.txt @@ -1,5 +1,5 @@ -add_subdirectory(echo) add_subdirectory(echo_attributes) +add_subdirectory(echo) add_subdirectory(protoc_echo_plugin) add_subdirectory(protoc_echo_plugin_csharp) add_subdirectory(protoc_echo_plugin_java) diff --git a/protobuf/echo/CMakeLists.txt b/protobuf/echo/CMakeLists.txt index 168b25331..3f459aaeb 100644 --- a/protobuf/echo/CMakeLists.txt +++ b/protobuf/echo/CMakeLists.txt @@ -8,6 +8,11 @@ target_link_libraries(protobuf.echo PUBLIC target_sources(protobuf.echo PRIVATE Echo.cpp Echo.hpp + Proto.hpp + ProtoMessageReceiver.cpp + ProtoMessageReceiver.hpp + ProtoMessageSender.cpp + ProtoMessageSender.hpp ServiceForwarder.cpp ServiceForwarder.hpp TracingEcho.cpp diff --git a/protobuf/echo/Echo.hpp b/protobuf/echo/Echo.hpp index 81d04ba97..96a5e6a1d 100644 --- a/protobuf/echo/Echo.hpp +++ b/protobuf/echo/Echo.hpp @@ -1,12 +1,11 @@ #ifndef PROTOBUF_ECHO_HPP #define PROTOBUF_ECHO_HPP -#include "infra/syntax/ProtoFormatter.hpp" -#include "infra/syntax/ProtoParser.hpp" #include "infra/util/BoundedDeque.hpp" #include "infra/util/Compatibility.hpp" #include "infra/util/Function.hpp" #include "infra/util/Optional.hpp" +#include "protobuf/echo/Proto.hpp" #include "services/util/MessageCommunication.hpp" namespace services @@ -15,121 +14,6 @@ namespace services class Service; class ServiceProxy; - struct ProtoBool - {}; - - struct ProtoUInt32 - {}; - - struct ProtoInt32 - {}; - - struct ProtoUInt64 - {}; - - struct ProtoInt64 - {}; - - struct ProtoFixed32 - {}; - - struct ProtoFixed64 - {}; - - struct ProtoSFixed32 - {}; - - struct ProtoSFixed64 - {}; - - struct ProtoUnboundedString - {}; - - struct ProtoUnboundedBytes - {}; - - template - struct ProtoMessage - {}; - - template - struct ProtoEnum - {}; - - template - struct ProtoBytes - {}; - - template - struct ProtoString - {}; - - template - struct ProtoRepeated - {}; - - template - struct ProtoUnboundedRepeated - {}; - - void SerializeField(ProtoBool, infra::ProtoFormatter& formatter, bool value, uint32_t fieldNumber); - void SerializeField(ProtoUInt32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber); - void SerializeField(ProtoInt32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber); - void SerializeField(ProtoUInt64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber); - void SerializeField(ProtoInt64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber); - void SerializeField(ProtoFixed32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber); - void SerializeField(ProtoFixed64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber); - void SerializeField(ProtoSFixed32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber); - void SerializeField(ProtoSFixed64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber); - void SerializeField(ProtoUnboundedString, infra::ProtoFormatter& formatter, const std::string& value, uint32_t fieldNumber); - void SerializeField(ProtoUnboundedBytes, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber); - - template - void SerializeField(ProtoRepeated, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber); - template - void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber); - template - void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber); - template - void SerializeField(ProtoMessage, infra::ProtoFormatter& formatter, const U& value, uint32_t fieldNumber); - template - void SerializeField(ProtoEnum, infra::ProtoFormatter& formatter, T value, uint32_t fieldNumber); - template - void SerializeField(ProtoBytes, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber); - template - void SerializeField(ProtoString, infra::ProtoFormatter& formatter, infra::BoundedConstString value, uint32_t fieldNumber); - - void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::Field& field, bool& value); - void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint32_t& value); - void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int32_t& value); - void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint64_t& value); - void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int64_t& value); - void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint32_t& value); - void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint64_t& value); - void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int32_t& value); - void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int64_t& value); - void DeserializeField(ProtoUnboundedString, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::string& value); - void DeserializeField(ProtoUnboundedBytes, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::vector& value); - - template - void DeserializeField(ProtoRepeated, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedVector& value); - template - void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::vector& value); - template - void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::vector& value); - template - void DeserializeField(ProtoMessage, infra::ProtoParser& parser, infra::ProtoParser::Field& field, U& value); - template - void DeserializeField(ProtoEnum, infra::ProtoParser& parser, infra::ProtoParser::Field& field, T& value); - template - void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedVector& value); - template - void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::ConstByteRange& value); - template - void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedString& value); - template - void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedConstString& value); - class EchoErrorPolicy { protected: @@ -275,261 +159,6 @@ namespace services //// Implementation //// - inline void SerializeField(ProtoBool, infra::ProtoFormatter& formatter, bool value, uint32_t fieldNumber) - { - formatter.PutVarIntField(value, fieldNumber); - } - - inline void SerializeField(ProtoUInt32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber) - { - formatter.PutVarIntField(value, fieldNumber); - } - - inline void SerializeField(ProtoInt32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber) - { - formatter.PutVarIntField(value, fieldNumber); - } - - inline void SerializeField(ProtoUInt64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber) - { - formatter.PutVarIntField(value, fieldNumber); - } - - inline void SerializeField(ProtoInt64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber) - { - formatter.PutVarIntField(value, fieldNumber); - } - - inline void SerializeField(ProtoFixed32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber) - { - formatter.PutFixed32Field(value, fieldNumber); - } - - inline void SerializeField(ProtoFixed64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber) - { - formatter.PutFixed64Field(value, fieldNumber); - } - - inline void SerializeField(ProtoSFixed32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber) - { - formatter.PutFixed32Field(static_cast(value), fieldNumber); - } - - inline void SerializeField(ProtoSFixed64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber) - { - formatter.PutFixed64Field(static_cast(value), fieldNumber); - } - - inline void SerializeField(ProtoUnboundedString, infra::ProtoFormatter& formatter, const std::string& value, uint32_t fieldNumber) - { - formatter.PutStringField(value, fieldNumber); - } - - inline void SerializeField(ProtoUnboundedBytes, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber) - { - formatter.PutBytesField(value, fieldNumber); - } - - template - void SerializeField(ProtoRepeated, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber) - { - for (auto& v : value) - SerializeField(T(), formatter, v, fieldNumber); - } - - template - void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber) - { - for (auto& v : value) - SerializeField(T(), formatter, v, fieldNumber); - } - - template - void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber) - { - for (auto v : value) - SerializeField(T(), formatter, v, fieldNumber); - } - - template - void SerializeField(ProtoMessage, infra::ProtoFormatter& formatter, const U& value, uint32_t fieldNumber) - { - infra::ProtoLengthDelimitedFormatter nestedMessage(formatter, fieldNumber); - value.Serialize(formatter); - } - - template - void SerializeField(ProtoEnum, infra::ProtoFormatter& formatter, T value, uint32_t fieldNumber) - { - formatter.PutVarIntField(static_cast(value), fieldNumber); - } - - template - void SerializeField(ProtoBytes, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber) - { - formatter.PutBytesField(infra::MakeRange(value), fieldNumber); - } - - template - void SerializeField(ProtoString, infra::ProtoFormatter& formatter, infra::BoundedConstString value, uint32_t fieldNumber) - { - formatter.PutStringField(value, fieldNumber); - } - - inline void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::Field& field, bool& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = field.first.Get() != 0; - } - - inline void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint32_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = static_cast(field.first.Get()); - } - - inline void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int32_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = static_cast(field.first.Get()); - } - - inline void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint64_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = field.first.Get(); - } - - inline void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int64_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = static_cast(field.first.Get()); - } - - inline void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint32_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = field.first.Get(); - } - - inline void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, uint64_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = field.first.Get(); - } - - inline void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int32_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = static_cast(field.first.Get()); - } - - inline void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::Field& field, int64_t& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = static_cast(field.first.Get()); - } - - inline void DeserializeField(ProtoUnboundedString, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::string& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = field.first.Get().GetStdString(); - } - - inline void DeserializeField(ProtoUnboundedBytes, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::vector& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = field.first.Get().GetUnboundedBytes(); - } - - template - void DeserializeField(ProtoRepeated, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedVector& value) - { - parser.ReportFormatResult(!value.full()); - if (!value.full()) - { - value.emplace_back(); - DeserializeField(T(), parser, field, value.back()); - } - } - - template - void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::vector& value) - { - value.emplace_back(); - DeserializeField(T(), parser, field, value.back()); - } - - template - void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::Field& field, std::vector& value) - { - bool result{}; - DeserializeField(T(), parser, field, result); - value.push_back(result); - } - - template - void DeserializeField(ProtoMessage, infra::ProtoParser& parser, infra::ProtoParser::Field& field, U& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - { - infra::ProtoParser nestedParser = field.first.Get().Parser(); - value.Deserialize(nestedParser); - } - } - - template - void DeserializeField(ProtoEnum, infra::ProtoParser& parser, infra::ProtoParser::Field& field, T& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - value = static_cast(field.first.Get()); - } - - template - void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedVector& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - field.first.Get().GetBytes(value); - } - - template - void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::ConstByteRange& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - field.first.Get().GetBytesReference(value); - } - - template - void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedString& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - field.first.Get().GetString(value); - } - - template - void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::Field& field, infra::BoundedConstString& value) - { - parser.ReportFormatResult(field.first.Is()); - if (field.first.Is()) - field.first.Get().GetStringReference(value); - } - template template ServiceProxyResponseQueue::ServiceProxyResponseQueue(Container& container, Args&&... args) diff --git a/protobuf/echo/Proto.hpp b/protobuf/echo/Proto.hpp new file mode 100644 index 000000000..3fb0ae479 --- /dev/null +++ b/protobuf/echo/Proto.hpp @@ -0,0 +1,541 @@ +#ifndef PROTOBUF_PROTO_HPP +#define PROTOBUF_PROTO_HPP + +#include "infra/syntax/ProtoFormatter.hpp" +#include "infra/syntax/ProtoParser.hpp" +#include + +namespace services +{ + struct ProtoBool + {}; + + struct ProtoUInt32 + {}; + + struct ProtoInt32 + {}; + + struct ProtoUInt64 + {}; + + struct ProtoInt64 + {}; + + struct ProtoFixed32 + {}; + + struct ProtoFixed64 + {}; + + struct ProtoSFixed32 + {}; + + struct ProtoSFixed64 + {}; + + struct ProtoUnboundedString + {}; + + struct ProtoUnboundedBytes + {}; + + template + struct ProtoMessage + {}; + + template + struct ProtoEnum + {}; + + struct ProtoBytesBase + {}; + + template + struct ProtoBytes + : ProtoBytesBase + {}; + + struct ProtoStringBase + {}; + + template + struct ProtoString + : ProtoStringBase + {}; + + template + struct ProtoRepeatedBase + {}; + + template + struct ProtoRepeated + : ProtoRepeatedBase + {}; + + template + struct ProtoUnboundedRepeated + {}; + + void SerializeField(ProtoBool, infra::ProtoFormatter& formatter, bool value, uint32_t fieldNumber); + void SerializeField(ProtoUInt32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber); + void SerializeField(ProtoInt32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber); + void SerializeField(ProtoUInt64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber); + void SerializeField(ProtoInt64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber); + void SerializeField(ProtoFixed32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber); + void SerializeField(ProtoFixed64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber); + void SerializeField(ProtoSFixed32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber); + void SerializeField(ProtoSFixed64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber); + void SerializeField(ProtoUnboundedString, infra::ProtoFormatter& formatter, const std::string& value, uint32_t fieldNumber); + void SerializeField(ProtoUnboundedBytes, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber); + + template + void SerializeField(ProtoRepeated, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber); + template + void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber); + template + void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber); + template + void SerializeField(ProtoMessage, infra::ProtoFormatter& formatter, const U& value, uint32_t fieldNumber); + template + void SerializeField(ProtoEnum, infra::ProtoFormatter& formatter, T value, uint32_t fieldNumber); + template + void SerializeField(ProtoBytes, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber); + template + void SerializeField(ProtoString, infra::ProtoFormatter& formatter, infra::BoundedConstString value, uint32_t fieldNumber); + + void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, bool& value); + void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint32_t& value); + void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int32_t& value); + void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint64_t& value); + void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int64_t& value); + void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint32_t& value); + void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint64_t& value); + void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int32_t& value); + void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int64_t& value); + void DeserializeField(ProtoUnboundedString, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::string& value); + void DeserializeField(ProtoUnboundedBytes, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::vector& value); + + template + void DeserializeField(ProtoRepeated, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedVector& value); + template + void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::vector& value); + template + void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::vector& value); + template + void DeserializeField(ProtoMessage, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, U& value); + template + void DeserializeField(ProtoEnum, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, T& value); + template + void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedVector& value); + template + void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::ConstByteRange& value); + template + void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedString& value); + template + void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedConstString& value); + + void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, bool& value); + void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value); + void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value); + void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value); + void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value); + void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value); + void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value); + void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value); + void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value); + + template + struct MessageDepth + { + static constexpr uint32_t value = 0; + }; + + template<> + struct MessageDepth + { + static constexpr uint32_t value = 1; + }; + + template<> + struct MessageDepth + { + static constexpr uint32_t value = 1; + }; + + template + struct MessageDepth> + { + static constexpr uint32_t value = 1; + }; + + template + struct MessageDepth> + { + static constexpr uint32_t value = 1; + }; + + template + struct MessageDepth> + { + static constexpr uint32_t value = 1; + }; + + template + struct MessageDepth> + { + static constexpr uint32_t value = 1; + }; + + template + struct Max; + + template + struct Max + { + static constexpr uint32_t value = V; + }; + + template + struct Max + { + static constexpr uint32_t value = std::max(V, Max::value); + }; + + template + struct MaxFieldsDepth; + + template + struct MaxFieldsDepth> + { + static constexpr uint32_t value = Max>::value...>::value; + }; + + template + struct MessageDepth> + { + static constexpr uint32_t value = MaxFieldsDepth>::value + 1; + }; + + //// Implementation //// + + inline void SerializeField(ProtoBool, infra::ProtoFormatter& formatter, bool value, uint32_t fieldNumber) + { + formatter.PutVarIntField(value, fieldNumber); + } + + inline void SerializeField(ProtoUInt32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber) + { + formatter.PutVarIntField(value, fieldNumber); + } + + inline void SerializeField(ProtoInt32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber) + { + formatter.PutVarIntField(value, fieldNumber); + } + + inline void SerializeField(ProtoUInt64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber) + { + formatter.PutVarIntField(value, fieldNumber); + } + + inline void SerializeField(ProtoInt64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber) + { + formatter.PutVarIntField(value, fieldNumber); + } + + inline void SerializeField(ProtoFixed32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber) + { + formatter.PutFixed32Field(value, fieldNumber); + } + + inline void SerializeField(ProtoFixed64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber) + { + formatter.PutFixed64Field(value, fieldNumber); + } + + inline void SerializeField(ProtoSFixed32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber) + { + formatter.PutFixed32Field(static_cast(value), fieldNumber); + } + + inline void SerializeField(ProtoSFixed64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber) + { + formatter.PutFixed64Field(static_cast(value), fieldNumber); + } + + inline void SerializeField(ProtoUnboundedString, infra::ProtoFormatter& formatter, const std::string& value, uint32_t fieldNumber) + { + formatter.PutStringField(value, fieldNumber); + } + + inline void SerializeField(ProtoUnboundedBytes, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber) + { + formatter.PutBytesField(value, fieldNumber); + } + + template + void SerializeField(ProtoRepeated, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber) + { + for (auto& v : value) + SerializeField(T(), formatter, v, fieldNumber); + } + + template + void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber) + { + for (auto& v : value) + SerializeField(T(), formatter, v, fieldNumber); + } + + template + void SerializeField(ProtoUnboundedRepeated, infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber) + { + for (auto v : value) + SerializeField(T(), formatter, v, fieldNumber); + } + + template + void SerializeField(ProtoMessage, infra::ProtoFormatter& formatter, const U& value, uint32_t fieldNumber) + { + infra::ProtoLengthDelimitedFormatter nestedMessage(formatter, fieldNumber); + value.Serialize(formatter); + } + + template + void SerializeField(ProtoEnum, infra::ProtoFormatter& formatter, T value, uint32_t fieldNumber) + { + formatter.PutVarIntField(static_cast(value), fieldNumber); + } + + template + void SerializeField(ProtoBytes, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber) + { + formatter.PutBytesField(infra::MakeRange(value), fieldNumber); + } + + template + void SerializeField(ProtoString, infra::ProtoFormatter& formatter, infra::BoundedConstString value, uint32_t fieldNumber) + { + formatter.PutStringField(value, fieldNumber); + } + + inline void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, bool& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get() != 0; + } + + inline void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get(); + } + + inline void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get(); + } + + inline void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, uint64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get(); + } + + inline void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, int64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoUnboundedString, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::string& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get().GetStdString(); + } + + inline void DeserializeField(ProtoUnboundedBytes, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::vector& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get().GetUnboundedBytes(); + } + + template + void DeserializeField(ProtoRepeated, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedVector& value) + { + parser.ReportFormatResult(!value.full()); + if (!value.full()) + { + value.emplace_back(); + DeserializeField(T(), parser, field, value.back()); + } + } + + template + void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::vector& value) + { + value.emplace_back(); + DeserializeField(T(), parser, field, value.back()); + } + + template + void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, std::vector& value) + { + bool result{}; + DeserializeField(T(), parser, field, result); + value.push_back(result); + } + + template + void DeserializeField(ProtoMessage, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, U& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + { + infra::ProtoParser nestedParser = field.Get().Parser(); + value.Deserialize(nestedParser); + } + } + + template + void DeserializeField(ProtoEnum, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, T& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + template + void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedVector& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + field.Get().GetBytes(value); + } + + template + void DeserializeField(ProtoBytes, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::ConstByteRange& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + field.Get().GetBytesReference(value); + } + + template + void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedString& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + field.Get().GetString(value); + } + + template + void DeserializeField(ProtoString, infra::ProtoParser& parser, infra::ProtoParser::FieldVariant& field, infra::BoundedConstString& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + field.Get().GetStringReference(value); + } + + inline void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, bool& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get() != 0; + } + + inline void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get(); + } + + inline void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get(); + } + + inline void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = field.Get(); + } + + inline void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + inline void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } +} + +#endif diff --git a/protobuf/echo/ProtoMessageReceiver.cpp b/protobuf/echo/ProtoMessageReceiver.cpp new file mode 100644 index 000000000..1c2e14a9e --- /dev/null +++ b/protobuf/echo/ProtoMessageReceiver.cpp @@ -0,0 +1,142 @@ +#include "protobuf/echo/ProtoMessageReceiver.hpp" +#include "infra/stream/BufferingStreamReader.hpp" + +namespace services +{ + ProtoMessageReceiverBase::ProtoMessageReceiverBase(infra::BoundedVector>>& stack) + : stack(stack) + {} + + void ProtoMessageReceiverBase::Feed(infra::StreamReaderWithRewinding& data) + { + infra::BufferingStreamReader reader{ buffer, data }; + + while (true) + { + infra::LimitedStreamReaderWithRewinding limitedReader(reader, stack.back().first); + infra::DataInputStream::WithErrorPolicy stream{ limitedReader, infra::softFail }; + + auto available = limitedReader.Available(); + + auto& current = stack.back(); + current.second(stream); + + if (stream.Failed() || reader.Empty()) + break; + + if (¤t != &stack.front()) + { + current.first -= available - limitedReader.Available(); + + if (current.first == 0) + stack.pop_back(); + } + } + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, bool& value) const + { + services::DeserializeField(ProtoBool(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value) const + { + services::DeserializeField(ProtoUInt32(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value) const + { + services::DeserializeField(ProtoInt32(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value) const + { + services::DeserializeField(ProtoUInt64(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value) const + { + services::DeserializeField(ProtoInt64(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value) const + { + services::DeserializeField(ProtoFixed32(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value) const + { + services::DeserializeField(ProtoFixed64(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value) const + { + services::DeserializeField(ProtoSFixed32(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value) const + { + services::DeserializeField(ProtoSFixed64(), parser, field, value); + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoStringBase, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, infra::BoundedString& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + { + auto stringSize = field.Get().length; + stack.emplace_back(stringSize, [&value](const infra::DataInputStream& stream) + { + while (!stream.Empty()) + value.append(infra::ByteRangeAsString(stream.ContiguousRange())); + }); + value.clear(); + } + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoUnboundedString, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, std::string& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + { + auto stringSize = field.Get().length; + stack.emplace_back(stringSize, [&value](const infra::DataInputStream& stream) + { + while (!stream.Empty()) + value.append(infra::ByteRangeAsStdString(stream.ContiguousRange())); + }); + value.clear(); + } + } + + void ProtoMessageReceiverBase::DeserializeField(ProtoBytesBase, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, infra::BoundedVector& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + { + auto bytesSize = field.Get().length; + stack.emplace_back(bytesSize, [&value](const infra::DataInputStream& stream) + { + while (!stream.Empty()) + { + auto range = stream.ContiguousRange(); + value.insert(value.end(), range.begin(), range.end()); + } + }); + value.clear(); + } + } + + void ProtoMessageReceiverBase::ConsumeUnknownField(infra::ProtoParser::PartialField& field) + { + if (field.first.Is()) + { + auto size = field.first.Get().length; + stack.emplace_back(size, [](const infra::DataInputStream& stream) + { + while (!stream.Empty()) + stream.ContiguousRange(); + }); + } + } +} diff --git a/protobuf/echo/ProtoMessageReceiver.hpp b/protobuf/echo/ProtoMessageReceiver.hpp new file mode 100644 index 000000000..b127695b4 --- /dev/null +++ b/protobuf/echo/ProtoMessageReceiver.hpp @@ -0,0 +1,173 @@ +#ifndef PROTOBUF_PROTO_MESSAGE_RECEIVER_HPP +#define PROTOBUF_PROTO_MESSAGE_RECEIVER_HPP + +#include "infra/syntax/ProtoParser.hpp" +#include "infra/util/BoundedDeque.hpp" +#include "infra/util/BoundedVector.hpp" +#include "protobuf/echo/Proto.hpp" + +namespace services +{ + class ProtoMessageReceiverBase + { + public: + explicit ProtoMessageReceiverBase(infra::BoundedVector>>& stack); + + void Feed(infra::StreamReaderWithRewinding& data); + + protected: + template + void FeedForMessage(const infra::DataInputStream& stream, Message& message); + + private: + template + bool DeserializeFields(infra::ProtoParser::PartialField& field, infra::ProtoParser& parser, Message& message, std::index_sequence); + + template + bool DeserializeSingleField(infra::ProtoParser::PartialField& field, infra::ProtoParser& parser, Message& message); + + void DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, bool& value) const; + void DeserializeField(ProtoUInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value) const; + void DeserializeField(ProtoInt32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value) const; + void DeserializeField(ProtoUInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value) const; + void DeserializeField(ProtoInt64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value) const; + void DeserializeField(ProtoFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint32_t& value) const; + void DeserializeField(ProtoFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, uint64_t& value) const; + void DeserializeField(ProtoSFixed32, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int32_t& value) const; + void DeserializeField(ProtoSFixed64, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, int64_t& value) const; + + void DeserializeField(ProtoStringBase, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, infra::BoundedString& value); + void DeserializeField(ProtoUnboundedString, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, std::string& value); + void DeserializeField(ProtoBytesBase, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, infra::BoundedVector& value); + + template + void DeserializeField(ProtoEnum, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Enum& value) const; + template + void DeserializeField(ProtoMessage, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Message& value); + template + void DeserializeField(ProtoRepeatedBase, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Type& value) const; + template + void DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Type& value) const; + + void ConsumeUnknownField(infra::ProtoParser::PartialField& field); + + private: + infra::BoundedDeque::WithMaxSize<32> buffer; + infra::BoundedVector>>& stack; + }; + + template + class ProtoMessageReceiver + : public ProtoMessageReceiverBase + { + public: + ProtoMessageReceiver(); + + Message message; + + private: + infra::BoundedVector>>::WithMaxSize>::value + 1> stack{ { std::pair>{ std::numeric_limits::max(), [this](const infra::DataInputStream& stream) + { + FeedForMessage(stream, message); + } } } }; + }; +} + +//// Implementation //// + +namespace services +{ + template + void ProtoMessageReceiverBase::FeedForMessage(const infra::DataInputStream& stream, Message& message) + { + infra::ProtoParser parser{ stream }; + + while (!stream.Empty()) + { + auto marker = static_cast(stream.Reader()).ConstructSaveMarker(); + auto field = parser.GetPartialField(); + + if (stream.Failed()) + { + static_cast(stream.Reader()).Rewind(marker); + break; + } + + auto stackSize = stack.size(); + if (!DeserializeFields(field, parser, message, std::make_index_sequence{})) + ConsumeUnknownField(field); + + if (stackSize != stack.size()) + { + stream.Failed(); + return; + } + } + } + + template + bool ProtoMessageReceiverBase::DeserializeFields(infra::ProtoParser::PartialField& field, infra::ProtoParser& parser, Message& message, std::index_sequence) + { + return (DeserializeSingleField(field, parser, message) || ...); + } + + template + bool ProtoMessageReceiverBase::DeserializeSingleField(infra::ProtoParser::PartialField& field, infra::ProtoParser& parser, Message& message) + { + if (field.second == Message::template fieldNumber) + { + DeserializeField(typename Message::template ProtoType(), parser, field.first, message.Get(std::integral_constant())); + return true; + } + + return false; + } + + template + void ProtoMessageReceiverBase::DeserializeField(ProtoEnum, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Enum& value) const + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + value = static_cast(field.Get()); + } + + template + void ProtoMessageReceiverBase::DeserializeField(ProtoMessage, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Message& value) + { + parser.ReportFormatResult(field.Is()); + if (field.Is()) + { + auto messageSize = field.Get().length; + stack.emplace_back(messageSize, [this, &value](const infra::DataInputStream& stream) + { + FeedForMessage(stream, value); + }); + infra::ReConstruct(value); + } + } + + template + void ProtoMessageReceiverBase::DeserializeField(ProtoRepeatedBase, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Type& value) const + { + parser.ReportFormatResult(!value.full()); + if (!value.full()) + { + value.emplace_back(); + DeserializeField(ProtoType(), parser, field, value.back()); + } + } + + template + void ProtoMessageReceiverBase::DeserializeField(ProtoUnboundedRepeated, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, Type& value) const + { + value.emplace_back(); + DeserializeField(ProtoType(), parser, field, value.back()); + } + + template + ProtoMessageReceiver::ProtoMessageReceiver() + : ProtoMessageReceiverBase(stack) + {} +} + +#endif diff --git a/protobuf/echo/ProtoMessageSender.cpp b/protobuf/echo/ProtoMessageSender.cpp new file mode 100644 index 000000000..5f013d486 --- /dev/null +++ b/protobuf/echo/ProtoMessageSender.cpp @@ -0,0 +1,132 @@ +#include "protobuf/echo/ProtoMessageSender.hpp" +#include "infra/stream/BufferingStreamWriter.hpp" + +namespace services +{ + ProtoMessageSenderBase::ProtoMessageSenderBase(infra::BoundedVector>>& stack) + : stack(stack) + {} + + void ProtoMessageSenderBase::Fill(infra::DataOutputStream output) + { + infra::BufferingStreamWriter writer{ buffer, output.Writer() }; + + while (!stack.empty()) + { + infra::DataOutputStream::WithErrorPolicy stream{ writer }; + + auto& [index, callback] = stack.back(); + bool retry = false; + auto result = callback(stream, index, retry, output.Writer()); + if (result) + stack.pop_back(); + else if (!retry) + break; + } + } + + bool ProtoMessageSenderBase::SerializeField(ProtoBool, infra::ProtoFormatter& formatter, bool value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoBool(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoUInt32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoUInt32(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoInt32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoInt32(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoUInt64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoUInt64(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoInt64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoInt64(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoFixed32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoFixed32(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoSFixed32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoSFixed32(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoFixed64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoFixed64(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoSFixed64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoSFixed64(), formatter, value, fieldNumber); + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoStringBase, infra::ProtoFormatter& formatter, const infra::BoundedString& value, uint32_t fieldNumber, bool& retry) const + { + formatter.PutVarInt((fieldNumber << 3) | 2); + formatter.PutVarInt(value.size()); + + stack.emplace_back(0, [&value](infra::DataOutputStream& stream, uint32_t& index, const bool&, const infra::StreamWriter&) + { + auto range = infra::Head(infra::DiscardHead(infra::StringAsByteRange(value), index), stream.Available()); + stream << range; + index += range.size(); + return index == value.size(); + }); + + retry = true; + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoUnboundedString, infra::ProtoFormatter& formatter, const std::string& value, uint32_t fieldNumber, bool& retry) const + { + formatter.PutVarInt((fieldNumber << 3) | 2); + formatter.PutVarInt(value.size()); + + stack.emplace_back(0, [&value](infra::DataOutputStream& stream, uint32_t& index, const bool&, const infra::StreamWriter&) + { + auto range = infra::Head(infra::DiscardHead(infra::StdStringAsByteRange(value), index), stream.Available()); + stream << range; + index += range.size(); + return index == value.size(); + }); + + retry = true; + return true; + } + + bool ProtoMessageSenderBase::SerializeField(ProtoBytesBase, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber, bool& retry) const + { + formatter.PutVarInt((fieldNumber << 3) | 2); + formatter.PutVarInt(value.size()); + + stack.emplace_back(0, [&value](infra::DataOutputStream& stream, uint32_t& index, const bool&, const infra::StreamWriter&) + { + auto range = infra::Head(infra::DiscardHead(infra::MakeRange(value), index), stream.Available()); + stream << range; + index += range.size(); + return index == value.size(); + }); + + retry = true; + return true; + } +} diff --git a/protobuf/echo/ProtoMessageSender.hpp b/protobuf/echo/ProtoMessageSender.hpp new file mode 100644 index 000000000..930c3df9f --- /dev/null +++ b/protobuf/echo/ProtoMessageSender.hpp @@ -0,0 +1,180 @@ +#ifndef PROTOBUF_PROTO_MESSAGE_SENDER_HPP +#define PROTOBUF_PROTO_MESSAGE_SENDER_HPP + +#include "infra/stream/CountingOutputStream.hpp" +#include "infra/syntax/ProtoFormatter.hpp" +#include "infra/util/BoundedDeque.hpp" +#include "infra/util/BoundedVector.hpp" +#include "protobuf/echo/Proto.hpp" + +namespace services +{ + class ProtoMessageSenderBase + { + public: + explicit ProtoMessageSenderBase(infra::BoundedVector>>& stack); + + void Fill(infra::DataOutputStream output); + + protected: + template + bool FillForMessage(infra::DataOutputStream& stream, const Message& message, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter) const; + + private: + template + bool SerializeFields(infra::ProtoFormatter& formatter, const Message& message, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter, std::index_sequence) const; + + template + bool SerializeSingleField(infra::ProtoFormatter& formatter, const Message& message, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter) const; + + bool SerializeField(ProtoBool, infra::ProtoFormatter& formatter, bool value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoUInt32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoInt32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoUInt64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoInt64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoFixed32, infra::ProtoFormatter& formatter, uint32_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoSFixed32, infra::ProtoFormatter& formatter, int32_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoFixed64, infra::ProtoFormatter& formatter, uint64_t value, uint32_t fieldNumber, const bool& retry) const; + bool SerializeField(ProtoSFixed64, infra::ProtoFormatter& formatter, int64_t value, uint32_t fieldNumber, const bool& retry) const; + + bool SerializeField(ProtoStringBase, infra::ProtoFormatter& formatter, const infra::BoundedString& value, uint32_t fieldNumber, bool& retry) const; + bool SerializeField(ProtoUnboundedString, infra::ProtoFormatter& formatter, const std::string& value, uint32_t fieldNumber, bool& retry) const; + bool SerializeField(ProtoBytesBase, infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber, bool& retry) const; + + template + bool SerializeField(ProtoEnum, infra::ProtoFormatter& formatter, const Enum& value, uint32_t fieldNumber, const bool& retry) const; + template + bool SerializeField(ProtoMessage, infra::ProtoFormatter& formatter, const Message& value, uint32_t fieldNumber, bool& retry) const; + template + bool SerializeField(ProtoRepeatedBase, const infra::ProtoFormatter& formatter, const infra::BoundedVector& value, uint32_t fieldNumber, bool& retry) const; + template + bool SerializeField(ProtoUnboundedRepeated, const infra::ProtoFormatter& formatter, const std::vector& value, uint32_t fieldNumber, bool& retry) const; + + private: + infra::BoundedDeque::WithMaxSize<32> buffer; + infra::BoundedVector>>& stack; + }; + + template + class ProtoMessageSender + : public ProtoMessageSenderBase + { + public: + explicit ProtoMessageSender(const Message& message); + + private: + const Message& message; + infra::BoundedVector>>::WithMaxSize>::value + 1> stack{ { std::pair>{ 0, [this](infra::DataOutputStream& stream, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter) + { + return FillForMessage(stream, message, index, retry, finalWriter); + } } } }; + }; + + //// Implementation //// + + template + bool ProtoMessageSenderBase::FillForMessage(infra::DataOutputStream& stream, const Message& message, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter) const + { + infra::ProtoFormatter formatter{ stream }; + + return SerializeFields(formatter, message, index, retry, finalWriter, std::make_index_sequence{}); + } + + template + bool ProtoMessageSenderBase::SerializeFields(infra::ProtoFormatter& formatter, const Message& message, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter, std::index_sequence) const + { + return (SerializeSingleField(formatter, message, index, retry, finalWriter) && ...); + } + + template + bool ProtoMessageSenderBase::SerializeSingleField(infra::ProtoFormatter& formatter, const Message& message, uint32_t& index, bool& retry, const infra::StreamWriter& finalWriter) const + { + if (finalWriter.Available() == 0) + return false; + + if (index == I) + { + if (!SerializeField(typename Message::template ProtoType(), formatter, message.Get(std::integral_constant()), Message::template fieldNumber, retry)) + return false; + + index = I + 1; + return !retry; + } + + return true; + } + + template + bool ProtoMessageSenderBase::SerializeField(ProtoEnum, infra::ProtoFormatter& formatter, const Enum& value, uint32_t fieldNumber, [[maybe_unused]] const bool& retry) const + { + services::SerializeField(ProtoEnum(), formatter, value, fieldNumber); + return true; + } + + template + bool ProtoMessageSenderBase::SerializeField(ProtoMessage, infra::ProtoFormatter& formatter, const Message& value, uint32_t fieldNumber, bool& retry) const + { + infra::DataOutputStream::WithWriter countingStream; + infra::ProtoFormatter countingFormatter{ countingStream }; + value.Serialize(countingFormatter); + formatter.PutLengthDelimitedSize(countingStream.Writer().Processed(), fieldNumber); + + stack.emplace_back(0, [this, &value](infra::DataOutputStream& stream, uint32_t& index, bool& retry2, const infra::StreamWriter& finalWriter) + { + return FillForMessage(stream, value, index, retry2, finalWriter); + }); + + retry = true; + return true; + } + + template + bool ProtoMessageSenderBase::SerializeField(ProtoRepeatedBase, const infra::ProtoFormatter&, const infra::BoundedVector& value, uint32_t fieldNumber, bool& retry) const + { + stack.emplace_back(0, [this, &value, fieldNumber](infra::DataOutputStream& stream, uint32_t& index, const bool&, const infra::StreamWriter& finalWriter) + { + infra::ProtoFormatter formatter{ stream }; + + for (; index != value.size(); ++index) + { + if (finalWriter.Available() == 0) + return false; + services::SerializeField(ProtoType(), formatter, value[index], fieldNumber); + } + + return true; + }); + + retry = true; + return true; + } + + template + bool ProtoMessageSenderBase::SerializeField(ProtoUnboundedRepeated, const infra::ProtoFormatter&, const std::vector& value, uint32_t fieldNumber, bool& retry) const + { + stack.emplace_back(0, [this, &value, fieldNumber](infra::DataOutputStream& stream, uint32_t& index, const bool&, const infra::StreamWriter& finalWriter) + { + infra::ProtoFormatter formatter{ stream }; + + for (; index != value.size(); ++index) + { + if (finalWriter.Available() == 0) + return false; + services::SerializeField(ProtoType(), formatter, value[index], fieldNumber); + } + + return true; + }); + + retry = true; + return true; + } + + template + ProtoMessageSender::ProtoMessageSender(const Message& message) + : ProtoMessageSenderBase(stack) + , message(message) + {} +} + +#endif diff --git a/protobuf/echo/test/CMakeLists.txt b/protobuf/echo/test/CMakeLists.txt index 3176af5dc..9dd11414e 100644 --- a/protobuf/echo/test/CMakeLists.txt +++ b/protobuf/echo/test/CMakeLists.txt @@ -2,8 +2,12 @@ add_executable(protobuf.echo_test) emil_build_for(protobuf.echo_test BOOL EMIL_BUILD_TESTS) emil_add_test(protobuf.echo_test) +protocol_buffer_echo_cpp(protobuf.echo_test TestMessages.proto) + target_sources(protobuf.echo_test PRIVATE TestEchoServiceResponseQueue.cpp + TestProtoMessageReceiver.cpp + TestProtoMessageSender.cpp TestServiceForwarder.cpp ) diff --git a/protobuf/protoc_echo_plugin/test/TestMessages.proto b/protobuf/echo/test/TestMessages.proto similarity index 92% rename from protobuf/protoc_echo_plugin/test/TestMessages.proto rename to protobuf/echo/test/TestMessages.proto index 8f931978e..5588d0a11 100644 --- a/protobuf/protoc_echo_plugin/test/TestMessages.proto +++ b/protobuf/echo/test/TestMessages.proto @@ -64,7 +64,7 @@ message TestRepeatedString { } message TestBytes { - bytes value = 1 [(bytes_size) = 10]; + bytes value = 1 [(bytes_size) = 50]; } message TestUnboundedBytes { @@ -72,7 +72,11 @@ message TestUnboundedBytes { } message TestRepeatedUInt32 { - repeated uint32 value = 1 [(array_size) = 10]; + repeated uint32 value = 1 [(array_size) = 50]; +} + +message TestUnboundedRepeatedUInt32 { + repeated uint32 value = 1; } message TestMessageWithMessageField { @@ -168,3 +172,8 @@ service TestService2 rpc Search (TestString) returns (Nothing) { option (method_id) = 1; } } + +message TestBoolWithBytes { + bytes b = 1 [(bytes_size) = 30]; + bool value = 2; +} diff --git a/protobuf/echo/test/TestProtoMessageReceiver.cpp b/protobuf/echo/test/TestProtoMessageReceiver.cpp new file mode 100644 index 000000000..fe7a83fc0 --- /dev/null +++ b/protobuf/echo/test/TestProtoMessageReceiver.cpp @@ -0,0 +1,222 @@ +#include "generated/echo/TestMessages.pb.hpp" +#include "infra/stream/StdVectorInputStream.hpp" +#include "protobuf/echo/ProtoMessageReceiver.hpp" +#include + +TEST(ProtoMessageReceiverTest, parse_bool) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 1 }); + receiver.Feed(data); + + EXPECT_EQ(true, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_unknown_simple_field) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 2 << 3, 1, 1 << 3, 1 }); + receiver.Feed(data); + + EXPECT_EQ(true, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_unknown_length_delimited) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 1, (2 << 3) | 2, 2, 1 << 3, 0 }); + receiver.Feed(data); + + EXPECT_EQ(true, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_incomplete_bool) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 8 }); + receiver.Feed(data); + + EXPECT_EQ(false, receiver.message.value); + + infra::StdVectorInputStreamReader::WithStorage data2(infra::inPlace, std::initializer_list{ 1 }); + receiver.Feed(data2); + + EXPECT_EQ(true, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_uint32) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 5 }); + receiver.Feed(data); + + EXPECT_EQ(5, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_int32) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1 }); + receiver.Feed(data); + + EXPECT_EQ(-1, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_uint64) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 5 }); + receiver.Feed(data); + + EXPECT_EQ(5, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_int64) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1 }); + receiver.Feed(data); + + EXPECT_EQ(-1, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_fixed32) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 13, 0x90, 0x91, 0x0f, 0 }); + receiver.Feed(data); + + EXPECT_EQ(1020304, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_fixed64) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 9, 0x64, 0xc8, 0x0c, 0xce, 0xcb, 0x5c, 0x00, 0x00 }); + receiver.Feed(data); + + EXPECT_EQ(102030405060708, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_sfixed32) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 13, 0xff, 0xff, 0xff, 0xff }); + receiver.Feed(data); + + EXPECT_EQ(-1, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_sfixed64) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); + receiver.Feed(data); + + EXPECT_EQ(-1, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_enum) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 1 }); + receiver.Feed(data); + + EXPECT_EQ(test_messages::Enumeration::val1, receiver.message.e); +} + +TEST(ProtoMessageReceiverTest, parse_repeated_uint32) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 5, 1 << 3, 6 }); + receiver.Feed(data); + + EXPECT_EQ((infra::BoundedVector::WithMaxSize<10>{ { 5, 6 } }), receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_unbounded_repeated_uint32) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 1 << 3, 5, 1 << 3, 6 }); + receiver.Feed(data); + + EXPECT_EQ((std::vector{ { 5, 6 } }), receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_incomplete_int) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); + receiver.Feed(data); + EXPECT_EQ(0, receiver.message.value); + + infra::StdVectorInputStreamReader::WithStorage data2(infra::inPlace, std::initializer_list{ 0xff, 1 }); + receiver.Feed(data2); + EXPECT_EQ(-1, receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_string) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 10, 4, 'a', 'b', 'c', 'd' }); + receiver.Feed(data); + + EXPECT_EQ("abcd", receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_std_string) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 10, 4, 'a', 'b', 'c', 'd' }); + receiver.Feed(data); + + EXPECT_EQ("abcd", receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_bytes) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ 10, 2, 5, 6 }); + receiver.Feed(data); + + EXPECT_EQ((infra::BoundedVector::WithMaxSize<10>{ { 5, 6 } }), receiver.message.value); +} + +TEST(ProtoMessageReceiverTest, parse_message) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ (1 << 3) | 2, 2, 1 << 3, 5 }); + receiver.Feed(data); + + EXPECT_EQ((test_messages::TestMessageWithMessageField(test_messages::TestUInt32(5))), receiver.message.message); +} + +TEST(ProtoMessageReceiverTest, parse_more_nested_message) +{ + services::ProtoMessageReceiver receiver; + + infra::StdVectorInputStreamReader::WithStorage data(infra::inPlace, std::initializer_list{ (1 << 3) | 2, 2, 1 << 3, 5, (2 << 3) | 2, 2, 2 << 3, 10 }); + receiver.Feed(data); + + EXPECT_EQ((test_messages::TestMoreNestedMessage({ 5 }, { 10 })), receiver.message); +} diff --git a/protobuf/echo/test/TestProtoMessageSender.cpp b/protobuf/echo/test/TestProtoMessageSender.cpp new file mode 100644 index 000000000..3cefc4282 --- /dev/null +++ b/protobuf/echo/test/TestProtoMessageSender.cpp @@ -0,0 +1,222 @@ +#include "generated/echo/TestMessages.pb.hpp" +#include "infra/stream/BoundedVectorOutputStream.hpp" +#include "infra/stream/ByteOutputStream.hpp" +#include "infra/stream/StdVectorOutputStream.hpp" +#include "infra/util/ConstructBin.hpp" +#include "protobuf/echo/ProtoMessageSender.hpp" +#include + +class ProtoMessageSenderTest + : public testing::Test +{ +public: + template + void ExpectFill(const std::vector& data, services::ProtoMessageSender& sender) + { + infra::StdVectorOutputStream::WithStorage stream; + sender.Fill(stream); + + EXPECT_EQ(data, stream.Storage()); + } +}; + +TEST_F(ProtoMessageSenderTest, format_bool) +{ + test_messages::TestBool message{ true }; + services::ProtoMessageSender sender(message); + + ExpectFill({ 1 << 3, 1 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_uint32) +{ + test_messages::TestUInt32 message(5); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 1 << 3, 5 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_int32) +{ + test_messages::TestInt32 message(-1); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_uint64) +{ + test_messages::TestUInt64 message(5); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 1 << 3, 5 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_int64) +{ + test_messages::TestInt64 message(-1); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_fixed32) +{ + test_messages::TestFixed32 message(1020304); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 13, 0x90, 0x91, 0x0f, 0 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_fixed64) +{ + test_messages::TestFixed64 message(102030405060708); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 9, 0x64, 0xc8, 0x0c, 0xce, 0xcb, 0x5c, 0x00, 0x00 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_sfixed32) +{ + test_messages::TestSFixed32 message(-1); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 13, 0xff, 0xff, 0xff, 0xff }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_sfixed64) +{ + test_messages::TestSFixed64 message(-1); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, sender); +} + +TEST_F(ProtoMessageSenderTest, partially_format_bool) +{ + test_messages::TestBool message{ true }; + services::ProtoMessageSender sender(message); + + infra::ByteOutputStream::WithStorage<1> partialStream; + sender.Fill(partialStream); + infra::StdVectorOutputStream::WithStorage stream; + sender.Fill(stream); + + EXPECT_EQ((std::array{ 1 << 3 }), partialStream.Storage()); + EXPECT_EQ((std::vector{ 1 }), stream.Storage()); +} + +TEST_F(ProtoMessageSenderTest, format_enum) +{ + test_messages::TestEnum message{ test_messages::Enumeration::val1 }; + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 1 << 3, 1 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_repeated_uint32) +{ + test_messages::TestRepeatedUInt32 message; + message.value.push_back(5); + message.value.push_back(6); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 1 << 3, 5, 1 << 3, 6 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_unbounded_repeated_uint32) +{ + test_messages::TestUnboundedRepeatedUInt32 message; + message.value.push_back(5); + message.value.push_back(6); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 1 << 3, 5, 1 << 3, 6 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_string) +{ + test_messages::TestString message{ "abcd" }; + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 10, 4, 'a', 'b', 'c', 'd' }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_std_string) +{ + test_messages::TestStdString message{ "abcd" }; + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 10, 4, 'a', 'b', 'c', 'd' }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_bytes) +{ + test_messages::TestBytes message; + message.value.push_back(5); + message.value.push_back(6); + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 10, 2, 5, 6 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_message) +{ + test_messages::TestMessageWithMessageField message{ 5 }; + services::ProtoMessageSender sender{ message }; + + ExpectFill({ 1 << 3 | 2, 2, 1 << 3, 5 }, sender); +} + +TEST_F(ProtoMessageSenderTest, format_more_nested_message) +{ + test_messages::TestMoreNestedMessage message{ { 5 }, { 10 } }; + services::ProtoMessageSender sender{ message }; + + ExpectFill({ (1 << 3) | 2, 2, 1 << 3, 5, (2 << 3) | 2, 2, 2 << 3, 10 }, sender); +} + +TEST_F(ProtoMessageSenderTest, dont_format_on_buffer_full) +{ + test_messages::TestBoolWithBytes message; + message.b.insert(message.b.begin(), 30, static_cast(5)); + message.value = true; + services::ProtoMessageSender sender{ message }; + + infra::ByteOutputStream::WithStorage<1> partialStream; + sender.Fill(partialStream); + + infra::StdVectorOutputStream::WithStorage stream; + sender.Fill(stream); + EXPECT_EQ((std::vector{ 30, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2 << 3, 1 }), stream.Storage()); +} + +TEST_F(ProtoMessageSenderTest, format_many_repeated_uint32) +{ + test_messages::TestRepeatedUInt32 message; + message.value.insert(message.value.end(), 50, static_cast(5)); + services::ProtoMessageSender sender{ message }; + + infra::ByteOutputStream::WithStorage<10> partialStream; + sender.Fill(partialStream); + EXPECT_EQ((std::array{ 1 << 3, 5, 1 << 3, 5, 1 << 3, 5, 1 << 3, 5, 1 << 3, 5 }), partialStream.Storage()); + + infra::StdVectorOutputStream::WithStorage stream; + sender.Fill(stream); + EXPECT_EQ(infra::ConstructBin().Repeat(45, { 1 << 3, 5 }).Vector(), stream.Storage()); +} + +TEST_F(ProtoMessageSenderTest, format_many_bytes) +{ + test_messages::TestBytes message; + message.value.insert(message.value.end(), 50, static_cast(5)); + services::ProtoMessageSender sender{ message }; + + infra::ByteOutputStream::WithStorage<10> partialStream; + sender.Fill(partialStream); + EXPECT_EQ((std::array{ 10, 50, 5, 5, 5, 5, 5, 5, 5, 5 }), partialStream.Storage()); + + infra::StdVectorOutputStream::WithStorage stream; + sender.Fill(stream); + EXPECT_EQ((std::vector{ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }), stream.Storage()); +} diff --git a/protobuf/echo/test_doubles/ServiceStub.cpp b/protobuf/echo/test_doubles/ServiceStub.cpp index a9216d6ee..90a16384e 100644 --- a/protobuf/echo/test_doubles/ServiceStub.cpp +++ b/protobuf/echo/test_doubles/ServiceStub.cpp @@ -19,7 +19,7 @@ namespace services switch (field.second) { case 1: - DeserializeField(services::ProtoUInt32(), parser, field, value); + DeserializeField(services::ProtoUInt32(), parser, field.first, value); break; default: if (field.first.Is()) diff --git a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp index 493f2b7bc..3a35ff3a0 100644 --- a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp +++ b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp @@ -319,7 +319,7 @@ namespace application , prefix(prefix) {} - void MessageTypeMapGenerator::Run(Entities& formatter) + void MessageTypeMapGenerator::Run(Entities& formatter) const { auto typeMapNamespace = std::make_shared("detail"); @@ -331,15 +331,21 @@ namespace application { auto typeMapSpecialization = std::make_shared(MessageName() + "TypeMap"); typeMapSpecialization->TemplateSpecialization(google::protobuf::SimpleItoa(std::distance(message->fields.data(), &field))); - typeMapSpecialization->Add(std::make_shared("ProtoType", field->protoType)); + AddTypeMapProtoType(*field, *typeMapSpecialization); AddTypeMapType(*field, *typeMapSpecialization); + AddTypeMapFieldNumber(*field, *typeMapSpecialization); typeMapNamespace->Add(typeMapSpecialization); } formatter.Add(typeMapNamespace); } - void MessageTypeMapGenerator::AddTypeMapType(EchoField& field, Entities& entities) + void MessageTypeMapGenerator::AddTypeMapProtoType(const EchoField& field, Entities& entities) const + { + entities.Add(std::make_shared("ProtoType", field.protoType)); + } + + void MessageTypeMapGenerator::AddTypeMapType(const EchoField& field, Entities& entities) const { std::string result; StorageTypeVisitor visitor(result); @@ -347,6 +353,11 @@ namespace application entities.Add(std::make_shared("Type", result)); } + void MessageTypeMapGenerator::AddTypeMapFieldNumber(const EchoField& field, Entities& entities) const + { + entities.Add(std::make_shared("fieldNumber", "static const uint32_t", google::protobuf::SimpleItoa(field.number))); + } + std::string MessageTypeMapGenerator::MessageName() const { return prefix + message->name + MessageSuffix(); @@ -357,27 +368,12 @@ namespace application return ""; } - void MessageReferenceTypeMapGenerator::Run(Entities& formatter) + void MessageReferenceTypeMapGenerator::AddTypeMapProtoType(const EchoField& field, Entities& entities) const { - auto typeMapNamespace = std::make_shared("detail"); - - auto typeMapDeclaration = std::make_shared(MessageName() + "TypeMap"); - typeMapDeclaration->TemplateParameter("std::size_t fieldIndex"); - typeMapNamespace->Add(typeMapDeclaration); - - for (auto& field : message->fields) - { - auto typeMapSpecialization = std::make_shared(MessageName() + "TypeMap"); - typeMapSpecialization->TemplateSpecialization(google::protobuf::SimpleItoa(std::distance(message->fields.data(), &field))); - typeMapSpecialization->Add(std::make_shared("ProtoType", field->protoReferenceType)); - AddTypeMapType(*field, *typeMapSpecialization); - typeMapNamespace->Add(typeMapSpecialization); - } - - formatter.Add(typeMapNamespace); + entities.Add(std::make_shared("ProtoType", field.protoReferenceType)); } - void MessageReferenceTypeMapGenerator::AddTypeMapType(EchoField& field, Entities& entities) + void MessageReferenceTypeMapGenerator::AddTypeMapType(const EchoField& field, Entities& entities) const { std::string result; ParameterReferenceTypeVisitor visitor(result); @@ -476,12 +472,16 @@ namespace application { auto typeMap = std::make_shared("public"); + auto numberOfFields = std::make_shared("numberOfFields", "static const uint32_t", google::protobuf::SimpleItoa(message->fields.size())); + typeMap->Add(numberOfFields); auto protoTypeUsing = std::make_shared("ProtoType", "typename " + TypeMapName() + "::ProtoType"); protoTypeUsing->TemplateParameter("std::size_t fieldIndex"); typeMap->Add(protoTypeUsing); auto typeUsing = std::make_shared("Type", "typename " + TypeMapName() + "::Type"); typeUsing->TemplateParameter("std::size_t fieldIndex"); typeMap->Add(typeUsing); + auto fieldNumber = std::make_shared("fieldNumber", "template static const uint32_t", TypeMapName() + "::fieldNumber"); + typeMap->Add(fieldNumber); classFormatter->Add(typeMap); } @@ -493,9 +493,12 @@ namespace application for (auto& field : message->fields) { auto index = std::distance(message->fields.data(), &field); - auto function = std::make_shared("Get", "return " + field->name + ";\n", ClassName() + "::Type<" + google::protobuf::SimpleItoa(index) + ">&", 0); - function->Parameter("std::integral_constant"); - getters->Add(function); + auto functionGet = std::make_shared("Get", "return " + field->name + ";\n", ClassName() + "::Type<" + google::protobuf::SimpleItoa(index) + ">&", 0); + functionGet->Parameter("std::integral_constant"); + getters->Add(functionGet); + auto functionConstGet = std::make_shared("Get", "return " + field->name + ";\n", "const " + ClassName() + "::Type<" + google::protobuf::SimpleItoa(index) + ">&", Function::fConst); + functionConstGet->Parameter("std::integral_constant"); + getters->Add(functionConstGet); } classFormatter->Add(getters); @@ -618,7 +621,7 @@ namespace application for (auto& field : message->fields) printer.Print(R"(case $constant$: - DeserializeField($type$(), parser, field, $name$); + DeserializeField($type$(), parser, field.first, $name$); break; )", "constant", field->constantName, "type", field->protoType, "name", field->name); @@ -740,9 +743,12 @@ namespace application for (auto& field : message->fields) { auto index = std::distance(message->fields.data(), &field); - auto function = std::make_shared("Get", "return " + field->name + ";\n", ClassName() + "::Type<" + google::protobuf::SimpleItoa(index) + ">&", 0); - function->Parameter("std::integral_constant"); - getters->Add(function); + auto functionGet = std::make_shared("Get", "return " + field->name + ";\n", ClassName() + "::Type<" + google::protobuf::SimpleItoa(index) + ">&", 0); + functionGet->Parameter("std::integral_constant"); + getters->Add(functionGet); + auto functionConstGet = std::make_shared("Get", "return " + field->name + ";\n", ClassName() + "::Type<" + google::protobuf::SimpleItoa(index) + ">", Function::fConst); + functionConstGet->Parameter("std::integral_constant"); + getters->Add(functionConstGet); } classFormatter->Add(getters); diff --git a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp index 81c3676f6..c611e71c2 100644 --- a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp +++ b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp @@ -55,10 +55,12 @@ namespace application MessageTypeMapGenerator& operator=(const MessageTypeMapGenerator& other) = delete; ~MessageTypeMapGenerator() = default; - void Run(Entities& formatter); + void Run(Entities& formatter) const; protected: - virtual void AddTypeMapType(EchoField& field, Entities& entities); + virtual void AddTypeMapProtoType(const EchoField& field, Entities& entities) const; + virtual void AddTypeMapType(const EchoField& field, Entities& entities) const; + void AddTypeMapFieldNumber(const EchoField& field, Entities& entities) const; std::string MessageName() const; virtual std::string MessageSuffix() const; @@ -73,10 +75,9 @@ namespace application public: using MessageTypeMapGenerator::MessageTypeMapGenerator; - void Run(Entities& formatter); - protected: - void AddTypeMapType(EchoField& field, Entities& entities) override; + void AddTypeMapProtoType(const EchoField& field, Entities& entities) const override; + void AddTypeMapType(const EchoField& field, Entities& entities) const override; std::string MessageSuffix() const override; }; diff --git a/protobuf/protoc_echo_plugin/test/CMakeLists.txt b/protobuf/protoc_echo_plugin/test/CMakeLists.txt index e301e87a6..9e2eed725 100644 --- a/protobuf/protoc_echo_plugin/test/CMakeLists.txt +++ b/protobuf/protoc_echo_plugin/test/CMakeLists.txt @@ -2,7 +2,7 @@ add_executable(protobuf.protoc_echo_plugin_test) emil_build_for(protobuf.protoc_echo_plugin_test BOOL EMIL_BUILD_TESTS) emil_add_test(protobuf.protoc_echo_plugin_test) -protocol_buffer_echo_cpp(protobuf.protoc_echo_plugin_test TestMessages.proto) +protocol_buffer_echo_cpp(protobuf.protoc_echo_plugin_test ../../echo/test/TestMessages.proto) target_sources(protobuf.protoc_echo_plugin_test PRIVATE TestCppFormatter.cpp diff --git a/protobuf/protoc_echo_plugin/test/TestProtoCEchoPlugin.cpp b/protobuf/protoc_echo_plugin/test/TestProtoCEchoPlugin.cpp index 83aa9272e..5bf5bbf8f 100644 --- a/protobuf/protoc_echo_plugin/test/TestProtoCEchoPlugin.cpp +++ b/protobuf/protoc_echo_plugin/test/TestProtoCEchoPlugin.cpp @@ -159,6 +159,28 @@ TEST(ProtoCEchoPluginTest, deserialize_bool) EXPECT_EQ(true, message.value); } +TEST(ProtoCEchoPluginTest, serialize_enum) +{ + test_messages::TestEnum message; + message.e = test_messages::Enumeration::val1; + + infra::ByteOutputStream::WithStorage<100> stream; + infra::ProtoFormatter formatter(stream); + message.Serialize(formatter); + + EXPECT_EQ((std::array{ 8, 1 }), stream.Writer().Processed()); +} + +TEST(ProtoCEchoPluginTest, deserialize_enum) +{ + std::array data{ 8, 1 }; + infra::ByteInputStream stream(data); + infra::ProtoParser parser(stream); + + test_messages::TestEnum message(parser); + EXPECT_EQ(test_messages::Enumeration::val1, message.e); +} + TEST(ProtoCEchoPluginTest, serialize_string) { test_messages::TestString message; @@ -265,6 +287,32 @@ TEST(ProtoCEchoPluginTest, deserialize_bytes) EXPECT_EQ(value, message.value); } +TEST(ProtoCEchoPluginTest, serialize_unbounded_bytes) +{ + test_messages::TestUnboundedBytes message; + message.value.push_back(5); + message.value.push_back(6); + + infra::ByteOutputStream::WithStorage<100> stream; + infra::ProtoFormatter formatter(stream); + message.Serialize(formatter); + + EXPECT_EQ((std::array{ 10, 2, 5, 6 }), stream.Writer().Processed()); +} + +TEST(ProtoCEchoPluginTest, deserialize_unbounded_bytes) +{ + std::array data{ 10, 2, 5, 6 }; + infra::ByteInputStream stream(data); + infra::ProtoParser parser(stream); + + test_messages::TestUnboundedBytes message(parser); + std::vector value; + value.push_back(5); + value.push_back(6); + EXPECT_EQ(value, message.value); +} + TEST(ProtoCEchoPluginTest, serialize_uint32) { test_messages::TestUInt32 message; @@ -334,6 +382,31 @@ TEST(ProtoCEchoPluginTest, deserialize_repeated_uint32) EXPECT_EQ(6, message.value[1]); } +TEST(ProtoCEchoPluginTest, serialize_unbounded_repeated_uint32) +{ + test_messages::TestUnboundedRepeatedUInt32 message; + message.value.push_back(5); + message.value.push_back(6); + + infra::ByteOutputStream::WithStorage<100> stream; + infra::ProtoFormatter formatter(stream); + message.Serialize(formatter); + + EXPECT_EQ((std::array{ 1 << 3, 5, 1 << 3, 6 }), stream.Writer().Processed()); +} + +TEST(ProtoCEchoPluginTest, deserialize_unbounded_repeated_uint32) +{ + std::array data{ 1 << 3, 5, 1 << 3, 6 }; + infra::ByteInputStream stream(data); + infra::ProtoParser parser(stream); + + test_messages::TestUnboundedRepeatedUInt32 message(parser); + EXPECT_EQ(2, message.value.size()); + EXPECT_EQ(5, message.value[0]); + EXPECT_EQ(6, message.value[1]); +} + TEST(ProtoCEchoPluginTest, serialize_message) { test_messages::TestMessageWithMessageField message; diff --git a/services/network/test_doubles/Certificates.cpp b/services/network/test_doubles/Certificates.cpp index 304f07a74..bffa0ff77 100644 --- a/services/network/test_doubles/Certificates.cpp +++ b/services/network/test_doubles/Certificates.cpp @@ -53,7 +53,7 @@ namespace services "-----END CERTIFICATE-----\r\n"; const char testServerKeyData[] = - "-----BEGIN RSA PRIVATE KEY-----\r\n" + "-----BEGIN RSA PRIVATE KEY-----\r\n" //NOSONAR "MIIEogIBAAKCAQEArcYgmszNxJu5pfLpploIw12iIfAyZWK6PZ1/6zlifaR1v0KL\r\n" "x08aLSQAOAvnb8jmfVzkBwpt3hYVm69gWdTJcFpRXMuZ1nIur7HEDQXtzrgvmV6v\r\n" "d8Eu7ngoGfHijP9eiuwxoYNiMmbyvTM2hYnRn5WllOnbK5OBldnh0Vawh/XErMO/\r\n" @@ -105,7 +105,7 @@ namespace services "-----END CERTIFICATE-----\r\n"; const char testClientKeyData[] = - "-----BEGIN RSA PRIVATE KEY-----\r\n" + "-----BEGIN RSA PRIVATE KEY-----\r\n" //NOSONAR "MIIEowIBAAKCAQEAqNdp/w5eM4io5Ki/amQC8FAuhhdk1H3ELm11MmkYTLXJBsSc\r\n" "RCLIdiyM3Ten/I3bZtI0Ak7yvubQnozeBZig3usBBapfOvx5adCSsZfwGjgsqLF+\r\n" "zQ2maEd15pHSRPPXBAJ++4ZpxdVkfr0r/ZRIxWJwvyxtK3N0BJfUcop1J2fa3cZx\r\n" From 6e05bb7551327fd5d52accbec2ef07ec8f6b961b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 17:52:31 +0200 Subject: [PATCH 09/37] build(deps): bump google-github-actions/release-please-action from 3.7.11 to 3.7.12 (#426) build(deps): bump google-github-actions/release-please-action Bumps [google-github-actions/release-please-action](https://github.com/google-github-actions/release-please-action) from 3.7.11 to 3.7.12. - [Release notes](https://github.com/google-github-actions/release-please-action/releases) - [Changelog](https://github.com/google-github-actions/release-please-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/google-github-actions/release-please-action/compare/ca6063f4ed81b55db15b8c42d1b6f7925866342d...4c5670f886fe259db4d11222f7dff41c1382304d) --- updated-dependencies: - dependency-name: google-github-actions/release-please-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 9714fc9cc..4ecbbbd77 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -26,7 +26,7 @@ jobs: app_id: ${{ secrets.FOREST_RELEASER_APP_ID }} app_base64_private_key: ${{ secrets.FOREST_RELEASER_APP_PRIVATE_KEY_BASE64 }} auth_type: installation - - uses: google-github-actions/release-please-action@ca6063f4ed81b55db15b8c42d1b6f7925866342d # v3.7.11 + - uses: google-github-actions/release-please-action@4c5670f886fe259db4d11222f7dff41c1382304d # v3.7.12 id: release with: command: manifest From 45eb746d2028b103ef88f5a1718329fa271f370e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 07:43:08 +0200 Subject: [PATCH 10/37] build(deps): bump oss-fuzz-base/base-builder from `5e1404d` to `6c61e46` in /.clusterfuzzlite (#427) build(deps): bump oss-fuzz-base/base-builder in /.clusterfuzzlite Bumps oss-fuzz-base/base-builder from `5e1404d` to `6c61e46`. --- updated-dependencies: - dependency-name: oss-fuzz-base/base-builder dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .clusterfuzzlite/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile index 42026362f..3d01d2e62 100644 --- a/.clusterfuzzlite/Dockerfile +++ b/.clusterfuzzlite/Dockerfile @@ -1,4 +1,4 @@ -FROM gcr.io/oss-fuzz-base/base-builder@sha256:5e1404dc68c77c2a8fdefd8c50f21d069aee193fe3648a9e4fe1ef4d45e3f732 +FROM gcr.io/oss-fuzz-base/base-builder@sha256:6c61e467be42d10170ab0c4715d25805829e7c97aa60ce7b408687a02cd40c2d RUN apt-get update && apt-get upgrade -y --no-install-recommends \ ninja-build \ From 19d14bf6403af9e88a514ac8caf4c3b71cde9800 Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Tue, 3 Oct 2023 08:10:08 +0200 Subject: [PATCH 11/37] build: add emil_install to emil_build_for.cmake which only installs the target if it is part of the All target (#425) (cherry picked from commit b66998378b034476eecbc835f4cd9b16502d0fb7) --- cmake/emil_build_for.cmake | 7 +++++++ services/echo_console/CMakeLists.txt | 2 +- upgrade/security_key_generator/CMakeLists.txt | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmake/emil_build_for.cmake b/cmake/emil_build_for.cmake index 0aa6e90da..282ce81cb 100644 --- a/cmake/emil_build_for.cmake +++ b/cmake/emil_build_for.cmake @@ -88,3 +88,10 @@ function(emil_build_for target) endif() endfunction() + +function(emil_install target) + get_target_property(exclude ${target} EXCLUDE_FROM_ALL) + if (NOT ${exclude}) + install(TARGETS ${target} ${ARGN}) + endif() +endfunction() diff --git a/services/echo_console/CMakeLists.txt b/services/echo_console/CMakeLists.txt index eb292ad84..843ecf8ef 100644 --- a/services/echo_console/CMakeLists.txt +++ b/services/echo_console/CMakeLists.txt @@ -1,6 +1,6 @@ if (EMIL_HOST_BUILD) add_executable(services.echo_console ${EMIL_EXCLUDE_FROM_ALL}) - install(TARGETS services.echo_console EXPORT emilProtobufTargets DESTINATION bin) + emil_install(services.echo_console EXPORT emilProtobufTargets DESTINATION bin) target_link_libraries(services.echo_console PUBLIC args diff --git a/upgrade/security_key_generator/CMakeLists.txt b/upgrade/security_key_generator/CMakeLists.txt index 885f1ba2c..660983433 100644 --- a/upgrade/security_key_generator/CMakeLists.txt +++ b/upgrade/security_key_generator/CMakeLists.txt @@ -1,6 +1,6 @@ add_executable(upgrade.security_key_generator) emil_build_for(upgrade.security_key_generator HOST All PREREQUISITE_BOOL EMIL_STANDALONE) -install(TARGETS upgrade.security_key_generator EXPORT emilUpgradeTargets DESTINATION bin) +emil_install(upgrade.security_key_generator EXPORT emilUpgradeTargets DESTINATION bin) target_link_libraries(upgrade.security_key_generator PUBLIC args From fd73c78b4c977c1110a218586848a4418e5b247b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:13:56 +0200 Subject: [PATCH 12/37] build(deps): bump seanmiddleditch/gha-setup-ninja from 3 to 4 (#430) Bumps [seanmiddleditch/gha-setup-ninja](https://github.com/seanmiddleditch/gha-setup-ninja) from 3 to 4. - [Release notes](https://github.com/seanmiddleditch/gha-setup-ninja/releases) - [Commits](https://github.com/seanmiddleditch/gha-setup-ninja/compare/16b940825621068d98711680b6c3ff92201f8fc0...8b297075da4cd2a5f1fd21fe011b499edf06e9d2) --- updated-dependencies: - dependency-name: seanmiddleditch/gha-setup-ninja dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 485e695a9..327ece4bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: with: key: ${{ github.job }}-ubuntu-latest variant: sccache - - uses: seanmiddleditch/gha-setup-ninja@16b940825621068d98711680b6c3ff92201f8fc0 # v3 + - uses: seanmiddleditch/gha-setup-ninja@8b297075da4cd2a5f1fd21fe011b499edf06e9d2 # v4 - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 with: configurePreset: "host" From 536bf6daf4bf9b9505da382cdbd26e83c16197ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:15:11 +0200 Subject: [PATCH 13/37] build(deps): bump ossf/scorecard-action from 2.2.0 to 2.3.0 (#432) Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/08b4669551908b1024bb425080c797723083c031...483ef80eb98fb506c348f7d62e28055e49fe2398) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 858a8e9bd..1d44dd266 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -25,7 +25,7 @@ jobs: with: persist-credentials: false - name: Analysis - uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0 + uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0 with: results_file: scorecards.sarif results_format: sarif From 48b11274403bb9a5ba11b1ab7b24711f17b2bb31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:15:42 +0200 Subject: [PATCH 14/37] build(deps): bump github/codeql-action from 2.21.9 to 2.22.1 (#433) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.9 to 2.22.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/ddccb873888234080b77e9bc2d4764d5ccaaccf9...fdcae64e1484d349b3366718cdfef3d404390e85) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 21860556d..a10482ec1 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -51,7 +51,7 @@ jobs: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + - uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 if: ${{ success() || failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 1d44dd266..4a78a47fc 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,6 @@ jobs: results_format: sarif repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} publish_results: true - - uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + - uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 with: sarif_file: scorecards.sarif diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index e6af0dae3..836538c8b 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -75,7 +75,7 @@ jobs: - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - - uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + - uses: github/codeql-action/init@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 with: languages: cpp - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 @@ -83,4 +83,4 @@ jobs: configurePreset: "host" buildPreset: "host-Debug" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" - - uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + - uses: github/codeql-action/analyze@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 From 83d39fdeebbdc04e4d44f380460320ba4711d949 Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Wed, 11 Oct 2023 12:01:29 +0200 Subject: [PATCH 15/37] chore: make services/util/MessageCommunicationSecured compliant with MbedTLS version 2 (#434) * chore: make services/util/MessageCommunicationSecured compliant with MbedTLS version 2 * services/util/MessageCommunicationSecured: Include mbedtls/version.h --- services/util/MessageCommunicationSecured.cpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/services/util/MessageCommunicationSecured.cpp b/services/util/MessageCommunicationSecured.cpp index 48a6591c0..32a5be95b 100644 --- a/services/util/MessageCommunicationSecured.cpp +++ b/services/util/MessageCommunicationSecured.cpp @@ -1,4 +1,5 @@ #include "services/util/MessageCommunicationSecured.hpp" +#include "mbedtls/version.h" #include namespace services @@ -71,7 +72,12 @@ namespace services return; receiveBuffer.clear(); + +#if MBEDTLS_VERSION_MAJOR < 3 + really_assert(mbedtls_gcm_starts(&receiveContext, MBEDTLS_GCM_DECRYPT, reinterpret_cast(receiveIv.data()), receiveIv.size(), nullptr, 0) == 0); +#else really_assert(mbedtls_gcm_starts(&receiveContext, MBEDTLS_GCM_DECRYPT, reinterpret_cast(receiveIv.data()), receiveIv.size()) == 0); +#endif while (stream.Available() != blockSize) { @@ -80,14 +86,22 @@ namespace services stream >> infra::MakeRange(encrypted); receiveBuffer.resize(receiveBuffer.size() + encrypted.size()); +#if MBEDTLS_VERSION_MAJOR < 3 + really_assert(mbedtls_gcm_update(&receiveContext, encrypted.size(), encrypted.data(), receiveBuffer.data() + receiveBuffer.size() - encrypted.size()) == 0); +#else std::size_t processedSize = 0; really_assert(mbedtls_gcm_update(&receiveContext, encrypted.data(), encrypted.size(), receiveBuffer.data() + receiveBuffer.size() - encrypted.size(), receiveBuffer.size(), &processedSize) == 0); receiveBuffer.resize(receiveBuffer.size() - encrypted.size() + processedSize); +#endif } std::array computedMac; +#if MBEDTLS_VERSION_MAJOR < 3 + really_assert(mbedtls_gcm_finish(&receiveContext, reinterpret_cast(computedMac.data()), computedMac.size()) == 0); +#else std::size_t processedSize = 0; really_assert(mbedtls_gcm_finish(&receiveContext, nullptr, 0, &processedSize, reinterpret_cast(computedMac.data()), computedMac.size()) == 0); +#endif std::array receivedMac; stream >> infra::MakeRange(receivedMac); @@ -101,15 +115,28 @@ namespace services void MessageCommunicationSecured::SendMessageStreamReleased() { +#if MBEDTLS_VERSION_MAJOR < 3 + really_assert(mbedtls_gcm_starts(&sendContext, MBEDTLS_GCM_ENCRYPT, reinterpret_cast(sendIv.data()), sendIv.size(), nullptr, 0) == 0); +#else really_assert(mbedtls_gcm_starts(&sendContext, MBEDTLS_GCM_ENCRYPT, reinterpret_cast(sendIv.data()), sendIv.size()) == 0); +#endif +#if MBEDTLS_VERSION_MAJOR < 3 + really_assert(mbedtls_gcm_update(&sendContext, sendBuffer.size(), sendBuffer.data(), sendBuffer.data()) == 0); +#else std::size_t processedSize = 0; really_assert(mbedtls_gcm_update(&sendContext, sendBuffer.data(), sendBuffer.size(), sendBuffer.data(), sendBuffer.size(), &processedSize) == 0); +#endif + sendBuffer.resize(sendBuffer.size() + blockSize); +#if MBEDTLS_VERSION_MAJOR < 3 + really_assert(mbedtls_gcm_finish(&sendContext, sendBuffer.data() + sendBuffer.size() - blockSize, blockSize) == 0); +#else std::size_t moreProcessedSize = 0; really_assert(mbedtls_gcm_finish(&sendContext, sendBuffer.data() + processedSize, sendBuffer.size() - processedSize - blockSize, &moreProcessedSize, sendBuffer.data() + sendBuffer.size() - blockSize, blockSize) == 0); really_assert(processedSize + moreProcessedSize + blockSize == sendBuffer.size()); +#endif infra::DataOutputStream::WithErrorPolicy stream(*sendWriter); stream << infra::MakeRange(sendBuffer); From ef29941697aba1567f57e809ef5ee3c47a8b5bcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 08:38:24 +0200 Subject: [PATCH 16/37] build(deps): bump github/codeql-action from 2.22.1 to 2.22.3 (#437) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.1 to 2.22.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/fdcae64e1484d349b3366718cdfef3d404390e85...0116bc2df50751f9724a2e35ef1f24d22f90e4e1) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index a10482ec1..81b7d4434 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -51,7 +51,7 @@ jobs: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 + - uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 if: ${{ success() || failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 4a78a47fc..4a763350c 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,6 @@ jobs: results_format: sarif repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} publish_results: true - - uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 + - uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 with: sarif_file: scorecards.sarif diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 836538c8b..16ac7b925 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -75,7 +75,7 @@ jobs: - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - - uses: github/codeql-action/init@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 + - uses: github/codeql-action/init@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 with: languages: cpp - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 @@ -83,4 +83,4 @@ jobs: configurePreset: "host" buildPreset: "host-Debug" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" - - uses: github/codeql-action/analyze@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 + - uses: github/codeql-action/analyze@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 From a9070a405daeaaf9f20e6f5b08baa2cf5c0a4241 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 09:26:31 +0200 Subject: [PATCH 17/37] build(deps): bump actions/checkout from 4.1.0 to 4.1.1 (#438) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8ade135a41bc03ea155e62e844d188df1ea18608...b4ffde65f46336ab88eb53be808477a3936bae11) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/dependency-scanner.yml | 4 ++-- .github/workflows/documentation.yml | 6 +++--- .github/workflows/linting-formatting.yml | 4 ++-- .github/workflows/release-please.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 327ece4bf..1c19418cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: name: Host Build & Test (ubuntu-latest) runs-on: ubuntu-latest steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 @@ -54,7 +54,7 @@ jobs: matrix: os: [macos-latest, windows-latest, windows-2019] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 @@ -82,7 +82,7 @@ jobs: gcc: ["7-2018-q2", "8-2019-q3", "9-2020-q2", "10.3-2021.10"] configuration: ["RelWithDebInfo"] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: Install GNU Arm Embedded Toolchain ${{ matrix.gcc }} @@ -111,7 +111,7 @@ jobs: matrix: rtos: ["FreeRTOS", "ThreadX"] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: Install GNU Arm Embedded Toolchain "10.3-2021.10" diff --git a/.github/workflows/dependency-scanner.yml b/.github/workflows/dependency-scanner.yml index 25ee4c5ce..f6936d907 100644 --- a/.github/workflows/dependency-scanner.yml +++ b/.github/workflows/dependency-scanner.yml @@ -16,7 +16,7 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: philips-forks/cmake-dependency-submission@72880580a7cafc16145d82268f1892c0ece3da2a # main dependency-review: runs-on: ubuntu-latest @@ -25,7 +25,7 @@ jobs: permissions: pull-requests: write steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3.1.0 with: comment-summary-in-pr: true diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 7bd5a63db..3ac1685c6 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -16,7 +16,7 @@ jobs: if: ${{ github.ref == 'refs/heads/main' }} steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 persist-credentials: false @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 persist-credentials: false @@ -69,7 +69,7 @@ jobs: name: Publish to GitHub Pages steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Retrieve Antora Site uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 81b7d4434..2e792f509 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -21,7 +21,7 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@a83a8fb7d371f66da7dd1c4f33a193023899494b # v0.16 @@ -42,7 +42,7 @@ jobs: pull-requests: write security-events: write steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 4ecbbbd77..78a43de67 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -43,7 +43,7 @@ jobs: matrix: os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 4a763350c..eae956b7a 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -21,7 +21,7 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: Analysis diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 16ac7b925..4b7eb3e17 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -23,7 +23,7 @@ jobs: SONAR_SCANNER_VERSION: 5.0.1.3006 SONAR_SERVER_URL: "https://sonarcloud.io" steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 # Disable shallow clone to enable blame information persist-credentials: false @@ -69,7 +69,7 @@ jobs: permissions: security-events: write steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 From 4b5215609b9ee2a6ca72d8d660b8c797aa3e31c9 Mon Sep 17 00:00:00 2001 From: Daan Timmer <8293597+daantimmer@users.noreply.github.com> Date: Thu, 19 Oct 2023 09:27:12 +0200 Subject: [PATCH 18/37] feat: removed Dac.hpp (#439) --- hal/interfaces/CMakeLists.txt | 1 - hal/interfaces/Dac.hpp | 59 ----------------------------------- 2 files changed, 60 deletions(-) delete mode 100644 hal/interfaces/Dac.hpp diff --git a/hal/interfaces/CMakeLists.txt b/hal/interfaces/CMakeLists.txt index f163c562f..0d94b4dcd 100644 --- a/hal/interfaces/CMakeLists.txt +++ b/hal/interfaces/CMakeLists.txt @@ -18,7 +18,6 @@ target_sources(hal.interfaces PRIVATE Can.cpp Can.hpp CommunicationConfigurator.hpp - Dac.hpp DigitalToAnalogPin.hpp Ethernet.hpp Flash.cpp diff --git a/hal/interfaces/Dac.hpp b/hal/interfaces/Dac.hpp deleted file mode 100644 index 930247590..000000000 --- a/hal/interfaces/Dac.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef HAL_DAC_HPP -#define HAL_DAC_HPP - -#include "infra/util/Unit.hpp" - -namespace hal -{ - template - class Dac - { - protected: - Dac() = default; - - Dac(const Dac&) = delete; - Dac& operator=(const Dac&) = delete; - ~Dac() = default; - - public: - virtual void SetOutput(infra::Quantity value) = 0; - }; - - class DacImplBase - { - protected: - ~DacImplBase() = default; - - public: - virtual void SetOutput(uint16_t value) = 0; - }; - - template - class DacConverter - : public Dac - , public Impl - { - public: - template - DacConverter(Args&&... args); - - void SetOutput(infra::Quantity value); - }; - - //// Implementation //// - - template - template - DacConverter::DacConverter(Args&&... args) - : Impl(std::forward(args)...) - {} - - template - void DacConverter::SetOutput(infra::Quantity value) - { - infra::Quantity convertedValue(value * infra::Quantity(1)); - Impl::SetOutput(convertedValue.Value()); - } -} - -#endif From 2c87dfb5ecd1e76669af69a97f80c29bfab773b9 Mon Sep 17 00:00:00 2001 From: Daan Timmer <8293597+daantimmer@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:59:24 +0200 Subject: [PATCH 19/37] feat: added SerialCommunicationLoopback (#440) * feat: added SerialCommunicationLoopback * chore: replaced ClockFixture with EventDispatcherFixture * chore: made SerialCommunicationLoopback compatible with <= GCC9 * chore: fixed comments * chore: correct comparing byte ranges for SerialCommunicationLoopbackTest * chore: fix coverage and macos build --------- Co-authored-by: Daan Timmer --- services/util/CMakeLists.txt | 2 + services/util/SerialCommunicationLoopback.cpp | 42 +++++++++++++ services/util/SerialCommunicationLoopback.hpp | 43 +++++++++++++ services/util/test/CMakeLists.txt | 2 + .../test/TestSerialCommunicationLoopback.cpp | 63 +++++++++++++++++++ 5 files changed, 152 insertions(+) create mode 100644 services/util/SerialCommunicationLoopback.cpp create mode 100644 services/util/SerialCommunicationLoopback.hpp create mode 100644 services/util/test/TestSerialCommunicationLoopback.cpp diff --git a/services/util/CMakeLists.txt b/services/util/CMakeLists.txt index 9e8191af2..ab5588d3d 100644 --- a/services/util/CMakeLists.txt +++ b/services/util/CMakeLists.txt @@ -58,6 +58,8 @@ target_sources(services.util PRIVATE MessageCommunicationWindowed.hpp RepeatingButton.cpp RepeatingButton.hpp + SerialCommunicationLoopback.cpp + SerialCommunicationLoopback.hpp Sha256.hpp SignalLed.cpp SignalLed.hpp diff --git a/services/util/SerialCommunicationLoopback.cpp b/services/util/SerialCommunicationLoopback.cpp new file mode 100644 index 000000000..c0e166e90 --- /dev/null +++ b/services/util/SerialCommunicationLoopback.cpp @@ -0,0 +1,42 @@ +#include "services/util/SerialCommunicationLoopback.hpp" +#include "hal/interfaces/SerialCommunication.hpp" +#include "infra/event/EventDispatcher.hpp" + +namespace services +{ + SerialCommunicationLoopback::SerialCommunicationLoopback() + : server(&client) + , client(&server) + {} + + hal::SerialCommunication& SerialCommunicationLoopback::Server() + { + return server; + } + + hal::SerialCommunication& SerialCommunicationLoopback::Client() + { + return client; + } + + SerialCommunicationLoopback::SerialCommunicationLoopbackPeer::SerialCommunicationLoopbackPeer(SerialCommunicationLoopbackPeer* other) + : other{ *other } + {} + + void SerialCommunicationLoopback::SerialCommunicationLoopbackPeer::SendData(infra::ConstByteRange data, infra::Function actionOnCompletion) + { + this->data = data; + this->actionOnCompletion = actionOnCompletion; + + infra::EventDispatcher::Instance().Schedule([this] + { + other.dataReceived(this->data); + this->actionOnCompletion(); + }); + } + + void SerialCommunicationLoopback::SerialCommunicationLoopbackPeer::ReceiveData(infra::Function dataReceived) + { + this->dataReceived = dataReceived; + } +} diff --git a/services/util/SerialCommunicationLoopback.hpp b/services/util/SerialCommunicationLoopback.hpp new file mode 100644 index 000000000..5b63250b2 --- /dev/null +++ b/services/util/SerialCommunicationLoopback.hpp @@ -0,0 +1,43 @@ +#ifndef SERVICES_SERIAL_COMMUNICATION_LOOPBACK_HPP +#define SERVICES_SERIAL_COMMUNICATION_LOOPBACK_HPP + +#include "hal/interfaces/SerialCommunication.hpp" + +namespace services +{ + + class SerialCommunicationLoopback + { + public: + SerialCommunicationLoopback(); + + hal::SerialCommunication& Server(); + hal::SerialCommunication& Client(); + + private: + class SerialCommunicationLoopbackPeer + : public hal::SerialCommunication + { + public: + // pointer instead of reference to avoid defining a copy constructor + // pass by reference generates a warning with clang and -Wunitialized + explicit SerialCommunicationLoopbackPeer(SerialCommunicationLoopbackPeer* other); + + void SendData(infra::ConstByteRange data, infra::Function actionOnCompletion) override; + void ReceiveData(infra::Function dataReceived) override; + + private: + SerialCommunicationLoopbackPeer& other; + + infra::ConstByteRange data; + infra::Function actionOnCompletion; + infra::Function dataReceived; + }; + + private: + SerialCommunicationLoopbackPeer server; + SerialCommunicationLoopbackPeer client; + }; +} + +#endif diff --git a/services/util/test/CMakeLists.txt b/services/util/test/CMakeLists.txt index 3a5634451..7a307a65a 100644 --- a/services/util/test/CMakeLists.txt +++ b/services/util/test/CMakeLists.txt @@ -14,6 +14,7 @@ target_link_libraries(services.util_test PUBLIC hal.interfaces_test_doubles infra.timer_test_helper infra.util_test_helper + infra.event_test_helper ) target_sources(services.util_test PRIVATE @@ -39,6 +40,7 @@ target_sources(services.util_test PRIVATE TestMessageCommunicationSecured.cpp TestMessageCommunicationWindowed.cpp TestRepeatingButton.cpp + TestSerialCommunicationLoopback.cpp TestSignalLed.cpp TestSpiMasterWithChipSelect.cpp TestSpiMultipleAccess.cpp diff --git a/services/util/test/TestSerialCommunicationLoopback.cpp b/services/util/test/TestSerialCommunicationLoopback.cpp new file mode 100644 index 000000000..748bf5db8 --- /dev/null +++ b/services/util/test/TestSerialCommunicationLoopback.cpp @@ -0,0 +1,63 @@ +#include "hal/interfaces/SerialCommunication.hpp" +#include "infra/event/test_helper/EventDispatcherFixture.hpp" +#include "infra/util/ByteRange.hpp" +#include "infra/util/Function.hpp" +#include "infra/util/test_helper/MockCallback.hpp" +#include "services/util/SerialCommunicationLoopback.hpp" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +class SerialCommunicationLoopbackTest + : public testing::Test + , public infra::EventDispatcherFixture +{ +public: + services::SerialCommunicationLoopback SerialCommunicationLoopback; + hal::SerialCommunication& server{ SerialCommunicationLoopback.Server() }; + hal::SerialCommunication& client{ SerialCommunicationLoopback.Client() }; +}; + +TEST_F(SerialCommunicationLoopbackTest, SendFromServerReceiveByClient) +{ + infra::ConstByteRange data = infra::MakeStringByteRange("hello"); + infra::VerifyingFunctionMock clientReceiveCallback{ data }; + + client.ReceiveData(clientReceiveCallback); + server.SendData(data, infra::emptyFunction); + + ExecuteAllActions(); +} + +TEST_F(SerialCommunicationLoopbackTest, SendFromClientReceiveByServer) +{ + infra::ConstByteRange data = infra::MakeStringByteRange("world"); + infra::VerifyingFunctionMock serverReceiveCallback{ data }; + + server.ReceiveData(serverReceiveCallback); + client.SendData(data, infra::emptyFunction); + + ExecuteAllActions(); +} + +TEST_F(SerialCommunicationLoopbackTest, ActionOnCompletionAfterDataReceivedByOtherPeer) +{ + infra::ConstByteRange data = infra::MakeStringByteRange("Hello World!"); + infra::MockCallback dataReceivedMockCallback; + infra::MockCallback actionOnCompletionMockCallback; + + server.ReceiveData([&dataReceivedMockCallback](infra::ConstByteRange data) + { + dataReceivedMockCallback.callback(data); + }); + + client.SendData(data, [&actionOnCompletionMockCallback] + { + actionOnCompletionMockCallback.callback(); + }); + + testing::InSequence sequence; + EXPECT_CALL(dataReceivedMockCallback, callback(data)); + EXPECT_CALL(actionOnCompletionMockCallback, callback()); + + ExecuteAllActions(); +} From 063b59508f1d09c2675b338c7b54d64934f7792c Mon Sep 17 00:00:00 2001 From: Daan Timmer <8293597+daantimmer@users.noreply.github.com> Date: Mon, 23 Oct 2023 18:00:31 +0200 Subject: [PATCH 20/37] fix: added workaround mbedtls and clang-cl incomatibility (#441) * fix: added workaround by replacing CMAKE_C_COMPILER_ID with CMAKE_C_SIMULATE_ID when configuring mbedtls * chore: reworked comment and removed references to xwin --- external/crypto/mbedtls/CMakeLists.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/external/crypto/mbedtls/CMakeLists.txt b/external/crypto/mbedtls/CMakeLists.txt index b5514e418..e44c96cd6 100644 --- a/external/crypto/mbedtls/CMakeLists.txt +++ b/external/crypto/mbedtls/CMakeLists.txt @@ -11,8 +11,28 @@ set(ENABLE_TESTING Off CACHE INTERNAL "") set(ENABLE_PROGRAMS Off CACHE INTERNAL "") set(GEN_FILES Off CACHE INTERNAL "") +# mbedtls uses CMAKE_C_COMPILER_ID to determine the type of compiler used. +# When compiling with clang-cl, mbedtls thinks the clang compiler +# is used, and sets flags according to what clang expects as arguments. +# However, clang-cl expects MSVC like arguments. Therefore we have to trick mbedtls +# in to thinking MSVC is being used as a compiler. +# After making mbedtls available the original COMPILER_ID will be restored +set(ORIGINAL_C_COMPILER_ID ${CMAKE_C_COMPILER_ID}) +set(ORIGINAL_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) + +if (CMAKE_C_SIMULATE_ID) + set(CMAKE_C_COMPILER_ID ${CMAKE_C_SIMULATE_ID}) +endif() + +if (CMAKE_CXX_SIMULATE_ID) + set(CMAKE_CXX_COMPILER_ID ${CMAKE_CXX_SIMULATE_ID}) +endif() + FetchContent_MakeAvailable(mbedtls) +set(CMAKE_C_COMPILER_ID ${ORIGINAL_C_COMPILER_ID}) +set(CMAKE_CXX_COMPILER_ID ${ORIGINAL_CXX_COMPILER_ID}) + function(add_mbedtls_target_properties) foreach(target ${ARGN}) target_compile_options(${target} PUBLIC From 21f640d69edfc22a0f81007e6360892f4f5e95f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:56:36 +0200 Subject: [PATCH 21/37] build(deps): bump Namchee/conventional-pr from 0.14.0 to 0.14.1 (#443) Bumps [Namchee/conventional-pr](https://github.com/namchee/conventional-pr) from 0.14.0 to 0.14.1. - [Release notes](https://github.com/namchee/conventional-pr/releases) - [Commits](https://github.com/namchee/conventional-pr/compare/5d1221ff603c491a4abb1e614a0f4ded41d4b397...cc86d488dd8f2c0d64386da3a6f4112f7475d25b) --- updated-dependencies: - dependency-name: Namchee/conventional-pr dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/validate-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index 209866b5d..459e7b1c1 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -11,7 +11,7 @@ jobs: conventional_commit: runs-on: ubuntu-latest steps: - - uses: Namchee/conventional-pr@5d1221ff603c491a4abb1e614a0f4ded41d4b397 # v0.14.0 + - uses: Namchee/conventional-pr@cc86d488dd8f2c0d64386da3a6f4112f7475d25b # v0.14.1 with: access_token: ${{ secrets.GITHUB_TOKEN }} body: false From d6de5359dfa9b222aef15b6e03e682e6b72e4ffa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 09:57:19 +0200 Subject: [PATCH 22/37] build(deps): bump ossf/scorecard-action from 2.3.0 to 2.3.1 (#444) Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.3.0 to 2.3.1. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/483ef80eb98fb506c348f7d62e28055e49fe2398...0864cf19026789058feabb7e87baa5f140aac736) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index eae956b7a..6f0529db4 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -25,7 +25,7 @@ jobs: with: persist-credentials: false - name: Analysis - uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0 + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 with: results_file: scorecards.sarif results_format: sarif From 8039f730a271195fd34ea39f7c47870390cda388 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:23:56 +0200 Subject: [PATCH 23/37] build(deps): bump github/codeql-action from 2.22.3 to 2.22.4 (#442) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.3 to 2.22.4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/0116bc2df50751f9724a2e35ef1f24d22f90e4e1...49abf0ba24d0b7953cb586944e918a0b92074c80) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 2e792f509..276948ee5 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -51,7 +51,7 @@ jobs: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 + - uses: github/codeql-action/upload-sarif@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 if: ${{ success() || failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 6f0529db4..1aa540075 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,6 @@ jobs: results_format: sarif repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} publish_results: true - - uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 + - uses: github/codeql-action/upload-sarif@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 with: sarif_file: scorecards.sarif diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 4b7eb3e17..08e91b6ab 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -75,7 +75,7 @@ jobs: - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - - uses: github/codeql-action/init@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 + - uses: github/codeql-action/init@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 with: languages: cpp - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 @@ -83,4 +83,4 @@ jobs: configurePreset: "host" buildPreset: "host-Debug" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" - - uses: github/codeql-action/analyze@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 + - uses: github/codeql-action/analyze@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 From 3358e4532571eba37900e8e9c3ab216a199b6f0e Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Thu, 26 Oct 2023 10:58:56 +0200 Subject: [PATCH 24/37] build: only build and install protobuf echo compilers when EMIL_BUILD_ECHO_COMPILERS is set (#445) * build: only build and install protobuf echo compilers when EMIL_BUILD_ECHO_COMPILERS is set * protobuf/protoc_echo_plugin*/CMakeLists: Fix emil_build_for statement * Install export file, but only whene EMIL_BUILD_ECHO_COMPILERS --- CMakeLists.txt | 42 ++++++++----------- protobuf/protoc_echo_plugin/CMakeLists.txt | 4 +- .../protoc_echo_plugin_csharp/CMakeLists.txt | 4 +- .../protoc_echo_plugin_java/CMakeLists.txt | 4 +- services/echo_console/CMakeLists.txt | 2 +- 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a1aacd3..e80f35eb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,7 @@ option(EMIL_BUILD_TESTS "Enable building the tests" ${EMIL_DEFAULTOPT}) option(EMIL_BUILD_EXAMPLES "Enable building the examples" ${EMIL_DEFAULTOPT}) option(EMIL_ENABLE_FUZZING "Enable building the fuzzing targets" Off) option(EMIL_ENABLE_DOCKER_TOOLS "Enable shift-left tools (e.g. linters, formatters) that are run using Docker" On) -option(EMIL_GENERATE_PACKAGE_CONFIG "Enable generation of package configuration and install files" ${EMIL_HOST_BUILD}) +option(EMIL_BUILD_ECHO_COMPILERS "Build and install the Protobuf ECHO compilers" ${EMIL_DEFAULTOPT}) # Enable or disable optional features. option(EMIL_INCLUDE_MBEDTLS "Include MbedTLS as part of EmIL" On) @@ -148,18 +148,12 @@ if (EMIL_STANDALONE) emil_folderize_all_targets() endif() -if (EMIL_GENERATE_PACKAGE_CONFIG) +if (EMIL_BUILD_ECHO_COMPILERS) function(generate_export_targets name) - # Generate and install export file install(EXPORT emil${name}Targets FILE emil${name}Targets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/emil ) - - # Generate the export targets for the build tree - export(EXPORT emil${name}Targets - FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/emil${name}Targets.cmake" - ) endfunction() foreach(target IN ITEMS Protobuf) @@ -184,20 +178,20 @@ if (EMIL_GENERATE_PACKAGE_CONFIG) "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} ) - - set(CPACK_GENERATOR "ZIP;TGZ") - set(CPACK_SOURCE_IGNORE_FILES ".vs/;.git/;build/") - set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") - set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") - set(CPACK_PACKAGE_VENDOR "Koninklijke Philips N.V") - set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") - set(CPACK_DEBIAN_PACKAGE_NAME "${CPACK_PACKAGE_NAME}") - set(CPACK_RPM_PACKAGE_NAME "${CPACK_PACKAGE_NAME}") - set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}") - set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") - set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") - set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md") - set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") - - include(CPack) endif() + +set(CPACK_GENERATOR "ZIP;TGZ") +set(CPACK_SOURCE_IGNORE_FILES ".vs/;.git/;build/") +set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") +set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") +set(CPACK_PACKAGE_VENDOR "Koninklijke Philips N.V") +set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") +set(CPACK_DEBIAN_PACKAGE_NAME "${CPACK_PACKAGE_NAME}") +set(CPACK_RPM_PACKAGE_NAME "${CPACK_PACKAGE_NAME}") +set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}") +set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md") +set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") + +include(CPack) diff --git a/protobuf/protoc_echo_plugin/CMakeLists.txt b/protobuf/protoc_echo_plugin/CMakeLists.txt index c9f8b14e7..19fce22c6 100644 --- a/protobuf/protoc_echo_plugin/CMakeLists.txt +++ b/protobuf/protoc_echo_plugin/CMakeLists.txt @@ -26,8 +26,8 @@ if (EMIL_HOST_BUILD) if (NOT CMAKE_CROSSCOMPILING) add_executable(protobuf.protoc_echo_plugin) - emil_build_for(protobuf.protoc_echo_plugin BOOL EMIL_STANDALONE) - install(TARGETS protobuf.protoc_echo_plugin EXPORT emilProtobufTargets DESTINATION bin) + emil_build_for(protobuf.protoc_echo_plugin BOOL EMIL_BUILD_ECHO_COMPILERS) + emil_install(protobuf.protoc_echo_plugin EXPORT emilProtobufTargets DESTINATION bin) target_link_libraries(protobuf.protoc_echo_plugin PUBLIC protobuf.protoc_echo_plugin_lib diff --git a/protobuf/protoc_echo_plugin_csharp/CMakeLists.txt b/protobuf/protoc_echo_plugin_csharp/CMakeLists.txt index e4a223263..8e6ae63c8 100644 --- a/protobuf/protoc_echo_plugin_csharp/CMakeLists.txt +++ b/protobuf/protoc_echo_plugin_csharp/CMakeLists.txt @@ -1,7 +1,7 @@ if (EMIL_HOST_BUILD AND NOT CMAKE_CROSSCOMPILING) add_executable(protobuf.protoc_echo_plugin_csharp) - emil_build_for(protobuf.protoc_echo_plugin_csharp BOOL EMIL_STANDALONE) - install(TARGETS protobuf.protoc_echo_plugin_csharp EXPORT emilProtobufTargets DESTINATION bin) + emil_build_for(protobuf.protoc_echo_plugin_csharp BOOL EMIL_BUILD_ECHO_COMPILERS) + emil_install(protobuf.protoc_echo_plugin_csharp EXPORT emilProtobufTargets DESTINATION bin) target_link_libraries(protobuf.protoc_echo_plugin_csharp PUBLIC protobuf.protoc_echo_plugin_lib diff --git a/protobuf/protoc_echo_plugin_java/CMakeLists.txt b/protobuf/protoc_echo_plugin_java/CMakeLists.txt index 4e8182fc4..3d1ef6b4a 100644 --- a/protobuf/protoc_echo_plugin_java/CMakeLists.txt +++ b/protobuf/protoc_echo_plugin_java/CMakeLists.txt @@ -1,7 +1,7 @@ if (EMIL_HOST_BUILD AND NOT CMAKE_CROSSCOMPILING) add_executable(protobuf.protoc_echo_plugin_java) - emil_build_for(protobuf.protoc_echo_plugin_java BOOL EMIL_STANDALONE) - install(TARGETS protobuf.protoc_echo_plugin_java EXPORT emilProtobufTargets DESTINATION bin) + emil_build_for(protobuf.protoc_echo_plugin_java BOOL EMIL_BUILD_ECHO_COMPILERS) + emil_install(protobuf.protoc_echo_plugin_java EXPORT emilProtobufTargets DESTINATION bin) target_link_libraries(protobuf.protoc_echo_plugin_java PUBLIC protobuf.protoc_echo_plugin_lib diff --git a/services/echo_console/CMakeLists.txt b/services/echo_console/CMakeLists.txt index 843ecf8ef..43ba34bb1 100644 --- a/services/echo_console/CMakeLists.txt +++ b/services/echo_console/CMakeLists.txt @@ -1,6 +1,6 @@ if (EMIL_HOST_BUILD) add_executable(services.echo_console ${EMIL_EXCLUDE_FROM_ALL}) - emil_install(services.echo_console EXPORT emilProtobufTargets DESTINATION bin) + emil_install(services.echo_console DESTINATION bin) target_link_libraries(services.echo_console PUBLIC args From 40958dc7ed44ae9f132af19fe7237662eff8dad6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 10:50:46 +0100 Subject: [PATCH 25/37] build(deps): bump oxsecurity/megalinter from 7.4.0 to 7.5.0 (#446) Bumps [oxsecurity/megalinter](https://github.com/oxsecurity/megalinter) from 7.4.0 to 7.5.0. - [Release notes](https://github.com/oxsecurity/megalinter/releases) - [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md) - [Commits](https://github.com/oxsecurity/megalinter/compare/a87b2872713c6bdde46d2473c5d7ed23e5752dc2...b48455a119cc28045eee8f1e9d0a542a85e71f4f) --- updated-dependencies: - dependency-name: oxsecurity/megalinter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 276948ee5..759c80b73 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -46,7 +46,7 @@ jobs: with: fetch-depth: 0 persist-credentials: false - - uses: oxsecurity/megalinter@a87b2872713c6bdde46d2473c5d7ed23e5752dc2 # v7.4.0 + - uses: oxsecurity/megalinter@b48455a119cc28045eee8f1e9d0a542a85e71f4f # v7.5.0 env: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true From 049ff322322dc8cb293a0e3a6aaea77fdcecdd21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 10:57:44 +0100 Subject: [PATCH 26/37] build(deps): bump github/codeql-action from 2.22.4 to 2.22.5 (#447) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.4 to 2.22.5. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/49abf0ba24d0b7953cb586944e918a0b92074c80...74483a38d39275f33fcff5f35b679b5ca4a26a99) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index 759c80b73..7293c1151 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -51,7 +51,7 @@ jobs: APPLY_FIXES: all VALIDATE_ALL_CODEBASE: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: github/codeql-action/upload-sarif@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 + - uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 if: ${{ success() || failure() }} with: sarif_file: megalinter-reports/megalinter-report.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 1aa540075..c6e0973d5 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,6 @@ jobs: results_format: sarif repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} publish_results: true - - uses: github/codeql-action/upload-sarif@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 + - uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 with: sarif_file: scorecards.sarif diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 08e91b6ab..5c458a844 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -75,7 +75,7 @@ jobs: - uses: hendrikmuhs/ccache-action@6d1841ec156c39a52b1b23a810da917ab98da1f4 # v1.2.10 with: key: ${{ github.job }} - - uses: github/codeql-action/init@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 + - uses: github/codeql-action/init@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 with: languages: cpp - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 @@ -83,4 +83,4 @@ jobs: configurePreset: "host" buildPreset: "host-Debug" configurePresetAdditionalArgs: "['-DCMAKE_C_COMPILER_LAUNCHER=ccache', '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache']" - - uses: github/codeql-action/analyze@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 + - uses: github/codeql-action/analyze@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 From ec3a2f7c31b87098a28582671732eea8484e678c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:01:21 +0100 Subject: [PATCH 27/37] build(deps): bump Namchee/conventional-pr from 0.14.1 to 0.15.1 (#448) Bumps [Namchee/conventional-pr](https://github.com/namchee/conventional-pr) from 0.14.1 to 0.15.1. - [Release notes](https://github.com/namchee/conventional-pr/releases) - [Commits](https://github.com/namchee/conventional-pr/compare/cc86d488dd8f2c0d64386da3a6f4112f7475d25b...93f510707dd4ef011c5e8fe7c94c93c59fc86d4c) --- updated-dependencies: - dependency-name: Namchee/conventional-pr dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/validate-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index 459e7b1c1..d85172744 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -11,7 +11,7 @@ jobs: conventional_commit: runs-on: ubuntu-latest steps: - - uses: Namchee/conventional-pr@cc86d488dd8f2c0d64386da3a6f4112f7475d25b # v0.14.1 + - uses: Namchee/conventional-pr@93f510707dd4ef011c5e8fe7c94c93c59fc86d4c # v0.15.1 with: access_token: ${{ secrets.GITHUB_TOKEN }} body: false From 8d5b900a6af5659c35cb6d01bab3fcf1515a367f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:05:02 +0100 Subject: [PATCH 28/37] build(deps): bump carlosperate/arm-none-eabi-gcc-action from 1.7.1 to 1.8.0 (#449) build(deps): bump carlosperate/arm-none-eabi-gcc-action Bumps [carlosperate/arm-none-eabi-gcc-action](https://github.com/carlosperate/arm-none-eabi-gcc-action) from 1.7.1 to 1.8.0. - [Release notes](https://github.com/carlosperate/arm-none-eabi-gcc-action/releases) - [Changelog](https://github.com/carlosperate/arm-none-eabi-gcc-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/carlosperate/arm-none-eabi-gcc-action/compare/6a221d7c85f5b36647d6e9b25e874abf187409d3...e9cd61b92edb079b14b2d0449b21f8a517121fe8) --- updated-dependencies: - dependency-name: carlosperate/arm-none-eabi-gcc-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c19418cc..8a8a9a1b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,7 +86,7 @@ jobs: with: persist-credentials: false - name: Install GNU Arm Embedded Toolchain ${{ matrix.gcc }} - uses: carlosperate/arm-none-eabi-gcc-action@6a221d7c85f5b36647d6e9b25e874abf187409d3 # v1.7.1 + uses: carlosperate/arm-none-eabi-gcc-action@e9cd61b92edb079b14b2d0449b21f8a517121fe8 # v1.8.0 with: release: ${{ matrix.gcc }} - run: sudo apt-get update && sudo apt-get install ninja-build @@ -115,7 +115,7 @@ jobs: with: persist-credentials: false - name: Install GNU Arm Embedded Toolchain "10.3-2021.10" - uses: carlosperate/arm-none-eabi-gcc-action@6a221d7c85f5b36647d6e9b25e874abf187409d3 # v1.7.1 + uses: carlosperate/arm-none-eabi-gcc-action@e9cd61b92edb079b14b2d0449b21f8a517121fe8 # v1.8.0 with: release: "10.3-2021.10" - run: sudo apt-get update && sudo apt-get install ninja-build From 96eaba0e28a56623a4eb0cba72f86fde6c4b51a5 Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Thu, 2 Nov 2023 11:23:05 +0100 Subject: [PATCH 29/37] chore: add missing dependency: SynchronousSpiMasterWithChipSelect depends on hal::OutputPin from hal.interfaces (#451) --- services/synchronous_util/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/services/synchronous_util/CMakeLists.txt b/services/synchronous_util/CMakeLists.txt index 82b016dd9..9b131f510 100644 --- a/services/synchronous_util/CMakeLists.txt +++ b/services/synchronous_util/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(services.synchronous_util ${EMIL_EXCLUDE_FROM_ALL} STATIC) target_link_libraries(services.synchronous_util PUBLIC + hal.interfaces hal.synchronous_interfaces ) From cf204ee45dfe85ebb4fb6c11cbd050885af69090 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:10:34 +0100 Subject: [PATCH 30/37] build(deps): bump lukka/run-cmake from 10.6 to 10.7 (#452) Bumps [lukka/run-cmake](https://github.com/lukka/run-cmake) from 10.6 to 10.7. - [Release notes](https://github.com/lukka/run-cmake/releases) - [Commits](https://github.com/lukka/run-cmake/compare/c2b72aff009141774c5a5fabe74ea46c8c04d9c4...2ce8982be71b8e9a3c4d5e432135035afd1e76a7) --- updated-dependencies: - dependency-name: lukka/run-cmake dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/release-please.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a8a9a1b7..f80c57f90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: key: ${{ github.job }}-ubuntu-latest variant: sccache - uses: seanmiddleditch/gha-setup-ninja@8b297075da4cd2a5f1fd21fe011b499edf06e9d2 # v4 - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "host" buildPreset: "host-Debug-WithPackage" @@ -61,7 +61,7 @@ jobs: with: key: ${{ github.job }}-${{ matrix.os }} variant: sccache - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "host-single-Debug" buildPreset: "host-single-Debug" @@ -98,7 +98,7 @@ jobs: name: emil - run: tar -zxvf emil-*.tar.gz - run: mkdir install && mv emil-*/* install/ - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "embedded" buildPreset: "embedded-${{ matrix.configuration }}" @@ -127,7 +127,7 @@ jobs: name: emil - run: tar -zxvf emil-*.tar.gz - run: mkdir install && mv emil-*/* install/ - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "embedded-${{ matrix.rtos }}" buildPreset: "embedded-${{ matrix.rtos }}-RelWithDebInfo" diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 78a43de67..012d2c2f5 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -50,7 +50,7 @@ jobs: with: key: ${{ github.job }}-${{ matrix.os }} variant: sccache - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "host-single-MinSizeRel" buildPreset: "release-package" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 5c458a844..c2fcd0bc3 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -42,7 +42,7 @@ jobs: cmake --build --preset coverage GTEST_OUTPUT="xml:${PWD}/testresults/" ctest --preset coverage gcovr --sonarqube=coverage.xml --exclude-lines-by-pattern '.*assert\(.*\);|.*really_assert\(.*\);|.*std::abort();' --exclude-unreachable-branches --exclude-throw-branches -j "$(nproc)" --exclude=.*/generated/.* --exclude=.*/examples/.* --exclude=.*/external/.* --exclude=.*/lwip/.* --exclude=.*/tracing/.* --exclude=.*/test/.* - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "mutation-testing" buildPreset: "mutation-testing" @@ -78,7 +78,7 @@ jobs: - uses: github/codeql-action/init@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 with: languages: cpp - - uses: lukka/run-cmake@c2b72aff009141774c5a5fabe74ea46c8c04d9c4 # v10.6 + - uses: lukka/run-cmake@2ce8982be71b8e9a3c4d5e432135035afd1e76a7 # v10.7 with: configurePreset: "host" buildPreset: "host-Debug" From b2955b7b6aad224074254aa53fe3c06fe70a0557 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:30:49 +0100 Subject: [PATCH 31/37] build(deps): bump oss-fuzz-base/base-builder from `6c61e46` to `4dfa9f8` in /.clusterfuzzlite (#450) build(deps): bump oss-fuzz-base/base-builder in /.clusterfuzzlite Bumps oss-fuzz-base/base-builder from `6c61e46` to `4dfa9f8`. --- updated-dependencies: - dependency-name: oss-fuzz-base/base-builder dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .clusterfuzzlite/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile index 3d01d2e62..b72043be6 100644 --- a/.clusterfuzzlite/Dockerfile +++ b/.clusterfuzzlite/Dockerfile @@ -1,4 +1,4 @@ -FROM gcr.io/oss-fuzz-base/base-builder@sha256:6c61e467be42d10170ab0c4715d25805829e7c97aa60ce7b408687a02cd40c2d +FROM gcr.io/oss-fuzz-base/base-builder@sha256:4dfa9f84d5c677988a612f76eff68340d4a7dd61d2067468e1db1df72a447e2e RUN apt-get update && apt-get upgrade -y --no-install-recommends \ ninja-build \ From 13868631903ed05e49699d408639ae4dcd425fae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:31:11 +0100 Subject: [PATCH 32/37] build(deps): bump actions/dependency-review-action from 3.1.0 to 3.1.1 (#453) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/6c5ccdad469c9f8a2996bfecaec55a631a347034...9f45b2463b475767b61721ccfef113fef513e6aa) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-scanner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-scanner.yml b/.github/workflows/dependency-scanner.yml index f6936d907..eb2e20f57 100644 --- a/.github/workflows/dependency-scanner.yml +++ b/.github/workflows/dependency-scanner.yml @@ -26,6 +26,6 @@ jobs: pull-requests: write steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3.1.0 + - uses: actions/dependency-review-action@9f45b2463b475767b61721ccfef113fef513e6aa # v3.1.1 with: comment-summary-in-pr: true From 056254cb6012070a3869eba23de7e411f025c76c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:31:38 +0000 Subject: [PATCH 33/37] build(deps): bump google-github-actions/release-please-action from 3.7.12 to 3.7.13 (#454) build(deps): bump google-github-actions/release-please-action Bumps [google-github-actions/release-please-action](https://github.com/google-github-actions/release-please-action) from 3.7.12 to 3.7.13. - [Release notes](https://github.com/google-github-actions/release-please-action/releases) - [Changelog](https://github.com/google-github-actions/release-please-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/google-github-actions/release-please-action/compare/4c5670f886fe259db4d11222f7dff41c1382304d...db8f2c60ee802b3748b512940dde88eabd7b7e01) --- updated-dependencies: - dependency-name: google-github-actions/release-please-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 012d2c2f5..487fc0b51 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -26,7 +26,7 @@ jobs: app_id: ${{ secrets.FOREST_RELEASER_APP_ID }} app_base64_private_key: ${{ secrets.FOREST_RELEASER_APP_PRIVATE_KEY_BASE64 }} auth_type: installation - - uses: google-github-actions/release-please-action@4c5670f886fe259db4d11222f7dff41c1382304d # v3.7.12 + - uses: google-github-actions/release-please-action@db8f2c60ee802b3748b512940dde88eabd7b7e01 # v3.7.13 id: release with: command: manifest From 52da8ff4a56141984842cdb25c3352f00e7727e3 Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Tue, 7 Nov 2023 11:38:31 +0100 Subject: [PATCH 34/37] chore: make the generated com/philips/emil/protobufEcho directory consistent in case (#455) --- external/protoc/CMakeLists.txt | 2 +- protobuf/echo_attributes/EchoAttributes.proto | 2 +- services/network/Gap.proto | 2 +- services/network/Network.proto | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/external/protoc/CMakeLists.txt b/external/protoc/CMakeLists.txt index e95241f24..07c71cfd8 100644 --- a/external/protoc/CMakeLists.txt +++ b/external/protoc/CMakeLists.txt @@ -106,7 +106,7 @@ function(protocol_buffer_csharp target input) endfunction() function(protocol_buffer_java target input) - protocol_buffer_generator(TARGET ${target} INPUT ${input} GENERATOR java PATH_INFIX "/com/philips/emil/ProtobufEcho/" GENERATED_POSTFIXES Proto.java) + protocol_buffer_generator(TARGET ${target} INPUT ${input} GENERATOR java PATH_INFIX "/com/philips/emil/protobufEcho/" GENERATED_POSTFIXES Proto.java) endfunction() function(protocol_buffer_all target input) diff --git a/protobuf/echo_attributes/EchoAttributes.proto b/protobuf/echo_attributes/EchoAttributes.proto index 6e054e302..206d9acd7 100644 --- a/protobuf/echo_attributes/EchoAttributes.proto +++ b/protobuf/echo_attributes/EchoAttributes.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -option java_package = "com.philips.emil.ProtobufEcho"; +option java_package = "com.philips.emil.protobufEcho"; option java_outer_classname = "EchoAttributesProto"; import "google/protobuf/descriptor.proto"; diff --git a/services/network/Gap.proto b/services/network/Gap.proto index 4a8171ae2..4f658d32f 100644 --- a/services/network/Gap.proto +++ b/services/network/Gap.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package gap; -option java_package = "com.philips.emil.ProtobufEcho"; +option java_package = "com.philips.emil.protobufEcho"; option java_outer_classname = "GapProto"; message IoCapabilities diff --git a/services/network/Network.proto b/services/network/Network.proto index e00153fad..f8b515841 100644 --- a/services/network/Network.proto +++ b/services/network/Network.proto @@ -3,7 +3,7 @@ syntax = "proto3"; import "EchoAttributes.proto"; package network; -option java_package = "com.philips.emil.ProtobufEcho"; +option java_package = "com.philips.emil.protobufEcho"; option java_outer_classname = "NetworkProto"; message IpConfig From 2b0fa881511f6f012ba17af621ab39cd8eec129e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:41:35 +0100 Subject: [PATCH 35/37] build(deps): bump actions/dependency-review-action from 3.1.1 to 3.1.2 (#456) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/9f45b2463b475767b61721ccfef113fef513e6aa...fde92acd0840415674c16b39c7d703fc28bc511e) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-scanner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-scanner.yml b/.github/workflows/dependency-scanner.yml index eb2e20f57..010d09a2a 100644 --- a/.github/workflows/dependency-scanner.yml +++ b/.github/workflows/dependency-scanner.yml @@ -26,6 +26,6 @@ jobs: pull-requests: write steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/dependency-review-action@9f45b2463b475767b61721ccfef113fef513e6aa # v3.1.1 + - uses: actions/dependency-review-action@fde92acd0840415674c16b39c7d703fc28bc511e # v3.1.2 with: comment-summary-in-pr: true From 07756bb41f068adbf3a2eb76adb2778fff5491f0 Mon Sep 17 00:00:00 2001 From: Richard Peters Date: Thu, 9 Nov 2023 14:20:00 +0100 Subject: [PATCH 36/37] feat: support streaming echo messages (#435) * First step streaming echo * Step two implementing streaming Echo, adjust tests * protobuf/echo/Echo: Release proxy after writing all data * protobuf/echo/ProtoMessageSender: Use the error policy of output in ProtoMessageSenderBase::Fill * services/util/EchoOnMessageCommunicationSymmetricKey: Delay setting key until current stream is released * Implement protobuf/echo/ServiceForwarder * Apply clang-format * ProtoCEchoPlugin: Make serviceId, id, and maxMessageSize constexpr * Implement TracngEchoOnConnection * Update services/network/TracingEchoOnConnection.hpp * Apply Sonar review comments * protobuf/echo/Echo: Introduce MethodDeserializerFactory * protobuf/echo/Echo.hpp: Extract EchoErrorPolicy and Serialization * Add MethodDeserializerFactory::ForServices * protobuf/echo/Serialization: Extract structs with partial specializations outside of the ForServices class * protobuf/echo/Serialization: Fix compilation for GCC * protobuf/echo/test_doubles/ServiceStub: Fix compilation for GCC * protobuf/protoc_echo_plugin/ProtoCEchoPlugin: Fix compilation for GCC * protobuf/echo/Serialization: Fix compilation for GCC * protobuf/echo/Serialization: Replace MakeSharedOnHeap with deserializerFactory.MakeDummyDeserializer * protobuf/echo/Echo: Remove ServiceProxyResponseQueue * protobuf/echo/Serialization: Replace MakeSharedOnHeap with serializerFactory.MakeSerializer * protobuf/echo/Serialization: Fix declaration order * build: only build and install protobuf echo compilers when EMIL_BUILD_ECHO_COMPILERS is set * protobuf/protoc_echo_plugin*/CMakeLists: Fix emil_build_for statement * Install export file, but only whene EMIL_BUILD_ECHO_COMPILERS * Resolve Sonar warnings * Stream empty parameters * protobuf/echo/Echo: Move MethodSerializerFactory to Echo * Update protobuf/echo/Serialization.hpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * services/util/EchoInstantiation: Add MethodSerializationFactory * protobuf/echo/Echo: Reserve size for service and method id * protobuf/echo/EchoErrorPolicy: Make destructor virtual * Apply review comments --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- examples/rpc/Server.cpp | 8 +- infra/stream/BufferingStreamReader.cpp | 4 +- infra/stream/LimitedInputStream.cpp | 30 +- infra/stream/LimitedInputStream.hpp | 4 +- infra/stream/OutputStream.hpp | 5 + infra/syntax/ProtoParser.cpp | 7 +- protobuf/echo/CMakeLists.txt | 4 + protobuf/echo/Echo.cpp | 214 ++++++----- protobuf/echo/Echo.hpp | 172 +++------ protobuf/echo/EchoErrorPolicy.cpp | 28 ++ protobuf/echo/EchoErrorPolicy.hpp | 47 +++ protobuf/echo/Proto.hpp | 5 +- protobuf/echo/ProtoMessageReceiver.cpp | 8 + protobuf/echo/ProtoMessageReceiver.hpp | 2 + protobuf/echo/ProtoMessageSender.cpp | 2 +- protobuf/echo/Serialization.cpp | 64 ++++ protobuf/echo/Serialization.hpp | 347 ++++++++++++++++++ protobuf/echo/ServiceForwarder.cpp | 96 +++-- protobuf/echo/ServiceForwarder.hpp | 40 +- protobuf/echo/test/CMakeLists.txt | 1 - .../test/TestEchoServiceResponseQueue.cpp | 66 ---- protobuf/echo/test/TestMessages.proto | 9 +- protobuf/echo/test/TestServiceForwarder.cpp | 28 +- protobuf/echo/test_doubles/EchoMock.hpp | 21 +- .../echo/test_doubles/EchoSingleLoopback.cpp | 14 +- .../echo/test_doubles/EchoSingleLoopback.hpp | 4 +- protobuf/echo/test_doubles/ServiceStub.cpp | 78 ++-- protobuf/echo/test_doubles/ServiceStub.hpp | 51 ++- .../protoc_echo_plugin/ProtoCEchoPlugin.cpp | 167 ++++++--- .../protoc_echo_plugin/ProtoCEchoPlugin.hpp | 5 +- services/ble/test/TestGapCentral.cpp | 3 +- services/network/EchoOnConnection.cpp | 19 +- services/network/EchoOnConnection.hpp | 2 +- services/network/TracingEchoOnConnection.cpp | 98 +++-- services/network/TracingEchoOnConnection.hpp | 30 +- services/network/test/CMakeLists.txt | 22 +- .../network/test/TestEchoOnConnection.cpp | 112 +++--- services/util/EchoInstantiation.hpp | 11 +- services/util/EchoOnMessageCommunication.cpp | 30 +- services/util/EchoOnMessageCommunication.hpp | 10 +- ...EchoOnMessageCommunicationSymmetricKey.cpp | 6 +- ...EchoOnMessageCommunicationSymmetricKey.hpp | 2 +- services/util/MessageCommunicationSecured.cpp | 23 +- services/util/MessageCommunicationSecured.hpp | 5 +- .../test/TestEchoOnMessageCommunication.cpp | 60 ++- ...EchoOnMessageCommunicationSymmetricKey.cpp | 4 +- .../test/TestMessageCommunicationSecured.cpp | 6 +- 47 files changed, 1296 insertions(+), 678 deletions(-) create mode 100644 protobuf/echo/EchoErrorPolicy.cpp create mode 100644 protobuf/echo/EchoErrorPolicy.hpp create mode 100644 protobuf/echo/Serialization.cpp create mode 100644 protobuf/echo/Serialization.hpp delete mode 100644 protobuf/echo/test/TestEchoServiceResponseQueue.cpp diff --git a/examples/rpc/Server.cpp b/examples/rpc/Server.cpp index 6e8f6ac32..c960da908 100644 --- a/examples/rpc/Server.cpp +++ b/examples/rpc/Server.cpp @@ -23,8 +23,9 @@ class EchoConnection : public services::EchoOnConnection { public: - EchoConnection() - : console(*this) + EchoConnection(services::MethodSerializerFactory& serializerFactory) + : services::EchoOnConnection(serializerFactory) + , console(*this) {} private: @@ -45,12 +46,13 @@ class RpcServer connection->::services::ConnectionObserver::Subject().AbortAndDestroy(); if (connection.Allocatable()) - createdObserver(connection.Emplace()); + createdObserver(connection.Emplace(serializerFactory)); } private: infra::SharedPtr listener; infra::SharedOptional connection; + services::MethodSerializerFactory::OnHeap serializerFactory; }; int main(int argc, const char* argv[], const char* env[]) diff --git a/infra/stream/BufferingStreamReader.cpp b/infra/stream/BufferingStreamReader.cpp index a2c2289ce..53c32f5ed 100644 --- a/infra/stream/BufferingStreamReader.cpp +++ b/infra/stream/BufferingStreamReader.cpp @@ -48,7 +48,9 @@ namespace infra return from; } - return input.ExtractContiguousRange(max); + auto result = input.ExtractContiguousRange(max); + index += result.size(); + return result; } infra::ConstByteRange BufferingStreamReader::PeekContiguousRange(std::size_t start) diff --git a/infra/stream/LimitedInputStream.cpp b/infra/stream/LimitedInputStream.cpp index 3fe3bba94..dd0f6cb56 100644 --- a/infra/stream/LimitedInputStream.cpp +++ b/infra/stream/LimitedInputStream.cpp @@ -58,7 +58,7 @@ namespace infra } LimitedStreamReaderWithRewinding::LimitedStreamReaderWithRewinding(StreamReaderWithRewinding& input, uint32_t length) - : input(input) + : input(&input) , length(length) {} @@ -72,12 +72,22 @@ namespace infra length = newLength; } + bool LimitedStreamReaderWithRewinding::LimitReached() const + { + return length == 0; + } + + void LimitedStreamReaderWithRewinding::SwitchInput(StreamReaderWithRewinding& newInput) + { + this->input = &newInput; + } + void LimitedStreamReaderWithRewinding::Extract(ByteRange range, StreamErrorPolicy& errorPolicy) { errorPolicy.ReportResult(length >= range.size()); range.shrink_from_back_to(length); length -= range.size(); - input.Extract(range, errorPolicy); + input->Extract(range, errorPolicy); } uint8_t LimitedStreamReaderWithRewinding::Peek(StreamErrorPolicy& errorPolicy) @@ -85,42 +95,42 @@ namespace infra errorPolicy.ReportResult(length != 0); if (length != 0) - return input.Peek(errorPolicy); + return input->Peek(errorPolicy); else return 0; } ConstByteRange LimitedStreamReaderWithRewinding::ExtractContiguousRange(std::size_t max) { - ConstByteRange result = input.ExtractContiguousRange(std::min(length, max)); + ConstByteRange result = input->ExtractContiguousRange(std::min(length, max)); length -= result.size(); return result; } ConstByteRange infra::LimitedStreamReaderWithRewinding::PeekContiguousRange(std::size_t start) { - return input.PeekContiguousRange(start); + return input->PeekContiguousRange(start); } bool LimitedStreamReaderWithRewinding::Empty() const { - return length == 0 || input.Empty(); + return length == 0 || input->Empty(); } std::size_t LimitedStreamReaderWithRewinding::Available() const { - return std::min(length, input.Available()); + return std::min(length, input->Available()); } std::size_t LimitedStreamReaderWithRewinding::ConstructSaveMarker() const { - return input.ConstructSaveMarker(); + return input->ConstructSaveMarker(); } void LimitedStreamReaderWithRewinding::Rewind(std::size_t marker) { - auto now = input.ConstructSaveMarker(); - input.Rewind(marker); + auto now = input->ConstructSaveMarker(); + input->Rewind(marker); length += now - marker; } diff --git a/infra/stream/LimitedInputStream.hpp b/infra/stream/LimitedInputStream.hpp index 2a170b6cf..66e6ecf77 100644 --- a/infra/stream/LimitedInputStream.hpp +++ b/infra/stream/LimitedInputStream.hpp @@ -44,6 +44,8 @@ namespace infra ~LimitedStreamReaderWithRewinding() = default; void ResetLength(uint32_t newLength); + bool LimitReached() const; + void SwitchInput(StreamReaderWithRewinding& newInput); public: void Extract(ByteRange range, StreamErrorPolicy& errorPolicy) override; @@ -56,7 +58,7 @@ namespace infra void Rewind(std::size_t marker) override; private: - StreamReaderWithRewinding& input; + StreamReaderWithRewinding* input; uint32_t length; }; diff --git a/infra/stream/OutputStream.hpp b/infra/stream/OutputStream.hpp index a0fe2702f..ed15456f1 100644 --- a/infra/stream/OutputStream.hpp +++ b/infra/stream/OutputStream.hpp @@ -27,6 +27,11 @@ namespace infra virtual void Insert(ConstByteRange range, StreamErrorPolicy& errorPolicy) = 0; virtual std::size_t Available() const = 0; + bool Empty() const + { + return Available() == 0; + } + virtual std::size_t ConstructSaveMarker() const; virtual std::size_t GetProcessedBytesSince(std::size_t marker) const; virtual infra::ByteRange SaveState(std::size_t marker); diff --git a/infra/syntax/ProtoParser.cpp b/infra/syntax/ProtoParser.cpp index 8b5e09fb5..445b84466 100644 --- a/infra/syntax/ProtoParser.cpp +++ b/infra/syntax/ProtoParser.cpp @@ -90,6 +90,7 @@ namespace infra uint64_t result = 0; uint8_t byte = 0; uint8_t shift = 0; + uint8_t index = 0; do { @@ -97,7 +98,11 @@ namespace infra result += static_cast(byte & 0x7f) << shift; shift += 7; - } while (!input.Failed() && (byte & 0x80) != 0); + ++index; + } while (!input.Failed() && (byte & 0x80) != 0 && index != 10); + + if (!input.Failed() && (byte & 0x80) != 0 && index == 10) + formatErrorPolicy.Failed(); return result; } diff --git a/protobuf/echo/CMakeLists.txt b/protobuf/echo/CMakeLists.txt index 3f459aaeb..6f345eece 100644 --- a/protobuf/echo/CMakeLists.txt +++ b/protobuf/echo/CMakeLists.txt @@ -8,11 +8,15 @@ target_link_libraries(protobuf.echo PUBLIC target_sources(protobuf.echo PRIVATE Echo.cpp Echo.hpp + EchoErrorPolicy.cpp + EchoErrorPolicy.hpp Proto.hpp ProtoMessageReceiver.cpp ProtoMessageReceiver.hpp ProtoMessageSender.cpp ProtoMessageSender.hpp + Serialization.cpp + Serialization.hpp ServiceForwarder.cpp ServiceForwarder.hpp TracingEcho.cpp diff --git a/protobuf/echo/Echo.cpp b/protobuf/echo/Echo.cpp index 2f357edfe..9f5ce4644 100644 --- a/protobuf/echo/Echo.cpp +++ b/protobuf/echo/Echo.cpp @@ -1,26 +1,10 @@ #include "protobuf/echo/Echo.hpp" -#include "infra/event/EventDispatcherWithWeakPtr.hpp" namespace services { - EchoErrorPolicyAbortOnMessageFormatError echoErrorPolicyAbortOnMessageFormatError; - EchoErrorPolicyAbort echoErrorPolicyAbort; - void Service::MethodDone() { - inProgress = false; - Rpc().ServiceDone(*this); - } - - bool Service::InProgress() const - { - return inProgress; - } - - void Service::HandleMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, EchoErrorPolicy& errorPolicy) - { - inProgress = true; - Handle(serviceId, methodId, contents, errorPolicy); + Rpc().ServiceDone(); } Echo& Service::Rpc() @@ -50,9 +34,10 @@ namespace services echo.RequestSend(*this); } - void ServiceProxy::GrantSend() + infra::SharedPtr ServiceProxy::GrantSend() { onGranted(); + return methodSerializer; } uint32_t ServiceProxy::MaxMessageSize() const @@ -65,79 +50,152 @@ namespace services return currentRequestedSize; } - void EchoErrorPolicyAbortOnMessageFormatError::MessageFormatError() + void ServiceProxy::SetSerializer(const infra::SharedPtr& serializer) { - std::abort(); + methodSerializer = serializer; } - void EchoErrorPolicyAbortOnMessageFormatError::ServiceNotFound(uint32_t serviceId) + EchoOnStreams::EchoOnStreams(services::MethodSerializerFactory& serializerFactory, const EchoErrorPolicy& errorPolicy) + : serializerFactory(serializerFactory) + , errorPolicy(errorPolicy) {} - void EchoErrorPolicyAbortOnMessageFormatError::MethodNotFound(uint32_t serviceId, uint32_t methodId) - {} + EchoOnStreams::~EchoOnStreams() + { + readerAccess.SetAction(nullptr); + } - void EchoErrorPolicyAbort::ServiceNotFound(uint32_t serviceId) + void EchoOnStreams::RequestSend(ServiceProxy& serviceProxy) { - std::abort(); + sendRequesters.push_back(serviceProxy); + + TryGrantSend(); } - void EchoErrorPolicyAbort::MethodNotFound(uint32_t serviceId, uint32_t methodId) + void EchoOnStreams::ServiceDone() { - std::abort(); + methodDeserializer = nullptr; + + if (readerPtr != nullptr) + DataReceived(); } - EchoOnStreams::EchoOnStreams(EchoErrorPolicy& errorPolicy) - : errorPolicy(errorPolicy) - {} + services::MethodSerializerFactory& EchoOnStreams::SerializerFactory() + { + return serializerFactory; + } - void EchoOnStreams::RequestSend(ServiceProxy& serviceProxy) + void EchoOnStreams::DataReceived(infra::SharedPtr&& reader) { - if (sendRequesters.empty() && streamWriter == nullptr) + assert(readerPtr == nullptr); + readerPtr = std::move(reader); + bufferedReader.Emplace(receiveBuffer, *readerPtr); + DataReceived(); + } + + void EchoOnStreams::TryGrantSend() + { + if (sendingProxy == nullptr && !sendRequesters.empty()) { - sendRequesters.push_back(serviceProxy); - RequestSendStream(serviceProxy.CurrentRequestedSize()); + sendingProxy = &sendRequesters.front(); + sendRequesters.pop_front(); + RequestSendStream(sendingProxy->CurrentRequestedSize() + 2 * infra::MaxVarIntSize(std::numeric_limits::max())); } - else - sendRequesters.push_back(serviceProxy); } - infra::StreamWriter& EchoOnStreams::SendStreamWriter() + infra::SharedPtr EchoOnStreams::GrantSend(ServiceProxy& proxy) { - return *streamWriter; + return proxy.GrantSend(); } - void EchoOnStreams::Send() + infra::SharedPtr EchoOnStreams::StartingMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const infra::SharedPtr& deserializer) { - streamWriter = nullptr; + return deserializer; + } - if (!sendRequesters.empty()) - RequestSendStream(sendRequesters.front().CurrentRequestedSize()); + void EchoOnStreams::SendStreamAvailable(infra::SharedPtr&& writer) + { + if (methodSerializer == nullptr) + methodSerializer = GrantSend(*sendingProxy); + + auto more = methodSerializer->Serialize(std::move(writer)); + + if (more) + RequestSendStream(sendingProxy->CurrentRequestedSize()); + else + { + sendingProxy = nullptr; + methodSerializer->SerializationDone(); + methodSerializer = nullptr; + TryGrantSend(); + } } - void EchoOnStreams::ServiceDone(Service& service) + void EchoOnStreams::DataReceived() { - if (serviceBusy && service.AcceptsService(*serviceBusy)) + while (readerPtr != nullptr && methodDeserializer == nullptr && !readerAccess.Referenced()) { - serviceBusy = infra::none; - infra::EventDispatcherWithWeakPtr::Instance().Schedule([](infra::SharedPtr echo) - { - echo->BusyServiceDone(); - }, - SharedFromThis()); + if (limitedReader == infra::none) + StartReceiveMessage(); + + if (limitedReader != infra::none) + ContinueReceiveMessage(); + } + } + + void EchoOnStreams::StartReceiveMessage() + { + auto start = bufferedReader->ConstructSaveMarker(); + infra::DataInputStream::WithErrorPolicy stream(*bufferedReader, infra::softFail); + infra::StreamErrorPolicy formatErrorPolicy(infra::softFail); + infra::ProtoParser parser(stream, formatErrorPolicy); + uint32_t serviceId = static_cast(parser.GetVarInt()); + auto [contents, methodId] = parser.GetPartialField(); + + if (stream.Failed()) + { + bufferedReader->Rewind(start); + bufferedReader = infra::none; + readerPtr = nullptr; + } + else if (formatErrorPolicy.Failed() || !contents.Is()) + { + errorPolicy.MessageFormatError(); + AckReceived(); + } + else + { + limitedReader.Emplace(*bufferedReader, contents.Get().length); + StartMethod(serviceId, methodId, contents.Get().length); + + if (formatErrorPolicy.Failed()) + errorPolicy.MessageFormatError(); } } - void EchoOnStreams::ExecuteMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, infra::StreamReaderWithRewinding& reader) + void EchoOnStreams::ContinueReceiveMessage() { - if (!NotifyObservers([this, serviceId, methodId, &contents](auto& service) + limitedReader->SwitchInput(*bufferedReader); + readerAccess.SetAction(infra::emptyFunction); + methodDeserializer->MethodContents(readerAccess.MakeShared(*limitedReader)); + + if (readerAccess.Referenced()) + readerAccess.SetAction([this]() + { + ReaderDone(); + DataReceived(); + }); + else + ReaderDone(); + } + + void EchoOnStreams::StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size) + { + if (!NotifyObservers([this, serviceId, methodId, size](auto& service) { if (service.AcceptsService(serviceId)) { - if (service.InProgress()) - serviceBusy = serviceId; - else - service.HandleMethod(serviceId, methodId, contents, errorPolicy); - + methodDeserializer = StartingMethod(serviceId, methodId, size, service.StartMethod(serviceId, methodId, size, errorPolicy)); return true; } @@ -145,44 +203,24 @@ namespace services })) { errorPolicy.ServiceNotFound(serviceId); - contents.SkipEverything(); + methodDeserializer = deserializerDummy.Emplace(*this); } } - void EchoOnStreams::SetStreamWriter(infra::SharedPtr&& writer) + void EchoOnStreams::ReaderDone() { - streamWriter = std::move(writer); + AckReceived(); - ServiceProxy& proxy = sendRequesters.front(); - sendRequesters.pop_front(); - proxy.GrantSend(); - } - - bool EchoOnStreams::ServiceBusy() const - { - return serviceBusy != infra::none; - } - - bool EchoOnStreams::ProcessMessage(infra::StreamReaderWithRewinding& reader) - { - infra::DataInputStream::WithErrorPolicy stream(reader, infra::softFail); - infra::StreamErrorPolicy formatErrorPolicy(infra::softFail); - infra::ProtoParser parser(stream, formatErrorPolicy); - uint32_t serviceId = static_cast(parser.GetVarInt()); - infra::ProtoParser::Field message = parser.GetField(); - if (stream.Failed()) - return false; - - if (formatErrorPolicy.Failed() || !message.first.Is()) - errorPolicy.MessageFormatError(); - else + if (limitedReader->LimitReached()) { - ExecuteMethod(serviceId, message.second, message.first.Get(), reader); - - if (stream.Failed() || formatErrorPolicy.Failed()) + limitedReader = infra::none; + if (methodDeserializer->Failed()) + { errorPolicy.MessageFormatError(); + methodDeserializer = nullptr; + } + else + methodDeserializer->ExecuteMethod(); } - - return true; } } diff --git a/protobuf/echo/Echo.hpp b/protobuf/echo/Echo.hpp index 96a5e6a1d..7015841c9 100644 --- a/protobuf/echo/Echo.hpp +++ b/protobuf/echo/Echo.hpp @@ -1,12 +1,15 @@ #ifndef PROTOBUF_ECHO_HPP #define PROTOBUF_ECHO_HPP +#include "infra/stream/BufferingStreamReader.hpp" #include "infra/util/BoundedDeque.hpp" #include "infra/util/Compatibility.hpp" #include "infra/util/Function.hpp" +#include "infra/util/Observer.hpp" #include "infra/util/Optional.hpp" +#include "protobuf/echo/EchoErrorPolicy.hpp" #include "protobuf/echo/Proto.hpp" -#include "services/util/MessageCommunication.hpp" +#include "protobuf/echo/Serialization.hpp" namespace services { @@ -14,37 +17,6 @@ namespace services class Service; class ServiceProxy; - class EchoErrorPolicy - { - protected: - ~EchoErrorPolicy() = default; - - public: - virtual void MessageFormatError() = 0; - virtual void ServiceNotFound(uint32_t serviceId) = 0; - virtual void MethodNotFound(uint32_t serviceId, uint32_t methodId) = 0; - }; - - class EchoErrorPolicyAbortOnMessageFormatError - : public EchoErrorPolicy - { - public: - void MessageFormatError() override; - void ServiceNotFound(uint32_t serviceId) override; - void MethodNotFound(uint32_t serviceId, uint32_t methodId) override; - }; - - class EchoErrorPolicyAbort - : public EchoErrorPolicyAbortOnMessageFormatError - { - public: - void ServiceNotFound(uint32_t serviceId) override; - void MethodNotFound(uint32_t serviceId, uint32_t methodId) override; - }; - - extern EchoErrorPolicyAbortOnMessageFormatError echoErrorPolicyAbortOnMessageFormatError; - extern EchoErrorPolicyAbort echoErrorPolicyAbort; - class Service : public infra::Observer { @@ -54,25 +26,10 @@ namespace services virtual bool AcceptsService(uint32_t id) const = 0; void MethodDone(); - bool InProgress() const; - void HandleMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, EchoErrorPolicy& errorPolicy); + virtual infra::SharedPtr StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const EchoErrorPolicy& errorPolicy) = 0; protected: Echo& Rpc(); - virtual void Handle(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, EchoErrorPolicy& errorPolicy) = 0; - - private: - bool inProgress = false; - }; - - class Echo - : public infra::Subject - { - public: - virtual void RequestSend(ServiceProxy& serviceProxy) = 0; - virtual infra::StreamWriter& SendStreamWriter() = 0; - virtual void Send() = 0; - virtual void ServiceDone(Service& service) = 0; }; class ServiceProxy @@ -84,46 +41,26 @@ namespace services Echo& Rpc(); virtual void RequestSend(infra::Function onGranted); virtual void RequestSend(infra::Function onGranted, uint32_t requestedSize); - void GrantSend(); + virtual infra::SharedPtr GrantSend(); uint32_t MaxMessageSize() const; uint32_t CurrentRequestedSize() const; + void SetSerializer(const infra::SharedPtr& serializer); private: Echo& echo; uint32_t maxMessageSize; infra::Function onGranted; uint32_t currentRequestedSize = 0; + infra::SharedPtr methodSerializer; }; - template - class ServiceProxyResponseQueue - : public ServiceProxyType + class Echo + : public infra::Subject { public: - struct Request - { - infra::Function onRequestGranted; - uint32_t requestedSize; - }; - - using Container = infra::BoundedDeque; - - template - using WithStorage = infra::WithStorage>; - - template - explicit ServiceProxyResponseQueue(Container& container, Args&&... args); - - void RequestSend(infra::Function onRequestGranted) override; - void RequestSend(infra::Function onRequestGranted, uint32_t requestedSize) override; - - private: - void ProcessSendQueue(); - - private: - Container& container; - - bool responseInProgress{ false }; + virtual void RequestSend(ServiceProxy& serviceProxy) = 0; + virtual void ServiceDone() = 0; + virtual services::MethodSerializerFactory& SerializerFactory() = 0; }; class EchoOnStreams @@ -131,74 +68,49 @@ namespace services , public infra::EnableSharedFromThis { public: - explicit EchoOnStreams(EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); + explicit EchoOnStreams(services::MethodSerializerFactory& serializerFactory, const EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); + ~EchoOnStreams() override; // Implementation of Echo void RequestSend(ServiceProxy& serviceProxy) override; - infra::StreamWriter& SendStreamWriter() override; - void Send() override; - void ServiceDone(Service& service) override; + void ServiceDone() override; + services::MethodSerializerFactory& SerializerFactory() override; protected: + virtual infra::SharedPtr GrantSend(ServiceProxy& proxy); + virtual infra::SharedPtr StartingMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const infra::SharedPtr& deserializer); virtual void RequestSendStream(std::size_t size) = 0; - virtual void BusyServiceDone() = 0; + virtual void AckReceived() = 0; - virtual void ExecuteMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, infra::StreamReaderWithRewinding& reader); - virtual void SetStreamWriter(infra::SharedPtr&& writer); - bool ServiceBusy() const; - bool ProcessMessage(infra::StreamReaderWithRewinding& reader); - - protected: - EchoErrorPolicy& errorPolicy; + void SendStreamAvailable(infra::SharedPtr&& writer); + void DataReceived(infra::SharedPtr&& reader); private: - infra::SharedPtr streamWriter; - infra::IntrusiveList sendRequesters; - infra::Optional serviceBusy; - }; - - //// Implementation //// + void TryGrantSend(); - template - template - ServiceProxyResponseQueue::ServiceProxyResponseQueue(Container& container, Args&&... args) - : ServiceProxyType{ std::forward(args)... } - , container{ container } - {} + void DataReceived(); + void StartReceiveMessage(); + void ContinueReceiveMessage(); + void StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size); + void ReaderDone(); - template - void ServiceProxyResponseQueue::RequestSend(infra::Function onRequestGranted) - { - RequestSend(onRequestGranted, ServiceProxyType::MaxMessageSize()); - } + private: + services::MethodSerializerFactory& serializerFactory; + const EchoErrorPolicy& errorPolicy; - template - void ServiceProxyResponseQueue::RequestSend(infra::Function onRequestGranted, uint32_t requestedSize) - { - if (container.full()) - return; + infra::IntrusiveList sendRequesters; + ServiceProxy* sendingProxy = nullptr; + infra::SharedPtr methodSerializer; - container.push_back({ onRequestGranted, requestedSize }); - ProcessSendQueue(); - } + infra::SharedPtr readerPtr; + infra::Optional limitedReader; + infra::SharedPtr methodDeserializer; + infra::BoundedDeque::WithMaxSize<32> receiveBuffer; + infra::Optional bufferedReader; + infra::AccessedBySharedPtr readerAccess; - template - void ServiceProxyResponseQueue::ProcessSendQueue() - { - if (!responseInProgress && !container.empty()) - { - responseInProgress = true; - ServiceProxyType::RequestSend([this] - { - container.front().onRequestGranted(); - container.pop_front(); - - responseInProgress = false; - ProcessSendQueue(); - }, - container.front().requestedSize); - } - } + infra::SharedOptional deserializerDummy; + }; } #endif diff --git a/protobuf/echo/EchoErrorPolicy.cpp b/protobuf/echo/EchoErrorPolicy.cpp new file mode 100644 index 000000000..985c2e754 --- /dev/null +++ b/protobuf/echo/EchoErrorPolicy.cpp @@ -0,0 +1,28 @@ +#include "protobuf/echo/EchoErrorPolicy.hpp" + +namespace services +{ + const EchoErrorPolicyAbortOnMessageFormatError echoErrorPolicyAbortOnMessageFormatError; + const EchoErrorPolicyAbort echoErrorPolicyAbort; + + void EchoErrorPolicyAbortOnMessageFormatError::MessageFormatError() const + { + std::abort(); + } + + void EchoErrorPolicyAbortOnMessageFormatError::ServiceNotFound(uint32_t serviceId) const + {} + + void EchoErrorPolicyAbortOnMessageFormatError::MethodNotFound(uint32_t serviceId, uint32_t methodId) const + {} + + void EchoErrorPolicyAbort::ServiceNotFound(uint32_t serviceId) const + { + std::abort(); + } + + void EchoErrorPolicyAbort::MethodNotFound(uint32_t serviceId, uint32_t methodId) const + { + std::abort(); + } +} diff --git a/protobuf/echo/EchoErrorPolicy.hpp b/protobuf/echo/EchoErrorPolicy.hpp new file mode 100644 index 000000000..73af320f2 --- /dev/null +++ b/protobuf/echo/EchoErrorPolicy.hpp @@ -0,0 +1,47 @@ +#ifndef PROTOBUF_ECHO_ERROR_POLICY_HPP +#define PROTOBUF_ECHO_ERROR_POLICY_HPP + +#include "infra/stream/BufferingStreamReader.hpp" +#include "infra/util/BoundedDeque.hpp" +#include "infra/util/Compatibility.hpp" +#include "infra/util/Function.hpp" +#include "infra/util/Observer.hpp" +#include "infra/util/Optional.hpp" +#include "protobuf/echo/Proto.hpp" +#include "protobuf/echo/Serialization.hpp" + +namespace services +{ + class EchoErrorPolicy + { + protected: + virtual ~EchoErrorPolicy() = default; + + public: + virtual void MessageFormatError() const = 0; + virtual void ServiceNotFound(uint32_t serviceId) const = 0; + virtual void MethodNotFound(uint32_t serviceId, uint32_t methodId) const = 0; + }; + + class EchoErrorPolicyAbortOnMessageFormatError + : public EchoErrorPolicy + { + public: + void MessageFormatError() const override; + void ServiceNotFound(uint32_t serviceId) const override; + void MethodNotFound(uint32_t serviceId, uint32_t methodId) const override; + }; + + class EchoErrorPolicyAbort + : public EchoErrorPolicyAbortOnMessageFormatError + { + public: + void ServiceNotFound(uint32_t serviceId) const override; + void MethodNotFound(uint32_t serviceId, uint32_t methodId) const override; + }; + + extern const EchoErrorPolicyAbortOnMessageFormatError echoErrorPolicyAbortOnMessageFormatError; + extern const EchoErrorPolicyAbort echoErrorPolicyAbort; +} + +#endif diff --git a/protobuf/echo/Proto.hpp b/protobuf/echo/Proto.hpp index 3fb0ae479..b52204c66 100644 --- a/protobuf/echo/Proto.hpp +++ b/protobuf/echo/Proto.hpp @@ -188,7 +188,10 @@ namespace services }; template - struct Max; + struct Max + { + static constexpr uint32_t value = 0; + }; template struct Max diff --git a/protobuf/echo/ProtoMessageReceiver.cpp b/protobuf/echo/ProtoMessageReceiver.cpp index 1c2e14a9e..47d31ad08 100644 --- a/protobuf/echo/ProtoMessageReceiver.cpp +++ b/protobuf/echo/ProtoMessageReceiver.cpp @@ -22,7 +22,10 @@ namespace services current.second(stream); if (stream.Failed() || reader.Empty()) + { + failed = stream.Failed(); break; + } if (¤t != &stack.front()) { @@ -34,6 +37,11 @@ namespace services } } + bool ProtoMessageReceiverBase::Failed() const + { + return failed; + } + void ProtoMessageReceiverBase::DeserializeField(ProtoBool, infra::ProtoParser& parser, infra::ProtoParser::PartialFieldVariant& field, bool& value) const { services::DeserializeField(ProtoBool(), parser, field, value); diff --git a/protobuf/echo/ProtoMessageReceiver.hpp b/protobuf/echo/ProtoMessageReceiver.hpp index b127695b4..ac66fa5f1 100644 --- a/protobuf/echo/ProtoMessageReceiver.hpp +++ b/protobuf/echo/ProtoMessageReceiver.hpp @@ -14,6 +14,7 @@ namespace services explicit ProtoMessageReceiverBase(infra::BoundedVector>>& stack); void Feed(infra::StreamReaderWithRewinding& data); + bool Failed() const; protected: template @@ -54,6 +55,7 @@ namespace services private: infra::BoundedDeque::WithMaxSize<32> buffer; infra::BoundedVector>>& stack; + bool failed = false; }; template diff --git a/protobuf/echo/ProtoMessageSender.cpp b/protobuf/echo/ProtoMessageSender.cpp index 5f013d486..c9a4c0b8d 100644 --- a/protobuf/echo/ProtoMessageSender.cpp +++ b/protobuf/echo/ProtoMessageSender.cpp @@ -13,7 +13,7 @@ namespace services while (!stack.empty()) { - infra::DataOutputStream::WithErrorPolicy stream{ writer }; + infra::DataOutputStream stream{ writer, output.ErrorPolicy() }; auto& [index, callback] = stack.back(); bool retry = false; diff --git a/protobuf/echo/Serialization.cpp b/protobuf/echo/Serialization.cpp new file mode 100644 index 000000000..aea1646c9 --- /dev/null +++ b/protobuf/echo/Serialization.cpp @@ -0,0 +1,64 @@ +#include "protobuf/echo/Serialization.hpp" +#include "protobuf/echo/Echo.hpp" + +namespace services +{ + MethodDeserializerDummy::MethodDeserializerDummy(Echo& echo) + : echo(echo) + {} + + void MethodDeserializerDummy::MethodContents(infra::SharedPtr&& reader) + { + while (!reader->Empty()) + reader->ExtractContiguousRange(std::numeric_limits::max()); + + reader = nullptr; + } + + void MethodDeserializerDummy::ExecuteMethod() + { + echo.ServiceDone(); + } + + bool MethodDeserializerDummy::Failed() const + { + return false; + } + + infra::SharedPtr MethodSerializerFactory::MakeDummyDeserializer(Echo& echo) + { + using Deserializer = MethodDeserializerDummy; + + auto memory = DeserializerMemory(sizeof(Deserializer)); + auto deserializer = new (memory->begin()) Deserializer(echo); + return infra::MakeContainedSharedObject(*deserializer, memory); + } + + infra::SharedPtr MethodSerializerFactory::OnHeap::SerializerMemory(uint32_t size) + { + auto m = new uint8_t[size]; + serializerMemory = { m, + m + size }; + return serializerAccess.MakeShared(serializerMemory); + } + + infra::SharedPtr MethodSerializerFactory::OnHeap::DeserializerMemory(uint32_t size) + { + auto m = new uint8_t[size]; + deserializerMemory = { m, + m + size }; + return deserializerAccess.MakeShared(deserializerMemory); + } + + void MethodSerializerFactory::OnHeap::DeAllocateSerializer() + { + delete[] serializerMemory.begin(); + serializerMemory = {}; + } + + void MethodSerializerFactory::OnHeap::DeAllocateDeserializer() + { + delete[] deserializerMemory.begin(); + deserializerMemory = {}; + } +} diff --git a/protobuf/echo/Serialization.hpp b/protobuf/echo/Serialization.hpp new file mode 100644 index 000000000..21840ebd2 --- /dev/null +++ b/protobuf/echo/Serialization.hpp @@ -0,0 +1,347 @@ +#ifndef PROTOBUF_SERIALIZATION_HPP +#define PROTOBUF_SERIALIZATION_HPP + +#include "infra/util/ReallyAssert.hpp" +#include "infra/util/SharedOptional.hpp" +#include "protobuf/echo/ProtoMessageReceiver.hpp" +#include "protobuf/echo/ProtoMessageSender.hpp" + +namespace services +{ + class Echo; + + class MethodDeserializer + { + public: + MethodDeserializer() = default; + MethodDeserializer(const MethodDeserializer& other) = delete; + MethodDeserializer& operator=(const MethodDeserializer& other) = delete; + virtual ~MethodDeserializer() = default; + + virtual void MethodContents(infra::SharedPtr&& reader) = 0; + virtual void ExecuteMethod() = 0; + virtual bool Failed() const = 0; + }; + + class MethodSerializer + { + public: + MethodSerializer() = default; + MethodSerializer(const MethodSerializer& other) = delete; + MethodSerializer& operator=(const MethodSerializer& other) = delete; + virtual ~MethodSerializer() = default; + + virtual bool Serialize(infra::SharedPtr&& writer) = 0; + + virtual void SerializationDone() + {} + }; + + class MethodDeserializerDummy + : public MethodDeserializer + { + public: + explicit MethodDeserializerDummy(Echo& echo); + + void MethodContents(infra::SharedPtr&& reader) override; + void ExecuteMethod() override; + bool Failed() const override; + + private: + Echo& echo; + }; + + template + class MethodDeserializerImpl + : public MethodDeserializer + { + public: + explicit MethodDeserializerImpl(const infra::Function& method); + + void MethodContents(infra::SharedPtr&& reader) override; + void ExecuteMethod() override; + bool Failed() const override; + + private: + template + void Execute(std::index_sequence); + + private: + ProtoMessageReceiver receiver; + infra::Function method; + }; + + template + class MethodSerializerImpl + : public MethodSerializer + { + public: + MethodSerializerImpl(uint32_t serviceId, uint32_t methodId, Args... args); + + bool Serialize(infra::SharedPtr&& writer) override; + + private: + uint32_t serviceId; + uint32_t methodId; + bool headerSent = false; + Message message; + ProtoMessageSender sender{ message }; + }; + + class MethodSerializerFactory + { + public: + template + class ForServices; + + class OnHeap; + + MethodSerializerFactory() = default; + MethodSerializerFactory(const MethodSerializerFactory& other) = delete; + MethodSerializerFactory& operator=(const MethodSerializerFactory& other) = delete; + virtual ~MethodSerializerFactory() = default; + + virtual infra::SharedPtr SerializerMemory(uint32_t size) = 0; + virtual infra::SharedPtr DeserializerMemory(uint32_t size) = 0; + + template + infra::SharedPtr MakeSerializer(uint32_t serviceId, uint32_t methodId, Args... args); + + template + infra::SharedPtr MakeDeserializer(const infra::Function& method); + + infra::SharedPtr MakeDummyDeserializer(Echo& echo); + }; + + template + struct MaxSerializerSize; + + template<> + struct MaxSerializerSize> + { + static constexpr std::size_t maxSize = 0; + }; + + template + struct MaxSerializerSize> + { + static constexpr std::size_t maxSize = std::max(sizeof(MethodSerializerImpl), MaxSerializerSize>::maxSize); + }; + + template + struct MaxDeserializerSize; + + template<> + struct MaxDeserializerSize> + { + static constexpr std::size_t maxSize = 0; + }; + + template + struct MaxDeserializerSize> + { + static constexpr std::size_t maxSize = std::max(sizeof(MethodDeserializerImpl), MaxDeserializerSize>::maxSize); + }; + + template + struct MaxServiceSize; + + template<> + struct MaxServiceSize<> + { + static constexpr std::size_t maxSize = sizeof(MethodDeserializerDummy); + }; + + template + struct MaxServiceSize + { + static constexpr std::size_t maxSize = std::max(MaxDeserializerSize::maxSize, MaxServiceSize::maxSize); + }; + + template + struct MaxServiceProxySize; + + template<> + struct MaxServiceProxySize<> + { + static constexpr std::size_t maxSize = 0; + }; + + template + struct MaxServiceProxySize + { + static constexpr std::size_t maxSize = std::max(MaxSerializerSize::maxSize, MaxServiceProxySize::maxSize); + }; + + template + class MethodSerializerFactory::ForServices + { + public: + template + class AndProxies; + }; + + template + template + class MethodSerializerFactory::ForServices::AndProxies + : public MethodSerializerFactory + { + public: + infra::SharedPtr SerializerMemory(uint32_t size) override; + infra::SharedPtr DeserializerMemory(uint32_t size) override; + + private: + alignas(std::max_align_t) std::array::maxSize> serializerStorage; + alignas(std::max_align_t) std::array::maxSize> deserializerStorage; + infra::ByteRange serializerMemory; + infra::ByteRange deserializerMemory; + infra::AccessedBySharedPtr serializerAccess{ infra::emptyFunction }; + infra::AccessedBySharedPtr deserializerAccess{ infra::emptyFunction }; + }; + + class MethodSerializerFactory::OnHeap + : public MethodSerializerFactory + { + public: + infra::SharedPtr SerializerMemory(uint32_t size) override; + infra::SharedPtr DeserializerMemory(uint32_t size) override; + + private: + void DeAllocateSerializer(); + void DeAllocateDeserializer(); + + private: + infra::AccessedBySharedPtr serializerAccess{ + [this]() + { + DeAllocateSerializer(); + } + }; + + infra::AccessedBySharedPtr deserializerAccess{ + [this]() + { + DeAllocateDeserializer(); + } + }; + + infra::ByteRange serializerMemory; + infra::ByteRange deserializerMemory; + }; + + class EmptyMessage + { + public: + static const uint32_t numberOfFields = 0; + template + using ProtoType = void; + template + using Type = void; + template + static const uint32_t fieldNumber = 0; + + public: + void Serialize([[maybe_unused]] infra::ProtoFormatter& formatter) const + {} + }; + + //// Implementation //// + + template + MethodDeserializerImpl::MethodDeserializerImpl(const infra::Function& method) + : method(method) + {} + + template + void MethodDeserializerImpl::MethodContents(infra::SharedPtr&& reader) + { + receiver.Feed(*reader); + } + + template + void MethodDeserializerImpl::ExecuteMethod() + { + Execute(std::make_index_sequence{}); + } + + template + bool MethodDeserializerImpl::Failed() const + { + return receiver.Failed(); + } + + template + template + void MethodDeserializerImpl::Execute(std::index_sequence) + { + method(receiver.message.Get(std::integral_constant{})...); + } + + template + MethodSerializerImpl::MethodSerializerImpl(uint32_t serviceId, uint32_t methodId, Args... args) + : serviceId(serviceId) + , methodId(methodId) + , message(args...) + {} + + template + bool MethodSerializerImpl::Serialize(infra::SharedPtr&& writer) + { + infra::DataOutputStream::WithErrorPolicy stream(*writer, infra::softFail); + + if (!headerSent) + { + infra::DataOutputStream::WithWriter countingStream; + infra::ProtoFormatter countingFormatter{ countingStream }; + message.Serialize(countingFormatter); + + infra::ProtoFormatter formatter(stream); + formatter.PutVarInt(serviceId); + formatter.PutLengthDelimitedSize(countingStream.Writer().Processed(), methodId); + + headerSent = true; + } + + sender.Fill(stream); + writer = nullptr; + return stream.Failed(); + } + + template + infra::SharedPtr MethodSerializerFactory::MakeSerializer(uint32_t serviceId, uint32_t methodId, Args... args) + { + using Serializer = MethodSerializerImpl; + + auto memory = SerializerMemory(sizeof(Serializer)); + auto serializer = new (memory->begin()) Serializer(serviceId, methodId, args...); + return infra::MakeContainedSharedObject(*serializer, memory); + } + + template + infra::SharedPtr MethodSerializerFactory::MakeDeserializer(const infra::Function& method) + { + using Deserializer = MethodDeserializerImpl; + + auto memory = DeserializerMemory(sizeof(Deserializer)); + auto deserializer = new (memory->begin()) Deserializer(method); + return infra::MakeContainedSharedObject(*deserializer, memory); + } + + template + template + infra::SharedPtr MethodSerializerFactory::ForServices::AndProxies::SerializerMemory(uint32_t size) + { + serializerMemory = infra::Head(infra::MakeRange(serializerStorage), size); + return serializerAccess.MakeShared(serializerMemory); + } + + template + template + infra::SharedPtr MethodSerializerFactory::ForServices::AndProxies::DeserializerMemory(uint32_t size) + { + deserializerMemory = infra::Head(infra::MakeRange(deserializerStorage), size); + return deserializerAccess.MakeShared(deserializerMemory); + } +} + +#endif diff --git a/protobuf/echo/ServiceForwarder.cpp b/protobuf/echo/ServiceForwarder.cpp index 5bb906fc9..293805633 100644 --- a/protobuf/echo/ServiceForwarder.cpp +++ b/protobuf/echo/ServiceForwarder.cpp @@ -2,46 +2,82 @@ namespace services { - ServiceForwarderBase::ServiceForwarderBase(infra::ByteRange messageBuffer, Echo& echo, Echo& forwardTo) + ServiceForwarderBase::ServiceForwarderBase(Echo& echo, Echo& forwardTo) : Service(echo) - , ServiceProxy(forwardTo, messageBuffer.size()) - , messageBuffer(messageBuffer) + , ServiceProxy(forwardTo, 0) {} - void ServiceForwarderBase::Handle(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, EchoErrorPolicy& errorPolicy) + infra::SharedPtr ServiceForwarderBase::StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const EchoErrorPolicy& errorPolicy) { - this->forwardingServiceId = serviceId; - bytes.Emplace(messageBuffer); - uint32_t processedSize = 0; + forwardingServiceId = serviceId; + forwardingMethodId = methodId; + forwardingSize = size; + processedSize = 0; + sentHeader = false; - while (true) + RequestSend([this]() + { + SetSerializer(infra::UnOwnedSharedPtr(static_cast(*this))); + }, + size); + + return infra::UnOwnedSharedPtr(static_cast(*this)); + } + + void ServiceForwarderBase::MethodContents(infra::SharedPtr&& reader) + { + contentsReader = std::move(reader); + Transfer(); + } + + void ServiceForwarderBase::ExecuteMethod() + { + MethodDone(); + } + + bool ServiceForwarderBase::Failed() const + { + return false; + } + + bool ServiceForwarderBase::Serialize(infra::SharedPtr&& writer) + { + contentsWriter = std::move(writer); + auto result = processedSize + contentsWriter->Available() < forwardingSize; + Transfer(); + + return result; + } + + void ServiceForwarderBase::Transfer() + { + if (!sentHeader) { - infra::ConstByteRange contiguousBytes; - contents.GetBytesReference(contiguousBytes); + if (contentsWriter == nullptr) + return; + + infra::DataOutputStream::WithErrorPolicy stream(*contentsWriter); - if (contiguousBytes.size() == 0) - break; + infra::ProtoFormatter formatter(stream); + formatter.PutVarInt(forwardingServiceId); + formatter.PutLengthDelimitedSize(forwardingSize, forwardingMethodId); - std::copy(contiguousBytes.begin(), contiguousBytes.end(), bytes->begin() + processedSize); - processedSize += contiguousBytes.size(); + sentHeader = true; } - bytes->shrink_from_back_to(processedSize); + infra::StreamErrorPolicy errorPolicy; - uint32_t messageSize = infra::MaxVarIntSize(this->forwardingServiceId) + infra::MaxVarIntSize((methodId << 3) | 2) + infra::MaxVarIntSize(bytes->size()) + bytes->size(); + while (processedSize != forwardingSize && contentsWriter != nullptr && contentsReader != nullptr) + { + auto range = contentsReader->ExtractContiguousRange(forwardingSize - processedSize); + contentsWriter->Insert(range, errorPolicy); + processedSize += range.size(); + } - RequestSend([this, methodId]() - { - infra::DataOutputStream::WithErrorPolicy stream(services::ServiceProxy::Rpc().SendStreamWriter()); - infra::ProtoFormatter formatter(stream); - formatter.PutVarInt(this->forwardingServiceId); - formatter.PutBytesField(*bytes, methodId); - bytes = infra::none; - - services::ServiceProxy::Rpc().Send(); - MethodDone(); - }, - messageSize); + if (processedSize == forwardingSize || (contentsReader != nullptr && contentsReader->Empty())) + contentsReader = nullptr; + if (processedSize == forwardingSize || (contentsWriter != nullptr && contentsWriter->Empty())) + contentsWriter = nullptr; } bool ServiceForwarderAll::AcceptsService(uint32_t id) const @@ -49,8 +85,8 @@ namespace services return true; } - ServiceForwarder::ServiceForwarder(infra::ByteRange messageBuffer, Echo& echo, uint32_t id, Echo& forwardTo) - : ServiceForwarderBase(messageBuffer, echo, forwardTo) + ServiceForwarder::ServiceForwarder(Echo& echo, uint32_t id, Echo& forwardTo) + : ServiceForwarderBase(echo, forwardTo) , serviceId(id) {} diff --git a/protobuf/echo/ServiceForwarder.hpp b/protobuf/echo/ServiceForwarder.hpp index fe8113934..0d7f1c2e4 100644 --- a/protobuf/echo/ServiceForwarder.hpp +++ b/protobuf/echo/ServiceForwarder.hpp @@ -6,18 +6,38 @@ namespace services { class ServiceForwarderBase - : public services::Service - , private services::ServiceProxy + : public Service + , private ServiceProxy + , private MethodDeserializer + , private MethodSerializer { public: - ServiceForwarderBase(infra::ByteRange messageBuffer, Echo& echo, Echo& forwardTo); + ServiceForwarderBase(Echo& echo, Echo& forwardTo); - void Handle(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, EchoErrorPolicy& errorPolicy) override; + // Implementation of Service + infra::SharedPtr StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const EchoErrorPolicy& errorPolicy) override; + + private: + // Implementation of MethodDeserializer + void MethodContents(infra::SharedPtr&& reader) override; + void ExecuteMethod() override; + bool Failed() const override; + + // Implementation of MethodSerializer + bool Serialize(infra::SharedPtr&& writer) override; + + private: + void Transfer(); private: - const infra::ByteRange messageBuffer; - infra::Optional bytes; uint32_t forwardingServiceId; + uint32_t forwardingMethodId; + uint32_t forwardingSize; + uint32_t processedSize; + bool sentHeader; + + infra::SharedPtr contentsReader; + infra::SharedPtr contentsWriter; }; class ServiceForwarderAll @@ -26,9 +46,6 @@ namespace services public: using ServiceForwarderBase::ServiceForwarderBase; - template - using WithMaxMessageSize = infra::WithStorage>; - bool AcceptsService(uint32_t id) const override; }; @@ -36,10 +53,7 @@ namespace services : public ServiceForwarderBase { public: - ServiceForwarder(infra::ByteRange messageBuffer, Echo& echo, uint32_t id, Echo& forwardTo); - - template - using WithMaxMessageSize = infra::WithStorage>; + ServiceForwarder(Echo& echo, uint32_t id, Echo& forwardTo); bool AcceptsService(uint32_t id) const override; diff --git a/protobuf/echo/test/CMakeLists.txt b/protobuf/echo/test/CMakeLists.txt index 9dd11414e..6fb247752 100644 --- a/protobuf/echo/test/CMakeLists.txt +++ b/protobuf/echo/test/CMakeLists.txt @@ -5,7 +5,6 @@ emil_add_test(protobuf.echo_test) protocol_buffer_echo_cpp(protobuf.echo_test TestMessages.proto) target_sources(protobuf.echo_test PRIVATE - TestEchoServiceResponseQueue.cpp TestProtoMessageReceiver.cpp TestProtoMessageSender.cpp TestServiceForwarder.cpp diff --git a/protobuf/echo/test/TestEchoServiceResponseQueue.cpp b/protobuf/echo/test/TestEchoServiceResponseQueue.cpp deleted file mode 100644 index 93f6e7169..000000000 --- a/protobuf/echo/test/TestEchoServiceResponseQueue.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "infra/util/Function.hpp" -#include "infra/util/test_helper/MockCallback.hpp" -#include "protobuf/echo/Echo.hpp" -#include "protobuf/echo/test_doubles/EchoMock.hpp" -#include "protobuf/echo/test_doubles/ServiceStub.hpp" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace services -{ - class EchoServiceResponseQueueTest - : public testing::Test - { - public: - testing::StrictMock echo; - testing::StrictMock>::WithStorage<2> serviceProxy{ echo }; - }; - - TEST_F(EchoServiceResponseQueueTest, RequestSendWhileEmptyImmediatelyForwardsRequestToEcho) - { - EXPECT_CALL(echo, RequestSend(testing::Ref(serviceProxy))); - - serviceProxy.RequestSend(infra::emptyFunction); - } - - TEST_F(EchoServiceResponseQueueTest, RequestsNextRequestAfterGrantingAccess) - { - infra::VerifyingFunctionMock request1{}; - infra::VerifyingFunctionMock request2{}; - - EXPECT_CALL(echo, RequestSend(testing::Ref(serviceProxy))).Times(2); - - serviceProxy.RequestSend(request1, 128); - serviceProxy.RequestSend(request2, 50); - - EXPECT_THAT(serviceProxy.CurrentRequestedSize(), testing::Eq(128)); - serviceProxy.GrantSend(); - - EXPECT_THAT(serviceProxy.CurrentRequestedSize(), testing::Eq(50)); - serviceProxy.GrantSend(); - } - - TEST_F(EchoServiceResponseQueueTest, DiscardsRequestWhenQueueFull) - { - infra::VerifyingFunctionMock request1{}; - infra::VerifyingFunctionMock request2{}; - infra::VerifyingFunctionMock request4{}; - - EXPECT_CALL(echo, RequestSend(testing::Ref(serviceProxy))) - .Times(3); - - serviceProxy.RequestSend(request1); - serviceProxy.RequestSend(request2); - - serviceProxy.RequestSend([] - { - FAIL(); - }); - - serviceProxy.GrantSend(); - serviceProxy.GrantSend(); - - serviceProxy.RequestSend(request4); - serviceProxy.GrantSend(); - } -} diff --git a/protobuf/echo/test/TestMessages.proto b/protobuf/echo/test/TestMessages.proto index 5588d0a11..cf1ee6c9f 100644 --- a/protobuf/echo/test/TestMessages.proto +++ b/protobuf/echo/test/TestMessages.proto @@ -170,7 +170,14 @@ service TestService2 { option (service_id) = 2; - rpc Search (TestString) returns (Nothing) { option (method_id) = 1; } + rpc Search(TestString) returns (Nothing) { option (method_id) = 1; } +} + +service TestServiceNoParameter +{ + option (service_id) = 3; + + rpc Method(Nothing) returns (Nothing) { option (method_id) = 1; } } message TestBoolWithBytes { diff --git a/protobuf/echo/test/TestServiceForwarder.cpp b/protobuf/echo/test/TestServiceForwarder.cpp index e359e39dc..87e99171a 100644 --- a/protobuf/echo/test/TestServiceForwarder.cpp +++ b/protobuf/echo/test/TestServiceForwarder.cpp @@ -9,7 +9,7 @@ class ServiceForwarderAllTest public: testing::StrictMock echoFrom; testing::StrictMock echoTo; - services::ServiceForwarderAll::WithMaxMessageSize<100> forwarder{ echoFrom, echoTo }; + services::ServiceForwarderAll forwarder{ echoFrom, echoTo }; testing::StrictMock errorPolicy; }; @@ -25,24 +25,24 @@ TEST_F(ServiceForwarderAllTest, accept_any_service) TEST_F(ServiceForwarderAllTest, forward_message) { - echoFrom.NotifyObservers([this](auto& service) + infra::StdVectorOutputStreamWriter::WithStorage writer; + + echoFrom.NotifyObservers([this, &writer](auto& service) { - infra::StreamErrorPolicy streamErrorPolicy; infra::StdVectorInputStream::WithStorage inputStream{ infra::inPlace, std::vector{ 1, 2, 3, 4, 5 } }; - infra::ProtoLengthDelimited contents{ inputStream, streamErrorPolicy, static_cast(inputStream.Available()) }; - EXPECT_CALL(echoTo, RequestSend(testing::_)).WillOnce(testing::Invoke([this, &service](services::ServiceProxy& serviceProxy) + EXPECT_CALL(echoTo, RequestSend(testing::_)).WillOnce(testing::Invoke([this, &service, &writer](services::ServiceProxy& serviceProxy) { - infra::StdVectorOutputStreamWriter::WithStorage writer; - EXPECT_CALL(echoTo, SendStreamWriter()).WillOnce(testing::ReturnRef(writer)); - EXPECT_CALL(echoTo, Send()); - EXPECT_CALL(echoFrom, ServiceDone(testing::Ref(service))); - serviceProxy.GrantSend(); - - EXPECT_EQ((std::vector{ 1, 42, 5, 1, 2, 3, 4, 5 }), writer.Storage()); + EXPECT_CALL(echoFrom, ServiceDone()); + auto serializer = serviceProxy.GrantSend(); + EXPECT_FALSE(serializer->Serialize(infra::UnOwnedSharedPtr(writer))); })); - service.HandleMethod(1, 5, contents, errorPolicy); + auto deserializer = service.StartMethod(1, 5, 5, errorPolicy); + deserializer->MethodContents(infra::UnOwnedSharedPtr(inputStream.Reader())); + deserializer->ExecuteMethod(); }); + + EXPECT_EQ((std::vector{ 1, 42, 5, 1, 2, 3, 4, 5 }), writer.Storage()); } class ServiceForwarderTest @@ -51,7 +51,7 @@ class ServiceForwarderTest public: testing::StrictMock echoFrom; testing::StrictMock echoTo; - services::ServiceForwarder::WithMaxMessageSize<100> forwarder{ echoFrom, 1, echoTo }; + services::ServiceForwarder forwarder{ echoFrom, 1, echoTo }; testing::StrictMock errorPolicy; }; diff --git a/protobuf/echo/test_doubles/EchoMock.hpp b/protobuf/echo/test_doubles/EchoMock.hpp index f13f91bf5..4080c7172 100644 --- a/protobuf/echo/test_doubles/EchoMock.hpp +++ b/protobuf/echo/test_doubles/EchoMock.hpp @@ -10,27 +10,18 @@ namespace services : public services::Echo { public: - MOCK_METHOD1(RequestSend, void(ServiceProxy& serviceProxy)); - MOCK_METHOD0(SendStreamWriter, infra::StreamWriter&()); - MOCK_METHOD0(Send, void()); - MOCK_METHOD1(ServiceDone, void(Service& service)); + MOCK_METHOD(void, RequestSend, (ServiceProxy & serviceProxy), (override)); + MOCK_METHOD(void, ServiceDone, (), (override)); + MOCK_METHOD(services::MethodSerializerFactory&, SerializerFactory, (), (override)); }; class EchoErrorPolicyMock : public services::EchoErrorPolicy { public: - MOCK_METHOD0(MessageFormatError, void()); - MOCK_METHOD1(ServiceNotFound, void(uint32_t serviceId)); - MOCK_METHOD2(MethodNotFound, void(uint32_t serviceId, uint32_t methodId)); - }; - - class MessageCommunicationMock - : public services::MessageCommunication - { - public: - MOCK_METHOD1(RequestSendMessage, void(uint16_t size)); - MOCK_CONST_METHOD0(MaxSendMessageSize, std::size_t()); + MOCK_METHOD(void, MessageFormatError, (), (const override)); + MOCK_METHOD(void, ServiceNotFound, (uint32_t serviceId), (const override)); + MOCK_METHOD(void, MethodNotFound, (uint32_t serviceId, uint32_t methodId), (const override)); }; } diff --git a/protobuf/echo/test_doubles/EchoSingleLoopback.cpp b/protobuf/echo/test_doubles/EchoSingleLoopback.cpp index 4c1fd3a76..e95b1b187 100644 --- a/protobuf/echo/test_doubles/EchoSingleLoopback.cpp +++ b/protobuf/echo/test_doubles/EchoSingleLoopback.cpp @@ -1,5 +1,4 @@ #include "protobuf/echo/test_doubles/EchoSingleLoopback.hpp" -#include "infra/stream/ByteInputStream.hpp" namespace application { @@ -7,20 +6,11 @@ namespace application { storage.clear(); storage.resize(size); - auto writer = sendStream.Emplace(infra::MakeRange(storage)); - SetStreamWriter(std::move(writer)); - } - - void EchoSingleLoopback::BusyServiceDone() - { - // In this class, services are never busy, so BusyServiceDone() is never invoked - std::abort(); + SendStreamAvailable(sendStream.Emplace(infra::MakeRange(storage))); } void EchoSingleLoopback::SendStreamFilled() { - infra::ByteInputStreamReader reader(infra::MakeRange(storage)); - if (!ProcessMessage(reader)) - errorPolicy.MessageFormatError(); + DataReceived(reader.Emplace(infra::MakeRange(storage))); } } diff --git a/protobuf/echo/test_doubles/EchoSingleLoopback.hpp b/protobuf/echo/test_doubles/EchoSingleLoopback.hpp index 73b4fa7a2..780dbf14f 100644 --- a/protobuf/echo/test_doubles/EchoSingleLoopback.hpp +++ b/protobuf/echo/test_doubles/EchoSingleLoopback.hpp @@ -1,6 +1,7 @@ #ifndef PROTOBUF_TEST_HELPER_ECHO_SINGLE_LOOPBACK_HPP #define PROTOBUF_TEST_HELPER_ECHO_SINGLE_LOOPBACK_HPP +#include "infra/stream/ByteInputStream.hpp" #include "infra/stream/ByteOutputStream.hpp" #include "infra/util/SharedOptional.hpp" #include "protobuf/echo/Echo.hpp" @@ -16,7 +17,6 @@ namespace application protected: // Implementation of services::EchoOnStreams void RequestSendStream(std::size_t size) override; - void BusyServiceDone() override; private: void SendStreamFilled(); @@ -27,6 +27,8 @@ namespace application { SendStreamFilled(); } }; + + infra::SharedOptional reader; }; } diff --git a/protobuf/echo/test_doubles/ServiceStub.cpp b/protobuf/echo/test_doubles/ServiceStub.cpp index 90a16384e..c71695cca 100644 --- a/protobuf/echo/test_doubles/ServiceStub.cpp +++ b/protobuf/echo/test_doubles/ServiceStub.cpp @@ -2,39 +2,51 @@ namespace services { - void ServiceStub::Handle(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, services::EchoErrorPolicy& errorPolicy) + Message::Message(uint32_t value) + : value(value) + {} + + void Message::Serialize(infra::ProtoFormatter& formatter) const + { + SerializeField(services::ProtoInt32(), formatter, value, 1); + } + + uint32_t& Message::Get(std::integral_constant) + { + return value; + } + + const uint32_t& Message::Get(std::integral_constant) const { - infra::ProtoParser parser(contents.Parser()); + return value; + } + ServiceStub::ServiceStub(Echo& echo) + : Service(echo) + {} + + bool ServiceStub::AcceptsService(uint32_t id) const + { + return id == serviceId; + } + + infra::SharedPtr ServiceStub::StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const services::EchoErrorPolicy& errorPolicy) + { switch (methodId) { - uint32_t value; - case idMethod: - { - while (!parser.Empty()) - { - infra::ProtoParser::Field field = parser.GetField(); - - switch (field.second) + return Rpc().SerializerFactory().MakeDeserializer(infra::Function([this](uint32_t v) + { + Method(v); + })); + case idMethodNoParameter: + return Rpc().SerializerFactory().MakeDeserializer(infra::Function([this]() { - case 1: - DeserializeField(services::ProtoUInt32(), parser, field.first, value); - break; - default: - if (field.first.Is()) - field.first.Get().SkipEverything(); - break; - } - } - - if (!parser.FormatFailed()) - Method(value); - break; - } + MethodNoParameter(); + })); default: errorPolicy.MethodNotFound(serviceId, methodId); - contents.SkipEverything(); + return Rpc().SerializerFactory().MakeDummyDeserializer(Rpc()); } } @@ -44,13 +56,13 @@ namespace services void ServiceStubProxy::Method(uint32_t value) { - infra::DataOutputStream::WithErrorPolicy stream(Rpc().SendStreamWriter()); - infra::ProtoFormatter formatter(stream); - formatter.PutVarInt(serviceId); - { - infra::ProtoLengthDelimitedFormatter argumentFormatter = formatter.LengthDelimitedFormatter(idMethod); - SerializeField(services::ProtoUInt32(), formatter, value, 1); - } - Rpc().Send(); + auto serializer = Rpc().SerializerFactory().MakeSerializer(serviceId, idMethod, value); + SetSerializer(serializer); + } + + void ServiceStubProxy::MethodNoParameter() + { + auto serializer = Rpc().SerializerFactory().MakeSerializer(serviceId, idMethodNoParameter); + SetSerializer(serializer); } } diff --git a/protobuf/echo/test_doubles/ServiceStub.hpp b/protobuf/echo/test_doubles/ServiceStub.hpp index cca507b0d..4ec33c159 100644 --- a/protobuf/echo/test_doubles/ServiceStub.hpp +++ b/protobuf/echo/test_doubles/ServiceStub.hpp @@ -6,26 +6,52 @@ namespace services { + struct Message + { + public: + static const uint32_t numberOfFields = 1; + template + using ProtoType = ProtoUInt32; + template + using Type = uint32_t; + template + static const uint32_t fieldNumber = 1; + + public: + Message() = default; + Message(uint32_t value); + + void Serialize(infra::ProtoFormatter& formatter) const; + + uint32_t& Get(std::integral_constant); + const uint32_t& Get(std::integral_constant) const; + + public: + uint32_t value = 0; + }; + class ServiceStub : public services::Service { public: - using services::Service::Service; + ServiceStub(Echo& echo); - bool AcceptsService(uint32_t id) const override - { - return id == serviceId; - } + bool AcceptsService(uint32_t id) const override; - MOCK_METHOD1(Method, void(uint32_t value)); + MOCK_METHOD(void, Method, (uint32_t value)); + MOCK_METHOD(void, MethodNoParameter, ()); protected: - void Handle(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, services::EchoErrorPolicy& errorPolicy) override; + infra::SharedPtr StartMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const services::EchoErrorPolicy& errorPolicy) override; public: static const uint32_t serviceId = 1; static const uint32_t idMethod = 1; + static const uint32_t idMethodNoParameter = 3; static const uint32_t maxMessageSize = 18; + + public: + using MethodTypeList = infra::List; }; class ServiceStubProxy @@ -36,11 +62,16 @@ namespace services public: void Method(uint32_t value); + void MethodNoParameter(); public: - static const uint32_t serviceId = 1; - static const uint32_t idMethod = 1; - static const uint32_t maxMessageSize = 18; + static constexpr uint32_t serviceId = 1; + static constexpr uint32_t idMethod = 1; + static const uint32_t idMethodNoParameter = 3; + static constexpr uint32_t maxMessageSize = 18; + + public: + using MethodTypeList = infra::List; }; } diff --git a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp index 3a35ff3a0..80f006108 100644 --- a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp +++ b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.cpp @@ -826,6 +826,7 @@ namespace application GenerateServiceFunctions(); GenerateServiceProxyFunctions(); GenerateFieldConstants(); + GenerateMethodTypeList(); } void ServiceGenerator::GenerateServiceConstructors() @@ -870,16 +871,16 @@ namespace application functions->Add(serviceMethod); } - auto acceptsService = std::make_shared("AcceptsService", AcceptsServiceBody(), "bool", Function::fConst | Function::fVirtual | Function::fOverride); + auto acceptsService = std::make_shared("AcceptsService", AcceptsServiceBody(), "bool", Function::fConst | Function::fOverride); acceptsService->Parameter("uint32_t id"); functions->Add(acceptsService); - auto handle = std::make_shared("Handle", HandleBody(), "void", Function::fVirtual | Function::fOverride); - handle->Parameter("uint32_t serviceId"); - handle->Parameter("uint32_t methodId"); - handle->Parameter("infra::ProtoLengthDelimited& contents"); - handle->Parameter("services::EchoErrorPolicy& errorPolicy"); - functions->Add(handle); + auto startMethod = std::make_shared("StartMethod", StartMethodBody(), "infra::SharedPtr", Function::fOverride); + startMethod->Parameter("uint32_t serviceId"); + startMethod->Parameter("uint32_t methodId"); + startMethod->Parameter("uint32_t size"); + startMethod->Parameter("const services::EchoErrorPolicy& errorPolicy"); + functions->Add(startMethod); serviceFormatter->Add(functions); } @@ -912,17 +913,37 @@ namespace application { auto fields = std::make_shared("public"); - fields->Add(std::make_shared("serviceId", "static const uint32_t", google::protobuf::SimpleItoa(service->serviceId))); + fields->Add(std::make_shared("serviceId", "static constexpr uint32_t", google::protobuf::SimpleItoa(service->serviceId))); for (auto& method : service->methods) - fields->Add(std::make_shared("id" + method.name, "static const uint32_t", google::protobuf::SimpleItoa(method.methodId))); + fields->Add(std::make_shared("id" + method.name, "static constexpr uint32_t", google::protobuf::SimpleItoa(method.methodId))); - fields->Add(std::make_shared("maxMessageSize", "static const uint32_t", google::protobuf::SimpleItoa(MaxMessageSize()))); + fields->Add(std::make_shared("maxMessageSize", "static constexpr uint32_t", google::protobuf::SimpleItoa(MaxMessageSize()))); serviceFormatter->Add(fields); serviceProxyFormatter->Add(fields); } + void ServiceGenerator::GenerateMethodTypeList() + { + auto methodTypeListAccess = std::make_shared("public"); + + std::string definition; + + for (auto& method : service->methods) + if (method.parameter != nullptr) + { + if (!definition.empty()) + definition += ", "; + definition += method.parameter->name; + } + + methodTypeListAccess->Add(std::make_shared("MethodTypeList", "infra::List<" + definition + ">")); + + serviceFormatter->Add(methodTypeListAccess); + serviceProxyFormatter->Add(methodTypeListAccess); + } + uint32_t ServiceGenerator::MaxMessageSize() const { uint32_t result = 0; @@ -953,53 +974,31 @@ namespace application return result.str(); } - std::string ServiceGenerator::HandleBody() const + std::string ServiceGenerator::StartMethodBody() const { std::ostringstream result; { google::protobuf::io::OstreamOutputStream stream(&result); google::protobuf::io::Printer printer(&stream, '$', nullptr); - printer.Print(R"(infra::ProtoParser parser(contents.Parser()); - -switch (methodId) + printer.Print(R"(switch (methodId) { )"); for (auto& method : service->methods) { if (method.parameter) - { - printer.Print(R"( case id$name$: - { - $argument$ argument(parser); - if (!parser.FormatFailed()) - $name$()", - "name", method.name, "argument", method.parameter->qualifiedName); - - for (auto& field : method.parameter->fields) - { - printer.Print("argument.$field$", "field", field->name); - if (&field != &method.parameter->fields.back()) - printer.Print(", "); - } - - printer.Print(R"(); - break; - } -)"); - } + PrintMethodCaseWithParameter(method, printer); else printer.Print(R"( case id$name$: - $name$(); - break; + return Rpc().SerializerFactory().MakeDeserializer(infra::Function([this]() { $name$(); })); )", "name", method.name); } printer.Print(R"( default: errorPolicy.MethodNotFound(serviceId, methodId); - contents.SkipEverything(); + return Rpc().SerializerFactory().MakeDummyDeserializer(Rpc()); )"); printer.Print("}\n"); @@ -1008,6 +1007,66 @@ switch (methodId) return result.str(); } + void ServiceGenerator::PrintMethodCaseWithParameter(const EchoMethod& method, google::protobuf::io::Printer& printer) const + { + printer.Print(R"( case id$name$: + return Rpc().SerializerFactory().MakeDeserializer<$argument$)", + "name", method.name, "argument", method.parameter->qualifiedName); + + for (auto& field : method.parameter->fields) + { + std::string typeName; + ParameterTypeVisitor visitor(typeName); + field->Accept(visitor); + + printer.Print(", $type$", "type", typeName); + } + + printer.Print(">(infra::Functionfields) + { + if (&field != &method.parameter->fields.front()) + printer.Print(", "); + + std::string typeName; + ParameterTypeVisitor visitor(typeName); + field->Accept(visitor); + + printer.Print("$type$", "type", typeName); + } + + printer.Print(")>([this]("); + + for (auto& field : method.parameter->fields) + { + auto index = std::distance(&method.parameter->fields.front(), &field); + if (index != 0) + printer.Print(", "); + + std::string typeName; + ParameterTypeVisitor visitor(typeName); + field->Accept(visitor); + + printer.Print("$type$ v$index$", "type", typeName, "index", google::protobuf::SimpleItoa(index)); + } + + printer.Print(R"() { $name$()", + "name", method.name); + + for (auto& field : method.parameter->fields) + { + auto index = std::distance(&method.parameter->fields.front(), &field); + if (index != 0) + printer.Print(", "); + + printer.Print("v$index$", "index", google::protobuf::SimpleItoa(index)); + } + + printer.Print(R"(); })); +)"); + } + std::string ServiceGenerator::ProxyMethodBody(const EchoMethod& method) const { std::ostringstream result; @@ -1015,34 +1074,29 @@ switch (methodId) google::protobuf::io::OstreamOutputStream stream(&result); google::protobuf::io::Printer printer(&stream, '$', nullptr); - printer.Print(R"(infra::DataOutputStream::WithErrorPolicy stream(Rpc().SendStreamWriter()); -infra::ProtoFormatter formatter(stream); -formatter.PutVarInt(serviceId); -{ - infra::ProtoLengthDelimitedFormatter argumentFormatter = formatter.LengthDelimitedFormatter(id$name$); -)", - "name", method.name); - - if (method.parameter) + if (method.parameter != nullptr) { - printer.Print(" $type$(", "type", method.parameter->qualifiedName); + printer.Print(R"(auto serializer = Rpc().SerializerFactory().MakeSerializer<$type$)", "type", method.parameter->qualifiedName); for (auto& field : method.parameter->fields) { std::string typeName; ParameterTypeVisitor visitor(typeName); field->Accept(visitor); - printer.Print("$field$", "field", field->name); - if (&field != &method.parameter->fields.back()) - printer.Print(", "); + printer.Print(", $type$", "type", typeName); } - - printer.Print(R"().Serialize(formatter); -)"); } + else + printer.Print(R"(auto serializer = Rpc().SerializerFactory().MakeSerializer(serviceId, $methodId$", "methodId", google::protobuf::SimpleItoa(method.methodId)); + + if (method.parameter != nullptr) + for (const auto& field : method.parameter->fields) + printer.Print(", $field$", "field", field->name); - printer.Print(R"(} -Rpc().Send(); + printer.Print(R"(); +SetSerializer(serializer); )"); } @@ -1081,7 +1135,7 @@ Rpc().Send(); { auto functions = std::make_shared("public"); - auto handle = std::make_shared("TraceMethod", TraceMethodBody(), "void", Function::fVirtual | Function::fOverride | Function::fConst); + auto handle = std::make_shared("TraceMethod", TraceMethodBody(), "void", Function::fOverride | Function::fConst); handle->Parameter("uint32_t methodId"); handle->Parameter("infra::ProtoLengthDelimited& contents"); handle->Parameter("services::Tracer& tracer"); @@ -1182,6 +1236,7 @@ switch (methodId) auto includesByHeader = std::make_shared(); includesByHeader->Path("infra/util/BoundedString.hpp"); includesByHeader->Path("infra/util/BoundedVector.hpp"); + includesByHeader->Path("infra/util/VariadicTemplates.hpp"); includesByHeader->Path("protobuf/echo/Echo.hpp"); includesByHeader->Path("infra/syntax/ProtoFormatter.hpp"); includesByHeader->Path("infra/syntax/ProtoParser.hpp"); diff --git a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp index c611e71c2..53479bccb 100644 --- a/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp +++ b/protobuf/protoc_echo_plugin/ProtoCEchoPlugin.hpp @@ -157,10 +157,13 @@ namespace application void GenerateServiceFunctions(); void GenerateServiceProxyFunctions(); void GenerateFieldConstants(); + void GenerateMethodTypeList(); uint32_t MaxMessageSize() const; std::string AcceptsServiceBody() const; - std::string HandleBody() const; + std::string StartMethodBody() const; + void PrintMethodCaseWithParameter(const EchoMethod& method, google::protobuf::io::Printer& printer) const; + std::string ProxyMethodBody(const EchoMethod& method) const; private: diff --git a/services/ble/test/TestGapCentral.cpp b/services/ble/test/TestGapCentral.cpp index 5f269750e..05697cca4 100644 --- a/services/ble/test/TestGapCentral.cpp +++ b/services/ble/test/TestGapCentral.cpp @@ -1,7 +1,6 @@ -#include "infra/util/ByteRange.hpp" #include "infra/stream/StringOutputStream.hpp" +#include "infra/util/ByteRange.hpp" #include "infra/util/test_helper/MemoryRangeMatcher.hpp" -#include "infra/stream/StringOutputStream.hpp" #include "services/ble/test_doubles/GapCentralMock.hpp" #include "services/ble/test_doubles/GapCentralObserverMock.hpp" #include "services/ble/test_doubles/GapPeripheralMock.hpp" diff --git a/services/network/EchoOnConnection.cpp b/services/network/EchoOnConnection.cpp index a7b28c3d8..1619bf1b6 100644 --- a/services/network/EchoOnConnection.cpp +++ b/services/network/EchoOnConnection.cpp @@ -4,30 +4,21 @@ namespace services { void EchoOnConnection::SendStreamAvailable(infra::SharedPtr&& writer) { - SetStreamWriter(std::move(writer)); + EchoOnStreams::SendStreamAvailable(std::move(writer)); } void EchoOnConnection::DataReceived() { - while (!ServiceBusy()) - { - infra::SharedPtr reader = ConnectionObserver::Subject().ReceiveStream(); - - if (!ProcessMessage(*reader)) - break; - - if (!ServiceBusy()) // The message was not executed when ServiceBusy() is true, so don't ack the received data - ConnectionObserver::Subject().AckReceived(); - } + EchoOnStreams::DataReceived(ConnectionObserver::Subject().ReceiveStream()); } void EchoOnConnection::RequestSendStream(std::size_t size) { - ConnectionObserver::Subject().RequestSendStream(size); + ConnectionObserver::Subject().RequestSendStream(std::min(size, ConnectionObserver::Subject().MaxSendStreamSize())); } - void EchoOnConnection::BusyServiceDone() + void EchoOnConnection::AckReceived() { - DataReceived(); + ConnectionObserver::Subject().AckReceived(); } } diff --git a/services/network/EchoOnConnection.hpp b/services/network/EchoOnConnection.hpp index d14256b97..e29c5b13b 100644 --- a/services/network/EchoOnConnection.hpp +++ b/services/network/EchoOnConnection.hpp @@ -20,7 +20,7 @@ namespace services protected: // Implementation of EchoOnStreams void RequestSendStream(std::size_t size) override; - void BusyServiceDone() override; + void AckReceived() override; }; } diff --git a/services/network/TracingEchoOnConnection.cpp b/services/network/TracingEchoOnConnection.cpp index 9e2766721..ecfbab29e 100644 --- a/services/network/TracingEchoOnConnection.cpp +++ b/services/network/TracingEchoOnConnection.cpp @@ -1,10 +1,10 @@ #include "services/network/TracingEchoOnConnection.hpp" -#include "infra/stream/ByteInputStream.hpp" +#include "infra/stream/BoundedVectorInputStream.hpp" namespace services { - TracingEchoOnConnection::TracingEchoOnConnection(services::Tracer& tracer, EchoErrorPolicy& errorPolicy) - : EchoOnConnection(errorPolicy) + TracingEchoOnConnection::TracingEchoOnConnection(services::Tracer& tracer, services::MethodSerializerFactory& serializerFactory, const EchoErrorPolicy& errorPolicy) + : EchoOnConnection(serializerFactory, errorPolicy) , tracer(tracer) {} @@ -18,49 +18,83 @@ namespace services services.erase_slow(service); } - void TracingEchoOnConnection::ExecuteMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, infra::StreamReaderWithRewinding& reader) + infra::SharedPtr TracingEchoOnConnection::GrantSend(ServiceProxy& proxy) { - auto service = FindService(serviceId); - - if (service != nullptr) - { - auto marker = reader.ConstructSaveMarker(); + writerBuffer.clear(); + serializer = EchoOnConnection::GrantSend(proxy); + return infra::MakeContainedSharedObject(static_cast(*this), serializer); + } - infra::DataInputStream::WithErrorPolicy stream(reader, infra::noFail); - infra::ProtoLengthDelimited contentsCopy(stream, stream.ErrorPolicy(), contents.Available()); + infra::SharedPtr TracingEchoOnConnection::StartingMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const infra::SharedPtr& deserializer) + { + receivingService = FindService(serviceId); - tracer.Trace() << "< "; - service->TraceMethod(methodId, contentsCopy, tracer); + if (receivingService != nullptr) + { + receivingMethodId = methodId; - reader.Rewind(marker); + readerBuffer.clear(); + this->deserializer = deserializer; + return infra::MakeContainedSharedObject(static_cast(*this), deserializer); } else + { tracer.Trace() << "< Unknown service " << serviceId << " method " << methodId; - - EchoOnConnection::ExecuteMethod(serviceId, methodId, contents, reader); + return deserializer; + } } - void TracingEchoOnConnection::SetStreamWriter(infra::SharedPtr&& writer) + bool TracingEchoOnConnection::Serialize(infra::SharedPtr&& writer) { - EchoOnConnection::SetStreamWriter(tracingWriter.Emplace(std::move(writer), *this)); + return serializer->Serialize(tracingWriter.Emplace(std::move(writer), *this)); } - void TracingEchoOnConnection::SendingData(infra::ConstByteRange range) const + void TracingEchoOnConnection::SerializationDone() { - infra::ByteInputStream stream(range, infra::noFail); + infra::BoundedVectorInputStream stream(writerBuffer, infra::noFail); infra::StreamErrorPolicy formatErrorPolicy(infra::softFail); infra::ProtoParser parser(stream, formatErrorPolicy); auto serviceId = static_cast(parser.GetVarInt()); auto message = parser.GetField(); - if (stream.Failed() || formatErrorPolicy.Failed() || !message.first.Is()) - { + if (stream.Failed()) + tracer.Trace() << "> message too big"; + else if (formatErrorPolicy.Failed() || !message.first.Is()) tracer.Trace() << "> Malformed message"; - return; + else + { + SendingMethod(serviceId, message.second, message.first.Get()); + if (stream.Failed() || formatErrorPolicy.Failed()) + tracer.Continue() << "... Malformed message"; } + } - SendingMethod(serviceId, message.second, message.first.Get()); - if (stream.Failed() || formatErrorPolicy.Failed()) - tracer.Continue() << "... Malformed message"; + void TracingEchoOnConnection::MethodContents(infra::SharedPtr&& reader) + { + auto start = reader->ConstructSaveMarker(); + while (!reader->Empty() && !readerBuffer.full()) + { + auto range = reader->ExtractContiguousRange(readerBuffer.max_size() - readerBuffer.size()); + readerBuffer.insert(readerBuffer.end(), range.begin(), range.end()); + } + reader->Rewind(start); + + deserializer->MethodContents(std::move(reader)); + } + + void TracingEchoOnConnection::ExecuteMethod() + { + infra::BoundedVectorInputStream stream(readerBuffer, infra::noFail); + infra::ProtoLengthDelimited contentsCopy(stream, stream.ErrorPolicy(), static_cast(stream.Available())); + + tracer.Trace() << "< "; + receivingService->TraceMethod(receivingMethodId, contentsCopy, tracer); + + deserializer->ExecuteMethod(); + } + + bool TracingEchoOnConnection::Failed() const + { + return deserializer->Failed(); } void TracingEchoOnConnection::SendingMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents) const @@ -86,18 +120,14 @@ namespace services } TracingEchoOnConnection::TracingWriter::TracingWriter(infra::SharedPtr&& delegate, TracingEchoOnConnection& echo) - : echo(echo) - , delegate(std::move(delegate)) + : delegate(std::move(delegate)) + , writer(echo.writerBuffer) {} - TracingEchoOnConnection::TracingWriter::~TracingWriter() - { - echo.SendingData(infra::MakeRange(writer.Storage())); - } - void TracingEchoOnConnection::TracingWriter::Insert(infra::ConstByteRange range, infra::StreamErrorPolicy& errorPolicy) { - writer.Insert(range, errorPolicy); + infra::StreamErrorPolicy tracingErrorPolicy(infra::noFail); + writer.Insert(range, tracingErrorPolicy); delegate->Insert(range, errorPolicy); } diff --git a/services/network/TracingEchoOnConnection.hpp b/services/network/TracingEchoOnConnection.hpp index 76923bcab..06be61014 100644 --- a/services/network/TracingEchoOnConnection.hpp +++ b/services/network/TracingEchoOnConnection.hpp @@ -8,20 +8,31 @@ namespace services { class TracingEchoOnConnection : public EchoOnConnection + , private MethodSerializer + , private MethodDeserializer { public: - TracingEchoOnConnection(services::Tracer& tracer, EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); + TracingEchoOnConnection(services::Tracer& tracer, services::MethodSerializerFactory& serializerFactory, const EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); void AddServiceTracer(ServiceTracer& service); void RemoveServiceTracer(ServiceTracer& service); protected: // Implementation of EchoOnConnection - void ExecuteMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents, infra::StreamReaderWithRewinding& reader) override; - void SetStreamWriter(infra::SharedPtr&& writer) override; + infra::SharedPtr GrantSend(ServiceProxy& proxy) override; + infra::SharedPtr StartingMethod(uint32_t serviceId, uint32_t methodId, uint32_t size, const infra::SharedPtr& deserializer) override; + + private: + // Implementation of MethodSerializer + virtual bool Serialize(infra::SharedPtr&& writer) override; + virtual void SerializationDone() override; + + // Implementation of MethodDeserializer + virtual void MethodContents(infra::SharedPtr&& reader) override; + virtual void ExecuteMethod() override; + virtual bool Failed() const override; private: - void SendingData(infra::ConstByteRange range) const; void SendingMethod(uint32_t serviceId, uint32_t methodId, infra::ProtoLengthDelimited& contents) const; const ServiceTracer* FindService(uint32_t serviceId) const; @@ -31,7 +42,6 @@ namespace services { public: TracingWriter(infra::SharedPtr&& delegate, TracingEchoOnConnection& echo); - ~TracingWriter(); // Implementation of StreamWriter void Insert(infra::ConstByteRange range, infra::StreamErrorPolicy& errorPolicy) override; @@ -43,9 +53,8 @@ namespace services infra::ByteRange Overwrite(std::size_t marker) override; private: - TracingEchoOnConnection& echo; infra::SharedPtr delegate; - infra::BoundedVectorStreamWriter::WithStorage<1024> writer; + infra::BoundedVectorStreamWriter writer; infra::ByteRange savedRange; infra::ByteRange savedDelegateRange; }; @@ -55,6 +64,13 @@ namespace services infra::IntrusiveForwardList services; infra::SharedOptional tracingWriter; + infra::SharedPtr serializer; + infra::BoundedVector::WithMaxSize<1024> writerBuffer; + + infra::SharedPtr deserializer; + infra::BoundedVector::WithMaxSize<1024> readerBuffer; + const ServiceTracer* receivingService; + uint32_t receivingMethodId; }; } diff --git a/services/network/test/CMakeLists.txt b/services/network/test/CMakeLists.txt index 3daa8cc1d..ec0939cb3 100644 --- a/services/network/test/CMakeLists.txt +++ b/services/network/test/CMakeLists.txt @@ -22,8 +22,6 @@ target_link_libraries(services.network_test PUBLIC target_sources(services.network_test PRIVATE TestAddress.cpp TestBonjourServer.cpp - TestCertificateConvertor.cpp - TestCertificatesMbedTls.cpp TestConnectionMbedTls.cpp TestDnsResolver.cpp TestDnsServer.cpp @@ -50,3 +48,23 @@ target_sources(services.network_test PRIVATE TestWebSocketServerConnectionObserver.cpp TestWiFiNetwork.cpp ) + +add_executable(services.network_test_certificates) +emil_build_for(services.network_test_certificates BOOL EMIL_BUILD_TESTS) +emil_add_test(services.network_test_certificates) + +if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang|AppleClang") + target_compile_options(services.network_test_certificates PRIVATE -Wno-braced-scalar-init) +endif() + +target_link_libraries(services.network_test_certificates PUBLIC + gmock_main + services.network + services.network_test_doubles + hal.generic +) + +target_sources(services.network_test_certificates PRIVATE + TestCertificateConvertor.cpp + TestCertificatesMbedTls.cpp +) diff --git a/services/network/test/TestEchoOnConnection.cpp b/services/network/test/TestEchoOnConnection.cpp index d11be8bb1..84f4acb1c 100644 --- a/services/network/test/TestEchoOnConnection.cpp +++ b/services/network/test/TestEchoOnConnection.cpp @@ -1,6 +1,7 @@ #include "infra/event/test_helper/EventDispatcherWithWeakPtrFixture.hpp" #include "infra/stream/ByteInputStream.hpp" #include "infra/stream/ByteOutputStream.hpp" +#include "infra/stream/StdVectorInputStream.hpp" #include "infra/util/test_helper/MockCallback.hpp" #include "protobuf/echo/test_doubles/EchoMock.hpp" #include "protobuf/echo/test_doubles/ServiceStub.hpp" @@ -18,8 +19,9 @@ class EchoOnConnectionTest } testing::StrictMock errorPolicy; - services::ConnectionMock connection; - services::EchoOnConnection echo{ errorPolicy }; + testing::StrictMock connection; + services::MethodSerializerFactory::ForServices::AndProxies serializerFactory; + services::EchoOnConnection echo{ serializerFactory, errorPolicy }; testing::StrictMock service{ echo }; }; @@ -27,77 +29,57 @@ TEST_F(EchoOnConnectionTest, invoke_service_proxy_method) { services::ServiceStubProxy serviceProxy{ echo }; - testing::StrictMock> onGranted; - EXPECT_CALL(connection, RequestSendStream(18)); - serviceProxy.RequestSend([&onGranted]() + EXPECT_CALL(connection, MaxSendStreamSize()).WillOnce(testing::Return(1000)); + EXPECT_CALL(connection, RequestSendStream(38)); + serviceProxy.RequestSend([&serviceProxy]() { - onGranted.callback(); + serviceProxy.Method(5); }); infra::ByteOutputStreamWriter::WithStorage<128> writer; auto writerPtr = infra::UnOwnedSharedPtr(writer); - EXPECT_CALL(onGranted, callback()); connection.Observer().SendStreamAvailable(writerPtr); - serviceProxy.Method(5); EXPECT_EQ((std::vector{ 1, 10, 2, 8, 5 }), (std::vector(writer.Storage().begin(), writer.Storage().begin() + 5))); } TEST_F(EchoOnConnectionTest, service_method_is_invoked) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 10, 2, 8, 5 }), infra::Head(infra::MakeRange(reader.Storage()), 5)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(emptyReaderPtr)); - EXPECT_CALL(service, Method(5)); - EXPECT_CALL(connection, AckReceived()); - connection.Observer().DataReceived(); -} - -TEST_F(EchoOnConnectionTest, on_partial_message_service_method_is_not_invoked) -{ - infra::ByteInputStreamReader::WithStorage<4> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 10, 2, 8 }), infra::Head(infra::MakeRange(reader.Storage()), 4)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 1, 10, 2, 8, 5 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); + EXPECT_CALL(service, Method(5)).WillOnce(testing::Invoke([this]() + { + service.MethodDone(); + })); + EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); } TEST_F(EchoOnConnectionTest, service_method_is_invoked_twice) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 10, 2, 8, 5 }), infra::Head(infra::MakeRange(reader.Storage()), 5)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<128> reader2; - infra::Copy(infra::MakeRange(std::array{ 1, 10, 2, 8, 5 }), infra::Head(infra::MakeRange(reader2.Storage()), 5)); - auto reader2Ptr = infra::UnOwnedSharedPtr(reader2); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(reader2Ptr)); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 1, 10, 2, 8, 5, 1, 10, 2, 8, 6 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); + + EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); EXPECT_CALL(service, Method(5)); EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); - reader2.Rewind(0); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(reader2Ptr)).WillOnce(testing::Return(emptyReaderPtr)); - EXPECT_CALL(service, Method(5)); + EXPECT_CALL(service, Method(6)).WillOnce(testing::Invoke([this]() + { + service.MethodDone(); + })); EXPECT_CALL(connection, AckReceived()); service.MethodDone(); - ExecuteAllActions(); } TEST_F(EchoOnConnectionTest, MessageFormatError_is_reported_when_message_is_not_a_LengthDelimited) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 0, 2 }), infra::Head(infra::MakeRange(reader.Storage()), 3)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(emptyReaderPtr)); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 1, 0, 2 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); + + EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); EXPECT_CALL(errorPolicy, MessageFormatError()); EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); @@ -105,12 +87,10 @@ TEST_F(EchoOnConnectionTest, MessageFormatError_is_reported_when_message_is_not_ TEST_F(EchoOnConnectionTest, MessageFormatError_is_reported_when_message_is_of_unknown_type) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 6 }), infra::Head(infra::MakeRange(reader.Storage()), 2)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(emptyReaderPtr)); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 1, 6 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); + + EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); EXPECT_CALL(errorPolicy, MessageFormatError()); EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); @@ -118,12 +98,10 @@ TEST_F(EchoOnConnectionTest, MessageFormatError_is_reported_when_message_is_of_u TEST_F(EchoOnConnectionTest, MessageFormatError_is_reported_when_parameter_in_message_is_of_incorrect_type) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 10, 2, 13, 5, 0, 0, 0 }), infra::Head(infra::MakeRange(reader.Storage()), 8)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(emptyReaderPtr)); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 1, 10, 5, 13, 5, 0, 0, 0 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); + + EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); EXPECT_CALL(errorPolicy, MessageFormatError()); EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); @@ -131,12 +109,10 @@ TEST_F(EchoOnConnectionTest, MessageFormatError_is_reported_when_parameter_in_me TEST_F(EchoOnConnectionTest, ServiceNotFound_is_reported) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 2, 10, 2, 8, 5 }), infra::Head(infra::MakeRange(reader.Storage()), 5)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(emptyReaderPtr)); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 2, 10, 2, 8, 5 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); + + EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); EXPECT_CALL(errorPolicy, ServiceNotFound(2)); EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); @@ -144,12 +120,10 @@ TEST_F(EchoOnConnectionTest, ServiceNotFound_is_reported) TEST_F(EchoOnConnectionTest, MethodNotFound_is_reported) { - infra::ByteInputStreamReader::WithStorage<128> reader; - infra::Copy(infra::MakeRange(std::array{ 1, 18, 2, 8, 5 }), infra::Head(infra::MakeRange(reader.Storage()), 5)); - auto readerPtr = infra::UnOwnedSharedPtr(reader); - infra::ByteInputStreamReader::WithStorage<0> emptyReader; - auto emptyReaderPtr = infra::UnOwnedSharedPtr(emptyReader); - EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)).WillOnce(testing::Return(emptyReaderPtr)); + infra::StdVectorInputStream::WithStorage stream(infra::inPlace, std::vector{ 1, 18, 2, 8, 5 }); + auto readerPtr = infra::UnOwnedSharedPtr(stream.Reader()); + + EXPECT_CALL(connection, ReceiveStream()).WillOnce(testing::Return(readerPtr)); EXPECT_CALL(errorPolicy, MethodNotFound(1, 2)); EXPECT_CALL(connection, AckReceived()); connection.Observer().DataReceived(); diff --git a/services/util/EchoInstantiation.hpp b/services/util/EchoInstantiation.hpp index f7d85e7eb..a194b610d 100644 --- a/services/util/EchoInstantiation.hpp +++ b/services/util/EchoInstantiation.hpp @@ -12,8 +12,9 @@ namespace main_ template struct EchoOnSerialCommunication { - explicit EchoOnSerialCommunication(hal::SerialCommunication& serialCommunication) + explicit EchoOnSerialCommunication(hal::SerialCommunication& serialCommunication, services::MethodSerializerFactory& serializerFactory) : cobs(serialCommunication) + , echo(windowed, serializerFactory) {} operator services::Echo&() @@ -23,7 +24,7 @@ namespace main_ services::MessageCommunicationCobs::WithMaxMessageSize cobs; services::MessageCommunicationWindowed::WithReceiveBuffer windowed{ cobs }; - services::EchoOnMessageCommunication echo{ windowed }; + services::EchoOnMessageCommunication echo; }; template @@ -56,14 +57,14 @@ namespace main_ services::Echo& from; services::Echo& to; - typename infra::BoundedVector>::template WithMaxSize forwarders; + typename infra::BoundedVector::template WithMaxSize forwarders; }; template struct EchoForwarderToSerial { - EchoForwarderToSerial(services::Echo& from, hal::SerialCommunication& toSerial) - : to(toSerial) + EchoForwarderToSerial(services::Echo& from, hal::SerialCommunication& toSerial, services::MethodSerializerFactory& serializerFactory) + : to(toSerial, serializerFactory) , echoForwarder(from, to) {} diff --git a/services/util/EchoOnMessageCommunication.cpp b/services/util/EchoOnMessageCommunication.cpp index 30ab77651..391d1cca0 100644 --- a/services/util/EchoOnMessageCommunication.cpp +++ b/services/util/EchoOnMessageCommunication.cpp @@ -2,8 +2,8 @@ namespace services { - EchoOnMessageCommunication::EchoOnMessageCommunication(MessageCommunication& subject, EchoErrorPolicy& errorPolicy) - : EchoOnStreams(errorPolicy) + EchoOnMessageCommunication::EchoOnMessageCommunication(MessageCommunication& subject, services::MethodSerializerFactory& serializerFactory, const EchoErrorPolicy& errorPolicy) + : EchoOnStreams(serializerFactory, errorPolicy) , MessageCommunicationObserver(subject) {} @@ -12,35 +12,19 @@ namespace services void EchoOnMessageCommunication::SendMessageStreamAvailable(infra::SharedPtr&& writer) { - SetStreamWriter(std::move(writer)); + EchoOnStreams::SendStreamAvailable(std::move(writer)); } void EchoOnMessageCommunication::ReceivedMessage(infra::SharedPtr&& reader) { - this->reader = std::move(reader); - ProcessMessage(); - } - - void EchoOnMessageCommunication::ServiceDone(Service& service) - { - reader = nullptr; - EchoOnStreams::ServiceDone(service); + DataReceived(std::move(reader)); } void EchoOnMessageCommunication::RequestSendStream(std::size_t size) { - MessageCommunicationObserver::Subject().RequestSendMessage(static_cast(size)); + MessageCommunicationObserver::Subject().RequestSendMessage(static_cast(std::min(size, MessageCommunicationObserver::Subject().MaxSendMessageSize()))); } - void EchoOnMessageCommunication::BusyServiceDone() - { - // In this class, services are never busy, so BusyServiceDone() is never invoked - std::abort(); - } - - void EchoOnMessageCommunication::ProcessMessage() - { - if (!EchoOnStreams::ProcessMessage(*reader)) - errorPolicy.MessageFormatError(); - } + void EchoOnMessageCommunication::AckReceived() + {} } diff --git a/services/util/EchoOnMessageCommunication.hpp b/services/util/EchoOnMessageCommunication.hpp index 1f7068e88..a7b93a995 100644 --- a/services/util/EchoOnMessageCommunication.hpp +++ b/services/util/EchoOnMessageCommunication.hpp @@ -11,24 +11,20 @@ namespace services , public MessageCommunicationObserver { public: - EchoOnMessageCommunication(MessageCommunication& subject, EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); + EchoOnMessageCommunication(MessageCommunication& subject, services::MethodSerializerFactory& serializerFactory, const EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); // Implementation of MessageCommunicationObserver void Initialized() override; void SendMessageStreamAvailable(infra::SharedPtr&& writer) override; void ReceivedMessage(infra::SharedPtr&& reader) override; - void ServiceDone(Service& service) override; - protected: + // Implementation of EchoOnStreams void RequestSendStream(std::size_t size) override; - void BusyServiceDone() override; + void AckReceived() override; private: void ProcessMessage(); - - private: - infra::SharedPtr reader; }; } diff --git a/services/util/EchoOnMessageCommunicationSymmetricKey.cpp b/services/util/EchoOnMessageCommunicationSymmetricKey.cpp index f5c726aaf..eaea7d4b4 100644 --- a/services/util/EchoOnMessageCommunicationSymmetricKey.cpp +++ b/services/util/EchoOnMessageCommunicationSymmetricKey.cpp @@ -20,8 +20,8 @@ namespace services } } - EchoOnMessageCommunicationSymmetricKey::EchoOnMessageCommunicationSymmetricKey(MessageCommunicationSecured& secured, hal::SynchronousRandomDataGenerator& randomDataGenerator, EchoErrorPolicy& errorPolicy) - : EchoOnMessageCommunication(secured, errorPolicy) + EchoOnMessageCommunicationSymmetricKey::EchoOnMessageCommunicationSymmetricKey(MessageCommunicationSecured& secured, MethodSerializerFactory& serializerFactory, hal::SynchronousRandomDataGenerator& randomDataGenerator, const EchoErrorPolicy& errorPolicy) + : EchoOnMessageCommunication(secured, serializerFactory, errorPolicy) , SymmetricKeyEstablishment(static_cast(*this)) , SymmetricKeyEstablishmentProxy(static_cast(*this)) , secured(secured) @@ -46,7 +46,7 @@ namespace services auto key = randomDataGenerator.GenerateRandomData(); auto iv = randomDataGenerator.GenerateRandomData(); SymmetricKeyEstablishmentProxy::ActivateNewKeyMaterial(Convert(key), Convert(iv)); - secured.SetSendKey(key, iv); + secured.SetNextSendKey(key, iv); initializingSending = false; ReQueueWaitingProxies(); diff --git a/services/util/EchoOnMessageCommunicationSymmetricKey.hpp b/services/util/EchoOnMessageCommunicationSymmetricKey.hpp index 0541a21a8..29ab18bf8 100644 --- a/services/util/EchoOnMessageCommunicationSymmetricKey.hpp +++ b/services/util/EchoOnMessageCommunicationSymmetricKey.hpp @@ -14,7 +14,7 @@ namespace services , private message_communication_security::SymmetricKeyEstablishmentProxy { public: - EchoOnMessageCommunicationSymmetricKey(MessageCommunicationSecured& secured, hal::SynchronousRandomDataGenerator& randomDataGenerator, EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); + EchoOnMessageCommunicationSymmetricKey(MessageCommunicationSecured& secured, MethodSerializerFactory& serializerFactory, hal::SynchronousRandomDataGenerator& randomDataGenerator, const EchoErrorPolicy& errorPolicy = echoErrorPolicyAbortOnMessageFormatError); // Implementation of Echo void RequestSend(ServiceProxy& serviceProxy) override; diff --git a/services/util/MessageCommunicationSecured.cpp b/services/util/MessageCommunicationSecured.cpp index 32a5be95b..2e6f41569 100644 --- a/services/util/MessageCommunicationSecured.cpp +++ b/services/util/MessageCommunicationSecured.cpp @@ -27,10 +27,12 @@ namespace services mbedtls_gcm_free(&sendContext); } - void MessageCommunicationSecured::SetSendKey(const KeyType& sendKey, const IvType& sendIv) + void MessageCommunicationSecured::SetNextSendKey(const KeyType& sendKey, const IvType& sendIv) { - mbedtls_gcm_setkey(&sendContext, MBEDTLS_CIPHER_ID_AES, reinterpret_cast(sendKey.data()), sendKey.size() * 8); //NOSONAR - this->sendIv = sendIv; + nextKeys = { sendKey, sendIv }; + + if (sendWriter == nullptr) + ActivateSendKey(); } void MessageCommunicationSecured::SetReceiveKey(const KeyType& receiveKey, const IvType& receiveIv) @@ -58,6 +60,18 @@ namespace services return std::min(MessageCommunicationObserver::Subject().MaxSendMessageSize(), sendBuffer.max_size()) - blockSize; } + void MessageCommunicationSecured::SetSendKey(const KeyType& sendKey, const IvType& sendIv) + { + mbedtls_gcm_setkey(&sendContext, MBEDTLS_CIPHER_ID_AES, reinterpret_cast(sendKey.data()), sendKey.size() * 8); //NOSONAR + this->sendIv = sendIv; + } + + void MessageCommunicationSecured::ActivateSendKey() + { + SetSendKey(nextKeys->first, nextKeys->second); + nextKeys = infra::none; + } + void MessageCommunicationSecured::SendMessageStreamAvailable(infra::SharedPtr&& writer) { sendWriter = std::move(writer); @@ -143,6 +157,9 @@ namespace services sendBuffer.clear(); IncreaseIv(sendIv); sendWriter = nullptr; + + if (nextKeys) + ActivateSendKey(); } void MessageCommunicationSecured::IncreaseIv(infra::ByteRange iv) const diff --git a/services/util/MessageCommunicationSecured.hpp b/services/util/MessageCommunicationSecured.hpp index 8ac9bf048..bbc2d7f02 100644 --- a/services/util/MessageCommunicationSecured.hpp +++ b/services/util/MessageCommunicationSecured.hpp @@ -28,7 +28,7 @@ namespace services MessageCommunicationSecured(infra::BoundedVector& sendBuffer, infra::BoundedVector& receiveBuffer, MessageCommunication& delegate, const KeyType& sendKey, const IvType& sendIv, const KeyType& receiveKey, const IvType& receiveIv); ~MessageCommunicationSecured(); - void SetSendKey(const KeyType& sendKey, const IvType& sendIv); + void SetNextSendKey(const KeyType& sendKey, const IvType& sendIv); void SetReceiveKey(const KeyType& receiveKey, const IvType& receiveIv); // Implementation of MessageCommunication @@ -41,6 +41,8 @@ namespace services void SendMessageStreamAvailable(infra::SharedPtr&& writer) override; void ReceivedMessage(infra::SharedPtr&& reader) override; + void SetSendKey(const KeyType& sendKey, const IvType& sendIv); + void ActivateSendKey(); void SendMessageStreamReleased(); void IncreaseIv(infra::ByteRange iv) const; @@ -67,6 +69,7 @@ namespace services SendMessageStreamReleased(); } }; uint16_t requestedSendSize = 0; + infra::Optional> nextKeys; mbedtls_gcm_context receiveContext; infra::BoundedVector& receiveBuffer; diff --git a/services/util/test/TestEchoOnMessageCommunication.cpp b/services/util/test/TestEchoOnMessageCommunication.cpp index 63c05e6ef..4b5267989 100644 --- a/services/util/test/TestEchoOnMessageCommunication.cpp +++ b/services/util/test/TestEchoOnMessageCommunication.cpp @@ -2,11 +2,23 @@ #include "infra/stream/ByteInputStream.hpp" #include "infra/stream/ByteOutputStream.hpp" #include "infra/util/ConstructBin.hpp" +#include "infra/util/SharedOptional.hpp" #include "infra/util/test_helper/MockCallback.hpp" #include "protobuf/echo/test_doubles/EchoMock.hpp" #include "protobuf/echo/test_doubles/ServiceStub.hpp" #include "services/network/test_doubles/ConnectionMock.hpp" #include "services/util/EchoOnMessageCommunication.hpp" +#include "services/util/test_doubles/MessageCommunicationMock.hpp" + +namespace services +{ + class MethodSerializerMock + : public MethodSerializer + { + public: + MOCK_METHOD(bool, Serialize, (infra::SharedPtr && writer), (override)); + }; +} class EchoOnMessageCommunicationTest : public testing::Test @@ -19,41 +31,63 @@ class EchoOnMessageCommunicationTest messageCommunication.GetObserver().ReceivedMessage(infra::UnOwnedSharedPtr(reader)); } + services::MethodSerializerFactory::ForServices::AndProxies serializerFactory; testing::StrictMock errorPolicy; testing::StrictMock messageCommunication; - services::EchoOnMessageCommunication echo{ messageCommunication, errorPolicy }; + services::EchoOnMessageCommunication echo{ messageCommunication, serializerFactory, errorPolicy }; services::ServiceStubProxy serviceProxy{ echo }; testing::StrictMock service{ echo }; + + infra::SharedOptional> serializer; }; TEST_F(EchoOnMessageCommunicationTest, invoke_service_proxy_method) { - testing::StrictMock> onGranted; - EXPECT_CALL(messageCommunication, RequestSendMessage(18)); - serviceProxy.RequestSend([&onGranted]() + EXPECT_CALL(messageCommunication, MaxSendMessageSize()).WillOnce(testing::Return(1000)); + EXPECT_CALL(messageCommunication, RequestSendMessage(38)); + serviceProxy.RequestSend([this]() { - onGranted.callback(); + serviceProxy.Method(5); }); infra::ByteOutputStreamWriter::WithStorage<128> writer; - EXPECT_CALL(onGranted, callback()); messageCommunication.GetObserver().SendMessageStreamAvailable(infra::UnOwnedSharedPtr(writer)); - serviceProxy.Method(5); - EXPECT_EQ((std::vector{ 1, 10, 2, 8, 5 }), (std::vector(writer.Storage().begin(), writer.Storage().begin() + 5))); + EXPECT_EQ((std::vector{ 1, (1 << 3) | 2, 2, 8, 5 }), (std::vector(writer.Storage().begin(), writer.Storage().begin() + 5))); +} + +TEST_F(EchoOnMessageCommunicationTest, invoke_service_proxy_method_without_parameters) +{ + EXPECT_CALL(messageCommunication, MaxSendMessageSize()).WillOnce(testing::Return(1000)); + EXPECT_CALL(messageCommunication, RequestSendMessage(38)); + serviceProxy.RequestSend([this]() + { + serviceProxy.MethodNoParameter(); + }); + + infra::ByteOutputStreamWriter::WithStorage<128> writer; + messageCommunication.GetObserver().SendMessageStreamAvailable(infra::UnOwnedSharedPtr(writer)); + + EXPECT_EQ((std::vector{ 1, (3 << 3) | 2, 0 }), (std::vector(writer.Storage().begin(), writer.Storage().begin() + 3))); } TEST_F(EchoOnMessageCommunicationTest, service_method_is_invoked) { - EXPECT_CALL(service, Method(5)); + EXPECT_CALL(service, Method(5)).WillOnce(testing::Invoke([this]() + { + service.MethodDone(); + })); ReceiveMessage(infra::ConstructBin()({ 1, 10, 2, 8, 5 }).Range()); } -TEST_F(EchoOnMessageCommunicationTest, on_partial_MessageFormatError_is_reported) +TEST_F(EchoOnMessageCommunicationTest, service_method_without_parameter_is_invoked) { - EXPECT_CALL(errorPolicy, MessageFormatError()); - ReceiveMessage(infra::ConstructBin()({ 1, 10, 2, 8 }).Range()); + EXPECT_CALL(service, MethodNoParameter()).WillOnce(testing::Invoke([this]() + { + service.MethodDone(); + })); + ReceiveMessage(infra::ConstructBin()({ 1, (3 << 3) | 2, 0 }).Range()); } TEST_F(EchoOnMessageCommunicationTest, MessageFormatError_is_reported_when_message_is_not_a_LengthDelimited) @@ -71,7 +105,7 @@ TEST_F(EchoOnMessageCommunicationTest, MessageFormatError_is_reported_when_messa TEST_F(EchoOnMessageCommunicationTest, MessageFormatError_is_reported_when_parameter_in_message_is_of_incorrect_type) { EXPECT_CALL(errorPolicy, MessageFormatError()); - ReceiveMessage(infra::ConstructBin()({ 1, 10, 2, 13, 5, 0, 0, 0 }).Range()); + ReceiveMessage(infra::ConstructBin()({ 1, 10, 5, 13, 5, 0, 0, 0 }).Range()); } TEST_F(EchoOnMessageCommunicationTest, ServiceNotFound_is_reported) diff --git a/services/util/test/TestEchoOnMessageCommunicationSymmetricKey.cpp b/services/util/test/TestEchoOnMessageCommunicationSymmetricKey.cpp index d92a78e4c..ecc30d6a2 100644 --- a/services/util/test/TestEchoOnMessageCommunicationSymmetricKey.cpp +++ b/services/util/test/TestEchoOnMessageCommunicationSymmetricKey.cpp @@ -6,6 +6,7 @@ #include "protobuf/echo/test_doubles/ServiceStub.hpp" #include "services/network/test_doubles/ConnectionMock.hpp" #include "services/util/EchoOnMessageCommunicationSymmetricKey.hpp" +#include "services/util/test_doubles/MessageCommunicationMock.hpp" class EchoOnMessageCommunicationSymmetricKeyTest : public testing::Test @@ -54,13 +55,14 @@ class EchoOnMessageCommunicationSymmetricKeyTest ASSERT_TRUE(reader.Allocatable()); } + services::MethodSerializerFactory::ForServices::AndProxies serializerFactory; testing::StrictMock errorPolicy; testing::StrictMock randomDataGenerator; testing::StrictMock lower; std::array key{ 1, 2 }; std::array iv{ 1, 3 }; services::MessageCommunicationSecured::WithBuffers<64> secured{ lower, key, iv, key, iv }; - services::EchoOnMessageCommunicationSymmetricKey echo{ secured, randomDataGenerator, errorPolicy }; + services::EchoOnMessageCommunicationSymmetricKey echo{ secured, serializerFactory, randomDataGenerator, errorPolicy }; services::ServiceStubProxy serviceProxy{ echo }; testing::StrictMock service{ echo }; diff --git a/services/util/test/TestMessageCommunicationSecured.cpp b/services/util/test/TestMessageCommunicationSecured.cpp index e1334999e..6f6877bbe 100644 --- a/services/util/test/TestMessageCommunicationSecured.cpp +++ b/services/util/test/TestMessageCommunicationSecured.cpp @@ -110,7 +110,7 @@ TEST_F(MessageCommunicationSecuredTest, key_change_to_default_key_results_in_sam auto first = sentData; Receive("abcd"); - secured.SetSendKey(key, iv); + secured.SetNextSendKey(key, iv); secured.SetReceiveKey(key, iv); Send("abcd"); @@ -128,7 +128,7 @@ TEST_F(MessageCommunicationSecuredTest, key_change_to_different_key_results_in_d std::array key2{ 1, 2, 1 }; std::array iv2{ 1, 3, 1 }; - secured.SetSendKey(key2, iv2); + secured.SetNextSendKey(key2, iv2); Send("abcd"); auto second = sentData; @@ -144,7 +144,7 @@ TEST_F(MessageCommunicationSecuredTest, initialization_results_in_default_keys) std::array key2{ 1, 2, 1 }; std::array iv2{ 1, 3, 1 }; - secured.SetSendKey(key2, iv2); + secured.SetNextSendKey(key2, iv2); EXPECT_CALL(upper, Initialized()); lower.GetObserver().Initialized(); From 67fcfd16e87f4d089d2a267b41e1a805cae21660 Mon Sep 17 00:00:00 2001 From: Ron <45816308+rjaegers@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:53:28 +0100 Subject: [PATCH 37/37] chore(main): release 5.0.0 (#326) --- .release-please-manifest.json | 2 +- CHANGELOG.md | 32 ++++++++++++++++++++++++ CMakeLists.txt | 2 +- documents/antora.yml | 2 +- protobuf/echo/protocol_buffer_echo.cmake | 2 +- sonar-project.properties | 2 +- 6 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e6f877563..32dbe0e2b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.0.0" + ".": "5.0.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b9b3070ff..3132e1fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,38 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +## [5.0.0](https://github.com/philips-software/amp-embedded-infra-lib/compare/v4.0.0...v5.0.0) (2023-11-09) + + +### ⚠ BREAKING CHANGES + +* generic pairing/bonding classes updated ([#330](https://github.com/philips-software/amp-embedded-infra-lib/issues/330)) +* ble interface improvements ([#300](https://github.com/philips-software/amp-embedded-infra-lib/issues/300)) + +### Features + +* Add protobuf/echo/ProtoMessageBuilder ([#416](https://github.com/philips-software/amp-embedded-infra-lib/issues/416)) ([f5260dd](https://github.com/philips-software/amp-embedded-infra-lib/commit/f5260dd65ae4adfea14755dfef04a18074441951)) +* Add ServiceProxyResponseQueue ([#338](https://github.com/philips-software/amp-embedded-infra-lib/issues/338)) ([88cb197](https://github.com/philips-software/amp-embedded-infra-lib/commit/88cb197acb2f38d3b6fad00f88983cf15d49c864)) +* Add streaming of little endian mac addresses ([#336](https://github.com/philips-software/amp-embedded-infra-lib/issues/336)) ([e3d7fd8](https://github.com/philips-software/amp-embedded-infra-lib/commit/e3d7fd8f12ad934b98a86a6b27d8f574049f12b3)) +* Added SerialCommunicationLoopback ([#440](https://github.com/philips-software/amp-embedded-infra-lib/issues/440)) ([2c87dfb](https://github.com/philips-software/amp-embedded-infra-lib/commit/2c87dfb5ecd1e76669af69a97f80c29bfab773b9)) +* Ble interface improvements ([#300](https://github.com/philips-software/amp-embedded-infra-lib/issues/300)) ([88a4689](https://github.com/philips-software/amp-embedded-infra-lib/commit/88a4689e8f08e2afe856170aa5b5036f69d1610c)) +* Generic pairing/bonding classes updated ([#330](https://github.com/philips-software/amp-embedded-infra-lib/issues/330)) ([dbda405](https://github.com/philips-software/amp-embedded-infra-lib/commit/dbda405cc2ef2d356fbe707df5389042a49c7959)) +* Removed Dac.hpp ([#439](https://github.com/philips-software/amp-embedded-infra-lib/issues/439)) ([4b52156](https://github.com/philips-software/amp-embedded-infra-lib/commit/4b5215609b9ee2a6ca72d8d660b8c797aa3e31c9)) +* Support payloads bigger than the MaxSendStreamSize ([#331](https://github.com/philips-software/amp-embedded-infra-lib/issues/331)) ([c411f66](https://github.com/philips-software/amp-embedded-infra-lib/commit/c411f66f7ae972786a7fa1134989ab8e4f0631aa)) +* Support streaming echo messages ([#435](https://github.com/philips-software/amp-embedded-infra-lib/issues/435)) ([07756bb](https://github.com/philips-software/amp-embedded-infra-lib/commit/07756bb41f068adbf3a2eb76adb2778fff5491f0)) + + +### Bug Fixes + +* Add acd sources to lwip ([#400](https://github.com/philips-software/amp-embedded-infra-lib/issues/400)) ([a4f68ef](https://github.com/philips-software/amp-embedded-infra-lib/commit/a4f68efdf19e7b556cb6fe2cba0165908f56be8c)) +* Added workaround mbedtls and clang-cl incomatibility ([#441](https://github.com/philips-software/amp-embedded-infra-lib/issues/441)) ([063b595](https://github.com/philips-software/amp-embedded-infra-lib/commit/063b59508f1d09c2675b338c7b54d64934f7792c)) +* Cpp:S6232 well-defined type-punning method should be used instead of a union-based one ([d809c17](https://github.com/philips-software/amp-embedded-infra-lib/commit/d809c173cacefd3bf2d661718111d5d301a95fc1)) +* Destruction of HttpClientJson while resetting the reader resulted in memory corruption ([#404](https://github.com/philips-software/amp-embedded-infra-lib/issues/404)) ([ed8a8a0](https://github.com/philips-software/amp-embedded-infra-lib/commit/ed8a8a0e5893074fc56fde94cfdb003a870e930c)) +* Detaching HttpClient while in HeaderAvailable resulted in a crash ([#406](https://github.com/philips-software/amp-embedded-infra-lib/issues/406)) ([a905a30](https://github.com/philips-software/amp-embedded-infra-lib/commit/a905a306be194c7cf6380e70cf83b668c8d27425)) +* Enable service scoping of method invocations in services.echo_console ([#325](https://github.com/philips-software/amp-embedded-infra-lib/issues/325)) ([7090a40](https://github.com/philips-software/amp-embedded-infra-lib/commit/7090a407f50d89073c468381e5207f1c0f56b6c1)) +* UpgradePackBuilderFacade setting mbedtls global memory pool on stack ([#324](https://github.com/philips-software/amp-embedded-infra-lib/issues/324)) ([ec567d5](https://github.com/philips-software/amp-embedded-infra-lib/commit/ec567d511f40eb3c0962ac4b6ac3479f64c0a871)) +* UpgradePackBuilderFacade setting mbedtls global memory pool on stack, causing a crash when combined with ConnectionMbedTls ([ec567d5](https://github.com/philips-software/amp-embedded-infra-lib/commit/ec567d511f40eb3c0962ac4b6ac3479f64c0a871)) + ## [4.0.0](https://github.com/philips-software/amp-embedded-infra-lib/compare/v3.2.0...v4.0.0) (2023-06-02) diff --git a/CMakeLists.txt b/CMakeLists.txt index e80f35eb0..a42903f04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ if (APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") endif() -project(emil LANGUAGES C CXX VERSION 4.0.0) # x-release-please-version +project(emil LANGUAGES C CXX VERSION 5.0.0) # x-release-please-version set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED On) diff --git a/documents/antora.yml b/documents/antora.yml index 8cd191ba9..b226c2ad7 100644 --- a/documents/antora.yml +++ b/documents/antora.yml @@ -1,5 +1,5 @@ name: embedded_infrastructure_library title: Embedded Infrastructure Library documentation -version: 4.0.0 # x-release-please-version +version: 5.0.0 # x-release-please-version nav: - modules/ROOT/nav.adoc diff --git a/protobuf/echo/protocol_buffer_echo.cmake b/protobuf/echo/protocol_buffer_echo.cmake index ef1bf83bb..c7b12dd14 100644 --- a/protobuf/echo/protocol_buffer_echo.cmake +++ b/protobuf/echo/protocol_buffer_echo.cmake @@ -17,7 +17,7 @@ function(emil_fetch_echo_plugins) return() endif() - set(emil_version "4.0.0") # x-release-please-version + set(emil_version "5.0.0") # x-release-please-version if (CMAKE_HOST_WIN32) set(os_postfix "win64") diff --git a/sonar-project.properties b/sonar-project.properties index c91e052d0..18f44511a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization=philips-software sonar.projectName=embeddedinfralib # x-release-please-start-version -sonar.projectVersion=4.0.0 +sonar.projectVersion=5.0.0 # x-release-please-end sonar.links.homepage=https://github.com/philips-software/amp-embedded-infra-lib