This is an automated email from the ASF dual-hosted git repository.

hgruszecki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new 88f43f525 feat(cpp): add bazel building and testing infrastructure 
(#2785)
88f43f525 is described below

commit 88f43f5251764848ad5dffcbde74eaea94c7dbce
Author: Rimuksh Kansal <[email protected]>
AuthorDate: Tue Mar 3 17:03:24 2026 +0900

    feat(cpp): add bazel building and testing infrastructure (#2785)
---
 .github/actions/cpp-bazel/pre-merge/action.yml     |  80 ++++++
 .../actions/utils/setup-cpp-with-cache/action.yml  |  37 +++
 .github/config/components.yml                      |   9 +
 .github/workflows/_detect.yml                      |  11 +-
 .github/workflows/_test.yml                        |  21 +-
 .github/workflows/pre-merge.yml                    |  21 +-
 Cargo.toml                                         |   2 +-
 foreign/cpp/.bazelrc                               |  54 ++++
 foreign/cpp/.bazelversion                          |   1 +
 foreign/cpp/.clang-format                          |  31 +++
 foreign/cpp/.gitignore                             |   1 +
 foreign/cpp/BUILD.bazel                            | 115 ++++++++
 foreign/cpp/Cargo.lock                             | 291 +++++++++++++++++++++
 foreign/cpp/Cargo.toml                             |  33 +++
 foreign/cpp/MODULE.bazel                           |  24 ++
 foreign/cpp/MODULE.bazel.lock                      | 272 +++++++++++++++++++
 foreign/cpp/README.md                              |  10 +
 foreign/cpp/build.rs                               |  24 ++
 foreign/cpp/include/iggy.hpp                       | 120 +++++++++
 foreign/cpp/src/lib.rs                             |  20 ++
 foreign/cpp/tests/test.cpp                         |  85 ++++++
 21 files changed, 1252 insertions(+), 10 deletions(-)

diff --git a/.github/actions/cpp-bazel/pre-merge/action.yml 
b/.github/actions/cpp-bazel/pre-merge/action.yml
new file mode 100644
index 000000000..8f7e6d10b
--- /dev/null
+++ b/.github/actions/cpp-bazel/pre-merge/action.yml
@@ -0,0 +1,80 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: cpp-bazel-pre-merge
+description: C++ pre-merge testing github iggy actions
+
+inputs:
+  task:
+    description: "Task to run (lint, build, test)"
+    required: true
+
+runs:
+  using: "composite"
+  steps:
+    - name: Setup Bazel with cache
+      uses: ./.github/actions/utils/setup-cpp-with-cache
+
+    - name: Setup Rust with cache
+      uses: ./.github/actions/utils/setup-rust-with-cache
+
+    - name: Install clang-format
+      if: inputs.task == 'lint'
+      shell: bash
+      run: |
+        if command -v clang-format-18 >/dev/null 2>&1; then
+          clang-format-18 --version
+          exit 0
+        fi
+        sudo apt-get update --yes
+        sudo apt-get install --yes clang-format-18
+        clang-format-18 --version
+
+    - name: Lint (clang-format)
+      if: inputs.task == 'lint'
+      shell: bash
+      run: |
+        cd foreign/cpp
+        mapfile -t files < <(find include src tests -type f \( -name '*.h' -o 
-name '*.hpp' -o -name '*.cc' -o -name '*.cpp' -o -name '*.cxx' \) | sort)
+
+        if [ "${#files[@]}" -eq 0 ]; then
+          echo "No C++ files found for clang-format check."
+          exit 0
+        fi
+
+        printf '%s\n' "${files[@]}" | xargs clang-format-18 --style=file 
--dry-run --Werror
+
+    - name: Build
+      if: inputs.task == 'build'
+      shell: bash
+      run: |
+        cd foreign/cpp
+        bazel build --config=ci //:iggy-cpp
+
+    - name: Test
+      if: inputs.task == 'test'
+      shell: bash
+      run: |
+        cd foreign/cpp
+        bazel test --config=ci //:iggy-cpp-test
+
+    - name: Validate task
+      if: inputs.task != 'lint' && inputs.task != 'build' && inputs.task != 
'test'
+      shell: bash
+      run: |
+        echo "::error::Unsupported task '${{ inputs.task }}'. Expected one of: 
lint, build, test."
+        exit 1
diff --git a/.github/actions/utils/setup-cpp-with-cache/action.yml 
b/.github/actions/utils/setup-cpp-with-cache/action.yml
new file mode 100644
index 000000000..bc15dbfe5
--- /dev/null
+++ b/.github/actions/utils/setup-cpp-with-cache/action.yml
@@ -0,0 +1,37 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: setup-cpp-with-cache
+description: Setup Bazel toolchain and caching (bazelisk + repository + disk 
cache)
+
+runs:
+  using: "composite"
+  steps:
+    - name: Setup Bazel with cache
+      uses: bazel-contrib/setup-bazel@8d2cb86a3680a820c3e219597279ce3f80d17a47
+      with:
+        bazelisk-cache: true
+        disk-cache: true
+        repository-cache: true
+        module-root: foreign/cpp
+
+    - name: Verify Bazel installation
+      shell: bash
+      run: |
+        echo "Bazel setup complete"
+        cd foreign/cpp
+        bazel --version
diff --git a/.github/config/components.yml b/.github/config/components.yml
index 6ea37faaa..1bd9717c1 100644
--- a/.github/config/components.yml
+++ b/.github/config/components.yml
@@ -224,6 +224,15 @@ components:
       - "examples/csharp/**"
     tasks: ["lint", "test", "build", "e2e"]
 
+  sdk-cpp:
+    depends_on:
+      - "rust-sdk"
+      - "rust-server"
+      - "ci-infrastructure"
+    paths:
+      - "foreign/cpp/**"
+    tasks: ["lint", "build", "test"]
+
   # Individual BDD tests per SDK - only run when specific SDK changes
   bdd-rust:
     depends_on:
diff --git a/.github/workflows/_detect.yml b/.github/workflows/_detect.yml
index 8fe50c889..15a358c51 100644
--- a/.github/workflows/_detect.yml
+++ b/.github/workflows/_detect.yml
@@ -38,6 +38,9 @@ on:
       csharp_matrix:
         description: "Matrix for C# SDK"
         value: ${{ jobs.detect.outputs.csharp_matrix }}
+      cpp_matrix:
+        description: "Matrix for C++ SDK"
+        value: ${{ jobs.detect.outputs.cpp_matrix }}
       bdd_matrix:
         description: "Matrix for BDD tests"
         value: ${{ jobs.detect.outputs.bdd_matrix }}
@@ -58,6 +61,7 @@ jobs:
       go_matrix: ${{ steps.mk.outputs.go_matrix }}
       java_matrix: ${{ steps.mk.outputs.java_matrix }}
       csharp_matrix: ${{ steps.mk.outputs.csharp_matrix }}
+      cpp_matrix: ${{ steps.mk.outputs.cpp_matrix }}
       bdd_matrix: ${{ steps.mk.outputs.bdd_matrix }}
       examples_matrix: ${{ steps.mk.outputs.examples_matrix }}
       other_matrix: ${{ steps.mk.outputs.other_matrix }}
@@ -223,7 +227,7 @@ jobs:
               console.log(`Total files changed: ${files.length}`);
             }
 
-            const groups = { rust:[], python:[], node:[], go:[], java:[], 
csharp:[], bdd:[], examples:[], other:[] };
+            const groups = { rust:[], python:[], node:[], go:[], java:[], 
csharp:[], cpp:[], bdd:[], examples:[], other:[] };
 
             // Process affected components and generate tasks
             console.log('');
@@ -250,6 +254,7 @@ jobs:
               else if (name === 'sdk-go') groups.go.push(...entries);
               else if (name === 'sdk-java') groups.java.push(...entries);
               else if (name === 'sdk-csharp') groups.csharp.push(...entries);
+              else if (name === 'sdk-cpp') groups.cpp.push(...entries);
               else if (name.startsWith('bdd-')) {
                 // Individual BDD tests should run separately with proper 
Docker setup
                 groups.bdd.push(...entries);
@@ -296,6 +301,7 @@ jobs:
               groups.go = [];
               groups.java = [];
               groups.csharp = [];
+              groups.cpp = [];
               groups.bdd = [];
               groups.examples = [];
               groups.other = [];
@@ -309,6 +315,7 @@ jobs:
                 else if (name === 'sdk-go') groups.go.push(...entries);
                 else if (name === 'sdk-java') groups.java.push(...entries);
                 else if (name === 'sdk-csharp') groups.csharp.push(...entries);
+                else if (name === 'sdk-cpp') groups.cpp.push(...entries);
                 else if (name.startsWith('bdd-')) groups.bdd.push(...entries);
                 else if (name === 'examples-suite') 
groups.examples.push(...entries);
                 else groups.other.push(...entries);
@@ -344,6 +351,7 @@ jobs:
               { name: 'Go SDK', tasks: groups.go },
               { name: 'Java SDK', tasks: groups.java },
               { name: 'C# SDK', tasks: groups.csharp },
+              { name: 'C++ SDK', tasks: groups.cpp },
               { name: 'BDD Tests', tasks: groups.bdd },
               { name: 'Examples', tasks: groups.examples },
               { name: 'Other', tasks: groups.other }
@@ -375,6 +383,7 @@ jobs:
             setOutput('go_matrix', JSON.stringify(matrix(groups.go)));
             setOutput('java_matrix', JSON.stringify(matrix(groups.java)));
             setOutput('csharp_matrix', JSON.stringify(matrix(groups.csharp)));
+            setOutput('cpp_matrix', JSON.stringify(matrix(groups.cpp)));
             setOutput('bdd_matrix', JSON.stringify(matrix(groups.bdd)));
             setOutput('examples_matrix', 
JSON.stringify(matrix(groups.examples)));
             setOutput('other_matrix', JSON.stringify(matrix(groups.other)));
diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml
index 1a10e89ac..e2b8d3487 100644
--- a/.github/workflows/_test.yml
+++ b/.github/workflows/_test.yml
@@ -140,6 +140,20 @@ jobs:
         with:
           task: ${{ inputs.task }}
 
+      # C# SDK
+      - name: Run C# SDK task
+        if: inputs.component == 'sdk-csharp'
+        uses: ./.github/actions/csharp-dotnet/pre-merge
+        with:
+          task: ${{ inputs.task }}
+
+      # C++ SDK
+      - name: Run C++ SDK Task
+        if: inputs.component == 'sdk-cpp'
+        uses: ./.github/actions/cpp-bazel/pre-merge
+        with:
+          task: ${{ inputs.task }}
+
       - name: Upload Java coverage to Codecov
         if: inputs.component == 'sdk-java' && inputs.task == 'test'
         uses: codecov/codecov-action@v5
@@ -152,13 +166,6 @@ jobs:
           verbose: true
           override_pr: ${{ github.event.pull_request.number }}
 
-      # C# SDK
-      - name: Run C# SDK task
-        if: inputs.component == 'sdk-csharp'
-        uses: ./.github/actions/csharp-dotnet/pre-merge
-        with:
-          task: ${{ inputs.task }}
-
       - name: Upload C# coverage to Codecov
         if: inputs.component == 'sdk-csharp' && (inputs.task == 'test' || 
inputs.task == 'e2e')
         uses: codecov/codecov-action@v5
diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml
index be2ceaf95..a3a976780 100644
--- a/.github/workflows/pre-merge.yml
+++ b/.github/workflows/pre-merge.yml
@@ -134,6 +134,19 @@ jobs:
     secrets:
       CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
 
+  # C++ SDK
+  test-cpp:
+    name: C++ • ${{ matrix.task }}
+    needs: detect
+    if: ${{ fromJson(needs.detect.outputs.cpp_matrix).include[0].component != 
'noop' }}
+    strategy:
+      fail-fast: false
+      matrix: ${{ fromJson(needs.detect.outputs.cpp_matrix) }}
+    uses: ./.github/workflows/_test.yml
+    with:
+      component: ${{ matrix.component }}
+      task: ${{ matrix.task }}
+
   # Other components
   test-other:
     name: Other • ${{ matrix.component }}/${{ matrix.task }}
@@ -177,7 +190,7 @@ jobs:
   status:
     name: CI Status
     runs-on: ubuntu-latest
-    needs: [common, detect, test-rust, test-python, test-node, test-go, 
test-java, test-csharp, test-bdd, test-examples, test-other]
+    needs: [common, detect, test-rust, test-python, test-node, test-go, 
test-java, test-csharp, test-cpp, test-bdd, test-examples, test-other]
     if: always()
     steps:
       - name: Get job execution times
@@ -259,6 +272,7 @@ jobs:
             const go = findJobInfo('Go •');
             const java = findJobInfo('Java •');
             const csharp = findJobInfo('C# •');
+            const cpp = findJobInfo('C++ •');
             const bdd = findJobInfo('BDD •');
             const examples = findJobInfo('Examples •');
             const other = findJobInfo('Other •');
@@ -278,6 +292,7 @@ jobs:
             core.setOutput('go_time', formatJobDuration(go));
             core.setOutput('java_time', formatJobDuration(java));
             core.setOutput('csharp_time', formatJobDuration(csharp));
+            core.setOutput('cpp_time', formatJobDuration(cpp));
             core.setOutput('bdd_time', formatJobDuration(bdd));
             core.setOutput('examples_time', formatJobDuration(examples));
             core.setOutput('other_time', formatJobDuration(other));
@@ -367,6 +382,7 @@ jobs:
           go_status=$(format_status "${{ needs.test-go.result }}" "${{ 
steps.times.outputs.go_time }}")
           java_status=$(format_status "${{ needs.test-java.result }}" "${{ 
steps.times.outputs.java_time }}")
           csharp_status=$(format_status "${{ needs.test-csharp.result }}" "${{ 
steps.times.outputs.csharp_time }}")
+          cpp_status=$(format_status "${{ needs.test-cpp.result }}" "${{ 
steps.times.outputs.cpp_time }}")
           bdd_status=$(format_status "${{ needs.test-bdd.result }}" "${{ 
steps.times.outputs.bdd_time }}")
           examples_status=$(format_status "${{ needs.test-examples.result }}" 
"${{ steps.times.outputs.examples_time }}")
           other_status=$(format_status "${{ needs.test-other.result }}" "${{ 
steps.times.outputs.other_time }}")
@@ -377,6 +393,7 @@ jobs:
           echo "| 🐹 Go | $go_status | ${{ steps.times.outputs.go_time }} |" >> 
$GITHUB_STEP_SUMMARY
           echo "| ☕ Java | $java_status | ${{ steps.times.outputs.java_time }} 
|" >> $GITHUB_STEP_SUMMARY
           echo "| 🔷 C# | $csharp_status | ${{ steps.times.outputs.csharp_time 
}} |" >> $GITHUB_STEP_SUMMARY
+          echo "| 🔶 C++ | $cpp_status | ${{ steps.times.outputs.cpp_time }} |" 
>> $GITHUB_STEP_SUMMARY
           echo "| 🧪 BDD | $bdd_status | ${{ steps.times.outputs.bdd_time }} |" 
>> $GITHUB_STEP_SUMMARY
           echo "| 📚 Examples | $examples_status | ${{ 
steps.times.outputs.examples_time }} |" >> $GITHUB_STEP_SUMMARY
           echo "| 📦 Other | $other_status | ${{ steps.times.outputs.other_time 
}} |" >> $GITHUB_STEP_SUMMARY
@@ -392,6 +409,7 @@ jobs:
              [[ "${{ needs.test-go.result }}" == "failure" ]] || \
              [[ "${{ needs.test-java.result }}" == "failure" ]] || \
              [[ "${{ needs.test-csharp.result }}" == "failure" ]] || \
+             [[ "${{ needs.test-cpp.result }}" == "failure" ]] || \
              [[ "${{ needs.test-bdd.result }}" == "failure" ]] || \
              [[ "${{ needs.test-examples.result }}" == "failure" ]] || \
              [[ "${{ needs.test-other.result }}" == "failure" ]]; then
@@ -406,6 +424,7 @@ jobs:
                [[ "${{ needs.test-go.result }}" == "cancelled" ]] || \
                [[ "${{ needs.test-java.result }}" == "cancelled" ]] || \
                [[ "${{ needs.test-csharp.result }}" == "cancelled" ]] || \
+               [[ "${{ needs.test-cpp.result }}" == "cancelled" ]] || \
                [[ "${{ needs.test-bdd.result }}" == "cancelled" ]] || \
                [[ "${{ needs.test-examples.result }}" == "cancelled" ]] || \
                [[ "${{ needs.test-other.result }}" == "cancelled" ]]; then
diff --git a/Cargo.toml b/Cargo.toml
index b09e40c39..dc2bb6641 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -55,7 +55,7 @@ members = [
     "core/tools",
     "examples/rust",
 ]
-exclude = ["foreign/python"]
+exclude = ["foreign/cpp", "foreign/python"]
 resolver = "2"
 
 [workspace.dependencies]
diff --git a/foreign/cpp/.bazelrc b/foreign/cpp/.bazelrc
new file mode 100644
index 000000000..51622b618
--- /dev/null
+++ b/foreign/cpp/.bazelrc
@@ -0,0 +1,54 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Bazel configuration for iggy C++ bindings
+
+# Enable BzlMod
+common --enable_bzlmod
+
+# Shared compiler warnings
+build --copt=-Wall
+build --copt=-Wpedantic
+build --copt=-Werror
+build --copt=-Wextra
+
+# Debug configuration
+build:debug --compilation_mode=dbg
+build:debug --copt=-g3
+build:debug --copt=-O0
+build:debug --copt=-fno-omit-frame-pointer
+build:debug --copt=-DDEBUG
+build:debug --strip=never
+build:debug --linkopt=-g
+
+# Release configuration
+build:release --compilation_mode=opt
+build:release --copt=-O2
+build:release --copt=-DNDEBUG
+build:release --strip=always
+
+# CI configuration
+common:ci --color=no
+common:ci --curses=no
+common:ci --announce_rc
+
+build:ci --config=release
+build:ci --lockfile_mode=error
+
+test:ci --lockfile_mode=error
+test:ci --test_output=errors
+test:ci --test_summary=detailed
diff --git a/foreign/cpp/.bazelversion b/foreign/cpp/.bazelversion
new file mode 100644
index 000000000..ae9a76b92
--- /dev/null
+++ b/foreign/cpp/.bazelversion
@@ -0,0 +1 @@
+8.0.0
diff --git a/foreign/cpp/.clang-format b/foreign/cpp/.clang-format
new file mode 100644
index 000000000..ad5ca1d0f
--- /dev/null
+++ b/foreign/cpp/.clang-format
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+BasedOnStyle: Chromium
+IndentWidth: 4
+ColumnLimit: 120
+BreakBeforeBraces: Custom
+IndentCaseLabels: true
+PointerAlignment: Right
+AlignOperands: true
+AlignConsecutiveAssignments: true
+AccessModifierOffset: -2
+AllowShortCaseLabelsOnASingleLine: false
+KeepEmptyLinesAtTheStartOfBlocks: true
+IndentPPDirectives: AfterHash
+IncludeBlocks: Preserve
diff --git a/foreign/cpp/.gitignore b/foreign/cpp/.gitignore
new file mode 100644
index 000000000..ac51a054d
--- /dev/null
+++ b/foreign/cpp/.gitignore
@@ -0,0 +1 @@
+bazel-*
diff --git a/foreign/cpp/BUILD.bazel b/foreign/cpp/BUILD.bazel
new file mode 100644
index 000000000..48e04a5d7
--- /dev/null
+++ b/foreign/cpp/BUILD.bazel
@@ -0,0 +1,115 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library", "cc_test")
+
+genrule(
+    name = "cargo_build",
+    srcs = glob(["src/**/*.rs"]) + [
+        "Cargo.toml",
+        "Cargo.lock",
+        "build.rs",
+    ],
+    outs = [
+        "libiggy_cpp.a",
+        "include/lib.rs.h",
+        "cxxbridge/rust/cxx.h",
+    ],
+    cmd = """
+        set -euo pipefail
+
+        CARGO="$$(command -v cargo)"
+        EXECROOT="$$(pwd)"
+        CARGO_TARGET_DIR="$$EXECROOT/$(@D)/cargo_target"
+        OUT_LIB="$$EXECROOT/$(location libiggy_cpp.a)"
+        OUT_RS="$$EXECROOT/$(location include/lib.rs.h)"
+        OUT_CXX="$$EXECROOT/$(location cxxbridge/rust/cxx.h)"
+
+        PROJECT_ROOT="$$(dirname $$(readlink -f $(location Cargo.toml)))"
+        cd "$$PROJECT_ROOT"
+
+        PROFILE="debug"
+        FLAGS=""
+        if [ "$(COMPILATION_MODE)" = "opt" ]; then
+            PROFILE="release"
+            FLAGS="--release"
+        fi
+
+        mkdir -p "$$CARGO_TARGET_DIR"
+        env -u PWD CARGO_TARGET_DIR="$$CARGO_TARGET_DIR" "$$CARGO" build 
$$FLAGS --locked
+
+        cp "$$CARGO_TARGET_DIR/$$PROFILE/libiggy_cpp.a" "$$OUT_LIB"
+
+        RS_HDR="$$(find "$$CARGO_TARGET_DIR/$$PROFILE/build" -name lib.rs.h 
-print -quit)"
+        if [ -z "$$RS_HDR" ]; then
+            echo "ERROR: Failed to locate generated lib.rs.h under 
$$CARGO_TARGET_DIR/$$PROFILE/build" >&2
+            exit 1
+        fi
+        cp "$$RS_HDR" "$$OUT_RS"
+
+        CXX_HDR="$$(find "$$CARGO_TARGET_DIR/$$PROFILE/build" -name cxx.h 
-print -quit)"
+        if [ -z "$$CXX_HDR" ]; then
+            echo "ERROR: Failed to locate generated cxx.h under 
$$CARGO_TARGET_DIR/$$PROFILE/build" >&2
+            exit 1
+        fi
+        cp "$$CXX_HDR" "$$OUT_CXX"
+    """,
+    local = 1,
+)
+
+cc_import(
+    name = "iggy_cpp_static",
+    static_library = ":libiggy_cpp.a",
+)
+
+cc_library(
+    name = "iggy-cpp",
+    srcs = glob([
+        "src/*.cpp",
+    ], allow_empty = True),
+    hdrs = [
+        "include/iggy.hpp",
+        ":include/lib.rs.h",
+        ":cxxbridge/rust/cxx.h",
+    ],
+    includes = [
+        "cxxbridge",
+        "include",
+    ],
+    linkopts = [
+        "-ldl",
+        "-lpthread",
+    ] + select({
+        "@platforms//os:macos": [
+            "-framework", "CoreFoundation",
+            "-framework", "Security",
+        ],
+        "//conditions:default": [],
+    }),
+    deps = [
+        ":iggy_cpp_static",
+    ],
+)
+
+cc_test(
+    name = "iggy-cpp-test",
+    srcs = ["tests/test.cpp"],
+    deps = [
+        ":iggy-cpp",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/foreign/cpp/Cargo.lock b/foreign/cpp/Cargo.lock
new file mode 100644
index 000000000..fd2290890
--- /dev/null
+++ b/foreign/cpp/Cargo.lock
@@ -0,0 +1,291 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "cc"
+version = "1.2.52"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.54"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.54"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
+
+[[package]]
+name = "codespan-reporting"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
+dependencies = [
+ "serde",
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "cxx"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e"
+dependencies = [
+ "cc",
+ "cxx-build",
+ "cxxbridge-cmd",
+ "cxxbridge-flags",
+ "cxxbridge-macro",
+ "foldhash",
+ "link-cplusplus",
+]
+
+[[package]]
+name = "cxx-build"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e"
+dependencies = [
+ "cc",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "scratch",
+ "syn",
+]
+
+[[package]]
+name = "cxxbridge-cmd"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328"
+dependencies = [
+ "clap",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "cxxbridge-flags"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a"
+
+[[package]]
+name = "cxxbridge-macro"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41"
+
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "iggy-cpp"
+version = "0.1.0"
+dependencies = [
+ "cxx",
+ "cxx-build",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "link-cplusplus"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.105"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.43"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "scratch"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
diff --git a/foreign/cpp/Cargo.toml b/foreign/cpp/Cargo.toml
new file mode 100644
index 000000000..5dbb66901
--- /dev/null
+++ b/foreign/cpp/Cargo.toml
@@ -0,0 +1,33 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+[package]
+name = "iggy-cpp"
+version = "0.1.0"
+edition = "2024"
+
+[package.metadata.cargo-machete]
+ignored = ["cxx-build"]
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+cxx = "1.0.194"
+
+[build-dependencies]
+cxx-build = "1.0.194"
diff --git a/foreign/cpp/MODULE.bazel b/foreign/cpp/MODULE.bazel
new file mode 100644
index 000000000..2686d5ef6
--- /dev/null
+++ b/foreign/cpp/MODULE.bazel
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+module(
+    name = "iggy_cpp",
+)
+
+bazel_dep(name = "rules_cc", version = "0.2.16")
+bazel_dep(name = "platforms", version = "1.0.0")
+bazel_dep(name = "googletest", version = "1.17.0")
diff --git a/foreign/cpp/MODULE.bazel.lock b/foreign/cpp/MODULE.bazel.lock
new file mode 100644
index 000000000..5797e65aa
--- /dev/null
+++ b/foreign/cpp/MODULE.bazel.lock
@@ -0,0 +1,272 @@
+{
+  "lockFileVersion": 16,
+  "registryFileHashes": {
+    "https://bcr.bazel.build/bazel_registry.json": 
"8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
+    "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": 
"7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
+    "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": 
"70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
+    "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": 
"89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0",
+    
"https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": 
"1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb",
+    "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": 
"d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16",
+    "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": 
"fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915",
+    "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": 
"37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed",
+    "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": 
"73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": 
"c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/source.json": 
"03c90ee57977264436d3231676dcddae116c4769a5d02b6fc16c2c9e019b583a",
+    "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": 
"a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
+    "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": 
"517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b",
+    "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": 
"27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
+    "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": 
"f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
+    "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": 
"d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d",
+    "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": 
"039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d",
+    "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": 
"1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a",
+    "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": 
"59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58",
+    "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": 
"675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b",
+    "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": 
"4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d",
+    "https://bcr.bazel.build/modules/bazel_features/1.28.0/source.json": 
"16a3fc5b4483cb307643791f5a4b7365fa98d2e70da7c378cdbde55f0c0b32cf",
+    "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": 
"e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
+    "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": 
"8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": 
"bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": 
"1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": 
"44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": 
"f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": 
"20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": 
"a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": 
"3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": 
"32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": 
"8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": 
"0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": 
"3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": 
"f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953",
+    "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": 
"2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
+    "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": 
"c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
+    "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": 
"a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
+    "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": 
"3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
+    "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": 
"22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
+    "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": 
"cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
+    "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": 
"6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108",
+    "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": 
"dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46",
+    "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": 
"38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713",
+    "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": 
"31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
+    "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": 
"4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d",
+    "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": 
"45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
+    "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": 
"8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
+    "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": 
"0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
+    "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": 
"9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
+    "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": 
"5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
+    "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": 
"ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
+    "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": 
"72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
+    "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": 
"9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d",
+    "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": 
"4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
+    "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": 
"f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580",
+    "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": 
"f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96",
+    "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": 
"a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
+    "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": 
"7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c",
+    "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": 
"703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d",
+    "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": 
"6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df",
+    "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": 
"319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e",
+    "https://bcr.bazel.build/modules/protobuf/29.0/source.json": 
"b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981",
+    "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": 
"6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
+    "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": 
"88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
+    "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": 
"e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34",
+    "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": 
"6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680",
+    "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": 
"cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206",
+    "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/MODULE.bazel": 
"b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a",
+    "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/source.json": 
"2ff292be6ef3340325ce8a045ecc326e92cbfab47c7cbab4bd85d28971b97ac4",
+    "https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": 
"0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa",
+    "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": 
"48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8",
+    "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": 
"e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": 
"cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": 
"ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": 
"0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": 
"5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": 
"6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": 
"7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": 
"2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": 
"6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": 
"abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": 
"964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": 
"836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
+    "https://bcr.bazel.build/modules/rules_cc/0.2.16/MODULE.bazel": 
"9242fa89f950c6ef7702801ab53922e99c69b02310c39fb6e62b2bd30df2a1d4",
+    "https://bcr.bazel.build/modules/rules_cc/0.2.16/source.json": 
"d03d5cde49376d87e14ec14b666c56075e5e3926930327fd5d0484a1ff2ac1cc",
+    "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": 
"c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
+    "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": 
"40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
+    "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": 
"c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e",
+    "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": 
"5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
+    "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": 
"a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86",
+    "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": 
"8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39",
+    "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": 
"e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6",
+    "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": 
"1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31",
+    "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": 
"530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a",
+    "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": 
"579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6",
+    "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": 
"06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab",
+    "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": 
"50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2",
+    "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": 
"2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
+    "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": 
"f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2",
+    "https://bcr.bazel.build/modules/rules_java/8.6.1/source.json": 
"f18d9ad3c4c54945bf422ad584fa6c5ca5b3116ff55a5b1bc77e5c1210be5960",
+    "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": 
"a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
+    "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": 
"33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
+    "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": 
"d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
+    "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": 
"bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": 
"75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": 
"c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": 
"6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197",
+    "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": 
"ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59",
+    "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": 
"d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3",
+    "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": 
"2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5",
+    "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": 
"627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
+    "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": 
"088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
+    "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": 
"a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c",
+    "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": 
"a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb",
+    "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": 
"df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
+    "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": 
"5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff",
+    "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": 
"bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a",
+    "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": 
"a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
+    "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": 
"e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
+    "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": 
"1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483",
+    "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": 
"ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73",
+    "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": 
"bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2",
+    "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": 
"1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1",
+    "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": 
"cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
+    "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": 
"49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
+    "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": 
"72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
+    "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": 
"cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
+    "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": 
"93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
+    "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": 
"3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937",
+    "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": 
"9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
+    "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": 
"9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7",
+    "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": 
"939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320",
+    "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": 
"fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
+    "https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": 
"7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95",
+    "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": 
"1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
+    "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": 
"c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
+    "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": 
"c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef",
+    "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": 
"05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c",
+    "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": 
"3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7",
+    "https://bcr.bazel.build/modules/stardoc/0.7.1/source.json": 
"b6500ffcd7b48cd72c29bb67bcac781e12701cc0d6d55d266a652583cfcdab01",
+    "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": 
"7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
+    "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": 
"07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
+    "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": 
"af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
+    "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": 
"2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d",
+    "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": 
"751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
+  },
+  "selectedYankedVersions": {},
+  "moduleExtensions": {
+    "@@apple_support+//crosstool:setup.bzl%apple_cc_configure_extension": {
+      "general": {
+        "bzlTransitiveDigest": "JxuYb2AtfNO78yM+Q5Uk73ioaGhKHP5Al8qrOCfHYOY=",
+        "usagesDigest": "aYRVMk+1OupIp+5hdBlpzT36qgd6ntgSxYTzMLW5K4U=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "local_config_apple_cc_toolchains": {
+            "repoRuleId": 
"@@apple_support+//crosstool:setup.bzl%_apple_cc_autoconf_toolchains",
+            "attributes": {}
+          },
+          "local_config_apple_cc": {
+            "repoRuleId": 
"@@apple_support+//crosstool:setup.bzl%_apple_cc_autoconf",
+            "attributes": {}
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "apple_support+",
+            "bazel_tools",
+            "bazel_tools"
+          ],
+          [
+            "bazel_tools",
+            "rules_cc",
+            "rules_cc+"
+          ]
+        ]
+      }
+    },
+    "@@rules_java+//java:rules_java_deps.bzl%compatibility_proxy": {
+      "general": {
+        "bzlTransitiveDigest": "84xJEZ1jnXXwo8BXMprvBm++rRt4jsTu9liBxz0ivps=",
+        "usagesDigest": "jTQDdLDxsS43zuRmg1faAjIEPWdLAbDAowI1pInQSoo=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "compatibility_proxy": {
+            "repoRuleId": 
"@@rules_java+//java:rules_java_deps.bzl%_compatibility_proxy_repo_rule",
+            "attributes": {}
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_java+",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    },
+    
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions":
 {
+      "general": {
+        "bzlTransitiveDigest": "sFhcgPbDQehmbD1EOXzX4H1q/CD5df8zwG4kp4jbvr8=",
+        "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=",
+        "recordedFileInputs": {},
+        "recordedDirentsInputs": {},
+        "envVariables": {},
+        "generatedRepoSpecs": {
+          "com_github_jetbrains_kotlin_git": {
+            "repoRuleId": 
"@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository",
+            "attributes": {
+              "urls": [
+                
"https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip";
+              ],
+              "sha256": 
"93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88"
+            }
+          },
+          "com_github_jetbrains_kotlin": {
+            "repoRuleId": 
"@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository",
+            "attributes": {
+              "git_repository_name": "com_github_jetbrains_kotlin_git",
+              "compiler_version": "1.9.23"
+            }
+          },
+          "com_github_google_ksp": {
+            "repoRuleId": 
"@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository",
+            "attributes": {
+              "urls": [
+                
"https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip";
+              ],
+              "sha256": 
"ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d",
+              "strip_version": "1.9.23-1.0.20"
+            }
+          },
+          "com_github_pinterest_ktlint": {
+            "repoRuleId": 
"@@bazel_tools//tools/build_defs/repo:http.bzl%http_file",
+            "attributes": {
+              "sha256": 
"01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985",
+              "urls": [
+                
"https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint";
+              ],
+              "executable": true
+            }
+          },
+          "rules_android": {
+            "repoRuleId": 
"@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
+            "attributes": {
+              "sha256": 
"cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806",
+              "strip_prefix": "rules_android-0.1.1",
+              "urls": [
+                
"https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip";
+              ]
+            }
+          }
+        },
+        "recordedRepoMappingEntries": [
+          [
+            "rules_kotlin+",
+            "bazel_tools",
+            "bazel_tools"
+          ]
+        ]
+      }
+    }
+  }
+}
diff --git a/foreign/cpp/README.md b/foreign/cpp/README.md
new file mode 100644
index 000000000..bcd07d765
--- /dev/null
+++ b/foreign/cpp/README.md
@@ -0,0 +1,10 @@
+# Iggy C++ Client
+
+Currently, the bazel build system relies on the system-provided cargo 
toolchain, so concurrent runs can race and lead to data corruption if executed 
remotely
+
+Running the example:
+
+```bash
+bazel build //:iggy-cpp
+bazel test //:iggy-cpp-test
+```
diff --git a/foreign/cpp/build.rs b/foreign/cpp/build.rs
new file mode 100644
index 000000000..a7e0ca0f2
--- /dev/null
+++ b/foreign/cpp/build.rs
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+fn main() {
+    cxx_build::bridge("src/lib.rs")
+        .std("c++17")
+        .compile("iggy-cpp-bridge");
+
+    println!("cargo:rerun-if-changed=src/lib.rs");
+}
diff --git a/foreign/cpp/include/iggy.hpp b/foreign/cpp/include/iggy.hpp
new file mode 100644
index 000000000..56641cb13
--- /dev/null
+++ b/foreign/cpp/include/iggy.hpp
@@ -0,0 +1,120 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <cstdint>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <string_view>
+#include <utility>
+
+namespace iggy {
+
+class IggyException : public std::runtime_error {
+  public:
+    explicit IggyException(const char *message) : std::runtime_error(message) 
{}
+    explicit IggyException(const std::string &message) : 
std::runtime_error(message) {}
+};
+
+class CompressionAlgorithm final {
+  public:
+    static CompressionAlgorithm none() { return CompressionAlgorithm("none"); }
+    static CompressionAlgorithm gzip() { return CompressionAlgorithm("gzip"); }
+
+    std::string_view compression_algorithm_value() const { return algorithm_; }
+
+  private:
+    explicit CompressionAlgorithm(std::string algorithm) : 
algorithm_(std::move(algorithm)) {}
+
+    std::string algorithm_;
+};
+
+class Expiry final {
+  public:
+    static Expiry server_default() { return Expiry("server_default", 0); }
+    static Expiry never_expire() { return Expiry("never_expire", 
std::numeric_limits<std::uint64_t>::max()); }
+    static Expiry duration(std::uint64_t micros) { return Expiry("duration", 
micros); }
+
+    std::string_view expiry_kind() const { return expiry_kind_; }
+    std::uint64_t expiry_value() const { return expiry_value_; }
+
+  private:
+    explicit Expiry(std::string expiry_kind, std::uint64_t expiry_value)
+        : expiry_kind_(std::move(expiry_kind)), expiry_value_(expiry_value) {}
+
+    std::string expiry_kind_;
+    std::uint64_t expiry_value_;
+};
+
+class MaxTopicSize final {
+  public:
+    static MaxTopicSize server_default() { return 
MaxTopicSize("server_default"); }
+    static MaxTopicSize unlimited() { return MaxTopicSize("unlimited"); }
+    static MaxTopicSize from_bytes(std::uint64_t bytes) {
+        if (bytes == 0) {
+            return server_default();
+        }
+        if (bytes == std::numeric_limits<std::uint64_t>::max()) {
+            return unlimited();
+        }
+        return MaxTopicSize(std::to_string(bytes));
+    }
+
+    std::string_view max_topic_size() const { return max_topic_size_; }
+
+  private:
+    explicit MaxTopicSize(std::string max_topic_size) : 
max_topic_size_(std::move(max_topic_size)) {}
+
+    std::string max_topic_size_;
+};
+
+class PollingStrategy final {
+  public:
+    static PollingStrategy offset(std::uint64_t value) { return 
PollingStrategy("offset", value); }
+    static PollingStrategy timestamp(std::uint64_t value) { return 
PollingStrategy("timestamp", value); }
+    static PollingStrategy first() { return PollingStrategy("first", 0); }
+    static PollingStrategy last() { return PollingStrategy("last", 0); }
+    static PollingStrategy next() { return PollingStrategy("next", 0); }
+
+    std::string_view polling_strategy_kind() const { return 
polling_strategy_kind_; }
+    std::uint64_t polling_strategy_value() const { return 
polling_strategy_value_; }
+
+  private:
+    explicit PollingStrategy(std::string kind, std::uint64_t value)
+        : polling_strategy_kind_(std::move(kind)), 
polling_strategy_value_(value) {}
+
+    std::string polling_strategy_kind_;
+    std::uint64_t polling_strategy_value_;
+};
+
+// TODO(slbotbm): Add rust bindings for Identifier that will use IdKind
+class IdKind final {
+  public:
+    static IdKind numeric() { return IdKind("numeric"); }
+    static IdKind string() { return IdKind("string"); }
+
+    std::string_view id_kind_value() const { return id_kind_; }
+
+  private:
+    explicit IdKind(std::string id_kind) : id_kind_(std::move(id_kind)) {}
+
+    std::string id_kind_;
+};
+
+}  // namespace iggy
diff --git a/foreign/cpp/src/lib.rs b/foreign/cpp/src/lib.rs
new file mode 100644
index 000000000..7d2d931b0
--- /dev/null
+++ b/foreign/cpp/src/lib.rs
@@ -0,0 +1,20 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+#[cxx::bridge(namespace = "iggy::ffi")]
+mod ffi {
+    extern "Rust" {}
+}
diff --git a/foreign/cpp/tests/test.cpp b/foreign/cpp/tests/test.cpp
new file mode 100644
index 000000000..e61b81497
--- /dev/null
+++ b/foreign/cpp/tests/test.cpp
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "iggy.hpp"
+
+TEST(CompressionAlgorithmTest, ReturnsExpectedValues) {
+    
EXPECT_EQ(iggy::CompressionAlgorithm::none().compression_algorithm_value(), 
"none");
+    
EXPECT_EQ(iggy::CompressionAlgorithm::gzip().compression_algorithm_value(), 
"gzip");
+}
+
+TEST(IdKindTest, ReturnsExpectedValues) {
+    EXPECT_EQ(iggy::IdKind::numeric().id_kind_value(), "numeric");
+    EXPECT_EQ(iggy::IdKind::string().id_kind_value(), "string");
+}
+
+TEST(MaxTopicSizeTest, ReturnsExpectedValues) {
+    EXPECT_EQ(iggy::MaxTopicSize::server_default().max_topic_size(), 
"server_default");
+    EXPECT_EQ(iggy::MaxTopicSize::unlimited().max_topic_size(), "unlimited");
+    EXPECT_EQ(iggy::MaxTopicSize::from_bytes(0).max_topic_size(), 
"server_default");
+    
EXPECT_EQ(iggy::MaxTopicSize::from_bytes(std::numeric_limits<std::uint64_t>::max()).max_topic_size(),
 "unlimited");
+    EXPECT_EQ(iggy::MaxTopicSize::from_bytes(1024).max_topic_size(), "1024");
+}
+
+TEST(PollingStrategyTest, ReturnsExpectedKindAndValue) {
+    const auto offset = iggy::PollingStrategy::offset(7);
+    EXPECT_EQ(offset.polling_strategy_kind(), "offset");
+    EXPECT_EQ(offset.polling_strategy_value(), 7u);
+
+    const auto timestamp = iggy::PollingStrategy::timestamp(42);
+    EXPECT_EQ(timestamp.polling_strategy_kind(), "timestamp");
+    EXPECT_EQ(timestamp.polling_strategy_value(), 42u);
+
+    const auto first = iggy::PollingStrategy::first();
+    EXPECT_EQ(first.polling_strategy_kind(), "first");
+    EXPECT_EQ(first.polling_strategy_value(), 0u);
+
+    const auto last = iggy::PollingStrategy::last();
+    EXPECT_EQ(last.polling_strategy_kind(), "last");
+    EXPECT_EQ(last.polling_strategy_value(), 0u);
+
+    const auto next = iggy::PollingStrategy::next();
+    EXPECT_EQ(next.polling_strategy_kind(), "next");
+    EXPECT_EQ(next.polling_strategy_value(), 0u);
+}
+
+TEST(ExpiryTest, ReturnsExpectedKindAndValue) {
+    const auto server_default = iggy::Expiry::server_default();
+    EXPECT_EQ(server_default.expiry_kind(), "server_default");
+    EXPECT_EQ(server_default.expiry_value(), 0);
+
+    const auto never_expire = iggy::Expiry::never_expire();
+    EXPECT_EQ(never_expire.expiry_kind(), "never_expire");
+    EXPECT_EQ(never_expire.expiry_value(), 
std::numeric_limits<std::uint64_t>::max());
+
+    const auto duration = iggy::Expiry::duration(15);
+    EXPECT_EQ(duration.expiry_kind(), "duration");
+    EXPECT_EQ(duration.expiry_value(), 15);
+}
+
+TEST(IggyExceptionTest, StoresMessage) {
+    const iggy::IggyException from_cstr("boom");
+    EXPECT_EQ(std::string(from_cstr.what()), "boom");
+
+    const std::string message = "boom2";
+    const iggy::IggyException from_string(message);
+    EXPECT_EQ(std::string(from_string.what()), message);
+}

Reply via email to