[
  {
    "path": ".clang-format",
    "content": "---\nLanguage: Cpp\nBasedOnStyle: Google\nIndentWidth: 4\nColumnLimit: 120\nPointerAlignment: Right\n"
  },
  {
    "path": ".cmake-format.py",
    "content": "with section(\"format\"):\n    line_width = 120\n    max_subgroups_hwrap = 4\n    max_pargs_hwrap = 10\n\nwith section(\"markup\"):\n  enable_markup = False\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Report a bug\ndescription: |\n  Create a bug report to help us improve Zenoh.\ntitle: \"[Bug] \"\nlabels: [\"bug\"]\nbody:\n  - type: textarea\n    id: summary\n    attributes:\n      label: \"Describe the bug\"\n      description: |\n        A clear and concise description of the expected behaviour and what the bug is.\n      placeholder: |\n        E.g. zenoh peers can not automatically establish a connection.\n    validations:\n      required: true\n  - type: textarea\n    id: reproduce\n    attributes:\n      label: To reproduce\n      description: \"Steps to reproduce the behavior:\"\n      placeholder: | \n        1. Start a subscriber \"...\"\n        2. Start a publisher \"....\"\n        3. See error\n    validations:\n      required: true\n  - type: textarea\n    id: system\n    attributes:\n      label: System info\n      description: \"Please complete the following information:\"\n      placeholder: |\n        - Platform: [e.g. Ubuntu 20.04 64-bit]\n        - CPU [e.g. AMD Ryzen 3800X]\n        - Zenoh version/commit [e.g. 6f172ea985d42d20d423a192a2d0d46bb0ce0d11]\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Ask a question\n    url: https://github.com/eclipse-zenoh/roadmap/discussions/categories/zenoh\n    about: Open to the Zenoh community. Share your feedback with the Zenoh team.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Request a feature\ndescription: |\n  Suggest a new feature specific to this repository. NOTE: for generic Zenoh ideas use \"Ask a question\".\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        **Guidelines for a good issue**\n\n        *Is your feature request related to a problem?*\n        A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n        *Describe the solution you'd like*\n        A clear and concise description of what you want to happen.\n\n        *Describe alternatives you've considered*\n        A clear and concise description of any alternative solutions or features you've considered.\n\n        *Additional context*\n        Add any other context about the feature request here.\n  - type: textarea\n    id: feature\n    attributes:\n      label: \"Describe the feature\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/release.yml",
    "content": "name: Add an issue to the next release\ndescription: |\n  Add an issue as part of next release. \n  This will be added to the current release project. \n  You must be a contributor to use this template.\nlabels: [\"release\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        **Guidelines for a good issue**\n\n        *Is your release item related to a problem?*\n        A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n        *Describe the solution you'd like*\n        A clear and concise description of what you want to happen.\n\n        *Describe alternatives you've considered*\n        A clear and concise description of any alternative solutions or features you've considered.\n\n        *Additional context*\n        Add any other context about the release item request here.\n  - type: textarea\n    id: item\n    attributes:\n      label: \"Describe the release item\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "## Description\n<!-- TODO: Add a clear description of what this PR does and why -->\n**⚠️ Please replace this section with your PR description**\n\n### What does this PR do?\n<!-- Describe the changes and their purpose -->\n\n### Why is this change needed?\n<!-- Explain the motivation or problem being solved -->\n\n### Related Issues\n<!-- Link to related issues: Fixes #123, Related to #456 -->\n"
  },
  {
    "path": ".github/release.yml",
    "content": "#\n# Copyright (c) 2023 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\nchangelog:\n  categories:\n    - title: Breaking changes 💥\n      labels:\n        - breaking-change\n    - title: New features 🎉\n      labels:\n        - enhancement\n        - new feature\n      exclude:\n        labels:\n          - internal\n    - title: Bug fixes 🐞\n      labels:\n        - bug\n      exclude:\n        labels:\n          - internal\n    - title: Documentation 📝\n      labels:\n        - documentation\n      exclude:\n        labels:\n          - internal\n    - title: Dependencies 👷\n      labels:\n        - dependencies\n      exclude:\n        labels:\n          - internal\n    - title: Other changes\n      labels:\n        - \"*\"\n      exclude:\n        labels:\n          - internal"
  },
  {
    "path": ".github/workflows/arduino_esp32.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: arduino_esp32\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest]\n\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cache/pip\n            ~/.platformio/.cache\n          key: ${{ runner.os }}-pio\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - name: Install PlatformIO Core\n        run: pip install --upgrade platformio\n\n      - name: Set up project\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          mkdir -p $ARDUINO_BASE\n          cd $ARDUINO_BASE\n          pio init -b esp32thing_plus -O \"-DZ_FEATURE_LINK_BLUETOOTH=1 -DZ_FEATURE_LINK_SERIAL=1\" -O \"build_flags=-DZENOH_COMPILER_GCC -DZENOH_LOG_DEBUG\" -O \"lib_ldf_mode=deep+\"\n\n          cd $ARDUINO_BASE/lib\n          ln -s $ZENOH_PICO_BASE\n\n          cd $ARDUINO_BASE\n\n      - name: Build z_pub example\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ARDUINO_BASE/src/*\n          cd $ARDUINO_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/arduino/z_pub.ino\n\n          cd $ARDUINO_BASE\n          pio run\n\n      - name: Build z_sub example\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ARDUINO_BASE/src/*\n          cd $ARDUINO_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/arduino/z_sub.ino\n\n          cd $ARDUINO_BASE\n          pio run\n\n      - name: Build z_pull example\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ARDUINO_BASE/src/*\n          cd $ARDUINO_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/arduino/z_pull.ino\n\n          cd $ARDUINO_BASE\n          pio run\n\n      - name: Build z_get example\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ARDUINO_BASE/src/*\n          cd $ARDUINO_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/arduino/z_get.ino\n\n          cd $ARDUINO_BASE\n          pio run\n\n      - name: Build z_queryable example\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ARDUINO_BASE/src/*\n          cd $ARDUINO_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/arduino/z_queryable.ino\n\n          cd $ARDUINO_BASE\n          pio run\n\n      - name: Build z_scout example\n        run: |\n          cd $HOME\n          export ARDUINO_BASE=$HOME/work/arduino_esp32project/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ARDUINO_BASE/src/*\n          cd $ARDUINO_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/arduino/z_scout.ino\n\n          cd $ARDUINO_BASE\n          pio run\n"
  },
  {
    "path": ".github/workflows/build-shared.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: build-shared\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest, macOS-latest, windows-latest]\n    steps:\n      - uses: actions/checkout@v4\n      - name: Compile debug\n        run: make all\n        env:\n          BUILD_TYPE: Debug\n          BUILD_SHARED_LIBS: ON\n          BUILD_TESTING: ON\n          BUILD_INTEGRATION: ON\n          BUILD_TOOLS: ON\n          ZENOH_LOG: debug\n\n  crossbuilds:\n    name: Build on ubuntu-latest\n    runs-on: ubuntu-latest\n    steps:\n      - name: Free Disk Space (Ubuntu)\n        uses: jlumbroso/free-disk-space@main\n        with:\n          tool-cache: false\n          android: true\n          dotnet: true\n          haskell: true\n          large-packages: true\n          docker-images: true\n          swap-storage: true\n\n      - uses: actions/checkout@v4\n      - name: Crosscompile debug\n        run: make crossbuilds\n        env:\n          BUILD_TYPE: Debug\n          BUILD_SHARED_LIBS: ON\n          ZENOH_LOG: debug\n"
  },
  {
    "path": ".github/workflows/build-static.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: build-static\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest, macOS-latest, windows-latest]\n    steps:\n      - uses: actions/checkout@v4\n      - name: Compile debug\n        run: make all\n        env:\n          BUILD_TYPE: Debug\n          BUILD_SHARED_LIBS: OFF\n          BUILD_TESTING: ON\n          BUILD_INTEGRATION: ON\n          BUILD_TOOLS: ON\n          ZENOH_LOG: debug\n\n  crossbuilds:\n    name: Build on ubuntu-latest\n    runs-on: ubuntu-latest\n    steps:\n      - name: Free Disk Space (Ubuntu)\n        uses: jlumbroso/free-disk-space@main\n        with:\n          tool-cache: false\n          android: true\n          dotnet: true\n          haskell: true\n          large-packages: true\n          docker-images: true\n          swap-storage: true\n\n      - uses: actions/checkout@v4\n      - name: Crosscompile debug\n        run: make crossbuilds\n        env:\n          BUILD_TYPE: Debug\n          BUILD_SHARED_LIBS: OFF\n          ZENOH_LOG: debug\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: CI\n\non:\n  push:\n    branches: [\"**\"]\n  pull_request:\n    branches: [\"**\"]\n  schedule:\n    - cron: \"0 6 * * 1-5\"\n\njobs:\n  run_tests:\n    name: Run unit tests on ubuntu-latest\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup mbedtls\n        uses: eclipse-zenoh/ci/setup-mbedtls@main\n        with:\n          mbedtls-version: mbedtls-3.6.5\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build & run tests\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_LINK_TLS=1 Z_FEATURE_LOCAL_QUERYABLE=1 Z_FEATURE_LOCAL_SUBSCRIBER=1 Z_FEATURE_UNSTABLE_API=1 CMAKE_GENERATOR=Ninja ASAN=ON make BUILD_TYPE=Debug test\n\n      - name: Check in-tree generated files are in sync with version.txt\n        run: |\n          if ! git diff --exit-code -- include/zenoh-pico.h library.json; then\n            echo \"::error::include/zenoh-pico.h or library.json is out of sync with version.txt.\"\n            echo \"Run a local CMake configure (e.g. 'cmake -S . -B build') and commit the refreshed files.\"\n            exit 1\n          fi\n\n  run_windows_test:\n    name: Run peer unicast test on windows-latest\n    runs-on: windows-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build & run tests\n        run: |\n          make all\n          .\\build\\tests\\Debug\\z_test_peer_unicast.exe\n        timeout-minutes: 15\n        shell: cmd\n        env:\n          ZENOH_LOG: INFO\n          Z_FEATURE_UNSTABLE_API: 1\n\n  memory_leak_unit_tests:\n    name: Memory leak unit tests\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Setup mbedtls\n        uses: eclipse-zenoh/ci/setup-mbedtls@main\n        with:\n          mbedtls-version: mbedtls-3.6.5\n\n      - name: Build tests\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_LINK_TLS=1 Z_FEATURE_LOCAL_QUERYABLE=1 Z_FEATURE_LOCAL_SUBSCRIBER=1 Z_FEATURE_UNSTABLE_API=1 CMAKE_GENERATOR=Ninja make BUILD_TYPE=Debug\n\n      - name: Install valgrind\n        run: |\n          sudo apt update\n          sudo apt install -y valgrind\n\n      - name: Memory leak unit tests\n        run: |\n          cd build/tests\n          for test in *_test; do\n            if [[ -x \"$test\" && ! -d \"$test\" ]]; then  # Run only executables\n              echo \"Running Valgrind on $test\"\n              valgrind --leak-check=full --error-exitcode=1 --suppressions=valgrind.supp \"./$test\" > /dev/null || exit 1\n            fi\n          done\n\n  check_format:\n    name: Check codebase format with clang-format\n    runs-on: ubuntu-24.04\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Run clang-format dry-run\n        run: |\n          clang-format --version\n          find include/ src/ tests/ examples/ -iname \"*.ino\" -o -iname \"*.h\" -o -iname \"*.c\" | xargs clang-format -n -Werror\n\n  c99_build:\n    name: Check c99 compilation\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with C99\n        run: |\n          sudo apt install -y ninja-build\n          FORCE_C99=ON CMAKE_GENERATOR=Ninja make\n\n  raweth_build:\n    name: Build raweth transport on ubuntu-latest\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build raweth\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_RAWETH_TRANSPORT=1 CMAKE_GENERATOR=Ninja make\n\n  tls_build:\n    name: Build TLS transport on ubuntu-latest\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup mbedtls\n        uses: eclipse-zenoh/ci/setup-mbedtls@main\n        with:\n          mbedtls-version: mbedtls-3.6.5\n\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with TLS\n        run: |\n          sudo apt update\n          sudo apt install -y ninja-build\n          Z_FEATURE_LINK_TLS=1 CMAKE_GENERATOR=Ninja make\n\n  zenoh_build:\n    name: Build Zenoh from source\n    runs-on: ubuntu-latest\n    outputs:\n      artifact-name: ${{ steps.main.outputs.artifact-name }}\n    steps:\n      - id: main\n        name: Build Zenoh\n        uses: eclipse-zenoh/ci/build-crates-standalone@main\n        with:\n          repo: eclipse-zenoh/zenoh\n          branch: main\n          artifact-patterns: |\n            ^zenohd$\n            ^libzenoh_plugin_rest.so$\n            ^libzenoh_plugin_storage_manager.so$\n\n  modular_build:\n    needs: zenoh_build\n    name: Modular build on ubuntu-latest\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        feature_publication: [1, 0]\n        feature_subscription: [1, 0]\n        feature_queryable: [1, 0]\n        feature_query: [1, 0]\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - id: run-zenoh\n        name: Run Zenoh router\n        run: |\n          RUST_LOG=debug ./zenoh-standalone/zenohd &\n          echo \"zenohd-pid=$!\" >> $GITHUB_OUTPUT\n\n      - name: Build project\n        run: |\n          sudo apt install -y ninja-build\n          CMAKE_GENERATOR=Ninja make\n          python3 ./build/tests/modularity.py --pub $Z_FEATURE_PUBLICATION --sub $Z_FEATURE_SUBSCRIPTION --queryable $Z_FEATURE_QUERYABLE --query $Z_FEATURE_QUERY\n        timeout-minutes: 15\n        env:\n          Z_FEATURE_PUBLICATION: ${{ matrix.feature_publication }}\n          Z_FEATURE_SUBSCRIPTION: ${{ matrix.feature_subscription }}\n          Z_FEATURE_QUERYABLE: ${{ matrix.feature_queryable }}\n          Z_FEATURE_QUERY: ${{ matrix.feature_query }}\n\n      - name: Kill Zenoh router\n        if: always()\n        run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }}\n\n  unstable_build:\n    name: Check compilation with unstable API\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with unstable\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_UNSTABLE_API=1 CMAKE_GENERATOR=Ninja make\n\n  no_scouting_build:\n    name: Check compilation without scouting\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build without scouting\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_SCOUTING=0 CMAKE_GENERATOR=Ninja make\n\n  no_interest_build:\n    name: Check compilation without interests\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build without interests\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_INTEREST=0 CMAKE_GENERATOR=Ninja make\n\n  no_liveliness_build:\n    name: Check compilation without liveliness\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build without interests\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_LIVELINESS=0 CMAKE_GENERATOR=Ninja make\n\n  advanced_publisher_build:\n    name: Check compilation with advanced publisher\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with advanced publisher\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_UNSTABLE_API=1 Z_FEATURE_ADVANCED_PUBLICATION=1 CMAKE_GENERATOR=Ninja make\n\n  advanced_subscriber_build:\n    name: Check compilation with advanced subscriber\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with advanced subscriber\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_UNSTABLE_API=1 Z_FEATURE_ADVANCED_SUBSCRIPTION=1 CMAKE_GENERATOR=Ninja make\n\n  rx_cache_build:\n    name: Check compilation with RX cache enabled\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with RX cache\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_RX_CACHE=1 CMAKE_GENERATOR=Ninja make\n\n  gcc10_build:\n    name: Check compilation with GCC 10\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with GCC 10\n        run: |\n          sudo apt update\n          sudo apt install -y ninja-build gcc-10\n          CC=gcc-10 Z_FEATURE_UNSTABLE_API=1 Z_FEATURE_ADVANCED_PUBLICATION=1 Z_FEATURE_ADVANCED_SUBSCRIPTION=1 CMAKE_GENERATOR=Ninja make\n\n  gcc9_build:\n    name: Check compilation with Ubuntu 20.04 (GCC 9)\n    runs-on: ubuntu-latest\n    container: ubuntu:20.04\n    env:\n      DEBIAN_FRONTEND: noninteractive\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build with GCC 9\n        run: |\n          apt update && apt install -y build-essential cmake\n          mkdir build && cd build\n          CC=gcc-9 Z_FEATURE_UNSTABLE_API=1 Z_FEATURE_ADVANCED_PUBLICATION=1 Z_FEATURE_ADVANCED_SUBSCRIPTION=1 cmake ..\n          cmake --build .\n\n  st_build:\n    needs: zenoh_build\n    name: Build and test in single thread on ubuntu-latest (unstable=${{ matrix.unstable_api }})\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        unstable_api: [0, 1]\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - id: run-zenoh\n        name: Run Zenoh router\n        run: |\n          RUST_LOG=debug ./zenoh-standalone/zenohd &\n          echo \"zenohd-pid=$!\" >> $GITHUB_OUTPUT\n\n      - name: Build project and run tests\n        run: |\n          sudo apt install -y ninja-build\n          CMAKE_GENERATOR=Ninja ASAN=ON make BUILD_TYPE=Debug\n          ninja -C build/ test\n          python3 ./build/tests/single_thread.py\n        timeout-minutes: 15\n        env:\n          Z_FEATURE_MULTI_THREAD: 0\n          Z_FEATURE_UNSTABLE_API: ${{ matrix.unstable_api }}\n\n      - name: Kill Zenoh router\n        if: always()\n        run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }}\n\n  fragment_test:\n    needs: zenoh_build\n    name: Test multicast and unicast fragmentation\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - id: run-zenoh\n        name: Run Zenoh router\n        run: |\n          RUST_LOG=debug ./zenoh-standalone/zenohd &\n          echo \"zenohd-pid=$!\" >> $GITHUB_OUTPUT\n\n      - name: Build project and run test\n        run: |\n          sudo apt install -y ninja-build\n          cmake -DBATCH_UNICAST_SIZE=4096 -B build/ -G Ninja\n          CMAKE_GENERATOR=Ninja make\n          python3 ./build/tests/fragment.py\n        timeout-minutes: 15\n\n      - name: Kill Zenoh router\n        if: always()\n        run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }}\n\n  attachment_test:\n    needs: zenoh_build\n    name: Test attachments\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - id: run-zenoh\n        name: Run Zenoh router\n        run: |\n          RUST_LOG=debug ./zenoh-standalone/zenohd &\n          echo \"zenohd-pid=$!\" >> $GITHUB_OUTPUT\n\n      - name: Build project and run test\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_UNSTABLE_API=1 CMAKE_GENERATOR=Ninja make\n          python3 ./build/tests/attachment.py\n        timeout-minutes: 15\n\n      - name: Kill Zenoh router\n        if: always()\n        run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }}\n\n  memory_leak_test:\n    needs: zenoh_build\n    name: Test examples memory leak\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup mbedtls\n        uses: eclipse-zenoh/ci/setup-mbedtls@main\n        with:\n          mbedtls-version: mbedtls-3.6.5\n\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - id: run-zenoh\n        name: Run Zenoh router\n        run: |\n          RUST_LOG=debug ./zenoh-standalone/zenohd &\n          echo \"zenohd-pid=$!\" >> $GITHUB_OUTPUT\n\n      - name: Install valgrind\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y valgrind\n\n      - name: Build project\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_LINK_TLS=1 Z_FEATURE_LOCAL_QUERYABLE=1 Z_FEATURE_LOCAL_SUBSCRIBER=1 Z_FEATURE_UNSTABLE_API=1 Z_FEATURE_LIVELINESS=1 CMAKE_GENERATOR=Ninja make\n\n      - name: Run test\n        run: python3 -u ./build/tests/memory_leak.py\n        timeout-minutes: 15\n\n      - name: Kill Zenoh router\n        if: always()\n        run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }}\n\n  no_router:\n    name: Test examples without router\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build & test pico\n        run: |\n          sudo apt install -y ninja-build\n          CMAKE_GENERATOR=Ninja ASAN=ON make\n          python3 ./build/tests/no_router.py\n        timeout-minutes: 15\n\n  connection_restore_test:\n    needs: zenoh_build\n    name: Connection restore test\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - name: Build project and run test\n        run: |\n          sudo apt install -y ninja-build\n          CMAKE_GENERATOR=Ninja ASAN=ON CMAKE_BUILD_TYPE=Debug ZENOH_DEBUG=3 make\n          RUST_LOG=debug sudo python3 ./build/tests/connection_restore.py ./zenoh-standalone/zenohd\n        timeout-minutes: 20\n\n  routed_peer_client_test:\n    needs: zenoh_build\n    name: Test routed peer client communication\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Download Zenoh artifacts\n        uses: actions/download-artifact@v4\n        with:\n          name: ${{ needs.zenoh_build.outputs.artifact-name }}\n\n      - name: Unzip Zenoh artifacts\n        run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone\n\n      - id: select-multicast-iface\n        name: Select multicast-capable interface\n        run: |\n          echo \"Detecting multicast interface...\"\n          # Pick first non-loopback, non-docker, non-veth interface\n          IFACE=$(ip -o link show | awk -F': ' '$2 != \"lo\" && $2 !~ /docker/ && $2 !~ /veth/ {print $2; exit}')\n          if [ -z \"$IFACE\" ]; then\n            echo \"No suitable interface found, defaulting to eth0\"\n            IFACE=eth0\n          fi\n          echo \"Selected interface: $IFACE\"\n          echo \"iface=$IFACE\" >> \"$GITHUB_OUTPUT\"\n\n      - id: run-zenoh\n        name: Run Zenoh router\n        run: |\n          IFACE=${{ steps.select-multicast-iface.outputs.iface }}\n          RUST_LOG=debug ./zenoh-standalone/zenohd -l tcp/127.0.0.1:7447 -l udp/224.0.0.123:7447#iface=$IFACE > zenohd.log 2>&1 &\n          echo \"zenohd-pid=$!\" >> $GITHUB_OUTPUT\n\n      - name: Build project and run test\n        run: |\n          sudo apt install -y ninja-build\n          Z_FEATURE_UNSTABLE_API=1 BATCH_MULTICAST_SIZE=8192 BATCH_UNICAST_SIZE=49152 CMAKE_GENERATOR=Ninja make\n          IFACE=${{ steps.select-multicast-iface.outputs.iface }}\n          python3 ./build/tests/routed_peer_client.py tcp/127.0.0.1:7447 udp/224.0.0.123:7447#iface=$IFACE\n        timeout-minutes: 15\n\n      - name: Kill Zenoh router\n        if: always()\n        run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }}\n\n      - name: Print zenohd logs\n        if: always()\n        run: |\n          echo \"===== ZENOH ROUTER LOGS =====\"\n          cat zenohd.log || echo \"zenohd.log not found\"\n\n  unicast_peer_test:\n    name: P2p unicast test\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build & test pico\n        run: |\n          sudo apt install -y ninja-build\n          CMAKE_GENERATOR=Ninja make\n          ./build/tests/z_test_peer_unicast\n        env:\n          Z_FEATURE_UNSTABLE_API: 1\n          Z_FEATURE_UNICAST_PEER: 1\n        timeout-minutes: 15\n\n  multicast_peer_test:\n    name: P2p multicast test\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        feature_declarations: [1, 0]\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Build & test pico\n        run: |\n          sudo apt install -y ninja-build\n          CMAKE_GENERATOR=Ninja make\n          ./build/tests/z_test_peer_multicast\n        env:\n          Z_FEATURE_UNSTABLE_API: 1\n          Z_FEATURE_MULTICAST_DECLARATIONS: ${{ matrix.feature_declarations }}\n        timeout-minutes: 15\n\n  markdown_lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: DavidAnson/markdownlint-cli2-action@v18\n        with:\n          config: \".markdownlint.yaml\"\n          globs: \"**/README.md\"\n\n  build_shared:\n    name: Build shared libs\n    uses: ./.github/workflows/build-shared.yaml\n\n  build_static:\n    name: Build static libs\n    uses: ./.github/workflows/build-static.yaml\n\n  integration:\n    name: Run integration tests\n    uses: ./.github/workflows/integration.yaml\n\n  arduino_esp32:\n    name: Build Arduino ESP32\n    uses: ./.github/workflows/arduino_esp32.yaml\n\n  emscripten:\n    name: Build Emscripten\n    uses: ./.github/workflows/emscripten.yaml\n\n  espidf:\n    name: Build ESP-IDF\n    uses: ./.github/workflows/espidf.yaml\n\n  freertos:\n    name: Build FreeRTOS\n    uses: ./.github/workflows/freertos_plus_tcp.yaml\n\n  mbed:\n    name: Build Mbed\n    uses: ./.github/workflows/mbed.yaml\n\n  rpi_pico:\n    name: Build Raspberry Pi Pico\n    uses: ./.github/workflows/rpi_pico.yaml\n\n  zephyr:\n    name: Build Zephyr\n    uses: ./.github/workflows/zephyr.yaml\n\n  codacy-security-scan:\n    name: Codacy Security Scan\n    uses: ./.github/workflows/codacy-analysis.yml\n\n  cpp_check:\n    name: CppCheck\n    uses: ./.github/workflows/cpp-check.yaml\n\n  # NOTE: In GitHub repository settings, the \"Require status checks to pass\n  # before merging\" branch protection rule ensures that commits are only merged\n  # from branches where specific status checks have passed. These checks are\n  # specified manually as a list of workflow job names. Thus we use this extra\n  # job to signal whether all CI checks have passed.\n  ci:\n    name: CI status checks\n    runs-on: ubuntu-latest\n    needs:\n      [\n        run_tests,\n        check_format,\n        c99_build,\n        raweth_build,\n        tls_build,\n        zenoh_build,\n        modular_build,\n        unstable_build,\n        no_interest_build,\n        no_liveliness_build,\n        st_build,\n        fragment_test,\n        attachment_test,\n        memory_leak_test,\n        no_router,\n        connection_restore_test,\n        markdown_lint,\n        build_shared,\n        build_static,\n        integration,\n        memory_leak_unit_tests,\n        unicast_peer_test,\n        multicast_peer_test,\n        arduino_esp32,\n        emscripten,\n        espidf,\n        freertos,\n        mbed,\n        rpi_pico,\n        zephyr,\n        codacy-security-scan,\n        cpp_check,\n      ]\n    if: always()\n    steps:\n      - name: Check whether all jobs pass\n        run: echo '${{ toJson(needs) }}' | jq -e 'all(.result == \"success\")'\n"
  },
  {
    "path": ".github/workflows/codacy-analysis.yml",
    "content": "# This workflow checks out code, performs a Codacy security scan\n# and integrates the results with the\n# GitHub Advanced Security code scanning feature.  For more information on\n# the Codacy security scan action usage and parameters, see\n# https://github.com/codacy/codacy-analysis-cli-action.\n# For more information on Codacy Analysis CLI in general, see\n# https://github.com/codacy/codacy-analysis-cli.\n\nname: Codacy Security Scan\n\non:\n  workflow_dispatch:\n  workflow_call:\n\njobs:\n  codacy-security-scan:\n    name: Codacy Security Scan with ${{ matrix.tool }}\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        # List of Codacy-supported tools: https://docs.codacy.com/repositories-configure/codacy-configuration-file/#which-tools-can-be-configured-and-which-name-should-i-use%20%20tool-timeout:\n        tool: [\n            cppcheck, # static analysis of C/C++ code\n            flawfinder, # a static analysis tool for finding vulnerabilities in C/C++ source code\n            markdownlint, # A Node.js style checker and lint tool for Markdown/CommonMark files\n            shellcheck, # a static analysis tool for shell scripts\n            pylintpython3, # a static code analyser for Python 3\n          ]\n    steps:\n      # Checkout the repository to the GitHub Actions runner\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis\n      - name: Run Codacy Analysis CLI for ${{ matrix.tool }}\n        uses: codacy/codacy-analysis-cli-action@v4.4.7\n        with:\n          verbose: true\n          output: results-${{ matrix.tool }}.sarif\n          format: sarif\n          # Adjust severity of non-security issues\n          gh-code-scanning-compat: true\n          # Force 0 exit code to allow SARIF file generation\n          # This will handover control about PR rejection to the GitHub side\n          max-allowed-issues: 2147483647\n          tool: ${{ matrix.tool }}\n\n      - name: Split SARIF into per-run files\n        run: |\n            mkdir -p sarif-splits\n            total_runs=$(jq '.runs | length' results-${{ matrix.tool }}.sarif)\n            echo \"Found $total_runs runs\"\n\n            schema=$(jq -r '.[\"$schema\"]' results-${{ matrix.tool }}.sarif)\n            version=$(jq -r '.version' results-${{ matrix.tool }}.sarif)\n\n            if [[ -z \"$version\" || \"$version\" == \"null\" ]]; then\n              echo \"Error: Missing SARIF version\"\n              exit 1\n            fi\n\n            for ((i=0; i<total_runs; i++)); do\n              jq \".runs[$i]\" results-${{ matrix.tool }}.sarif > tmp-run.json\n\n              echo \"{ \\\"\\$schema\\\": \\\"$schema\\\", \\\"version\\\": \\\"$version\\\", \\\"runs\\\": [$(cat tmp-run.json)] }\" \\\n                > sarif-splits/${{ matrix.tool }}-${i}.sarif\n              \n            done\n\n            rm -f tmp-run.json\n\n      - name: Validate SARIF files\n        run: |\n          for f in sarif-splits/*.sarif; do\n            echo \"Validating $f...\"\n            jq empty \"$f\" || { echo \"::error ::Invalid JSON in $f\"; exit 1; }\n          done\n\n      # Pre-upload: detect how many files exist\n      - name: Set SARIF file count\n        id: sarif-count\n        run: |\n          count=$(ls sarif-splits/${{ matrix.tool }}-*.sarif | wc -l)\n          echo \"count=$count\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Fail if SARIF run count exceeds 3\n        if: steps.sarif-count.outputs.count > '3'\n        run: |\n          echo \"::error ::Too many SARIF runs detected (${COUNT}). Maximum allowed is 3.\"\n          exit 1\n\n      # Upload SARIF files (max 3 supported here)\n      - name: Upload SARIF run 0\n        if: steps.sarif-count.outputs.count != '0'\n        uses: github/codeql-action/upload-sarif@v3\n        with:\n          sarif_file: sarif-splits/${{ matrix.tool }}-0.sarif\n          category: ${{ matrix.tool }}-0\n\n      - name: Upload SARIF run 1\n        if: steps.sarif-count.outputs.count > '1'\n        uses: github/codeql-action/upload-sarif@v3\n        with:\n          sarif_file: sarif-splits/${{ matrix.tool }}-1.sarif\n          category: ${{ matrix.tool }}-1\n\n      - name: Upload SARIF run 2\n        if: steps.sarif-count.outputs.count > '2'\n        uses: github/codeql-action/upload-sarif@v3\n        with:\n          sarif_file: sarif-splits/${{ matrix.tool }}-2.sarif\n          category: ${{ matrix.tool }}-2\n"
  },
  {
    "path": ".github/workflows/cpp-check.yaml",
    "content": "#\n# Copyright (c) 2024 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale zenoh Team, <zenoh@zettascale.tech>\n#\nname: cpp-check\n\non:\n  workflow_dispatch:\n    inputs:\n      zenoh_cpp_branch:\n        description: 'Branch of zenoh-cpp to use'\n        required: false\n        default: 'main'\n  workflow_call:\n    inputs:\n      zenoh_cpp_branch:\n        description: 'Branch of zenoh-cpp to use'\n        required: false\n        default: 'main'\n        type: string\n\njobs:\n  build-and-test:\n    name: Build and test zenoh-cpp on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n        unstable: [0, 1]\n\n    steps:\n    - name: checkout zenoh-pico\n      uses: actions/checkout@v3\n\n    - name: Install cmake\n      uses: jwlawson/actions-setup-cmake@v2\n      with:\n        cmake-version: '3.31.x'\n\n    - name: build zenoh-pico\n      run: |\n        mkdir build && cd build\n        cmake .. -DCMAKE_BUILD_TYPE=Release -DZENOH_LOG=DEBUG -DCMAKE_INSTALL_PREFIX=~/local -DZ_FEATURE_UNSTABLE_API=${{ matrix.unstable }} -DZ_FEATURE_LIVELINESS=1 -DASAN=ON\n        cmake --build . --target install --config Release\n\n    - name: clone zenoh-cpp\n      run: |\n        git clone https://github.com/eclipse-zenoh/zenoh-cpp.git\n        cd zenoh-cpp\n        git fetch --all\n        git checkout ${{ github.event.inputs.zenoh_cpp_branch || 'main' }}\n        git submodule update --init --recursive\n\n    - name: build zenoh-cpp\n      run: |\n        cd zenoh-cpp\n        mkdir build && cd build\n        cmake .. -DCMAKE_INSTALL_PREFIX=~/local -DCMAKE_BUILD_TYPE=Release -DZENOHCXX_ZENOHPICO=ON -DZENOHCXX_ZENOHC=OFF\n        cmake --build . --config Release\n\n    - name: build examples\n      run: |\n        cd zenoh-cpp/build\n        cmake --build . --target examples --config Release\n\n    - name: build tests\n      run: |\n        cd zenoh-cpp/build\n        cmake --build . --target tests --config Release\n\n    - name: run tests\n      shell: bash\n      run: |\n        cd zenoh-cpp/build\n        # On macOS, sudo is required to run tests due to LAN access permissions\n        if [[ \"${{ matrix.os }}\" == \"macos-latest\" ]]; then\n          sudo ctest -C Release --output-on-failure\n        else\n          ctest -C Release --output-on-failure\n        fi"
  },
  {
    "path": ".github/workflows/emscripten.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: emscripten\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: jwlawson/actions-setup-cmake@v1.14\n      - uses: mymindstorm/setup-emsdk@v12\n      - name: Compile debug\n        run: |\n          mkdir build\n          emcmake cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_STANDARD=11 -DBUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=OFF -DBUILD_INTEGRATION=OFF -DBUILD_TOOLS=OFF -DZENOH_LOG=debug -DZ_FEATURE_LINK_WS=1 -DZ_FEATURE_LINK_TCP=0 -DZ_FEATURE_LINK_UDP_MULTICAST=0 -DZ_FEATURE_LINK_UDP_UNICAST=0 -DZ_FEATURE_SCOUTING=0 -H. -Bbuild\n          make -C build\n"
  },
  {
    "path": ".github/workflows/espidf.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: espidf\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest]\n\n    env:\n      IDF_COMPONENT_MANAGER: \"0\"   # ← disable pacman to avoid the pydantic crash\n\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cache/pip\n            ~/.platformio/.cache\n          key: ${{ runner.os }}-pio\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - name: Install PlatformIO Core\n        run: pip install --upgrade platformio\n\n      - name: Set up project\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          mkdir -p $ESPIDF_BASE\n          cd $ESPIDF_BASE\n          # Temporary workaround: espressif32@7.0.0 pulls in ESP-IDF 6.0 and exposes\n          # the existing PlatformIO source-selection issue after the platform\n          # restructuring from #1188. Remove this pin once PlatformIO integration is\n          # aligned with the new platform structure.\n          pio init -b az-delivery-devkit-v4 \\\n            --project-option=\"platform=espressif32@6.13.0\" \\\n            --project-option=\"framework=espidf\" \\\n            --project-option=\"build_flags=-DZENOH_ESPIDF -DZENOH_LOG_DEBUG\" \\\n            -O \"board_build.cmake_extra_args=-DZ_FEATURE_LINK_SERIAL=1\"\n\n          cd $ESPIDF_BASE/lib\n          ln -s $ZENOH_PICO_BASE\n\n          cd $ESPIDF_BASE\n\n      - name: Build z_pub example\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ESPIDF_BASE/src/*\n          cd $ESPIDF_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/espidf/z_pub.c\n\n          cd $ESPIDF_BASE\n          pio run\n\n      - name: Build z_sub example\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ESPIDF_BASE/src/*\n          cd $ESPIDF_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/espidf/z_sub.c\n\n          cd $ESPIDF_BASE\n          pio run\n\n      - name: Build z_pull example\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ESPIDF_BASE/src/*\n          cd $ESPIDF_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/espidf/z_pull.c\n\n          cd $ESPIDF_BASE\n          pio run\n\n      - name: Build z_get example\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ESPIDF_BASE/src/*\n          cd $ESPIDF_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/espidf/z_get.c\n\n          cd $ESPIDF_BASE\n          pio run\n\n      - name: Build z_queryable example\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ESPIDF_BASE/src/*\n          cd $ESPIDF_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/espidf/z_queryable.c\n\n          cd $ESPIDF_BASE\n          pio run\n\n      - name: Build z_scout example\n        run: |\n          cd $HOME\n          export ESPIDF_BASE=$HOME/work/espidfproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ESPIDF_BASE/src/*\n          cd $ESPIDF_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/espidf/z_scout.c\n\n          cd $ESPIDF_BASE\n          pio run\n"
  },
  {
    "path": ".github/workflows/freertos_plus_tcp.yaml",
    "content": "#\n# Copyright (c) 2023 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   Błażej Sowa, <blazej@fictionlab.pl>\n#\nname: freertos_plus_tcp\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest]\n    steps:\n    - uses: actions/checkout@v4\n    - uses: jwlawson/actions-setup-cmake@v1.13\n    - name: Install requirements\n      run: |\n        sudo apt update\n        sudo apt install -y ninja-build libslirp-dev libglib2.0-dev\n    - name: Build examples\n      run: |\n        cd examples/freertos_plus_tcp\n        cmake -Bbuild -G\"Ninja Multi-Config\" -DZ_FEATURE_LINK_UDP_MULTICAST=0 -DZ_CONFIG_SOCKET_TIMEOUT=1000\n        cmake --build ./build --config Debug\n        cmake --build ./build --config Release\n"
  },
  {
    "path": ".github/workflows/integration.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: integration\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest, macOS-latest]\n\n    steps:\n      - name: Clone this repository\n        uses: actions/checkout@v4\n\n      - name: Setup mbedtls\n        if: runner.os == 'Linux'\n        uses: eclipse-zenoh/ci/setup-mbedtls@main\n        with:\n          mbedtls-version: mbedtls-3.6.5\n\n      - name: Install TLS dependencies (macOS)\n        if: runner.os == 'macOS'\n        shell: bash\n        run: |\n          # Install mbedtls@3 if not installed\n          if ! brew list mbedtls@3 >/dev/null 2>&1; then\n            brew install mbedtls@3\n          fi\n\n          MBEDTLS_PREFIX=\"$(brew --prefix mbedtls@3)\"\n\n          # Make this prefix available for later steps\n          echo \"MBEDTLS_INSTALL=${MBEDTLS_PREFIX}\" >> \"$GITHUB_ENV\"\n\n          # Let pkg-config find the v3 .pc files first\n          echo \"PKG_CONFIG_PATH=${MBEDTLS_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}\" >> \"$GITHUB_ENV\"\n\n          # Help CMake find it as a generic prefix\n          echo \"CMAKE_PREFIX_PATH=${MBEDTLS_PREFIX}:${CMAKE_PREFIX_PATH}\" >> \"$GITHUB_ENV\"\n\n          # Needed to *run* binaries/tests that link against libmbedtls.dylib\n          echo \"LD_LIBRARY_PATH=${MBEDTLS_PREFIX}/lib:${LD_LIBRARY_PATH}\" >> \"$GITHUB_ENV\"\n          echo \"DYLD_LIBRARY_PATH=${MBEDTLS_PREFIX}/lib:${DYLD_LIBRARY_PATH}\" >> \"$GITHUB_ENV\"\n\n      - name: Compile debug\n        run: make all\n        env:\n          BUILD_TYPE: Debug\n          BUILD_TESTING: OFF\n          BUILD_INTEGRATION: ON\n          Z_FEATURE_LINK_TLS: 1\n          Z_FEATURE_UNSTABLE_API: 1\n          Z_FEATURE_LOCAL_QUERYABLE: 1\n          Z_FEATURE_LOCAL_SUBSCRIBER: 1\n          Z_FEATURE_ADVANCED_PUBLICATION: 1\n          Z_FEATURE_ADVANCED_SUBSCRIPTION: 1\n          Z_FEATURE_ADMIN_SPACE: 1\n\n      - name: Test debug\n        run: make test\n        timeout-minutes: 40\n        env:\n          BUILD_TYPE: Debug # Workaround for Windows as it seems the previous step is being ignored\n          BUILD_TESTING: OFF # Workaround for Windows as it seems the previous step is being ignored\n          BUILD_INTEGRATION: ON # Workaround for Windows as it seems the previous step is being ignored\n          Z_FEATURE_LINK_TLS: 1\n          Z_FEATURE_LOCAL_QUERYABLE: 1\n          Z_FEATURE_LOCAL_SUBSCRIBER: 1\n          Z_FEATURE_UNSTABLE_API: 1\n          ZENOH_BRANCH: main\n\n  asan-build:\n    name: Build on ubuntu-latest with ASAN\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n\n    steps:\n      - name: Clone this repository\n        uses: actions/checkout@v4\n\n      - name: Setup mbedtls (Linux)\n        if: runner.os == 'Linux'\n        uses: eclipse-zenoh/ci/setup-mbedtls@main\n        with:\n          mbedtls-version: mbedtls-3.6.5\n\n      - name: Install TLS dependencies (macOS)\n        if: runner.os == 'macOS'\n        run: brew list mbedtls >/dev/null 2>&1 || brew install mbedtls\n\n      - name: Compile debug\n        run: make all\n        env:\n          BUILD_TYPE: Debug\n          BUILD_TESTING: OFF\n          BUILD_INTEGRATION: ON\n          Z_FEATURE_LINK_TLS: 1\n          Z_FEATURE_UNSTABLE_API: 1\n          Z_FEATURE_LOCAL_QUERYABLE: 1\n          Z_FEATURE_LOCAL_SUBSCRIBER: 1\n          Z_FEATURE_ADVANCED_PUBLICATION: 1\n          Z_FEATURE_ADVANCED_SUBSCRIPTION: 1\n          ASAN: 1\n\n      - name: Test debug\n        run: make test\n        timeout-minutes: 40\n        env:\n          BUILD_TYPE: Debug # Workaround for Windows as it seems the previous step is being ignored\n          BUILD_TESTING: OFF # Workaround for Windows as it seems the previous step is being ignored\n          BUILD_INTEGRATION: ON # Workaround for Windows as it seems the previous step is being ignored\n          Z_FEATURE_LINK_TLS: 1\n          Z_FEATURE_UNSTABLE_API: 1\n          Z_FEATURE_LOCAL_SUBSCRIBER: 1\n          ZENOH_BRANCH: main\n"
  },
  {
    "path": ".github/workflows/mbed.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: mbed\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-22.04]\n\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cache/pip\n            ~/.platformio/.cache\n          key: ${{ runner.os }}-pio\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - name: Install PlatformIO Core\n        run: pip install --upgrade platformio\n\n      - name: Set up project\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          mkdir -p $MBED_BASE\n          cd $MBED_BASE\n          pio init -b nucleo_f767zi --project-option=\"framework=mbed\" --project-option=\"board_build.cmake_extra_args=-DZ_FEATURE_LINK_SERIAL=1\" -O \"build_flags=-DZENOH_COMPILER_GCC -DZENOH_LOG_DEBUG\"\n\n          cd $MBED_BASE/lib\n          ln -s $ZENOH_PICO_BASE\n\n          cd $MBED_BASE\n\n      - name: Build z_pub example\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $MBED_BASE/src/*\n          cd $MBED_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/mbed/z_pub.cpp\n\n          cd $MBED_BASE\n          pio run\n\n      - name: Build z_sub example\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $MBED_BASE/src/*\n          cd $MBED_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/mbed/z_sub.cpp\n\n          cd $MBED_BASE\n          pio run\n\n      - name: Build z_pull example\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $MBED_BASE/src/*\n          cd $MBED_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/mbed/z_pull.cpp\n\n          cd $MBED_BASE\n          pio run\n\n      - name: Build z_get example\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $MBED_BASE/src/*\n          cd $MBED_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/mbed/z_get.cpp\n\n          cd $MBED_BASE\n          pio run\n\n      - name: Build z_queryable example\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $MBED_BASE/src/*\n          cd $MBED_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/mbed/z_queryable.cpp\n\n          cd $MBED_BASE\n          pio run\n\n      - name: Build z_scout example\n        run: |\n          cd $HOME\n          export MBED_BASE=$HOME/work/mbedproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $MBED_BASE/src/*\n          cd $MBED_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/mbed/z_scout.cpp\n\n          cd $MBED_BASE\n          pio run\n"
  },
  {
    "path": ".github/workflows/pr-label-checklists-generate.yml",
    "content": "name: PR Label Checklists Generate\n\n# This workflow runs in the context of the base repository, so be mindful of the permissions granted here and the actions used in the workflow:\n# For more information see https://docs.github.com/en/enterprise-cloud@latest/actions/reference/security/secure-use#mitigating-the-risks-of-untrusted-code-checkout\non:\n  pull_request_target:\n    types: [opened, reopened, labeled, unlabeled, synchronize]\n\n# Prevent duplicate runs when swapping labels (unlabeled + labeled events fire together)\nconcurrency:\n  group: pr-checklists-generate-${{ github.event.pull_request.number }}\n  cancel-in-progress: true\n\njobs:\n  checklist:\n    name: Generate\n    permissions:\n      pull-requests: write\n      statuses: write\n      contents: read\n    uses: eclipse-zenoh/ci/.github/workflows/pr-label-checklists-generate.yml@main\n    with:\n      checklists-repo: eclipse-zenoh/ci\n    secrets:\n      github-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/pr-label-checklists-verify.yml",
    "content": "name: PR Label Checklists Verify\n\n# This workflow runs in the context of the base repository, so be mindful of the permissions granted here and the actions used in the workflow:\n# For more information see https://docs.github.com/en/enterprise-cloud@latest/actions/reference/security/secure-use#mitigating-the-risks-of-untrusted-code-checkout\non:\n  pull_request_target:\n    types: [edited]\n\njobs:\n  verify:\n    name: Verify\n    permissions:\n      pull-requests: read\n      statuses: write\n      contents: read\n    uses: eclipse-zenoh/ci/.github/workflows/pr-label-checklists-verify.yml@main\n    secrets:\n      github-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: Release\n\non:\n  schedule:\n    - cron: \"0 0 * * 1-5\"\n  workflow_dispatch:\n    inputs:\n      live-run:\n        type: boolean\n        description: Live-run\n        required: false\n      version:\n        type: string\n        description: Release number\n        required: false\n      branch:\n        type: string\n        description: Release branch\n        required: false\njobs:\n  tag:\n    name: Branch, Bump & tag\n    runs-on: ubuntu-latest\n    outputs:\n      version: ${{ steps.create-release-branch.outputs.version }}\n      branch: ${{ steps.create-release-branch.outputs.branch }}\n    steps:\n      - name: Checkout this repository\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ inputs.branch || 'main' }}\n          fetch-tags: true\n          fetch-depth: 0\n          path: version-checkout\n\n      - id: version\n        run: |\n          if [[ -n \"${{ inputs.version }}\" ]]; then\n            echo \"version=${{ inputs.version }}\" >> \"$GITHUB_OUTPUT\"\n          else\n            cd version-checkout\n            tag=$(git describe --tags --abbrev=0)\n            tweak=$(git describe --tags --abbrev=1 | cut -d'-' -f2)\n            echo \"version=$tag.$tweak\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n      - id: create-release-branch\n        uses: eclipse-zenoh/ci/create-release-branch@main\n        with:\n          repo: ${{ github.repository }}\n          live-run: ${{ inputs.live-run || false }}\n          version: ${{ steps.version.outputs.version }}\n          branch: ${{ inputs.branch }}\n          github-token: ${{ secrets.BOT_TOKEN_WORKFLOW }}\n\n      - name: Checkout this repository\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ steps.create-release-branch.outputs.branch }}\n          fetch-tags: true\n\n      - name: Bump and tag project\n        run: bash ci/scripts/bump-and-tag.bash\n        env:\n          LIVE_RUN: ${{ inputs.live-run || false }}\n          VERSION: ${{ steps.create-release-branch.outputs.version }}\n          GIT_USER_NAME: eclipse-zenoh-bot\n          GIT_USER_EMAIL: eclipse-zenoh-bot@users.noreply.github.com\n\n  pre-build:\n    name: Pre-Build\n    needs: tag\n    runs-on: ubuntu-latest\n    outputs:\n      build-linux-matrix: ${{ steps.pre-build.outputs.build-linux-matrix }}\n    steps:\n      - name: Clone this repository\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ needs.tag.outputs.branch }}\n\n      - id: pre-build\n        run: bash ci/scripts/pre-build.bash\n\n  build-macos:\n    name: Build for macOS (x64)\n    needs: [tag, pre-build]\n    runs-on: macos-latest\n    steps:\n      - name: Clone this repository\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ needs.tag.outputs.branch }}\n\n      - id: build-macos\n        run: bash ci/scripts/build-macos.bash\n        env:\n          REPO: ${{ github.repository }}\n          VERSION: ${{ needs.tag.outputs.version }}\n\n      - name: Upload macOS library archive\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.build-macos.outputs.archive-lib }}\n          path: ${{ steps.build-macos.outputs.archive-lib }}\n\n      - name: Upload macOS examples archive\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.build-macos.outputs.archive-examples }}\n          path: ${{ steps.build-macos.outputs.archive-examples }}\n\n  build-linux:\n    name: Crossbuild for ${{ matrix.target }}\n    needs: [tag, pre-build]\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix: ${{ fromJson(needs.pre-build.outputs.build-linux-matrix) }}\n    steps:\n      - name: Clone this repository\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ needs.tag.outputs.branch }}\n\n      - id: build-linux\n        run: bash ci/scripts/build-linux.bash\n        env:\n          REPO: ${{ github.repository }}\n          VERSION: ${{ needs.tag.outputs.version }}\n          TARGET: ${{ matrix.target }}\n\n      - name: Upload Linux library archive for ${{ matrix.target }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.build-linux.outputs.archive-lib }}\n          path: ${{ steps.build-linux.outputs.archive-lib }}\n\n      - name: Upload Linux examples archive for ${{ matrix.target }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.build-linux.outputs.archive-examples }}\n          path: ${{ steps.build-linux.outputs.archive-examples }}\n\n      - name: Upload Linux RPM archive for ${{ matrix.target }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.build-linux.outputs.archive-rpm }}\n          path: ${{ steps.build-linux.outputs.archive-rpm }}\n\n      - name: Upload Linux DEB archive for ${{ matrix.target }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.build-linux.outputs.archive-deb }}\n          path: ${{ steps.build-linux.outputs.archive-deb }}\n\n  debian:\n    name: Publish Debian packages\n    needs: [tag, build-linux]\n    uses: eclipse-zenoh/ci/.github/workflows/release-crates-debian.yml@main\n    with:\n      no-build: true\n      live-run: ${{ inputs.live-run || false }}\n      version: ${{ needs.tag.outputs.version }}\n      repo: ${{ github.repository }}\n      branch: ${{ needs.tag.outputs.branch }}\n    secrets: inherit\n\n  eclipse:\n    needs: [tag, build-macos, build-linux]\n    runs-on: ubuntu-latest\n    steps:\n      - uses: eclipse-zenoh/ci/publish-crates-eclipse@main\n        with:\n          live-run: ${{ inputs.live-run || false }}\n          version: ${{ needs.tag.outputs.version }}\n          ssh-host: genie.zenoh@projects-storage.eclipse.org\n          ssh-host-path: /home/data/httpd/download.eclipse.org/zenoh/zenoh-pico\n          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}\n          ssh-passphrase: ${{ secrets.SSH_PASSPHRASE }}\n          archive-patterns: '.*\\.zip'\n\n  github:\n    needs: [tag, build-macos, build-linux]\n    runs-on: ubuntu-latest\n    steps:\n      - uses: eclipse-zenoh/ci/publish-crates-github@main\n        with:\n          repo: ${{ github.repository }}\n          live-run: ${{ inputs.live-run || false }}\n          version: ${{ needs.tag.outputs.version }}\n          branch: ${{ needs.tag.outputs.branch }}\n          github-token: ${{ secrets.BOT_TOKEN_WORKFLOW }}\n          archive-patterns: '.*\\.zip'\n"
  },
  {
    "path": ".github/workflows/rpi_pico.yaml",
    "content": "#\n# Copyright (c) 2024 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: rpi_pico \n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }} for ${{ matrix.pico_board }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest]\n        pico_board: [\"pico\", \"pico_w\", \"pico2\", \"pico2_w\"]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: jwlawson/actions-setup-cmake@v1.13\n      - name: Install requirements\n        run: |\n          sudo apt update\n          sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential g++ libstdc++-arm-none-eabi-newlib\n          \n      - name: Install Raspberry Pico SDK \n        run: |\n          export PICO_SDK_PATH=$HOME/work/pico-sdk\n          mkdir -p $PICO_SDK_PATH\n          cd $PICO_SDK_PATH\n          git clone https://github.com/raspberrypi/pico-sdk.git --branch 2.1.1-correct-picotool .\n          git submodule update --init\n          \n      - name: Install FreeRTOS SDK \n        run: |\n          export FREERTOS_KERNEL_PATH=$HOME/work/FreeRTOS-Kernel/\n          mkdir -p $FREERTOS_KERNEL_PATH\n          cd $FREERTOS_KERNEL_PATH\n          git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git .\n          # Some version witch aleready supports the Pico SDK but not the latest, because sometimes latest is broken\n          git checkout e169442c29ba8e26faf033cc0886029dd5812979 \n          git submodule update --init\n          \n      - name: Build examples\n        run: |\n          export PICO_SDK_PATH=$HOME/work/pico-sdk\n          export FREERTOS_KERNEL_PATH=$HOME/work/FreeRTOS-Kernel/\n          cd $HOME/work/zenoh-pico/zenoh-pico/examples/rpi_pico\n          cmake -Bbuild -DWIFI_SSID=wifi_network_ssid -DWIFI_PASSWORD=wifi_network_password -DPICO_BOARD=\"$PICO_BOARD\"\n          cmake --build ./build\n        env:\n          PICO_BOARD: ${{ matrix.pico_board}}\n          CMAKE_POLICY_VERSION_MINIMUM: 3.5\n"
  },
  {
    "path": ".github/workflows/update-release-project.yml",
    "content": "name: Update release project\n\non:\n  issues:\n    types: [opened, edited, labeled]\n  pull_request_target:\n    types: [closed]\n    branches:\n      - main\n\njobs:\n  main:\n    uses: eclipse-zenoh/zenoh/.github/workflows/update-release-project.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/zephyr.yaml",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nname: zephyr\n\non:\n  workflow_call:\n\njobs:\n  build:\n    name: Build on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest]\n\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cache/pip\n            ~/.platformio/.cache\n          key: ${{ runner.os }}-pio\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - name: Install PlatformIO Core\n        run: pip install --upgrade platformio\n\n      - name: Set up project\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          mkdir -p $ZEPHYR_BASE\n          cd $ZEPHYR_BASE\n          pio init -b nucleo_f767zi --project-option=\"framework=zephyr\" --project-option=\"board_build.cmake_extra_args=-DZ_FEATURE_LINK_SERIAL=1\" --project-option=\"build_flags=-DZENOH_LOG_DEBUG\"\n\n          cd $ZEPHYR_BASE/lib\n          ln -s $ZENOH_PICO_BASE\n\n          mkdir -p $ZEPHYR_BASE/zephyr\n          cd $ZEPHYR_BASE/zephyr\n          ln -s $ZENOH_PICO_BASE/docs/zephyr/nucleo_f767zi/prj.conf prj.conf\n          ln -s $ZENOH_PICO_BASE/docs/zephyr/nucleo_f767zi/CMakeLists.txt CMakeLists.txt\n\n      - name: Build z_pub example\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ZEPHYR_BASE/src/*\n          cd $ZEPHYR_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/zephyr/z_pub.c\n\n          cd $ZEPHYR_BASE\n          pio run\n\n      - name: Build z_sub example\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ZEPHYR_BASE/src/*\n          cd $ZEPHYR_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/zephyr/z_sub.c\n\n          cd $ZEPHYR_BASE\n          pio run\n\n      - name: Build z_pull example\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ZEPHYR_BASE/src/*\n          cd $ZEPHYR_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/zephyr/z_pull.c\n\n          cd $ZEPHYR_BASE\n          pio run\n\n      - name: Build z_get example\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ZEPHYR_BASE/src/*\n          cd $ZEPHYR_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/zephyr/z_get.c\n\n          cd $ZEPHYR_BASE\n          pio run\n\n      - name: Build z_queryable example\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ZEPHYR_BASE/src/*\n          cd $ZEPHYR_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/zephyr/z_queryable.c\n\n          cd $ZEPHYR_BASE\n          pio run\n\n      - name: Build z_scout example\n        run: |\n          cd $HOME\n          export ZEPHYR_BASE=$HOME/work/zephyrproject/\n          export ZENOH_PICO_BASE=$HOME/work/zenoh-pico/zenoh-pico/\n\n          rm -rf $ZEPHYR_BASE/src/*\n          cd $ZEPHYR_BASE/src\n          ln -s $ZENOH_PICO_BASE/examples/zephyr/z_scout.c\n\n          cd $ZEPHYR_BASE\n          pio run\n"
  },
  {
    "path": ".gitignore",
    "content": "# CMake\nbuild\nbuild_default\ncrossbuilds\nCMakeFiles\ncompile_commands.json\n\n# vscode\n.vscode \n\n# IntelliJ / CLion \n.idea \ncmake-build-debug\ncmake-build-release \n\n# Prerequisites\n*.d\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Linker output\n*.ilk\n*.map\n*.exp\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Debug files\n*.dSYM/\n*.su\n*.idb\n*.pdb\n*.sarif\n.gdb_history\n\n# Kernel Module Compile Results\n*.mod*\n*.cmd\n.tmp_versions/\nmodules.order\nModule.symvers\nMkfile.old\ndkms.conf\n.cache\n"
  },
  {
    "path": ".markdownlint.yaml",
    "content": "{\n  \"MD013\": false, # Line length limitation\n  \"MD033\": false, # Enable Inline HTML\n  \"MD041\": false, # Allow first line heading\n  \"MD045\": false, # Allow Images have no alternate text\n}"
  },
  {
    "path": ".readthedocs.yaml",
    "content": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\n# Required\nversion: 2\n\n# Set the version of Python and other tools you might need\nbuild:\n  os: ubuntu-22.04\n  tools:\n    python: \"3.11\"\n  apt_packages:\n    - libclang-dev\n\n# Build documentation in the docs/ directory with Sphinx\nsphinx:\n  configuration: docs/conf.py\n\n# We recommend specifying your dependencies to enable reproducible builds:\n# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html\npython:\n  install:\n  - requirements: docs/requirements.txt\n"
  },
  {
    "path": "BSDmakefile",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n.PHONY: test clean\n\n# Build type. This set the CMAKE_BUILD_TYPE variable.\n# Accepted values: Release, Debug, GCov\nBUILD_TYPE?=Release\n\n# Build examples. This sets the BUILD_EXAMPLES variable.\n# Accepted values: ON, OFF\nBUILD_EXAMPLES?=ON\n\n# Build testing. This sets the BUILD_TESTING variable.\n# Accepted values: ON, OFF\nBUILD_TESTING?=ON\n\n# Build integration tests. This sets the BUILD_INTEGRATION variable.\n# Accepted values: ON, OFF\nBUILD_INTEGRATION?=OFF\n\n# Build integration tests. This sets the BUILD_TOOLS variable.\n# Accepted values: ON, OFF\nBUILD_TOOLS?=OFF\n\n# Logging level. This sets the ZENOH_LOG variable.\n# Accepted values (empty string means no log):\n#  ERROR/error\n#  WARN/warn\n#  INFO/info\n#  DEBUG/debug\n#  TRACE/trace\nZENOH_LOG?=\"\"\n\n# zenoh-pico/ directory\nROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\n# Build directory\nBUILD_DIR=build\n\n# Crossbuild directory\nCROSSBUILD_TARGETS=linux-armv5 linux-armv6 linux-armv7 linux-armv7a linux-arm64 linux-mips linux-x86 linux-x64\nCROSSBUILD_DIR=crossbuilds\nCROSSIMG_PREFIX=zenoh-pico_\n# NOTES:\n# - ARM:   old versions of dockcross/dockcross were creating some issues since they used an old GCC (4.8.3) which lacks <stdatomic.h> (even using -std=gnu11)\n\nCMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DZENOH_LOG=$(ZENOH_LOG) -DZENOH_LOG_PRINT=$(ZENOH_LOG_PRINT) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H.\n\nall: make\n\n$(BUILD_DIR)/Makefile:\n\tmkdir -p $(BUILD_DIR)\n\techo $(CMAKE_OPT)\n\tcmake $(CMAKE_OPT) -B$(BUILD_DIR)\n\nmake: $(BUILD_DIR)/Makefile\n\tcmake --build $(BUILD_DIR)\n\ninstall: $(BUILD_DIR)/Makefile\n\tcmake --install $(BUILD_DIR)\n\ntest: make\n\tctest --verbose --test-dir build\n\ncrossbuilds: $(CROSSBUILD_TARGETS)\n\nDOCKER_OK := $(shell docker version 2> /dev/null)\ncheck-docker:\n.ifndef DOCKER_OK\n\t$(error \"Docker is not available. Please install Docker\")\n.endif\n\ncrossbuild: check-docker\n\t@echo \"FROM dockcross/$(CROSSIMG)\\nRUN apt-get update && apt-get -y install rpm\" | docker build -t $(CROSSIMG_PREFIX)$(CROSSIMG) -\n\tdocker run --rm -v $(ROOT_DIR):/workdir -w /workdir $(CROSSIMG_PREFIX)$(CROSSIMG) bash -c \"\\\n\t\tcmake $(CMAKE_OPT) -DPACKAGING=DEB,RPM -DDEBARCH=$(DEBARCH) -DRPMARCH=$(RPMARCH) -B$(CROSSBUILD_DIR)/$(CROSSIMG) && \\\n\t\tmake VERBOSE=1 -C$(CROSSBUILD_DIR)/$(CROSSIMG) all package\"\n\tdocker rmi $(CROSSIMG_PREFIX)$(CROSSIMG)\n\nlinux-armv5:\n\tCROSSIMG=$@ DEBARCH=arm RPMARCH=arm make crossbuild\n\nlinux-armv6:\n\tCROSSIMG=$@ DEBARCH=arm RPMARCH=arm make crossbuild\n\nlinux-armv7:\n\tCROSSIMG=$@ DEBARCH=armhf RPMARCH=armhf make crossbuild\n\nlinux-armv7a:\n\tCROSSIMG=$@ DEBARCH=armhf RPMARCH=armhf make crossbuild\n\nlinux-arm64:\n\tCROSSIMG=$@ DEBARCH=arm64 RPMARCH=aarch64 make crossbuild\n\nlinux-mips:\n\tCROSSIMG=$@ DEBARCH=mips RPMARCH=mips make crossbuild\n\nlinux-x86:\n\tCROSSIMG=$@ DEBARCH=i386 RPMARCH=x86 make crossbuild\n\nlinux-x64:\n\tCROSSIMG=$@ DEBARCH=amd64 RPMARCH=x86_64 make crossbuild\n\nclean:\n\trm -fr $(BUILD_DIR)\n\trm -rf $(CROSSBUILD_DIR)\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n# ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\ncmake_minimum_required(VERSION 3.14)\n\nfile(READ ${CMAKE_CURRENT_SOURCE_DIR}/version.txt version)\n\nproject(zenohpico VERSION ${version} LANGUAGES C)\n\nset(CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake\" ${CMAKE_MODULE_PATH})\ninclude(helpers)\ninclude(platforms)\n\n# Configure header file to define the project version\nset(ZENOH_PICO ${PROJECT_VERSION})\nset(ZENOH_PICO_MAJOR ${PROJECT_VERSION_MAJOR})\nset(ZENOH_PICO_MINOR ${PROJECT_VERSION_MINOR})\nset(ZENOH_PICO_PATCH ${PROJECT_VERSION_PATCH})\nif(PROJECT_VERSION_TWEAK STREQUAL \"\")\n  set(ZENOH_PICO_TWEAK 0)\nelse()\n  set(ZENOH_PICO_TWEAK ${PROJECT_VERSION_TWEAK})\nendif()\n\nconfigure_file(\n  ${CMAKE_CURRENT_SOURCE_DIR}/include/zenoh-pico.h.in\n  ${CMAKE_CURRENT_SOURCE_DIR}/include/zenoh-pico.h\n  @ONLY\n)\n\ninclude(CMakePackageConfigHelpers)\ninclude(GNUInstallDirs)\n\noption(BUILD_SHARED_LIBS \"Build shared libraries if ON, otherwise build static libraries\" ON)\nset(ZP_PLATFORM \"\" CACHE STRING \"Built-in or external platform profile\")\nset(ZP_EXTERNAL_PACKAGES \"\" CACHE STRING \"Optional external CMake packages to load\")\nset(ZENOH_LOG \"\" CACHE STRING \"Use this to set the ZENOH_LOG variable\")\nset(ZENOH_LOG_PRINT \"\" CACHE STRING \"Use this to set the ZENOH_LOG_PRINT variable\")\nset(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL \"\")\nif(CMAKE_EXPORT_COMPILE_COMMANDS)\n  set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES \n      ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})\nendif()\n\nset(ZP_PLATFORM_DIRS \"\")\nset(ZP_EXTERNAL_IMPORTED_TARGETS \"\")\nset(ZP_EXTERNAL_IMPORTED_TARGET_PACKAGES \"\")\nif(NOT ZP_EXTERNAL_PACKAGES STREQUAL \"\")\n  foreach(_zp_external_package IN LISTS ZP_EXTERNAL_PACKAGES)\n    zp_find_external_package(\"${_zp_external_package}\")\n  endforeach()\nendif()\nfind_package(zenohpico_platform CONFIG REQUIRED CONFIGS platformConfig.cmake PATHS \"${CMAKE_CURRENT_SOURCE_DIR}/cmake\"\n             NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)\nif(DEFINED ZP_SYSTEM_LAYER AND NOT \"${ZP_SYSTEM_LAYER}\" STREQUAL \"\")\n  message(FATAL_ERROR \"ZP_SYSTEM_LAYER is no longer supported. Use ZP_PLATFORM instead.\")\nendif()\nif(ZP_PLATFORM STREQUAL \"\")\n  zp_detect_default_platform(_zp_default_platform)\n  set(ZP_PLATFORM \"${_zp_default_platform}\")\nendif()\nif(ZP_PLATFORM STREQUAL \"\")\n  message(FATAL_ERROR \"No platform profile selected. Set ZP_PLATFORM.\")\nendif()\nif(DEFINED Z_FEATURE_LINK_UDP_MULTICAST)\n  set(_zp_link_udp_multicast \"${Z_FEATURE_LINK_UDP_MULTICAST}\")\nelse()\n  set(_zp_link_udp_multicast \"1\")\nendif()\nif(DEFINED Z_FEATURE_MULTICAST_TRANSPORT)\n  set(_zp_multicast_transport \"${Z_FEATURE_MULTICAST_TRANSPORT}\")\nelse()\n  set(_zp_multicast_transport \"1\")\nendif()\nif(\"${_zp_link_udp_multicast}\" STREQUAL \"1\" AND \"${_zp_multicast_transport}\" STREQUAL \"1\")\n  set(ZP_UDP_MULTICAST_ENABLED ON)\nelse()\n  set(ZP_UDP_MULTICAST_ENABLED OFF)\nendif()\nzp_load_platform_profile(\"${ZP_PLATFORM}\")\nif(NOT ZP_PLATFORM_SYSTEM_LAYER STREQUAL \"\")\n  set(ZP_SYSTEM_LAYER \"${ZP_PLATFORM_SYSTEM_LAYER}\")\nelse()\n  set(ZP_SYSTEM_LAYER \"${ZP_PLATFORM}\")\nendif()\nset(ZP_SYSTEM_PLATFORM_HEADER \"${ZP_PLATFORM_SYSTEM_PLATFORM_HEADER}\")\n\nif(CMAKE_SYSTEM_NAME MATCHES \"Windows\")\n  if (BUILD_SHARED_LIBS) \n    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)\n  endif()\nelseif(CMAKE_SYSTEM_NAME MATCHES \"Generic\")\n  if(ZP_SYSTEM_LAYER STREQUAL \"zephyr\")\n    set(PACKAGING OFF) # no packaging support for zephyr\n    set(BUILD_SHARED_LIBS \"OFF\")\n  endif()\nendif()\n\n# Language options\nif(NOT CMAKE_C_STANDARD)\n  if(c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES)\n    set(CMAKE_C_STANDARD 11)\n    message(STATUS \"Setting C11 as the C Standard\")\n  else()\n    # C99 pedantic doesn't like unix header anonymous structure\n    set(CMAKE_C_STANDARD 99)\n    message(STATUS \"Setting C99 as the C Standard\")\n  endif()\nendif()\nset(CMAKE_C_STANDARD_REQUIRED TRUE)\n\n# Use cmake .. -DCMAKE_BUILD_TYPE=DEBUG for debug\nif(NOT CMAKE_BUILD_TYPE)\n  set(CMAKE_BUILD_TYPE RELEASE)\nendif()\nstring(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)\n\n# Compile options\nif(CMAKE_BUILD_TYPE MATCHES \"RELEASE\" OR \"Release\")\n  if(UNIX)\n    add_compile_options(-pipe -O3)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"Generic\")\n    add_compile_options(-pipe -O3)\n  endif()\nelse()\n  if(CMAKE_SYSTEM_NAME MATCHES \"PICO\")\n    add_compile_options(-c -Wall -Wextra -Wno-unused -Wno-strict-prototypes -pipe -g -O0)\n  elseif(UNIX)\n    add_compile_options(-c -Wall -Wextra -Werror -Wshadow -Wunused -Wstrict-prototypes -pipe -g -O0)\n    # C99 pedantic doesn't like struct anonymous in unix header\n    if (NOT CMAKE_C_STANDARD STREQUAL \"99\")\n      add_compile_options(-Wpedantic)\n    endif()\n    if(CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n      add_compile_options(-Wconversion)\n    endif()\n  elseif(MSVC)\n    add_compile_options(/W4 /WX /Od /wd4127)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"Generic\")\n    add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes -pipe -g -O0)\n  endif()\nendif()\n\nif (PACKAGING)\n  set(PICO_STATIC ON)\n  set(PICO_SHARED ON)\nendif()\nif(BUILD_SHARED_LIBS)\n  set(PICO_SHARED ON)\nelse()\n  set(PICO_STATIC ON)\nendif()\n\nset(Libname \"zenohpico\")\nif(PICO_STATIC)\n  add_library(${Libname}_static STATIC)\n  set_target_properties(${Libname}_static PROPERTIES OUTPUT_NAME ${Libname})\n  add_library(zenohpico::static ALIAS ${Libname}_static)\nendif()\nif(PICO_SHARED)\n  add_library(${Libname}_shared SHARED)\n  set_target_properties(${Libname}_shared PROPERTIES OUTPUT_NAME ${Libname})\n  add_library(zenohpico::shared ALIAS ${Libname}_shared)\nendif()\nif(BUILD_SHARED_LIBS)\n  add_library(zenohpico::lib ALIAS ${Libname}_shared)\nelse()\n  add_library(zenohpico::lib ALIAS ${Libname}_static)\nendif()\n\nfunction(pico_add_compile_definition value)\n  add_definitions(-D${value})\n  if(PICO_STATIC)\n    target_compile_definitions(zenohpico_static PUBLIC ${value})\n  endif()\n  if(PICO_SHARED)\n    target_compile_definitions(zenohpico_shared PUBLIC ${value})\n  endif()\nendfunction()\n\nfunction(pico_target_link_library value)\n  if(PICO_STATIC)\n    target_link_libraries(zenohpico_static PUBLIC ${value})\n  endif()\n  if(PICO_SHARED)\n    target_link_libraries(zenohpico_shared PRIVATE ${value})\n  endif()\nendfunction()\n\npico_add_compile_definition(ZENOH_C_STANDARD=${CMAKE_C_STANDARD})\n\nif (NOT CMAKE_BUILD_TYPE MATCHES \"RELEASE\" OR \"Release\") \n  # while in development, use timestamp for patch version:\n  string(TIMESTAMP PROJECT_VERSION_PATCH \"%Y%m%ddev\")\n  set(PROJECT_VERSION \"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}\")\nendif()\n\nif(ZP_SYSTEM_LAYER STREQUAL \"macos\")\n  set(MACOSX_RPATH \"ON\")\nendif()\n\nset(_zp_platform_globbed_sources \"\")\nforeach(_zp_platform_source_glob IN LISTS ZP_PLATFORM_SOURCE_GLOBS)\n  file(GLOB _zp_globbed_platform_sources ${_zp_platform_source_glob})\n  list(APPEND _zp_platform_globbed_sources ${_zp_globbed_platform_sources})\nendforeach()\nset(_zp_platform_sources\n    ${_zp_platform_globbed_sources}\n    ${ZP_PLATFORM_SOURCE_FILES})\nset(_zp_platform_include_dirs ${ZP_PLATFORM_INCLUDE_DIRS})\nset(_zp_platform_compile_definitions ${ZP_PLATFORM_COMPILE_DEFINITIONS})\nset(_zp_platform_compile_options ${ZP_PLATFORM_COMPILE_OPTIONS})\nset(_zp_platform_link_libraries ${ZP_PLATFORM_LINK_LIBRARIES})\nset(_zp_platform_imported_targets \"\")\nforeach(_zp_platform_target IN LISTS _zp_platform_link_libraries)\n  if(NOT TARGET \"${_zp_platform_target}\")\n    continue()\n  endif()\n\n  get_property(_zp_is_imported TARGET \"${_zp_platform_target}\" PROPERTY IMPORTED)\n  if(NOT _zp_is_imported)\n    message(FATAL_ERROR\n            \"Platform from ${ZP_PLATFORM_PROFILE_FILE} requires \"\n            \"ZP_PLATFORM_LINK_LIBRARIES targets to be imported/exported package targets. \"\n            \"Local targets created directly inside package config files are not supported \"\n            \"because they break static install/export paths.\")\n  endif()\n\n  get_target_property(_zp_platform_target_type \"${_zp_platform_target}\" TYPE)\n  if(_zp_platform_target_type STREQUAL \"INTERFACE_LIBRARY\")\n    get_target_property_if_set(_zp_interface_sources \"${_zp_platform_target}\" INTERFACE_SOURCES)\n    if(NOT \"${_zp_interface_sources}\" STREQUAL \"\")\n      message(FATAL_ERROR\n              \"External platform target ${_zp_platform_target} must not use INTERFACE_SOURCES. \"\n              \"Define a real library target instead.\")\n    endif()\n  endif()\n\n  list(APPEND _zp_platform_imported_targets \"${_zp_platform_target}\")\nendforeach()\nlist(REMOVE_DUPLICATES _zp_platform_imported_targets)\nzp_source_list_requires_cxx(_zp_platform_uses_cxx ${_zp_platform_sources})\nif(_zp_platform_uses_cxx)\n  set(ZP_USES_CXX ON)\nelse()\n  set(ZP_USES_CXX OFF)\n  foreach(_zp_platform_target IN LISTS _zp_platform_imported_targets)\n    zp_target_requires_cxx(\"${_zp_platform_target}\" _zp_platform_target_uses_cxx)\n    if(_zp_platform_target_uses_cxx)\n      set(ZP_USES_CXX ON)\n      break()\n    endif()\n  endforeach()\nendif()\nif(ZP_USES_CXX)\n  enable_language(CXX)\nendif()\nforeach(_zp_platform_definition IN LISTS _zp_platform_compile_definitions)\n  pico_add_compile_definition(${_zp_platform_definition})\nendforeach()\n\n# Compiler definition\nmessage(\"Compilers in use: ${CMAKE_C_COMPILER_ID}, ${CMAKE_CXX_COMPILER_ID}\")\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\" OR CMAKE_C_COMPILER_ID STREQUAL \"Clang\")\n  pico_add_compile_definition(ZENOH_COMPILER_CLANG)\nelseif (CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_C_COMPILER_ID STREQUAL \"GNU\")\n  pico_add_compile_definition(ZENOH_COMPILER_GCC)\nelseif (CMAKE_CXX_COMPILER_ID STREQUAL \"Intel\" OR CMAKE_C_COMPILER_ID STREQUAL \"Intel\")\n  pico_add_compile_definition(ZENOH_COMPILER_INTEL)\nelseif (CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\" OR CMAKE_C_COMPILER_ID STREQUAL \"MSVC\")\n  pico_add_compile_definition(ZENOH_COMPILER_MSVC)\nelse()\n  pico_add_compile_definition(ZENOH_COMPILER_OTHER)\nendif()\n\n# Logging\nif (DEFINED ZENOH_DEBUG AND NOT (ZENOH_DEBUG STREQUAL \"\"))\n  pico_add_compile_definition(ZENOH_DEBUG=${ZENOH_DEBUG})\nelseif (ZENOH_LOG STREQUAL ERROR OR ZENOH_LOG STREQUAL error)\n  pico_add_compile_definition(ZENOH_LOG_ERROR)\nelseif (ZENOH_LOG STREQUAL WARN OR ZENOH_LOG STREQUAL warn)\n  pico_add_compile_definition(ZENOH_LOG_WARN)\nelseif (ZENOH_LOG STREQUAL INFO OR ZENOH_LOG STREQUAL info)\n  pico_add_compile_definition(ZENOH_LOG_INFO)\nelseif (ZENOH_LOG STREQUAL DEBUG OR ZENOH_LOG STREQUAL debug)\n  pico_add_compile_definition(ZENOH_LOG_DEBUG)\nelseif (ZENOH_LOG STREQUAL TRACE OR ZENOH_LOG STREQUAL trace)\n  pico_add_compile_definition(ZENOH_LOG_TRACE)\nendif()\nif (NOT(ZENOH_LOG_PRINT STREQUAL \"\"))\n pico_add_compile_definition(ZENOH_LOG_PRINT=${ZENOH_LOG_PRINT})\nendif()\nadd_compile_definitions(\"Z_BUILD_LOG=$<CONFIG:Debug>\")\n\n# Zenoh pico feature configuration options\nset(FRAG_MAX_SIZE 4096 CACHE STRING \"Use this to override the maximum size for fragmented messages\")\nset(BATCH_UNICAST_SIZE 2048 CACHE STRING \"Use this to override the maximum unicast batch size\")\nset(BATCH_MULTICAST_SIZE 2048 CACHE STRING \"Use this to override the maximum multicast batch size\")\nset(Z_CONFIG_SOCKET_TIMEOUT 100 CACHE STRING \"Default socket timeout in milliseconds\")\nset(Z_TRANSPORT_LEASE 10000 CACHE STRING \"Link lease duration in milliseconds to announce to other zenoh nodes\")\nset(Z_TRANSPORT_LEASE_EXPIRE_FACTOR 3 CACHE STRING \"Default session lease expire factor.\")\nset(Z_RUNTIME_MAX_TASKS 64 CACHE STRING \"Maximum number of tasks in zenoh-pico's runtime\")\nset(Z_TRANSPORT_ACCEPT_TIMEOUT 1000 CACHE STRING \"Link accept timeout in P2P mode in milliseconds\")\nset(Z_TRANSPORT_CONNECT_TIMEOUT 10000 CACHE STRING \"Link connect timeout in P2P mode inmilliseconds\")\n\nset(Z_FEATURE_UNSTABLE_API 0 CACHE STRING \"Toggle unstable Zenoh-C API\")\nset(Z_FEATURE_CONNECTIVITY 0 CACHE STRING \"Toggle connectivity status/events API (unstable)\")\nset(Z_FEATURE_PUBLICATION 1 CACHE STRING \"Toggle publication feature\")\nset(Z_FEATURE_ADVANCED_PUBLICATION 0 CACHE STRING \"Toggle advanced publication feature\")\nset(Z_FEATURE_SUBSCRIPTION 1 CACHE STRING \"Toggle subscription feature\")\nset(Z_FEATURE_ADVANCED_SUBSCRIPTION 0 CACHE STRING \"Toggle advanced subscription feature\")\nset(Z_FEATURE_QUERY 1 CACHE STRING \"Toggle query feature\")\nset(Z_FEATURE_QUERYABLE 1 CACHE STRING \"Toggle queryable feature\")\nset(Z_FEATURE_LIVELINESS 1 CACHE STRING \"Toggle liveliness feature\")\nset(Z_FEATURE_INTEREST 1 CACHE STRING \"Toggle interests\")\nset(Z_FEATURE_FRAGMENTATION 1 CACHE STRING \"Toggle fragmentation\")\nset(Z_FEATURE_ENCODING_VALUES 1 CACHE STRING \"Toggle encoding values\")\nset(Z_FEATURE_MULTI_THREAD 1 CACHE STRING \"Toggle multithread\")\n\nset(Z_FEATURE_LINK_TCP 1 CACHE STRING \"Toggle TCP links\")\nset(Z_FEATURE_LINK_BLUETOOTH 0 CACHE STRING \"Toggle Bluetooth links\")\nset(Z_FEATURE_LINK_WS 0 CACHE STRING \"Toggle WebSocket links\")\nset(Z_FEATURE_LINK_SERIAL 0 CACHE STRING \"Toggle Serial links\")\nset(Z_FEATURE_LINK_SERIAL_USB 0 CACHE STRING \"Toggle Serial USB links\")\nset(Z_FEATURE_LINK_TLS 0 CACHE STRING \"Toggle TLS links\")\nset(Z_FEATURE_SCOUTING 1 CACHE STRING \"Toggle UDP scouting\")\nset(Z_FEATURE_LINK_UDP_MULTICAST 1 CACHE STRING \"Toggle UDP multicast links\")\nset(Z_FEATURE_LINK_UDP_UNICAST 1 CACHE STRING \"Toggle UDP unicast links\")\nset(Z_FEATURE_MULTICAST_TRANSPORT 1 CACHE STRING \"Toggle multicast transport\")\nset(Z_FEATURE_UNICAST_TRANSPORT 1 CACHE STRING \"Toggle unicast transport\")\nset(Z_FEATURE_RAWETH_TRANSPORT 0 CACHE STRING \"Toggle raw ethernet transport\")\nset(Z_FEATURE_TCP_NODELAY 1 CACHE STRING \"Toggle TCP_NODELAY\")\nset(Z_FEATURE_LOCAL_SUBSCRIBER 0 CACHE STRING \"Toggle local subscriptions\")\nset(Z_FEATURE_SESSION_CHECK 1 CACHE STRING \"Toggle publisher/querier session check\")\nset(Z_FEATURE_BATCHING 1 CACHE STRING \"Toggle batching\")\nset(Z_FEATURE_BATCH_TX_MUTEX 0 CACHE STRING \"Toggle tx mutex lock at a batch level\")\nset(Z_FEATURE_BATCH_PEER_MUTEX 0 CACHE STRING \"Toggle peer mutex lock at a batch level\")\nset(Z_FEATURE_MATCHING 1 CACHE STRING \"Toggle matching feature\")\nset(Z_FEATURE_RX_CACHE 0 CACHE STRING \"Toggle RX_CACHE\")\nset(Z_FEATURE_UNICAST_PEER 1 CACHE STRING \"Toggle Unicast peer mode\")\nset(Z_FEATURE_AUTO_RECONNECT 1 CACHE STRING \"Toggle automatic reconnection\")\nset(Z_FEATURE_MULTICAST_DECLARATIONS 0 CACHE STRING \"Toggle multicast resource declarations\")\nset(Z_FEATURE_LOCAL_QUERYABLE 0 CACHE STRING \"Toggle local queriables\")\nset(Z_FEATURE_ADMIN_SPACE 0 CACHE STRING \"Toggle admin space support\")\n\n# Add a warning message if someone tries to enable Z_FEATURE_LINK_SERIAL_USB directly\nif(Z_FEATURE_LINK_SERIAL_USB AND NOT Z_FEATURE_UNSTABLE_API)\n  message(WARNING \"Z_FEATURE_LINK_SERIAL_USB can only be enabled when Z_FEATURE_UNSTABLE_API is also enabled. Disabling Z_FEATURE_LINK_SERIAL_USB.\")\n  set(Z_FEATURE_LINK_SERIAL_USB 0 CACHE STRING \"Toggle Serial USB links\" FORCE)\nendif()\n\nif(Z_FEATURE_LINK_WS AND NOT ZP_SYSTEM_LAYER STREQUAL \"emscripten\")\n  message(FATAL_ERROR \"Z_FEATURE_LINK_WS is currently only supported on the emscripten platform.\")\nendif()\n\nif(Z_FEATURE_CONNECTIVITY AND NOT Z_FEATURE_UNSTABLE_API)\n  message(WARNING \"Z_FEATURE_CONNECTIVITY can only be enabled when Z_FEATURE_UNSTABLE_API is also enabled. Disabling Z_FEATURE_CONNECTIVITY.\")\n  set(Z_FEATURE_CONNECTIVITY 0 CACHE STRING \"Toggle connectivity status/events API (unstable)\" FORCE)\nendif()\n\nif(Z_FEATURE_MATCHING AND NOT Z_FEATURE_INTEREST)\n  message(STATUS \"Z_FEATURE_MATCHING can only be enabled when Z_FEATURE_INTEREST is also enabled. Disabling Z_FEATURE_MATCHING.\")\n  set(Z_FEATURE_MATCHING 0 CACHE STRING \"Toggle matching feature\" FORCE)\nendif()\n\nif(Z_FEATURE_SCOUTING AND NOT Z_FEATURE_LINK_UDP_UNICAST)\n  message(STATUS \"Z_FEATURE_SCOUTING disabled because Z_FEATURE_LINK_UDP_UNICAST disabled\")\n  set(Z_FEATURE_SCOUTING 0 CACHE STRING \"Toggle scouting feature\" FORCE)\nendif()\n\nif(ZP_SYSTEM_LAYER STREQUAL \"freertos_plus_tcp\" AND Z_FEATURE_LINK_UDP_MULTICAST)\n  message(STATUS \"Z_FEATURE_LINK_UDP_MULTICAST disabled for FreeRTOS-Plus-TCP system layer\")\n  set(Z_FEATURE_LINK_UDP_MULTICAST 0 CACHE STRING \"Toggle UDP multicast links\" FORCE)\nendif()\n\nif(Z_FEATURE_ADVANCED_PUBLICATION AND (NOT Z_FEATURE_UNSTABLE_API OR NOT Z_FEATURE_PUBLICATION OR NOT Z_FEATURE_LIVELINESS))\n  message(WARNING \"Z_FEATURE_ADVANCED_PUBLICATION can only be enabled when Z_FEATURE_UNSTABLE_API, Z_FEATURE_PUBLICATION and Z_FEATURE_LIVELINESS is also enabled. Disabling Z_FEATURE_ADVANCED_PUBLICATION.\")\n  set(Z_FEATURE_ADVANCED_PUBLICATION 0 CACHE STRING \"Toggle advanced publication feature\" FORCE)\nendif()\n\n\nif(Z_FEATURE_ADMIN_SPACE AND NOT Z_FEATURE_UNSTABLE_API)\n  message(WARNING \"Z_FEATURE_ADMIN_SPACE can only be enabled when Z_FEATURE_UNSTABLE_API is enabled. Disabling Z_FEATURE_ADMIN_SPACE.\")\n  set(Z_FEATURE_ADMIN_SPACE 0 CACHE STRING \"Toggle admin space support\" FORCE)\nendif()\n\nif(Z_FEATURE_ADMIN_SPACE AND NOT Z_FEATURE_QUERYABLE)\n  message(WARNING \"Z_FEATURE_ADMIN_SPACE can only be enabled when Z_FEATURE_QUERYABLE is enabled. Disabling Z_FEATURE_ADMIN_SPACE.\")\n  set(Z_FEATURE_ADMIN_SPACE 0 CACHE STRING \"Toggle admin space support\" FORCE)\nendif()\n\n\nmessage(STATUS \"Building with feature config:\\n\\\n* UNSTABLE_API: ${Z_FEATURE_UNSTABLE_API}\\n\\\n* CONNECTIVITY: ${Z_FEATURE_CONNECTIVITY}\\n\\\n* MULTI-THREAD: ${Z_FEATURE_MULTI_THREAD}\\n\\\n* PUBLICATION: ${Z_FEATURE_PUBLICATION}\\n\\\n* SUBSCRIPTION: ${Z_FEATURE_SUBSCRIPTION}\\n\\\n* ADVANCED PUBLICATION: ${Z_FEATURE_ADVANCED_PUBLICATION}\\n\\\n* ADVANCED SUBSCRIPTION: ${Z_FEATURE_ADVANCED_SUBSCRIPTION}\\n\\\n* QUERY: ${Z_FEATURE_QUERY}\\n\\\n* QUERYABLE: ${Z_FEATURE_QUERYABLE}\\n\\\n* LIVELINESS: ${Z_FEATURE_LIVELINESS}\\n\\\n* INTEREST: ${Z_FEATURE_INTEREST}\\n\\\n* AUTO_RECONNECT: ${Z_FEATURE_AUTO_RECONNECT}\\n\\\n* MATCHING: ${Z_FEATURE_MATCHING}\\n\\\n* RAWETH: ${Z_FEATURE_RAWETH_TRANSPORT}\\n\\\n* ADMIN SPACE: ${Z_FEATURE_ADMIN_SPACE}\")\n\nconfigure_file(\n  ${CMAKE_CURRENT_SOURCE_DIR}/include/zenoh-pico/config.h.in\n  ${CMAKE_CURRENT_BINARY_DIR}/include/zenoh-pico/config.h\n  @ONLY\n)\n\n# Print summary of CMAKE configurations\nmessage(STATUS \"Building in ${CMAKE_BUILD_TYPE} mode\")\nmessage(STATUS \"Build shared library: ${BUILD_SHARED_LIBS}\")\nmessage(STATUS \"Zenoh Level Log: ${ZENOH_LOG}\")\nmessage(STATUS \"Fragmented message max size: ${FRAG_MAX_SIZE}\")\nmessage(STATUS \"Unicast batch max size: ${BATCH_UNICAST_SIZE}\")\nmessage(STATUS \"Multicast batch max size: ${BATCH_MULTICAST_SIZE}\")\nif(NOT ZP_PLATFORM STREQUAL \"\")\n  message(STATUS \"Platform profile: ${ZP_PLATFORM}\")\nelse()\n  message(STATUS \"Platform profile: none\")\nendif()\nmessage(STATUS \"System layer: ${ZP_SYSTEM_LAYER}\")\nmessage(STATUS \"Configuring for ${CMAKE_SYSTEM_NAME}\")\n\nif(SKBUILD)\n  set(INSTALL_RPATH \"zenoh\")\n  set(INSTALL_NAME_DIR \"zenoh\")\n  set(INSTALL_INCLUDE_NAME_DIR \"zenoh/include\")\nendif()\n\nset(THREADS_PREFER_PTHREAD_FLAG ON)\nif(CHECK_THREADS)\n  find_package(Threads REQUIRED)\nendif()\n\nif(MSVC)\n  set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /std:c11 /experimental:c11atomics\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /std:c++latest /experimental:c11atomics\")\nendif()\n\nif(PICO_STATIC)\n  target_include_directories(${Libname}_static\n    PUBLIC\n      $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>\n      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\n      $<INSTALL_INTERFACE:include>)\nendif()\nif(PICO_SHARED)\n  target_include_directories(${Libname}_shared\n    PUBLIC\n      $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>\n      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\n      $<INSTALL_INTERFACE:include>)\nendif()\n\n# TLS support via Mbed TLS\nif(Z_FEATURE_LINK_TLS)\n  find_package(PkgConfig REQUIRED)\n\n  # Prefer Mbed TLS 3.x, fall back to 2.x\n  # Never accept 4.x or newer\n  #\n  pkg_search_module(MBEDTLS REQUIRED\n    mbedtls-3>=3.0.0\n    mbedtls>=3.0.0\n    mbedtls>=2.0.0\n  )\n  if(NOT MBEDTLS_VERSION VERSION_LESS \"4.0.0\")\n    message(FATAL_ERROR\n      \"Mbed TLS ${MBEDTLS_VERSION} is not supported. \"\n      \"Please install Mbed TLS 2.x or 3.x.\")\n  endif()\n  message(STATUS \"Using Mbed TLS ${MBEDTLS_VERSION}\")\n\n  pkg_search_module(MBEDX509 OPTIONAL\n    mbedx509-3>=3.0.0\n    mbedx509>=3.0.0\n    mbedx509>=2.0.0)\n\n  pkg_search_module(MBEDCRYPTO OPTIONAL\n    mbedcrypto-3>=3.0.0\n    mbedcrypto>=3.0.0\n    mbedcrypto>=2.0.0)\n\n  set(MBEDTLS_LINK_LIBRARIES\n    ${MBEDTLS_LIBRARIES}\n  )\n\n  if(MBEDX509_FOUND)\n    if(MBEDX509_VERSION AND NOT MBEDX509_VERSION VERSION_EQUAL MBEDTLS_VERSION)\n      message(FATAL_ERROR\n        \"mbedtls (${MBEDTLS_VERSION}) and mbedx509 (${MBEDX509_VERSION}) \"\n        \"versions do not match.\")\n    endif()\n    list(APPEND MBEDTLS_LINK_LIBRARIES ${MBEDX509_LIBRARIES})\n  endif()\n\n  if(MBEDCRYPTO_FOUND)\n    if(MBEDCRYPTO_VERSION AND NOT MBEDCRYPTO_VERSION VERSION_EQUAL MBEDTLS_VERSION)\n      message(FATAL_ERROR\n        \"mbedtls (${MBEDTLS_VERSION}) and mbedcrypto (${MBEDCRYPTO_VERSION}) \"\n        \"versions do not match.\")\n    endif()\n    list(APPEND MBEDTLS_LINK_LIBRARIES ${MBEDCRYPTO_LIBRARIES})\n  endif()\n\n  if(PICO_STATIC)\n    target_include_directories(${Libname}_static PUBLIC ${MBEDTLS_INCLUDE_DIRS})\n    target_link_directories(${Libname}_static PUBLIC ${MBEDTLS_LIBRARY_DIRS})\n    target_link_libraries(${Libname}_static PUBLIC ${MBEDTLS_LINK_LIBRARIES})\n  endif()\n  if(PICO_SHARED)\n    target_include_directories(${Libname}_shared PUBLIC ${MBEDTLS_INCLUDE_DIRS})\n    target_link_directories(${Libname}_shared PUBLIC ${MBEDTLS_LIBRARY_DIRS})\n    target_link_libraries(${Libname}_shared PUBLIC ${MBEDTLS_LINK_LIBRARIES})\n  endif()\nendif()\n\nfile(GLOB_RECURSE Sources\n  \"src/api/*.c\"\n  \"src/collections/*.c\"\n  \"src/net/*.c\"\n  \"src/protocol/*.c\"\n  \"src/runtime/*.c\"\n  \"src/session/*.c\"\n  \"src/transport/*.c\"\n  \"src/utils/*.c\"\n  \"src/system/common/*.c\"\n)\nfile(GLOB LinkSources\n  \"src/link/config/*.c\"\n  \"src/link/multicast/*.c\"\n  \"src/link/unicast/*.c\"\n  \"src/link/transport/common/*.c\"\n)\nlist(APPEND Sources ${LinkSources})\nlist(APPEND Sources\n  \"${PROJECT_SOURCE_DIR}/src/link/link.c\"\n  \"${PROJECT_SOURCE_DIR}/src/link/endpoint.c\"\n  \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/address.c\"\n  \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/address.c\"\n  \"${PROJECT_SOURCE_DIR}/src/link/transport/upper/serial_protocol.c\"\n  \"${PROJECT_SOURCE_DIR}/src/link/transport/upper/tls_stream.c\"\n)\nlist(APPEND Sources ${_zp_platform_sources})\n\nset(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)\nlink_directories(${LIBRARY_OUTPUT_PATH})\n\nif(PICO_STATIC)\n  target_sources(zenohpico_static PRIVATE ${Sources})\nendif()\nif(PICO_SHARED)\n  target_sources(zenohpico_shared PRIVATE ${Sources})\nendif()\nlist(REMOVE_DUPLICATES _zp_platform_include_dirs)\nif(NOT \"${_zp_platform_include_dirs}\" STREQUAL \"\")\n  set(_zp_build_interface_platform_include_dirs \"\")\n  foreach(_zp_platform_include_dir IN LISTS _zp_platform_include_dirs)\n    list(APPEND _zp_build_interface_platform_include_dirs\n         \"$<BUILD_INTERFACE:${_zp_platform_include_dir}>\")\n  endforeach()\n  if(PICO_STATIC)\n    target_include_directories(zenohpico_static PUBLIC ${_zp_build_interface_platform_include_dirs})\n  endif()\n  if(PICO_SHARED)\n    target_include_directories(zenohpico_shared PUBLIC ${_zp_build_interface_platform_include_dirs})\n  endif()\nendif()\nlist(REMOVE_DUPLICATES _zp_platform_compile_definitions)\nforeach(_zp_platform_definition IN LISTS _zp_platform_compile_definitions)\n  pico_add_compile_definition(${_zp_platform_definition})\nendforeach()\nlist(REMOVE_DUPLICATES _zp_platform_compile_options)\nif(NOT \"${_zp_platform_compile_options}\" STREQUAL \"\")\n  if(PICO_STATIC)\n    target_compile_options(zenohpico_static PRIVATE ${_zp_platform_compile_options})\n  endif()\n  if(PICO_SHARED)\n    target_compile_options(zenohpico_shared PRIVATE ${_zp_platform_compile_options})\n  endif()\nendif()\nlist(REMOVE_DUPLICATES _zp_platform_link_libraries)\nforeach(_zp_platform_link_library IN LISTS _zp_platform_link_libraries)\n  pico_target_link_library(\"${_zp_platform_link_library}\")\nendforeach()\n\nif(CHECK_THREADS)\n  pico_target_link_library(Threads::Threads)\nendif()\n\nif(CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n  pico_target_link_library(rt)\nendif()\n\n\n#\n# Build tests, examples, installation only when project is root\n#\nif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})\n\noption(PACKAGING \"Use option on Linux to produce Debian and RPM packages.\" OFF)\noption(BUILD_EXAMPLES \"Use this to also build the examples.\" ON)\noption(BUILD_TOOLS \"Use this to also build the tools.\" OFF)\noption(BUILD_TESTING \"Use this to also build tests.\" ON)\noption(BUILD_INTEGRATION \"Use this to also build integration tests.\" OFF)\noption(ASAN \"Enable AddressSanitizer.\" OFF)\n\nmessage(STATUS \"Produce Debian and RPM packages: ${PACKAGING}\")\nmessage(STATUS \"Build examples: ${BUILD_EXAMPLES}\")\nmessage(STATUS \"Build tools: ${BUILD_TOOLS}\")\nmessage(STATUS \"Build tests: ${BUILD_TESTING}\")\nmessage(STATUS \"Build integration: ${BUILD_INTEGRATION}\")\nmessage(STATUS \"AddressSanitizer: ${ASAN}\")\n\nset(PICO_LIBS \"\")\nif(PICO_STATIC)\n  list(APPEND PICO_LIBS zenohpico_static)\nendif()\nif(PICO_SHARED)\n  list(APPEND PICO_LIBS zenohpico_shared)\nendif()\n\nset(_zp_required_dependency_targets \"\")\nif(PICO_STATIC)\n  list(APPEND _zp_required_dependency_targets ${_zp_platform_imported_targets})\nendif()\nlist(REMOVE_DUPLICATES _zp_required_dependency_targets)\nzp_collect_target_packages(ZP_PACKAGE_DEPENDENCY_PACKAGES\n                           ${_zp_required_dependency_targets})\n\ninstall(TARGETS ${PICO_LIBS}\n  EXPORT zenohpicoTargets\n  LIBRARY DESTINATION lib\n  ARCHIVE DESTINATION lib\n  RUNTIME DESTINATION bin\n  LIBRARY COMPONENT Runtime\n  ARCHIVE COMPONENT Dev\n  RUNTIME COMPONENT Runtime\n)\ninstall(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/zenoh-pico.h\n  DESTINATION include\n  COMPONENT Headers\n)\ninstall(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/zenoh-pico\n  DESTINATION include\n  COMPONENT Headers\n  PATTERN \"include/zenoh-pico/config.h\" EXCLUDE\n)\ninstall(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/zenoh-pico/config.h\n  DESTINATION include/zenoh-pico\n  COMPONENT Headers\n)\nif(BUILD_SHARED_LIBS)\n  set(LIBNAME ${CMAKE_SHARED_LIBRARY_PREFIX}${Libname}${CMAKE_SHARED_LIBRARY_SUFFIX})\nelse()\n  set(LIBNAME ${CMAKE_STATIC_LIBRARY_PREFIX}${Libname}${CMAKE_STATIC_LIBRARY_SUFFIX})\nendif()\n\nset(CMAKE_INSTALL_CMAKEDIR \"${CMAKE_INSTALL_LIBDIR}/cmake/zenohpico\")\n# Generate <Package>Config.cmake\nconfigure_package_config_file(\n  \"PackageConfig.cmake.in\"\n  \"${CMAKE_CURRENT_BINARY_DIR}/zenohpicoConfig.cmake\"\n  INSTALL_DESTINATION \"${CMAKE_INSTALL_CMAKEDIR}\")\n\n# Generate <Package>Version.cmake\nwrite_basic_package_version_file(\n  \"${CMAKE_CURRENT_BINARY_DIR}/zenohpicoConfigVersion.cmake\"\n  VERSION ${PROJECT_VERSION}\n  COMPATIBILITY SameMajorVersion)\n\ninstall(\n  FILES \"${CMAKE_CURRENT_BINARY_DIR}/zenohpicoConfig.cmake\"\n        \"${CMAKE_CURRENT_BINARY_DIR}/zenohpicoConfigVersion.cmake\"\n  DESTINATION \"${CMAKE_INSTALL_CMAKEDIR}\"\n  CONFIGURATIONS ${configurations}\n  COMPONENT Dev)\n\n# Generate <Package>Targets.cmake\ninstall(\n  EXPORT zenohpicoTargets\n  NAMESPACE zenohpico::\n  DESTINATION \"${CMAKE_INSTALL_CMAKEDIR}\"\n  COMPONENT Dev)\n\nif(UNIX)\n  configure_file(\"${CMAKE_CURRENT_SOURCE_DIR}/zenohpico.pc.in\" \"${CMAKE_CURRENT_BINARY_DIR}/zenohpico.pc\" @ONLY)\n  install(FILES \"${CMAKE_CURRENT_BINARY_DIR}/zenohpico.pc\" CONFIGURATIONS Release RelWithDebInfo DESTINATION \"${CMAKE_INSTALL_LIBDIR}/pkgconfig\" COMPONENT Dev)\nendif()\n\nif(ASAN AND NOT MSVC)\n  add_compile_options(-fsanitize=address)\n  add_link_options(-fsanitize=address)\nendif()\n\nif(BUILD_EXAMPLES)\n  add_subdirectory(examples)\nendif()\n\nif(UNIX OR MSVC)\n  if(BUILD_TOOLS)\n    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tools)\n    add_executable(z_keyexpr_canonizer ${PROJECT_SOURCE_DIR}/tools/z_keyexpr_canonizer.c)\n    target_link_libraries(z_keyexpr_canonizer zenohpico::lib)\n  endif()\n\n  if(BUILD_TESTING AND CMAKE_C_STANDARD MATCHES \"11\")\n    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/tests\")\n\n    add_executable(z_data_struct_test ${PROJECT_SOURCE_DIR}/tests/z_data_struct_test.c)\n    add_executable(z_channels_test ${PROJECT_SOURCE_DIR}/tests/z_channels_test.c)\n    add_executable(z_collections_test ${PROJECT_SOURCE_DIR}/tests/z_collections_test.c)\n    add_executable(z_endpoint_test ${PROJECT_SOURCE_DIR}/tests/z_endpoint_test.c)\n    add_executable(z_iobuf_test ${PROJECT_SOURCE_DIR}/tests/z_iobuf_test.c)\n    add_executable(z_msgcodec_test ${PROJECT_SOURCE_DIR}/tests/z_msgcodec_test.c)\n    add_executable(z_keyexpr_test ${PROJECT_SOURCE_DIR}/tests/z_keyexpr_test.c)\n    add_executable(z_api_null_drop_test ${PROJECT_SOURCE_DIR}/tests/z_api_null_drop_test.c)\n    add_executable(z_api_double_drop_test ${PROJECT_SOURCE_DIR}/tests/z_api_double_drop_test.c)\n    add_executable(z_test_fragment_tx ${PROJECT_SOURCE_DIR}/tests/z_test_fragment_tx.c)\n    add_executable(z_test_fragment_rx ${PROJECT_SOURCE_DIR}/tests/z_test_fragment_rx.c)\n    add_executable(z_perf_tx ${PROJECT_SOURCE_DIR}/tests/z_perf_tx.c)\n    add_executable(z_perf_rx ${PROJECT_SOURCE_DIR}/tests/z_perf_rx.c)\n    add_executable(z_bytes_test ${PROJECT_SOURCE_DIR}/tests/z_bytes_test.c)\n    add_executable(z_api_bytes_test ${PROJECT_SOURCE_DIR}/tests/z_api_bytes_test.c)\n    add_executable(z_api_encoding_test ${PROJECT_SOURCE_DIR}/tests/z_api_encoding_test.c)\n    add_executable(z_refcount_test ${PROJECT_SOURCE_DIR}/tests/z_refcount_test.c)\n    add_executable(z_lru_cache_test ${PROJECT_SOURCE_DIR}/tests/z_lru_cache_test.c)\n    add_executable(z_test_peer_unicast ${PROJECT_SOURCE_DIR}/tests/z_test_peer_unicast.c)\n    add_executable(z_test_peer_multicast ${PROJECT_SOURCE_DIR}/tests/z_test_peer_multicast.c)\n    add_executable(z_utils_test ${PROJECT_SOURCE_DIR}/tests/z_utils_test.c)\n    add_executable(z_tls_test ${PROJECT_SOURCE_DIR}/tests/z_tls_test.c)\n    add_executable(z_tls_config_test ${PROJECT_SOURCE_DIR}/tests/z_tls_config_test.c)\n    add_executable(z_condvar_wait_until_test ${PROJECT_SOURCE_DIR}/tests/z_condvar_wait_until_test.c)\n    add_executable(z_sync_group_test ${PROJECT_SOURCE_DIR}/tests/z_sync_group_test.c)\n    add_executable(z_cancellation_token_test ${PROJECT_SOURCE_DIR}/tests/z_cancellation_token_test.c)\n    add_executable(z_local_loopback_test ${PROJECT_SOURCE_DIR}/tests/z_local_loopback_test.c)\n    add_executable(z_open_test ${PROJECT_SOURCE_DIR}/tests/z_open_test.c)\n    add_executable(z_json_encoder_test ${PROJECT_SOURCE_DIR}/tests/z_json_encoder_test.c)\n    add_executable(z_executor_test ${PROJECT_SOURCE_DIR}/tests/z_executor_test.c)\n    add_executable(z_background_executor_test ${PROJECT_SOURCE_DIR}/tests/z_background_executor_test.c)\n    add_executable(z_hashmap_test ${PROJECT_SOURCE_DIR}/tests/z_hashmap_test.c)\n    add_executable(z_pqueue_test ${PROJECT_SOURCE_DIR}/tests/z_pqueue_test.c)\n    add_executable(z_test_fragment_decode_error_transport_zbuf ${PROJECT_SOURCE_DIR}/tests/z_test_fragment_decode_error_transport_zbuf.c)\n\n    target_link_libraries(z_data_struct_test zenohpico::lib)\n    target_link_libraries(z_channels_test zenohpico::lib)\n    target_link_libraries(z_collections_test zenohpico::lib)\n    target_link_libraries(z_endpoint_test zenohpico::lib)\n    target_link_libraries(z_iobuf_test zenohpico::lib)\n    target_link_libraries(z_msgcodec_test zenohpico::lib)\n    target_link_libraries(z_keyexpr_test zenohpico::lib)\n    target_link_libraries(z_api_null_drop_test zenohpico::lib)\n    target_link_libraries(z_api_double_drop_test zenohpico::lib)\n    target_link_libraries(z_test_fragment_tx zenohpico::lib)\n    target_link_libraries(z_test_fragment_rx zenohpico::lib)\n    target_link_libraries(z_perf_tx zenohpico::lib)\n    target_link_libraries(z_perf_rx zenohpico::lib)\n    target_link_libraries(z_bytes_test zenohpico::lib)\n    target_link_libraries(z_api_bytes_test zenohpico::lib)\n    target_link_libraries(z_api_encoding_test zenohpico::lib)\n    target_link_libraries(z_refcount_test zenohpico::lib)\n    target_link_libraries(z_lru_cache_test zenohpico::lib)\n    target_link_libraries(z_test_peer_unicast zenohpico::lib)\n    target_link_libraries(z_test_peer_multicast zenohpico::lib)\n    target_link_libraries(z_utils_test zenohpico::lib)\n    target_link_libraries(z_tls_test zenohpico::lib)\n    target_link_libraries(z_tls_config_test zenohpico::lib)\n    target_link_libraries(z_condvar_wait_until_test zenohpico::lib)\n    target_link_libraries(z_sync_group_test zenohpico::lib)\n    target_link_libraries(z_cancellation_token_test zenohpico::lib)\n    target_link_libraries(z_local_loopback_test zenohpico::lib)\n    target_link_libraries(z_open_test zenohpico::lib)\n    if(CHECK_THREADS)\n      target_link_libraries(z_open_test Threads::Threads)\n    endif()\n    target_compile_definitions(z_local_loopback_test PRIVATE Z_TEST_HOOKS=1)\n    if(PICO_SHARED)\n      target_compile_definitions(${Libname}_shared PRIVATE Z_TEST_HOOKS=1)\n    endif()\n    if(PICO_STATIC)\n      target_compile_definitions(${Libname}_static PRIVATE Z_TEST_HOOKS=1)\n    endif()\n    target_link_libraries(z_json_encoder_test zenohpico::lib)\n    target_link_libraries(z_executor_test zenohpico::lib)\n    target_link_libraries(z_background_executor_test zenohpico::lib)\n    target_link_libraries(z_hashmap_test zenohpico::lib)\n    target_link_libraries(z_pqueue_test zenohpico::lib)\n    target_link_libraries(z_test_fragment_decode_error_transport_zbuf zenohpico::lib)\n    target_compile_definitions(z_test_fragment_decode_error_transport_zbuf PRIVATE Z_TEST_HOOKS=1)\n\n    configure_file(${PROJECT_SOURCE_DIR}/tests/modularity.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/modularity.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/raweth.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/raweth.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/fragment.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/fragment.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/single_thread.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/single_thread.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/attachment.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/attachment.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/no_router.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/no_router.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/memory_leak.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/memory_leak.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/connection_restore.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/connection_restore.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/routed_peer_client.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/routed_peer_client.py COPYONLY)\n    configure_file(${PROJECT_SOURCE_DIR}/tests/valgrind.supp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/valgrind.supp COPYONLY)\n    if(UNIX)\n      configure_file(${PROJECT_SOURCE_DIR}/tests/package_mylinux.sh.in\n                     ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/package_mylinux.sh @ONLY)\n      configure_file(${PROJECT_SOURCE_DIR}/tests/package_myrtos.sh.in\n                     ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/package_myrtos.sh @ONLY)\n    endif()\n\n    enable_testing()\n    add_test(z_data_struct_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_data_struct_test)\n    add_test(z_channels_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_channels_test)\n    add_test(z_collections_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_collections_test)\n    add_test(z_endpoint_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_endpoint_test)\n    add_test(z_iobuf_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_iobuf_test)\n    add_test(z_msgcodec_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_msgcodec_test)\n    add_test(z_keyexpr_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_keyexpr_test)\n    add_test(z_api_null_drop_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_api_null_drop_test)\n    add_test(z_api_double_drop_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_api_double_drop_test)\n    add_test(z_bytes_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_bytes_test)\n    add_test(z_api_bytes_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_api_bytes_test)\n    add_test(z_api_encoding_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_api_encoding_test)\n    add_test(z_refcount_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_refcount_test)\n    add_test(z_lru_cache_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_lru_cache_test)\n    add_test(z_utils_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_utils_test)\n    add_test(z_tls_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_tls_test)\n    add_test(z_tls_config_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_tls_config_test)\n    add_test(z_condvar_wait_until_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_condvar_wait_until_test)\n    add_test(z_sync_group_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_sync_group_test)\n    add_test(z_cancellation_token_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_cancellation_token_test)\n    add_test(z_local_loopback_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_local_loopback_test)\n    add_test(z_open_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_open_test)\n    add_test(z_json_encoder_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_json_encoder_test)\n    add_test(z_executor_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_executor_test)\n    add_test(z_background_executor_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_background_executor_test)\n    add_test(z_hashmap_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_hashmap_test)\n    add_test(z_pqueue_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_pqueue_test)\n    add_test(z_test_fragment_decode_error_transport_zbuf ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_test_fragment_decode_error_transport_zbuf)\n    if(UNIX)\n      add_test(z_package_mylinux_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/package_mylinux.sh)\n      add_test(z_package_myrtos_configure_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/package_myrtos.sh)\n    endif()\n  endif()\n\n  if(BUILD_INTEGRATION)\n    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/tests\")\n\n    if(CMAKE_C_STANDARD MATCHES \"11\")\n      add_executable(z_client_test ${PROJECT_SOURCE_DIR}/tests/z_client_test.c)\n      add_executable(z_api_alignment_test ${PROJECT_SOURCE_DIR}/tests/z_api_alignment_test.c)\n      add_executable(z_wildcard_subscription_test ${PROJECT_SOURCE_DIR}/tests/z_wildcard_subscription_test.c)\n      add_executable(z_api_liveliness_test ${PROJECT_SOURCE_DIR}/tests/z_api_liveliness_test.c)\n      add_executable(z_api_matching_test ${PROJECT_SOURCE_DIR}/tests/z_api_matching_test.c)\n      add_executable(z_api_source_info_test ${PROJECT_SOURCE_DIR}/tests/z_api_source_info_test.c)\n      add_executable(z_api_connectivity_test ${PROJECT_SOURCE_DIR}/tests/z_api_connectivity_test.c)\n      add_executable(z_api_queryable_test ${PROJECT_SOURCE_DIR}/tests/z_api_queryable_test.c)\n      add_executable(z_api_cancellation_test ${PROJECT_SOURCE_DIR}/tests/z_api_cancellation_test.c)\n      add_executable(z_api_local_queryable_test ${PROJECT_SOURCE_DIR}/tests/z_api_local_queryable_test.c)\n      add_executable(z_api_local_subscriber_test ${PROJECT_SOURCE_DIR}/tests/z_api_local_subscriber_test.c)\n      add_executable(z_api_admin_space_test ${PROJECT_SOURCE_DIR}/tests/z_api_admin_space_test.c)\n      add_executable(z_multi_pubsub_test ${PROJECT_SOURCE_DIR}/tests/z_multi_pubsub_test.c)\n      add_executable(z_multi_queryable_test ${PROJECT_SOURCE_DIR}/tests/z_multi_queryable_test.c)\n      add_executable(z_api_batching_test ${PROJECT_SOURCE_DIR}/tests/z_api_batching_test.c)\nif(UNIX)\n      add_executable(z_api_advanced_pubsub_test ${PROJECT_SOURCE_DIR}/tests/z_api_advanced_pubsub_test.c\n                                                ${PROJECT_SOURCE_DIR}/tests/utils/tcp_proxy.c)\n      add_executable(z_api_callback_drop_on_undeclare_test ${PROJECT_SOURCE_DIR}/tests/z_api_callback_drop_on_undeclare_test.c\n                                                ${PROJECT_SOURCE_DIR}/tests/utils/tcp_proxy.c)\n      add_compile_definitions(Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY)\nelse()\n      add_executable(z_api_advanced_pubsub_test ${PROJECT_SOURCE_DIR}/tests/z_api_advanced_pubsub_test.c)\n      add_executable(z_api_callback_drop_on_undeclare_test ${PROJECT_SOURCE_DIR}/tests/z_api_callback_drop_on_undeclare_test.c)\nendif()\n\n      target_link_libraries(z_client_test zenohpico::lib)\n      target_link_libraries(z_api_alignment_test zenohpico::lib)\n      target_link_libraries(z_wildcard_subscription_test zenohpico::lib)\n      target_link_libraries(z_api_liveliness_test zenohpico::lib)\n      target_link_libraries(z_api_matching_test zenohpico::lib)\n      target_link_libraries(z_api_source_info_test zenohpico::lib)\n      target_link_libraries(z_api_connectivity_test zenohpico::lib)\n      target_link_libraries(z_api_queryable_test zenohpico::lib)\n      target_link_libraries(z_api_advanced_pubsub_test zenohpico::lib)\n      target_link_libraries(z_api_cancellation_test zenohpico::lib)\n      target_link_libraries(z_api_local_queryable_test zenohpico::lib)\n      target_link_libraries(z_api_local_subscriber_test zenohpico::lib)\n      target_link_libraries(z_api_admin_space_test zenohpico::lib)\n      target_link_libraries(z_multi_pubsub_test zenohpico::lib)\n      target_link_libraries(z_multi_queryable_test zenohpico::lib)\n      target_link_libraries(z_api_callback_drop_on_undeclare_test zenohpico::lib)\n      target_link_libraries(z_api_batching_test zenohpico::lib)\n\n      configure_file(${PROJECT_SOURCE_DIR}/tests/routed.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/routed.sh COPYONLY)\n      configure_file(${PROJECT_SOURCE_DIR}/tests/tls_verify.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tls_verify.sh COPYONLY)\n      configure_file(${PROJECT_SOURCE_DIR}/tests/api.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh COPYONLY)\n\n      enable_testing()\n      if(Z_FEATURE_LINK_TLS)\n        add_test(z_client_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/routed.sh z_client_test --enable-tls)\n        add_test(z_tls_verify_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tls_verify.sh z_client_test)\n      else()\n        add_test(z_client_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/routed.sh z_client_test)\n      endif()\n      add_test(z_api_alignment_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_alignment_test)\n      add_test(z_wildcard_subscription_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_wildcard_subscription_test)\n      add_test(z_api_liveliness_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_liveliness_test)\n      add_test(z_api_cancellation_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_cancellation_test)\n      add_test(z_api_matching_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_matching_test)\n      add_test(z_api_source_info_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_source_info_test)\n      add_test(z_api_connectivity_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_connectivity_test)\n      add_test(z_api_queryable_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_queryable_test)\n      add_test(z_api_advanced_pubsub_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_advanced_pubsub_test)\n      add_test(z_api_local_queryable_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_local_queryable_test)\n      add_test(z_api_local_subscriber_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_local_subscriber_test)\n      add_test(z_api_admin_space_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_admin_space_test)\n      add_test(z_multi_pubsub_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_multi_pubsub_test)\n      add_test(z_multi_queryable_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_multi_queryable_test)\n      add_test(z_api_callback_drop_on_undeclare_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_callback_drop_on_undeclare_test)\n      add_test(z_api_batching_test bash ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/api.sh z_api_batching_test)\n    endif()\n  endif()\nendif()\n\n# For packaging\nif(PACKAGING)\n\n  set(CPACK_PACKAGE_DIRECTORY \"${CMAKE_BINARY_DIR}/packages\")\n\n  set(CPACK_COMPONENTS_ALL Runtime Headers Dev)\n\n  set(CPACK_COMPONENT_RUNTIME_GROUP \"lib\")\n  set(CPACK_COMPONENT_HEADERS_GROUP \"dev\")\n  set(CPACK_COMPONENT_DEV_GROUP \"dev\")\n  set(CPACK_COMPONENT_HEADERS_DEPENDS Runtime)\n  set(CPACK_COMPONENT_DEV_DEPENDS Runtime)\n\n  set(CPACK_PACKAGE_CHECKSUM MD5)\n  set(CPACK_PACKAGE_VENDOR \"The Eclipse Foundation\")\n  if(NOT CPACK_PACKAGE_VERSION)\n      set(SEM_VER \"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}\")\n      if(PROJECT_VERSION_TWEAK STREQUAL \"\")\n          set(CPACK_PACKAGE_VERSION ${SEM_VER})\n      elseif(PROJECT_VERSION_TWEAK EQUAL 0)\n          set(CPACK_PACKAGE_VERSION \"${SEM_VER}+dev-1\")\n      elseif(PROJECT_VERSION_TWEAK GREATER 0)\n          set(CPACK_PACKAGE_VERSION \"${SEM_VER}+pre.${PROJECT_VERSION_TWEAK}-1\")\n      endif()\n  endif()\n  set(CPACK_COMPONENT_RUNTIME_DESCRIPTION \"The C client library for Eclipse zenoh targeting pico devices\")\n  set(CPACK_COMPONENT_HEADERS_DESCRIPTION \"${CPACK_COMPONENT_LIB_DESCRIPTION} - headers\")\n  set(CPACK_COMPONENT_DEV_DESCRIPTION \"${CPACK_COMPONENT_LIB_DESCRIPTION} - config files\")\n\n  # Sources package\n  set(CPACK_SOURCE_GENERATOR \"TGZ\")\n  set(CPACK_SOURCE_PACKAGE_FILE_NAME \"${PROJECT_NAME}-src-${project_version}\")\n\n  set(CPACK_PACKAGE_FILE_NAME \"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}\")\n\n  if(PACKAGING MATCHES \"DEB\")\n    if(NOT DEBARCH)\n      set(DEBARCH ${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME})\n    endif()\n\n    if(CPACK_GENERATOR)\n      set(CPACK_GENERATOR \"${CPACK_GENERATOR};DEB\")\n    else()\n      set(CPACK_GENERATOR \"DEB\")\n    endif()\n\n    # DEB package\n    set(CPACK_DEBIAN_PACKAGE_MAINTAINER \"ZettaScale Zenoh Team, <zenoh@zettascale.tech>\")\n    set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEBARCH})\n    set(CPACK_DEB_COMPONENT_INSTALL ON)\n    set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)\n    set(CPACK_DEBIAN_LIB_PACKAGE_NAME \"lib${CPACK_PACKAGE_NAME}\")\n    set(CPACK_DEBIAN_LIB_PACKAGE_DEPENDS \"libc6 (>=2.12)\")\n    set(CPACK_DEBIAN_DEV_PACKAGE_NAME \"lib${CPACK_PACKAGE_NAME}-dev\")\n    set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS \"${CPACK_DEBIAN_LIB_PACKAGE_NAME} (=${CPACK_PACKAGE_VERSION})\")\n  endif()\n\n  if(PACKAGING MATCHES \"RPM\")\n    if(NOT RPMARCH)\n      set(RPMARCH ${CMAKE_SYSTEM_PROCESSOR})\n    endif()\n\n    if(CPACK_GENERATOR)\n      set(CPACK_GENERATOR \"${CPACK_GENERATOR};RPM\")\n    else()\n      set(CPACK_GENERATOR \"RPM\")\n    endif()\n\n    # RPM package\n    set(CPACK_RPM_PACKAGE_ARCHITECTURE ${RPMARCH})\n    set(CPACK_RPM_COMPONENT_INSTALL ON)\n    set(CPACK_RPM_FILE_NAME RPM-DEFAULT)\n    set(CPACK_RPM_LIB_PACKAGE_NAME ${CPACK_PACKAGE_NAME}) # avoid \"-lib\" suffix for \"lib\" package\n    set(CPACK_RPM_DEV_PACKAGE_REQUIRES \"${CPACK_RPM_LIB_PACKAGE_NAME} = ${CPACK_PACKAGE_VERSION}\")\n  endif()\n\n  include(CPack)\nendif()\n\nendif()\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Eclipse zenoh\n\nThanks for your interest in this project.\n\n## Project description\n\nEclipse zenoh provides is a stack  designed to\n1. minimize network overhead,\n2. support extremely constrained devices,\n3. supports devices with low duty-cycle by allowing the negotiation of data exchange modes and schedules,\n4. provide a rich set of abstraction for distributing, querying and storing data along the entire system, and\n5. provide extremely low latency and high throughput.\n\n* [https://projects.eclipse.org/projects/iot.zenoh](https://projects.eclipse.org/projects/iot.zenoh)\n\n## Developer resources\n\nInformation regarding source code management, builds, coding standards, and\nmore.\n\n* [https://projects.eclipse.org/projects/iot.zenoh/developer](https://projects.eclipse.org/projects/iot.zenoh/developer)\n\nThe project maintains the following source code repositories\n\n* [https://github.com/eclipse-zenoh](https://github.com/eclipse-zenoh)\n\n## Eclipse Contributor Agreement\n\nBefore your contribution can be accepted by the project team contributors must\nelectronically sign the Eclipse Contributor Agreement (ECA).\n\n* [http://www.eclipse.org/legal/ECA.php](http://www.eclipse.org/legal/ECA.php)\n\nCommits that are provided by non-committers must have a Signed-off-by field in\nthe footer indicating that the author is aware of the terms by which the\ncontribution has been provided to the project. The non-committer must\nadditionally have an Eclipse Foundation account and must have a signed Eclipse\nContributor Agreement (ECA) on file.\n\nFor more information, please see the Eclipse Committer Handbook:\n[https://www.eclipse.org/projects/handbook/#resources-commit](https://www.eclipse.org/projects/handbook/#resources-commit)\n\n## Contact\n\nContact the project developers via the project's \"dev\" list.\n\n* [https://accounts.eclipse.org/mailing-list/zenoh-dev](https://accounts.eclipse.org/mailing-list/zenoh-dev)\n\nOr via the Gitter channel.\n\n* [https://gitter.im/atolab/zenoh](https://gitter.im/atolab/zenoh)\n"
  },
  {
    "path": "CONTRIBUTORS.md",
    "content": "# Contributors to Eclipse zenoh\n\nThese are the contributors to Eclipse zenoh (the initial contributors and the contributors listed in the Git log).\n\n\n| GitHub username | Name                         |\n| --------------- | -----------------------------|\n| kydos           | Angelo Corsaro (ZettaScale)      |\n| JEnoch          | Julien Enoch (ZettaScale)        |\n| OlivierHecart   | Olivier Hécart (ZettaScale)      |\n| gabrik          | Gabriele Baldoni (ZettaScale)    |\n| Mallets         | Luca Cominardi (ZettaScale)      |\n| IvanPaez        | Ivan Paez (ZettaScale)           |\n"
  },
  {
    "path": "GNUmakefile",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n.PHONY: test clean\n\n# Build type. This set the CMAKE_BUILD_TYPE variable.\n# Accepted values: Release, Debug, GCov\nBUILD_TYPE?=Release\n\n# Build examples. This sets the BUILD_EXAMPLES variable.\n# Accepted values: ON, OFF\nBUILD_EXAMPLES?=ON\n\n# Build testing. This sets the BUILD_TESTING variable.\n# Accepted values: ON, OFF\nBUILD_TESTING?=ON\n\n# Build integration tests. This sets the BUILD_INTEGRATION variable.\n# Accepted values: ON, OFF\nBUILD_INTEGRATION?=OFF\n\n# Build integration tests. This sets the BUILD_TOOLS variable.\n# Accepted values: ON, OFF\nBUILD_TOOLS?=OFF\n\n# Force the use of c99 standard.\n# Accepted values: ON, OFF\nFORCE_C99?=OFF\n\n# Enable AddressSanitizer.\n# Accepted values: ON, OFF\nASAN?=OFF\n\n# Logging level. This sets the ZENOH_LOG variable.\n# Accepted values (empty string means no log):\n#  ERROR/error\n#  WARN/warn\n#  INFO/info\n#  DEBUG/debug\n#  TRACE/trace\nZENOH_LOG?=\"\"\n\n# Feature config toggle\n# Accepted values: 0, 1\nZ_FEATURE_UNSTABLE_API?=0\nZ_FEATURE_CONNECTIVITY?=0\nZ_FEATURE_MULTI_THREAD?=1\nZ_FEATURE_PUBLICATION?=1\nZ_FEATURE_ADVANCED_PUBLICATION?=0\nZ_FEATURE_SUBSCRIPTION?=1\nZ_FEATURE_ADVANCED_SUBSCRIPTION?=0\nZ_FEATURE_QUERY?=1\nZ_FEATURE_QUERYABLE?=1\nZ_FEATURE_INTEREST?=1\nZ_FEATURE_LIVELINESS?=1\nZ_FEATURE_SCOUTING?=1\nZ_FEATURE_MATCHING?=1\nZ_FEATURE_UNICAST_TRANSPORT?=1\nZ_FEATURE_MULTICAST_TRANSPORT?=1\nZ_FEATURE_RAWETH_TRANSPORT?=0\nZ_FEATURE_LOCAL_SUBSCRIBER?=0\nZ_FEATURE_LOCAL_QUERYABLE?=0\nZ_FEATURE_UNICAST_PEER?=1\nZ_FEATURE_LINK_TLS?=0\nZ_FEATURE_RX_CACHE?=0\nZ_FEATURE_ADMIN_SPACE?=0\n\n# Buffer sizes\nFRAG_MAX_SIZE?=300000\nBATCH_UNICAST_SIZE?=65535\nBATCH_MULTICAST_SIZE?=8192\n\n# zenoh-pico/ directory\nROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\n# Build directory\nBUILD_DIR=build\n\n# Crossbuild directory\nCROSSBUILD_TARGETS=linux-armv5 linux-armv6 linux-armv7 linux-armv7a linux-arm64 linux-mips linux-x86 linux-x64\nCROSSBUILD_DIR=crossbuilds\nCROSSIMG_PREFIX=zenoh-pico_\n# NOTES:\n# - ARM:   old versions of dockcross/dockcross were creating some issues since they used an old GCC (4.8.3) which lacks <stdatomic.h> (even using -std=gnu11)\n\nCMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DZENOH_LOG=$(ZENOH_LOG) -DZENOH_LOG_PRINT=$(ZENOH_LOG_PRINT) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING)\\\n -DZ_FEATURE_MULTI_THREAD=$(Z_FEATURE_MULTI_THREAD) -DZ_FEATURE_INTEREST=$(Z_FEATURE_INTEREST) -DZ_FEATURE_UNSTABLE_API=$(Z_FEATURE_UNSTABLE_API) -DZ_FEATURE_CONNECTIVITY=$(Z_FEATURE_CONNECTIVITY)\\\n -DZ_FEATURE_PUBLICATION=$(Z_FEATURE_PUBLICATION) -DZ_FEATURE_SUBSCRIPTION=$(Z_FEATURE_SUBSCRIPTION) -DZ_FEATURE_QUERY=$(Z_FEATURE_QUERY) -DZ_FEATURE_QUERYABLE=$(Z_FEATURE_QUERYABLE)\\\n -DZ_FEATURE_LIVELINESS=$(Z_FEATURE_LIVELINESS) -DZ_FEATURE_MATCHING=$(Z_FEATURE_MATCHING) -DZ_FEATURE_SCOUTING=$(Z_FEATURE_SCOUTING)\\\n -DZ_FEATURE_ADVANCED_PUBLICATION=$(Z_FEATURE_ADVANCED_PUBLICATION) -DZ_FEATURE_ADVANCED_SUBSCRIPTION=$(Z_FEATURE_ADVANCED_SUBSCRIPTION)\\\n -DZ_FEATURE_UNICAST_TRANSPORT=$(Z_FEATURE_UNICAST_TRANSPORT) -DZ_FEATURE_MULTICAST_TRANSPORT=$(Z_FEATURE_MULTICAST_TRANSPORT) -DZ_FEATURE_ADMIN_SPACE=$(Z_FEATURE_ADMIN_SPACE)\\\n -DZ_FEATURE_RAWETH_TRANSPORT=$(Z_FEATURE_RAWETH_TRANSPORT) -DZ_FEATURE_LOCAL_SUBSCRIBER=$(Z_FEATURE_LOCAL_SUBSCRIBER) -DZ_FEATURE_LOCAL_QUERYABLE=$(Z_FEATURE_LOCAL_QUERYABLE)\\\n -DFRAG_MAX_SIZE=$(FRAG_MAX_SIZE) -DBATCH_UNICAST_SIZE=$(BATCH_UNICAST_SIZE) -DZ_FEATURE_LINK_TLS=$(Z_FEATURE_LINK_TLS) -DZ_FEATURE_RX_CACHE=$(Z_FEATURE_RX_CACHE)\\\n -DBATCH_MULTICAST_SIZE=$(BATCH_MULTICAST_SIZE) -DZ_FEATURE_UNICAST_PEER=$(Z_FEATURE_UNICAST_PEER) -DASAN=$(ASAN) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H.\n\nifeq ($(FORCE_C99), ON)\n\tCMAKE_OPT += -DCMAKE_C_STANDARD=99\nendif\n\nall: make\n\n$(BUILD_DIR)/Makefile:\n\tmkdir -p $(BUILD_DIR)\n\techo $(CMAKE_OPT)\n\tcmake $(CMAKE_OPT) -B $(BUILD_DIR)\n\nmake: $(BUILD_DIR)/Makefile\n\tcmake --build $(BUILD_DIR)\n\ninstall: $(BUILD_DIR)/Makefile\n\tcmake --install $(BUILD_DIR)\n\ntest: make\n\tif [ \"$(shell uname -s)\" = \"Darwin\" ]; then \\\n\t\tsudo ctest --verbose --test-dir build; \\\n\telse \\\n\t\tctest --verbose --test-dir build; \\\n\tfi\n\ncrossbuilds: $(CROSSBUILD_TARGETS)\n\nDOCKER_OK := $(shell docker version 2> /dev/null)\ncheck-docker:\nifndef DOCKER_OK\n\t$(error \"Docker is not available. Please install Docker\")\nendif\n\ncrossbuild: check-docker\n\t@echo \"FROM dockcross/$(CROSSIMG)\\nRUN apt-get update && apt-get -y install rpm\" | docker build -t $(CROSSIMG_PREFIX)$(CROSSIMG) -\n\tdocker run --rm -v $(ROOT_DIR):/workdir -w /workdir $(CROSSIMG_PREFIX)$(CROSSIMG) bash -c \"\\\n\t\tcmake $(CMAKE_OPT) -DCPACK_PACKAGE_NAME=$(PACKAGE_NAME) -DPACKAGING=DEB,RPM -DDEBARCH=$(DEBARCH) -DRPMARCH=$(RPMARCH) -B$(CROSSBUILD_DIR)/$(CROSSIMG) && \\\n\t\tmake VERBOSE=1 -C$(CROSSBUILD_DIR)/$(CROSSIMG) all package\"\n\tdocker rmi $(CROSSIMG_PREFIX)$(CROSSIMG)\n\nlinux-armv5:\n\tPACKAGE_NAME=\"zenohpico\" CROSSIMG=$@ DEBARCH=arm RPMARCH=arm make crossbuild\n\nlinux-armv6:\n\tPACKAGE_NAME=\"zenohpico-armv6\" CROSSIMG=$@ DEBARCH=arm RPMARCH=arm make crossbuild\n\nlinux-armv7:\n\tPACKAGE_NAME=\"zenohpico\" CROSSIMG=$@ DEBARCH=armhf RPMARCH=armhf make crossbuild\n\nlinux-armv7a:\n\tPACKAGE_NAME=\"zenohpico-armv7a\" CROSSIMG=$@ DEBARCH=armhf RPMARCH=armhf make crossbuild\n\nlinux-arm64:\n\tPACKAGE_NAME=\"zenohpico\" CROSSIMG=$@ DEBARCH=arm64 RPMARCH=aarch64 make crossbuild\n\nlinux-mips:\n\tPACKAGE_NAME=\"zenohpico\" CROSSIMG=$@ DEBARCH=mips RPMARCH=mips make crossbuild\n\nlinux-x86:\n\tPACKAGE_NAME=\"zenohpico\" CROSSIMG=$@ DEBARCH=i386 RPMARCH=x86 make crossbuild\n\nlinux-x64:\n\tPACKAGE_NAME=\"zenohpico\" CROSSIMG=$@ DEBARCH=amd64 RPMARCH=x86_64 make crossbuild\n\nclean:\n\trm -fr $(BUILD_DIR)\n\trm -rf $(CROSSBUILD_DIR)\n"
  },
  {
    "path": "LICENSE",
    "content": "apache-2.0\nepl-2.0\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the pur_poses of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the pur_poses\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the pur_poses of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the pur_pose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational pur_poses only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n    OR\n\nEclipse Public License - v 2.0\n\n    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n    PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR DISTRIBUTION\n    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.\n\n1. DEFINITIONS\n\n\"Contribution\" means:\n\n  a) in the case of the initial Contributor, the initial content\n     Distributed under this Agreement, and\n\n  b) in the case of each subsequent Contributor:\n     i) changes to the Program, and\n     ii) additions to the Program;\n  where such changes and/or additions to the Program originate from\n  and are Distributed by that particular Contributor. A Contribution\n  \"originates\" from a Contributor if it was added to the Program by\n  such Contributor itself or anyone acting on such Contributor's behalf.\n  Contributions do not include changes or additions to the Program that\n  are not Modified Works.\n\n\"Contributor\" means any person or entity that Distributes the Program.\n\n\"Licensed Patents\" mean patent claims licensable by a Contributor which\nare necessarily infringed by the use or sale of its Contribution alone\nor when combined with the Program.\n\n\"Program\" means the Contributions Distributed in accordance with this\nAgreement.\n\n\"Recipient\" means anyone who receives the Program under this Agreement\nor any Secondary License (as applicable), including Contributors.\n\n\"Derivative Works\" shall mean any work, whether in Source Code or other\nform, that is based on (or derived from) the Program and for which the\neditorial revisions, annotations, elaborations, or other modifications\nrepresent, as a whole, an original work of authorship.\n\n\"Modified Works\" shall mean any work in Source Code or other form that\nresults from an addition to, deletion from, or modification of the\ncontents of the Program, including, for pur_poses of clarity any new file\nin Source Code form that contains any contents of the Program. Modified\nWorks shall not include works that contain only declarations,\ninterfaces, types, classes, structures, or files of the Program solely\nin each case in order to link to, bind by name, or subclass the Program\nor Modified Works thereof.\n\n\"Distribute\" means the acts of a) distributing or b) making available\nin any manner that enables the transfer of a copy.\n\n\"Source Code\" means the form of a Program preferred for making\nmodifications, including but not limited to software source code,\ndocumentation source, and configuration files.\n\n\"Secondary License\" means either the GNU General Public License,\nVersion 2.0, or any later versions of that license, including any\nexceptions or additional permissions as identified by the initial\nContributor.\n\n2. GRANT OF RIGHTS\n\n  a) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free copyright\n  license to reproduce, prepare Derivative Works of, publicly display,\n  publicly perform, Distribute and sublicense the Contribution of such\n  Contributor, if any, and such Derivative Works.\n\n  b) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free patent\n  license under Licensed Patents to make, use, sell, offer to sell,\n  import and otherwise transfer the Contribution of such Contributor,\n  if any, in Source Code or other form. This patent license shall\n  apply to the combination of the Contribution and the Program if, at\n  the time the Contribution is added by the Contributor, such addition\n  of the Contribution causes such combination to be covered by the\n  Licensed Patents. The patent license shall not apply to any other\n  combinations which include the Contribution. No hardware per se is\n  licensed hereunder.\n\n  c) Recipient understands that although each Contributor grants the\n  licenses to its Contributions set forth herein, no assurances are\n  provided by any Contributor that the Program does not infringe the\n  patent or other intellectual property rights of any other entity.\n  Each Contributor disclaims any liability to Recipient for claims\n  brought by any other entity based on infringement of intellectual\n  property rights or otherwise. As a condition to exercising the\n  rights and licenses granted hereunder, each Recipient hereby\n  assumes sole responsibility to secure any other intellectual\n  property rights needed, if any. For example, if a third party\n  patent license is required to allow Recipient to Distribute the\n  Program, it is Recipient's responsibility to acquire that license\n  before distributing the Program.\n\n  d) Each Contributor represents that to its knowledge it has\n  sufficient copyright rights in its Contribution, if any, to grant\n  the copyright license set forth in this Agreement.\n\n  e) Notwithstanding the terms of any Secondary License, no\n  Contributor makes additional grants to any Recipient (other than\n  those set forth in this Agreement) as a result of such Recipient's\n  receipt of the Program under the terms of a Secondary License\n  (if permitted under the terms of Section 3).\n\n3. REQUIREMENTS\n\n3.1 If a Contributor Distributes the Program in any form, then:\n\n  a) the Program must also be made available as Source Code, in\n  accordance with section 3.2, and the Contributor must accompany\n  the Program with a statement that the Source Code for the Program\n  is available under this Agreement, and informs Recipients how to\n  obtain it in a reasonable manner on or through a medium customarily\n  used for software exchange; and\n\n  b) the Contributor may Distribute the Program under a license\n  different than this Agreement, provided that such license:\n     i) effectively disclaims on behalf of all other Contributors all\n     warranties and conditions, express and implied, including\n     warranties or conditions of title and non-infringement, and\n     implied warranties or conditions of merchantability and fitness\n     for a particular pur_pose;\n\n     ii) effectively excludes on behalf of all other Contributors all\n     liability for damages, including direct, indirect, special,\n     incidental and consequential damages, such as lost profits;\n\n     iii) does not attempt to limit or alter the recipients' rights\n     in the Source Code under section 3.2; and\n\n     iv) requires any subsequent distribution of the Program by any\n     party to be under a license that satisfies the requirements\n     of this section 3.\n\n3.2 When the Program is Distributed as Source Code:\n\n  a) it must be made available under this Agreement, or if the\n  Program (i) is combined with other material in a separate file or\n  files made available under a Secondary License, and (ii) the initial\n  Contributor attached to the Source Code the notice described in\n  Exhibit A of this Agreement, then the Program may be made available\n  under the terms of such Secondary Licenses, and\n\n  b) a copy of this Agreement must be included with each copy of\n  the Program.\n\n3.3 Contributors may not remove or alter any copyright, patent,\ntrademark, attribution notices, disclaimers of warranty, or limitations\nof liability (\"notices\") contained within the Program from any copy of\nthe Program which they Distribute, provided that Contributors may add\ntheir own appropriate notices.\n\n4. COMMERCIAL DISTRIBUTION\n\nCommercial distributors of software may accept certain responsibilities\nwith respect to end users, business partners and the like. While this\nlicense is intended to facilitate the commercial use of the Program,\nthe Contributor who includes the Program in a commercial product\noffering should do so in a manner which does not create potential\nliability for other Contributors. Therefore, if a Contributor includes\nthe Program in a commercial product offering, such Contributor\n(\"Commercial Contributor\") hereby agrees to defend and indemnify every\nother Contributor (\"Indemnified Contributor\") against any losses,\ndamages and costs (collectively \"Losses\") arising from claims, lawsuits\nand other legal actions brought by a third party against the Indemnified\nContributor to the extent caused by the acts or omissions of such\nCommercial Contributor in connection with its distribution of the Program\nin a commercial product offering. The obligations in this section do not\napply to any claims or Losses relating to any actual or alleged\nintellectual property infringement. In order to qualify, an Indemnified\nContributor must: a) promptly notify the Commercial Contributor in\nwriting of such claim, and b) allow the Commercial Contributor to control,\nand cooperate with the Commercial Contributor in, the defense and any\nrelated settlement negotiations. The Indemnified Contributor may\nparticipate in any such claim at its own expense.\n\nFor example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those performance\nclaims and warranties, and if a court requires any other Contributor to\npay any damages as a result, the Commercial Contributor must pay\nthose damages.\n\n5. NO WARRANTY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN \"AS IS\"\nBASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR\nIMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF\nTITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR\nPURPOSE. Each Recipient is solely responsible for determining the\nappropriateness of using and distributing the Program and assumes all\nrisks associated with its exercise of rights under this Agreement,\nincluding but not limited to the risks and costs of program errors,\ncompliance with applicable laws, damage to or loss of data, programs\nor equipment, and unavailability or interruption of operations.\n\n6. DISCLAIMER OF LIABILITY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS\nSHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST\nPROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE\nEXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n7. GENERAL\n\nIf any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further\naction by the parties hereto, such provision shall be reformed to the\nminimum extent necessary to make such provision valid and enforceable.\n\nIf Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other software\nor hardware) infringes such Recipient's patent(s), then such Recipient's\nrights granted under Section 2(b) shall terminate as of the date such\nlitigation is filed.\n\nAll Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of\ntime after becoming aware of such noncompliance. If all Recipient's\nrights under this Agreement terminate, Recipient agrees to cease use\nand distribution of the Program as soon as reasonably practicable.\nHowever, Recipient's obligations under this Agreement and any licenses\ngranted by Recipient relating to the Program shall continue and survive.\n\nEveryone is permitted to copy and distribute copies of this Agreement,\nbut in order to avoid inconsistency the Agreement is copyrighted and\nmay only be modified in the following manner. The Agreement Steward\nreserves the right to publish new versions (including revisions) of\nthis Agreement from time to time. No one other than the Agreement\nSteward has the right to modify this Agreement. The Eclipse Foundation\nis the initial Agreement Steward. The Eclipse Foundation may assign the\nresponsibility to serve as the Agreement Steward to a suitable separate\nentity. Each new version of the Agreement will be given a distinguishing\nversion number. The Program (including Contributions) may always be\nDistributed subject to the version of the Agreement under which it was\nreceived. In addition, after a new version of the Agreement is published,\nContributor may elect to Distribute the Program (including its\nContributions) under the new version.\n\nExcept as expressly stated in Sections 2(a) and 2(b) above, Recipient\nreceives no rights or licenses to the intellectual property of any\nContributor under this Agreement, whether expressly, by implication,\nestoppel or otherwise. All rights in the Program not expressly granted\nunder this Agreement are reserved. Nothing in this Agreement is intended\nto be enforceable by any entity that is not a Contributor or Recipient.\nNo third-party beneficiary rights are created under this Agreement.\n\nExhibit A - Form of Secondary Licenses Notice\n\n\"This Source Code may also be made available under the following\nSecondary Licenses when the conditions for such availability set forth\nin the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\nversion(s), and exceptions or additional permissions here}.\"\n\n  Simply including a copy of this Agreement, including this Exhibit A\n  is not sufficient to license the Source Code under Secondary Licenses.\n\n  If it is not possible or desirable to put the notice in a particular\n  file, then You may include the notice in a location (such as a LICENSE\n  file in a relevant directory) where a recipient would be likely to\n  look for such a notice.\n\n  You may add additional accurate notices of copyright ownership.\n\n"
  },
  {
    "path": "NOTICE.md",
    "content": "# Notices for Eclipse zenoh-pico\n\nThis content is produced and maintained by the Eclipse zenoh project.\n\n* Project home: [https://projects.eclipse.org/projects/iot.zenoh](https://projects.eclipse.org/projects/iot.zenoh)\n\n## Trademarks\n\nEclipse zenoh is trademark of the Eclipse Foundation.\nEclipse, and the Eclipse Logo are registered trademarks of the Eclipse Foundation.\n\n## Copyright\n\nAll content is the property of the respective authors or their employers.\nFor more information regarding authorship of content, please consult the\nlisted source code repository logs.\n\n## Declared Project Licenses\n\nThis program and the accompanying materials are made available under the\nterms of the Eclipse Public License 2.0 which is available at\n[http://www.eclipse.org/legal/epl-2.0](http://www.eclipse.org/legal/epl-2.0), or the Apache License, Version 2.0\nwhich is available at [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0).\n\nSPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n\n## Source Code\n\nThe project maintains the following source code repositories:\n\n* [https://github.com/eclipse-zenoh/zenoh.git](https://github.com/eclipse-zenoh/zenoh.git)\n* [https://github.com/eclipse-zenoh/zenoh-pico.git](https://github.com/eclipse-zenoh/zenoh-pico.git)\n* [https://github.com/eclipse-zenoh/zenoh-java.git](https://github.com/eclipse-zenoh/zenoh-java.git)\n* [https://github.com/eclipse-zenoh/zenoh-go.git](https://github.com/eclipse-zenoh/zenoh-go.git)\n* [https://github.com/eclipse-zenoh/zenoh-python.git](https://github.com/eclipse-zenoh/zenoh-python.git)\n\n## Third-party Content\n\n*To be completed...*\n\n"
  },
  {
    "path": "PackageConfig.cmake.in",
    "content": "include(CMakeFindDependencyMacro)\n\nset(ZENOHPICO_FEATURE_UNSTABLE_API @Z_FEATURE_UNSTABLE_API@)\nset(ZENOHPICO_FEATURE_CONNECTIVITY @Z_FEATURE_CONNECTIVITY@)\nset(ZENOHPICO_FEATURE_MULTI_THREAD @Z_FEATURE_MULTI_THREAD@)\nset(ZENOHPICO_FEATURE_PUBLICATION @Z_FEATURE_PUBLICATION@)\nset(ZENOHPICO_FEATURE_ADVANCED_PUBLICATION @Z_FEATURE_ADVANCED_PUBLICATION@)\nset(ZENOHPICO_FEATURE_SUBSCRIPTION @Z_FEATURE_SUBSCRIPTION@)\nset(ZENOHPICO_FEATURE_ADVANCED_SUBSCRIPTION @Z_FEATURE_ADVANCED_SUBSCRIPTION@)\nset(ZENOHPICO_FEATURE_QUERY @Z_FEATURE_QUERY@)\nset(ZENOHPICO_FEATURE_QUERYABLE @Z_FEATURE_QUERYABLE@)\nset(ZENOHPICO_FEATURE_RAWETH_TRANSPORT @Z_FEATURE_RAWETH_TRANSPORT@)\nset(ZENOHPICO_FEATURE_INTEREST @Z_FEATURE_INTEREST@)\nset(ZENOHPICO_FEATURE_LIVELINESS @Z_FEATURE_LIVELINESS@)\nset(ZENOHPICO_FEATURE_BATCHING @Z_FEATURE_BATCHING@)\n\nif(@CHECK_THREADS@)\n  find_dependency(Threads REQUIRED)\nendif()\n\nset(_zenohpico_dependency_packages \"@ZP_PACKAGE_DEPENDENCY_PACKAGES@\")\nforeach(_zenohpico_dependency_package IN LISTS _zenohpico_dependency_packages)\n  if(NOT _zenohpico_dependency_package STREQUAL \"\")\n    find_dependency(${_zenohpico_dependency_package} CONFIG REQUIRED)\n  endif()\nendforeach()\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/zenohpicoTargets.cmake\")\n\nif(@PICO_SHARED@)\n  add_library(zenohpico::shared ALIAS zenohpico::zenohpico_shared)\nendif()\nif(@PICO_STATIC@)\n  add_library(zenohpico::static ALIAS zenohpico::zenohpico_static)\nendif()\n\nif(@BUILD_SHARED_LIBS@)\n  add_library(zenohpico::lib ALIAS zenohpico::zenohpico_shared)\nelse()\n  add_library(zenohpico::lib ALIAS zenohpico::zenohpico_static)\nendif()\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"https://raw.githubusercontent.com/eclipse-zenoh/zenoh/master/zenoh-dragon.png\" height=\"150\">\n\n![Build](https://github.com/eclipse-zenoh/zenoh-pico/workflows/build/badge.svg)\n![integration](https://github.com/eclipse-zenoh/zenoh-pico/workflows/integration/badge.svg)\n[![Documentation Status](https://readthedocs.org/projects/zenoh-pico/badge/?version=latest)](https://zenoh-pico.readthedocs.io/en/latest/?badge=latest)\n[![Discussion](https://img.shields.io/badge/discussion-on%20github-blue)](https://github.com/eclipse-zenoh/roadmap/discussions)\n[![Discord](https://img.shields.io/badge/chat-on%20discord-blue)](https://discord.gg/2GJ958VuHs)\n[![License](https://img.shields.io/badge/License-EPL%202.0-blue)](https://choosealicense.com/licenses/epl-2.0/)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\n# Eclipse Zenoh\n\nThe Eclipse Zenoh: Zero Overhead Pub/sub, Store/Query and Compute.\n\nZenoh (pronounce _/zeno/_) unifies data in motion, data at rest, and computations. It carefully blends traditional pub/sub with geo-distributed storages, queries and computations, while retaining a level of time and space efficiency that is well beyond any of the mainstream stacks.\n\nCheck the website [zenoh.io](http://zenoh.io) and the [roadmap](https://github.com/eclipse-zenoh/roadmap) for more detailed information.\n\n-------------------------------\n\n# Zenoh-Pico: native C library for constrained devices\n\nzenoh-pico is the [Eclipse zenoh](http://zenoh.io) implementation that targets constrained devices, offering a native C API.\nIt is fully compatible with its main [Rust Zenoh implementation](https://github.com/eclipse-zenoh/zenoh), providing a lightweight implementation of most functionalities.\n\nCurrently, zenoh-pico provides support for the following (RT)OSs and protocols:\n\n|    **(RT)OS**         |        **Transport Layer**       |  **Network Layer**  |                 **Data Link Layer**                |\n|:---------------------:|:--------------------------------:|:-------------------:|:--------------------------------------------------:|\n|       **Unix**        | UDP (unicast and multicast), TCP | IPv4, IPv6, 6LoWPAN |               WiFi, Ethernet, Thread               |\n|     **Windows**       | UDP (unicast and multicast), TCP |      IPv4, IPv6     |                   WiFi, Ethernet                   |\n|      **Zephyr**       | UDP (unicast and multicast), TCP | IPv4, IPv6, 6LoWPAN |           WiFi, Ethernet, Thread, Serial           |\n|     **Arduino**       | UDP (unicast and multicast), TCP |      IPv4, IPv6     | WiFi, Ethernet, Bluetooth (Serial profile), Serial |\n|     **ESP-IDF**       | UDP (unicast and multicast), TCP |      IPv4, IPv6     |               WiFi, Ethernet, Serial               |\n|      **MbedOS**       | UDP (unicast and multicast), TCP |      IPv4, IPv6     |               WiFi, Ethernet, Serial               |\n|      **OpenCR**       | UDP (unicast and multicast), TCP |         IPv4        |                        WiFi                        |\n|    **Emscripten**     |             Websocket            |      IPv4, IPv6     |                   WiFi, Ethernet                   |\n| **FreeRTOS-Plus-TCP** |         UDP (unicast), TCP       |         IPv4        |                      Ethernet                      |\n| **Raspberry Pi Pico** | UDP (unicast and multicast), TCP |         IPv4        |      WiFi (for \"W\" version), Serial, USB (CDC)     |\n\nCheck the website [zenoh.io](http://zenoh.io) and the [roadmap](https://github.com/eclipse-zenoh/roadmap) for more detailed information.\n\n-------------------------------\n\n## 1. How to install it\n\nThe Eclipse zenoh-pico library is available as **Debian**, **RPM**, and **tgz** packages in the [Eclipse zenoh-pico download area](https://download.eclipse.org/zenoh/zenoh-pico/).\nThose packages are built using manylinux2010 x86-32 and x86-64 for compatibility with most Linux platforms.\nThere are two kind of packages:\n\n- **libzenohpico**: only contains the library file (.so)\n- **libzenohpico-dev**: contains the zenoh-pico header files for development and depends on the _libzenohpico_ package\n\nFor other platforms - like RTOS for embedded systems / microcontrollers -, you will need to clone and build the sources. Check [below](#2. how-to-build-it) for more details.\n\n-------------------------------\n\n## 2. How to build it\n\nFor platform profiles and adding a new platform, see [docs/platforms.rst](docs/platforms.rst).\n\n### 2.1 Unix Environments\n\nTo build the **zenoh-pico** library, you need to ensure that [cmake](https://cmake.org) is available\non your platform -- if not please install it.\n\nOnce the [cmake](https://cmake.org) dependency is satisfied, just do the following for **CMake** version 3 and higher:\n\n  -- CMake version 3 and higher --\n\n  ```bash\n  cd /path/to/zenoh-pico\n  make\n  make install # on Linux use **sudo**\n  ```\n\nIf you want to build with debug symbols, set the `BUILD_TYPE=Debug`environment variable before to run make:\n\n  ```bash\n  cd /path/to/zenoh-pico\n  BUILD_TYPE=Debug make\n  make install # on Linux use **sudo**\n  ```\n\nFor those that still have **CMake** version 2.8, do the following commands:\n\n  ```bash\n  cd /path/to/zenoh-pico\n  mkdir build\n  cd build\n  cmake -DCMAKE_BUILD_TYPE=Release ../cmake-2.8\n  make\n  make install # on Linux use **sudo**\n  ```\n\n### 2.2. Real Time Operating System (RTOS) for Embedded Systems and Microcontrollers\n\nIn order to manage and ease the process of building and deploying into a a variety of platforms and frameworks\nfor embedded systems and microcontrollers, [PlatformIO](https://platformio.org) can be\nused as a supporting platform.\n\nOnce the PlatformIO dependency is satisfied, follow the steps below for the\ntested micro controllers.\n\n#### 2.2.1. Zephyr\n\nNote: tested with reel_board, nucleo-f767zi, nucleo-f420zi, and nRF52840 boards.\n\nA typical PlatformIO project for Zephyr framework must have the following\nstructure:\n\n  ```bash\n  project_dir\n  ├── include\n  ├── lib\n  ├── src\n  │    └── main.c\n  ├── zephyr\n  │    ├── prj.conf\n  │    └── CMakeLists.txt\n  └── platformio.ini\n  ```\n\nTo initialize this project structure, execute the following commands:\n\n  ```bash\n  mkdir -p /path/to/project_dir\n  cd /path/to/project_dir\n  platformio init -b reel_board\n  platformio run\n  ```\n\nInclude the CMakelist.txt and prj.conf in the project_dir/zephyr folder as\nshown in the structure above,\n\n  ```bash\n  cp /path/to/zenoh-pico/docs/zephyr/reel_board/CMakelists.txt /path/to/project_dir/zephyr/\n  cp /path/to/zenoh-pico/docs/zephyr/reel_board/prj.conf /path/to/project_dir/zephyr/\n  ```\n\nand add zenoh-pico as a library by doing:\n\n  ```bash\n  ln -s /path/to/zenoh-pico /path/to/project_dir/lib/zenoh-pico\n  ```\n\nor just include the following line in platformio.ini:\n\n  ```ini\n  lib_deps = https://github.com/eclipse-zenoh/zenoh-pico\n  ```\n\nFinally, your code should go into project_dir/src/main.c.\nCheck the examples provided in examples directory.\n\nTo build and upload the code into the board, run the following command:\n\n  ```bash\n  platformio run\n  platformio run -t upload\n  ```\n\n#### 2.2.2. Arduino\n\nNote: tested with az-delivery-devkit-v4 ESP32 board\n\nA typical PlatformIO project for Arduino framework must have the following\nstructure:\n\n  ```bash\n  project_dir\n  ├── include\n  ├── lib\n  ├── src\n  │    └── main.ino\n  └── platformio.ini\n  ```\n\nTo initialize this project structure, execute the following commands:\n\n  ```bash\n  mkdir -p /path/to/project_dir\n  cd /path/to/project_dir\n  platformio init -b az-delivery-devkit-v4\n  platformio run\n  ```\n\nAdd zenoh-pico as a library by doing:\n\n  ```bash\n  ln -s /path/to/zenoh-pico /path/to/project_dir/lib/zenoh-pico\n  ```\n\nor just include the following line in platformio.ini:\n\n  ```ini\n  lib_deps = https://github.com/eclipse-zenoh/zenoh-pico\n  ```\n\nFinally, your code should go into project_dir/src/main.ino.\nCheck the examples provided in examples directory.\n\nTo build and upload the code into the board, run the following command:\n\n  ```bash\n  platformio run\n  platformio run -t upload\n  ```\n\n#### 2.2.3. ESP-IDF\n\nNote: tested with az-delivery-devkit-v4 ESP32 board\n\nA typical PlatformIO project for ESP-IDF framework must have the following\nstructure:\n\n  ```bash\n  project_dir\n  ├── include\n  ├── lib\n  ├── src\n  |    ├── CMakeLists.txt\n  │    └── main.c\n  ├── CMakeLists.txt\n  └── platformio.ini\n  ```\n\nTo initialize this project structure, execute the following commands:\n\n  ```bash\n  mkdir -p /path/to/project_dir\n  cd /path/to/project_dir\n  platformio init -b az-delivery-devkit-v4\n  platformio run\n  ```\n\nAdd zenoh-pico as a library by doing:\n\n  ```bash\n  ln -s /path/to/zenoh-pico /path/to/project_dir/lib/zenoh-pico\n  ```\n\nor just include the following line in platformio.ini:\n\n  ```ini\n  lib_deps = https://github.com/eclipse-zenoh/zenoh-pico\n  ```\n\nFinally, your code should go into project_dir/src/main.ino.\nCheck the examples provided in examples directory.\n\nTo build and upload the code into the board, run the following command:\n\n  ```bash\n  platformio run\n  platformio run -t upload\n  ```\n\n#### 2.2.4. MbedOS\n\nNote: tested with nucleo-f747zi and nucleo-f429zi boards\n\nA typical PlatformIO project for MbedOS framework must have the following structure:\n\n  ```bash\n  project_dir\n  ├── include\n  ├── src\n  │    └── main.ino\n  └── platformio.ini\n  ```\n\nTo initialize this project structure, execute the following commands:\n\n  ```bash\n  mkdir -p /path/to/project_dir\n  cd /path/to/project_dir\n  platformio init -b az-delivery-devkit-v4\n  platformio run\n  ```\n\nAdd zenoh-pico as a library by doing:\n\n  ```bash\n  ln -s /path/to/zenoh-pico /path/to/project_dir/lib/zenoh-pico\n  ```\n\nor just include the following line in platformio.ini:\n\n  ```ini\n  lib_deps = https://github.com/eclipse-zenoh/zenoh-pico\n  ```\n\nFinally, your code should go into project_dir/src/main.ino.\nCheck the examples provided in examples directory.\n\nTo build and upload the code into the board, run the following command:\n\n  ```bash\n  platformio run\n  platformio run -t upload\n  ```\n\n#### 2.2.5. OpenCR\n\nNote: tested with ROBOTIS OpenCR 1.0 board\n\nA typical PlatformIO project for OpenCR framework must have the following structure:\n\n  ```bash\n  project_dir\n  ├── include\n  ├── lib\n  ├── src\n  │    └── main.ino\n  └── platformio.ini\n  ```\n\nNote: to add support for OpenCR in PlatformIO, follow the steps presented in our [blog](https://zenoh.io/blog/2022-02-08-dragonbot/).\n\nTo initialize this project structure, execute the following commands:\n\n  ```bash\n  mkdir -p /path/to/project_dir\n  cd /path/to/project_dir\n  platformio init -b opencr\n  platformio run\n  ```\n\nAdd zenoh-pico as a library by doing:\n\n  ```bash\n  ln -s /path/to/zenoh-pico /path/to/project_dir/lib/zenoh-pico\n  ```\n\nor just include the following line in platformio.ini:\n\n  ```ini\n  lib_deps = https://github.com/eclipse-zenoh/zenoh-pico\n  ```\n\nFinally, your code should go into project_dir/src/main.ino.\nCheck the examples provided in examples directory.\n\nTo build and upload the code into the board, run the following command:\n\n  ```bash\n  platformio run\n  platformio run -t upload\n  ```\n\n#### 2.2.6. Raspberry Pi Pico\n\nNote: tested with `Raspberry Pi Pico W` and `Raspberry Pi Pico 2 W` boards\n\nEnsure your system has the necessary tools and libraries installed. Run the following commands:\n\n```bash\nsudo apt update\nsudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential g++ libstdc++-arm-none-eabi-newlib\n```\n\nSet up the Raspberry Pi Pico SDK by cloning the repository:\n\n```bash\nexport PICO_SDK_PATH=$HOME/src/pico-sdk\nmkdir -p $PICO_SDK_PATH\ncd $PICO_SDK_PATH\ngit clone https://github.com/raspberrypi/pico-sdk.git .\ngit submodule update --init\n```\n\nClone the FreeRTOS Kernel repository for the project:\n\n```bash\nexport FREERTOS_KERNEL_PATH=$HOME/src/FreeRTOS-Kernel/\nmkdir -p $FREERTOS_KERNEL_PATH\ncd $FREERTOS_KERNEL_PATH\ngit clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git .\ngit submodule update --init\n```\n\nSetup and build the examples:\n\n- `PICO_BOARD` - Pico board type: pico, pico_w, pico2, pico2_w (default: pico_w)\n- `WIFI_SSID` - Wi-Fi network SSID\n- `WIFI_PASSWORD` - Wi-Fi password\n- `ZENOH_CONFIG_MODE` - client or peer mode (default: client)\n- `ZENOH_CONFIG_CONNECT` - connect endpoint (only for client mode, optional)\n- `ZENOH_CONFIG_LISTEN` - listen endpoint (only for peer mode, optional)\n\n```bash\ncd examples/rpi_pico\ncmake -Bbuild -DPICO_BOARD=\"pico\" -DWIFI_SSID=wifi_network_ssid -DWIFI_PASSWORD=wifi_network_password -DZENOH_CONFIG_MODE=[client|peer] -DZENOH_CONFIG_CONNECT=connect -DZENOH_CONFIG_LISTEN=listen\ncmake --build ./build\n```\n\nTo flash the Raspberry Pi Pico board, connect it in bootloader mode (it will appear as a removable drive) and copy the generated .uf2 file onto it.\n\n**Serial connection**:\n\nTo connect via UART specify pins or predefined device name and baud rate:\n\ne.g.\n\n```bash\n-DZENOH_CONFIG_CONNECT=\"serial/0.1#baudrate=38400\"\n-DZENOH_CONFIG_CONNECT=\"serial/uart1_0#baudrate=38400\"\n```\n\nValid PIN combinations and associated device names:\n\n| **PINS** | **Device name** |\n|---------:|:---------------:|\n|  0.1     |     uart0_0     |\n|  4.5     |     uart1_0     |\n|  8.9     |     uart1_1     |\n|  12.13   |     uart0_1     |\n|  16.17   |     uart0_2     |\n\n**USB Serial connection (experemental)**:\n\nTo enable this feature, zenoh-pico should be compiled with `Z_FEATURE_LINK_SERIAL_USB` and `Z_FEATURE_UNSTABLE_API` enabled.\n\nTo connect via USB CDC, specify `usb` device:\n\ne.g.\n\n```bash\n-DZENOH_CONFIG_CONNECT=\"serial/usb#baudrate=112500\"\n```\n\nOn the host Zenoh, specify the USB CDC device:\n\ne.g.\n\n```bash\nzenohd -l serial//dev/ttyACM1#baudrate=112500\n```\n\n#### 2.2.7. STM32 ThreadX\n\n1. Create a new project using STMCubeIDE for your target MCU.\n\n2. In CubeMX project configuration tool:\n    - Add and enable AZURE-RTOS(threadx) Middleware.\n    - Enable UART periphery, set up RX DMA in circular mode and enable UART global interrupt.\n    - Move HAL_Tick to TIM peripheral for threadx to work with HAL. (SYS - Timebase source configuration)\n\n3. Generate initialization code with CubeMX.\n\n4. Clone zenoh-pico repository to your project folder (or submodule, copy files)\n\n5. Add zenoh-pico/src to project source folders. Exclude any folders in platforms/* except common and threadx/stm32.\n\n6. Add zenoh-pico/include to project include paths.\n\n7. Edit zenoh-pico/include/config.h to exclude unsuported features or add compile flags\n\n8. Add \"hal.h\" file to your project. This file should include your target hal headers (ex. `#include \"stm32f4xx_hal.h\"`)\n\n9. Add defines to project:\n    - `ZENOH_THREADX_STM32`\n    - `ZENOH_HUART=huartx` (huart1 / huar2, etc...)\n    - `ZENOH_THREADX_STM32_GEN_IRQ=0` (only if you want to write your own interrupt handler)\n\n10. Exclude from build <project_root>/Core/Src/app_threadx.c and replace with one of the z_*.c* files from zenoh-pico/examples/threadx_stm32/\n\n11. Set `TICK_INT_PRIORITY` in stm32xx_hal_conf.h to higher value than SysTick. (0 works ok for testing).\n\n12. Set static bytepool size bigger than 25kB.\n\n13. On host compile zenohd with serial support and run with:\n\n    ```bash\n    zenohd -l serial//dev/ttyACM0#baudrate=115200\n    ```\n\n## 3. Running the Examples\n\nThe simplest way to run some of the example is to get a Docker image of the **zenoh** router (see [http://zenoh.io/docs/getting-started/quick-test/](http://zenoh.io/docs/getting-started/quick-test/)) and then to run the examples on your machine.\n\n### 3.1. Starting the Zenoh Router\n\nAssuming you've pulled the Docker image of the **zenoh** router on a Linux host (to leverage UDP multicast scouting as explained [here](https://zenoh.io/docs/getting-started/quick-test/#run-zenoh-router-in-a-docker-container), then simply do:\n\n```bash\ndocker run --init --net host eclipse/zenoh:main\n```\n\nTo see the zenoh manual page, simply do:\n\n```bash\ndocker run --init --net host eclipse/zenoh:main --help\n```\n\n:warning: **Please notice that the `--net host` option in Docker is restricted to Linux only.**\nThe cause is that Docker doesn't support UDP multicast between a container and its host (see cases [moby/moby#23659](https://github.com/moby/moby/issues/23659), [moby/libnetwork#2397](https://github.com/moby/libnetwork/issues/2397) or [moby/libnetwork#552](https://github.com/moby/libnetwork/issues/552)). The only known way to make it work is to use the `--net host` option that is [only supported on Linux hosts](https://docs.docker.com/network/host/).\n\n### 3.2. Basic Pub/Sub Example\n\nAssuming that (1) you are running the **zenoh** router,  and (2) you are under the build directory, do:\n\n```bash\n./z_sub\n```\n\nAnd on another shell, do:\n\n```bash\n./z_pub\n```\n\n### 3.3. Basic Queryable/Get Example\n\nAssuming you are running the **zenoh** router, do:\n\n```bash\n./z_queryable\n```\n\nAnd on another shell, do:\n\n```bash\n./z_get\n```\n\n### 3.4. Basic Pub/Sub Example - P2P over UDP multicast\n\nZenoh-Pico can also work in P2P mode over UDP multicast. This allows a Zenoh-Pico application to communicate directly with another Zenoh-Pico application without requiring a Zenoh Router.\n\nAssuming that (1) you are under the build directory, do:\n\n```bash\n./z_sub -m peer -l udp/224.0.0.123:7447#iface=lo0\n```\n\nAnd on another shell, do:\n\n```bash\n./z_pub -m peer -l udp/224.0.0.123:7447#iface=lo0\n```\n\nwhere `lo0` is the network interface you want to use for multicast communication.\n\n> [!WARNING]\n> Multicast communication does not perform any negotiation upon group joining. Because of that, it is important that all transport parameters are the same to make sure all your nodes in the system can communicate.\n> One common parameter to configure is the batch size since its default value depends on the actual platform when operating on multicast:\n>\n> - with zenoh-pico you can configure it via the `BATCH_MULTICAST_SIZE` build option (see [below](#error-when-opening-a-session-on-a-microcontroller))\n> - with other Zenoh APIs, set the \"transport/link/tx/batch_size\" value in configuration file\n>\n> E.g., the batch size on Linux and Windows is 65535 bytes, on Mac OS X is 9216, anything else is 8192.\n\n### 3.4. Basic Pub/Sub Example - Mixing Client and P2P communication\n\nTo allow Zenoh-Pico unicast clients to talk to Zenoh-Pico multicast peers, as well as with any other Zenoh client/peer, you need to start a Zenoh Router that listens on both multicast and unicast:\n\n```bash\ndocker run --init --net host eclipse/zenoh:main -l udp/224.0.0.123:7447#iface=lo0 -l tcp/127.0.0.1:7447\n```\n\nAssuming that (1) you are running the **zenoh** router as indicated above, and (2) you are under the build directory, do:\n\n```bash\n./z_sub -m client -e tcp/127.0.0.1:7447 \n```\n\nA subscriber will connect in client mode to the **zenoh** router over TCP unicast.\n\nAnd on another shell, do:\n\n```bash\n./z_pub -m peer -l udp/224.0.0.123:7447#iface=lo0\n```\n\nA publisher will start publishing over UDP multicast and the **zenoh** router will take care of forwarding data from the Zenoh-Pico publisher to the Zenoh-Pico subscriber.\n\n## Troubleshooting\n\n### Activate debug logs\n\nBy default debug logs are deactivated but if you're encountering issues they can help you finding the cause. To activate them you need to pass the build flag value: `-DZENOH_LOG=DEBUG`\n\n### Error when opening a session on a microcontroller\n\nIf you get an error when opening the session even though everything is setup correctly, it might be because the default buffer sizes are too large for the limited memory available on your system.\n\nThe first thing to try is to reduce the values of the following configuration options (found in `CMakeLists.txt`):\n\n- BATCH_UNICAST_SIZE: The maximum size of a packet in client mode.\n- BATCH_MULTICAST_SIZE: The maximum size of a packet in peer mode.\n- FRAG_MAX_SIZE: The maximum size of a message that can be fragmented into multiple packets.\n\nUntil you find values that suits both your app requirements and your system memory constraints.\n\nThese values can also be passed directly as cmake args. For example, in a `platformio.ini` you might write:\n\n```bash\nboard_build.cmake_extra_args=\n  -DBATCH_UNICAST_SIZE=1024\n  -DFRAG_MAX_SIZE=2048\n```\n"
  },
  {
    "path": "ci/scripts/build-linux.bash",
    "content": "#!/usr/bin/env bash\n\nset -xeo pipefail\n\n# Repository\nreadonly repo=${REPO:?input REPO is required}\n# Release number\nreadonly version=${VERSION:?input VERSION is required}\n# Build target\nreadonly target=${TARGET:?input TARGET is required}\n\nBUILD_SHARED_LIBS=ON BUILD_TYPE=RELEASE make \"$target\"\n\nreadonly out=$GITHUB_WORKSPACE\nreadonly repo_name=${repo#*/}\nreadonly archive_lib=$out/$repo_name-$version-$target-standalone.zip\nreadonly archive_deb=$out/$repo_name-$version-$target-debian.zip\nreadonly archive_rpm=$out/$repo_name-$version-$target-rpm.zip\nreadonly archive_examples=$out/$repo_name-$version-$target-examples.zip\n\ncd crossbuilds/\"$target\"\nzip -r \"$archive_lib\" lib\ncd -\nzip -r \"$archive_lib\" include\n\ncd crossbuilds/\"$target\"/packages\nzip -9 -j \"$archive_deb\" ./*.deb\nzip -9 -j \"$archive_rpm\" ./*.rpm\ncd -\n\ncd crossbuilds/\"$target\"/examples\nzip \"$archive_examples\" ./*\ncd -\n\n{ echo \"archive-lib=$(basename \"$archive_lib\")\";\n  echo \"archive-deb=$(basename \"$archive_deb\")\";\n  echo \"archive-rpm=$(basename \"$archive_rpm\")\";\n  echo \"archive-examples=$(basename \"$archive_examples\")\";\n} >> \"$GITHUB_OUTPUT\"\n"
  },
  {
    "path": "ci/scripts/build-macos.bash",
    "content": "#!/usr/bin/env bash\n\nset -xeo pipefail\n\n# Repository\nreadonly repo=${REPO:?input REPO is required}\n# Release number\nreadonly version=${VERSION:?input VERSION is required}\n\nBUILD_TYPE=RELEASE make\n\nreadonly out=$GITHUB_WORKSPACE\nreadonly repo_name=${repo#*/}\nreadonly archive_lib=$out/$repo_name-$version-macos-x64.zip\nreadonly archive_examples=$out/$repo_name-$version-macos-x64-examples.zip\n\ncd build\nzip -r \"$archive_lib\" lib\ncd ..\nzip -r \"$archive_lib\" include\n\ncd build/examples\nzip \"$archive_examples\" ./*\ncd ..\n\n{ echo \"archive-lib=$(basename \"$archive_lib\")\";\n  echo \"archive-examples=$(basename \"$archive_examples\")\";\n} >> \"$GITHUB_OUTPUT\"\n"
  },
  {
    "path": "ci/scripts/bump-and-tag.bash",
    "content": "#!/usr/bin/env bash\n\nset -xeo pipefail\n\nreadonly live_run=${LIVE_RUN:-false}\n# Release number\nreadonly version=${VERSION:?input VERSION is required}\n# Git actor name\nreadonly git_user_name=${GIT_USER_NAME:?input GIT_USER_NAME is required}\n# Git actor email\nreadonly git_user_email=${GIT_USER_EMAIL:?input GIT_USER_EMAIL is required}\n\nexport GIT_AUTHOR_NAME=$git_user_name\nexport GIT_AUTHOR_EMAIL=$git_user_email\nexport GIT_COMMITTER_NAME=$git_user_name\nexport GIT_COMMITTER_EMAIL=$git_user_email\n\n# Bump CMake project version\nprintf '%s' \"$version\" > version.txt\n\n# Update the version field in library.json directly (it is no longer\n# generated by CMake).\ntmp=$(mktemp)\njq --indent 4 --arg v \"$version\" '.version = $v' library.json > \"$tmp\"\nmv \"$tmp\" library.json\n\n# Refresh the in-tree copy of zenoh-pico.h so the release commit (and\n# the tag that points at it) is internally consistent. A short CMake\n# configure is enough — configure_file() writes the file into the\n# source tree as part of the normal configure step.\ncmake -S . -B build-bump -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF\nrm -rf build-bump\n\ngit commit version.txt include/zenoh-pico.h library.json \\\n  -m \"chore: Bump version to $version\"\nif [[ ${live_run} == true ]]; then\n  git tag --force \"$version\" -m \"v$version\"\n  git show-ref --tags\n  git --no-pager log -10\n  git push --force origin\n  git push --force origin \"$version\"\nelse\n  git --no-pager log -10\n  git push --force origin\nfi\n"
  },
  {
    "path": "ci/scripts/pre-build.bash",
    "content": "#!/usr/bin/env bash\n\nset -xeo pipefail\n\n# Extract cross-compilation targets from the Makefile\ncrossbuild_targets=$(sed -n 's/^CROSSBUILD_TARGETS=\\(.*\\)/\\1/p' GNUmakefile | head -n1)\ntarget_matrix=\"{\\\"target\\\": [\\\"${crossbuild_targets// /\\\",\\\"}\\\"]}\"\necho \"build-linux-matrix=$target_matrix\" >> \"$GITHUB_OUTPUT\"\n"
  },
  {
    "path": "cmake/helpers.cmake",
    "content": "#\n# Copyright (c) 2023 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\n#\n# DO NOT add include_guard() to this file\n# It have to be reincluded multiple times on each 'include_project' call to restore\n# functions and macros definitions\n#\n\n#\n# Show VARIABLE = value on configuration stage\n#\nmacro(status_print var)\n  message(STATUS \"${var} = ${${var}}\")\nendmacro()\n\n#\n# Declare cache variable and print VARIABLE = value on configuration stage\n#\nfunction(declare_cache_var var default_value type docstring)\n  set(${var} ${default_value} CACHE ${type} ${docstring})\n  status_print(${var})\nendfunction()\n\n#\n# Declare cache variable which is set to TRUE if project is supposedly\n# loaded as root project into vscode\n#\nfunction(declare_cache_var_true_if_vscode var docstring)\n  if(CMAKE_CURRENT_BINARY_DIR STREQUAL \"${CMAKE_CURRENT_SOURCE_DIR}/build\")\n    set(in_vscode TRUE)\n  else()\n    set(in_vscode FALSE)\n  endif()\n  declare_cache_var(${var} ${in_vscode} BOOL ${docstring})\nendfunction()\n\n#\n# Create target named 'debug_print' which prints VARIABLE = value\n# when this target is built. Useful to debug generated expressions.\n#`\nfunction(debug_print var)\n  if(NOT TARGET debug_print)\n    add_custom_target(debug_print GLOBAL)\n  endif()\n  add_custom_command(COMMAND ${CMAKE_COMMAND} -E echo ${var} = ${${var}} TARGET debug_print)\nendfunction()\n\n#\n# Copy necessary dlls to target runtime directory\n#\nfunction(copy_dlls target)\n  if(WIN32)\n    add_custom_command(\n      TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${target}>\n                                          $<TARGET_FILE_DIR:${target}> COMMAND_EXPAND_LISTS)\n  endif()\nendfunction()\n\n#\n# Select default build config with support of multi config generators\n#\nmacro(set_default_build_type config_type)\n  get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\n  if(GENERATOR_IS_MULTI_CONFIG)\n    if(NOT DEFINED CMAKE_BUILD_TYPE) # if user passed argument '-DCMAKE_BUILD_TYPE=value', use it\n      set(CMAKE_BUILD_TYPE ${config_type})\n    endif()\n    list(FIND CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE} n)\n    if(n LESS 0)\n      message(FATAL_ERROR \"Configuration ${CMAKE_BUILD_TYPE} is not in CMAKE_CONFIGURATION_TYPES\")\n    else()\n      if(CMAKE_GENERATOR STREQUAL \"Ninja Multi-Config\")\n        set(CMAKE_DEFAULT_BUILD_TYPE ${CMAKE_BUILD_TYPE})\n        status_print(CMAKE_DEFAULT_BUILD_TYPE)\n      else()\n        message(STATUS \"Default build type is not supported for generator '${CMAKE_GENERATOR}'\")\n        message(STATUS \"use cmake --build . --config ${config_type}\")\n      endif()\n    endif()\n  else()\n    if(CMAKE_BUILD_TYPE STREQUAL \"\")\n      set(CMAKE_BUILD_TYPE ${config_type})\n    endif()\n    status_print(CMAKE_BUILD_TYPE)\n  endif()\nendmacro()\n\n# Copy necessary dlls to target runtime directory\n#\nfunction(copy_dlls target)\n  if(WIN32)\n    add_custom_command(\n      TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${target}>\n                                          $<TARGET_FILE_DIR:${target}> COMMAND_EXPAND_LISTS)\n  endif()\nendfunction()\n\n#\n# get property value avoiding CMake behavior - setting variable to <VAR>-NOTFOUND for undefined property\n#\nfunction(get_target_property_if_set var target property)\n  get_property(is_set TARGET ${target} PROPERTY ${property} SET)\n  if(NOT is_set)\n    unset(${var} PARENT_SCOPE)\n    return()\n  endif()\n  get_property(value TARGET ${target} PROPERTY ${property})\n  set(${var} ${value} PARENT_SCOPE)\nendfunction()\n\nfunction(zp_source_list_requires_cxx out_var)\n  set(_zp_uses_cxx OFF)\n  foreach(_zp_source IN LISTS ARGN)\n    get_filename_component(_zp_source_ext \"${_zp_source}\" EXT)\n    string(TOLOWER \"${_zp_source_ext}\" _zp_source_ext)\n    if(_zp_source_ext STREQUAL \".cc\" OR _zp_source_ext STREQUAL \".cpp\" OR _zp_source_ext STREQUAL \".cxx\")\n      set(_zp_uses_cxx ON)\n      break()\n    endif()\n  endforeach()\n  set(${out_var} \"${_zp_uses_cxx}\" PARENT_SCOPE)\nendfunction()\n\nfunction(zp_target_requires_cxx target out_var)\n  if(\"${target}\" STREQUAL \"\" OR NOT TARGET \"${target}\")\n    set(${out_var} OFF PARENT_SCOPE)\n    return()\n  endif()\n\n  get_target_property_if_set(_zp_sources \"${target}\" SOURCES)\n  get_target_property_if_set(_zp_interface_sources \"${target}\" INTERFACE_SOURCES)\n  zp_source_list_requires_cxx(_zp_requires_cxx ${_zp_sources} ${_zp_interface_sources})\n  set(${out_var} \"${_zp_requires_cxx}\" PARENT_SCOPE)\nendfunction()\n\nmacro(zp_find_external_package package_name)\n  get_property(_zp_imported_targets_before DIRECTORY PROPERTY IMPORTED_TARGETS)\n  find_package(${package_name} CONFIG REQUIRED)\n  get_property(_zp_imported_targets_after DIRECTORY PROPERTY IMPORTED_TARGETS)\n\n  set(_zp_new_imported_targets ${_zp_imported_targets_after})\n  if(NOT \"${_zp_imported_targets_before}\" STREQUAL \"\")\n    list(REMOVE_ITEM _zp_new_imported_targets ${_zp_imported_targets_before})\n  endif()\n\n  foreach(_zp_target IN LISTS _zp_new_imported_targets)\n    list(FIND ZP_EXTERNAL_IMPORTED_TARGETS \"${_zp_target}\" _zp_target_index)\n    if(_zp_target_index EQUAL -1)\n      list(APPEND ZP_EXTERNAL_IMPORTED_TARGETS \"${_zp_target}\")\n      list(APPEND ZP_EXTERNAL_IMPORTED_TARGET_PACKAGES \"${package_name}\")\n    endif()\n  endforeach()\nendmacro()\n\nfunction(zp_collect_target_packages out_var)\n  set(_zp_packages \"\")\n  foreach(_zp_target IN LISTS ARGN)\n    if(\"${_zp_target}\" STREQUAL \"\" OR NOT TARGET \"${_zp_target}\")\n      continue()\n    endif()\n\n    list(FIND ZP_EXTERNAL_IMPORTED_TARGETS \"${_zp_target}\" _zp_target_index)\n    if(NOT _zp_target_index EQUAL -1)\n      list(GET ZP_EXTERNAL_IMPORTED_TARGET_PACKAGES ${_zp_target_index} _zp_package_name)\n      list(APPEND _zp_packages \"${_zp_package_name}\")\n    endif()\n  endforeach()\n\n  list(REMOVE_DUPLICATES _zp_packages)\n  set(${out_var} \"${_zp_packages}\" PARENT_SCOPE)\nendfunction()\n\n\n#\n# Unset variables if they have empty string value\n#\nmacro(unset_if_empty)\n  foreach(var ${ARGN})\n    if(\"${${var}}\" STREQUAL \"\")\n      unset(${var})\n    endif()\n  endforeach()\nendmacro()\n\n#\n# Usage:\n#\n# include_project(<project_name> TARGET <target>\n#  < PATH <project_path>] [QUIET] |\n#    PACKAGE <package_name>] [QUIET] |\n#    GIT_URL <git_url> [GIT_TAG <git_tag>] >\n# )\n#\n# includes CMake project with one of the following ways:\n#   add_subdirectory(project_path) or\n#   find_package(package_name) or\n#   FetchContent(git_url)\n#\n# If target <target> is already defined, does nothing. If parameter QUIET is passed, does nothing\n# in case of failure to incude project from requested source. This allows to try to load project\n# from first available source, like this:\n#\n# include_project(zenohc TARGET zenohc::lib PATH ..\\zenoh_c QUIET)\n# include_project(zenohc TARGET zenohc::lib PACKAGE zenohc QUIET)\n# include_project(zenohc TARGET zenohc::lib GIT_URL https://github.com/eclipse-zenoh/zenoh-c)\n#\n# QUIET parameter not supported for GIT_URL due to lack of support of such mode in FetchContent\n#\nfunction(include_project)\n  __include_project(${ARGN})\n  # recover functions which may be replaced by included project\n  include(${CMAKE_CURRENT_FUNCTION_LIST_FILE})\nendfunction()\n\nfunction(__include_project project_name)\n  include(FetchContent)\n  include(CMakeParseArguments)\n  cmake_parse_arguments(PARSE_ARGV 1 \"ARG\" \"QUIET\" \"TARGET;PATH;PACKAGE;GIT_URL;GIT_TAG\" \"\")\n  unset_if_empty(ARG_PATH ARG_TARGET ARG_PACKAGE ARG_GIT_URL)\n  if(NOT DEFINED ARG_TARGET)\n    message(FATAL_ERROR \"Non-empty TARGET parameter is required\")\n  endif()\n  if(TARGET ${ARG_TARGET})\n    return()\n  endif()\n\n  if(DEFINED ARG_PATH)\n    message(STATUS \"trying to include project '${project_name} from directory '${ARG_PATH}'\")\n    file(GLOB cmakelists ${ARG_PATH}/CMakeLists.txt)\n    if(NOT (cmakelists STREQUAL \"\"))\n      message(STATUS \"found cmake project in directory, including it\")\n      list(APPEND CMAKE_MESSAGE_INDENT \"  \")\n      add_subdirectory(${ARG_PATH} ${project_name})\n      list(POP_BACK CMAKE_MESSAGE_INDENT)\n      if(TARGET ${ARG_TARGET} OR ARG_QUIET)\n        return()\n      endif()\n      message(FATAL_ERROR \"Project at '${ARG_PATH}' should define target ${ARG_TARGET}\")\n    elseif(ARG_QUIET)\n      return()\n    else()\n      message(FATAL_ERROR \"no CMakeLists.txt file in '${ARG_PATH}'\")\n    endif()\n  elseif(DEFINED ARG_PACKAGE)\n    message(STATUS \"trying to include project '${project_name}' from package '${ARG_PACKAGE}'\")\n    # Give priority to install directory\n    # Useful for development when older version of the project version may be installed in system\n    #\n    # TODO: \"if( NOT TARGET\" below should be not necessary\n    # (see https://cmake.org/cmake/help/latest/command/find_package.html, search for \"override the order\")\n    # but in fact cmake fails without it when zenohc is present both in CMAKE_INSTALL_PREFIX and in /usr/local.\n    # Consider is it still necessary after next bumping up cmake version\n    find_package(${ARG_PACKAGE} PATHS ${CMAKE_INSTALL_PREFIX} NO_DEFAULT_PATH QUIET)\n    if(NOT TARGET ${ARG_TARGET})\n      find_package(${ARG_PACKAGE} QUIET)\n    endif()\n    set(package_path ${${ARG_PACKAGE}_CONFIG})\n    if(TARGET ${ARG_TARGET})\n      message(STATUS \"found the package on path '${package_path}'\")\n      return()\n    endif()\n    if(ARG_QUIET)\n      return()\n    endif()\n    if(\"${package_path}\" STREQUAL \"\")\n      message(FATAL_ERROR \"Package '${ARG_PACKAGE}' not found\")\n    else()\n      message(FATAL_ERROR \"Package '${ARG_PACKAGE}' on path '${package_path}' doesn't define target '${ARG_TARGET}\")\n    endif()\n  elseif(DEFINED ARG_GIT_URL)\n    if(DEFINED ARG_GIT_TAG)\n      set(git_url \"${ARG_GIT_URL}#{ARG_GIT_TAG}\")\n    else()\n      set(git_url ${ARG_GIT_URL})\n    endif()\n    message(STATUS \"trying to include project '${project_name}' from git '${git_url}'\")\n    list(APPEND CMAKE_MESSAGE_INDENT \"  \")\n    if(DEFINED ARG_GIT_TAG)\n      FetchContent_Declare(${project_name} GIT_REPOSITORY ${ARG_GIT_URL} GIT_TAG ${ARG_GIT_TAG})\n    else()\n      FetchContent_Declare(${project_name} GIT_REPOSITORY ${ARG_GIT_URL})\n    endif()\n    FetchContent_MakeAvailable(${project_name})\n    list(POP_BACK CMAKE_MESSAGE_INDENT)\n    if(TARGET ${ARG_TARGET})\n      return()\n    endif()\n    message(FATAL_ERROR \"Project at ${git_url} should define target ${ARG_TARGET}\")\n  else()\n    message(FATAL_ERROR \"No source for project '${project_name}' specified\")\n  endif()\nendfunction()\n\n#\n# Configure set of cache variables\n# Include external project accordingly to these variables\n#\n# Example:\n#\n# configure_include_project(ZENOHC zenohc zenohc::lib \"..\" zenohc \"https://github.com/eclipse-zenoh/zenoh-c\" \"\")\n#\n# This command defines cache variables\n#\n# ZENOHC_SOURCE = \"\"\n# ZENOHC_PATH = \"..\"\n# ZENOHC_PACKAGE = \"zenohc\"\n# ZENOHC_GIT_URL = \"https://github.com/eclipse-zenoh/zenoh-c\"\n# ZENOHC_GIT_TAG = \"\"\n#\n# Then it tries to include the project with name 'zenohc' from first available source in order (PATH,PACKAGE,GIT_URL).\n# Project should define target `zenohc::lib`, otherwise cmake configuration step fails with error.\n#\n# If ZENOHC_SOURCE is set by user to value PATH, PACKAGE or GIT_URL, then the project is included from this source only.\n#\n# For example:\n#\n# cmake ../zenoh-c/examples -DZENOHC_SOURCE=GIT_URL -DZENOHC_GIT_URL=https://github.com/username/zenoh-c\n#\n# makes 'examples' project to compile with zenoh-c from username's zenoh-c git repository\n#\nfunction(configure_include_project var_prefix project target path package git_url git_tag)\n  declare_cache_var(\n    ${var_prefix}_SOURCE \"\" STRING\n    \"Explicit ${project} source type. Can be PATH, PACKAGE or GIT_URL. If empty, tries all these variants in order\")\n  declare_cache_var(${var_prefix}_PATH \"${path}\" STRING \"PATH to ${project} source directory\")\n  declare_cache_var(${var_prefix}_PACKAGE \"${package}\" STRING \"name of ${project} PACKAGE\")\n  declare_cache_var(${var_prefix}_GIT_URL \"${git_url}\" STRING \"GIT_URL of ${project} repository\")\n  declare_cache_var(${var_prefix}_GIT_TAG \"${git_tag}\" STRING \"GIT_TAG of ${project} repository\")\n  if(${var_prefix}_SOURCE STREQUAL \"\")\n    include_project(${project} TARGET ${target} PATH ${${var_prefix}_PATH} QUIET)\n    include_project(${project} TARGET ${target} PACKAGE ${${var_prefix}_PACKAGE} QUIET)\n    include_project(${project} TARGET ${target} GIT_URL ${${var_prefix}_GIT_URL} GIT_TAG ${${var_prefix}_GIT_TAG})\n  else()\n    include_project(${project} TARGET ${target} ${${var_prefix}_SOURCE} ${${var_prefix}_${${var_prefix}_SOURCE}}\n                    GIT_TAG ${${var_prefix}_GIT_TAG})\n  endif()\nendfunction()\n"
  },
  {
    "path": "cmake/platformConfig.cmake",
    "content": "list(PREPEND ZP_PLATFORM_DIRS \"${CMAKE_CURRENT_LIST_DIR}/platforms\")\n"
  },
  {
    "path": "cmake/platforms/arduino_esp32.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER arduino_esp32)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_ARDUINO_ESP32)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/arduino/esp32/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/bt/bt_arduino_esp32.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/system/socket/esp32.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_esp32.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_esp32.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_arduino_esp32.cpp\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_esp32.c\")\nendif()\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/bsd.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER bsd)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_BSD)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/raweth_unix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/tty_posix.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_posix.c\")\nendif()\n"
  },
  {
    "path": "cmake/platforms/emscripten.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER emscripten)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_EMSCRIPTEN)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/emscripten/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/emscripten/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/upper/ws_emscripten.c\")\n"
  },
  {
    "path": "cmake/platforms/espidf.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER espidf)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_ESPIDF)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/espidf/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/socket/esp32.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_esp32.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_esp32.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_espidf.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_esp32.c\")\nendif()\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/flipper.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER flipper)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_FLIPPER)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/flipper/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/flipper/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_flipper.c\")\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/freertos_lwip.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER freertos_lwip)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_FREERTOS_LWIP)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/freertos/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/socket/lwip.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_lwip.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_lwip.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip_common.c\")\nendif()\n"
  },
  {
    "path": "cmake/platforms/freertos_plus_tcp.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER freertos_plus_tcp)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_FREERTOS_PLUS_TCP)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/freertos/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/freertos/freertos_plus_tcp/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_freertos_plus_tcp.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_freertos_plus_tcp.c\")\n"
  },
  {
    "path": "cmake/platforms/linux.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER linux)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_LINUX)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/raweth_unix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/tty_posix.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_posix.c\")\nendif()\n"
  },
  {
    "path": "cmake/platforms/macos.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER macos)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_MACOS)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/raweth_unix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/tty_posix.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_posix.c\")\nendif()\n"
  },
  {
    "path": "cmake/platforms/mbed.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER mbed)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_MBED)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/mbed/system.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/system/mbed/network.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_mbed.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_mbed.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_mbed.cpp\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_mbed.cpp\")\nendif()\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/opencr.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER arduino_opencr)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_ARDUINO_OPENCR)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/arduino/opencr/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/arduino/opencr/network.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_opencr.cpp\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_opencr.cpp\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_opencr.cpp\")\nendif()\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/posix_compatible.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER posix_compatible)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_LINUX)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/raweth_unix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/tty_posix.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_posix.c\")\nendif()\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/rpi_pico.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER rpi_pico)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_RPI_PICO)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/rpi_pico/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/rpi_pico/usb_uart.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/socket/lwip.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_lwip.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_lwip.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_rpi_pico.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_rpi_pico.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip_common.c\")\nendif()\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/threadx_stm32.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER threadx_stm32)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_THREADX_STM32)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/threadx/stm32/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/threadx/stm32/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_threadx_stm32.c\")\nset(CHECK_THREADS OFF)\n"
  },
  {
    "path": "cmake/platforms/windows.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER windows)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS\n    ZENOH_WINDOWS\n    _CRT_SECURE_NO_WARNINGS)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/windows/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/windows/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_windows.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_windows.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_windows.c\")\nendif()\nset(ZP_PLATFORM_LINK_LIBRARIES Ws2_32 Iphlpapi)\n"
  },
  {
    "path": "cmake/platforms/zephyr.cmake",
    "content": "set(ZP_PLATFORM_SYSTEM_LAYER zephyr)\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_ZEPHYR)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/zephyr/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/zephyr/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_zephyr.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_zephyr.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_zephyr.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_zephyr.c\")\nendif()\n"
  },
  {
    "path": "cmake/platforms.cmake",
    "content": "function(zp_detect_default_platform out_var)\n  if(CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n    set(${out_var} \"linux\" PARENT_SCOPE)\n  elseif(POSIX_COMPATIBLE)\n    set(${out_var} \"posix_compatible\" PARENT_SCOPE)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"BSD\")\n    set(${out_var} \"bsd\" PARENT_SCOPE)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"Darwin\")\n    set(${out_var} \"macos\" PARENT_SCOPE)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"Emscripten\")\n    set(${out_var} \"emscripten\" PARENT_SCOPE)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"Windows\")\n    set(${out_var} \"windows\" PARENT_SCOPE)\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"Generic\")\n    message(FATAL_ERROR \"A Generic build requires an explicit ZP_PLATFORM (for example zephyr, freertos_plus_tcp, or freertos_lwip)\")\n  elseif(CMAKE_SYSTEM_NAME MATCHES \"PICO\")\n    set(${out_var} \"rpi_pico\" PARENT_SCOPE)\n  else()\n    message(FATAL_ERROR \"zenoh-pico is not yet available on ${CMAKE_SYSTEM_NAME} platform\")\n  endif()\nendfunction()\n\nmacro(zp_add_platform_dir value)\n  list(APPEND ZP_PLATFORM_DIRS \"${value}\")\nendmacro()\n\nmacro(zp_load_platform_profile profile_name)\n  set(ZP_PLATFORM_PROFILE_FILE \"\")\n  set(ZP_PLATFORM_COMPILE_DEFINITIONS \"\")\n  set(ZP_PLATFORM_SOURCE_GLOBS \"\")\n  set(ZP_PLATFORM_SOURCE_FILES \"\")\n  set(ZP_PLATFORM_INCLUDE_DIRS \"\")\n  set(ZP_PLATFORM_COMPILE_OPTIONS \"\")\n  set(ZP_PLATFORM_LINK_LIBRARIES \"\")\n  set(ZP_PLATFORM_SYSTEM_LAYER \"\")\n  set(ZP_PLATFORM_SYSTEM_PLATFORM_HEADER \"\")\n  set(CHECK_THREADS \"ON\")\n\n  foreach(_zp_platform_dir IN LISTS ZP_PLATFORM_DIRS)\n    if(EXISTS \"${_zp_platform_dir}/${profile_name}.cmake\")\n      set(ZP_PLATFORM_PROFILE_FILE \"${_zp_platform_dir}/${profile_name}.cmake\")\n      break()\n    endif()\n  endforeach()\n\n  if(ZP_PLATFORM_PROFILE_FILE STREQUAL \"\")\n    message(FATAL_ERROR \"Unknown platform profile: ${profile_name}\")\n  endif()\n\n  include(\"${ZP_PLATFORM_PROFILE_FILE}\")\nendmacro()\n"
  },
  {
    "path": "colcon.pkg",
    "content": "{\n    \"name\": \"zenoh_pico\",\n    \"type\": \"cmake\",\n    \"cmake-args\":[\n        \"-DTESTS=OFF\",\n        \"-DEXAMPLES=OFF\",\n    ],\n}\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "_build\n"
  },
  {
    "path": "docs/api.rst",
    "content": "..\n.. Copyright (c) 2024 ZettaScale Technology\n..\n.. This program and the accompanying materials are made available under the\n.. terms of the Eclipse Public License 2.0 which is available at\n.. http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n.. which is available at https://www.apache.org/licenses/LICENSE-2.0.\n..\n.. SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n..\n.. Contributors:\n..   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n..\n\n*************\nAPI Reference\n*************\n\nContainers\n=============\n\nSlice\n-----\n  \nRepresents an array of bytes.\n\nTypes\n^^^^^\n  \nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_slice_t\n.. c:type:: z_view_slice_t\n.. c:type:: z_loaned_slice_t\n.. c:type:: z_moved_slice_t\n\n\nFunctions\n^^^^^^^^^\n\n.. autocfunction:: primitives.h::z_slice_empty\n.. autocfunction:: primitives.h::z_slice_copy_from_buf\n.. autocfunction:: primitives.h::z_slice_from_buf\n.. autocfunction:: primitives.h::z_slice_data\n.. autocfunction:: primitives.h::z_slice_len\n.. autocfunction:: primitives.h::z_slice_is_empty\n\n.. autocfunction:: primitives.h::z_view_slice_from_buf\n.. c:function:: void z_view_slice_empty(z_view_slice_t * slice)\n\n  See :c:func:`z_slice_empty`\n\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_slice_drop(z_moved_slice_t * slice) \n.. c:function:: void z_slice_clone(z_owned_slice_t * dst, const z_loaned_slice_t * slice) \n.. c:function:: const z_loaned_slice_t * z_view_slice_loan(const z_view_slice_t * slice)\n.. c:function:: z_loaned_slice_t * z_view_slice_loan_mut(z_view_slice_t * slice)\n.. c:function:: const z_loaned_slice_t * z_slice_loan(const z_owned_slice_t * slice)\n.. c:function:: z_loaned_slice_t * z_slice_loan_mut(z_owned_slice_t * slice)\n.. c:function:: z_result_t z_slice_take_from_loaned(z_owned_slice_t *dst, z_loaned_slice_t *src)\n\nString\n------\n  \nRepresents a string without null-terminator.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_string_t\n.. c:type:: z_view_string_t\n.. c:type:: z_loaned_string_t\n.. c:type:: z_moved_string_t\n\nFunctions\n^^^^^^^^^\n\n.. autocfunction:: primitives.h::z_string_empty\n.. autocfunction:: primitives.h::z_string_copy_from_str\n.. autocfunction:: primitives.h::z_string_copy_from_substr\n.. autocfunction:: primitives.h::z_string_from_str\n.. autocfunction:: primitives.h::z_string_data\n.. autocfunction:: primitives.h::z_string_len\n.. autocfunction:: primitives.h::z_string_is_empty\n.. autocfunction:: primitives.h::z_string_as_slice\n\n.. autocfunction:: primitives.h::z_view_string_from_str\n.. autocfunction:: primitives.h::z_view_string_from_substr\n.. c:function:: void z_view_string_empty(z_view_string_t * string)\n\n  See :c:func:`z_string_empty`\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_string_drop(z_moved_string_t * string) \n.. c:function:: void z_string_clone(z_owned_string_t * dst, const z_loaned_string_t * string) \n.. c:function:: const z_loaned_string_t * z_view_string_loan(const z_view_string_t * string)\n.. c:function:: z_loaned_string_t * z_view_string_loan_mut(z_view_string_t * string)\n.. c:function:: const z_loaned_string_t * z_string_loan(const z_owned_string_t * string)\n.. c:function:: z_loaned_string_t * z_string_loan_mut(z_owned_string_t * string)\n.. c:function:: z_result_t z_string_take_from_loaned(z_owned_string_t *dst, z_loaned_string_t *src)\n\nString Array\n------------\n\nRepresents an array of non null-terminated strings.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_string_array_t\n.. c:type:: z_loaned_string_array_t\n.. c:type:: z_moved_string_array_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_string_array_new\n.. autocfunction:: primitives.h::z_string_array_push_by_alias\n.. autocfunction:: primitives.h::z_string_array_push_by_copy\n.. autocfunction:: primitives.h::z_string_array_get\n.. autocfunction:: primitives.h::z_string_array_len\n.. autocfunction:: primitives.h::z_string_array_is_empty\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_string_array_drop(z_moved_string_array_t * string_array) \n.. c:function:: void z_string_array_clone(z_owned_string_array_t * dst, const z_loaned_string_array_t * string_array) \n.. c:function:: const z_loaned_string_array_t * z_string_array_loan(const z_owned_string_array_t * string_array)\n.. c:function:: z_loaned_string_array_t * z_string_array_loan_mut(z_owned_string_array_t * string_array)\n.. c:function:: z_result_t z_string_array_take_from_loaned(z_owned_string_array_t *dst, z_loaned_string_array_t *src)\n\n\nCommon\n======\n\nKey expression\n--------------\n\nRepresents a `key expression <https://zenoh.io/docs/manual/abstractions/#key-expression>`_ in Zenoh.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_keyexpr_t\n.. c:type:: z_view_keyexpr_t\n.. c:type:: z_loaned_keyexpr_t\n.. c:type:: z_moved_keyexpr_t\n\n.. autocenum:: constants.h::z_keyexpr_intersection_level_t\n.. autocenum:: constants.h::zp_keyexpr_canon_status_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_keyexpr_from_str\n.. autocfunction:: primitives.h::z_view_keyexpr_from_str\n.. autocfunction:: primitives.h::z_keyexpr_from_str_autocanonize\n.. autocfunction:: primitives.h::z_view_keyexpr_from_str_autocanonize\n.. autocfunction:: primitives.h::z_view_keyexpr_from_str_unchecked\n.. autocfunction:: primitives.h::z_keyexpr_from_substr\n.. autocfunction:: primitives.h::z_view_keyexpr_from_substr\n.. autocfunction:: primitives.h::z_keyexpr_from_substr_autocanonize\n.. autocfunction:: primitives.h::z_view_keyexpr_from_substr_autocanonize\n.. autocfunction:: primitives.h::z_view_keyexpr_from_substr_unchecked\n\n.. autocfunction:: primitives.h::z_keyexpr_as_view_string\n\n.. autocfunction:: primitives.h::z_keyexpr_canonize\n.. autocfunction:: primitives.h::z_keyexpr_canonize_null_terminated\n.. autocfunction:: primitives.h::z_keyexpr_is_canon\n\n.. autocfunction:: primitives.h::z_keyexpr_concat\n.. autocfunction:: primitives.h::z_keyexpr_join\n.. autocfunction:: primitives.h::z_keyexpr_equals\n.. autocfunction:: primitives.h::z_keyexpr_includes\n.. autocfunction:: primitives.h::z_keyexpr_intersects\n.. autocfunction:: primitives.h::z_keyexpr_relation_to\n\n.. autocfunction:: primitives.h::z_declare_keyexpr\n.. autocfunction:: primitives.h::z_undeclare_keyexpr\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_keyexpr_drop(z_moved_keyexpr_t * keyexpr) \n.. c:function:: void z_keyexpr_clone(z_owned_keyexpr_t * dst, const z_loaned_keyexpr_t * keyexpr) \n.. c:function:: const z_loaned_keyexpr_t * z_view_keyexpr_loan(const z_view_keyexpr_t * keyexpr)\n.. c:function:: z_loaned_keyexpr_t * z_view_keyexpr_loan_mut(z_view_keyexpr_t * keyexpr)\n.. c:function:: const z_loaned_keyexpr_t * z_keyexpr_loan(const z_owned_keyexpr_t * keyexpr)\n.. c:function:: z_loaned_keyexpr_t * z_keyexpr_loan_mut(z_owned_keyexpr_t * keyexpr)\n.. c:function:: z_result_t z_keyexpr_take_from_loaned(z_owned_keyexpr_t *dst, z_loaned_keyexpr_t *src)\n\nPayload\n-------\n\nTypes\n^^^^^\n\nsee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_bytes_t\n.. c:type:: z_loaned_bytes_t\n.. c:type:: z_moved_bytes_t\n\n.. c:type:: z_owned_bytes_writter_t\n.. c:type:: z_loaned_bytes_writter_t\n.. c:type:: z_moved_bytes_writter_t\n\n.. autoctype:: types.h::z_bytes_reader_t\n.. autoctype:: types.h::z_bytes_slice_iterator_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_bytes_empty\n.. autocfunction:: primitives.h::z_bytes_len\n.. autocfunction:: primitives.h::z_bytes_from_buf\n.. autocfunction:: primitives.h::z_bytes_from_slice\n.. autocfunction:: primitives.h::z_bytes_from_static_buf\n.. autocfunction:: primitives.h::z_bytes_from_static_str\n.. autocfunction:: primitives.h::z_bytes_from_str\n.. autocfunction:: primitives.h::z_bytes_from_string\n.. autocfunction:: primitives.h::z_bytes_copy_from_buf\n.. autocfunction:: primitives.h::z_bytes_copy_from_slice\n.. autocfunction:: primitives.h::z_bytes_copy_from_str\n.. autocfunction:: primitives.h::z_bytes_copy_from_string\n.. autocfunction:: primitives.h::z_bytes_to_slice\n.. autocfunction:: primitives.h::z_bytes_to_string\n\n.. autocfunction:: primitives.h::z_bytes_get_contiguous_view\n.. autocfunction:: primitives.h::z_bytes_get_slice_iterator\n.. autocfunction:: primitives.h::z_bytes_slice_iterator_next\n\n.. autocfunction:: primitives.h::z_bytes_get_reader\n.. autocfunction:: primitives.h::z_bytes_reader_read\n.. autocfunction:: primitives.h::z_bytes_reader_remaining\n.. autocfunction:: primitives.h::z_bytes_reader_seek\n.. autocfunction:: primitives.h::z_bytes_reader_tell\n\n.. autocfunction:: primitives.h::z_bytes_writer_append\n.. autocfunction:: primitives.h::z_bytes_writer_empty\n.. autocfunction:: primitives.h::z_bytes_writer_finish\n.. autocfunction:: primitives.h::z_bytes_writer_write_all\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_bytes_drop(z_moved_bytes_t * bytes) \n.. c:function:: void z_bytes_clone(z_owned_bytes_t * dst, const z_loaned_bytes_t * bytes) \n.. c:function:: const z_loaned_bytes_t * z_bytes_loan(const z_owned_bytes_t * bytes)\n.. c:function:: z_loaned_bytes_t * z_bytes_loan_mut(z_owned_bytes_t * bytes)\n.. c:function:: z_result_t z_bytes_take_from_loaned(z_owned_bytes_t *dst, z_loaned_bytes_t *src)\n\n.. c:function:: void z_bytes_writer_drop(z_moved_bytes_writer_t * bytes_writer) \n.. c:function:: void z_bytes_writer_clone(z_owned_bytes_writer_t * dst, const z_loaned_bytes_writer_t * bytes_writer) \n.. c:function:: const z_loaned_bytes_writer_t * z_bytes_writer_loan(const z_owned_bytes_writer_t * bytes_writer)\n.. c:function:: z_loaned_bytes_writer_t * z_bytes_writer_loan_mut(z_owned_bytes_writer_t * bytes_writer)\n.. c:function:: z_result_t z_bytes_writer_take_from_loaned(z_owned_bytes_writer_t *dst, z_loaned_bytes_writer_t *src)\n\nEncoding\n--------\n  \nRepresents the encoding of a payload, in a MIME-like format.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_encoding_t\n.. c:type:: z_loaned_encoding_t\n.. c:type:: z_moved_encoding_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_encoding_from_str\n.. autocfunction:: primitives.h::z_encoding_from_substr\n.. autocfunction:: primitives.h::z_encoding_set_schema_from_str\n.. autocfunction:: primitives.h::z_encoding_set_schema_from_substr\n.. autocfunction:: primitives.h::z_encoding_to_string\n.. autocfunction:: primitives.h::z_encoding_equals\n.. autocfunction:: encoding.h::z_encoding_loan_default\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_encoding_drop(z_moved_encoding_t * encoding) \n.. c:function:: void z_encoding_clone(z_owned_encoding_t * dst, const z_loaned_encoding_t * encoding) \n.. c:function:: const z_loaned_encoding_t * z_encoding_loan(const z_owned_encoding_t * encoding)\n.. c:function:: z_loaned_encoding_t * z_encoding_loan_mut(z_owned_encoding_t * encoding)\n.. c:function:: z_result_t z_encoding_take_from_loaned(z_owned_encoding_t *dst, z_loaned_encoding_t *src)\n\n\nPredefined Encodings\n^^^^^^^^^^^^^^^^^^^^\n.. autocfunction:: encoding.h::z_encoding_zenoh_bytes\n.. autocfunction:: encoding.h::z_encoding_zenoh_string\n.. autocfunction:: encoding.h::z_encoding_zenoh_serialized\n.. autocfunction:: encoding.h::z_encoding_application_octet_stream\n.. autocfunction:: encoding.h::z_encoding_text_plain\n.. autocfunction:: encoding.h::z_encoding_application_json\n.. autocfunction:: encoding.h::z_encoding_text_json\n.. autocfunction:: encoding.h::z_encoding_application_cdr\n.. autocfunction:: encoding.h::z_encoding_application_cbor\n.. autocfunction:: encoding.h::z_encoding_application_yaml\n.. autocfunction:: encoding.h::z_encoding_text_yaml\n.. autocfunction:: encoding.h::z_encoding_text_json5\n.. autocfunction:: encoding.h::z_encoding_application_python_serialized_object\n.. autocfunction:: encoding.h::z_encoding_application_protobuf\n.. autocfunction:: encoding.h::z_encoding_application_java_serialized_object\n.. autocfunction:: encoding.h::z_encoding_application_openmetrics_text\n.. autocfunction:: encoding.h::z_encoding_image_png\n.. autocfunction:: encoding.h::z_encoding_image_jpeg\n.. autocfunction:: encoding.h::z_encoding_image_gif\n.. autocfunction:: encoding.h::z_encoding_image_bmp\n.. autocfunction:: encoding.h::z_encoding_image_webp\n.. autocfunction:: encoding.h::z_encoding_application_xml\n.. autocfunction:: encoding.h::z_encoding_application_x_www_form_urlencoded\n.. autocfunction:: encoding.h::z_encoding_text_html\n.. autocfunction:: encoding.h::z_encoding_text_xml\n.. autocfunction:: encoding.h::z_encoding_text_css\n.. autocfunction:: encoding.h::z_encoding_text_javascript\n.. autocfunction:: encoding.h::z_encoding_text_markdown\n.. autocfunction:: encoding.h::z_encoding_text_csv\n.. autocfunction:: encoding.h::z_encoding_application_sql\n.. autocfunction:: encoding.h::z_encoding_application_coap_payload\n.. autocfunction:: encoding.h::z_encoding_application_json_patch_json\n.. autocfunction:: encoding.h::z_encoding_application_json_seq\n.. autocfunction:: encoding.h::z_encoding_application_jsonpath\n.. autocfunction:: encoding.h::z_encoding_application_jwt\n.. autocfunction:: encoding.h::z_encoding_application_mp4\n.. autocfunction:: encoding.h::z_encoding_application_soap_xml\n.. autocfunction:: encoding.h::z_encoding_application_yang\n.. autocfunction:: encoding.h::z_encoding_audio_aac\n.. autocfunction:: encoding.h::z_encoding_audio_flac\n.. autocfunction:: encoding.h::z_encoding_audio_mp4\n.. autocfunction:: encoding.h::z_encoding_audio_ogg\n.. autocfunction:: encoding.h::z_encoding_audio_vorbis\n.. autocfunction:: encoding.h::z_encoding_video_h261\n.. autocfunction:: encoding.h::z_encoding_video_h263\n.. autocfunction:: encoding.h::z_encoding_video_h264\n.. autocfunction:: encoding.h::z_encoding_video_h265\n.. autocfunction:: encoding.h::z_encoding_video_h266\n.. autocfunction:: encoding.h::z_encoding_video_mp4\n.. autocfunction:: encoding.h::z_encoding_video_ogg\n.. autocfunction:: encoding.h::z_encoding_video_raw\n.. autocfunction:: encoding.h::z_encoding_video_vp8\n.. autocfunction:: encoding.h::z_encoding_video_vp9\n\nReply Error\n-----------\n\nRepresents a Zenoh reply error value.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_reply_err_t\n.. c:type:: z_loaned_reply_err_t\n.. c:type:: z_moved_reply_err_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_reply_err_payload\n.. autocfunction:: primitives.h::z_reply_err_encoding\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_reply_err_drop(z_moved_reply_err_t * reply_err) \n.. c:function:: void z_reply_err_clone(z_owned_reply_err_t * dst, const z_loaned_reply_err_t * reply_err) \n.. c:function:: const z_loaned_reply_err_t * z_reply_err_loan(const z_owned_reply_err_t * reply_err)\n.. c:function:: z_loaned_reply_err_t * z_reply_err_loan_mut(z_owned_reply_err_t * reply_err)\n.. c:function:: z_result_t z_reply_err_take_from_loaned(z_owned_reply_err_t *dst, z_loaned_reply_err_t *src)\n\nSample\n------\n\nRepresents a data sample.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_sample_t\n.. c:type:: z_loaned_sample_t\n.. c:type:: z_moved_sample_t\n\n.. autocenum:: constants.h::z_sample_kind_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_sample_timestamp\n.. autocfunction:: primitives.h::z_sample_attachment\n.. autocfunction:: primitives.h::z_sample_encoding\n.. autocfunction:: primitives.h::z_sample_payload\n.. autocfunction:: primitives.h::z_sample_keyexpr\n.. autocfunction:: primitives.h::z_sample_priority\n.. autocfunction:: primitives.h::z_sample_congestion_control\n.. autocfunction:: primitives.h::z_sample_express\n.. autocfunction:: primitives.h::z_sample_reliability\n.. autocfunction:: primitives.h::z_sample_kind\n.. autocfunction:: primitives.h::z_sample_source_info\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_sample_drop(z_moved_sample_t * sample) \n.. c:function:: void z_sample_clone(z_owned_sample_t * dst, const z_loaned_sample_t * sample) \n.. c:function:: const z_loaned_sample_t * z_sample_loan(const z_owned_sample_t * sample)\n.. c:function:: z_loaned_sample_t * z_sample_loan_mut(z_owned_sample_t * sample)\n.. c:function:: z_result_t z_sample_take_from_loaned(z_owned_sample_t *dst, z_loaned_sample_t *src)\n\n\nTimestamp\n---------\nTypes\n^^^^^\n.. c:type:: z_timestamp_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_timestamp_id\n.. autocfunction:: primitives.h::z_timestamp_ntp64_time\n\n\nEntity Global ID\n----------------\n\nRepresents an entity global id.\n\nTypes\n^^^^^\n.. c:type:: z_entity_global_id_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_entity_global_id_new\n.. autocfunction:: primitives.h::z_entity_global_id_eid\n.. autocfunction:: primitives.h::z_entity_global_id_zid\n\nSource Info\n-----------\n\nRepresents sample source information.\n\nTypes\n^^^^^\n.. c:type:: z_source_info_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_source_info_new\n.. autocfunction:: primitives.h::z_source_info_sn\n.. autocfunction:: primitives.h::z_source_info_id\n\nClosures\n========\n\nA closure is a structure that contains all the elements for stateful, memory-leak-free callbacks:\n  - context: a pointer to an arbitrary state.\n  - call: the typical callback function. ``context`` will be passed as its last argument.\n  - drop: allows the callback's state to be freed. ``context`` will be passed as its last argument.\n\nThere is no guarantee closures won't be called concurrently.\n\nIt is guaranteed that:\n  - ``call`` will never be called once ``drop`` has started.\n  - ``drop`` will only be called **once**, and **after every** ``call`` has ended.\n  - The two previous guarantees imply that ``call`` and ``drop`` are never called concurrently.\n\nSample closure\n---------------\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_sample_t\n.. c:type:: z_loaned_closure_sample_t\n.. c:type:: z_moved_closure_sample_t\n\n.. c:type:: void (* z_closure_sample_callback_t)(z_loaned_sample_t * sample, void * arg);\n\n    Function pointer type for handling samples.\n    Represents a callback function that is invoked when a sample is available for processing.\n\n    Parameters:\n      - **sample** - Pointer to a :c:type:`z_loaned_sample_t` representing the sample to be processed.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the sample.\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_sample\n.. autocfunction:: primitives.h::z_closure_sample_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_sample_t * z_closure_sample_loan(const z_owned_closure_sample_t * closure)\n.. c:function:: void z_closure_sample_drop(z_moved_closure_sample_t * closure) \n\nQuery closure\n-------------\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_query_t\n.. c:type:: z_loaned_closure_query_t\n.. c:type:: z_moved_closure_query_t\n\n.. c:type:: void (* z_closure_query_callback_t)(z_loaned_query_t * query, void * arg);\n\n    Function pointer type for handling queries.\n    Represents a callback function that is invoked when a query is available for processing.\n\n    Parameters:\n      - **query** - Pointer to a :c:type:`z_loaned_query_t` representing the query to be processed.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the query.\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_query\n.. autocfunction:: primitives.h::z_closure_query_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_query_t * z_closure_query_loan(const z_owned_closure_query_t * closure)\n.. c:function:: void z_closure_query_drop(z_moved_closure_query_t * closure) \n\n\nReply closure\n-------------\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_reply_t\n.. c:type:: z_loaned_closure_reply_t\n.. c:type:: z_moved_closure_reply_t\n \n.. c:type:: void (* z_closure_reply_callback_t)(z_loaned_reply_t * reply, void * arg);\n\n    Function pointer type for handling replies.\n    Represents a callback function that is invoked when a reply is available for processing.\n\n    Parameters:\n      - **reply** - Pointer to a :c:type:`z_loaned_reply_t` representing the reply to be processed.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the reply.\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_reply\n.. autocfunction:: primitives.h::z_closure_reply_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_reply_t * z_closure_reply_loan(const z_owned_closure_reply_t * closure)\n.. c:function:: void z_closure_reply_drop(z_moved_closure_reply_t * closure) \n\n\nHello closure\n-------------\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_hello_t\n.. c:type:: z_loaned_closure_hello_t\n.. c:type:: z_moved_closure_hello_t\n \n.. c:type:: void (* z_closure_hello_callback_t)(z_loaned_hello_t * hello, void * arg);\n\n    Function pointer type for handling scouting response.\n    Represents a callback function that is invoked when a hello is available for processing.\n\n    Parameters:\n      - **hello** - Pointer to a :c:type:`z_loaned_hello_t` representing the hello to be processed.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the hello.\n   \nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_hello\n.. autocfunction:: primitives.h::z_closure_hello_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_hello_t * z_closure_hello_loan(const z_owned_closure_hello_t * closure)\n.. c:function:: void z_closure_hello_drop(z_moved_closure_hello_t * closure) \n\n\nID closure\n----------\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_zid_t\n.. c:type:: z_loaned_closure_zid_t\n.. c:type:: z_moved_closure_zid_t\n \n.. c:type:: void (* z_closure_zid_callback_t)(const z_id_t * id, void * arg);\n\n    Function pointer type for handling Zenoh ID routers response.\n    Represents a callback function that is invoked when a zid is available for processing.\n\n    Parameters:\n      - **zid** - Pointer to a :c:type:`z_id_t` representing the zid to be processed.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the zid.\n   \nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_zid\n.. autocfunction:: primitives.h::z_closure_zid_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_zid_t * z_closure_zid_loan(const z_owned_closure_zid_t * closure)\n.. c:function:: void z_closure_zid_drop(z_moved_closure_zid_t * closure) \n\n\nMatching closure\n----------------\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_matching_status_t\n.. c:type:: z_loaned_closure_matching_status_t\n.. c:type:: z_moved_closure_matching_status_t\n \n.. c:type:: void (* z_closure_matching_status_callback_t)(z_matching_status_t * status, void * arg);\n\n    Function pointer type for handling matching status response.\n    Represents a callback function that is invoked when a matching status was changed.\n\n    Parameters:\n      - **status** - Pointer to a :c:type:`z_matching_status_t`.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the matching status.\n   \n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_matching_status\n.. autocfunction:: primitives.h::z_closure_matching_status_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_matching_status_t * z_closure_matching_status_loan(const z_owned_closure_matching_status_t * closure)\n.. c:function:: void z_closure_matching_status_drop(z_moved_closure_matching_status_t * closure) \n\nConnectivity closures\n---------------------\n\n.. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_closure_transport_t\n.. c:type:: z_loaned_closure_transport_t\n.. c:type:: z_moved_closure_transport_t\n\n.. c:type:: z_owned_closure_link_t\n.. c:type:: z_loaned_closure_link_t\n.. c:type:: z_moved_closure_link_t\n\n.. c:type:: z_owned_closure_transport_event_t\n.. c:type:: z_loaned_closure_transport_event_t\n.. c:type:: z_moved_closure_transport_event_t\n\n.. c:type:: z_owned_closure_link_event_t\n.. c:type:: z_loaned_closure_link_event_t\n.. c:type:: z_moved_closure_link_event_t\n\n.. c:type:: void (* z_closure_transport_callback_t)(z_loaned_transport_t * transport, void * arg);\n.. c:type:: void (* z_closure_link_callback_t)(z_loaned_link_t * link, void * arg);\n.. c:type:: void (* z_closure_transport_event_callback_t)(z_loaned_transport_event_t * event, void * arg);\n.. c:type:: void (* z_closure_link_event_callback_t)(z_loaned_link_event_t * event, void * arg);\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_closure_transport\n.. autocfunction:: primitives.h::z_closure_transport_call\n.. autocfunction:: primitives.h::z_closure_link\n.. autocfunction:: primitives.h::z_closure_link_call\n.. autocfunction:: primitives.h::z_closure_transport_event\n.. autocfunction:: primitives.h::z_closure_transport_event_call\n.. autocfunction:: primitives.h::z_closure_link_event\n.. autocfunction:: primitives.h::z_closure_link_event_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_closure_transport_t * z_closure_transport_loan(const z_owned_closure_transport_t * closure)\n.. c:function:: void z_closure_transport_drop(z_moved_closure_transport_t * closure)\n.. c:function:: const z_loaned_closure_link_t * z_closure_link_loan(const z_owned_closure_link_t * closure)\n.. c:function:: void z_closure_link_drop(z_moved_closure_link_t * closure)\n.. c:function:: const z_loaned_closure_transport_event_t * z_closure_transport_event_loan(const z_owned_closure_transport_event_t * closure)\n.. c:function:: void z_closure_transport_event_drop(z_moved_closure_transport_event_t * closure)\n.. c:function:: const z_loaned_closure_link_event_t * z_closure_link_event_loan(const z_owned_closure_link_event_t * closure)\n.. c:function:: void z_closure_link_event_drop(z_moved_closure_link_event_t * closure)\n\nSample miss closure\n-------------------\n\n.. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: ze_owned_closure_miss_t\n.. c:type:: ze_loaned_closure_miss_t\n.. c:type:: ze_moved_closure_miss_t\n\n.. c:type:: void (* ze_closure_miss_callback_t)(const ze_miss_t * miss, void *arg);\n\n    Function pointer type for handling sample misses.\n    Represents a callback function that is invoked when an advanced subscriber detects a missed sample.\n\n    Parameters:\n      - **miss** - Pointer to a :c:type:`ze_miss_t` representing the missed sample.\n      - **arg** - A user-defined pointer to additional data that can be used during the processing of the missed sample.\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::ze_closure_miss\n.. autocfunction:: primitives.h::ze_closure_miss_call\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const ze_loaned_closure_miss_t * ze_closure_miss_loan(const ze_owned_closure_miss_t * closure)\n.. c:function:: void ze_closure_miss_drop(ze_moved_closure_miss_t * closure) \n\n\n.. _channels_concept:\n\nChannels\n========\n\nThe concept of channels and handlers revolves around managing communication between different components using two types of channels: FIFO (First-In-First-Out) and Ring Buffers. These channels support handling various item types such as sample, reply, and query, with distinct methods available for each.\n\nThe FIFO channel ensures that data is received in the order it was sent. It supports blocking and non-blocking (try) reception of data.\nIf the channel is dropped, the handlers transition into a \"gravestone\" state, signifying that no more data will be sent or received.\n\nThe Ring channel differs from FIFO in that data is overwritten if the buffer is full, but it still supports blocking and non-blocking reception of data. As with the FIFO channel, the handler can be dropped, resetting it to a gravestone state.\n\nThe methods common for all channles:\n\n- `z_yyy_channel_xxx_new`: Constructs the send and receive ends of the `yyy` (`fifo` or `ring`) channel for items type `xxx`.\n- `z_yyy_handler_xxx_recv`: Receives an item from the channel (blocking). If no more items are available or the channel is dropped, the item transitions to the gravestone state.\n- `z_yyy_handler_xxx_try_recv`: Attempts to receive an item immediately (non-blocking). Returns a gravestone state if no data is available.\n- `z_yyy_handler_xxx_loan`: Borrows the handler for access.\n- `z_yyy_handler_xxx_drop`: Drops the the handler, setting it to a gravestone state.\n\n\nSample channel\n--------------\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_fifo_handler_sample_t\n.. c:type:: z_loaned_fifo_handler_sample_t\n.. c:type:: z_owned_ring_handler_sample_t\n.. c:type:: z_loaned_ring_handler_sample_t\n\nMethods\n^^^^^^^\n.. c:function:: void z_fifo_channel_sample_new(z_owned_closure_sample_t * callback, z_owned_fifo_handler_sample_t * handler, size_t capacity)\n.. c:function:: void z_ring_channel_sample_new(z_owned_closure_sample_t * callback, z_owned_ring_handler_sample_t * handler, size_t capacity)\n\nSee details at :ref:`channels_concept`\n\n.. c:function:: z_result_t z_fifo_handler_sample_recv(const z_loaned_fifo_handler_sample_t * handler, z_owned_sample_t * sample) \n.. c:function:: z_result_t z_fifo_handler_sample_try_recv(const z_loaned_fifo_handler_sample_t * handler, z_owned_sample_t * sample) \n.. c:function:: z_result_t z_ring_handler_sample_recv(const z_loaned_ring_handler_sample_t * handler, z_owned_sample_t * sample) \n.. c:function:: z_result_t z_ring_handler_sample_try_recv(const z_loaned_ring_handler_sample_t * handler, z_owned_sample_t * sample) \n\nSee details at :ref:`channels_concept`\n\n.. c:function:: const z_loaned_fifo_handler_sample_t * z_fifo_handler_sample_loan(const z_owned_fifo_handler_sample_t * handler) \n.. c:function:: void z_fifo_handler_sample_drop(z_moved_fifo_handler_sample_t * handler) \n.. c:function:: const z_loaned_ring_handler_sample_t * z_ring_handler_sample_loan(const z_owned_ring_handler_sample_t * handler) \n.. c:function:: void z_ring_handler_sample_drop(z_moved_ring_handler_sample_t * handler) \n\nSee details at :ref:`owned_types_concept`\n\n\nQuery channel\n-------------\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_fifo_handler_query_t\n.. c:type:: z_loaned_fifo_handler_query_t\n.. c:type:: z_owned_ring_handler_query_t\n.. c:type:: z_loaned_ring_handler_query_t\n\nMethods\n^^^^^^^\n.. c:function:: void z_fifo_channel_query_new(z_owned_closure_query_t * callback, z_owned_fifo_handler_query_t * handler, size_t capacity)\n.. c:function:: void z_ring_channel_query_new(z_owned_closure_query_t * callback, z_owned_ring_handler_query_t * handler, size_t capacity)\n\nSee details at :ref:`channels_concept`\n\n.. c:function:: z_result_t z_fifo_handler_query_recv(const z_loaned_fifo_handler_query_t * handler, z_owned_query_t * query) \n.. c:function:: z_result_t z_fifo_handler_query_try_recv(const z_loaned_fifo_handler_query_t * handler, z_owned_query_t * query) \n.. c:function:: z_result_t z_ring_handler_query_recv(const z_loaned_ring_handler_query_t * handler, z_owned_query_t * query) \n.. c:function:: z_result_t z_ring_handler_query_try_recv(const z_loaned_ring_handler_query_t * handler, z_owned_query_t * query) \n\nSee details at :ref:`channels_concept`\n\n.. c:function:: const z_loaned_fifo_handler_query_t * z_fifo_handler_query_loan(const z_owned_fifo_handler_query_t * handler) \n.. c:function:: void z_fifo_handler_query_drop(z_moved_fifo_handler_query_t * handler) \n.. c:function:: const z_loaned_ring_handler_query_t * z_ring_handler_query_loan(const z_owned_ring_handler_query_t * handler) \n.. c:function:: void z_ring_handler_query_drop(z_moved_ring_handler_query_t * handler) \n\nSee details at :ref:`owned_types_concept`\n\nReply channel\n-------------\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_fifo_handler_reply_t\n.. c:type:: z_loaned_fifo_handler_reply_t\n.. c:type:: z_owned_ring_handler_reply_t\n.. c:type:: z_loaned_ring_handler_reply_t\n\nMethods\n^^^^^^^\n.. c:function:: void z_fifo_channel_reply_new(z_owned_closure_reply_t * callback, z_owned_fifo_handler_reply_t * handler, size_t capacity)\n.. c:function:: void z_ring_channel_reply_new(z_owned_closure_reply_t * callback, z_owned_ring_handler_reply_t * handler, size_t capacity)\n\nSee details at :ref:`channels_concept`\n\n.. c:function:: z_result_t z_fifo_handler_reply_recv(const z_loaned_fifo_handler_reply_t * handler, z_owned_reply_t * reply) \n.. c:function:: z_result_t z_fifo_handler_reply_try_recv(const z_loaned_fifo_handler_reply_t * handler, z_owned_reply_t * reply) \n.. c:function:: z_result_t z_ring_handler_reply_recv(const z_loaned_ring_handler_reply_t * handler, z_owned_reply_t * reply) \n.. c:function:: z_result_t z_ring_handler_reply_try_recv(const z_loaned_ring_handler_reply_t * handler, z_owned_reply_t * reply) \n\nSee details at :ref:`channels_concept`\n\n.. c:function:: const z_loaned_fifo_handler_reply_t * z_fifo_handler_reply_loan(const z_owned_fifo_handler_reply_t * handler) \n.. c:function:: void z_fifo_handler_reply_drop(z_moved_fifo_handler_reply_t * handler) \n.. c:function:: const z_loaned_ring_handler_reply_t * z_ring_handler_reply_loan(const z_owned_ring_handler_reply_t * handler) \n.. c:function:: void z_ring_handler_reply_drop(z_moved_ring_handler_reply_t * handler) \n\nSee details at :ref:`owned_types_concept`\n\n\nSystem\n======\nRandom\n------\nFunctions\n^^^^^^^^^\n.. autocfunction:: common/platform.h::z_random_u8\n.. autocfunction:: common/platform.h::z_random_u16\n.. autocfunction:: common/platform.h::z_random_u32\n.. autocfunction:: common/platform.h::z_random_u64\n.. autocfunction:: common/platform.h::z_random_fill\n\nSleep\n------\nFunctions\n^^^^^^^^^\n.. autocfunction:: common/platform.h::z_sleep_s\n.. autocfunction:: common/platform.h::z_sleep_ms\n.. autocfunction:: common/platform.h::z_sleep_us\n\nTime\n----\n\nTypes\n^^^^^\n.. c:type:: z_time_t\n\nA time value that is accurate to the nearest microsecond but also has a range of years.\n\n.. c:type:: z_clock_t\n\nThis is like a :c:type:`z_time_t` but has nanoseconds instead of microseconds.\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: common/platform.h::z_time_now\n.. autocfunction:: common/platform.h::z_time_elapsed_s\n.. autocfunction:: common/platform.h::z_time_elapsed_ms\n.. autocfunction:: common/platform.h::z_time_elapsed_us\n.. autocfunction:: common/platform.h::z_time_now_as_str\n\n.. autocfunction:: common/platform.h::z_clock_now\n.. autocfunction:: common/platform.h::z_clock_elapsed_s\n.. autocfunction:: common/platform.h::z_clock_elapsed_ms\n.. autocfunction:: common/platform.h::z_clock_elapsed_us\n\n\nMutex\n-----\nTypes\n^^^^^\n\nRepresents a mutual exclusion (mutex) object used to ensure exclusive access to shared resources.\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_mutex_t\n.. c:type:: z_loaned_mutex_t\n.. c:type:: z_moved_mutex_t\n\nFunctions\n^^^^^^^^^\n\n.. autocfunction:: common/platform.h::z_mutex_init\n.. autocfunction:: common/platform.h::z_mutex_lock\n.. autocfunction:: common/platform.h::z_mutex_unlock\n.. autocfunction:: common/platform.h::z_mutex_try_lock\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_mutex_drop(z_moved_mutex_t * mutex) \n.. c:function:: z_loaned_mutex_t * z_mutex_loan_mut(z_owned_mutex_t * mutex)\n\n\nConditional Variable\n--------------------\nTypes\n^^^^^\n\nRepresents a condition variable, which is a synchronization primitive \nthat allows threads to wait until a particular condition occurs.\n\nA condition variable is used in conjunction with mutexes to enable threads to \nwait for signals from other threads. When a thread calls the wait function \non a condition variable, it releases the associated mutex and enters a wait \nstate until another thread signals the condition variable.\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_condvar_t\n.. c:type:: z_loaned_condvar_t\n.. c:type:: z_moved_condvar_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: common/platform.h::z_condvar_init\n.. autocfunction:: common/platform.h::z_condvar_wait\n.. autocfunction:: common/platform.h::z_condvar_signal\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_condvar_drop(z_moved_condvar_t * condvar) \n.. c:function:: const z_loaned_condvar_t * z_condvar_loan(const z_owned_condvar_t * condvar)\n\n\nTask\n----\nTypes\n^^^^^\n\nRepresents a task that can be executed by a thread.\n\nA task is an abstraction for encapsulating a unit of work that can \nbe scheduled and executed by a thread. Tasks are typically \nused to represent asynchronous operations, allowing the program to perform \nmultiple operations concurrently.   \n\n.. c:type:: z_owned_task_t\n.. c:type:: z_moved_task_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: common/platform.h::z_task_init\n.. autocfunction:: common/platform.h::z_task_join\n.. autocfunction:: common/platform.h::z_task_detach\n.. autocfunction:: common/platform.h::z_task_drop\n\nSession\n=======\n\nSession configuration\n---------------------\n\nRepresents a Zenoh configuration, used to configure Zenoh sessions upon opening.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_config_t\n.. c:type:: z_loaned_config_t\n.. c:type:: z_moved_config_t\n\nFunctions\n^^^^^^^^^\n\n.. autocfunction:: primitives.h::z_config_default\n.. autocfunction:: primitives.h::zp_config_get\n.. autocfunction:: primitives.h::zp_config_insert\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_config_drop(z_moved_config_t * config) \n.. c:function:: void z_config_clone(z_owned_config_t * dst, const z_loaned_config_t * config) \n.. c:function:: const z_loaned_config_t * z_config_loan(const z_owned_config_t * config)\n.. c:function:: z_loaned_config_t * z_config_loan_mut(z_owned_config_t * config)\n\n\nSession management\n------------------\n\nRepresents a Zenoh Session.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_session_t\n.. c:type:: z_loaned_session_t\n.. c:type:: z_moved_session_t\n\n.. c:type:: z_id_t\n.. autoctype:: types.h::z_open_options_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_open\n.. autocfunction:: primitives.h::z_open_options_default\n.. autocfunction:: primitives.h::z_close\n.. autocfunction:: primitives.h::z_session_is_closed\n.. autocfunction:: primitives.h::z_session_id\n.. autocfunction:: primitives.h::zp_spin_once\n\n.. autocfunction:: primitives.h::z_info_zid\n.. autocfunction:: primitives.h::z_info_routers_zid\n.. autocfunction:: primitives.h::z_info_peers_zid\n.. autocfunction:: primitives.h::z_id_to_string\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_session_t * z_session_loan(const z_owned_session_t * closure)\n.. c:function:: void z_session_drop(z_moved_session_t * closure) \n\nConnectivity\n------------\n\n.. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n\nThe connectivity API is available only when both ``Z_FEATURE_UNSTABLE_API`` and\n``Z_FEATURE_CONNECTIVITY`` are enabled.\n\nTypes\n^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_transport_t\n.. c:type:: z_loaned_transport_t\n.. c:type:: z_moved_transport_t\n\n.. c:type:: z_owned_link_t\n.. c:type:: z_loaned_link_t\n.. c:type:: z_moved_link_t\n\n.. c:type:: z_owned_transport_event_t\n.. c:type:: z_loaned_transport_event_t\n.. c:type:: z_moved_transport_event_t\n\n.. c:type:: z_owned_link_event_t\n.. c:type:: z_loaned_link_event_t\n.. c:type:: z_moved_link_event_t\n\n.. c:type:: z_owned_transport_events_listener_t\n.. c:type:: z_loaned_transport_events_listener_t\n.. c:type:: z_moved_transport_events_listener_t\n\n.. c:type:: z_owned_link_events_listener_t\n.. c:type:: z_loaned_link_events_listener_t\n.. c:type:: z_moved_link_events_listener_t\n\nOption Types\n^^^^^^^^^^^^\n\n.. autoctype:: types.h::z_info_links_options_t\n.. autoctype:: types.h::z_transport_events_listener_options_t\n.. autoctype:: types.h::z_link_events_listener_options_t\n\nFunctions\n^^^^^^^^^\n.. autocfunction:: primitives.h::z_info_transports\n.. autocfunction:: primitives.h::z_info_links_options_default\n.. autocfunction:: primitives.h::z_info_links\n\n.. autocfunction:: primitives.h::z_transport_events_listener_options_default\n.. autocfunction:: primitives.h::z_declare_transport_events_listener\n.. autocfunction:: primitives.h::z_declare_background_transport_events_listener\n.. autocfunction:: primitives.h::z_undeclare_transport_events_listener\n\n.. autocfunction:: primitives.h::z_link_events_listener_options_default\n.. autocfunction:: primitives.h::z_declare_link_events_listener\n.. autocfunction:: primitives.h::z_declare_background_link_events_listener\n.. autocfunction:: primitives.h::z_undeclare_link_events_listener\n\n.. autocfunction:: primitives.h::z_transport_zid\n.. autocfunction:: primitives.h::z_transport_whatami\n.. autocfunction:: primitives.h::z_transport_is_qos\n.. autocfunction:: primitives.h::z_transport_is_multicast\n.. autocfunction:: primitives.h::z_transport_is_shm\n\n.. autocfunction:: primitives.h::z_link_zid\n.. autocfunction:: primitives.h::z_link_src\n.. autocfunction:: primitives.h::z_link_dst\n.. autocfunction:: primitives.h::z_link_mtu\n.. autocfunction:: primitives.h::z_link_is_streamed\n.. autocfunction:: primitives.h::z_link_is_reliable\n\n.. autocfunction:: primitives.h::z_transport_event_kind\n.. autocfunction:: primitives.h::z_transport_event_transport\n.. autocfunction:: primitives.h::z_transport_event_transport_mut\n.. autocfunction:: primitives.h::z_link_event_kind\n.. autocfunction:: primitives.h::z_link_event_link\n.. autocfunction:: primitives.h::z_link_event_link_mut\n\n\nMatching\n========\n\nTypes\n-----\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_matching_listener_t\n.. c:type:: z_loaned_matching_listener_t\n.. c:type:: z_moved_matching_listener_t\n\n\n.. autoctype:: types.h::z_matching_status_t\n\nFunctions\n---------\n\n.. autocfunction:: primitives.h::z_undeclare_matching_listener\n\n\nPublication\n===========\n\nRepresents a Zenoh Publisher entity.\n\nTypes\n-----\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_publisher_t\n.. c:type:: z_loaned_publisher_t\n.. c:type:: z_moved_publisher_t\n\nOption Types\n------------\n\n.. autoctype:: types.h::z_put_options_t\n.. autoctype:: types.h::z_delete_options_t\n.. autoctype:: types.h::z_publisher_options_t\n.. autoctype:: types.h::z_publisher_put_options_t\n.. autoctype:: types.h::z_publisher_delete_options_t\n\nConstants\n---------\n\n.. autocenum:: constants.h::z_congestion_control_t\n.. autocenum:: constants.h::z_priority_t\n.. autocenum:: constants.h::z_reliability_t\n.. autocenum:: constants.h::z_locality_t\n\nFunctions\n---------\n.. autocfunction:: primitives.h::z_put\n.. autocfunction:: primitives.h::z_delete\n\n.. autocfunction:: primitives.h::z_declare_publisher\n.. autocfunction:: primitives.h::z_undeclare_publisher\n.. autocfunction:: primitives.h::z_publisher_put\n.. autocfunction:: primitives.h::z_publisher_delete\n.. autocfunction:: primitives.h::z_publisher_keyexpr\n\n.. autocfunction:: primitives.h::z_put_options_default\n.. autocfunction:: primitives.h::z_delete_options_default\n.. autocfunction:: primitives.h::z_publisher_options_default\n.. autocfunction:: primitives.h::z_publisher_put_options_default\n.. autocfunction:: primitives.h::z_publisher_delete_options_default\n.. autocfunction:: primitives.h::z_reliability_default\n.. autocfunction:: primitives.h::z_publisher_get_matching_status\n.. autocfunction:: primitives.h::z_publisher_declare_matching_listener\n.. autocfunction:: primitives.h::z_publisher_declare_background_matching_listener\n.. autocfunction:: primitives.h::z_publisher_id\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_publisher_t * z_publisher_loan(const z_owned_publisher_t * closure)\n.. c:function:: void z_publisher_drop(z_moved_publisher_t * closure) \n\n\nAdvanced Publication\n====================\n\nRepresents a Zenoh Advanced Publisher entity.\n\nIn addition to publishing the data, it also maintains the storage, allowing matching\nsubscribers to retrieve missed samples.\n\nTypes\n-----\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: ze_owned_advanced_publisher_t\n.. c:type:: ze_loaned_advanced_publisher_t\n.. c:type:: ze_moved_advanced_publisher_t\n\nOption Types\n------------\n\n.. autoctype:: advanced_publisher.h::ze_advanced_publisher_put_options_t\n.. autoctype:: advanced_publisher.h::ze_advanced_publisher_delete_options_t\n.. autoctype:: advanced_publisher.h::ze_advanced_publisher_options_t\n.. autoctype:: advanced_cache.h::ze_advanced_publisher_cache_options_t\n.. autoctype:: advanced_publisher.h::ze_advanced_publisher_sample_miss_detection_options_t\n\nConstants\n---------\n\n.. autocenum:: advanced_publisher.h::ze_advanced_publisher_heartbeat_mode_t\n\nFunctions\n---------\n.. autocfunction:: advanced_publisher.h::ze_declare_advanced_publisher\n.. autocfunction:: advanced_publisher.h::ze_undeclare_advanced_publisher\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_put\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_delete\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_keyexpr\n\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_options_default\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_cache_options_default\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_sample_miss_detection_options_default\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_put_options_default\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_delete_options_default\n\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_get_matching_status\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_declare_matching_listener\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_declare_background_matching_listener\n.. autocfunction:: advanced_publisher.h::ze_advanced_publisher_id\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const ze_loaned_advanced_publisher_t * ze_advanced_publisher_loan(const ze_owned_advanced_publisher_t * closure)\n.. c:function:: void ze_advanced_publisher_drop(ze_moved_advanced_publisher_t * closure) \n\n\nSubscription\n============\n\nTypes\n-----\n\nRepresents a Zenoh Subscriber entity.\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_subscriber_t\n.. c:type:: z_loaned_subscriber_t\n.. c:type:: z_moved_subscriber_t\n\nOption Types\n------------\n\n.. autoctype:: types.h::z_subscriber_options_t\n\nFunctions\n---------\n\n.. autocfunction:: primitives.h::z_declare_subscriber\n.. autocfunction:: primitives.h::z_undeclare_subscriber\n.. autocfunction:: primitives.h::z_declare_background_subscriber\n\n.. autocfunction:: primitives.h::z_subscriber_options_default\n.. autocfunction:: primitives.h::z_subscriber_keyexpr\n.. autocfunction:: primitives.h::z_subscriber_id\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_subscriber_t * z_subscriber_loan(const z_owned_subscriber_t * closure)\n.. c:function:: void z_subscriber_drop(z_moved_subscriber_t * closure) \n\n\nAdvanced Subscriber\n===================\n\nRepresents a Zenoh Advanced Subscriber entity.\n\nIn addition to receiving the data it is subscribed to, it is also able to receive notifications\nregarding missed samples and/or automatically recover them.\n\nTypes\n-----\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: ze_owned_advanced_subscriber_t\n.. c:type:: ze_loaned_advanced_subscriber_t\n.. c:type:: ze_moved_advanced_subscriber_t\n\nOption Types\n------------\n\n.. autoctype:: advanced_subscriber.h::ze_advanced_subscriber_history_options_t\n.. autoctype:: advanced_subscriber.h::ze_advanced_subscriber_recovery_options_t\n.. autoctype:: advanced_subscriber.h::ze_advanced_subscriber_last_sample_miss_detection_options_t\n.. autoctype:: advanced_subscriber.h::ze_advanced_subscriber_options_t\n\nFunctions\n---------\n\n.. autocfunction:: advanced_subscriber.h::ze_declare_advanced_subscriber\n.. autocfunction:: advanced_subscriber.h::ze_declare_background_advanced_subscriber\n.. autocfunction:: advanced_subscriber.h::ze_undeclare_advanced_subscriber\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_keyexpr\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_id\n\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_declare_sample_miss_listener\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_declare_background_sample_miss_listener\n.. autocfunction:: advanced_subscriber.h::ze_undeclare_sample_miss_listener\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_detect_publishers\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_detect_publishers_background\n\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_history_options_default\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_recovery_options_default\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_last_sample_miss_detection_options_default\n.. autocfunction:: advanced_subscriber.h::ze_advanced_subscriber_options_default\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_advanced_subscriber_t * z_advanced_subscriber_loan(const z_owned_advanced_subscriber_t * closure)\n.. c:function:: void z_advanced_subscriber_drop(z_moved_advanced_subscriber_t * closure) \n\n\nQueryable\n=========\n\nTypes\n-----\n\nRepresents a Zenoh Queryable entity.\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_queryable_t\n.. c:type:: z_loaned_queryable_t\n.. c:type:: z_moved_queryable_t\n\nRepresents a Zenoh Query entity, received by Zenoh queryable entities.\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_query_t\n.. c:type:: z_loaned_query_t\n.. c:type:: z_moved_query_t\n\nOption Types\n------------\n\n.. autoctype:: types.h::z_queryable_options_t\n.. autoctype:: types.h::z_query_reply_options_t\n.. autoctype:: types.h::z_query_reply_err_options_t\n.. autoctype:: types.h::z_query_reply_del_options_t\n\nFunctions\n---------\n.. autocfunction:: primitives.h::z_declare_queryable\n.. autocfunction:: primitives.h::z_undeclare_queryable\n.. autocfunction:: primitives.h::z_declare_background_queryable\n\n.. autocfunction:: primitives.h::z_queryable_id\n.. autocfunction:: primitives.h::z_queryable_keyexpr\n\n.. autocfunction:: primitives.h::z_queryable_options_default\n.. autocfunction:: primitives.h::z_query_reply_options_default\n.. autocfunction:: primitives.h::z_query_reply_err_options_default\n.. autocfunction:: primitives.h::z_query_reply_del_options_default\n\n.. autocfunction:: primitives.h::z_query_keyexpr\n.. autocfunction:: primitives.h::z_query_parameters\n.. autocfunction:: primitives.h::z_query_payload\n.. autocfunction:: primitives.h::z_query_encoding\n.. autocfunction:: primitives.h::z_query_attachment\n.. autocfunction:: primitives.h::z_query_reply\n.. autocfunction:: primitives.h::z_query_reply_err\n.. autocfunction:: primitives.h::z_query_reply_del\n.. autocfunction:: primitives.h::z_query_source_info\n.. autocfunction:: primitives.h::z_query_accepts_replies\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_queryable_drop(z_moved_queryable_t * closure) \n.. c:function:: const z_loaned_queryable_t * z_queryable_loan(const z_owned_queryable_t * closure)\n\n.. c:function:: void z_query_drop(z_moved_query_t * query) \n.. c:function:: void z_query_clone(z_owned_query_t * dst, const z_loaned_query_t * query) \n.. c:function:: const z_loaned_query_t * z_query_loan(const z_owned_query_t * query)\n.. c:function:: z_loaned_query_t * z_query_loan_mut(z_owned_query_t * query)\n.. c:function:: z_result_t z_query_take_from_loaned(z_owned_query_t *dst, z_loaned_query_t *src)\n\nQuery\n=====\nTypes\n-----\n\nRepresents the reply to a query.\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_reply_t\n.. c:type:: z_loaned_reply_t\n.. c:type:: z_moved_reply_t\n  \nOption Types\n------------\n\n.. autoctype:: types.h::z_get_options_t\n.. autocenum:: constants.h::z_query_target_t\n.. autocenum:: constants.h::z_consolidation_mode_t\n.. autocenum:: constants.h::z_reply_keyexpr_t\n.. autoctype:: types.h::z_query_consolidation_t\n\nFunctions\n---------\n\n.. autocfunction:: primitives.h::z_get\n.. autocfunction:: primitives.h::z_get_with_parameters_substr\n.. autocfunction:: primitives.h::z_get_options_default\n\n.. autocfunction:: primitives.h::z_query_consolidation_default\n.. autocfunction:: primitives.h::z_query_consolidation_auto\n.. autocfunction:: primitives.h::z_query_consolidation_none\n.. autocfunction:: primitives.h::z_query_consolidation_monotonic\n.. autocfunction:: primitives.h::z_query_consolidation_latest\n.. autocfunction:: primitives.h::z_query_target_default\n.. autocfunction:: primitives.h::z_reply_keyexpr_default\n\n.. autocfunction:: primitives.h::z_reply_is_ok\n.. autocfunction:: primitives.h::z_reply_ok\n.. autocfunction:: primitives.h::z_reply_err\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_reply_drop(z_moved_reply_t * reply) \n.. c:function:: void z_reply_clone(z_owned_reply_t * dst, const z_loaned_reply_t * reply) \n.. c:function:: const z_loaned_reply_t * z_reply_loan(const z_owned_reply_t * reply)\n.. c:function:: z_loaned_reply_t * z_reply_loan_mut(z_owned_reply_t * reply)\n.. c:function:: z_result_t z_reply_take_from_loaned(z_owned_reply_t *dst, z_loaned_reply_t *src)\n\nQuerier\n=======\n\nRepresents a Zenoh Querier entity.\n\nTypes\n-----\n\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_querier_t\n.. c:type:: z_loaned_querier_t\n.. c:type:: z_moved_querier_t\n\nOption Types\n------------\n\n.. autoctype:: types.h::z_querier_options_t\n.. autoctype:: types.h::z_querier_get_options_t\n\nConstants\n---------\n\nFunctions\n---------\n.. autocfunction:: primitives.h::z_declare_querier\n.. autocfunction:: primitives.h::z_undeclare_querier\n.. autocfunction:: primitives.h::z_querier_get\n.. autocfunction:: primitives.h::z_querier_get_with_parameters_substr\n.. autocfunction:: primitives.h::z_querier_keyexpr\n.. autocfunction:: primitives.h::z_querier_get_matching_status\n.. autocfunction:: primitives.h::z_querier_declare_matching_listener\n.. autocfunction:: primitives.h::z_querier_declare_background_matching_listener\n.. autocfunction:: primitives.h::z_querier_id\n\n.. autocfunction:: primitives.h::z_querier_options_default\n.. autocfunction:: primitives.h::z_querier_get_options_default\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: const z_loaned_querier_t * z_querier_loan(const z_owned_querier_t * closure)\n.. c:function:: void z_querier_drop(z_moved_querier_t * closure) \n\nScouting\n========\n\nTypes\n-----\n\nRepresents the content of a `hello` message returned by a zenoh entity as a reply to a `scout` message.\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_hello_t\n.. c:type:: z_loaned_hello_t\n.. c:type:: z_moved_hello_t\n  \nOption Types\n------------\n\n.. autoctype:: types.h::z_scout_options_t\n\nFunctions\n---------\n.. autocfunction:: primitives.h::z_scout\n.. autocfunction:: primitives.h::z_hello_whatami\n.. autocfunction:: primitives.h::z_hello_locators\n.. autocfunction:: primitives.h::zp_hello_locators\n.. autocfunction:: primitives.h::z_hello_zid\n.. autocfunction:: primitives.h::z_whatami_to_view_string\n.. autocfunction:: primitives.h::z_scout_options_default\n\nOwnership Functions\n-------------------\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_hello_drop(z_moved_hello_t * hello) \n.. c:function:: void z_hello_clone(z_owned_hello_t * dst, const z_loaned_hello_t * hello) \n.. c:function:: const z_loaned_hello_t * z_hello_loan(const z_owned_hello_t * hello)\n.. c:function:: z_loaned_hello_t * z_hello_loan_mut(z_owned_hello_t * hello)\n.. c:function:: z_result_t z_hello_take_from_loaned(z_owned_hello_t *dst, z_loaned_hello_t *src)\n\n\nSerialization\n========================\nTypes\n-----\n\nRepresents a data serializer (unstable).\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: ze_owned_serializer_t\n.. c:type:: ze_loaned_serializer_t\n.. c:type:: ze_moved_serializer_t\n\n.. autoctype:: serialization.h::ze_deserializer_t\n\nFunctions\n---------\n.. autocfunction:: serialization.h::ze_deserializer_from_bytes\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_int8\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_int16\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_int32\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_int64\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_uint8\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_uint16\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_uint32\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_uint64\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_float\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_double\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_bool\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_slice\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_string\n.. autocfunction:: serialization.h::ze_deserializer_deserialize_sequence_length\n.. autocfunction:: serialization.h::ze_serializer_empty\n.. autocfunction:: serialization.h::ze_serializer_finish\n.. autocfunction:: serialization.h::ze_serializer_serialize_int8\n.. autocfunction:: serialization.h::ze_serializer_serialize_int16\n.. autocfunction:: serialization.h::ze_serializer_serialize_int32\n.. autocfunction:: serialization.h::ze_serializer_serialize_int64\n.. autocfunction:: serialization.h::ze_serializer_serialize_uint8\n.. autocfunction:: serialization.h::ze_serializer_serialize_uint16\n.. autocfunction:: serialization.h::ze_serializer_serialize_uint32\n.. autocfunction:: serialization.h::ze_serializer_serialize_uint64\n.. autocfunction:: serialization.h::ze_serializer_serialize_float\n.. autocfunction:: serialization.h::ze_serializer_serialize_double\n.. autocfunction:: serialization.h::ze_serializer_serialize_bool\n.. autocfunction:: serialization.h::ze_serializer_serialize_slice\n.. autocfunction:: serialization.h::ze_serializer_serialize_buf\n.. autocfunction:: serialization.h::ze_serializer_serialize_string\n.. autocfunction:: serialization.h::ze_serializer_serialize_str\n.. autocfunction:: serialization.h::ze_serializer_serialize_substr\n.. autocfunction:: serialization.h::ze_serializer_serialize_sequence_length\n.. autocfunction:: serialization.h::ze_deserialize_int8\n.. autocfunction:: serialization.h::ze_deserialize_int16\n.. autocfunction:: serialization.h::ze_deserialize_int32\n.. autocfunction:: serialization.h::ze_deserialize_int64\n.. autocfunction:: serialization.h::ze_deserialize_uint8\n.. autocfunction:: serialization.h::ze_deserialize_uint16\n.. autocfunction:: serialization.h::ze_deserialize_uint32\n.. autocfunction:: serialization.h::ze_deserialize_uint64\n.. autocfunction:: serialization.h::ze_deserialize_float\n.. autocfunction:: serialization.h::ze_deserialize_double\n.. autocfunction:: serialization.h::ze_deserialize_bool\n.. autocfunction:: serialization.h::ze_deserialize_slice\n.. autocfunction:: serialization.h::ze_deserialize_string\n.. autocfunction:: serialization.h::ze_deserializer_is_done\n.. autocfunction:: serialization.h::ze_serialize_int8\n.. autocfunction:: serialization.h::ze_serialize_int16\n.. autocfunction:: serialization.h::ze_serialize_int32\n.. autocfunction:: serialization.h::ze_serialize_int64\n.. autocfunction:: serialization.h::ze_serialize_uint8\n.. autocfunction:: serialization.h::ze_serialize_uint16\n.. autocfunction:: serialization.h::ze_serialize_uint32\n.. autocfunction:: serialization.h::ze_serialize_uint64\n.. autocfunction:: serialization.h::ze_serialize_float\n.. autocfunction:: serialization.h::ze_serialize_double\n.. autocfunction:: serialization.h::ze_serialize_bool\n.. autocfunction:: serialization.h::ze_serialize_slice\n.. autocfunction:: serialization.h::ze_serialize_buf\n.. autocfunction:: serialization.h::ze_serialize_string\n.. autocfunction:: serialization.h::ze_serialize_str\n.. autocfunction:: serialization.h::ze_serialize_substr\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void ze_serializer_drop(ze_moved_serializer_t * serializer) \n.. c:function:: void ze_serializer_clone(ze_owned_serializer_t * dst, const ze_loaned_serializer_t * serializer) \n.. c:function:: const ze_loaned_serializer_t * ze_serializer_loan(const ze_owned_serializer_t * serializer)\n.. c:function:: ze_loaned_serializer_t * ze_serializer_loan_mut(ze_owned_serializer_t * serializer)\n.. c:function:: z_result_t ze_serializer_take_from_loaned(ze_owned_serializer_t *dst, ze_loaned_serializer_t *src)\n\nLiveliness\n========================\nTypes\n-----\n.. autoctype:: liveliness.h::z_liveliness_token_options_t\n.. autoctype:: liveliness.h::z_liveliness_subscriber_options_t\n.. autoctype:: liveliness.h::z_liveliness_get_options_t\n\nRepresents a Liveliness token entity.\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_liveliness_token_t\n.. c:type:: z_loaned_liveliness_token_t\n.. c:type:: z_moved_liveliness_token_t\n\n\nFunctions\n---------\n.. autocfunction:: liveliness.h::z_liveliness_token_options_default\n.. autocfunction:: liveliness.h::z_liveliness_declare_token\n.. autocfunction:: liveliness.h::z_liveliness_undeclare_token\n.. autocfunction:: liveliness.h::z_liveliness_subscriber_options_default\n.. autocfunction:: liveliness.h::z_liveliness_declare_subscriber\n.. autocfunction:: liveliness.h::z_liveliness_declare_background_subscriber\n.. autocfunction:: liveliness.h::z_liveliness_get\n\nCancellation Token\n==================\nTypes\n-----\n\nRepresents a Cancellation token entity, which is used to interrupt initiated queries (unstable).\nSee details at :ref:`owned_types_concept`\n\n.. c:type:: z_owned_cancellation_token_t\n.. c:type:: z_loaned_cancellation_token_t\n.. c:type:: z_moved_cancellation_token_t\n\n\nFunctions\n---------\n.. autocfunction:: primitives.h::z_cancellation_token_new\n.. autocfunction:: primitives.h::z_cancellation_token_is_cancelled\n.. autocfunction:: primitives.h::z_cancellation_token_cancel\n\nOwnership Functions\n^^^^^^^^^^^^^^^^^^^\n\nSee details at :ref:`owned_types_concept`\n\n.. c:function:: void z_cancellation_token_drop(z_moved_cancellation_token_t *cancellation_token) \n.. c:function:: void z_cancellation_token_clone(z_owned_cancellation_token_t *dst, const z_loaned_cancellation_token_t *src) \n.. c:function:: const z_loaned_cancellation_token_t *z_cancellation_token_loan(const z_owned_cancellation_token_t * cancellation_token)\n.. c:function:: z_loaned_cancellation_token * z_cancellation_token_loan_mut(z_owned_cancellation_token_t *cancellation_token)\n.. c:function:: z_result_t z_cancellation_token_take_from_loaned(z_owned_cancellation_token_t *dst, z_loaned_cancellation_token_t *src)\n\nOthers\n======\n\nConstants\n---------\n\n.. autocenum:: constants.h::z_whatami_t\n\nMacros\n------\n.. autocmacro:: macros.h::z_loan\n.. autocmacro:: macros.h::z_move\n.. autocmacro:: macros.h::z_clone\n.. autocmacro:: macros.h::z_drop\n.. autocmacro:: macros.h::z_closure\n\nLogging\n=======\n\n.. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n\nZenoh-Pico provides a flexible logging system to assist with debugging and monitoring.\nBy default, logging is disabled in release builds, but it can be enabled and configured \nbased on the desired level of verbosity.\n\nLogging Levels\n--------------\n\nZenoh-Pico supports three logging levels:\n\n- **Error**: Only error messages are logged. This is the least verbose level.\n- **Info**: Logs informational messages and error messages.\n- **Debug**: Logs debug messages, informational messages, and error messages. This is the most verbose level.\n\nEnabling Logging\n----------------\n\nCMake build provides a variable ``ZENOH_LOG`` which accepts the following values (either uppercase or lowercase):\n - ``ERROR`` to enable error messages.\n - ``WARN`` to enable warning and higher level messages.\n - ``INFO`` to enable informational and higher level messages.\n - ``DEBUG`` to enable debug and higher level messages.\n - ``TRACE`` to enable trace and higher level messages.\n\n.. code-block:: bash\n\n    ZENOH_LOG=debug make  # build zenoh-pico with debug and higher level messages enabled\n\nWhen building zenoh-pico from source, logging can be enabled by defining corresponding macro, like ``-DZENOH_LOG=DEBUG``.\n\nOverride Logs printing\n----------------------\n\nBy default, logging use `printf`, but it can be overridden by setting `ZENOH_LOG_PRINT`:\n\n.. code-block:: bash\n\n    ZENOH_LOG_PRINT=my_print make  # build zenoh-pico using `my_print` instead of `printf` for logging\n\nAdmin Space\n===========\n\n.. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n\nThe *Admin Space* exposes internal runtime information of a Zenoh-Pico session\nthrough a queryable namespace. It allows external Zenoh applications to inspect\nsession state such as transports, links, peers, and capabilities using standard\nZenoh queries.\n\nThe Admin Space is primarily intended for diagnostics, debugging, and tooling.\n\nEnabling the Admin Space\n------------------------\n\nThe Admin Space is an **optional feature** and must be explicitly enabled at\nbuild time by defining the ``Z_FEATURE_ADMIN_SPACE`` configuration flag.\nIt requires both ``Z_FEATURE_UNSTABLE_API`` and ``Z_FEATURE_QUERYABLE``.\nWhen ``Z_FEATURE_CONNECTIVITY`` and ``Z_FEATURE_PUBLICATION`` are enabled,\nAdmin Space also publishes transport/link connectivity events and includes\nconnectivity-specific fields in replies.\n\nWhen building Zenoh-Pico with CMake, this can be enabled via:\n\n.. code-block:: bash\n\n    -DZ_FEATURE_ADMIN_SPACE=1\n\nIf the feature is not enabled, all Admin Space APIs will be unavailable and\nattempts to start the Admin Space will have no effect.\n\nStarting and Stopping the Admin Space\n-------------------------------------\n\nThe Admin Space is implemented as a queryable attached to a session. It can be\nstarted and stopped explicitly using the following functions:\n\n.. autocfunction:: admin_space.h::zp_start_admin_space\n.. autocfunction:: admin_space.h::zp_stop_admin_space\n\nAutomatic Startup\n-----------------\n\nThe Admin Space can also be started automatically when opening a session by\nconfiguring the appropriate option in ``z_open_options_t``.\n\nWhen the ``auto_start_admin_space`` field is set to ``true``, the Admin Space\nis started immediately after the session is opened.\n\n.. code-block:: c\n\n    z_open_options_t opts;\n    z_open_options_default(&opts);\n    opts.auto_start_admin_space = true;\n\n    z_open(&session, config, &opts);\n"
  },
  {
    "path": "docs/concepts.rst",
    "content": "..\n.. Copyright (c) 2024 ZettaScale Technology\n..\n.. This program and the accompanying materials are made available under the\n.. terms of the Eclipse Public License 2.0 which is available at\n.. http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n.. which is available at https://www.apache.org/licenses/LICENSE-2.0.\n..\n.. SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n..\n.. Contributors:\n..   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n..\n\n********\nConcepts\n********\n\nTypes Classification\n====================\n\nZenoh-Pico types fall into these categories:\n\n- Owned types: `z_owned_xxx_t`\n- Loaned types: `z_loaned_xxx_t`\n- Moved types: `z_moved_xxx_t`\n- View types: `z_view_xxx_t`\n- Option structures: `z_xxx_options_t`\n- Enums and plain data structures: `z_xxx_t`\n\n.. _owned_types_concept:\n\nOwned Types `z_owned_xxx_t`\n---------------------------\n\nThe Zenoh-Pico library incorporates concepts like ownership, moving, and borrowing.\n\nTypes prefixed with `z_owned_xxx_t` \"own\" external resources (e.g., memory, file descriptors). \nThese types must be destroyed at the end of their lifecycle using the `z_xxx_drop` function or \nthe `z_drop` macro. Example:\n\n.. code-block:: c\n\n    z_owned_string_t s;\n    z_string_copy_from_str(&s, \"Hello, world!\");\n    //...\n    z_drop(z_move(s));\n\nOwned objects can be passed to functions in two ways: by moving (`z_moved_xxx_t`) or \nloaning (`z_loaned_xxx_t`).\n\n.. _loaned_types_concept:\n\nLoaned Types `z_loaned_xxx_t`\n-----------------------------\n\nTo temporarily pass an owned object, it can be loaned using `z_xxx_loan` functions, which return \na pointer to the corresponding `z_loaned_xxx_t`. For readability, the generic macro `z_loan` is also available.\n\nFunctions accepting a loaned object can either read (`const z_loaned_xxx_t*`) or read and \nmodify (`z_loaned_xxx_t*`) the object. In both cases, ownership remains with the caller. Example:\n\n.. code-block:: c\n\n    z_owned_string_t s, s1;\n    z_string_copy_from_str(&s, \"Hello, world!\");\n    // notice that the prototype of z_string_clone is\n    // void z_string_clone(z_owned_string_t* dst, const z_loaned_string_t* src);\n    // I.e. the only way to pass the source string is by loaning it\n    z_string_clone(&s1, z_loan(s));\n    //...\n    z_drop(z_move(s));\n    z_drop(z_move(s1));\n\n.. _moved_types_concept:\n\nMoved types `z_moved_xxx_t`\n---------------------------\n\nWhen a function accepts a `z_moved_xxx_t*` parameter, it takes ownership of the passed object. \nTo pass the object, use the `z_xxx_move` function or the `z_move` macro.\n\nOnce the object is moved, the caller should no longer use it. While calling `z_drop` is safe, \nit's not required. Note that `z_drop` itself takes ownership, so `z_move` is also needed in this case. Example:\n\n.. code-block:: c\n    \n    z_owned_config_t cfg;\n    z_config_default(&cfg);\n    z_owned_session_t session;\n    // session takes ownership of the config\n    if (z_open(&session, z_move(cfg)) == Z_OK) {\n        //...\n        z_drop(z_move(session));\n    }\n    // z_drop(z_move(cfg)); // this is safe but useless\n\n.. _view_types_concept:\n\nView Types `z_view_xxx_t`\n-------------------------\n\n`z_view_xxx_t` types are reference types that point to external data. These values do not need to be dropped and \nremain valid only as long as the data they reference is valid. Typically the view types are the variants of\nowned types that do not own the data. This allows to use view and owned types interchangeably.\n\n.. code-block:: c\n\n    z_owned_string_t owned;\n    z_string_copy_from_str(&owned, \"Hello, world!\");\n    z_view_string_t view;\n    z_view_string_from_str(&view, \"Hello, another world!\");\n    z_owned_string_t dst;\n    z_string_clone(&dst, z_loan(owned));\n    z_drop(z_move(dst));\n    z_string_clone(&dst, z_loan(view));\n    z_drop(z_move(dst));\n    z_drop(z_move(owned)); // but no need to drop view\n\nOptions Structures `z_xxx_options_t`\n------------------------------------\n\n`z_xxx_options_t` are Plain Old Data (POD) structures used to pass multiple parameters to functions. This makes API \ncompact and allows to extend the API keeping backward compatibility.\n\nNote that when an \"options\" structure contains `z_moved_xxx_t*` fields, assigning `z_move` to this field does not \naffect the owned object. However, passing the structure to a function transfers ownership of the object. Example:\n\n.. code-block:: c\n\n    // assume that we want to mark our message with some metadate of type int64_t\n    z_publisher_put_options_t options;\n    z_publisher_put_options_default(&options);\n    int64_t metadata = 42;\n    z_owned_bytes_t attachment;\n    ze_serialize_int64(&attachment, metadata);\n    options.attachment = z_move(attachment); // the data itself is still in the `attachment`\n\n    z_owned_bytes_t payload;\n    z_bytes_copy_from_str(&payload, \"Don't panic!\"); \n    z_publisher_put(z_loan(pub), z_move(payload), &options);\n    // the `payload` and `attachment` are consumed by the `z_publisher_put` function\n\n\nOther Structures and Enums `z_xxx_t`\n-----------------------------------------\n\nTypes named `z_xxx_t` are copyable, and can be passed by value. Some of them are just plain data structures or enums, like \n`z_timestamp_t`, `z_priority_t`. Some are temporary data access structures, like `z_bytes_slice_iterator_t`, `z_bytes_reader_t`, etc.\n\n.. code-block:: c\n\n    z_timestamp_t ts;\n    z_timestamp_new(&ts, z_loan(session));\n    z_timestamp_t ts1 = ts;\n\nName Prefixes `z_`, `zp_`\n================================\n\nMost functions and types in the C API use the `z_` prefix, which applies to the common zenoh C API\n(currently Rust-based zenoh-c and pure C zenoh-pico).\n\nThe `zp_` prefix is used for functions that are exclusive to zenoh-pico, zenoh-c uses the `zc_` prefix for the same purpose.\n"
  },
  {
    "path": "docs/conf.py",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\n# Configuration file for the Sphinx documentation builder.\nfrom sys import platform\nfrom pathlib import Path\nfrom clang.cindex import Config\n\n# -- Project information -----------------------------------------------------\nproject = 'zenoh-pico'\ncopyright = '2017, 2022 ZettaScale Technology Inc'\nauthor = 'ZettaScale Zenoh team'\nwith open(\"../version.txt\", \"rt\") as f:\n    release = f.read()\n\n# -- General configuration ---------------------------------------------------\nmaster_doc = 'index'\nextensions = ['sphinx_c_autodoc', 'sphinx_c_autodoc.napoleon']\nlanguage = 'c'\nc_autodoc_roots = ['../include/zenoh-pico/api/',\n                   '../include/zenoh-pico/collections/',\n                   '../include/zenoh-pico/system/']\nc_autodoc_compilation_args = [\n    \"-DSPHINX_DOCS\",\n    \"-DZ_FEATURE_AUTODOC=1\",\n    \"-DZ_FEATURE_UNSTABLE_API=1\",\n    \"-DZ_FEATURE_CONNECTIVITY=1\",\n    \"-DZ_FEATURE_PUBLICATION=1\",\n    \"-DZ_FEATURE_ADVANCED_PUBLICATION=1\",\n    \"-DZ_FEATURE_ADVANCED_SUBSCRIPTION=1\",\n    \"-DZ_FEATURE_SUBSCRIPTION=1\",\n    \"-DZ_FEATURE_QUERY=1\",\n    \"-DZ_FEATURE_QUERYABLE=1\",\n    \"-DZ_FEATURE_ENCODING_VALUES=1\",\n    \"-DZ_FEATURE_LIVELINESS=1\",\n    \"-DZ_FEATURE_MATCHING=1\",\n    \"-DZ_FEATURE_SCOUTING=1\",\n    \"-DZ_FEATURE_ADMIN_SPACE=1\",\n]\n\n# -- Options for HTML output -------------------------------------------------\nhtml_theme = 'sphinx_rtd_theme'\n\nbreathe_debug_trace_directives = True\n\nif platform == \"darwin\":\n    LIBCLANG_FILE = Path(\"/Library/Developer/CommandLineTools/usr/lib/libclang.dylib\")\n    LIBCLANG_CELLAR = Path(\"/usr/local/Cellar/llvm/14.0.6/lib/libclang.dylib\")\n    if LIBCLANG_FILE.is_file():\n        Config.set_library_file(LIBCLANG_FILE)\n    elif LIBCLANG_CELLAR.is_file():\n        Config.set_library_file(LIBCLANG_CELLAR)\n    else:\n        raise ValueError(f\"libclang not found. \\nTried: \\n {LIBCLANG_FILE}\\n {LIBCLANG_CELLAR}\")\n\nelif platform == \"win32\":\n    raise ValueError(\"Windows not supported yet for building docs.\")\n\nelse:\n    Config.set_library_file('/usr/lib/llvm-14/lib/libclang.so.1')  # Required for readthedocs\n"
  },
  {
    "path": "docs/config.rst",
    "content": "..\n.. Copyright (c) 2025 ZettaScale Technology\n..\n.. This program and the accompanying materials are made available under the\n.. terms of the Eclipse Public License 2.0 which is available at\n.. http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n.. which is available at https://www.apache.org/licenses/LICENSE-2.0.\n..\n.. SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n..\n.. Contributors:\n..   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n..\n\n*************\nConfiguration\n*************\n\nZenoh-Pico has many run-time and compile-time configuration options. Some are passed as flags by the build system (make, cmake) while others can be modified manually. \n\nAll of those options are visible in the generated `include/zenoh-pico/config.h` from a configured build or install tree.\n\nRun-time options\n================\n\nAll the run-time options presented in `config.h` should be changed using the `zp_config_insert` function with the corresponding key in your application.\n\nMode\n----\n\nDefines if a Zenoh node is a client or peer.\n\n* `Z_CONFIG_MODE_KEY`: The index of the option in the config table.\n* `Z_CONFIG_MODE_CLIENT`: The string value representing client mode.\n* `Z_CONFIG_MODE_PEER`: The string value representing peer mode.\n* `Z_CONFIG_MODE_DEFAULT`: The default value for client or peer mode.\n\nConnect\n-------\n\nDefines one or multiple endpoints a node will connect to.\n\n* `Z_CONFIG_CONNECT_KEY`: The index of the option in the config table.\n* `Z_CONFIG_CONNECT_TIMEOUT_KEY`: Timeout, in milliseconds, dedicated to establishing configured connect locators.\n* `Z_CONFIG_CONNECT_TIMEOUT_DEFAULT`: The default timeout value for configured connect locators.\n* `Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY`: Whether `z_open` should fail when configured connect locators cannot all be\n  established.\n* `Z_CONFIG_CONNECT_EXIT_ON_FAILURE_CLIENT_DEFAULT`: The default exit-on-failure value for client mode.\n* `Z_CONFIG_CONNECT_EXIT_ON_FAILURE_PEER_DEFAULT`: The default exit-on-failure value for peer mode.\n\n.. warning:: `Z_CONFIG_CONNECT_TIMEOUT_KEY` and `Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY` are currently unstable, are only\n  available when `Z_FEATURE_UNSTABLE_API` is enabled, and may be changed in a future release.\n\n`Z_CONFIG_CONNECT_TIMEOUT_KEY` accepts the following values:\n\n* `0`: no retry, try each locator once.\n* `>0`: retry retryable connect failures until the timeout expires.\n* `-1`: retry indefinitely.\n\nThe default connect timeout is `0`.\n\n`Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY` accepts `true` or `false`.\nIts default value is `true` in client mode and `false` in peer mode.\n\nIn client mode, configured connect locators are alternatives.\nZenoh-Pico tries them until one succeeds or the configured timeout expires.\nClient mode always requires at least one connect locator to succeed before `z_open` returns successfully.\nSetting `Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY` to `false` does not allow a client session to open without a transport.\n\nIn peer mode, `z_open` also requires a primary transport before returning successfully.\nThe primary transport is established either by opening the configured listen locator or by connecting to one configured connect locator.\nOnce the primary transport is open, remaining connect locators are added as peers.\n`Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY` controls whether failures while connecting configured peer locators are tolerated.\nIf it is `true`, non-retryable connect errors fail immediately.\nRetryable connect errors are retried according to `Z_CONFIG_CONNECT_TIMEOUT_KEY`; if the timeout expires before the\nrequired connectivity is established, `z_open` fails.\nIf it is `false`, peer connections that are still failing may continue retrying from the transport task until the\nconfigured connect timeout expires.\nWith `Z_FEATURE_MULTI_THREAD` enabled this task runs in the background; otherwise it progresses when the application\nspins the session tasks.\n\nListen\n------\n\nDefines a single endpoint a node will listen on.\n\n* `Z_CONFIG_LISTEN_KEY`: The index of the option in the config table.\n* `Z_CONFIG_LISTEN_TIMEOUT_KEY`: Timeout, in milliseconds, dedicated to opening the configured listen locator.\n* `Z_CONFIG_LISTEN_TIMEOUT_DEFAULT`: The default timeout value for the configured listen locator.\n* `Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY`: Whether `z_open` should fail when the configured listen locator cannot be\n  opened.\n* `Z_CONFIG_LISTEN_EXIT_ON_FAILURE_DEFAULT`: The default exit-on-failure value for the configured listen locator.\n\n.. warning:: `Z_CONFIG_LISTEN_TIMEOUT_KEY` and `Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY` are currently unstable, are only\n  available when `Z_FEATURE_UNSTABLE_API` is enabled, and may be changed in a future release.\n\nZenoh-Pico supports a single configured listen locator.\nConfiguring more than one listen locator causes `z_open` to fail.\n\n`Z_CONFIG_LISTEN_TIMEOUT_KEY` accepts the following values:\n\n* `0`: no retry, try opening the listen locator once.\n* `>0`: retry retryable listen failures until the timeout expires.\n* `-1`: retry indefinitely.\n\nThe default listen timeout is `0`.\n\n`Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY` accepts `true` or `false`.\nIts default value is `true`.\n\nIf `Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY` is `true`, non-retryable listen errors fail immediately.\nRetryable listen errors are retried according to `Z_CONFIG_LISTEN_TIMEOUT_KEY`; if the timeout expires before the listen\nlocator is opened, `z_open` fails.\nIn peer mode, if listening fails and `Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY` is `false`, Zenoh-Pico may still open the\nsession by connecting to a configured connect locator.\nIf no listen or connect locator establishes a primary transport, `z_open` fails.\n\nTLS\n---\n\nWith `Z_FEATURE_LINK_TLS` enabled, configure TLS using the following keys:\n\n* `Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY`: Path to the CA bundle used to verify remote certificates (required).\n* `Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY`: Base64-encoded CA bundle (inline alternative to the file path).\n* `Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_KEY`: Path to the listener private key used while listening for TLS peers (required for peers).\n* `Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_BASE64_KEY`: Base64-encoded listener private key.\n* `Z_CONFIG_TLS_LISTEN_CERTIFICATE_KEY`: Path to the listener certificate presented to clients (required for peers).\n* `Z_CONFIG_TLS_LISTEN_CERTIFICATE_BASE64_KEY`: Base64-encoded listener certificate.\n* `Z_CONFIG_TLS_ENABLE_MTLS_KEY`: Set to `true`/`1`/`yes`/`on` to require client certificates (mutual TLS); defaults to disabled.\n* `Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_KEY`: Path to the client private key (required when mTLS is enabled).\n* `Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_BASE64_KEY`: Base64-encoded client private key.\n* `Z_CONFIG_TLS_CONNECT_CERTIFICATE_KEY`: Path to the client certificate (required when mTLS is enabled).\n* `Z_CONFIG_TLS_CONNECT_CERTIFICATE_BASE64_KEY`: Base64-encoded client certificate.\n* `Z_CONFIG_TLS_VERIFY_NAME_ON_CONNECT_KEY`: Set to `false`/`0`/`no`/`off` to skip CN/SAN hostname verification; defaults to enabled.\n\nScouting\n--------\n\nScouting is used when a node isn't provided with a connect or listen endpoint.\n\nDefines if and how the node will do the scouting.\n\n* `Z_CONFIG_MULTICAST_SCOUTING_KEY`: The index of the option in the config table.\n* `Z_CONFIG_MULTICAST_SCOUTING_DEFAULT`: Default value of run-time scouting activation.\n* `Z_CONFIG_MULTICAST_LOCATOR_KEY`: The index of the option in the config table.\n* `Z_CONFIG_MULTICAST_LOCATOR_DEFAULT`: Default value of endpoint use for scouting.\n* `Z_CONFIG_SCOUTING_TIMEOUT_KEY`: The index of the option in the config table.\n* `Z_CONFIG_SCOUTING_TIMEOUT_DEFAULT`: Default value for scouting timeout in milliseconds.\n* `Z_CONFIG_SCOUTING_WHAT_KEY`: The index of the option in the config table.\n* `Z_CONFIG_SCOUTING_WHAT_DEFAULT`: Default value for scouting node types as a bitmask, see :c:type:`z_whatami_t`\n\nSession id\n----------\n\nDefine a custom value for the session id. Otherwise it will be random.\n\n* `Z_CONFIG_SESSION_ZID_KEY`: The index of the option in the config table.\n\nUnused\n------\n\nThe following options are not currently in use, but might be in the future.\n\n* `Z_CONFIG_ADD_TIMESTAMP_KEY`: The index of the option in the config table.\n* `Z_CONFIG_ADD_TIMESTAMP_DEFAULT`: Default value for automatic timestamps.\n* `Z_CONFIG_USER_KEY`: The index of the option in the config table.\n* `Z_CONFIG_PASSWORD_KEY`: The index of the option in the config table.\n\nManual compile-time options\n===========================\n\nThese options can be changed manually in `config.h.in` if your build system invokes zenoh-pico's own CMake.\n\n* `Z_ZID_LENGTH`: Length of session ids generated by zenoh-pico, in bytes.\n* `Z_PROTO_VERSION`: Id used to identify the Zenoh wire protocol version, DO NOT MODIFY.\n* `Z_TRANSPORT_LEASE_EXPIRE_FACTOR`: Ratio used to calculate the interval for sending keep alive messages.\n* `Z_JOIN_INTERVAL`: Time to wait before sending a new join message, in milliseconds, multicast transport only.\n* `Z_SN_RESOLUTION`: Length of the packet serial number as enum value (0: 8bits, 1: 16 bits, 2: 32 bits, 3: 64 bits)\n* `Z_REQ_RESOLUTION`: Length of the request id as enum value (0: 8bits, 1: 16 bits, 2: 32 bits, 3: 64 bits)\n* `Z_RX_CACHE_SIZE`: Width of the rx cache, when activated.\n* `Z_GET_TIMEOUT_DEFAULT`: Default value for a request timeout, in milliseconds.\n* `Z_LISTEN_MAX_CONNECTION_NB`: Maximum number of connections on a listening socket.\n* `ZP_ASM_NOP`: Change this options if your platform doesn't have a standard `nop` instruction.\n\nGenerated compile-time options\n==============================\n\nAll the generated options must be changed in zenoh-pico's CMake (beware of CMake's cache) or by passing them as flags when calling zenoh-pico's CMake.\n\n* `Z_FRAG_MAX_SIZE`: Size of the defragmentation buffer, in bytes. Any packet bigger than this cannot be received by the node.\n* `Z_BATCH_UNICAST_SIZE`: Size of the unicast packet buffers, in bytes. Any packet bigger than this will be fragmented if possible.\n* `Z_BATCH_MULTICAST_SIZE`: Size of the multicast packet buffers, in bytes. Any packet bigger than this will be fragmented if possible.\n* `Z_CONFIG_SOCKET_TIMEOUT`: Timeout for socket options, if applicable, in milliseconds.\n* `Z_TRANSPORT_LEASE`: Maximum time without receiving messages from a connection before closing it, in milliseconds.\n* `Z_TRANSPORT_ACCEPT_TIMEOUT`: Link accept timeout in P2P mode in milliseconds (maximum amount of time the listening peer would wait to receive a response).\n* `Z_TRANSPORT_CONNECT_TIMEOUT`: Link connect timeout in milliseconds (maximum amount of time the connecting peer would wait to receive a response).\n* `Z_FEATURE_TCP_NODELAY`: (DEFAULT: ON) Toggle the `TCP_NODELAY` socket option that disables Nagle's algorithm as it can cause latency spikes.\n* `Z_FEATURE_AUTO_RECONNECT`: (DEFAULT: ON) Toggle the auto reconnection feature.\n* `Z_FEATURE_MULTICAST_DECLARATIONS`: (DEFAULT: OFF) Toggle multicast declarations. It lets nodes declare key expressions and activate write filtering but requires each node to send all the declarations every time a new node join the network. \n* `Z_FEATURE_RX_CACHE`: (DEFAULT: OFF) Toggle LRU cache on the Rx side, improves throughput at the cost of heap memory.\n* `Z_FEATURE_BATCH_TX_MUTEX`: (DEFAULT: OFF) Toggle tx mutex lock at a batch level instead of at a message level. Improves throughput at the risk of losing connection as it prevents session to send keep alive messages.\n* `Z_FEATURE_BATCH_PEER_MUTEX`: (DEFAULT: OFF) Toggle peer mutex lock at a batch level instead of at a message level. Prevents reception of messages from peers while batching is active, may also trigger loss of connection.\n\nThe following options are here to reduce binary sizes for users that don't need those features but need the extra memory. \n\n* `Z_FEATURE_UNSTABLE_API`: (DEFAULT: OFF) Toggle compilation of unstable API functions.\n* `Z_FEATURE_CONNECTIVITY`: (DEFAULT: OFF) Toggle compilation of connectivity status/events API functions. This feature requires `Z_FEATURE_UNSTABLE_API`.\n* `Z_FEATURE_MULTI_THREAD`: (DEFAULT: ON) Toggle compilation of multi thread capabilities. Will limit the library to single thread only without this.\n* `Z_FEATURE_PUBLICATION`: (DEFAULT: ON) Toggle compilation of publication API functions, the library can't publish without this.\n* `Z_FEATURE_ADVANCED_PUBLICATION`: (DEFAULT: OFF) Toggle compilation of advanced publication API functions.\n* `Z_FEATURE_SUBSCRIPTION`: (DEFAULT: ON) Toggle compilation of subscription API functions, the library can't subscribe without this.\n* `Z_FEATURE_ADVANCED_SUBSCRIPTION`: (DEFAULT: OFF) Toggle compilation of advanced subscription API functions.\n* `Z_FEATURE_QUERY`: (DEFAULT: ON) Toggle compilation of query API functions, the library can't get/query without this.\n* `Z_FEATURE_QUERYABLE`: (DEFAULT: ON) Toggle compilation of queryable API functions, the library can't reply to queries without this.\n* `Z_FEATURE_SCOUTING`: (DEFAULT: ON) Toggle compilation of scouting API functions, the library can't scout without this.\n* `Z_FEATURE_LIVELINESS`: (DEFAULT: ON) Toggle compilation of liveliness API functions, the library can't declare liveliness tokens without this.\n* `Z_FEATURE_BATCHING`: (DEFAULT: ON) Toggle compilation of batching API functions, the library can't batch messages without this.\n* `Z_FEATURE_MATCHING`: (DEFAULT: ON) Toggle compilation of matching API functions,the library can't do matching without this.\n* `Z_FEATURE_INTEREST`: (DEFAULT: ON) Toggle compilation of interest protocol, the library can't do write filtering without this.\n* `Z_FEATURE_ENCODING_VALUES`: (DEFAULT: ON) Toggle compilation of encoding values constants, the library will not provide encoding constants without this.\n* `Z_FEATURE_SESSION_CHECK`: (DEFAULT: ON) Toggle session reference check. Dangerous if entities like publishers or queriers are used after a session is closed.\n* `Z_FEATURE_LOCAL_SUBSCRIBER`: (DEFAULT: OFF) Toggle local subscriber feature, subscribers will not be triggered by local publications without this.\n* `Z_FEATURE_LOCAL_QUERYABLE`: (DEFAULT: OFF) Toggle local queryable feature, queryables will not be triggered by local queries without this.\n* `Z_FEATURE_FRAGMENTATION`: (DEFAULT: ON) Toggle fragmentation feature, the library can't send or receive fragmented messages without this.\n* `Z_FEATURE_MULTICAST_TRANSPORT`: (DEFAULT: ON) Toggle multicast transport feature, the library can't handle multicast connections without this.\n* `Z_FEATURE_UNICAST_TRANSPORT`: (DEFAULT: ON) Toggle unicast transport feature, the library can't handle unicast connections without this.\n* `Z_FEATURE_RAWETH_TRANSPORT`:  (DEFAULT: OFF) Toggle compilation of raw ethernet transport, the library can't handle raw ethernet connections without this.\n* `Z_FEATURE_UNICAST_PEER`: (DEFAULT: ON) Toggle unicast peer feature, the library can't do peer to peer unicast without this.\n* `Z_FEATURE_LINK_TCP`: (DEFAULT: ON) Toggle compilation of TCP link support. \n* `Z_FEATURE_LINK_UDP_MULTICAST`: (DEFAULT: ON) Toggle compilation of UDP multicast link support.\n* `Z_FEATURE_LINK_UDP_UNICAST`: (DEFAULT: ON) Toggle compilation of UDP unicast link support.\n* `Z_FEATURE_LINK_BLUETOOTH`: (DEFAULT: OFF) Toggle compilation of Bluetooth link support.\n* `Z_FEATURE_LINK_WS`: (DEFAULT: OFF) Toggle compilation of WebSocket link support.\n* `Z_FEATURE_LINK_SERIAL`: (DEFAULT: OFF) Toggle compilation of Serial link support.\n* `Z_FEATURE_LINK_SERIAL_USB`: (DEFAULT: OFF) Toggle compilation of Serial USB link support.\n* `Z_FEATURE_LINK_TLS`: (DEFAULT: OFF) Toggle compilation of TLS support.\n* `Z_FEATURE_ADMIN_SPACE`: (DEFAULT: OFF) Toggle compilation of admin space API functions. This feature requires both `Z_FEATURE_UNSTABLE_API` and `Z_FEATURE_QUERYABLE`.\n"
  },
  {
    "path": "docs/index.rst",
    "content": "..\n.. Copyright (c) 2022 ZettaScale Technology\n..\n.. This program and the accompanying materials are made available under the\n.. terms of the Eclipse Public License 2.0 which is available at\n.. http:..www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n.. which is available at https:..www.apache.org/licenses/LICENSE-2.0.\n..\n.. SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n..\n.. Contributors:\n..   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n..\n\n**********\nzenoh-pico\n**********\n\nThe *libzenoh-pico* library provides a C client API for the `Zenoh protocol <https://zenoh.io/>`_.\n\n.. toctree::\n    :maxdepth: 10\n\n    concepts\n    config\n    platforms\n    api\n"
  },
  {
    "path": "docs/platforms.rst",
    "content": "..\n.. Copyright (c) 2026 ZettaScale Technology\n..\n.. This program and the accompanying materials are made available under the\n.. terms of the Eclipse Public License 2.0 which is available at\n.. http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n.. which is available at https://www.apache.org/licenses/LICENSE-2.0.\n..\n.. SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n..\n.. Contributors:\n..   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n..\n\n*********\nPlatforms\n*********\n\n``ZP_PLATFORM`` selects a platform profile.\nThe profile is one CMake file.\nBuilt-in profiles are defined in ``cmake/platforms/<name>.cmake``.\n\nPlatform Selection\n==================\n\nIf ``ZP_PLATFORM`` is not set, Zenoh-Pico selects a default host profile.\n\nExample:\n\n.. code-block:: bash\n\n   cmake -S . -B build \\\n     -DZP_PLATFORM=linux\n\nOne-File Platform Descriptors\n=============================\n\nA platform profile is a CMake file.\nThe template file is ``examples/platforms/myplatform.cmake``.\n\nA minimal profile defines:\n\n* ``ZP_PLATFORM_SOURCE_FILES``;\n* optional ``ZP_PLATFORM_COMPILE_DEFINITIONS``,\n  ``ZP_PLATFORM_INCLUDE_DIRS``, ``ZP_PLATFORM_COMPILE_OPTIONS``, and\n  ``ZP_PLATFORM_LINK_LIBRARIES``;\n* optional ``ZP_PLATFORM_SYSTEM_LAYER`` when the logical system-layer name\n  differs from the profile name;\n* optional ``ZP_PLATFORM_SYSTEM_PLATFORM_HEADER`` when\n  ``include/zenoh-pico/system/common/platform.h`` should include a custom\n  header instead of a built-in one.\n\nPut all platform-specific sources into ``ZP_PLATFORM_SOURCE_FILES``:\n\n* system-layer sources;\n* network/socket sources;\n* TCP, UDP, BT, and serial transport sources;\n* any extra platform files.\n\nExample platform profile:\n\n.. code-block:: cmake\n\n   # cmake/platforms/myrtos.cmake\n   set(ZP_PLATFORM_COMPILE_DEFINITIONS\n       ZENOH_MYRTOS)\n\n   set(ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/system/myrtos/system.c\"\n       \"${PROJECT_SOURCE_DIR}/src/system/socket/lwip.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_lwip.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_lwip.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_myrtos.c\")\n\n   if(ZP_UDP_MULTICAST_ENABLED)\n     list(APPEND ZP_PLATFORM_SOURCE_FILES\n          \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip.c\"\n          \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip_common.c\")\n   endif()\n\n   # Optional platform-wide additions\n   # list(APPEND ZP_PLATFORM_SOURCE_FILES\n   #      \"${PROJECT_SOURCE_DIR}/src/system/myrtos/platform_extra.c\")\n   # list(APPEND ZP_PLATFORM_INCLUDE_DIRS\n   #      \"${PROJECT_SOURCE_DIR}/src/system/myrtos/include\")\n   # list(APPEND ZP_PLATFORM_COMPILE_DEFINITIONS\n   #      ZENOH_MYRTOS_BOARD)\n   # list(APPEND ZP_PLATFORM_COMPILE_OPTIONS\n   #      -Wall)\n   # list(APPEND ZP_PLATFORM_LINK_LIBRARIES\n   #      myrtos::sdk)\n\nNotes:\n\n* ``ZP_PLATFORM_SOURCE_FILES`` is the only source-file bucket.\n* The build does not classify files by role. Put a file into\n  ``ZP_PLATFORM_SOURCE_FILES`` if it belongs to the selected platform.\n* Set ``ZP_PLATFORM_SYSTEM_LAYER`` only when the logical system-layer name\n  differs from the profile name. For example, ``opencr`` uses\n  ``arduino_opencr``.\n* Use ``ZP_UDP_MULTICAST_ENABLED`` when multicast sources depend on the current\n  build configuration.\n\nOut-of-Tree Packages\n====================\n\nOut-of-tree integrations are provided as CMake packages.\nFor each name listed in ``ZP_EXTERNAL_PACKAGES``, Zenoh-Pico runs\n``find_package(<name> CONFIG REQUIRED)``.\n\nExample:\n\n.. code-block:: bash\n\n   cmake -S . -B build \\\n     -DZP_EXTERNAL_PACKAGES=zenohpico-myrtos \\\n     -DCMAKE_PREFIX_PATH=/path/to/prefix \\\n     -DZP_PLATFORM=myrtos\n\nA package usually:\n\n* exports the library targets it owns;\n* registers the platform descriptor directory it provides.\n\nInstalled package platform descriptors should use installed library targets and\ninstalled include paths instead of package source paths.\n\nExample platform descriptor from an external package:\n\n.. code-block:: cmake\n\n   # <prefix>/lib/cmake/zenohpico-myrtos/platforms/myrtos.cmake\n   set(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_MYRTOS)\n   set(ZP_PLATFORM_SYSTEM_PLATFORM_HEADER \"zenoh_myrtos_platform.h\")\n\n   set(ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/system/socket/lwip.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_lwip.c\"\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_lwip.c\")\n\n   if(ZP_UDP_MULTICAST_ENABLED)\n     list(APPEND ZP_PLATFORM_SOURCE_FILES\n          \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip.c\"\n          \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_lwip_common.c\")\n   endif()\n\n   list(APPEND ZP_PLATFORM_INCLUDE_DIRS\n        \"${CMAKE_CURRENT_LIST_DIR}/../../../../include\")\n\n   list(APPEND ZP_PLATFORM_LINK_LIBRARIES\n        myrtos::system\n        myrtos::serial_uart)\n\nExample package config:\n\n.. code-block:: cmake\n\n   include(\"${CMAKE_CURRENT_LIST_DIR}/zenohpicoMyrtosTargets.cmake\")\n\n   if(COMMAND zp_add_platform_dir)\n     zp_add_platform_dir(\"${CMAKE_CURRENT_LIST_DIR}/platforms\")\n   endif()\n\nBuild library targets in the package's own project, install/export them there,\nand load the exported targets from the package's config (``*Config.cmake``)\nfile. Do not call ``add_library()`` or ``add_executable()`` directly in the\npackage's config file.\n\nFor a full out-of-tree example, see\n``examples/packages/zenohpico-mylinux/README.md``.\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "sphinx==7.2.6\nsphinx_c_autodoc==1.3.0\nsphinx_rtd_theme==2.0.0\nclang==14.0\n"
  },
  {
    "path": "docs/zephyr/frdm_mcxn947/prj.conf",
    "content": "# Kernel options\nCONFIG_MAIN_STACK_SIZE=5120\nCONFIG_HEAP_MEM_POOL_SIZE=120000\nCONFIG_ENTROPY_GENERATOR=y\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Generic library options\nCONFIG_NEWLIB_LIBC=y\nCONFIG_NEWLIB_LIBC_NANO=n\nCONFIG_POSIX_API=y\n\n# Generic networking options\nCONFIG_SERIAL=y\nCONFIG_NETWORKING=y\n\nCONFIG_NET_L2_ETHERNET=y\n\nCONFIG_NET_IPV4=y\nCONFIG_NET_IPV6=y\nCONFIG_NET_TCP=y\nCONFIG_NET_ARP=y\nCONFIG_NET_UDP=y\nCONFIG_NET_DHCPV4=n\nCONFIG_NET_SHELL=y\nCONFIG_NET_MGMT=y\nCONFIG_NET_MGMT_EVENT=y\nCONFIG_DNS_RESOLVER=y\n\n# Sockets\nCONFIG_NET_SOCKETS=y\nCONFIG_NET_SOCKETS_POLL_MAX=4\n\n# Network driver config\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Network buffers\n# Note: commented out since those are default values from Zephyr 4.1\n# Please do not increase as this will quickly lead to RAM consumed due\n# to a need of CONFIG_NET_BUF_DATA_SIZE=1536\n#CONFIG_NET_PKT_RX_COUNT=4\n#CONFIG_NET_PKT_TX_COUNT=4\n#CONFIG_NET_BUF_RX_COUNT=36\n#CONFIG_NET_BUF_TX_COUNT=36\nCONFIG_NET_CONTEXT_NET_PKT_POOL=y\n\n# Network address config\nCONFIG_NET_CONFIG_SETTINGS=y\nCONFIG_NET_CONFIG_NEED_IPV4=y\nCONFIG_NET_IPV4_IGMP=y\nCONFIG_NET_CONFIG_NEED_IPV6=y\nCONFIG_NET_IPV6_MLD=y\nCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"192.168.11.2\"\nCONFIG_NET_CONFIG_MY_IPV4_NETMASK=\"255.255.255.0\"\nCONFIG_NET_CONFIG_MY_IPV4_GW=\"192.168.11.1\"\n#CONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"192.168.10.10\"\nCONFIG_NET_CONFIG_MY_IPV6_ADDR=\"2001:db8::2\"\nCONFIG_NET_CONFIG_PEER_IPV6_ADDR=\"2001:db8::1\"\n\n# IP address options\nCONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3\nCONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4\nCONFIG_NET_MAX_CONTEXTS=10\n\n# Logging\nCONFIG_NET_LOG=y\nCONFIG_LOG=y\nCONFIG_NET_STATISTICS=y\nCONFIG_PRINTK=y\n#\n# NXP related configuration for FRDM MCX N947 and Zenoh\n#\nCONFIG_ETH_NXP_ENET_QOS_MAC=y\nCONFIG_ETH_NXP_ENET_QOS=y\n# BUF_DATA_SIZE is needed as with default value of 128 you will quickly\n# see error: 'Rx pkt spans over multiple DMA bufs, not implemented, drop here'\n# Due to BUF size it also makes problematic to increase BUF_RX/TX count above\nCONFIG_NET_BUF_DATA_SIZE=1536\n\nCONFIG_ZENOH_PICO=y\n"
  },
  {
    "path": "docs/zephyr/nRF52840/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13.1)\n\ninclude($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)\nproject(zenoh-pico-zephyr)\n\nFILE(GLOB app_sources ../src/*.c*)\ntarget_sources(app PRIVATE ${app_sources})\n"
  },
  {
    "path": "docs/zephyr/nRF52840/platformio.ini",
    "content": "; PlatformIO Project Configuration File\n;\n;   Build options: build flags, source filter\n;   Upload options: custom upload port, speed and extra flags\n;   Library options: dependencies, extra library storages\n;   Advanced options: extra scripting\n;\n; Please visit documentation for the other options and examples\n; https://docs.platformio.org/page/projectconf.html\n\n[env:nrf52840_mdk]\nplatform = nordicnrf52\nboard = nrf52840_mdk\nframework = zephyr\n"
  },
  {
    "path": "docs/zephyr/nRF52840/prj.conf",
    "content": "# Kernel options\nCONFIG_MAIN_STACK_SIZE=5120\nCONFIG_HEAP_MEM_POOL_SIZE=120000\nCONFIG_ENTROPY_GENERATOR=y\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Generic library options\nCONFIG_NEWLIB_LIBC=y\nCONFIG_POSIX_API=y\nCONFIG_MAX_PTHREAD_COUNT=4\n\n# Generic networking options\nCONFIG_NETWORKING=y\n\n#CONFIG_NET_L2_ETHERNET=y\n#CONFIG_ETH_NATIVE_POSIX=y\n#CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y\n\nCONFIG_NET_IPV4=y\nCONFIG_NET_IPV6=y\nCONFIG_NET_TCP=y\nCONFIG_NET_ARP=y\nCONFIG_NET_UDP=y\nCONFIG_NET_DHCPV4=n\nCONFIG_NET_SHELL=y\nCONFIG_NET_MGMT=y\nCONFIG_NET_MGMT_EVENT=y\nCONFIG_DNS_RESOLVER=y\n\n# Sockets\nCONFIG_NET_SOCKETS=y\nCONFIG_NET_SOCKETS_POSIX_NAMES=y\nCONFIG_NET_SOCKETS_POLL_MAX=4\n\n# Network driver config\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Network buffers\nCONFIG_NET_PKT_RX_COUNT=16\nCONFIG_NET_PKT_TX_COUNT=16\nCONFIG_NET_BUF_RX_COUNT=80\nCONFIG_NET_BUF_TX_COUNT=80\nCONFIG_NET_CONTEXT_NET_PKT_POOL=y\n\n# Network address config\nCONFIG_NET_CONFIG_SETTINGS=y\nCONFIG_NET_CONFIG_NEED_IPV4=y\nCONFIG_NET_IPV4_IGMP=y\nCONFIG_NET_CONFIG_NEED_IPV6=y\nCONFIG_NET_IPV6_NBR_CACHE=n\nCONFIG_NET_IPV6_MLD=y\n\n\n# IP address options\nCONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3\nCONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4\nCONFIG_NET_MAX_CONTEXTS=10\n\n# Openthread options\nCONFIG_OPENTHREAD_SHELL=y\nCONFIG_SHELL_STACK_SIZE=3072\n\nCONFIG_NET_L2_OPENTHREAD=y\n\nCONFIG_OPENTHREAD_DEBUG=y\nCONFIG_OPENTHREAD_L2_DEBUG=y\nCONFIG_OPENTHREAD_L2_LOG_LEVEL_INF=y\n\nCONFIG_OPENTHREAD_NETWORK_NAME=\"zenohnet\"\nCONFIG_OPENTHREAD_CHANNEL=14\nCONFIG_OPENTHREAD_XPANID=\"B0960A4EE8EEEDFD\"\nCONFIG_OPENTHREAD_PANID=53775\n\n# In latest zephyr, this changes to NETWORKKEY\nCONFIG_OPENTHREAD_MASTERKEY=\"EEBDB1818A18AB3B07E51CE370366B5B\"\n\nCONFIG_OPENTHREAD_JOINER=y\nCONFIG_OPENTHREAD_JOINER_AUTOSTART=y\n\n# mbedTLS options\nCONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=768\n\n# Logging\nCONFIG_NET_LOG=y\nCONFIG_LOG=y\nCONFIG_NET_STATISTICS=y\nCONFIG_PRINTK=y\n"
  },
  {
    "path": "docs/zephyr/nucleo_f767zi/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13.1)\n\ninclude($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)\nproject(zenoh-pico-zephyr)\n\nFILE(GLOB app_sources ../src/*.c*)\ntarget_sources(app PRIVATE ${app_sources})\n"
  },
  {
    "path": "docs/zephyr/nucleo_f767zi/platformio.ini",
    "content": "; PlatformIO Project Configuration File\n;\n;   Build options: build flags, source filter\n;   Upload options: custom upload port, speed and extra flags\n;   Library options: dependencies, extra library storages\n;   Advanced options: extra scripting\n;\n; Please visit documentation for the other options and examples\n; https://docs.platformio.org/page/projectconf.html\n\n[env:nucleo_f767zi]\nplatform = ststm32\nboard = nucleo_f767zi\nframework = zephyr\n"
  },
  {
    "path": "docs/zephyr/nucleo_f767zi/prj.conf",
    "content": "# Kernel options\nCONFIG_MAIN_STACK_SIZE=5120\nCONFIG_HEAP_MEM_POOL_SIZE=150000\nCONFIG_ENTROPY_GENERATOR=y\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Generic library options\nCONFIG_NEWLIB_LIBC=y\nCONFIG_NEWLIB_LIBC_NANO=n\nCONFIG_POSIX_API=y\n\n# Generic networking options\nCONFIG_SERIAL=y\nCONFIG_NETWORKING=y\n\nCONFIG_NET_L2_ETHERNET=y\n\nCONFIG_NET_IPV4=y\nCONFIG_NET_IPV6=y\nCONFIG_NET_TCP=y\nCONFIG_NET_ARP=y\nCONFIG_NET_UDP=y\nCONFIG_NET_DHCPV4=n\nCONFIG_NET_SHELL=y\nCONFIG_NET_MGMT=y\nCONFIG_NET_MGMT_EVENT=y\nCONFIG_DNS_RESOLVER=y\n\n# Sockets\nCONFIG_NET_SOCKETS=y\nCONFIG_NET_SOCKETS_POLL_MAX=4\n\n# Network driver config\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Network buffers\nCONFIG_NET_PKT_RX_COUNT=16\nCONFIG_NET_PKT_TX_COUNT=16\nCONFIG_NET_BUF_RX_COUNT=80\nCONFIG_NET_BUF_TX_COUNT=80\nCONFIG_NET_CONTEXT_NET_PKT_POOL=y\n\n# Network address config\nCONFIG_NET_CONFIG_SETTINGS=y\nCONFIG_NET_CONFIG_NEED_IPV4=y\nCONFIG_NET_IPV4_IGMP=y\nCONFIG_NET_CONFIG_NEED_IPV6=y\nCONFIG_NET_IPV6_MLD=y\nCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"192.168.11.2\"\nCONFIG_NET_CONFIG_MY_IPV4_NETMASK=\"255.255.255.0\"\nCONFIG_NET_CONFIG_MY_IPV4_GW=\"192.168.11.1\"\n#CONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"192.168.10.10\"\nCONFIG_NET_CONFIG_MY_IPV6_ADDR=\"2001:db8::2\"\nCONFIG_NET_CONFIG_PEER_IPV6_ADDR=\"2001:db8::1\"\n\n# IP address options\nCONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3\nCONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4\nCONFIG_NET_MAX_CONTEXTS=10\n\n# Logging\nCONFIG_NET_LOG=y\nCONFIG_LOG=y\nCONFIG_NET_STATISTICS=y\nCONFIG_PRINTK=y\n"
  },
  {
    "path": "docs/zephyr/reel_board/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13.1)\n\nadd_definitions(-DSHIELD=link_board_eth)\n#set(DTC_OVERLAY_FILE \"/Users/user/.platformio/packages/framework-zephyr/boards/shields/link_board_eth/link_board_eth.overlay\")\nset(DTC_OVERLAY_FILE $ENV{ZEPHYR_BASE}/boards/shields/link_board_eth/link_board_eth.overlay)\n\ninclude($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)\nproject(zenoh-pico-zephyr)\n\nFILE(GLOB app_sources ../src/*.c*)\ntarget_sources(app PRIVATE ${app_sources})\n"
  },
  {
    "path": "docs/zephyr/reel_board/platformio.ini",
    "content": "; PlatformIO Project Configuration File\n;\n;   Build options: build flags, source filter\n;   Upload options: custom upload port, speed and extra flags\n;   Library options: dependencies, extra library storages\n;   Advanced options: extra scripting\n;\n; Please visit documentation for the other options and examples\n; https://docs.platformio.org/page/projectconf.html\n\n[env:reel_board]\nplatform = nordicnrf52\nboard = reel_board\nframework = zephyr\n"
  },
  {
    "path": "docs/zephyr/reel_board/prj.conf",
    "content": "# Kernel options\nCONFIG_MAIN_STACK_SIZE=5120\nCONFIG_HEAP_MEM_POOL_SIZE=150000\nCONFIG_ENTROPY_GENERATOR=y\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Generic library options\nCONFIG_NEWLIB_LIBC=y\nCONFIG_NEWLIB_LIBC_NANO=n\nCONFIG_POSIX_API=y\n\n# Generic networking options\nCONFIG_NETWORKING=y\n\nCONFIG_SPI=y\nCONFIG_NET_L2_ETHERNET=y\nCONFIG_ETH_ENC424J600=y\n\nCONFIG_ETH_NATIVE_POSIX=y\nCONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y\n\nCONFIG_NET_IPV4=y\nCONFIG_NET_IPV6=y\nCONFIG_NET_TCP=y\nCONFIG_NET_ARP=y\nCONFIG_NET_UDP=y\nCONFIG_NET_DHCPV4=n\nCONFIG_NET_SHELL=y\nCONFIG_NET_MGMT=y\nCONFIG_NET_MGMT_EVENT=y\nCONFIG_DNS_RESOLVER=y\n\n# Sockets\nCONFIG_NET_SOCKETS=y\nCONFIG_NET_SOCKETS_POSIX_NAMES=y\nCONFIG_NET_SOCKETS_POLL_MAX=4\n\n# Network driver config\nCONFIG_TEST_RANDOM_GENERATOR=y\nCONFIG_INIT_STACKS=y\n\n# Network buffers\nCONFIG_NET_PKT_RX_COUNT=16\nCONFIG_NET_PKT_TX_COUNT=16\nCONFIG_NET_BUF_RX_COUNT=80\nCONFIG_NET_BUF_TX_COUNT=80\nCONFIG_NET_CONTEXT_NET_PKT_POOL=y\n\n# Network address config\nCONFIG_NET_CONFIG_SETTINGS=y\nCONFIG_NET_CONFIG_NEED_IPV4=y\nCONFIG_NET_IPV4_IGMP=y\nCONFIG_NET_CONFIG_NEED_IPV6=y\nCONFIG_NET_IPV6_MLD=y\nCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"192.168.11.2\"\nCONFIG_NET_CONFIG_MY_IPV4_NETMASK=\"255.255.255.0\"\nCONFIG_NET_CONFIG_MY_IPV4_GW=\"192.168.11.1\"\n#CONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"192.168.10.10\"\nCONFIG_NET_CONFIG_MY_IPV6_ADDR=\"2001:db8::2\"\nCONFIG_NET_CONFIG_PEER_IPV6_ADDR=\"2001:db8::1\"\n\n# IP address options\nCONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3\nCONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4\nCONFIG_NET_MAX_CONTEXTS=10\n\n# Logging\nCONFIG_NET_LOG=y\nCONFIG_LOG=y\nCONFIG_NET_STATISTICS=y\nCONFIG_PRINTK=y\n\nCONFIG_USE_SEGGER_RTT=y\nCONFIG_SHELL_BACKEND_RTT=y\nCONFIG_RTT_CONSOLE=y\nCONFIG_UART_CONSOLE=n\nCONFIG_LOG=y\n"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})\n    # Settings when 'examples' is the root project\n    cmake_minimum_required(VERSION 3.20)\n    project(zenohpico_examples LANGUAGES C)\n    include(../cmake/helpers.cmake)\n    set_default_build_type(Release)\n    configure_include_project(ZENOHPICO zenohpico zenohpico::lib \"..\" zenohpico \"https://github.com/eclipse-zenoh/zenoh-pico\" \"\")\n    add_custom_target(examples ALL)\n\n    set(CHECK_THREADS \"ON\")\n    if(CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n        # keep ON\n    elseif(POSIX_COMPATIBLE)\n        set(CHECK_THREADS \"OFF\")\n    elseif(CMAKE_SYSTEM_NAME MATCHES \"PICO\")\n        set(CHECK_THREADS \"OFF\")\n    endif()\n\n    set(THREADS_PREFER_PTHREAD_FLAG ON)\n    if(CHECK_THREADS)\n        find_package(Threads REQUIRED)\n    endif()\nelse()\n    message(STATUS \"zenoh-pico examples\")\n    add_custom_target(examples)\n\n    set(THREADS_PREFER_PTHREAD_FLAG ON)\n    if(CHECK_THREADS)\n        find_package(Threads REQUIRED)\n    endif()\nendif()\n\nfunction(add_example name path)\n    add_executable(${name} ${path})\n    set_property(TARGET ${name} PROPERTY C_STANDARD 11)\n    target_link_libraries(${name} PRIVATE zenohpico::lib)\n    cmake_parse_arguments(EX \"THREADS\" \"\" \"\" ${ARGN})\n    if(EX_THREADS AND CHECK_THREADS)\n        target_link_libraries(${name} PRIVATE Threads::Threads)\n    endif()\n    add_dependencies(examples ${name})\nendfunction()\n\nif(UNIX)\n    if(CMAKE_C_STANDARD MATCHES \"99\")\n        add_example(z_put unix/c99/z_put.c)\n        add_example(z_pub unix/c99/z_pub.c)\n        add_example(z_pub_st unix/c99/z_pub_st.c)\n        add_example(z_sub unix/c99/z_sub.c)\n        add_example(z_sub_st unix/c99/z_sub_st.c)\n        add_example(z_pull unix/c99/z_pull.c)\n        add_example(z_get unix/c99/z_get.c)\n        add_example(z_queryable unix/c99/z_queryable.c)\n        add_example(z_info unix/c99/z_info.c)\n        add_example(z_scout unix/c99/z_scout.c)\n        add_example(z_ping unix/c99/z_ping.c)\n        add_example(z_pong unix/c99/z_pong.c)\n    else()\n        add_example(z_put unix/c11/z_put.c)\n        add_example(z_pub unix/c11/z_pub.c)\n        add_example(z_pub_st unix/c11/z_pub_st.c)\n        add_example(z_pub_attachment unix/c11/z_pub_attachment.c)\n        add_example(z_pub_tls unix/c11/z_pub_tls.c)\n        add_example(z_advanced_pub unix/c11/z_advanced_pub.c)\n        add_example(z_sub unix/c11/z_sub.c)\n        add_example(z_sub_channel unix/c11/z_sub_channel.c)\n        add_example(z_sub_st unix/c11/z_sub_st.c)\n        add_example(z_sub_attachment unix/c11/z_sub_attachment.c)\n        add_example(z_sub_liveliness unix/c11/z_sub_liveliness.c)\n        add_example(z_sub_tls unix/c11/z_sub_tls.c)\n        add_example(z_advanced_sub unix/c11/z_advanced_sub.c)\n        add_example(z_pull unix/c11/z_pull.c)\n        add_example(z_get unix/c11/z_get.c)\n        add_example(z_get_channel unix/c11/z_get_channel.c)\n        add_example(z_get_attachment unix/c11/z_get_attachment.c)\n        add_example(z_get_liveliness unix/c11/z_get_liveliness.c)\n        add_example(z_querier unix/c11/z_querier.c)\n        add_example(z_queryable unix/c11/z_queryable.c)\n        add_example(z_queryable_channel unix/c11/z_queryable_channel.c)\n        add_example(z_queryable_attachment unix/c11/z_queryable_attachment.c)\n        add_example(z_info unix/c11/z_info.c)\n        add_example(z_scout unix/c11/z_scout.c)\n        add_example(z_ping unix/c11/z_ping.c)\n        add_example(z_pong unix/c11/z_pong.c)\n        add_example(z_pub_thr unix/c11/z_pub_thr.c THREADS)\n        add_example(z_sub_thr unix/c11/z_sub_thr.c THREADS)\n        add_example(z_bytes unix/c11/z_bytes.c)\n        add_example(z_liveliness unix/c11/z_liveliness.c)\n        add_example(z_get_lat unix/c11/z_get_lat.c)\n        add_example(z_queryable_lat unix/c11/z_queryable_lat.c THREADS)\n    endif()\nelseif(MSVC)\n    add_example(z_put windows/z_put.c)\n    add_example(z_pub windows/z_pub.c)\n    add_example(z_pub_st windows/z_pub_st.c)\n    add_example(z_sub windows/z_sub.c)\n    add_example(z_sub_st windows/z_sub_st.c)\n    add_example(z_pull windows/z_pull.c)\n    add_example(z_get windows/z_get.c)\n    add_example(z_queryable windows/z_queryable.c)\n    add_example(z_info windows/z_info.c)\n    add_example(z_scout windows/z_scout.c)\n    add_example(z_ping windows/z_ping.c)\n    add_example(z_pong windows/z_pong.c)\nendif()\n"
  },
  {
    "path": "examples/arduino/z_get.ino",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <Arduino.h>\n#include <WiFi.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1\n// WiFi-specific parameters\n#define SSID \"SSID\"\n#define PASS \"PASS\"\n\n// Client mode values (comment/uncomment as needed)\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n// Peer mode values (comment/uncomment as needed)\n// #define MODE \"peer\"\n// #define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n\n#define KEYEXPR \"demo/example/**\"\n#define VALUE \"\"\n\nz_owned_session_t s;\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    Serial.println(\" >> Received query final notification\");\n}\n\nvoid reply_handler(z_loaned_reply_t *oreply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(oreply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(oreply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        Serial.print(\" >> [Get listener] Received (\");\n        Serial.write(z_string_data(z_view_string_loan(&keystr)), z_string_len(z_view_string_loan(&keystr)));\n        Serial.print(\", \");\n        Serial.write(z_string_data(z_string_loan(&replystr)), z_string_len(z_string_loan(&replystr)));\n        Serial.println(\")\");\n\n        z_string_drop(z_string_move(&replystr));\n    } else {\n        Serial.println(\" >> Received an error\");\n    }\n}\n\nvoid setup() {\n    // Initialize Serial for debug\n    Serial.begin(115200);\n    while (!Serial) {\n        delay(1000);\n    }\n\n    // Set WiFi in STA mode and trigger attachment\n    Serial.print(\"Connecting to WiFi...\");\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(SSID, PASS);\n    while (WiFi.status() != WL_CONNECTED) {\n        delay(1000);\n    }\n    Serial.println(\"OK\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    Serial.print(\"Opening Zenoh Session...\");\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        Serial.println(\"Unable to open session!\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n    Serial.println(\"Zenoh setup finished!\");\n\n    delay(300);\n}\n\nvoid loop() {\n    delay(5000);\n\n    Serial.print(\"Sending Query \");\n    Serial.print(KEYEXPR);\n    Serial.println(\" ...\");\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    // Value encoding\n    z_owned_bytes_t payload;\n    if (strcmp(VALUE, \"\") != 0) {\n        z_bytes_from_static_str(&payload, VALUE);\n        opts.payload = z_bytes_move(&payload);\n    }\n    z_owned_closure_reply_t callback;\n    z_closure_reply(&callback, reply_handler, reply_dropper, NULL);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_get(z_session_loan(&s), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&callback), &opts) < 0) {\n        Serial.println(\"Unable to send query.\");\n    }\n}\n#else\nvoid setup() {\n    Serial.println(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY but this example requires it.\");\n    return;\n}\nvoid loop() {}\n#endif\n"
  },
  {
    "path": "examples/arduino/z_pub.ino",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <Arduino.h>\n#include <WiFi.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\n// WiFi-specific parameters\n#define SSID \"SSID\"\n#define PASS \"PASS\"\n\n// Client mode values (comment/uncomment as needed)\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n// Peer mode values (comment/uncomment as needed)\n// #define MODE \"peer\"\n// #define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[ARDUINO]{ESP32} Publication from Zenoh-Pico!\"\n\nz_owned_session_t s;\nz_owned_publisher_t pub;\nstatic int idx = 0;\n\nvoid setup() {\n    // Initialize Serial for debug\n    Serial.begin(115200);\n    while (!Serial) {\n        delay(1000);\n    }\n\n    // Set WiFi in STA mode and trigger attachment\n    Serial.print(\"Connecting to WiFi...\");\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(SSID, PASS);\n    while (WiFi.status() != WL_CONNECTED) {\n        delay(1000);\n    }\n    Serial.println(\"OK\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    Serial.print(\"Opening Zenoh Session...\");\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        Serial.println(\"Unable to open session!\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n\n    // Declare Zenoh publisher\n    Serial.print(\"Declaring publisher for \");\n    Serial.print(KEYEXPR);\n    Serial.println(\"...\");\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_session_loan(&s), &pub, z_view_keyexpr_loan(&ke), NULL) < 0) {\n        Serial.println(\"Unable to declare publisher for key expression!\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n    Serial.println(\"Zenoh setup finished!\");\n\n    delay(300);\n}\n\nvoid loop() {\n    delay(1000);\n    char buf[256];\n    sprintf(buf, \"[%4d] %s\", idx++, VALUE);\n\n    Serial.print(\"Writing Data ('\");\n    Serial.print(KEYEXPR);\n    Serial.print(\"': '\");\n    Serial.print(buf);\n    Serial.println(\"')\");\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_copy_from_str(&payload, buf);\n\n    if (z_publisher_put(z_publisher_loan(&pub), z_bytes_move(&payload), NULL) < 0) {\n        Serial.println(\"Error while publishing data\");\n    }\n}\n#else\nvoid setup() {\n    Serial.println(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\");\n    return;\n}\nvoid loop() {}\n#endif\n"
  },
  {
    "path": "examples/arduino/z_pull.ino",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <Arduino.h>\n#include <WiFi.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n// WiFi-specific parameters\n#define SSID \"SSID\"\n#define PASS \"PASS\"\n\n// Client mode values (comment/uncomment as needed)\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n// Peer mode values (comment/uncomment as needed)\n// #define MODE \"peer\"\n// #define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n\n#define KEYEXPR \"demo/example/**\"\n\nconst size_t INTERVAL = 5000;\nconst size_t SIZE = 3;\nz_owned_session_t s;\nz_owned_subscriber_t sub;\nz_owned_ring_handler_sample_t handler;\n\nvoid setup() {\n    // Initialize Serial for debug\n    Serial.begin(115200);\n    while (!Serial) {\n        delay(1000);\n    }\n\n    // Set WiFi in STA mode and trigger attachment\n    Serial.print(\"Connecting to WiFi...\");\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(SSID, PASS);\n    while (WiFi.status() != WL_CONNECTED) {\n        delay(1000);\n    }\n    Serial.println(\"OK\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    Serial.print(\"Opening Zenoh Session...\");\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        Serial.println(\"Unable to open session!\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_sample_t closure;\n    z_ring_channel_sample_new(&closure, &handler, SIZE);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&closure),\n                             NULL) < 0) {\n        Serial.println(\"Unable to declare subscriber.\");\n        return;\n    }\n\n    Serial.println(\"OK\");\n    Serial.println(\"Zenoh setup finished!\");\n\n    delay(300);\n}\n\nvoid loop() {\n    z_owned_sample_t sample;\n    z_result_t res;\n    for (res = z_ring_handler_sample_try_recv(z_ring_handler_sample_loan(&handler), &sample); res == Z_OK;\n         res = z_ring_handler_sample_try_recv(z_ring_handler_sample_loan(&handler), &sample)) {\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(z_sample_loan(&sample)), &keystr);\n        z_owned_string_t value;\n        z_bytes_to_string(z_sample_payload(z_sample_loan(&sample)), &value);\n        Serial.print(\">> [Subscriber] Pulled (\");\n        Serial.write(z_string_data(z_view_string_loan(&keystr)), z_string_len(z_view_string_loan(&keystr)));\n        Serial.print(\": \");\n        Serial.write(z_string_data(z_string_loan(&value)), z_string_len(z_string_loan(&value)));\n        Serial.println(\")\");\n\n        z_string_drop(z_string_move(&value));\n        z_sample_drop(z_sample_move(&sample));\n    }\n    if (res == Z_CHANNEL_NODATA) {\n        delay(INTERVAL);\n    }\n}\n#else\nvoid setup() {\n    Serial.println(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\");\n    return;\n}\nvoid loop() {}\n#endif\n"
  },
  {
    "path": "examples/arduino/z_queryable.ino",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <Arduino.h>\n#include <WiFi.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\n// WiFi-specific parameters\n#define SSID \"SSID\"\n#define PASS \"PASS\"\n\n// Client mode values (comment/uncomment as needed)\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n// Peer mode values (comment/uncomment as needed)\n// #define MODE \"peer\"\n// #define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n\n#define KEYEXPR \"demo/example/zenoh-pico-queryable\"\n#define VALUE \"[ARDUINO]{ESP32} Queryable from Zenoh-Pico!\"\n\nz_owned_session_t s;\nz_owned_queryable_t qable;\n\nvoid query_handler(z_loaned_query_t *query, void *arg) {\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    Serial.print(\" >> [Queryable handler] Received Query '\");\n    Serial.write(z_string_data(z_view_string_loan(&keystr)), z_string_len(z_view_string_loan(&keystr)));\n    Serial.println(\"'\");\n\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_string_loan(&payload_string)) > 1) {\n        Serial.print(\"     with value '\");\n        Serial.write(z_string_data(z_string_loan(&payload_string)), z_string_len(z_string_loan(&payload_string)));\n        Serial.println(\"'\");\n    }\n    z_string_drop(z_string_move(&payload_string));\n\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, VALUE);\n\n    z_query_reply(query, z_view_keyexpr_loan(&ke), z_bytes_move(&reply_payload), NULL);\n}\n\nvoid setup() {\n    // Initialize Serial for debug\n    Serial.begin(115200);\n    while (!Serial) {\n        delay(1000);\n    }\n\n    // Set WiFi in STA mode and trigger attachment\n    Serial.print(\"Connecting to WiFi...\");\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(SSID, PASS);\n    while (WiFi.status() != WL_CONNECTED) {\n        delay(1000);\n    }\n    Serial.println(\"OK\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    Serial.print(\"Opening Zenoh Session...\");\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        Serial.println(\"Unable to open session!\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n\n    // Declare Zenoh queryable\n    Serial.print(\"Declaring Queryable on \");\n    Serial.print(KEYEXPR);\n    Serial.println(\" ...\");\n    z_owned_closure_query_t callback;\n    z_closure_query(&callback, query_handler, NULL, NULL);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_queryable(z_session_loan(&s), &qable, z_view_keyexpr_loan(&ke), z_closure_query_move(&callback),\n                            NULL) < 0) {\n        Serial.println(\"Unable to declare queryable.\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n    Serial.println(\"Zenoh setup finished!\");\n\n    delay(300);\n}\n\nvoid loop() { delay(1000); }\n\n#else\nvoid setup() {\n    Serial.println(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\");\n    return;\n}\nvoid loop() {}\n#endif\n"
  },
  {
    "path": "examples/arduino/z_scout.ino",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <Arduino.h>\n#include <WiFi.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\n// WiFi-specific parameters\n#define SSID \"SSID\"\n#define PASS \"PASS\"\n\nuint8_t zid_len(z_id_t id) {\n    uint8_t len = 16;\n    while (len > 0) {\n        --len;\n        if (id.id[len] != 0) {\n            ++len;\n            break;\n        }\n    }\n    return len;\n}\nvoid fprintzid(z_id_t zid) {\n    unsigned int zidlen = zid_len(zid);\n    if (zidlen == 0) {\n        Serial.print(\"None\");\n    } else {\n        Serial.print(\"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            Serial.print(zid.id[i], HEX);\n        }\n        Serial.print(\")\");\n    }\n}\n\nvoid fprintwhatami(z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    Serial.write(z_string_data(z_view_string_loan(&s)), z_string_len(z_view_string_loan(&s)));\n}\n\nvoid fprintlocators(const z_loaned_string_array_t *locs) {\n    Serial.print(\"[\");\n    size_t len = z_string_array_len(locs);\n    for (unsigned int i = 0; i < len; i++) {\n        Serial.print(\"'\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        Serial.write(z_string_data(str), z_string_len(str));\n        Serial.print(\"'\");\n        if (i < len - 1) {\n            Serial.print(\", \");\n        }\n    }\n    Serial.print(\"]\");\n}\n\nvoid fprinthello(const z_loaned_hello_t *hello) {\n    Serial.print(\" >> Hello { zid: \");\n    fprintzid(z_hello_zid(hello));\n    Serial.print(\", whatami: \");\n    fprintwhatami(z_hello_whatami(hello));\n    Serial.print(\", locators: \");\n    fprintlocators(zp_hello_locators(hello));\n    Serial.println(\" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(hello);\n    Serial.println(\"\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nvoid setup() {\n    // Initialize Serial for debug\n    Serial.begin(115200);\n    while (!Serial) {\n        delay(1000);\n    }\n\n    // Set WiFi in STA mode and trigger attachment\n    Serial.print(\"Connecting to WiFi...\");\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(SSID, PASS);\n    while (WiFi.status() != WL_CONNECTED) {\n        delay(1000);\n    }\n    Serial.println(\"OK\");\n}\n\nvoid loop() {\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure_hello(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_config_move(&config), z_closure_hello_move(&closure), NULL);\n}\n#else\nvoid setup() {\n    Serial.println(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\");\n    return;\n}\nvoid loop() {}\n#endif\n"
  },
  {
    "path": "examples/arduino/z_sub.ino",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <Arduino.h>\n#include <WiFi.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n// WiFi-specific parameters\n#define SSID \"SSID\"\n#define PASS \"PASS\"\n\n// Client mode values (comment/uncomment as needed)\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n// Peer mode values (comment/uncomment as needed)\n// #define MODE \"peer\"\n// #define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n\n#define KEYEXPR \"demo/example/**\"\n\nz_owned_session_t s;\nz_owned_subscriber_t sub;\n\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n\n    Serial.print(\" >> [Subscription listener] Received (\");\n    Serial.write(z_string_data(z_view_string_loan(&keystr)), z_string_len(z_view_string_loan(&keystr)));\n    Serial.print(\", \");\n    Serial.write(z_string_data(z_string_loan(&value)), z_string_len(z_string_loan(&value)));\n    Serial.println(\")\");\n\n    z_string_drop(z_string_move(&value));\n}\n\nvoid setup() {\n    // Initialize Serial for debug\n    Serial.begin(115200);\n    while (!Serial) {\n        delay(1000);\n    }\n\n    // Set WiFi in STA mode and trigger attachment\n    Serial.print(\"Connecting to WiFi...\");\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(SSID, PASS);\n    while (WiFi.status() != WL_CONNECTED) {\n        delay(1000);\n    }\n    Serial.println(\"OK\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    Serial.print(\"Opening Zenoh Session...\");\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        Serial.println(\"Unable to open session!\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n\n    // Declare Zenoh subscriber\n    Serial.print(\"Declaring Subscriber on \");\n    Serial.print(KEYEXPR);\n    Serial.println(\" ...\");\n    z_owned_closure_sample_t callback;\n    z_closure_sample(&callback, data_handler, NULL, NULL);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&callback),\n                             NULL) < 0) {\n        Serial.println(\"Unable to declare subscriber.\");\n        while (1) {\n            ;\n        }\n    }\n    Serial.println(\"OK\");\n    Serial.println(\"Zenoh setup finished!\");\n\n    delay(300);\n}\n\nvoid loop() { delay(1000); }\n\n#else\nvoid setup() {\n    Serial.println(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\");\n    return;\n}\nvoid loop() {}\n#endif\n"
  },
  {
    "path": "examples/espidf/z_get.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <esp_event.h>\n#include <esp_log.h>\n#include <esp_system.h>\n#include <esp_wifi.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n#include <nvs_flash.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1\n#define ESP_WIFI_SSID \"SSID\"\n#define ESP_WIFI_PASS \"PASS\"\n#define ESP_MAXIMUM_RETRY 5\n#define WIFI_CONNECTED_BIT BIT0\n\nstatic bool s_is_wifi_connected = false;\nstatic EventGroupHandle_t s_event_group_handler;\nstatic int s_retry_count = 0;\n\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n#define VALUE \"\"\n\nstatic void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (s_retry_count < ESP_MAXIMUM_RETRY) {\n            esp_wifi_connect();\n            s_retry_count++;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        xEventGroupSetBits(s_event_group_handler, WIFI_CONNECTED_BIT);\n        s_retry_count = 0;\n    }\n}\n\nvoid wifi_init_sta(void) {\n    s_event_group_handler = xEventGroupCreate();\n\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    esp_netif_create_default_wifi_sta();\n\n    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&config));\n\n    esp_event_handler_instance_t handler_any_id;\n    esp_event_handler_instance_t handler_got_ip;\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &handler_any_id));\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &handler_got_ip));\n\n    wifi_config_t wifi_config = {.sta = {\n                                     .ssid = ESP_WIFI_SSID,\n                                     .password = ESP_WIFI_PASS,\n                                 }};\n\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    EventBits_t bits = xEventGroupWaitBits(s_event_group_handler, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    if (bits & WIFI_CONNECTED_BIT) {\n        s_is_wifi_connected = true;\n    }\n\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_got_ip));\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handler_any_id));\n    vEventGroupDelete(s_event_group_handler);\n}\n\nvoid reply_dropper(void *ctx) { printf(\" >> Received query final notification\\n\"); }\n\nvoid reply_handler(z_loaned_reply_t *oreply, void *ctx) {\n    if (z_reply_is_ok(oreply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(oreply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\" >> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n               (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n        z_drop(z_move(replystr));\n    } else {\n        printf(\" >> Received an error\\n\");\n    }\n}\n\nvoid app_main() {\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Set WiFi in STA mode and trigger attachment\n    printf(\"Connecting to WiFi...\");\n    wifi_init_sta();\n    while (!s_is_wifi_connected) {\n        printf(\".\");\n        sleep(1);\n    }\n    printf(\"OK!\\n\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    while (1) {\n        sleep(5);\n        printf(\"Sending Query '%s'...\\n\", KEYEXPR);\n        z_get_options_t opts;\n        z_get_options_default(&opts);\n        // Value encoding\n        z_owned_bytes_t payload;\n        if (strcmp(VALUE, \"\") != 0) {\n            z_bytes_from_static_str(&payload, VALUE);\n            opts.payload = z_move(payload);\n        }\n        z_owned_closure_reply_t callback;\n        z_closure(&callback, reply_handler, reply_dropper, NULL);\n        z_view_keyexpr_t ke;\n        z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n        if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n            printf(\"Unable to send query.\\n\");\n            exit(-1);\n        }\n    }\n\n    printf(\"Closing Zenoh Session...\");\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n}\n#else\nvoid app_main() { printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY but this example requires it.\\n\"); }\n#endif\n"
  },
  {
    "path": "examples/espidf/z_pub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <esp_event.h>\n#include <esp_log.h>\n#include <esp_system.h>\n#include <esp_wifi.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n#include <nvs_flash.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\n#define ESP_WIFI_SSID \"SSID\"\n#define ESP_WIFI_PASS \"PASS\"\n#define ESP_MAXIMUM_RETRY 5\n#define WIFI_CONNECTED_BIT BIT0\n\nstatic bool s_is_wifi_connected = false;\nstatic EventGroupHandle_t s_event_group_handler;\nstatic int s_retry_count = 0;\n\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[ESPIDF]{ESP32} Publication from Zenoh-Pico!\"\n\nstatic void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (s_retry_count < ESP_MAXIMUM_RETRY) {\n            esp_wifi_connect();\n            s_retry_count++;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        xEventGroupSetBits(s_event_group_handler, WIFI_CONNECTED_BIT);\n        s_retry_count = 0;\n    }\n}\n\nvoid wifi_init_sta(void) {\n    s_event_group_handler = xEventGroupCreate();\n\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    esp_netif_create_default_wifi_sta();\n\n    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&config));\n\n    esp_event_handler_instance_t handler_any_id;\n    esp_event_handler_instance_t handler_got_ip;\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &handler_any_id));\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &handler_got_ip));\n\n    wifi_config_t wifi_config = {.sta = {\n                                     .ssid = ESP_WIFI_SSID,\n                                     .password = ESP_WIFI_PASS,\n                                 }};\n\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    EventBits_t bits = xEventGroupWaitBits(s_event_group_handler, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    if (bits & WIFI_CONNECTED_BIT) {\n        s_is_wifi_connected = true;\n    }\n\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_got_ip));\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handler_any_id));\n    vEventGroupDelete(s_event_group_handler);\n}\n\nvoid app_main() {\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Set WiFi in STA mode and trigger attachment\n    printf(\"Connecting to WiFi...\");\n    wifi_init_sta();\n    while (!s_is_wifi_connected) {\n        printf(\".\");\n        sleep(1);\n    }\n    printf(\"OK!\\n\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring publisher for '%s'...\", KEYEXPR);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    char buf[256];\n    for (int idx = 0; 1; ++idx) {\n        sleep(1);\n        sprintf(buf, \"[%4d] %s\", idx, VALUE);\n        printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_drop(z_move(pub));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n}\n#else\nvoid app_main() {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/espidf/z_pull.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <esp_event.h>\n#include <esp_log.h>\n#include <esp_system.h>\n#include <esp_wifi.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n#include <nvs_flash.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define ESP_WIFI_SSID \"SSID\"\n#define ESP_WIFI_PASS \"PASS\"\n#define ESP_MAXIMUM_RETRY 5\n#define WIFI_CONNECTED_BIT BIT0\n\nstatic bool s_is_wifi_connected = false;\nstatic EventGroupHandle_t s_event_group_handler;\nstatic int s_retry_count = 0;\n\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nconst size_t INTERVAL = 5000;\nconst size_t SIZE = 3;\n\nstatic void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (s_retry_count < ESP_MAXIMUM_RETRY) {\n            esp_wifi_connect();\n            s_retry_count++;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        xEventGroupSetBits(s_event_group_handler, WIFI_CONNECTED_BIT);\n        s_retry_count = 0;\n    }\n}\n\nvoid wifi_init_sta(void) {\n    s_event_group_handler = xEventGroupCreate();\n\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    esp_netif_create_default_wifi_sta();\n\n    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&config));\n\n    esp_event_handler_instance_t handler_any_id;\n    esp_event_handler_instance_t handler_got_ip;\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &handler_any_id));\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &handler_got_ip));\n\n    wifi_config_t wifi_config = {.sta = {\n                                     .ssid = ESP_WIFI_SSID,\n                                     .password = ESP_WIFI_PASS,\n                                 }};\n\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    EventBits_t bits = xEventGroupWaitBits(s_event_group_handler, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    if (bits & WIFI_CONNECTED_BIT) {\n        s_is_wifi_connected = true;\n    }\n\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_got_ip));\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handler_any_id));\n    vEventGroupDelete(s_event_group_handler);\n}\n\nvoid app_main() {\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Set WiFi in STA mode and trigger attachment\n    printf(\"Connecting to WiFi...\");\n    wifi_init_sta();\n    while (!s_is_wifi_connected) {\n        printf(\".\");\n        sleep(1);\n    }\n    printf(\"OK!\\n\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, SIZE);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        exit(-1);\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", INTERVAL, SIZE);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &sample); res == Z_OK; res = z_try_recv(z_loan(handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n            z_drop(z_move(value));\n            z_drop(z_move(sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", INTERVAL);\n            z_sleep_ms(INTERVAL);\n        } else {\n            break;\n        }\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n}\n#else\nvoid app_main() {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/espidf/z_queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <esp_event.h>\n#include <esp_log.h>\n#include <esp_system.h>\n#include <esp_wifi.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n#include <nvs_flash.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#define ESP_WIFI_SSID \"SSID\"\n#define ESP_WIFI_PASS \"PASS\"\n#define ESP_MAXIMUM_RETRY 5\n#define WIFI_CONNECTED_BIT BIT0\n\n#if Z_FEATURE_QUERYABLE == 1\nstatic bool s_is_wifi_connected = false;\nstatic EventGroupHandle_t s_event_group_handler;\nstatic int s_retry_count = 0;\n\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-queryable\"\n#define VALUE \"[ESPIDF]{ESP32} Queryable from Zenoh-Pico!\"\n\nstatic void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (s_retry_count < ESP_MAXIMUM_RETRY) {\n            esp_wifi_connect();\n            s_retry_count++;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        xEventGroupSetBits(s_event_group_handler, WIFI_CONNECTED_BIT);\n        s_retry_count = 0;\n    }\n}\n\nvoid wifi_init_sta(void) {\n    s_event_group_handler = xEventGroupCreate();\n\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    esp_netif_create_default_wifi_sta();\n\n    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&config));\n\n    esp_event_handler_instance_t handler_any_id;\n    esp_event_handler_instance_t handler_got_ip;\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &handler_any_id));\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &handler_got_ip));\n\n    wifi_config_t wifi_config = {.sta = {\n                                     .ssid = ESP_WIFI_SSID,\n                                     .password = ESP_WIFI_PASS,\n                                 }};\n\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    EventBits_t bits = xEventGroupWaitBits(s_event_group_handler, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    if (bits & WIFI_CONNECTED_BIT) {\n        s_is_wifi_connected = true;\n    }\n\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_got_ip));\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handler_any_id));\n    vEventGroupDelete(s_event_group_handler);\n}\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, VALUE);\n\n    z_query_reply(query, z_loan(ke), z_move(reply_payload), NULL);\n}\n\nvoid app_main() {\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Set WiFi in STA mode and trigger attachment\n    printf(\"Connecting to WiFi...\");\n    wifi_init_sta();\n    while (!s_is_wifi_connected) {\n        printf(\".\");\n        sleep(1);\n    }\n    printf(\"OK!\\n\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    // Declare Zenoh queryable\n    printf(\"Declaring Queryable on %s...\", KEYEXPR);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare queryable.\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n    printf(\"Zenoh setup finished!\\n\");\n\n    while (1) {\n        sleep(1);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n}\n#else\nvoid app_main() {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/espidf/z_scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <esp_event.h>\n#include <esp_log.h>\n#include <esp_system.h>\n#include <esp_wifi.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n#include <nvs_flash.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\n#define ESP_WIFI_SSID \"SSID\"\n#define ESP_WIFI_PASS \"PASS\"\n#define ESP_MAXIMUM_RETRY 5\n#define WIFI_CONNECTED_BIT BIT0\n\nstatic bool s_is_wifi_connected = false;\nstatic EventGroupHandle_t s_event_group_handler;\nstatic int s_retry_count = 0;\n\nstatic void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (s_retry_count < ESP_MAXIMUM_RETRY) {\n            esp_wifi_connect();\n            s_retry_count++;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        xEventGroupSetBits(s_event_group_handler, WIFI_CONNECTED_BIT);\n        s_retry_count = 0;\n    }\n}\n\nvoid wifi_init_sta(void) {\n    s_event_group_handler = xEventGroupCreate();\n\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    esp_netif_create_default_wifi_sta();\n\n    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&config));\n\n    esp_event_handler_instance_t handler_any_id;\n    esp_event_handler_instance_t handler_got_ip;\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &handler_any_id));\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &handler_got_ip));\n\n    wifi_config_t wifi_config = {.sta = {\n                                     .ssid = ESP_WIFI_SSID,\n                                     .password = ESP_WIFI_PASS,\n                                 }};\n\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    EventBits_t bits = xEventGroupWaitBits(s_event_group_handler, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    if (bits & WIFI_CONNECTED_BIT) {\n        s_is_wifi_connected = true;\n    }\n\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_got_ip));\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handler_any_id));\n    vEventGroupDelete(s_event_group_handler);\n}\n\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_loan(s)), z_string_data(z_loan(s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nvoid app_main() {\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Set WiFi in STA mode and trigger attachment\n    printf(\"Connecting to WiFi...\");\n    wifi_init_sta();\n    while (!s_is_wifi_connected) {\n        printf(\".\");\n        sleep(1);\n    }\n    printf(\"OK!\\n\");\n\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure_hello(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_config_move(&config), z_closure_hello_move(&closure), NULL);\n}\n#else\nvoid app_main() { printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\"); }\n#endif\n"
  },
  {
    "path": "examples/espidf/z_sub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <esp_event.h>\n#include <esp_log.h>\n#include <esp_system.h>\n#include <esp_wifi.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n#include <nvs_flash.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define ESP_WIFI_SSID \"SSID\"\n#define ESP_WIFI_PASS \"PASS\"\n#define ESP_MAXIMUM_RETRY 5\n#define WIFI_CONNECTED_BIT BIT0\n\nstatic bool s_is_wifi_connected = false;\nstatic EventGroupHandle_t s_event_group_handler;\nstatic int s_retry_count = 0;\n\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nstatic void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (s_retry_count < ESP_MAXIMUM_RETRY) {\n            esp_wifi_connect();\n            s_retry_count++;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        xEventGroupSetBits(s_event_group_handler, WIFI_CONNECTED_BIT);\n        s_retry_count = 0;\n    }\n}\n\nvoid wifi_init_sta(void) {\n    s_event_group_handler = xEventGroupCreate();\n\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    esp_netif_create_default_wifi_sta();\n\n    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&config));\n\n    esp_event_handler_instance_t handler_any_id;\n    esp_event_handler_instance_t handler_got_ip;\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &handler_any_id));\n    ESP_ERROR_CHECK(\n        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &handler_got_ip));\n\n    wifi_config_t wifi_config = {.sta = {\n                                     .ssid = ESP_WIFI_SSID,\n                                     .password = ESP_WIFI_PASS,\n                                 }};\n\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    EventBits_t bits = xEventGroupWaitBits(s_event_group_handler, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    if (bits & WIFI_CONNECTED_BIT) {\n        s_is_wifi_connected = true;\n    }\n\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, handler_got_ip));\n    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, handler_any_id));\n    vEventGroupDelete(s_event_group_handler);\n}\n\nvoid data_handler(z_loaned_sample_t* sample, void* arg) {\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\" >> [Subscriber handler] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n           z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&value)),\n           z_string_data(z_string_loan(&value)));\n    z_string_drop(z_string_move(&value));\n}\n\nvoid app_main() {\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Set WiFi in STA mode and trigger attachment\n    printf(\"Connecting to WiFi...\");\n    wifi_init_sta();\n    while (!s_is_wifi_connected) {\n        printf(\".\");\n        sleep(1);\n    }\n    printf(\"OK!\\n\");\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring Subscriber on '%s'...\", KEYEXPR);\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        exit(-1);\n    }\n    printf(\"OK!\\n\");\n\n    while (1) {\n        sleep(1);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_drop(z_move(sub));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n}\n#else\nvoid app_main() {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2023 Fictionlab sp. z o.o.\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   Błażej Sowa, <blazej@fictionlab.pl>\n\ncmake_minimum_required(VERSION 3.20)\nproject(zenohpico_freertos_plus_tcp_examples)\n\nset(CMAKE_SYSTEM_NAME \"Generic\")\nset(CMAKE_C_STANDARD 11)\n\ninclude(../../cmake/helpers.cmake)\nset_default_build_type(Release)\n\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(SLIRP REQUIRED slirp)\n\nadd_library(slirp INTERFACE)\ntarget_link_libraries(slirp INTERFACE ${SLIRP_LINK_LIBRARIES})\ntarget_include_directories(slirp INTERFACE ${SLIRP_INCLUDE_DIRS})\ntarget_compile_options(slirp INTERFACE -Wno-error)\n\ninclude(FetchContent)\n\nFetchContent_Declare(freertos_kernel\n  GIT_REPOSITORY \"https://github.com/FreeRTOS/FreeRTOS-Kernel.git\"\n  GIT_TAG \"V10.6.1\"\n)\n\nFetchContent_Declare(freertos_plus_tcp\n  GIT_REPOSITORY \"https://github.com/FreeRTOS/FreeRTOS-Plus-TCP.git\"\n  GIT_TAG \"34148c3\"\n  GIT_SUBMODULES \"\"\n)\n\nadd_library(freertos_config INTERFACE)\ntarget_include_directories(freertos_config SYSTEM INTERFACE include)\ntarget_compile_options(freertos_config INTERFACE -Wno-error)\n\nset(FREERTOS_HEAP \"3\" CACHE STRING \"\" FORCE)\nset(FREERTOS_PORT \"GCC_POSIX\" CACHE STRING \"\" FORCE)\nset(FREERTOS_PLUS_TCP_NETWORK_IF \"LIBSLIRP\" CACHE STRING \"\" FORCE)\nset(FREERTOS_PLUS_TCP_BUFFER_ALLOCATION \"2\" CACHE STRING \"\" FORCE)\n\nFetchContent_MakeAvailable(freertos_kernel freertos_plus_tcp)\n\nset(BUILD_SHARED_LIBS OFF)\nset(ZP_PLATFORM \"freertos_plus_tcp\" CACHE STRING \"Zenoh-Pico platform profile\")\nset(ZENOH_LOG DEBUG)\nconfigure_include_project(ZENOHPICO zenohpico zenohpico::lib \"../..\" zenohpico \"https://github.com/eclipse-zenoh/zenoh-pico\" \"\")\n\ntarget_link_libraries(zenohpico_static\n  PRIVATE\n    freertos_kernel\n    freertos_plus_tcp\n)\n\nadd_library(main OBJECT main.c)\ntarget_link_libraries(main\n  freertos_kernel\n  freertos_plus_tcp\n)\n\nfunction(add_example name)\n  add_executable(${name} ${name}.c)\n  target_link_libraries(${name}\n    main\n    freertos_kernel\n    freertos_plus_tcp\n    zenohpico::lib\n  )\nendfunction()\n\nadd_example(z_get)\nadd_example(z_pub_st)\nadd_example(z_pub)\nadd_example(z_pull)\nadd_example(z_put)\nadd_example(z_queryable)\nadd_example(z_scout)\nadd_example(z_sub_st)\nadd_example(z_sub)\n"
  },
  {
    "path": "examples/freertos_plus_tcp/include/FreeRTOSConfig.h",
    "content": "//\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#ifndef FREERTOS_CONFIG_H\n#define FREERTOS_CONFIG_H\n\n#include \"bits/pthread_stack_min.h\"\n\n/* Core options */\n#define configUSE_PREEMPTION 1\n#define configTICK_RATE_HZ ((TickType_t)1000)\n#define configMAX_PRIORITIES (56)\n#define configMINIMAL_STACK_SIZE ((uint16_t)PTHREAD_STACK_MIN)\n#define configMAX_TASK_NAME_LEN (16)\n#define configUSE_16_BIT_TICKS 0\n#define configQUEUE_REGISTRY_SIZE 0\n#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1\n#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0\n\n/* Hook function related definitions. */\n#define configUSE_IDLE_HOOK 0\n#define configUSE_TICK_HOOK 0\n#define configUSE_MALLOC_FAILED_HOOK 0\n#define configUSE_DAEMON_TASK_STARTUP_HOOK 0\n#define configUSE_SB_COMPLETED_CALLBACK 0\n\n/* Enable/Disable features */\n#define configSUPPORT_STATIC_ALLOCATION 1\n#define configSUPPORT_DYNAMIC_ALLOCATION 1\n#define configUSE_MUTEXES 1\n#define configUSE_RECURSIVE_MUTEXES 1\n#define configUSE_COUNTING_SEMAPHORES 1\n#define configUSE_CO_ROUTINES 0\n#define configUSE_TIMERS 0\n#define configUSE_TRACE_FACILITY 0\n#define configUSE_QUEUE_SETS 0\n#define configUSE_NEWLIB_REENTRANT 0\n\n/* Set the API functions which should be included */\n#define INCLUDE_vTaskPrioritySet 1\n#define INCLUDE_uxTaskPriorityGet 1\n#define INCLUDE_vTaskDelete 1\n#define INCLUDE_vTaskCleanUpResources 0\n#define INCLUDE_vTaskSuspend 1\n#define INCLUDE_vTaskDelayUntil 1\n#define INCLUDE_vTaskDelay 1\n#define INCLUDE_xTaskGetSchedulerState 1\n#define INCLUDE_xTimerPendFunctionCall 1\n#define INCLUDE_xQueueGetMutexHolder 1\n#define INCLUDE_uxTaskGetStackHighWaterMark 1\n#define INCLUDE_eTaskGetState 1\n#define INCLUDE_xTimerPendFunctionCall 0\n\n#endif /* FREERTOS_CONFIG_H */\n"
  },
  {
    "path": "examples/freertos_plus_tcp/include/FreeRTOSIPConfig.h",
    "content": "//\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#ifndef FREERTOS_IP_CONFIG_H\n#define FREERTOS_IP_CONFIG_H\n\n// Driver specific\n#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN\n#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1\n#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 0\n#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1\n#define ipconfigZERO_COPY_RX_DRIVER 1\n#define ipconfigZERO_COPY_TX_DRIVER 1\n#define ipconfigUSE_LINKED_RX_MESSAGES 1\n#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60\n\n// Enable/Disable features\n#define ipconfigUSE_IPv4 1\n#define ipconfigUSE_IPv6 1\n#define ipconfigUSE_DHCP 1\n#define ipconfigUSE_DHCPv6 0\n#define ipconfigUSE_RA 0\n#define ipconfigUSE_DNS 1\n#define ipconfigUSE_TCP 1\n#define ipconfigUSE_ARP_REMOVE_ENTRY 0\n#define ipconfigUSE_ARP_REVERSED_LOOKUP 0\n#define ipconfigSUPPORT_SELECT_FUNCTION 1\n#define ipconfigSUPPORT_OUTGOING_PINGS 0\n#define ipconfigUSE_NETWORK_EVENT_HOOK 1\n#define ipconfigUSE_DHCP_HOOK 0\n\n// DHCP\n#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD (pdMS_TO_TICKS(1000U))\n#define ipconfigDHCP_REGISTER_HOSTNAME 1\n\n#define ipconfigIP_TASK_PRIORITY (configMAX_PRIORITIES - 2)\n#define ipconfigIP_TASK_STACK_SIZE_WORDS (configMINIMAL_STACK_SIZE * 5)\n\n// Set ipconfigBUFFER_PADDING on 64-bit platforms\n#if INTPTR_MAX == INT64_MAX\n#define ipconfigBUFFER_PADDING 14U\n#endif\n\n#endif /* FREERTOS_IP_CONFIG_H */\n"
  },
  {
    "path": "examples/freertos_plus_tcp/main.c",
    "content": "//\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"FreeRTOS.h\"\n#include \"FreeRTOS_IP.h\"\n#include \"task.h\"\n\n#define APP_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE\n#define APP_TASK_PRIORITY 10\n\nstatic const uint8_t ucIPAddress[] = {192, 168, 1, 80};\nstatic const uint8_t ucNetMask[] = {255, 255, 255, 0};\nstatic const uint8_t ucGatewayAddress[] = {192, 168, 1, 1};\nstatic const uint8_t ucDNSServerAddress[] = {192, 168, 1, 1};\nstatic const uint8_t ucMACAddress[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};\n\nNetworkInterface_t *pxLibslirp_FillInterfaceDescriptor(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface);\n\nstatic NetworkInterface_t xInterface;\nstatic NetworkEndPoint_t xEndPoint;\n\nstatic TaskHandle_t xAppTaskHandle;\nstatic StaticTask_t xAppTaskTCB;\nstatic StackType_t uxAppTaskStack[APP_TASK_STACK_DEPTH];\n\nvoid app_main();\n\nstatic void vAppTask(void * /*argument*/) {\n    printf(\"Waiting for network...\\n\");\n\n    uint32_t ulNotificationValue = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5000));\n\n    if (ulNotificationValue == 0) {\n        printf(\"Timed out waiting for network.\\n\");\n    } else {\n        printf(\"Starting Zenoh App...\\n\");\n        app_main();\n    }\n\n    vTaskDelete(NULL);\n}\n\nint main(int argc, char **argv) {\n    memcpy(ipLOCAL_MAC_ADDRESS, ucMACAddress, sizeof(ucMACAddress));\n\n    pxLibslirp_FillInterfaceDescriptor(0, &xInterface);\n\n    FreeRTOS_FillEndPoint(&xInterface, &xEndPoint, ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress,\n                          ucMACAddress);\n    xEndPoint.bits.bWantDHCP = 1;\n\n    FreeRTOS_IPInit_Multi();\n\n    xAppTaskHandle =\n        xTaskCreateStatic(vAppTask, \"\", APP_TASK_STACK_DEPTH, NULL, APP_TASK_PRIORITY, uxAppTaskStack, &xAppTaskTCB);\n    vTaskStartScheduler();\n\n    return 0;\n}\n\nvoid vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer,\n                                   uint32_t *pulIdleTaskStackSize) {\n    static StaticTask_t xIdleTaskTCB;\n    static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];\n\n    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;\n    *ppxIdleTaskStackBuffer = uxIdleTaskStack;\n    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;\n}\n\nBaseType_t xApplicationGetRandomNumber(uint32_t *pulNumber) {\n    *pulNumber = (uint32_t)rand();\n\n    return pdTRUE;\n}\n\nuint32_t ulApplicationGetNextSequenceNumber(uint32_t /*ulSourceAddress*/, uint16_t /*usSourcePort*/,\n                                            uint32_t /*ulDestinationAddress*/, uint16_t /*usDestinationPort*/) {\n    uint32_t ulNext = 0;\n    xApplicationGetRandomNumber(&ulNext);\n\n    return ulNext;\n}\n\nconst char *pcApplicationHostnameHook(void) { return \"FreeRTOS-simulator\"; }\n\nvoid vApplicationIPNetworkEventHook_Multi(eIPCallbackEvent_t eNetworkEvent, struct xNetworkEndPoint * /*xEndPoint*/) {\n    if (eNetworkEvent == eNetworkUp) {\n        printf(\"Network is up!\\n\");\n\n        uint32_t ulIPAddress = 0;\n        uint32_t ulNetMask = 0;\n        uint32_t ulGatewayAddress = 0;\n        uint32_t ulDNSServerAddress = 0;\n        char cBuf[50];\n\n        // The network is up and configured. Print out the configuration obtained\n        // from the DHCP server.\n        FreeRTOS_GetEndPointConfiguration(&ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, &xEndPoint);\n\n        // Convert the IP address to a string then print it out.\n        FreeRTOS_inet_ntoa(ulIPAddress, cBuf);\n        printf(\"IP Address: %s\\n\", cBuf);\n\n        // Convert the net mask to a string then print it out.\n        FreeRTOS_inet_ntoa(ulNetMask, cBuf);\n        printf(\"Subnet Mask: %s\\n\", cBuf);\n\n        // Convert the IP address of the gateway to a string then print it out.\n        FreeRTOS_inet_ntoa(ulGatewayAddress, cBuf);\n        printf(\"Gateway IP Address: %s\\n\", cBuf);\n\n        // Convert the IP address of the DNS server to a string then print it out.\n        FreeRTOS_inet_ntoa(ulDNSServerAddress, cBuf);\n        printf(\"DNS server IP Address: %s\\n\", cBuf);\n\n        // Make sure MAC address of the gateway is known\n        if (xARPWaitResolution(ulGatewayAddress, pdMS_TO_TICKS(3000)) < 0) {\n            xTaskNotifyGive(xAppTaskHandle);\n        } else {\n            printf(\"Failed to obtain the MAC address of the gateway!\\n\");\n        }\n\n    } else if (eNetworkEvent == eNetworkDown) {\n        printf(\"IPv4 End Point is down!\\n\");\n    }\n}\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_get.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#include \"FreeRTOS.h\"\n\n#if Z_FEATURE_QUERY == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n#define VALUE \"\"\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    printf(\">> Received query final notification\\n\");\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n               (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n        z_drop(z_move(replystr));\n    } else {\n        printf(\">> Received an error\\n\");\n    }\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, KEYEXPR) < 0) {\n        printf(\"%s is not a valid key expression\\n\", KEYEXPR);\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(5);\n        printf(\"Sending Query '%s'...\\n\", KEYEXPR);\n        z_get_options_t opts;\n        z_get_options_default(&opts);\n        // Value encoding\n        z_owned_bytes_t payload;\n        if (strcmp(VALUE, \"\") != 0) {\n            z_bytes_from_static_str(&payload, VALUE);\n            opts.payload = z_move(payload);\n        }\n        z_owned_closure_reply_t callback;\n        z_closure(&callback, reply_handler, reply_dropper, NULL);\n        if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n            printf(\"Unable to send query.\\n\");\n            return;\n        }\n    }\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_pub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#include \"FreeRTOS.h\"\n\n#if Z_FEATURE_PUBLICATION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[FreeRTOS-Plus-TCP] Pub from Zenoh-Pico!\"\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", KEYEXPR);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return;\n    }\n\n    char *buf = (char *)pvPortMalloc(256);\n    for (int idx = 0; 1; ++idx) {\n        z_sleep_s(1);\n        snprintf(buf, 256, \"[%4d] %s\", idx, VALUE);\n        printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put_options_t options;\n        z_publisher_put_options_default(&options);\n        z_publisher_put(z_loan(pub), z_move(payload), &options);\n    }\n\n    // Clean-up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_pub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#include \"FreeRTOS.h\"\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 0\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[FreeRTOS-Plus-TCP] Pub from Zenoh-Pico!\"\n#define N 2147483647  // max int value by default\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", KEYEXPR);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return;\n    }\n\n    char *buf = (char *)pvPortMalloc(256);\n    z_clock_t now = z_clock_now();\n    for (int idx = 0; idx < N;) {\n        if (z_clock_elapsed_ms(&now) > 1000) {\n            snprintf(buf, 256, \"[%4d] %s\", idx, VALUE);\n            printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_copy_from_str(&payload, buf);\n\n            z_publisher_put(z_loan(pub), z_move(payload), NULL);\n            ++idx;\n\n            now = z_clock_now();\n        }\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n\n    z_drop(z_move(pub));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_PUBLICATION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_pull.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nconst size_t INTERVAL = 5000;\nconst size_t SIZE = 3;\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, SIZE);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", INTERVAL, SIZE);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &sample); res == Z_OK; res = z_try_recv(z_loan(handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n            z_drop(z_move(value));\n            z_drop(z_move(sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", INTERVAL);\n            z_sleep_ms(INTERVAL);\n        } else {\n            break;\n        }\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_put.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-put\"\n#define VALUE \"[FreeRTOS-Plus-TCP] Pub from Zenoh-Pico!\"\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring key expression '%s'...\\n\", KEYEXPR);\n    z_owned_keyexpr_t ke;\n    z_view_keyexpr_t vke;\n    z_view_keyexpr_from_str_unchecked(&vke, KEYEXPR);\n    if (z_declare_keyexpr(z_loan(s), &ke, z_loan(vke)) < 0) {\n        printf(\"Unable to declare key expression!\\n\");\n        z_drop(z_move(s));\n        return;\n    }\n\n    printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, VALUE);\n    z_put_options_t options;\n    z_put_options_default(&options);\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, VALUE);\n\n    if (z_put(z_loan(s), z_loan(ke), z_move(payload), &options) < 0) {\n        printf(\"Oh no! Put has failed...\\n\");\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    // Clean up\n    z_undeclare_keyexpr(z_loan(s), z_move(ke));\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-queryable\"\n#define VALUE \"[FreeRTOS-Plus-TCP] Queryable from Zenoh-Pico!\"\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n\n    z_query_reply_options_t options;\n    z_query_reply_options_default(&options);\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, VALUE);\n\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), &options);\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, KEYEXPR) < 0) {\n        printf(\"%s is not a valid key expression\\n\", KEYEXPR);\n        return;\n    }\n\n    printf(\"Creating Queryable on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#include \"FreeRTOS.h\"\n\n#if Z_FEATURE_SCOUTING == 1\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_loan(s)), z_string_data(z_loan(s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    vPortFree(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nvoid app_main(void) {\n    int *context = (int *)pvPortMalloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_move(config), z_move(closure), NULL);\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_sub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    z_drop(z_move(sub));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/freertos_plus_tcp/z_sub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_MULTI_THREAD == 0\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n#define N 2147483647  // max int value by default\n\nint msg_nb = 0;\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    msg_nb++;\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    printf(\"Running until %d messages are received...\\n\", N);\n    while (msg_nb < N) {\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n\n    z_drop(z_move(sub));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_SUBSCRIPTION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/mbed/z_get.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <EthernetInterface.h>\n#include <mbed.h>\n#include <randLIB.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n#define VALUE \"\"\n\nvoid reply_dropper(void *ctx) { printf(\" >> Received query final notification\\n\"); }\n\nvoid reply_handler(z_loaned_reply_t *oreply, void *ctx) {\n    if (z_reply_is_ok(oreply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(oreply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\" >> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n               z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&replystr)),\n               z_string_data(z_string_loan(&replystr)));\n        z_string_drop(z_string_move(&replystr));\n    } else {\n        printf(\" >> Received an error\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    randLIB_seed_random();\n\n    EthernetInterface net;\n    net.set_network(\"192.168.11.2\", \"255.255.255.0\", \"192.168.11.1\");\n    net.connect();\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    while (1) {\n        z_sleep_s(5);\n        printf(\"Sending Query '%s'...\\n\", KEYEXPR);\n        z_get_options_t opts;\n        z_get_options_default(&opts);\n        // Value encoding\n        z_owned_bytes_t payload;\n        if (strcmp(VALUE, \"\") != 0) {\n            z_bytes_from_static_str(&payload, VALUE);\n            opts.payload = z_bytes_move(&payload);\n        }\n        z_owned_closure_reply_t callback;\n        z_closure_reply(&callback, reply_handler, reply_dropper, NULL);\n        z_view_keyexpr_t ke;\n        z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n        if (z_get(z_session_loan(&s), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&callback), &opts) < 0) {\n            printf(\"Unable to send query.\\n\");\n            exit(-1);\n        }\n    }\n\n    printf(\"Closing Zenoh Session...\");\n\n    z_session_drop(z_session_move(&s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY but this example requires it\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/mbed/z_pub.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <EthernetInterface.h>\n#include <mbed.h>\n#include <randLIB.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[MBedOS]{nucleo-F767ZI} Pub from Zenoh-Pico!\"\n\nint main(int argc, char **argv) {\n    randLIB_seed_random();\n\n    EthernetInterface net;\n    net.set_network(\"192.168.11.2\", \"255.255.255.0\", \"192.168.11.1\");\n    net.connect();\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring publisher for '%s'...\", KEYEXPR);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_session_loan(&s), &pub, z_view_keyexpr_loan(&ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    char buf[256];\n    for (int idx = 0; 1; ++idx) {\n        z_sleep_s(1);\n        sprintf(buf, \"[%4d] %s\", idx, VALUE);\n        printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put(z_publisher_loan(&pub), z_bytes_move(&payload), NULL);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_publisher_drop(z_publisher_move(&pub));\n\n    z_session_drop(z_session_move(&s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/mbed/z_pull.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <EthernetInterface.h>\n#include <mbed.h>\n#include <randLIB.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nconst size_t INTERVAL = 5000;\nconst size_t SIZE = 3;\n\nint main(int argc, char **argv) {\n    randLIB_seed_random();\n\n    EthernetInterface net;\n    net.set_network(\"192.168.11.2\", \"255.255.255.0\", \"192.168.11.1\");\n    net.connect();\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, SIZE);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&closure),\n                             NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", INTERVAL, SIZE);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_ring_handler_sample_try_recv(z_ring_handler_sample_loan(&handler), &sample); res == Z_OK;\n             res = z_ring_handler_sample_try_recv(z_ring_handler_sample_loan(&handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_sample_loan(&sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_sample_loan(&sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n                   z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&value)),\n                   z_string_data(z_string_loan(&value)));\n            z_string_drop(z_string_move(&value));\n            z_sample_drop(z_sample_move(&sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", INTERVAL);\n            z_sleep_ms(INTERVAL);\n        } else {\n            break;\n        }\n    }\n\n    z_subscriber_drop(z_subscriber_move(&sub));\n    z_ring_handler_sample_drop(z_ring_handler_sample_move(&handler));\n\n    z_session_drop(z_session_move(&s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/mbed/z_queryable.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <EthernetInterface.h>\n#include <mbed.h>\n#include <randLIB.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-queryable\"\n#define VALUE \"[MBedOS]{nucleo-F767ZI} Queryable from Zenoh-Pico!\"\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n           z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_view_string_loan(&params)),\n           z_string_data(z_view_string_loan(&params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_string_loan(&payload_string)) > 1) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_string_loan(&payload_string)),\n               z_string_data(z_string_loan(&payload_string)));\n    }\n    z_string_drop(z_string_move(&payload_string));\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, VALUE);\n\n    z_query_reply(query, z_query_keyexpr(query), z_bytes_move(&reply_payload), NULL);\n}\n\nint main(int argc, char **argv) {\n    randLIB_seed_random();\n\n    EthernetInterface net;\n    net.set_network(\"192.168.11.2\", \"255.255.255.0\", \"192.168.11.1\");\n    net.connect();\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    // Declare Zenoh queryable\n    printf(\"Declaring Queryable on %s...\", KEYEXPR);\n    z_owned_closure_query_t callback;\n    z_closure_query(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_queryable(z_session_loan(&s), &qable, z_view_keyexpr_loan(&ke), z_closure_query_move(&callback),\n                            NULL) < 0) {\n        printf(\"Unable to declare queryable.\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n    printf(\"Zenoh setup finished!\\n\");\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_queryable_drop(z_queryable_move(&qable));\n\n    z_session_drop(z_session_move(&s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/mbed/z_scout.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <EthernetInterface.h>\n#include <mbed.h>\n#include <randLIB.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\nuint8_t zid_len(z_id_t id) {\n    uint8_t len = 16;\n    while (len > 0) {\n        --len;\n        if (id.id[len] != 0) {\n            ++len;\n            break;\n        }\n    }\n    return len;\n}\n\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = zid_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_view_string_loan(&s)), z_string_data(z_view_string_loan(&s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nint main(void) {\n    randLIB_seed_random();\n\n    EthernetInterface net;\n    net.set_network(\"192.168.11.2\", \"255.255.255.0\", \"192.168.11.1\");\n    net.connect();\n\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure_hello(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_config_move(&config), z_closure_hello_move(&closure), NULL);\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/mbed/z_sub.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <EthernetInterface.h>\n#include <mbed.h>\n#include <randLIB.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\" >> [Subscriber handler] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n           z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&value)),\n           z_string_data(z_string_loan(&value)));\n    z_string_drop(z_string_move(&value));\n}\n\nint main(int argc, char **argv) {\n    randLIB_seed_random();\n\n    EthernetInterface net;\n    net.set_network(\"192.168.11.2\", \"255.255.255.0\", \"192.168.11.1\");\n    net.connect();\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring Subscriber on '%s'...\", KEYEXPR);\n    z_owned_closure_sample_t callback;\n    z_closure_sample(&callback, data_handler, NULL, NULL);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&callback),\n                             NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        exit(-1);\n    }\n    printf(\"OK!\\n\");\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_subscriber_drop(z_subscriber_move(&sub));\n\n    z_session_drop(z_session_move(&s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.14)\nproject(zenohpico_mylinux LANGUAGES C)\n\ninclude(GNUInstallDirs)\n\nset(ZENOH_PICO_SOURCE_DIR\n    \"${CMAKE_CURRENT_LIST_DIR}/../../..\"\n    CACHE PATH\n    \"Path to the zenoh-pico source tree\")\nget_filename_component(ZENOH_PICO_SOURCE_DIR \"${ZENOH_PICO_SOURCE_DIR}\" ABSOLUTE)\nset(ZENOH_PICO_CONFIG_INCLUDE_DIR\n    \"${ZENOH_PICO_SOURCE_DIR}/build/include\"\n    CACHE PATH\n    \"Path to the configured zenoh-pico include directory with zenoh-pico/config.h\")\nget_filename_component(ZENOH_PICO_CONFIG_INCLUDE_DIR \"${ZENOH_PICO_CONFIG_INCLUDE_DIR}\" ABSOLUTE)\n\nif(NOT EXISTS \"${ZENOH_PICO_SOURCE_DIR}/include/zenoh-pico.h\")\n  message(FATAL_ERROR\n          \"ZENOH_PICO_SOURCE_DIR must point to a zenoh-pico source tree; \"\n          \"missing include/zenoh-pico.h in ${ZENOH_PICO_SOURCE_DIR}\")\nendif()\nif(NOT EXISTS \"${ZENOH_PICO_CONFIG_INCLUDE_DIR}/zenoh-pico/config.h\")\n  message(FATAL_ERROR\n          \"ZENOH_PICO_CONFIG_INCLUDE_DIR must point to a configured zenoh-pico include tree; \"\n          \"missing zenoh-pico/config.h in ${ZENOH_PICO_CONFIG_INCLUDE_DIR}\")\nendif()\n\nadd_library(mylinux_system STATIC \"${ZENOH_PICO_SOURCE_DIR}/src/system/unix/system.c\")\nset_target_properties(mylinux_system PROPERTIES\n                      POSITION_INDEPENDENT_CODE ON\n                      EXPORT_NAME system)\ntarget_include_directories(mylinux_system\n                           PUBLIC\n                             $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>\n                             $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\n                           PRIVATE\n                             \"${ZENOH_PICO_CONFIG_INCLUDE_DIR}\"\n                             \"${ZENOH_PICO_SOURCE_DIR}/include\")\ntarget_compile_definitions(mylinux_system\n                           PRIVATE\n                             ZENOH_MYLINUX\n                             ZP_SYSTEM_PLATFORM_HEADER=\\\"zenoh_mylinux_platform.h\\\")\n\nadd_library(mylinux_serial_uart STATIC \"${ZENOH_PICO_SOURCE_DIR}/src/link/transport/serial/tty_posix.c\")\nset_target_properties(mylinux_serial_uart PROPERTIES\n                      POSITION_INDEPENDENT_CODE ON\n                      EXPORT_NAME serial_uart)\ntarget_include_directories(mylinux_serial_uart\n                           PRIVATE\n                             \"${ZENOH_PICO_CONFIG_INCLUDE_DIR}\"\n                             \"${ZENOH_PICO_SOURCE_DIR}/include\"\n                             \"${CMAKE_CURRENT_LIST_DIR}/include\")\ntarget_compile_definitions(mylinux_serial_uart\n                           PRIVATE\n                             ZENOH_MYLINUX\n                             ZP_SYSTEM_PLATFORM_HEADER=\\\"zenoh_mylinux_platform.h\\\")\n\ninstall(TARGETS mylinux_system mylinux_serial_uart\n        EXPORT zenohpicoMylinuxTargets\n        ARCHIVE DESTINATION \"${CMAKE_INSTALL_LIBDIR}\")\ninstall(EXPORT zenohpicoMylinuxTargets\n        NAMESPACE mylinux::\n        DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/zenohpico-mylinux\")\ninstall(FILES \"${CMAKE_CURRENT_LIST_DIR}/include/zenoh_mylinux_platform.h\"\n        DESTINATION \"${CMAKE_INSTALL_INCLUDEDIR}\")\ninstall(FILES \"${CMAKE_CURRENT_LIST_DIR}/cmake/zenohpico-mylinuxConfig.cmake\"\n        DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/zenohpico-mylinux\")\ninstall(DIRECTORY \"${CMAKE_CURRENT_LIST_DIR}/cmake/platforms\"\n        DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/zenohpico-mylinux\")\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/README.md",
    "content": "# zenohpico-mylinux\n\nThis directory contains a full out-of-tree package example for Zenoh-Pico.\nIt exports:\n\n- `mylinux::system`\n- `mylinux::serial_uart`\n\nand provides:\n\n- `platforms/mylinux.cmake`\n\nThe example defines one `mylinux` platform profile. The profile sets one\n`ZP_PLATFORM_SOURCE_FILES` list with the reused POSIX network/TCP/UDP sources,\nadds the package include directory for `zenoh_mylinux_platform.h`, and links\nthe exported `mylinux::system` and `mylinux::serial_uart` targets through\n`ZP_PLATFORM_LINK_LIBRARIES`.\n\n## Package layout\n\n```text\nexamples/packages/zenohpico-mylinux/\n  CMakeLists.txt\n  include/\n    zenoh_mylinux_platform.h\n  cmake/\n    zenohpico-mylinuxConfig.cmake\n    platforms/\n      mylinux.cmake\n  consumer/\n    CMakeLists.txt\n    main.c\n```\n\n## What each file does\n\n- `CMakeLists.txt` builds and installs the exported package targets\n  `mylinux::system` and `mylinux::serial_uart`, and installs the custom\n  platform header.\n- `include/zenoh_mylinux_platform.h` defines the platform-specific types used\n  when `ZENOH_MYLINUX` is selected.\n- `cmake/zenohpico-mylinuxConfig.cmake` loads the exported targets file and\n  registers the package platform descriptor directory.\n- `cmake/platforms/mylinux.cmake` defines the `mylinux` platform profile with\n  `ZP_PLATFORM_*` variables.\n- `consumer/` is a minimal downstream project that uses an installed\n  `zenohpico::static`.\n\n## Build and install the package\n\nFrom the Zenoh-Pico source tree root:\n\n```bash\ncmake -S . -B /tmp/zenohpico-config \\\n  -DBUILD_EXAMPLES=OFF \\\n  -DBUILD_TESTING=OFF\ncmake -S examples/packages/zenohpico-mylinux -B /tmp/zenohpico-mylinux-pkg \\\n  -DZENOH_PICO_SOURCE_DIR=\"$PWD\" \\\n  -DZENOH_PICO_CONFIG_INCLUDE_DIR=/tmp/zenohpico-config/include\ncmake --build /tmp/zenohpico-mylinux-pkg -j\ncmake --install /tmp/zenohpico-mylinux-pkg --prefix /tmp/zenohpico-mylinux-prefix\n```\n\n## Build Zenoh-Pico with the package\n\n```bash\ncmake -S . -B /tmp/zenohpico-mylinux-build \\\n  -DBUILD_SHARED_LIBS=OFF \\\n  -DBUILD_TESTING=OFF \\\n  -DZP_EXTERNAL_PACKAGES=zenohpico-mylinux \\\n  -DCMAKE_PREFIX_PATH=/tmp/zenohpico-mylinux-prefix \\\n  -DZP_PLATFORM=mylinux\ncmake --build /tmp/zenohpico-mylinux-build -j --target zenohpico_static\ncmake --install /tmp/zenohpico-mylinux-build --prefix /tmp/zenohpico-install\n```\n\n## Build a downstream consumer\n\nAfter installing Zenoh-Pico itself, the `consumer/` subdirectory can be used as\na minimal downstream project:\n\n```bash\ncmake -S examples/packages/zenohpico-mylinux/consumer -B /tmp/zenohpico-mylinux-consumer \\\n  -DCMAKE_PREFIX_PATH=\"/tmp/zenohpico-install;/tmp/zenohpico-mylinux-prefix\"\ncmake --build /tmp/zenohpico-mylinux-consumer -j\n```\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/cmake/platforms/mylinux.cmake",
    "content": "set(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_MYLINUX)\nset(ZP_PLATFORM_SYSTEM_PLATFORM_HEADER \"zenoh_mylinux_platform.h\")\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/unix/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_posix.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_posix.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_posix.c\")\nendif()\nlist(APPEND ZP_PLATFORM_INCLUDE_DIRS\n     \"${CMAKE_CURRENT_LIST_DIR}/../../../../include\")\nlist(APPEND ZP_PLATFORM_LINK_LIBRARIES\n     mylinux::system\n     mylinux::serial_uart)\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/cmake/zenohpico-mylinuxConfig.cmake",
    "content": "include(\"${CMAKE_CURRENT_LIST_DIR}/zenohpicoMylinuxTargets.cmake\")\n\nif(COMMAND zp_add_platform_dir)\n  zp_add_platform_dir(\"${CMAKE_CURRENT_LIST_DIR}/platforms\")\nendif()\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/consumer/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.14)\nproject(zenohpico_mylinux_consumer LANGUAGES C)\n\nfind_package(zenohpico CONFIG REQUIRED)\n\nadd_executable(consumer main.c)\ntarget_link_libraries(consumer PRIVATE zenohpico::static)\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/consumer/main.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <zenoh-pico.h>\n\nint main(void) { return 0; }\n"
  },
  {
    "path": "examples/packages/zenohpico-mylinux/include/zenoh_mylinux_platform.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_EXAMPLES_MYLINUX_PLATFORM_H\n#define ZENOH_PICO_EXAMPLES_MYLINUX_PLATFORM_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <sys/time.h>\n#if Z_FEATURE_MULTI_THREAD == 1\n#include <pthread.h>\n#endif\n\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1\n#include <netdb.h>\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZP_PLATFORM_SOCKET_POSIX 1\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef pthread_t _z_task_t;\ntypedef pthread_attr_t z_task_attr_t;\ntypedef pthread_mutex_t _z_mutex_t;\ntypedef pthread_mutex_t _z_mutex_rec_t;\ntypedef pthread_cond_t _z_condvar_t;\ntypedef pthread_t _z_task_id_t;\n#endif\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1 || \\\n    Z_FEATURE_RAWETH_TRANSPORT == 1 || Z_FEATURE_LINK_SERIAL == 1\n        int _fd;\n#endif\n    };\n#if Z_FEATURE_LINK_TLS == 1\n    void *_tls_sock;\n#endif\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_EXAMPLES_MYLINUX_PLATFORM_H */\n"
  },
  {
    "path": "examples/platforms/myplatform.cmake",
    "content": "# Minimal one-file platform descriptor template.\n#\n# Copy this file to:\n#   - cmake/platforms/<name>.cmake for an in-tree platform profile, or\n#   - <package-config-dir>/platforms/<name>.cmake for an external package.\n#\n# Replace the paths and names below with the files and libraries from your\n# platform.\n\n# Minimal required\n\nset(ZP_PLATFORM_COMPILE_DEFINITIONS\n    ZENOH_MYPLATFORM)\n\nset(ZP_PLATFORM_SOURCE_FILES\n    \"${PROJECT_SOURCE_DIR}/src/system/myplatform/system.c\"\n    \"${PROJECT_SOURCE_DIR}/src/system/myplatform/network.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/tcp/tcp_myplatform.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_myplatform.c\"\n    \"${PROJECT_SOURCE_DIR}/src/link/transport/serial/uart_myplatform.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"${PROJECT_SOURCE_DIR}/src/link/transport/udp/udp_multicast_myplatform.c\")\nendif()\n\n# Optional, when the platform provides a BT transport implementation.\n# list(APPEND ZP_PLATFORM_SOURCE_FILES\n#      \"${PROJECT_SOURCE_DIR}/src/link/transport/bt/bt_myplatform.c\")\n\n# Optional\n\n# Only when the logical system-layer name differs from the profile name.\n# set(ZP_PLATFORM_SYSTEM_LAYER arduino_opencr)\n\n# Only when include/zenoh-pico/system/common/platform.h should include a\n# custom header instead of a built-in one.\n# set(ZP_PLATFORM_SYSTEM_PLATFORM_HEADER \"zenoh_myplatform_platform.h\")\n\n# list(APPEND ZP_PLATFORM_SOURCE_FILES\n#      \"${PROJECT_SOURCE_DIR}/src/system/myplatform/platform_extra.c\")\n# list(APPEND ZP_PLATFORM_INCLUDE_DIRS\n#      \"${PROJECT_SOURCE_DIR}/src/system/myplatform/include\")\n# list(APPEND ZP_PLATFORM_COMPILE_DEFINITIONS\n#      ZENOH_MYPLATFORM_BOARD)\n# list(APPEND ZP_PLATFORM_COMPILE_OPTIONS\n#      -Wall)\n# list(APPEND ZP_PLATFORM_LINK_LIBRARIES\n#      myplatform::sdk)\n"
  },
  {
    "path": "examples/rpi_pico/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\n\nset(PICO_BOARD \"pico_w\" CACHE STRING \"Raspberry Pi Pico board: pico, pico_w, pico2, pico2_w\")\n\nset(WIFI_SUPPORT_ENABLED 0)\nif(PICO_BOARD STREQUAL \"pico_w\" OR PICO_BOARD STREQUAL \"pico2_w\")\n  set(WIFI_SUPPORT_ENABLED 1)\nendif()\n\n# Set options\nset(WIFI_SSID \"\" CACHE STRING \"WiFi SSID\")\nset(WIFI_PASSWORD \"\" CACHE STRING \"WiFi Password\")\n\nset(ZENOH_CONFIG_MODE \"client\" CACHE STRING \"ZENOH_CONFIG_MODE\")\nset(ZENOH_CONFIG_CONNECT CACHE STRING \"ZENOH_CONFIG_CONNECT\")\nset(ZENOH_CONFIG_LISTEN CACHE STRING \"ZENOH_CONFIG_LISTEN\")\noption(ZENOH_USB_UART \"Enable USB UART\" OFF)\n\nmessage(STATUS \"PICO_BOARD: ${PICO_BOARD}\")\nmessage(STATUS \"WIFI_SSID: ${WIFI_SSID}\")\nif(WIFI_PASSWORD STREQUAL \"\")\n  message(STATUS \"WIFI_PASSWORD is empty\")\nelse()\n  message(STATUS \"WIFI_PASSWORD is set\")\nendif()\n\nmessage(STATUS \"ZENOH_CONFIG_MODE: ${ZENOH_CONFIG_MODE}\")\nmessage(STATUS \"ZENOH_CONFIG_CONNECT: ${ZENOH_CONFIG_CONNECT}\")\nmessage(STATUS \"ZENOH_CONFIG_LISTEN: ${ZENOH_CONFIG_LISTEN}\")\nmessage(STATUS \"ZENOH_USB_UART: ${ZENOH_USB_UART}\")\n\nconfigure_file(\n  \"${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in\"\n  \"${CMAKE_CURRENT_SOURCE_DIR}/include/config.h\"\n)\n\nset(CMAKE_C_STANDARD 11)\n\n# Include Raspberry Pi Pico SDK\nif(NOT DEFINED ENV{PICO_SDK_PATH})\n  message(FATAL_ERROR \"PICO_SDK_PATH environment variable is not set. Please set it to the location of the Pico SDK.\")\nendif()\ninclude($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)\n\n# Include FreeRTOS SDK\ninclude(FreeRTOS_Kernel_import.cmake)\n\n# Configure project\nproject(zenohpico_rpi_pico_examples C CXX ASM)\n\nif(WIFI_SUPPORT_ENABLED)\n  set(WIFI_LIB pico_cyw43_arch_lwip_sys_freertos)\nelse()\n  set(WIFI_LIB \"\")\nendif()\n\nif(ZENOH_USB_UART)\n  set(USB_LIBS \n    tinyusb_host\n    tinyusb_device\n    tinyusb_board\n  )\n  set(USB_INCLUDE \n    ${CMAKE_CURRENT_LIST_DIR}/include/tusb\n  )\nelse()\n  set(USB_LIBS \"\")\n  set(USB_INCLUDE \"\")\nendif()\n\nadd_compile_definitions(LWIP_TIMEVAL_PRIVATE=0)\npico_sdk_init()\n\n# Include Zenoh Pico library\ninclude(../../cmake/helpers.cmake)\nset_default_build_type(Release)\n\nif (NOT WIFI_SUPPORT_ENABLED)\n  declare_cache_var(Z_FEATURE_LINK_TCP 0 STRING \"TCP support\")\n  declare_cache_var(Z_FEATURE_LINK_UDP_MULTICAST 0 STRING \"UDP multicast support\")\n  declare_cache_var(Z_FEATURE_LINK_UDP_UNICAST 0 STRING \"UDP unicast support\")\n  declare_cache_var(Z_FEATURE_SCOUTING 0 STRING \"Scouting support\")\nendif()\n\ndeclare_cache_var(Z_FEATURE_LINK_SERIAL 1 STRING \"Serial support\")\nif(ZENOH_USB_UART)\n  declare_cache_var(Z_FEATURE_UNSTABLE_API 1 STRING \"Enable unstable API\")\n  declare_cache_var(Z_FEATURE_LINK_SERIAL_USB 1 STRING \"Serial USB support\")\nelse()\n  declare_cache_var(Z_FEATURE_LINK_SERIAL_USB 0 STRING \"Serial USB support\")\nendif()\n\nset(BUILD_SHARED_LIBS OFF)\nset(ZP_PLATFORM \"rpi_pico\" CACHE STRING \"Zenoh-Pico platform profile\")\n\nconfigure_include_project(ZENOHPICO zenohpico zenohpico::lib \"../..\" zenohpico \"https://github.com/eclipse-zenoh/zenoh-pico\" \"\")\n\ntarget_link_libraries(zenohpico_static\n  PRIVATE\n    hardware_uart\n    pico_stdlib\n    pico_rand\n    FreeRTOS-Kernel-Heap4\n    ${WIFI_LIB}\n    ${USB_LIBS}\n)\n\n# Configure build  \ntarget_include_directories(zenohpico_static PRIVATE \n  ${CMAKE_CURRENT_LIST_DIR}\n  ${CMAKE_CURRENT_LIST_DIR}/include\n  ${USB_INCLUDE} \n)\n\nadd_library(main STATIC main.c)\n\ntarget_include_directories(main PRIVATE \n  ${CMAKE_CURRENT_LIST_DIR}\n  ${CMAKE_CURRENT_LIST_DIR}/include\n)\ntarget_link_libraries(main\n  pico_stdlib\n  pico_rand\n  FreeRTOS-Kernel-Heap4\n  ${WIFI_LIB} \n)\n\nfunction(add_example name)\n  add_executable(${name} ${name}.c)\n  target_link_libraries(${name}\n    main\n    hardware_uart \n    pico_stdlib\n    pico_rand\n    FreeRTOS-Kernel-Heap4\n    zenohpico::lib\n    ${WIFI_LIB} \n    ${USB_LIBS} \n  )\n  target_include_directories(${name} PRIVATE \n    ${CMAKE_CURRENT_LIST_DIR}\n    ${CMAKE_CURRENT_LIST_DIR}/include\n    ${USB_INCLUDE} \n  )\n  if(ZENOH_USB_UART)\n    pico_enable_stdio_uart(${name} 1)\n    pico_enable_stdio_usb(${name} 0)\n  else()\n    pico_enable_stdio_uart(${name} 0)\n    pico_enable_stdio_usb(${name} 1)\n  endif()\n  pico_add_extra_outputs(${name})\nendfunction()\n\nadd_example(z_get)\nadd_example(z_pub)\nadd_example(z_pub_st)\nadd_example(z_pub_thr)\nadd_example(z_pull)\nadd_example(z_put)\nadd_example(z_queryable)\nadd_example(z_scout)\nadd_example(z_sub)\nadd_example(z_sub_st)\nadd_example(z_sub_thr)\n"
  },
  {
    "path": "examples/rpi_pico/FreeRTOS_Kernel_import.cmake",
    "content": "# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake\n\n# This can be dropped into an external project to help locate the FreeRTOS kernel\n# It should be include()ed prior to project(). Alternatively this file may\n# or the CMakeLists.txt in this directory may be included or added via add_subdirectory\n# respectively.\n\nif (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))\n    set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})\n    message(\"Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')\")\nendif ()\n\n# first pass we look in old tree; second pass we look in new tree\nforeach(SEARCH_PASS RANGE 0 1)\n    if (SEARCH_PASS)\n        # ports may be moving to submodule in the future\n        set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH \"portable/ThirdParty/Community-Supported-Ports/GCC\")\n        set(FREERTOS_KERNEL_RP2040_BACK_PATH \"../../../../..\")\n    else()\n        set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH \"portable/ThirdParty/GCC\")\n        set(FREERTOS_KERNEL_RP2040_BACK_PATH \"../../../..\")\n    endif()\n\n    if(PICO_PLATFORM STREQUAL \"rp2040\")\n        set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH \"${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2040\")\n    else()\n        if (PICO_PLATFORM STREQUAL \"rp2350-riscv\")\n            set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH \"${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_RISC-V\")\n        else()\n            set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH \"${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_ARM_NTZ\")\n        endif()\n    endif()\n\n    if (NOT FREERTOS_KERNEL_PATH)\n        # check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)\n        get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)\n        get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)\n        if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)\n            get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)\n        endif()\n        if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)\n            get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)\n            message(\"Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake\")\n            break()\n        elseif (PICO_SDK_PATH AND EXISTS \"${PICO_SDK_PATH}/../FreeRTOS-Kernel\")\n            set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)\n            message(\"Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}\")\n            break()\n        endif()\n    endif ()\n\n    if (NOT FREERTOS_KERNEL_PATH)\n        foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)\n            # check if FreeRTOS-Kernel exists under directory that included us\n            set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})\n            get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)\n            if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)\n                get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)\n                message(\"Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project\")\n                break()\n            endif()\n        endforeach()\n        if (FREERTOS_KERNEL_PATH)\n            break()\n        endif()\n    endif()\n\n    # user must have specified\n    if (FREERTOS_KERNEL_PATH)\n        if (EXISTS \"${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}\")\n            break()\n        endif()\n    endif()\nendforeach ()\n\nif (NOT FREERTOS_KERNEL_PATH)\n    message(FATAL_ERROR \"FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.\")\nendif()\n\nset(FREERTOS_KERNEL_PATH \"${FREERTOS_KERNEL_PATH}\" CACHE PATH \"Path to the FreeRTOS Kernel\")\n\nget_filename_component(FREERTOS_KERNEL_PATH \"${FREERTOS_KERNEL_PATH}\" REALPATH BASE_DIR \"${CMAKE_BINARY_DIR}\")\nif (NOT EXISTS ${FREERTOS_KERNEL_PATH})\n    message(FATAL_ERROR \"Directory '${FREERTOS_KERNEL_PATH}' not found\")\nendif()\nif (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)\n    message(FATAL_ERROR \"Directory '${FREERTOS_KERNEL_PATH}' does not contain a '${PICO_PLATFORM}' port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}\")\nendif()\nset(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH \"Path to the FreeRTOS_KERNEL\" FORCE)\n\nadd_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)\n"
  },
  {
    "path": "examples/rpi_pico/include/FreeRTOSConfig.h",
    "content": "/*\n * FreeRTOS V202111.00\n * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\n * this software and associated documentation files (the \"Software\"), to deal in\n * the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n * the Software, and to permit persons to whom the Software is furnished to do so,\n * subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * http://www.FreeRTOS.org\n * http://aws.amazon.com/freertos\n *\n * 1 tab == 4 spaces!\n */\n\n#ifndef FREERTOS_CONFIG_EXAMPLES_COMMON_H\n#define FREERTOS_CONFIG_EXAMPLES_COMMON_H\n\n/*-----------------------------------------------------------\n * Application specific definitions.\n *\n * These definitions should be adjusted for your particular hardware and\n * application requirements.\n *\n * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE\n * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.\n *\n * See http://www.freertos.org/a00110.html\n *----------------------------------------------------------*/\n\n/* Scheduler Related */\n#define configUSE_PREEMPTION 1\n#define configUSE_TICKLESS_IDLE 0\n#define configUSE_IDLE_HOOK 0\n#define configUSE_TICK_HOOK 0\n#define configTICK_RATE_HZ ((TickType_t)1000)\n#define configMAX_PRIORITIES 32\n#define configMINIMAL_STACK_SIZE (configSTACK_DEPTH_TYPE)512\n#define configUSE_16_BIT_TICKS 0\n\n#define configIDLE_SHOULD_YIELD 1\n\n/* Synchronization Related */\n#define configUSE_MUTEXES 1\n#define configUSE_RECURSIVE_MUTEXES 1\n#define configUSE_APPLICATION_TASK_TAG 0\n#define configUSE_COUNTING_SEMAPHORES 1\n#define configQUEUE_REGISTRY_SIZE 8\n#define configUSE_QUEUE_SETS 1\n#define configUSE_TIME_SLICING 1\n#define configUSE_NEWLIB_REENTRANT 0\n// todo need this for lwip FreeRTOS sys_arch to compile\n#define configENABLE_BACKWARD_COMPATIBILITY 1\n#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5\n\n/* System */\n#define configSTACK_DEPTH_TYPE uint32_t\n#define configMESSAGE_BUFFER_LENGTH_TYPE size_t\n\n/* Memory allocation related definitions. */\n#define configSUPPORT_STATIC_ALLOCATION 0\n#define configSUPPORT_DYNAMIC_ALLOCATION 1\n#define configTOTAL_HEAP_SIZE (128 * 1024)\n#define configAPPLICATION_ALLOCATED_HEAP 0\n\n/* Hook function related definitions. */\n#define configCHECK_FOR_STACK_OVERFLOW 0\n#define configUSE_MALLOC_FAILED_HOOK 0\n#define configUSE_DAEMON_TASK_STARTUP_HOOK 0\n\n/* Run time and task stats gathering related definitions. */\n#define configGENERATE_RUN_TIME_STATS 0\n#define configUSE_TRACE_FACILITY 1\n#define configUSE_STATS_FORMATTING_FUNCTIONS 0\n\n/* Co-routine related definitions. */\n#define configUSE_CO_ROUTINES 0\n#define configMAX_CO_ROUTINE_PRIORITIES 1\n\n/* Software timer related definitions. */\n#define configUSE_TIMERS 1\n#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)\n#define configTIMER_QUEUE_LENGTH 10\n#define configTIMER_TASK_STACK_DEPTH 1024\n\n/* Interrupt nesting behaviour configuration. */\n/*\n#define configKERNEL_INTERRUPT_PRIORITY         [dependent of processor]\n#define configMAX_SYSCALL_INTERRUPT_PRIORITY    [dependent on processor and application]\n#define configMAX_API_CALL_INTERRUPT_PRIORITY   [dependent on processor and application]\n*/\n\n#define configNUMBER_OF_CORES 2\n/* SMP (configNUMBER_OF_CORES > 1) only */\n#define configTICK_CORE 0\n#define configRUN_MULTIPLE_PRIORITIES 1\n#if configNUMBER_OF_CORES > 1\n#define configUSE_CORE_AFFINITY 1\n#endif\n#define configUSE_PASSIVE_IDLE_HOOK 0\n\n/* Armv8-M */\n\n/* Not currently supported */\n#define configENABLE_MPU 0\n// #define configSYSTEM_CALL_STACK_SIZE            ( configSTACK_DEPTH_TYPE ) 512\n#define configENABLE_FPU 1\n/* Not currently supported */\n#define configENABLE_TRUSTZONE 0\n#define configRUN_FREERTOS_SECURE_ONLY 1\n// see https://www.freertos.org/RTOS-Cortex-M3-M4.html\n#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16\n\n/* RP2xxx specific */\n#define configSUPPORT_PICO_SYNC_INTEROP 1\n#define configSUPPORT_PICO_TIME_INTEROP 1\n\n#include <assert.h>\n/* Define to trap errors during development. */\n#define configASSERT(x) assert(x)\n\n/* Set the following definitions to 1 to include the API function, or zero\nto exclude the API function. */\n#define INCLUDE_vTaskPrioritySet 1\n#define INCLUDE_uxTaskPriorityGet 1\n#define INCLUDE_vTaskDelete 1\n#define INCLUDE_vTaskSuspend 1\n#define INCLUDE_vTaskDelayUntil 1\n#define INCLUDE_vTaskDelay 1\n#define INCLUDE_xTaskGetSchedulerState 1\n#define INCLUDE_xTaskGetCurrentTaskHandle 1\n#define INCLUDE_uxTaskGetStackHighWaterMark 1\n#define INCLUDE_xTaskGetIdleTaskHandle 1\n#define INCLUDE_eTaskGetState 1\n#define INCLUDE_xTimerPendFunctionCall 1\n#define INCLUDE_xTaskAbortDelay 1\n#define INCLUDE_xTaskGetHandle 1\n#define INCLUDE_xTaskResumeFromISR 1\n#define INCLUDE_xQueueGetMutexHolder 1\n\n/* A header file that defines trace macro can be included here. */\n\n#endif /* FREERTOS_CONFIG_H */\n"
  },
  {
    "path": "examples/rpi_pico/include/config.h.in",
    "content": "#ifndef CONFIG_H\n#define CONFIG_H\n\n#define WIFI_SUPPORT_ENABLED @WIFI_SUPPORT_ENABLED@\n#define WIFI_SSID \"@WIFI_SSID@\"\n#define WIFI_PASSWORD \"@WIFI_PASSWORD@\"\n#define ZENOH_CONFIG_MODE \"@ZENOH_CONFIG_MODE@\"\n#define ZENOH_CONFIG_CONNECT \"@ZENOH_CONFIG_CONNECT@\"\n#define ZENOH_CONFIG_LISTEN \"@ZENOH_CONFIG_LISTEN@\"\n\n#endif // CONFIG_H\n"
  },
  {
    "path": "examples/rpi_pico/include/lwipopts.h",
    "content": "#ifndef _LWIPOPTS_H\n#define _LWIPOPTS_H\n\n// Common settings used in most of the pico_w examples\n// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)\n\n#define NO_SYS 0\n#define LWIP_SOCKET 1\n#if PICO_CYW43_ARCH_POLL\n#define MEM_LIBC_MALLOC 1\n#else\n// MEM_LIBC_MALLOC is incompatible with non polling versions\n#define MEM_LIBC_MALLOC 0\n#endif\n#define MEM_ALIGNMENT 4\n#define MEM_SIZE 4000\n#define MEMP_NUM_TCP_SEG 64\n#define MEMP_NUM_ARP_QUEUE 20\n#define PBUF_POOL_SIZE 24\n#define LWIP_ARP 1\n#define LWIP_ETHERNET 1\n#define LWIP_ICMP 1\n#define LWIP_RAW 1\n#define TCP_WND (16 * TCP_MSS)\n#define TCP_MSS 1460\n#define TCP_SND_BUF (16 * TCP_MSS)\n#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))\n#define LWIP_NETIF_STATUS_CALLBACK 1\n#define LWIP_NETIF_LINK_CALLBACK 1\n#define LWIP_NETIF_HOSTNAME 1\n#define LWIP_NETCONN 0\n#define MEM_STATS 0\n#define SYS_STATS 0\n#define MEMP_STATS 0\n#define LINK_STATS 0\n// #define ETH_PAD_SIZE                2\n#define LWIP_CHKSUM_ALGORITHM 3\n#define LWIP_DHCP 1\n#define LWIP_IPV4 1\n#define LWIP_TCP 1\n#define LWIP_UDP 1\n#define LWIP_DNS 1\n#define LWIP_IGMP 1\n#define LWIP_TCP_KEEPALIVE 1\n#define LWIP_NETIF_TX_SINGLE_PBUF 1\n#define DHCP_DOES_ARP_CHECK 0\n#define LWIP_DHCP_DOES_ACD_CHECK 0\n#define LWIP_SOCKET_POLL 0\n#define LWIP_MULTICAST_TX_OPTIONS 1\n\n#ifndef NDEBUG\n#define LWIP_DEBUG 1\n#define LWIP_STATS 1\n#define LWIP_STATS_DISPLAY 1\n#define LWIP_FREERTOS_CHECK_CORE_LOCKING 1\n#define LWIP_TCPIP_CORE_LOCKING 1\n#define LWIP_TCPIP_CORE_LOCKING_INPUT 1\n#endif\n\n#define ETHARP_DEBUG LWIP_DBG_OFF\n#define NETIF_DEBUG LWIP_DBG_OFF\n#define PBUF_DEBUG LWIP_DBG_OFF\n#define API_LIB_DEBUG LWIP_DBG_OFF\n#define API_MSG_DEBUG LWIP_DBG_OFF\n#define SOCKETS_DEBUG LWIP_DBG_OFF\n#define ICMP_DEBUG LWIP_DBG_OFF\n#define INET_DEBUG LWIP_DBG_OFF\n#define IP_DEBUG LWIP_DBG_OFF\n#define IP_REASS_DEBUG LWIP_DBG_OFF\n#define RAW_DEBUG LWIP_DBG_OFF\n#define MEM_DEBUG LWIP_DBG_OFF\n#define MEMP_DEBUG LWIP_DBG_OFF\n#define SYS_DEBUG LWIP_DBG_OFF\n#define TCP_DEBUG LWIP_DBG_OFF\n#define TCP_INPUT_DEBUG LWIP_DBG_OFF\n#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF\n#define TCP_RTO_DEBUG LWIP_DBG_OFF\n#define TCP_CWND_DEBUG LWIP_DBG_OFF\n#define TCP_WND_DEBUG LWIP_DBG_OFF\n#define TCP_FR_DEBUG LWIP_DBG_OFF\n#define TCP_QLEN_DEBUG LWIP_DBG_OFF\n#define TCP_RST_DEBUG LWIP_DBG_OFF\n#define UDP_DEBUG LWIP_DBG_OFF\n#define TCPIP_DEBUG LWIP_DBG_OFF\n#define PPP_DEBUG LWIP_DBG_OFF\n#define SLIP_DEBUG LWIP_DBG_OFF\n#define DHCP_DEBUG LWIP_DBG_OFF\n\n#define TCP_LISTEN_BACKLOG 1\n#define TCPIP_THREAD_STACKSIZE 2048\n#define DEFAULT_THREAD_STACKSIZE 2048\n#define DEFAULT_RAW_RECVMBOX_SIZE 16\n#define DEFAULT_UDP_RECVMBOX_SIZE 16\n#define DEFAULT_TCP_RECVMBOX_SIZE 16\n#define DEFAULT_ACCEPTMBOX_SIZE 16\n#define TCPIP_MBOX_SIZE 16\n#define LWIP_TIMEVAL_PRIVATE 0\n\n#define LWIP_SO_RCVTIMEO 1\n#define LWIP_SO_SNDTIMEO 1\n#define LWIP_SO_LINGER 1\n\n#endif /* __LWIPOPTS_H__ */\n"
  },
  {
    "path": "examples/rpi_pico/include/tusb/tusb_config.h",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\n#ifndef _TUSB_CONFIG_H_\n#define _TUSB_CONFIG_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//--------------------------------------------------------------------+\n// Board Specific Configuration\n//--------------------------------------------------------------------+\n\n// RHPort number used for device can be defined by board.mk, default to port 0\n#ifndef BOARD_TUD_RHPORT\n#define BOARD_TUD_RHPORT 0\n#endif\n\n// RHPort max operational speed can defined by board.mk\n#ifndef BOARD_TUD_MAX_SPEED\n#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED\n#endif\n\n//--------------------------------------------------------------------\n// COMMON CONFIGURATION\n//--------------------------------------------------------------------\n\n// defined by board.mk\n#ifndef CFG_TUSB_MCU\n#error CFG_TUSB_MCU must be defined\n#endif\n\n#ifndef CFG_TUSB_OS\n#define CFG_TUSB_OS OPT_OS_NONE\n#endif\n\n#ifndef CFG_TUSB_DEBUG\n#define CFG_TUSB_DEBUG 0\n#endif\n\n// Enable Device stack\n#define CFG_TUD_ENABLED 1\n\n// Default is max speed that hardware controller could support with on-chip PHY\n#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED\n\n/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.\n * Tinyusb use follows macros to declare transferring memory so that they can be put\n * into those specific section.\n * e.g\n * - CFG_TUSB_MEM SECTION : __attribute__ (( section(\".usb_ram\") ))\n * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))\n */\n#ifndef CFG_TUSB_MEM_SECTION\n#define CFG_TUSB_MEM_SECTION\n#endif\n\n#ifndef CFG_TUSB_MEM_ALIGN\n#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))\n#endif\n\n//--------------------------------------------------------------------\n// DEVICE CONFIGURATION\n//--------------------------------------------------------------------\n\n#ifndef CFG_TUD_ENDPOINT0_SIZE\n#define CFG_TUD_ENDPOINT0_SIZE 64\n#endif\n\n//------------- CLASS -------------//\n#define CFG_TUD_CDC 2\n#define CFG_TUD_MSC 0\n#define CFG_TUD_HID 0\n#define CFG_TUD_MIDI 0\n#define CFG_TUD_VENDOR 0\n\n// CDC FIFO size of TX and RX\n#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)\n#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)\n\n// CDC Endpoint transfer buffer size, more is faster\n#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _TUSB_CONFIG_H_ */\n"
  },
  {
    "path": "examples/rpi_pico/main.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n\n#include \"FreeRTOS.h\"\n#include \"config.h\"\n\n#if WIFI_SUPPORT_ENABLED\n#include \"pico/cyw43_arch.h\"\n#endif\n\n#include \"pico/stdlib.h\"\n#include \"task.h\"\n\n#define TASK_PRIORITY (tskIDLE_PRIORITY + 2UL)\n#define WIFI_TIMEOUT 30000\n\nint app_main();\n\n#if WIFI_SUPPORT_ENABLED\nvoid print_ip_address() {\n    struct netif *netif = &cyw43_state.netif[CYW43_ITF_STA];\n    if (netif_is_up(netif)) {\n        printf(\"IP Address: %s\\n\", ip4addr_ntoa(netif_ip4_addr(netif)));\n        printf(\"Netmask: %s\\n\", ip4addr_ntoa(netif_ip4_netmask(netif)));\n        printf(\"Gateway: %s\\n\", ip4addr_ntoa(netif_ip4_gw(netif)));\n    } else {\n        printf(\"Network interface is down.\\n\");\n    }\n}\n#endif\n\nvoid main_task(void *params) {\n    (void)params;\n#ifndef NDEBUG\n    vTaskDelay(pdMS_TO_TICKS(3000));\n#endif\n\n#if WIFI_SUPPORT_ENABLED\n    if (cyw43_arch_init()) {\n        printf(\"Failed to initialise\\n\");\n        return;\n    }\n\n    if (strlen(WIFI_SSID) != 0) {\n        cyw43_arch_enable_sta_mode();\n        printf(\"Connecting to Wi-Fi...\\n\");\n        if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, WIFI_TIMEOUT) == 0) {\n            printf(\"Wi-Fi connected.\\n\");\n            print_ip_address();\n            app_main();\n        } else {\n            printf(\"Failed to connect Wi-Fi\\n\");\n        }\n    } else {\n        printf(\"Offline mode\\n\");\n        app_main();\n    }\n#else\n    app_main();\n#endif\n\n    printf(\"Terminate.\\n\");\n\n#if WIFI_SUPPORT_ENABLED\n    cyw43_arch_deinit();\n#endif\n\n    vTaskDelete(NULL);\n}\n\nint main(void) {\n    stdio_init_all();\n\n    xTaskCreate(main_task, \"MainThread\", configMINIMAL_STACK_SIZE * 16, NULL, TASK_PRIORITY, NULL);\n\n    vTaskStartScheduler();\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/rpi_pico/z_get.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_QUERY == 1\n\n#define KEYEXPR \"demo/example/**\"\n#define VALUE \"\"\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    printf(\">> Received query final notification\\n\");\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n               (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n        z_drop(z_move(replystr));\n    } else {\n        printf(\">> Received an error\\n\");\n    }\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, KEYEXPR) < 0) {\n        printf(\"%s is not a valid key expression\\n\", KEYEXPR);\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(5);\n        printf(\"Sending Query '%s'...\\n\", KEYEXPR);\n        z_get_options_t opts;\n        z_get_options_default(&opts);\n        // Value encoding\n        z_owned_bytes_t payload;\n        if (strcmp(VALUE, \"\") != 0) {\n            z_bytes_from_static_str(&payload, VALUE);\n            opts.payload = z_move(payload);\n        }\n        z_owned_closure_reply_t callback;\n        z_closure(&callback, reply_handler, reply_dropper, NULL);\n        if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n            printf(\"Unable to send query.\\n\");\n            return;\n        }\n    }\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_pub.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_PUBLICATION == 1\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[RPI] Pub from Zenoh-Pico!\"\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", KEYEXPR);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return;\n    }\n\n    // Publish data\n    char buf[256];\n    for (int idx = 0; 1; ++idx) {\n        z_sleep_s(1);\n        snprintf(buf, 256, \"[%4d] %s\", idx, VALUE);\n        printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put_options_t options;\n        z_publisher_put_options_default(&options);\n        z_publisher_put(z_loan(pub), z_move(payload), &options);\n    }\n\n    // Clean-up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_pub_st.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 0\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[RPI] Pub from Zenoh-Pico!\"\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", KEYEXPR);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return;\n    }\n\n    char *buf = (char *)pvPortMalloc(256);\n    z_clock_t now = z_clock_now();\n    for (int idx = 0;; ++idx) {\n        if (z_clock_elapsed_ms(&now) > 1000) {\n            snprintf(buf, 256, \"[%4d] %s\", idx, VALUE);\n            printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_copy_from_str(&payload, buf);\n\n            z_publisher_put(z_loan(pub), z_move(payload), NULL);\n            ++idx;\n\n            now = z_clock_now();\n        }\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n\n    z_drop(z_move(pub));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_PUBLICATION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_pub_thr.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_PUBLICATION == 1\n\n#define KEYEXPR \"test/thr\"\n#define PAYLOAD_SIZE 8\n\nvoid z_free_with_context(void *ptr, void *context) {\n    (void)context;\n    z_free(ptr);\n}\n\nvoid app_main(void) {\n    uint8_t *value = (uint8_t *)z_malloc(PAYLOAD_SIZE);\n    memset(value, 1, PAYLOAD_SIZE);\n\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    // Declare publisher\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return;\n    }\n\n    printf(\"Send packets\\n\");\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, value, PAYLOAD_SIZE, z_free_with_context, NULL);\n    while (1) {\n        // Clone payload\n        z_owned_bytes_t p;\n        z_bytes_clone(&p, z_loan(payload));\n        z_publisher_put(z_loan(pub), z_move(p), NULL);\n    }\n\n    // Clean-up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    z_drop(z_move(payload));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_pull.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\n#define KEYEXPR \"demo/example/**\"\n\nconst size_t INTERVAL = 5000;\nconst size_t SIZE = 3;\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, SIZE);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", INTERVAL, SIZE);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &sample); res == Z_OK; res = z_try_recv(z_loan(handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n            z_drop(z_move(value));\n            z_drop(z_move(sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", INTERVAL);\n            z_sleep_ms(INTERVAL);\n        } else {\n            break;\n        }\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_put.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_PUBLICATION == 1\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[RPI] Pub from Zenoh-Pico!\"\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    printf(\"Declaring key expression '%s'...\\n\", KEYEXPR);\n    z_owned_keyexpr_t ke;\n    z_view_keyexpr_t vke;\n    z_view_keyexpr_from_str_unchecked(&vke, KEYEXPR);\n    if (z_declare_keyexpr(z_loan(s), &ke, z_loan(vke)) < 0) {\n        printf(\"Unable to declare key expression!\\n\");\n        z_drop(z_move(s));\n        return;\n    }\n\n    printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, VALUE);\n    z_put_options_t options;\n    z_put_options_default(&options);\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, VALUE);\n\n    if (z_put(z_loan(s), z_loan(ke), z_move(payload), &options) < 0) {\n        printf(\"Oh no! Put has failed...\\n\");\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    // Clean up\n    z_undeclare_keyexpr(z_loan(s), z_move(ke));\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_queryable.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_QUERYABLE == 1\n\n#define KEYEXPR \"demo/example/zenoh-pico-queryable\"\n#define VALUE \"[RPI] Queryable from Zenoh-Pico!\"\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n\n    z_query_reply_options_t options;\n    z_query_reply_options_default(&options);\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, VALUE);\n\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), &options);\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, KEYEXPR) < 0) {\n        printf(\"%s is not a valid key expression\\n\", KEYEXPR);\n        return;\n    }\n\n    printf(\"Creating Queryable on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_scout.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_SCOUTING == 1\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_loan(s)), z_string_data(z_loan(s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    z_free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nvoid app_main(void) {\n    int *context = (int *)z_malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_move(config), z_move(closure), NULL);\n    while (1) {\n        z_sleep_s(1);\n    }\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_sub.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\n#define KEYEXPR \"demo/example/**\"\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    // Clean-up\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_sub_st.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_MULTI_THREAD == 0\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[RPI] Pub from Zenoh-Pico!\"\nint msg_nb = 0;\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    msg_nb++;\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    while (true) {\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_SUBSCRIPTION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/rpi_pico/z_sub_thr.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#include \"config.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\n#define KEYEXPR \"test/thr\"\n\n#define PACKET_NB 1000000\n\ntypedef struct {\n    volatile unsigned long count;\n    volatile unsigned long finished_rounds;\n    z_clock_t start;\n    z_clock_t first_start;\n} z_stats_t;\n\nz_stats_t *z_stats_make(void) {\n    z_stats_t *stats = malloc(sizeof(z_stats_t));\n    stats->count = 0;\n    stats->finished_rounds = 0;\n    stats->first_start.tv_nsec = 0;\n    return stats;\n}\n\nvoid on_sample(z_loaned_sample_t *sample, void *context) {\n    (void)sample;\n    z_stats_t *stats = (z_stats_t *)context;\n    stats->count++;\n    // Start set measurement\n    if (stats->count == 1) {\n        stats->start = z_clock_now();\n        if (stats->first_start.tv_nsec == 0) {\n            stats->first_start = stats->start;\n        }\n    } else if (stats->count >= PACKET_NB) {\n        // Stop set measurement\n        stats->finished_rounds++;\n        unsigned long elapsed_ms = z_clock_elapsed_ms(&stats->start);\n        printf(\"%f msg/s\\n\", (double)(PACKET_NB * 1000) / (double)elapsed_ms);\n        stats->count = 0;\n    }\n}\n\nvoid drop_stats(void *context) {\n    z_stats_t *stats = (z_stats_t *)context;\n    unsigned long elapsed_ms = z_clock_elapsed_ms(&stats->first_start);\n    const unsigned long sent_messages = PACKET_NB * stats->finished_rounds + stats->count;\n    printf(\"Stats after unsubscribing: received %ld messages over %lu miliseconds (%.1f msg/s)\\n\", sent_messages,\n           elapsed_ms, (double)(sent_messages * 1000) / (double)elapsed_ms);\n    free(context);\n}\n\nvoid app_main(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, ZENOH_CONFIG_MODE);\n    if (strcmp(ZENOH_CONFIG_CONNECT, \"\") != 0) {\n        printf(\"Connect endpoint: %s\\n\", ZENOH_CONFIG_CONNECT);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, ZENOH_CONFIG_CONNECT);\n    }\n    if (strcmp(ZENOH_CONFIG_LISTEN, \"\") != 0) {\n        printf(\"Listen endpoint: %s\\n\", ZENOH_CONFIG_LISTEN);\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, ZENOH_CONFIG_LISTEN);\n    }\n\n    printf(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return;\n    }\n\n    // Declare Subscriber/resource\n    z_stats_t *context = z_stats_make();\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, on_sample, drop_stats, (void *)context);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_background_subscriber(z_loan(s), z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return;\n    }\n\n    while (1) {\n        z_sleep_s(1);\n    }\n\n    // Clean-up\n    z_drop(z_move(s));\n}\n#else\nvoid app_main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n}\n#endif\n"
  },
  {
    "path": "examples/threadx_stm32/z_pub.c",
    "content": "/**\r\n ******************************************************************************\r\n * @file    z_pub.c\r\n * @brief   Example zenoh-pico publisher on STM32 running ThreadX\r\n\r\n ******************************************************************************\r\n */\r\n\r\n#include <stdio.h>\r\n\r\n#include \"app_threadx.h\"\r\n#include \"zenoh-pico.h\"\r\n\r\n#define MODE \"client\"\r\n#define LOCATOR \"serial/Serial\"\r\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\r\n#define VALUE \"[STM32 THREADX] Pub from Zenoh-Pico!\"\r\n#define LOGGING 0\r\n\r\n#if LOGGING == 1\r\n#define _LOG(...) printf(__VA_ARGS__)\r\n#else\r\n#define _LOG(...)\r\n#endif\r\n\r\n/* Pointer used by system.c implementation to allocate from pool*/\r\nTX_BYTE_POOL* pthreadx_byte_pool;\r\nVOID start_example_thread(ULONG initial_input) {\r\n    z_owned_config_t config;\r\n    z_owned_session_t s;\r\n    z_result_t r = _Z_ERR_GENERIC;\r\n    while (r != Z_OK) {\r\n        // Wait until router is started\r\n        z_config_default(&config);\r\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\r\n        if (strcmp(MODE, \"client\") == 0) {\r\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\r\n        } else {\r\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\r\n        }\r\n\r\n        _LOG(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\r\n        if ((r = z_open(&s, z_move(config), NULL)) < 0) {\r\n            _LOG(\"Unable to open session!\\n\");\r\n        }\r\n    }\r\n\r\n    _LOG(\"Declaring publisher for '%s'...\\n\", KEYEXPR);\r\n    z_owned_publisher_t pub;\r\n    z_view_keyexpr_t ke;\r\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\r\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\r\n        _LOG(\"Unable to declare publisher for key expression!\\n\");\r\n        return;\r\n    }\r\n\r\n    // Publish data\r\n    while (1) {\r\n        char buf[256];\r\n        for (int idx = 0; 1; ++idx) {\r\n            z_sleep_s(1);\r\n            snprintf(buf, 256, \"[%4d] %s\", idx, VALUE);\r\n            _LOG(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\r\n\r\n            // Create payload\r\n            z_owned_bytes_t payload;\r\n            z_bytes_copy_from_str(&payload, buf);\r\n\r\n            z_publisher_put_options_t options;\r\n            z_publisher_put_options_default(&options);\r\n            z_publisher_put(z_loan(pub), z_move(payload), &options);\r\n        }\r\n    }\r\n    // Clean-up\r\n    z_drop(z_move(pub));\r\n    z_drop(z_move(s));\r\n}\r\n\r\nTX_THREAD example_thread;\r\nUINT App_ThreadX_Init(VOID* memory_ptr) {\r\n    UINT ret = TX_SUCCESS;\r\n    TX_BYTE_POOL* byte_pool = (TX_BYTE_POOL*)memory_ptr;\r\n\r\n    pthreadx_byte_pool = (TX_BYTE_POOL*)memory_ptr;\r\n    void* pointer;\r\n\r\n    /* Allocate the stack for the serial thread.  */\r\n    tx_byte_allocate(byte_pool, &pointer, 4096, TX_NO_WAIT);\r\n    /* Create the serial thread.  */\r\n    tx_thread_create(&example_thread, \"Zenoh-Pico-Example\", start_example_thread, 0, pointer, 4096, 15, 15,\r\n                     TX_NO_TIME_SLICE, TX_AUTO_START);\r\n\r\n    return ret;\r\n}\r\n\r\nvoid MX_ThreadX_Init(void) { tx_kernel_enter(); }\r\n"
  },
  {
    "path": "examples/threadx_stm32/z_sub.c",
    "content": "/**\r\n ******************************************************************************\r\n * @file    z_sub.c\r\n * @brief   Example zenoh-pico subscriber on STM32 running ThreadX\r\n ******************************************************************************\r\n */\r\n\r\n#include <stdio.h>\r\n\r\n#include \"app_threadx.h\"\r\n#include \"zenoh-pico.h\"\r\n\r\n#define MODE \"client\"\r\n#define LOCATOR \"serial/Serial\"\r\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\r\n#define LOGGING 0\r\n\r\n#if LOGGING == 1\r\n#define _LOG(...) printf(__VA_ARGS__)\r\n#else\r\n#define _LOG(...)\r\n#endif\r\n\r\n/* Pointer used by system.c implementation to allocate from pool*/\r\nTX_BYTE_POOL *pthreadx_byte_pool;\r\n\r\nint msg_nb = 0;\r\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\r\n    (void)(ctx);\r\n    z_view_string_t keystr;\r\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\r\n    z_owned_string_t value;\r\n    z_bytes_to_string(z_sample_payload(sample), &value);\r\n    _LOG(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\r\n         z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\r\n    z_drop(z_move(value));\r\n    msg_nb++;\r\n}\r\n\r\nVOID start_example_thread(ULONG initial_input) {\r\n    z_result_t r = _Z_ERR_GENERIC;\r\n    z_owned_session_t s;\r\n    z_owned_config_t config;\r\n\r\n    while (r != Z_OK) {\r\n        // Wait until router is started\r\n        z_config_default(&config);\r\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\r\n        if (strcmp(MODE, \"client\") == 0) {\r\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\r\n        } else {\r\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\r\n        }\r\n\r\n        _LOG(\"Opening %s session ...\\n\", ZENOH_CONFIG_MODE);\r\n        if ((r = z_open(&s, z_move(config), NULL)) < 0) {\r\n            _LOG(\"Unable to open session!\\n\");\r\n        }\r\n    }\r\n\r\n    z_owned_closure_sample_t callback;\r\n    z_closure(&callback, data_handler, NULL, NULL);\r\n    _LOG(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\r\n    z_view_keyexpr_t ke;\r\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\r\n    z_owned_subscriber_t sub;\r\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\r\n        _LOG(\"Unable to declare subscriber.\\n\");\r\n        return;\r\n    }\r\n\r\n    while (1) {\r\n        z_sleep_s(1);\r\n    }\r\n\r\n    // Clean-up\r\n    z_drop(z_move(sub));\r\n    z_drop(z_move(s));\r\n}\r\n\r\nTX_THREAD example_thread;\r\nUINT App_ThreadX_Init(VOID *memory_ptr) {\r\n    UINT ret = TX_SUCCESS;\r\n    TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL *)memory_ptr;\r\n\r\n    pthreadx_byte_pool = (TX_BYTE_POOL *)memory_ptr;\r\n    void *pointer;\r\n\r\n    /* Allocate the stack for the serial thread.  */\r\n    tx_byte_allocate(byte_pool, &pointer, 4096, TX_NO_WAIT);\r\n    /* Create the serial thread.  */\r\n    tx_thread_create(&example_thread, \"Zenoh-Pico-Example\", start_example_thread, 0, pointer, 4096, 15, 15,\r\n                     TX_NO_TIME_SLICE, TX_AUTO_START);\r\n\r\n    return ret;\r\n}\r\n\r\nvoid MX_ThreadX_Init(void) { tx_kernel_enter(); }\r\n"
  },
  {
    "path": "examples/unix/c11/z_advanced_pub.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, size_t *history);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    char *const default_value = \"Pub from Pico!\";\n    char *value = default_value;\n    size_t history = 1;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value, &history);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    // Declare advanced publisher\n    printf(\"Declaring AdvancedPublisher for '%s'...\\n\", keyexpr);\n    ze_owned_advanced_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    pub_opts.cache.max_samples = history;\n    pub_opts.cache.is_enabled = true;\n    pub_opts.publisher_detection = true;\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    // or pub_opts.sample_miss_detection.is_enabled = true\n    pub_opts.sample_miss_detection.is_enabled = true;\n    pub_opts.sample_miss_detection.heartbeat_period_ms = 500;\n    pub_opts.sample_miss_detection.heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_PERIODIC;\n    // if not set, publisher will retransmit samples based on periodic queries from advanced subscriber\n\n    if (ze_declare_advanced_publisher(z_loan(s), &pub, z_loan(ke), &pub_opts) < 0) {\n        printf(\"Unable to declare AdvancedPublisher for key expression!\\n\");\n        return -1;\n    }\n\n    // Publish data\n    printf(\"Press CTRL-C to quit...\\n\");\n    char buf[256];\n    for (int idx = 0; 1; ++idx) {\n        z_sleep_s(1);\n        sprintf(buf, \"[%4d] %s\", idx, value);\n        printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n        ze_advanced_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, size_t *history) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:i:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'i': {\n                int tmp = atoi(optarg);\n                if (tmp < 0) {\n                    fprintf(stderr, \"History size must be a positive integer.\\n\");\n                    return 1;\n                }\n                *history = (size_t)tmp;\n                break;\n            }\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'i') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_ADVANCED_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_advanced_sub.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_ADVANCED_SUBSCRIPTION == 1\n\nstatic int parse_args(int argc, char** argv, z_owned_config_t* config, char** keyexpr);\n\nconst char* kind_to_str(z_sample_kind_t kind);\n\nvoid data_handler(z_loaned_sample_t* sample, void* ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Advanced Subscriber] Received %s ('%.*s': '%.*s')\\n\", kind_to_str(z_sample_kind(sample)),\n           (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)),\n           z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n}\n\nvoid liveliness_handler(z_loaned_sample_t* sample, void* ctx) {\n    (void)(ctx);\n    z_view_string_t key_string;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_string);\n    switch (z_sample_kind(sample)) {\n        case Z_SAMPLE_KIND_PUT:\n            printf(\">> [Liveliness Subscriber] New alive token ('%.*s')\\n\", (int)z_string_len(z_loan(key_string)),\n                   z_string_data(z_loan(key_string)));\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            printf(\">> [Liveliness Subscriber] Dropped token ('%.*s')\\n\", (int)z_string_len(z_loan(key_string)),\n                   z_string_data(z_loan(key_string)));\n            break;\n    }\n}\n\nvoid miss_handler(const ze_miss_t* miss, void* arg) {\n    (void)(arg);\n    z_id_t id = z_entity_global_id_zid(&miss->source);\n    z_owned_string_t id_string;\n    z_id_to_string(&id, &id_string);\n    printf(\">> [Advanced Subscriber] Missed %d samples from '%.*s' !!!\", miss->nb, (int)z_string_len(z_loan(id_string)),\n           z_string_data(z_loan(id_string)));\n    z_drop(z_move(id_string));\n}\n\nint main(int argc, char** argv) {\n    char* keyexpr = \"demo/example/**\";\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_history_options_default(&sub_opts.history);\n    // or sub_opts.history.is_enabled = true;\n    sub_opts.history.detect_late_publishers = true;\n    ze_advanced_subscriber_recovery_options_default(&sub_opts.recovery);\n    // or sub_opts.recovery.is_enabled = true;\n    ze_advanced_subscriber_last_sample_miss_detection_options_default(&sub_opts.recovery.last_sample_miss_detection);\n    // or sub_opts.recovery.last_sample_miss_detection.is_enabled = true;\n    sub_opts.recovery.last_sample_miss_detection.periodic_queries_period_ms = 0;\n    // use publisher heartbeats by default, otherwise enable periodic queries as follows:\n    // sub_opts.recovery.last_sample_miss_detection.periodic_queries_period_ms = 1000;\n    sub_opts.subscriber_detection = true;\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring AdvancedSubscriber on '%s'...\\n\", keyexpr);\n    ze_owned_advanced_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (ze_declare_advanced_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), &sub_opts) < 0) {\n        printf(\"Unable to declare advanced subscriber.\\n\");\n        return -1;\n    }\n\n    ze_owned_closure_miss_t miss_callback;\n    ze_owned_sample_miss_listener_t miss_listener;\n    z_closure(&miss_callback, miss_handler, NULL, NULL);\n    ze_advanced_subscriber_declare_sample_miss_listener(z_loan(sub), &miss_listener, z_move(miss_callback));\n\n    z_owned_closure_sample_t liveliness_callback;\n    z_closure(&liveliness_callback, liveliness_handler, NULL, NULL);\n\n    z_liveliness_subscriber_options_t liveliness_sub_opt;\n    z_liveliness_subscriber_options_default(&liveliness_sub_opt);\n\n    z_owned_subscriber_t liveliness_sub;\n    if (ze_advanced_subscriber_detect_publishers(z_loan(sub), &liveliness_sub, z_move(liveliness_callback),\n                                                 &liveliness_sub_opt) < 0) {\n        printf(\"Unable to declare liveliness subscriber.\\n\");\n        exit(-1);\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        sleep(1);\n    }\n\n    // Clean up\n    z_drop(z_move(miss_listener));\n    z_drop(z_move(liveliness_sub));\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    return 0;\n}\n\nconst char* kind_to_str(z_sample_kind_t kind) {\n    switch (kind) {\n        case Z_SAMPLE_KIND_PUT:\n            return \"PUT\";\n        case Z_SAMPLE_KIND_DELETE:\n            return \"DELETE\";\n        default:\n            return \"UNKNOWN\";\n    }\n}\n\nstatic int parse_args(int argc, char** argv, z_owned_config_t* config, char** ke) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_ADVANCED_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_bytes.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#undef NDEBUG\n#include <assert.h>\n\ntypedef struct custom_struct_t {\n    float f;\n    uint64_t u[2][3];\n    const char *c;\n} custom_struct_t;\n\ntypedef struct kv_pair_t {\n    int32_t key;\n    z_owned_string_t value;\n} kv_pair_t;\n\nstatic void print_slice_data(z_view_slice_t *slice);\n\nint main(void) {\n    // Wrapping raw data into z_bytes_t\n    z_owned_bytes_t payload;\n    {\n        const uint8_t input_bytes[] = {1, 2, 3, 4};\n        z_owned_slice_t output_bytes;\n        z_bytes_copy_from_buf(&payload, input_bytes, sizeof(input_bytes));\n        z_bytes_to_slice(z_loan(payload), &output_bytes);\n        assert(memcmp(input_bytes, z_slice_data(z_loan(output_bytes)), z_slice_len(z_loan(output_bytes))) == 0);\n        z_drop(z_move(payload));\n        z_drop(z_move(output_bytes));\n        // Corresponding encoding to be used in operations options like `z_put()`, `z_get()`, etc.\n        // const z_loaned_encoding* encoding = z_encoding_zenoh_bytes();\n\n        // The same can be done for const char*\n        const char *input_str = \"test\";\n        z_owned_string_t output_string;\n        z_bytes_copy_from_str(&payload, input_str);\n        z_bytes_to_string(z_loan(payload), &output_string);\n        assert(strncmp(input_str, z_string_data(z_loan(output_string)), z_string_len(z_loan(output_string))) == 0);\n        z_drop(z_move(payload));\n        z_drop(z_move(output_string));\n        // Corresponding encoding to be used in operations options like `z_put()`, `z_get()`, etc.\n        // const z_loaned_encoding* encoding = z_encoding_zenoh_string();\n    }\n\n    // Serialization\n    {\n        // Arithmetic types: uint8, uint16, uint32, uint64, int8, int16, int32, int64, float, double\n        uint32_t input_u32 = 1234;\n        uint32_t output_u32 = 0;\n        ze_serialize_uint32(&payload, input_u32);\n        ze_deserialize_uint32(z_loan(payload), &output_u32);\n        assert(input_u32 == output_u32);\n        z_drop(z_move(payload));\n        // Corresponding encoding to be used in operations options like `z_put()`, `z_get()`, etc.\n        // const z_loaned_encoding* encoding = z_encoding_zenoh_serialized();\n    }\n\n    // Writer/reader for raw bytes\n    {\n        uint8_t input_writer[] = {0, 1, 2, 3, 4};\n        uint8_t output_reader[5] = {0};\n\n        z_owned_bytes_writer_t writer;\n        z_bytes_writer_empty(&writer);\n        z_bytes_writer_write_all(z_loan_mut(writer), input_writer, 3);\n        z_bytes_writer_write_all(z_loan_mut(writer), input_writer + 3, 2);\n        z_bytes_writer_finish(z_move(writer), &payload);\n        z_bytes_reader_t reader = z_bytes_get_reader(z_loan(payload));\n        z_bytes_reader_read(&reader, output_reader, sizeof(output_reader));\n        assert(0 == memcmp(input_writer, output_reader, sizeof(output_reader)));\n        z_drop(z_move(payload));\n    }\n\n    // Using serializer/deserializer for composite types\n    {\n        // A sequence of primitive types\n        int32_t input_vec[] = {1, 2, 3, 4};\n        int32_t output_vec[4] = {0};\n        ze_owned_serializer_t serializer;\n        ze_serializer_empty(&serializer);\n        ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 4);\n        for (size_t i = 0; i < 4; ++i) {\n            ze_serializer_serialize_int32(z_loan_mut(serializer), input_vec[i]);\n        }\n        ze_serializer_finish(z_move(serializer), &payload);\n\n        ze_deserializer_t deserializer = ze_deserializer_from_bytes(z_loan(payload));\n        size_t num_elements = 0;\n        ze_deserializer_deserialize_sequence_length(&deserializer, &num_elements);\n        assert(num_elements == 4);\n        for (size_t i = 0; i < num_elements; ++i) {\n            ze_deserializer_deserialize_int32(&deserializer, &output_vec[i]);\n        }\n\n        for (size_t i = 0; i < 4; ++i) {\n            assert(input_vec[i] == output_vec[i]);\n        }\n        z_drop(z_move(payload));\n    }\n\n    {\n        // Sequence of key-value pairs\n        kv_pair_t kvs_input[2];\n        kvs_input[0].key = 0;\n        z_string_from_str(&kvs_input[0].value, \"abc\", NULL, NULL);\n        kvs_input[1].key = 1;\n        z_string_from_str(&kvs_input[1].value, \"def\", NULL, NULL);\n\n        ze_owned_serializer_t serializer;\n        ze_serializer_empty(&serializer);\n        ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 2);\n        for (size_t i = 0; i < 2; ++i) {\n            ze_serializer_serialize_int32(z_loan_mut(serializer), kvs_input[i].key);\n            ze_serializer_serialize_string(z_loan_mut(serializer), z_loan(kvs_input[i].value));\n        }\n        ze_serializer_finish(z_move(serializer), &payload);\n\n        ze_deserializer_t deserializer = ze_deserializer_from_bytes(z_loan(payload));\n        size_t num_elements = 0;\n        ze_deserializer_deserialize_sequence_length(&deserializer, &num_elements);\n        assert(num_elements == 2);\n        kv_pair_t kvs_output[2];\n        for (size_t i = 0; i < num_elements; ++i) {\n            ze_deserializer_deserialize_int32(&deserializer, &kvs_output[i].key);\n            ze_deserializer_deserialize_string(&deserializer, &kvs_output[i].value);\n        }\n\n        for (size_t i = 0; i < 2; ++i) {\n            assert(kvs_input[i].key == kvs_output[i].key);\n            assert(strncmp(z_string_data(z_loan(kvs_input[i].value)), z_string_data(z_loan(kvs_output[i].value)),\n                           z_string_len(z_loan(kvs_input[i].value))) == 0);\n            z_drop(z_move(kvs_input[i].value));\n            z_drop(z_move(kvs_output[i].value));\n        }\n        z_drop(z_move(payload));\n    }\n\n    {\n        // Custom struct/tuple serializaiton\n        custom_struct_t cs = (custom_struct_t){.f = 1.0f, .u = {{1, 2, 3}, {4, 5, 6}}, .c = \"test\"};\n\n        ze_owned_serializer_t serializer;\n        ze_serializer_empty(&serializer);\n        ze_serializer_serialize_float(z_loan_mut(serializer), cs.f);\n        ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 2);\n        for (size_t i = 0; i < 2; ++i) {\n            ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 3);\n            for (size_t j = 0; j < 3; ++j) {\n                ze_serializer_serialize_uint64(z_loan_mut(serializer), cs.u[i][j]);\n            }\n        }\n        ze_serializer_serialize_str(z_loan_mut(serializer), cs.c);\n        ze_serializer_finish(z_move(serializer), &payload);\n\n        float f = 0.0f;\n        uint64_t u = 0;\n        z_owned_string_t c;\n\n        ze_deserializer_t deserializer = ze_deserializer_from_bytes(z_loan(payload));\n        ze_deserializer_deserialize_float(&deserializer, &f);\n        assert(f == cs.f);\n        size_t num_elements0 = 0;\n        ze_deserializer_deserialize_sequence_length(&deserializer, &num_elements0);\n        assert(num_elements0 == 2);\n        for (size_t i = 0; i < 2; ++i) {\n            size_t num_elements1 = 0;\n            ze_deserializer_deserialize_sequence_length(&deserializer, &num_elements1);\n            assert(num_elements1 == 3);\n            for (size_t j = 0; j < 3; ++j) {\n                ze_deserializer_deserialize_uint64(&deserializer, &u);\n                assert(u == cs.u[i][j]);\n            }\n        }\n        ze_deserializer_deserialize_string(&deserializer, &c);\n        assert(strncmp(cs.c, z_string_data(z_loan(c)), z_string_len(z_loan(c))) == 0);\n\n        z_drop(z_move(c));\n        z_drop(z_move(payload));\n    }\n\n    // Slice iterator\n    {\n        /// Fill z_bytes with some data\n        z_owned_bytes_t b1, b2, b3;\n        z_bytes_copy_from_str(&b1, \"abc\");\n        z_bytes_copy_from_str(&b2, \"def\");\n        z_bytes_copy_from_str(&b3, \"hij\");\n        z_owned_bytes_writer_t writer;\n        z_bytes_writer_empty(&writer);\n        z_bytes_writer_append(z_loan_mut(writer), z_move(b1));\n        z_bytes_writer_append(z_loan_mut(writer), z_move(b2));\n        z_bytes_writer_append(z_loan_mut(writer), z_move(b3));\n\n        z_bytes_writer_finish(z_move(writer), &payload);\n        z_bytes_slice_iterator_t slice_iter = z_bytes_get_slice_iterator(z_bytes_loan(&payload));\n        z_view_slice_t curr_slice;\n        while (z_bytes_slice_iterator_next(&slice_iter, &curr_slice)) {\n            printf(\"slice len: %d, slice data: '\", (int)z_slice_len(z_view_slice_loan(&curr_slice)));\n            print_slice_data(&curr_slice);\n            printf(\"'\\n\");\n        }\n        z_drop(z_move(payload));\n    }\n    return 0;\n}\n\nstatic void print_slice_data(z_view_slice_t *slice) {\n    for (size_t i = 0; i < z_slice_len(z_view_slice_loan(slice)); i++) {\n        printf(\"0x%02x \", z_slice_data(z_view_slice_loan(slice))[i]);\n    }\n}\n"
  },
  {
    "path": "examples/unix/c11/z_get.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1\nstatic z_owned_condvar_t cond;\nstatic z_owned_mutex_t mutex;\n\nconst char *kind_to_str(z_sample_kind_t kind);\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value);\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    printf(\">> Received query final notification\\n\");\n    z_condvar_signal(z_loan_mut(cond));\n    z_drop(z_move(cond));\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\">> Received %s ('%.*s': '%.*s')\\n\", kind_to_str(z_sample_kind(sample)),\n               (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(replystr)),\n               z_string_data(z_loan(replystr)));\n        z_drop(z_move(replystr));\n    } else {\n        const z_loaned_reply_err_t *err = z_reply_err(reply);\n        z_owned_string_t errstr;\n        z_bytes_to_string(z_reply_err_payload(err), &errstr);\n        printf(\">> Received an error: %.*s\\n\", (int)z_string_len(z_loan(errstr)), z_string_data(z_loan(errstr)));\n        z_drop(z_move(errstr));\n    }\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    char *value = NULL;\n\n    z_mutex_init(&mutex);\n    z_condvar_init(&cond);\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    z_mutex_lock(z_loan_mut(mutex));\n    printf(\"Sending Query '%s'...\\n\", keyexpr);\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    // Value encoding\n    z_owned_bytes_t payload;\n    if (value != NULL) {\n        z_bytes_from_static_str(&payload, value);\n        opts.payload = z_bytes_move(&payload);\n    }\n\n    z_owned_closure_reply_t callback;\n    z_closure(&callback, reply_handler, reply_dropper, NULL);\n    if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n        printf(\"Unable to send query.\\n\");\n        return -1;\n    }\n    z_condvar_wait(z_loan_mut(cond), z_loan_mut(mutex));\n    z_mutex_unlock(z_loan_mut(mutex));\n\n    z_drop(z_move(s));\n    return 0;\n}\n\nconst char *kind_to_str(z_sample_kind_t kind) {\n    switch (kind) {\n        case Z_SAMPLE_KIND_PUT:\n            return \"PUT\";\n        case Z_SAMPLE_KIND_DELETE:\n            return \"DELETE\";\n        default:\n            return \"UNKNOWN\";\n    }\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_get_attachment.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\ntypedef struct kv_pair_t {\n    z_owned_string_t key;\n    z_owned_string_t value;\n} kv_pair_t;\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1\nstatic z_owned_condvar_t cond;\nstatic z_owned_mutex_t mutex;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value);\n\nvoid print_attachment(const kv_pair_t *kvp, size_t len) {\n    printf(\"    with attachment:\\n\");\n    for (size_t i = 0; i < len; i++) {\n        printf(\"     %zu: %.*s, %.*s\\n\", i, (int)z_string_len(z_loan(kvp[i].key)), z_string_data(z_loan(kvp[i].key)),\n               (int)z_string_len(z_loan(kvp[i].value)), z_string_data(z_loan(kvp[i].value)));\n    }\n}\n\nvoid drop_attachment(kv_pair_t *kvp, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        z_drop(z_move(kvp[i].key));\n        z_drop(z_move(kvp[i].value));\n    }\n}\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    printf(\">> Received query final notification\\n\");\n    z_condvar_signal(z_loan_mut(cond));\n    z_drop(z_move(cond));\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n        z_owned_string_t encoding;\n        z_encoding_to_string(z_sample_encoding(sample), &encoding);\n\n        printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n               (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n        printf(\"    with encoding: %.*s\\n\", (int)z_string_len(z_loan(encoding)), z_string_data(z_loan(encoding)));\n        z_drop(z_move(replystr));\n        z_drop(z_move(encoding));\n\n        // Check attachment\n        const z_loaned_bytes_t *attachment = z_sample_attachment(sample);\n        ze_deserializer_t deserializer = ze_deserializer_from_bytes(attachment);\n        size_t attachment_len;\n        if (ze_deserializer_deserialize_sequence_length(&deserializer, &attachment_len) < 0) {\n            return;\n        }\n        kv_pair_t *kvp = (kv_pair_t *)malloc(sizeof(kv_pair_t) * attachment_len);\n        for (size_t i = 0; i < attachment_len; ++i) {\n            ze_deserializer_deserialize_string(&deserializer, &kvp[i].key);\n            ze_deserializer_deserialize_string(&deserializer, &kvp[i].value);\n        }\n        if (attachment_len > 0) {\n            print_attachment(kvp, attachment_len);\n        }\n        drop_attachment(kvp, attachment_len);\n        free(kvp);\n    } else {\n        printf(\">> Received an error\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    char *value = NULL;\n\n    z_mutex_init(&mutex);\n    z_condvar_init(&cond);\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    z_mutex_lock(z_loan_mut(mutex));\n    printf(\"Sending Query '%s'...\\n\", keyexpr);\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    // Value encoding\n    z_owned_bytes_t payload;\n    if (value != NULL) {\n        z_bytes_from_static_str(&payload, value);\n        opts.payload = z_bytes_move(&payload);\n    }\n\n    // Add attachment value\n    kv_pair_t kvs[1];\n    z_string_from_str(&kvs[0].key, \"test_key\", NULL, NULL);\n    z_string_from_str(&kvs[0].value, \"test_value\", NULL, NULL);\n    z_owned_bytes_t attachment;\n\n    ze_owned_serializer_t serializer;\n    ze_serializer_empty(&serializer);\n    ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 1);\n    for (size_t i = 0; i < 1; ++i) {\n        ze_serializer_serialize_string(z_loan_mut(serializer), z_loan(kvs[i].key));\n        ze_serializer_serialize_string(z_loan_mut(serializer), z_loan(kvs[i].value));\n    }\n    drop_attachment(kvs, 1);\n    ze_serializer_finish(z_move(serializer), &attachment);\n    opts.attachment = z_move(attachment);\n\n    // Add encoding value\n    z_owned_encoding_t encoding;\n    z_encoding_from_str(&encoding, \"zenoh/string;utf8\");\n    opts.encoding = z_move(encoding);\n\n    z_owned_closure_reply_t callback;\n    z_closure(&callback, reply_handler, reply_dropper, NULL);\n    if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n        printf(\"Unable to send query.\\n\");\n        return -1;\n    }\n    z_condvar_wait(z_loan_mut(cond), z_loan_mut(mutex));\n    z_mutex_unlock(z_loan_mut(mutex));\n\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_get_channel.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    char *value = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Sending Query '%s'...\\n\", keyexpr);\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    // Value encoding\n    z_owned_bytes_t payload;\n    if (value != NULL) {\n        z_bytes_from_static_str(&payload, value);\n        opts.payload = z_bytes_move(&payload);\n    }\n    z_owned_closure_reply_t closure;\n    z_owned_ring_handler_reply_t handler;\n    z_ring_channel_reply_new(&closure, &handler, 1);\n    if (z_get(z_loan(s), z_loan(ke), \"\", z_move(closure), &opts) < 0) {\n        printf(\"Unable to send query.\\n\");\n        return -1;\n    }\n\n    z_owned_reply_t reply;\n    for (z_result_t res = z_recv(z_loan(handler), &reply); res == Z_OK; res = z_recv(z_loan(handler), &reply)) {\n        if (z_reply_is_ok(z_loan(reply))) {\n            const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n            z_owned_string_t replystr;\n            z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n            printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n                   (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n            z_drop(z_move(replystr));\n        } else {\n            printf(\">> Received an error\\n\");\n        }\n    }\n\n    z_drop(z_move(handler));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_get_lat.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdatomic.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1 && defined Z_FEATURE_UNSTABLE_API\n\n#define DEFAULT_PKT_SIZE 8\n#define DEFAULT_PING_NB 100\n#define DEFAULT_WARMUP_MS 1000\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, unsigned int *size, unsigned int *ping_nb,\n                      unsigned int *warmup_ms, bool *is_peer);\n\nstatic _Atomic unsigned long sync_tx_rx = 0;\n\nstatic unsigned long load_loop(unsigned long target_value) {\n    unsigned long curr_val;\n    do {\n        curr_val = atomic_load_explicit(&sync_tx_rx, memory_order_relaxed);\n    } while (curr_val != target_value);\n    return curr_val;\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)reply;\n    (void)ctx;\n    atomic_fetch_add_explicit(&sync_tx_rx, 1, memory_order_relaxed);\n}\n\nint main(int argc, char **argv) {\n    unsigned int pkt_size = DEFAULT_PKT_SIZE;\n    unsigned int ping_nb = DEFAULT_PING_NB;\n    unsigned int warmup_ms = DEFAULT_WARMUP_MS;\n    bool is_peer = false;\n\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &pkt_size, &ping_nb, &warmup_ms, &is_peer);\n    if (ret != 0) {\n        return ret;\n    }\n\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    // Wait for queryable to stabilize\n    z_sleep_ms(1);\n\n    // Get keyexpr & closure\n    z_view_keyexpr_t ke;\n    z_owned_querier_t que;\n    z_view_keyexpr_from_str_unchecked(&ke, \"lat\");\n    if (z_declare_querier(z_loan(s), &que, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare querier for key expression!\\n\");\n        return -1;\n    }\n    unsigned long prev_val = sync_tx_rx;\n    z_owned_closure_reply_t callback;\n\n    // Send packets\n    if (warmup_ms) {\n        z_clock_t warmup_start = z_clock_now();\n        unsigned long elapsed_us = 0;\n        while (elapsed_us < warmup_ms * 1000) {\n            z_closure(&callback, reply_handler, NULL, NULL);\n            if (z_querier_get(z_loan(que), NULL, z_move(callback), NULL) < 0) {\n                printf(\"Tx failed\");\n                continue;\n            }\n            prev_val = load_loop(prev_val + 1);\n            elapsed_us = z_clock_elapsed_us(&warmup_start);\n        }\n    }\n\n    unsigned long *results = (unsigned long *)z_malloc(sizeof(unsigned long) * ping_nb);\n    for (unsigned int i = 0; i < ping_nb; i++) {\n        z_clock_t measure_start = z_clock_now();\n        z_closure(&callback, reply_handler, NULL, NULL);\n        if (z_querier_get(z_loan(que), NULL, z_move(callback), NULL) < 0) {\n            printf(\"Tx failed\");\n            continue;\n        }\n        prev_val = load_loop(prev_val + 1);\n        results[i] = z_clock_elapsed_us(&measure_start);\n    }\n    for (unsigned int i = 0; i < ping_nb; i++) {\n        printf(\"%lu\\n\", results[i]);\n    }\n    // Clean up\n    z_free(results);\n    z_drop(z_move(que));\n    z_drop(z_move(s));\n    exit(0);\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, unsigned int *size, unsigned int *ping_nb,\n                      unsigned int *warmup_ms, bool *is_peer) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"s:n:w:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 's':\n                *size = (unsigned int)atoi(optarg);\n                break;\n            case 'n':\n                *ping_nb = (unsigned int)atoi(optarg);\n                break;\n            case 'w':\n                *warmup_ms = (unsigned int)atoi(optarg);\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                if (strcmp(optarg, \"peer\") == 0) {\n                    *is_peer = true;\n                }\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 's' || optopt == 'n' || optopt == 'w' || optopt == 'e' || optopt == 'm' ||\n                    optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY, Z_FEATURE_MULTI_THREAD or Z_FEATURE_UNSTABLE_API but \"\n        \"this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_get_liveliness.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_LIVELINESS == 1 && Z_FEATURE_QUERY == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"group1/**\";\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Sending liveliness query '%s'...\\n\", keyexpr);\n    z_owned_fifo_handler_reply_t handler;\n    z_owned_closure_reply_t closure;\n    z_fifo_channel_reply_new(&closure, &handler, 16);\n    if (z_liveliness_get(z_loan(s), z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Liveliness query failed\");\n        return -1;\n    }\n    z_owned_reply_t reply;\n    for (z_result_t res = z_recv(z_loan(handler), &reply); res == Z_OK; res = z_recv(z_loan(handler), &reply)) {\n        if (z_reply_is_ok(z_loan(reply))) {\n            const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n            z_view_string_t key_str;\n            z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_str);\n            printf(\">> Alive token ('%.*s')\\n\", (int)z_string_len(z_loan(key_str)), z_string_data(z_loan(key_str)));\n        } else {\n            printf(\"Received an error\\n\");\n        }\n        z_drop(z_move(reply));\n    }\n\n    z_drop(z_move(closure));\n    z_drop(z_move(handler));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_LIVELINESS but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_info.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <signal.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\nvoid print_zid(const z_id_t *id, void *ctx) {\n    (void)(ctx);\n    z_owned_string_t id_str;\n    z_id_to_string(id, &id_str);\n    printf(\" %.*s\\n\", (int)z_string_len(z_loan(id_str)), z_string_data(z_loan(id_str)));\n    z_drop(z_move(id_str));\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic const char *bool_to_str(bool value) { return value ? \"true\" : \"false\"; }\n\nstatic void print_transport(z_loaned_transport_t *transport, void *ctx) {\n    (void)(ctx);\n    z_id_t zid = z_transport_zid(transport);\n    z_owned_string_t id_str;\n    z_id_to_string(&zid, &id_str);\n    z_view_string_t whatami;\n    z_whatami_to_view_string(z_transport_whatami(transport), &whatami);\n\n    printf(\"  transport{zid=%.*s, whatami=%.*s, is_qos=%s, is_multicast=%s, is_shm=%s}\\n\",\n           (int)z_string_len(z_loan(id_str)), z_string_data(z_loan(id_str)), (int)z_string_len(z_loan(whatami)),\n           z_string_data(z_loan(whatami)), bool_to_str(z_transport_is_qos(transport)),\n           bool_to_str(z_transport_is_multicast(transport)), bool_to_str(z_transport_is_shm(transport)));\n    z_drop(z_move(id_str));\n}\n\nstatic void print_link(z_loaned_link_t *link, void *ctx) {\n    (void)(ctx);\n    z_id_t zid = z_link_zid(link);\n    z_owned_string_t id_str;\n    z_id_to_string(&zid, &id_str);\n    z_owned_string_t src;\n    z_owned_string_t dst;\n    bool has_src = z_link_src(link, &src) == 0;\n    bool has_dst = z_link_dst(link, &dst) == 0;\n\n    printf(\"  link{zid=%.*s\", (int)z_string_len(z_loan(id_str)), z_string_data(z_loan(id_str)));\n    printf(\", src=\");\n    if (has_src) {\n        printf(\"%.*s\", (int)z_string_len(z_loan(src)), z_string_data(z_loan(src)));\n    } else {\n        printf(\"<n/a>\");\n    }\n    printf(\", dst=\");\n    if (has_dst) {\n        printf(\"%.*s\", (int)z_string_len(z_loan(dst)), z_string_data(z_loan(dst)));\n    } else {\n        printf(\"<n/a>\");\n    }\n    z_owned_string_t group;\n    z_link_group(link, &group);\n    z_owned_string_t auth_id;\n    z_link_auth_identifier(link, &auth_id);\n    z_owned_string_array_t interfaces;\n    z_link_interfaces(link, &interfaces);\n    uint8_t prio_min, prio_max;\n    bool has_prio = z_link_priorities(link, &prio_min, &prio_max);\n    z_reliability_t reliability;\n    bool has_rel = z_link_reliability(link, &reliability);\n\n    if (z_string_len(z_loan(group)) > 0) {\n        printf(\", group=%.*s\", (int)z_string_len(z_loan(group)), z_string_data(z_loan(group)));\n    }\n    if (z_string_len(z_loan(auth_id)) > 0) {\n        printf(\", auth_id=%.*s\", (int)z_string_len(z_loan(auth_id)), z_string_data(z_loan(auth_id)));\n    }\n    printf(\", interfaces=[\");\n    size_t iface_len = z_string_array_len(z_loan(interfaces));\n    for (size_t i = 0; i < iface_len; i++) {\n        const z_loaned_string_t *iface = z_string_array_get(z_loan(interfaces), i);\n        if (i > 0) printf(\", \");\n        printf(\"%.*s\", (int)z_string_len(iface), z_string_data(iface));\n    }\n    printf(\"]\");\n    if (has_prio) {\n        printf(\", priorities=[%u, %u]\", (unsigned)prio_min, (unsigned)prio_max);\n    }\n    if (has_rel) {\n        printf(\", reliability=%s\", (reliability == Z_RELIABILITY_RELIABLE) ? \"reliable\" : \"best_effort\");\n    }\n    printf(\", mtu=%u, is_streamed=%s, is_reliable=%s}\\n\", (unsigned)z_link_mtu(link),\n           bool_to_str(z_link_is_streamed(link)), bool_to_str(z_link_is_reliable(link)));\n\n    z_drop(z_move(id_str));\n    if (has_src) {\n        z_drop(z_move(src));\n    }\n    if (has_dst) {\n        z_drop(z_move(dst));\n    }\n    z_drop(z_move(group));\n    z_drop(z_move(auth_id));\n    z_drop(z_move(interfaces));\n}\n\nstatic volatile bool running = true;\n\nstatic void handle_signal(int signo) {\n    (void)signo;\n    running = false;\n}\n\nstatic void transport_event_handler(z_loaned_transport_event_t *event, void *ctx) {\n    (void)ctx;\n    z_sample_kind_t kind = z_transport_event_kind(event);\n    const z_loaned_transport_t *transport = z_transport_event_transport(event);\n    printf(\">> [Transport Event] %s:\\n\", (kind == Z_SAMPLE_KIND_PUT) ? \"Opened\" : \"Closed\");\n    print_transport((z_loaned_transport_t *)transport, NULL);\n}\n\nstatic void link_event_handler(z_loaned_link_event_t *event, void *ctx) {\n    (void)ctx;\n    z_sample_kind_t kind = z_link_event_kind(event);\n    const z_loaned_link_t *link = z_link_event_link(event);\n    printf(\">> [Link Event] %s:\\n\", (kind == Z_SAMPLE_KIND_PUT) ? \"Opened\" : \"Closed\");\n    print_link((z_loaned_link_t *)link, NULL);\n}\n#endif\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config);\n\nint main(int argc, char **argv) {\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_id_t self_id = z_info_zid(z_loan(s));\n    printf(\"Own ID:\");\n    print_zid(&self_id, NULL);\n\n    printf(\"Routers IDs:\\n\");\n    z_owned_closure_zid_t callback;\n    z_closure(&callback, print_zid, NULL, NULL);\n    z_info_routers_zid(z_loan(s), z_move(callback));\n\n    // `callback` has been `z_move`d just above, so it's safe to reuse the variable,\n    // we'll just have to make sure we `z_move` it again to avoid mem-leaks.\n    printf(\"Peers IDs:\\n\");\n    z_owned_closure_zid_t callback2;\n    z_closure(&callback2, print_zid, NULL, NULL);\n    z_info_peers_zid(z_loan(s), z_move(callback2));\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    printf(\"Connected transports:\\n\");\n    z_owned_closure_transport_t transport_cb;\n    z_closure(&transport_cb, print_transport, NULL, NULL);\n    if (z_info_transports(z_loan(s), z_move(transport_cb)) < 0) {\n        printf(\"Unable to fetch connected transports\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    printf(\"Connected links:\\n\");\n    z_owned_closure_link_t link_cb;\n    z_closure(&link_cb, print_link, NULL, NULL);\n    if (z_info_links(z_loan(s), z_move(link_cb), NULL) < 0) {\n        printf(\"Unable to fetch connected links\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    // Register transport event listener (background, no history to avoid duplicating already-printed items)\n    printf(\"Declaring transport events listener...\\n\");\n    z_owned_closure_transport_event_t te_cb;\n    z_closure(&te_cb, transport_event_handler, NULL, NULL);\n    z_transport_events_listener_options_t te_opts;\n    z_transport_events_listener_options_default(&te_opts);\n    te_opts.history = false;\n    if (z_declare_background_transport_events_listener(z_loan(s), z_move(te_cb), &te_opts) < 0) {\n        printf(\"Unable to declare transport events listener\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    // Register link event listener (non-background so we can undeclare it)\n    printf(\"Declaring link events listener...\\n\");\n    z_owned_closure_link_event_t le_cb;\n    z_closure(&le_cb, link_event_handler, NULL, NULL);\n    z_link_events_listener_options_t le_opts;\n    z_link_events_listener_options_default(&le_opts);\n    le_opts.history = false;\n    z_owned_link_events_listener_t le_listener;\n    if (z_declare_link_events_listener(z_loan(s), &le_listener, z_move(le_cb), &le_opts) < 0) {\n        printf(\"Unable to declare link events listener\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    signal(SIGINT, handle_signal);\n    signal(SIGTERM, handle_signal);\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (running) {\n        z_sleep_s(1);\n    }\n\n    z_drop(z_move(le_listener));\n#endif\n\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n"
  },
  {
    "path": "examples/unix/c11/z_liveliness.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_LIVELINESS == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, unsigned long *timeout);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"group1/zenoh-pico\";\n    unsigned long timeout = 0;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &timeout);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Declaring liveliness token '%s'...\\n\", keyexpr);\n    z_owned_liveliness_token_t token;\n    if (z_liveliness_declare_token(z_loan(s), &token, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to create liveliness token!\\n\");\n        exit(-1);\n    }\n\n    printf(\"Press CTRL-C to undeclare liveliness token and quit...\\n\");\n    z_clock_t clock = z_clock_now();\n    while (timeout == 0 || z_clock_elapsed_s(&clock) < timeout) {\n        z_sleep_ms(100);\n    }\n\n    // LivelinessTokens are automatically closed when dropped\n    // Use the code below to manually undeclare it if needed\n    printf(\"Undeclaring liveliness token...\\n\");\n    z_drop(z_move(token));\n\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, unsigned long *timeout) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:t:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 't':\n                *timeout = (unsigned long)atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 't' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_ping.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdatomic.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 1\n\n#define DEFAULT_PKT_SIZE 8\n#define DEFAULT_PING_NB 100\n#define DEFAULT_WARMUP_MS 1000\n\nstatic int parse_args(int argc, char** argv, z_owned_config_t* config, unsigned int* size, unsigned int* ping_nb,\n                      unsigned int* warmup_ms, bool* is_peer);\n\nstatic _Atomic unsigned long sync_tx_rx = 0;\n\nvoid callback(z_loaned_sample_t* sample, void* context) {\n    (void)sample;\n    (void)context;\n    atomic_fetch_add_explicit(&sync_tx_rx, 1, memory_order_relaxed);\n}\n\nstatic unsigned long load_loop(unsigned long target_value) {\n    unsigned long curr_val;\n    do {\n        curr_val = atomic_load_explicit(&sync_tx_rx, memory_order_relaxed);\n    } while (curr_val != target_value);\n    return curr_val;\n}\n\nint main(int argc, char** argv) {\n    unsigned int pkt_size = DEFAULT_PKT_SIZE;\n    unsigned int ping_nb = DEFAULT_PING_NB;\n    unsigned int warmup_ms = DEFAULT_WARMUP_MS;\n    bool is_peer = false;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &pkt_size, &ping_nb, &warmup_ms, &is_peer);\n    if (ret != 0) {\n        return ret;\n    }\n\n    z_owned_session_t session;\n    if (z_open(&session, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    z_view_keyexpr_t ping;\n    z_view_keyexpr_from_str_unchecked(&ping, \"test/ping\");\n    z_view_keyexpr_t pong;\n    z_view_keyexpr_from_str_unchecked(&pong, \"test/pong\");\n\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(session), &pub, z_loan(ping), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_owned_closure_sample_t respond;\n    z_closure(&respond, callback);\n    if (z_declare_background_subscriber(z_loan(session), z_loan(pong), z_move(respond), NULL) < 0) {\n        printf(\"Unable to declare subscriber for key expression.\\n\");\n        return -1;\n    }\n\n    uint8_t* data = (uint8_t*)z_malloc(pkt_size);\n    for (unsigned int i = 0; i < pkt_size; i++) {\n        data[i] = (uint8_t)(i % 10);\n    }\n    // Wait for declare to be processed\n    z_sleep_ms(50);\n\n    // Create payload\n    unsigned long prev_val = sync_tx_rx;\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, data, pkt_size, NULL, NULL);\n    z_owned_bytes_t curr_payload;\n    if (warmup_ms) {\n        z_clock_t warmup_start = z_clock_now();\n        unsigned long elapsed_us = 0;\n        while (elapsed_us < warmup_ms * 1000) {\n            z_bytes_clone(&curr_payload, z_loan(payload));\n            if (z_publisher_put(z_loan(pub), z_move(curr_payload), NULL) != _Z_RES_OK) {\n                printf(\"Tx failed\");\n                continue;\n            }\n            prev_val = load_loop(prev_val + 1);\n            elapsed_us = z_clock_elapsed_us(&warmup_start);\n        }\n    }\n    unsigned long* results = (unsigned long*)z_malloc(sizeof(unsigned long) * ping_nb);\n    for (unsigned int i = 0; i < ping_nb; i++) {\n        z_clock_t measure_start = z_clock_now();\n        z_bytes_clone(&curr_payload, z_loan(payload));\n        if (z_publisher_put(z_loan(pub), z_move(curr_payload), NULL) != _Z_RES_OK) {\n            printf(\"Tx failed\");\n            continue;\n        }\n        prev_val = load_loop(prev_val + 1);\n        results[i] = z_clock_elapsed_us(&measure_start);\n    }\n    for (unsigned int i = 0; i < ping_nb; i++) {\n        printf(\"%lu\\n\", results[i]);\n    }\n    z_drop(z_move(payload));\n    z_free(results);\n    z_free(data);\n    z_drop(z_move(pub));\n    z_drop(z_move(session));\n}\n\nstatic int parse_args(int argc, char** argv, z_owned_config_t* config, unsigned int* size, unsigned int* ping_nb,\n                      unsigned int* warmup_ms, bool* is_peer) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"s:n:w:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 's':\n                *size = (unsigned int)atoi(optarg);\n                break;\n            case 'n':\n                *ping_nb = (unsigned int)atoi(optarg);\n                break;\n            case 'w':\n                *warmup_ms = (unsigned int)atoi(optarg);\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                if (strcmp(optarg, \"peer\") == 0) {\n                    *is_peer = true;\n                }\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 's' || optopt == 'n' || optopt == 'w' || optopt == 'e' || optopt == 'm' ||\n                    optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION or Z_FEATURE_PUBLICATION or \"\n        \"Z_FEATURE_MULTI_THREAD but this example requires them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pong.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <unistd.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\n\nstatic int parse_args(int argc, char** argv, z_owned_config_t* config);\n\nvoid callback(z_loaned_sample_t* sample, void* context) {\n    const z_loaned_publisher_t* pub = z_loan(*(z_owned_publisher_t*)context);\n    z_owned_bytes_t payload = {._val = sample->payload};\n    z_publisher_put(pub, z_move(payload), NULL);\n}\n\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config);\n    if (ret != 0) {\n        return ret;\n    }\n\n    z_owned_session_t session;\n    if (z_open(&session, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t pong;\n    z_view_keyexpr_from_str_unchecked(&pong, \"test/pong\");\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(session), &pub, z_loan(pong), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ping;\n    z_view_keyexpr_from_str_unchecked(&ping, \"test/ping\");\n    z_owned_closure_sample_t respond;\n    z_closure(&respond, callback, NULL, (void*)(&pub));\n    if (z_declare_background_subscriber(z_loan(session), z_loan(ping), z_move(respond), NULL) < 0) {\n        printf(\"Unable to declare subscriber for key expression.\\n\");\n        return -1;\n    }\n    printf(\"Pong app is running, press 'q' to quit\\n\");\n    while (getchar() != 'q') {\n    }\n    z_drop(z_move(pub));\n    z_drop(z_move(session));\n}\n\nstatic int parse_args(int argc, char** argv, z_owned_config_t* config) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION or Z_FEATURE_PUBLICATION but this example \"\n        \"requires them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, int *n,\n                      bool *add_matching_listener);\n\n#if Z_FEATURE_MATCHING == 1\nvoid matching_status_handler(const z_matching_status_t *matching_status, void *arg) {\n    (void)arg;\n    if (matching_status->matching) {\n        printf(\"Publisher has matching subscribers.\\n\");\n    } else {\n        printf(\"Publisher has NO MORE matching subscribers.\\n\");\n    }\n}\n#endif\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    char *const default_value = \"Pub from Pico!\";\n    char *value = default_value;\n    int n = 2147483647;  // max int value by default\n    bool add_matching_listener = false;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value, &n, &add_matching_listener);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n    // Declare publisher\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    if (add_matching_listener) {\n#if Z_FEATURE_MATCHING == 1\n        z_owned_closure_matching_status_t callback;\n        z_closure(&callback, matching_status_handler, NULL, NULL);\n        z_publisher_declare_background_matching_listener(z_loan(pub), z_move(callback));\n#else\n        printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_MATCHING but this example requires it.\\n\");\n        return -2;\n#endif\n    }\n\n    // Publish data\n    printf(\"Press CTRL-C to quit...\\n\");\n    char buf[256];\n    for (int idx = 0; idx < n; ++idx) {\n        z_sleep_s(1);\n        sprintf(buf, \"[%4d] %s\", idx, value);\n        printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n    // Clean up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, int *n,\n                      bool *add_matching_listener) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:a\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case 'a':\n                *add_matching_listener = true;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pub_attachment.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n#include <zenoh-pico/system/platform.h>\n\ntypedef struct kv_pair_t {\n    const char *key;\n    const char *value;\n} kv_pair_t;\n\n#if Z_FEATURE_PUBLICATION == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, int *n);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    char *const default_value = \"Pub from Pico!\";\n    char *value = default_value;\n    int n = 2147483647;  // max int value by default\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value, &n);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n    // Declare publisher\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_publisher_put_options_t options;\n    z_publisher_put_options_default(&options);\n\n    // Allocate attachment\n    kv_pair_t kvs[2];\n    kvs[0] = (kv_pair_t){.key = \"source\", .value = \"C\"};\n\n    z_owned_bytes_t attachment;\n    z_bytes_empty(&attachment);\n\n    // Create encoding\n    z_owned_encoding_t encoding;\n\n    // Create timestamp\n    z_timestamp_t ts;\n    z_timestamp_new(&ts, z_loan(s));\n\n    // Publish data\n    printf(\"Press CTRL-C to quit...\\n\");\n    char buf[256];\n    for (int idx = 0; idx < n; ++idx) {\n        z_sleep_s(1);\n        sprintf(buf, \"[%4d] %s\", idx, value);\n        printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        // Add attachment value\n        char buf_ind[16];\n        sprintf(buf_ind, \"%d\", idx);\n        kvs[1] = (kv_pair_t){.key = \"index\", .value = buf_ind};\n        ze_owned_serializer_t serializer;\n        ze_serializer_empty(&serializer);\n        ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 2);\n        for (size_t i = 0; i < 2; ++i) {\n            ze_serializer_serialize_str(z_loan_mut(serializer), kvs[i].key);\n            ze_serializer_serialize_str(z_loan_mut(serializer), kvs[i].value);\n        }\n        ze_serializer_finish(z_move(serializer), &attachment);\n        options.attachment = z_move(attachment);\n\n        // Add encoding value\n        z_encoding_from_str(&encoding, \"zenoh/string;utf8\");\n        options.encoding = z_move(encoding);\n\n        // Add timestamp\n        options.timestamp = &ts;\n\n        z_publisher_put(z_loan(pub), z_move(payload), &options);\n    }\n    // Clean up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, int *n) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 0\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, int *n);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    char *const default_value = \"Pub from Pico!\";\n    char *value = default_value;\n    int n = 2147483647;  // max int value by default\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value, &n);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    // Main loop\n    printf(\"Press CTRL-C to quit...\\n\");\n    char buf[256];\n    z_clock_t now = z_clock_now();\n    for (int idx = 0; idx < n;) {\n        if (z_clock_elapsed_ms(&now) > 1000) {\n            snprintf(buf, 256, \"[%4d] %s\", idx, value);\n            printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_copy_from_str(&payload, buf);\n\n            z_publisher_put(z_loan(pub), z_move(payload), NULL);\n            ++idx;\n\n            now = z_clock_now();\n        }\n        z_sleep_ms(50);\n        zp_spin_once(z_session_loan(&s));\n    }\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value, int *n) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_PUBLICATION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pub_thr.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdatomic.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/protocol/codec.h\"\n\n#define ZENOH_MSH_HDR_SIZE 3\n#define ZENOH_FRAME_HDR_SIZE 2\n#define ZENOH_TCP_MTU 49150\n#define ZENOH_UDP_MTU 1450\n#define ZENOH_TCP_PEER_MTU 65533\n#define TEST_RUN_TIME_S 20\n\ntypedef struct {\n    unsigned long frequency;\n    _Atomic unsigned long count;\n    bool *stop_flag;\n} z_stats_t;\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, unsigned long *freq, size_t *pkt_size,\n                      bool *is_peer, bool *is_udp);\n\nvoid z_free_with_context(void *ptr, void *context) {\n    (void)context;\n    z_free(ptr);\n}\n\nunsigned long cas_loop(z_stats_t *ctx, unsigned long value) {\n    unsigned long prev_val = atomic_load_explicit(&ctx->count, memory_order_relaxed);\n    unsigned long curr_val = prev_val;\n    while (curr_val != value) {\n        prev_val = curr_val;\n        if (atomic_compare_exchange_weak_explicit(&ctx->count, &curr_val, value, memory_order_acquire,\n                                                  memory_order_relaxed)) {\n            return prev_val;\n        }\n    }\n    return prev_val;\n}\n\nvoid *measure_task(void *ctx) {\n    z_stats_t *stats = (z_stats_t *)ctx;\n    unsigned long sleep_dur_us = 1000000 / stats->frequency;\n    while (!*stats->stop_flag) {\n        z_clock_t start = z_clock_now();\n        z_sleep_us(sleep_dur_us);\n        unsigned long elapsed = z_clock_elapsed_us(&start);\n        // Clear count\n        unsigned long count = cas_loop(stats, 0);\n        if (count > 0) {\n            printf(\"%.3lf\\n\", (double)count * 1000000.0 / (double)elapsed);\n        }\n    }\n    return NULL;\n}\n\nvoid *stop_task(void *ctx) {\n    z_sleep_s(TEST_RUN_TIME_S);\n    bool *stop_flag = (bool *)ctx;\n    *stop_flag = true;\n    return NULL;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"thr\";\n    size_t len = 8;\n    bool is_peer = false;\n    bool is_udp = false;\n\n    z_stats_t *context = malloc(sizeof(z_stats_t));\n    atomic_store_explicit(&context->count, 0, memory_order_relaxed);\n    context->frequency = 10;\n\n    // Calculate max mtu batch size\n    size_t batch_size = 0;\n#if Z_FEATURE_BATCHING == 1\n    uint_fast8_t vle_size = _z_zint_len(len);\n    uint_fast8_t vle_str = _z_zint_len(strlen(keyexpr));\n    size_t msg_size = 0;\n    size_t max_mtu_size = 0;\n    size_t zenoh_overhead = 0;\n    if (is_peer) {\n        if ((is_udp)) {\n            zenoh_overhead = vle_size + vle_str + strlen(keyexpr) + ZENOH_MSH_HDR_SIZE;\n            msg_size = len + zenoh_overhead;\n            max_mtu_size = (ZENOH_UDP_MTU - ZENOH_FRAME_HDR_SIZE);\n        } else {\n            zenoh_overhead = vle_size + ZENOH_MSH_HDR_SIZE;\n            msg_size = len + zenoh_overhead;\n            max_mtu_size = (ZENOH_TCP_PEER_MTU - ZENOH_FRAME_HDR_SIZE);\n        }\n        batch_size = max_mtu_size / msg_size;\n    }\n    if (!is_peer) {\n        zenoh_overhead = vle_size + ZENOH_MSH_HDR_SIZE;\n        msg_size = len + zenoh_overhead;\n        max_mtu_size = (ZENOH_TCP_MTU - ZENOH_FRAME_HDR_SIZE);\n        batch_size = max_mtu_size / msg_size;\n    }\n    if (batch_size < 2) {\n        batch_size = 0;\n    }\n    // double overhead = (double)(ZENOH_FRAME_HDR_SIZE) / (ZENOH_FRAME_HDR_SIZE + (double)(msg_size * batch_size)) +\n    //                   (double)(zenoh_overhead);\n#endif\n\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &context->frequency, &len, &is_peer, &is_udp);\n    if (ret != 0) {\n        return ret;\n    }\n\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n\n    // Timer for sub to prepare\n    z_sleep_s(1);\n    // Declare publisher\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    z_publisher_options_t opts;\n    z_publisher_options_default(&opts);\n    opts.congestion_control = Z_CONGESTION_CONTROL_DROP;\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), &opts) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        exit(-1);\n    }\n\n    uint8_t *value = (uint8_t *)z_malloc(len);\n    memset(value, 1, len);\n\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, value, len, z_free_with_context, NULL);\n\n    bool stop_flag = false;\n    context->stop_flag = &stop_flag;\n    pthread_t task;\n    pthread_create(&task, NULL, measure_task, (void *)context);\n    pthread_t task2;\n    pthread_create(&task2, NULL, stop_task, &stop_flag);\n\n    // Send packets\n    (void)batch_size;\n#if Z_FEATURE_BATCHING == 1\n    if (batch_size > 0) zp_batch_start(z_loan(s));\n#endif\n    z_owned_bytes_t p;\n    while (!stop_flag) {\n        // Clone payload\n        z_bytes_clone(&p, z_loan(payload));\n        z_publisher_put(z_loan(pub), z_move(p), NULL);\n        atomic_fetch_add_explicit(&context->count, 1, memory_order_relaxed);\n    }\n#if Z_FEATURE_BATCHING == 1\n    if (batch_size > 0) zp_batch_stop(z_loan(s));\n#endif\n\n    // Clean up\n    pthread_join(task, NULL);\n    pthread_join(task2, NULL);\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    z_drop(z_move(payload));\n    z_free(context);\n    exit(0);\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, unsigned long *freq, size_t *pkt_size,\n                      bool *is_peer, bool *is_udp) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:f:s:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                if (strncmp(optarg, \"udp\", 3) == 0) {\n                    *is_udp = true;\n                }\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                if (strcmp(optarg, \"peer\") == 0) {\n                    *is_peer = true;\n                }\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                if (strncmp(optarg, \"udp\", 3) == 0) {\n                    *is_udp = true;\n                }\n                break;\n            case 'f':\n                *freq = (unsigned long)atoi(optarg);\n                break;\n            case 's':\n                *pkt_size = (size_t)atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'f' ||\n                    optopt == 's') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pub_tls.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <getopt.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_LINK_TLS == 1\n\nstatic const char SERVER_CA_PEM[] =\n    \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTekNDQWpPZ0F3SUJBZ0lJVGN3djFOMTBu\"\n    \"cUV3RFFZSktvWklodmNOQVFFTEJRQXdJREVlTUJ3R0ExVUUKQXhNVmJXbHVhV05oSUhKdmIzUWdZ\"\n    \"MkVnTkdSall6Sm1NQ0FYRFRJek1ETXdOakUyTkRFd05sb1lEekl4TWpNdwpNekEyTVRZME1UQTJX\"\n    \"akFnTVI0d0hBWURWUVFERXhWdGFXNXBZMkVnY205dmRDQmpZU0EwWkdOak1tWXdnZ0VpCk1BMEdD\"\n    \"U3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzJXVWdON05NbFhJa25ldzFjWGlUV0dt\"\n    \"UzAKMVQxRWpjTk5EQXE3RHFaNy9aVlhyakQ0N3l4VHQ1RU9pT1hLL2NJTktOdzRacS9NS1F2cTlx\"\n    \"dStPYXg0bHdpVgpIYTBpOFNoR0xTdVlJMUhCbFh1NE1tdmRHKzMvU2p3WW9Hc0dhU2hyMHkvUUd6\"\n    \"RDNjRCtEUVpnL1JhYUlQSGxPCk1kbWlVWHhrTWN5NHFhMGhGSjFpbWxKZHEvNlRseDQ2WCswdlJD\"\n    \"aDhua2Vrdk9aUit0N1o1VTRqbjRYRTU0S2wKMFBpd2N5WDh2ZkRaM2VwYS9GU0hadlZRaWVNL2c1\"\n    \"WWg5T2pJS0NrZFdSZzd0RDBJRUdzYVcxMXRFUEo1U2lRcgptRHFkUm5lTXpaS3FZMHhDK1FxWFN2\"\n    \"SWx6cE9qaXU4UFlReDd4dWdhVUZFL25wS1JRZHZoOG9qSEpNZE5BZ01CCkFBR2pnWVl3Z1lNd0Rn\"\n    \"WURWUjBQQVFIL0JBUURBZ0tFTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQkJnZ3IKQmdFRkJR\"\n    \"Y0RBakFTQmdOVkhSTUJBZjhFQ0RBR0FRSC9BZ0VBTUIwR0ExVWREZ1FXQkJUWDQ2K3ArUG8xbnBF\"\n    \"NgpRTFE3bU1JKzgzczZxREFmQmdOVkhTTUVHREFXZ0JUWDQ2K3ArUG8xbnBFNlFMUTdtTUkrODNz\"\n    \"NnFEQU5CZ2txCmhraUc5dzBCQVFzRkFBT0NBUUVBYU4wSXZFQzY3N1BML0pYek1yWGN5QlY4OEl2\"\n    \"aW1sWU4wekN0NDhHWWxobXgKdkwxWVVERkxKRUI3SitkeUVSR0U1TjZCS0tER2JsQzRXaVRGZ0RN\"\n    \"TGNIRnNNR1JjMHY3ektQRjFQU0J3UllKaQp1YkFta3dkdW5HRzVwRFBVWXRURURQWE1sZ0NsWjBZ\"\n    \"eXFTRkpNT3FBNEl6UWc2ZXhWalh0VXhQcXp4Tmh5QzdTCnZsZ1V3UGJYNDZ1Tmk1ODFhOStMczJW\"\n    \"M2ZnMFpuaGtUU2N0WVpIR1pOZWgwTnNmN0FtOHhkVURZRy9iWmNWZWYKamJROWdwQ2hvc2RqRjBC\"\n    \"Z2JsbzdIU1VjdC8yVmErWWxZd1crV0ZqSlg4azRvTjZaVTVXNXhoZGZPOEN6bWd3awpVUzVrSi8r\"\n    \"MU0wdVI4elVoWkhMNjFGYnNkUHhFaitmWUtySHY0d29vK0E9PQotLS0tLUVORCBDRVJUSUZJQ0FU\"\n    \"RS0tLS0tCg==\";\n\nstatic const char SERVER_CERT_PEM[] =\n    \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURMakNDQWhhZ0F3SUJBZ0lJVzFtQXRKV0pB\"\n    \"Sll3RFFZSktvWklodmNOQVFFTEJRQXdJREVlTUJ3R0ExVUUKQXhNVmJXbHVhV05oSUhKdmIzUWdZ\"\n    \"MkVnTkdSall6Sm1NQ0FYRFRJek1ETXdOakUyTkRFd05sb1lEekl4TWpNdwpNekEyTVRZME1UQTJX\"\n    \"akFVTVJJd0VBWURWUVFERXdsc2IyTmhiR2h2YzNRd2dnRWlNQTBHQ1NxR1NJYjNEUUVCCkFRVUFB\"\n    \"NElCRHdBd2dnRUtBb0lCQVFDWU1MSktvb2MrWVJsS0VNZmVWMDlwWDlteUgzNGVVY1V1VDBmWFM4\"\n    \"bG0KUGxaL05XN21tNWxEd2E4RVVnNjFXdVhRdjJvdVFEcHRtSWNkZWIvdzRSVzkzWGZsa3luZzFY\"\n    \"YmQ5MU93UUJKZAorOFpWQmp6TDdoU1JrM1FQRHF4L0NWQlUvSTFHbVhLemI2Y1d6cTFmVGtPbjFX\"\n    \"TE5YZjIxSTZwNytOM3FITFBGCkpRZW9WcTFIQkJGY0FqVGdKbnB5UU52UkdMRHVMVEsrT3NXRUdp\"\n    \"YjJVOHFyZ2lSZGthQkxreEdYU2xHQUJsT28KY1F5Vy96T2hmNHB3YjJaL0pBZ2UybVJXNUljZXhD\"\n    \"UEJXaW50OHlkUHNvSkRkczhqNStBeVlDRDZIVWhIWDBPYgpRa3o3M09XN2YyUFFodVRLMnV6S3kw\"\n    \"WXo2bE5GdDJudXphV0MwNHdJVzNUN0FnTUJBQUdqZGpCME1BNEdBMVVkCkR3RUIvd1FFQXdJRm9E\"\n    \"QWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBUVlJS3dZQkJRVUhBd0l3REFZRFZSMFQKQVFIL0JB\"\n    \"SXdBREFmQmdOVkhTTUVHREFXZ0JUWDQ2K3ArUG8xbnBFNlFMUTdtTUkrODNzNnFEQVVCZ05WSFJF\"\n    \"RQpEVEFMZ2dsc2IyTmhiR2h2YzNRd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFBeHJtUVBHNTR5\"\n    \"YktnTVZsaU44Ck1nNXBvdlNkUElWVm5sVS9IT1ZHOXl4ekFPYXYveFFQMDAzTTR3cXBhdFd4STh0\"\n    \"UjFQY0x1WmYwRVBtY2RKZ2IKdFZsOW5aTVZadHZlUW5ZTWxVOFBwa0VWdTU2Vk00WnIzckg5bGlQ\"\n    \"UmxyMEpFQVhPRGRLdzc2a1dLem1kcVdaLwpyemh1cDNFazdpRVg2VDVqL2NQVXZUV3RNRDRWRUsy\"\n    \"STdmZ29LU0hJWDhNSVZ6cU03Y3Vib0dXUHRTM2VSTlhsCk1ndmFoQTRUd0xFWFBFZStWMVdBcTZu\"\n    \"U2I0ZzJxU1hXSURwSXN5L08xV0dTL3p6Um5Ldlh1OS85TmtYV3FaTWwKQzFMU3BpaVFVYVJTZ2xP\"\n    \"dllmL1p4NnIrNEJPUzRPYWFBcndIa2VjWlFxQlNDY0JMRUF5Yi9GYWFYZEJvd0kwVQpQUTQ9Ci0t\"\n    \"LS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\";\n\nstatic const char SERVER_KEY_PEM[] =\n    \"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBbURDeVNxS0hQ\"\n    \"bUVaU2hESDNsZFBhVi9ac2g5K0hsSEZMazlIMTB2SlpqNVdmelZ1CjVwdVpROEd2QkZJT3RWcmww\"\n    \"TDlxTGtBNmJaaUhIWG0vOE9FVnZkMTM1Wk1wNE5WMjNmZFRzRUFTWGZ2R1ZRWTgKeSs0VWtaTjBE\"\n    \"dzZzZndsUVZQeU5ScGx5czIrbkZzNnRYMDVEcDlWaXpWMzl0U09xZS9qZDZoeXp4U1VIcUZhdApS\"\n    \"d1FSWEFJMDRDWjZja0RiMFJpdzdpMHl2anJGaEJvbTlsUEtxNElrWFpHZ1M1TVJsMHBSZ0FaVHFI\"\n    \"RU1sdjh6Cm9YK0tjRzltZnlRSUh0cGtWdVNISHNRandWb3A3Zk1uVDdLQ1EzYlBJK2ZnTW1BZyto\"\n    \"MUlSMTlEbTBKTSs5emwKdTM5ajBJYmt5dHJzeXN0R00rcFRSYmRwN3MybGd0T01DRnQwK3dJREFR\"\n    \"QUJBb0lCQUROVFNPMnV2bG1sT1hnbgpES0RKWlRpdVlLYVh4RnJKVE94L1JFVXhnK3g5WFlKdExN\"\n    \"ZU05alZKbnBLZ2NlRnJsRkhBSERrWTVCdU44eE5YCnVnbXNmejZXOEJaMmVRc2dNb1JOSXVZdjFZ\"\n    \"SG9wVXlMVy9tU2cxRk5Iempzdy9QYjJrR3ZJcDRLcGdvcHYzb0wKbmFDa3JtQnRzSEorSGsvMmhV\"\n    \"cGw5Y0U4aU13VldjVmV2THp5SGk5OGpOeTFJRGRJUGhSdGwwZGhNaXFDNU1Scgo0Z0xKNWdOa0xZ\"\n    \"WDd4ZjN0dzVIbWZrL2JWTlByb3FaWERJUVZJN3JGdkl0WDU4Nm52UTNMTlFrbVcvRDJTaFpmCjNG\"\n    \"RXFNdTZFZEEyWWNjNFVaZ0FsUU5HVjBWQnJXV1ZYaXpPUSs5Z2pMbkJrM2tKanFmaWdDVTZORzk0\"\n    \"YlRKK0gKMFlJaHNHRUNnWUVBd2RTU3l1TVNPWGd6WlE3VnYrR3NObi83aXZpL0g4ZWIvbER6a3Nx\"\n    \"Uy9Kcm9BMmNpQW1IRwoyT0YzMGVVSktSZytTVHFCVHBPZlhnUzRRVWE4UUxTd0JTbndjdzY1Nzl4\"\n    \"OWJZR1VocUQyWXBhdzl1Q25PdWtBCkN3d2dnWjljRG1GMHRiNXJZanFrVzNiRlBxa0NuVEdiMHls\"\n    \"TUZhWVJoUkRVMjBpRzV0OFBRY2tDZ1lFQXlRRU0KS0sxOEZMUVVLaXZHclFnUDVJYjZJQzNteXps\"\n    \"SEd4RHpmb2JYR3BhUW50Rm5IWTdDeHAvNkJCdG1BU3p0OUp4dQpldG5yZXZtenJiS3FzTFRKU2cz\"\n    \"aXZiaXEwWVRMQUoxRnNackNwNzFkeDQ5WVIvNW85UUZpcTBuUW9LbndVVmViCi9ockRqTUFva05r\"\n    \"akZMNXZvdVhPNzExR1NTNll5TTRXekFLWkFxTUNnWUVBaHFHeGFHMDZqbUo0U0Z4NmliSWwKblNG\"\n    \"ZVJoUXJKTmJQK21DZUhycklSOThOQXJnUy9sYU4rTHo3TGZhSlcxcjBnSWE3cENtVGk0bDV0aFY4\"\n    \"MHZEdQpSbGZ3Sk9yNHFhdWNENER1K21nNVd4ZFNTZGlYTDZzQmxhclJ0VmRNYU15MmRUcVRlZ0pE\"\n    \"Z1NoSkx4SFR0LzNxClAweXpCV0o1VHRUM0ZHMFhEcXVtL0VrQ2dZQVlOSHdXV2UzYlFHUTlQOUJJ\"\n    \"L2ZPTC9ZVVpZdTJzQTFYQXVLWFoKMHJzTWhKMGR3dkc3NlhrakdoaXRiZTgyclFacXNudkxaM3Fu\"\n    \"OEhIbXRPRkJMa1FmR3RUM0s4bkdPVXVJNDJlRgpIN0haS1VDbHkybENJaXpaZERWQmt6NEFXdmFK\"\n    \"bFJjLzNsRTJIZDNFczZFNTJrVHZST1ZLaGR6MDZ4dVM4dDVqCjZ0d3FLUUtCZ1FDMDFBZWlXTDZS\"\n    \"em8reVpOelZnYnBlZURvZ2FaejVkdG1VUkRnQ1lIOHlGWDVlb0NLTEhmbkkKMm5ESW9xcGFIWTBM\"\n    \"dVgrZGludUgralA0dGx5bmRiYzJtdVhuSGQ5cjBhdHl0eEE2OWF5M3NTQTVXRnRmaTRlZgpFU0Vs\"\n    \"R082cVhFQTgyMVJwUXArMit1aEw5MCtpQzI5NGNQcWxTNUxEbXZUTXlwVkRIenJ4UFE9PQotLS0t\"\n    \"LUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=\";\n\n#if Z_FEATURE_MATCHING == 1\nstatic void matching_status_handler(const z_matching_status_t *matching_status, void *arg) {\n    (void)arg;\n    if (matching_status->matching) {\n        printf(\"Publisher has matching subscribers.\\n\");\n    } else {\n        printf(\"Publisher has NO MORE matching subscribers.\\n\");\n    }\n}\n#endif\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    char *const default_value = \"Pub from Pico!\";\n    char *value = default_value;\n    int repeat = 2147483647;\n    bool add_matching_listener = false;\n    bool has_listen = false;\n    bool enable_mtls = false;\n    bool enable_verify_name = false;\n    const char *ca_path = NULL;\n    const char *listen_key_path = NULL;\n    const char *listen_cert_path = NULL;\n    const char *client_key_path = NULL;\n    const char *client_cert_path = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"hk:v:e:m:l:n:aC:P:Q:R:S:MV\")) != -1) {\n        switch (opt) {\n            case 'h':\n                printf(\"Usage: %s [options]\\n\", argv[0]);\n                printf(\"  -k <keyexpr>  Key expression (default: demo/example/zenoh-pico-pub)\\n\");\n                printf(\"  -v <value>    Payload value (default: \\\"Pub from Pico!\\\")\\n\");\n                printf(\"  -n <count>    Number of samples to publish (default: infinite)\\n\");\n                printf(\"  -e <locator>  Add connect locator (e.g., tls/127.0.0.1:7447)\\n\");\n                printf(\"  -l <locator>  Set listen locator (e.g., tls/0.0.0.0:7447)\\n\");\n                printf(\"  -m <mode>     Session mode: client or peer (default: client)\\n\");\n                printf(\"  -C <file>     CA bundle path (optional; inline bundle used otherwise)\\n\");\n                printf(\"  -P <file>     Listener private key path (peers)\\n\");\n                printf(\"  -Q <file>     Listener certificate path (peers)\\n\");\n                printf(\"  -R <file>     Client private key path (mTLS)\\n\");\n                printf(\"  -S <file>     Client certificate path (mTLS)\\n\");\n                printf(\"  -M            Enable mutual TLS (client authentication)\\n\");\n                printf(\"  -V            Enable hostname verification on connect\\n\");\n                printf(\"  -a            Enable matching listener\\n\");\n                printf(\"  -h            Show this help message\\n\");\n                z_drop(z_move(config));\n                return 0;\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'v':\n                value = optarg;\n                break;\n            case 'e':\n                if (zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, optarg) != Z_OK) {\n                    fprintf(stderr, \"Failed to add connect locator\\n\");\n                    z_drop(z_move(config));\n                    return -1;\n                }\n                break;\n            case 'm':\n                if (zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, optarg) != Z_OK) {\n                    fprintf(stderr, \"Failed to set session mode\\n\");\n                    z_drop(z_move(config));\n                    return -1;\n                }\n                break;\n            case 'l':\n                if (zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, optarg) != Z_OK) {\n                    fprintf(stderr, \"Failed to set listen locator\\n\");\n                    z_drop(z_move(config));\n                    return -1;\n                }\n                has_listen = true;\n                break;\n            case 'n':\n                repeat = atoi(optarg);\n                break;\n            case 'a':\n                add_matching_listener = true;\n                break;\n            case 'C':\n                ca_path = optarg;\n                break;\n            case 'P':\n                listen_key_path = optarg;\n                break;\n            case 'Q':\n                listen_cert_path = optarg;\n                break;\n            case 'R':\n                client_key_path = optarg;\n                break;\n            case 'S':\n                client_cert_path = optarg;\n                break;\n            case 'M':\n                enable_mtls = true;\n                break;\n            case 'V':\n                enable_verify_name = true;\n                break;\n            default:\n                z_drop(z_move(config));\n                return -1;\n        }\n    }\n\n    if (ca_path) {\n        if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY, ca_path) != Z_OK) {\n            fprintf(stderr, \"Failed to set CA certificate path\\n\");\n            z_drop(z_move(config));\n            return -1;\n        }\n    } else {\n        if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY, SERVER_CA_PEM) != Z_OK) {\n            fprintf(stderr, \"Failed to set inline CA certificate\\n\");\n            z_drop(z_move(config));\n            return -1;\n        }\n    }\n\n    if (has_listen) {\n        if (listen_key_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_KEY, listen_key_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set listener private key path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_BASE64_KEY, SERVER_KEY_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline listener private key\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n\n        if (listen_cert_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_CERTIFICATE_KEY, listen_cert_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set listener certificate path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_CERTIFICATE_BASE64_KEY, SERVER_CERT_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline listener certificate\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n    }\n\n    if (enable_mtls) {\n        if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_ENABLE_MTLS_KEY, \"true\") != Z_OK) {\n            fprintf(stderr, \"Failed to enable mTLS\\n\");\n            z_drop(z_move(config));\n            return -1;\n        }\n\n        if (client_key_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_KEY, client_key_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set client private key path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_BASE64_KEY, SERVER_KEY_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline client private key\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n\n        if (client_cert_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_CERTIFICATE_KEY, client_cert_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set client certificate path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_CERTIFICATE_BASE64_KEY, SERVER_CERT_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline client certificate\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n    }\n\n    if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_VERIFY_NAME_ON_CONNECT_KEY,\n                         enable_verify_name ? \"true\" : \"false\") != Z_OK) {\n        fprintf(stderr, \"Failed to configure hostname verification\\n\");\n        z_drop(z_move(config));\n        return -1;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t session;\n    if (z_open(&session, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        z_drop(z_move(session));\n        return -1;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(session), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        z_drop(z_move(session));\n        return -1;\n    }\n\n    if (add_matching_listener) {\n#if Z_FEATURE_MATCHING == 1\n        z_owned_closure_matching_status_t callback;\n        z_closure(&callback, matching_status_handler, NULL, NULL);\n        z_publisher_declare_background_matching_listener(z_loan(pub), z_move(callback));\n#else\n        printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_MATCHING but this example requires it.\\n\");\n        z_drop(z_move(pub));\n        z_drop(z_move(session));\n        return -2;\n#endif\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    for (int idx = 0; idx < repeat; ++idx) {\n        z_sleep_s(1);\n        char buf[256];\n        snprintf(buf, sizeof(buf), \"[%4d] %s\", idx, value);\n        printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n\n    z_drop(z_move(pub));\n    z_drop(z_move(session));\n    return 0;\n}\n\n#else\nint main(void) {\n#if Z_FEATURE_PUBLICATION != 1\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n#elif Z_FEATURE_LINK_TLS != 1\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_LINK_TLS but this example requires it.\\n\");\n#endif\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_pull.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, size_t *interval,\n                      size_t *ring_size);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    size_t interval = 5000;\n    size_t ring_size = 3;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &interval, &ring_size);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, ring_size);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", interval, ring_size);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &sample); res == Z_OK; res = z_try_recv(z_loan(handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n            z_drop(z_move(value));\n            z_drop(z_move(sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", interval);\n            z_sleep_ms(interval);\n        } else {\n            break;\n        }\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, size_t *interval,\n                      size_t *ring_size) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:i:s:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'i':\n                *interval = (size_t)atoi(optarg);\n                break;\n            case 's':\n                *ring_size = (size_t)atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'i' || optopt == 's' || optopt == 'e' || optopt == 'm' ||\n                    optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_put.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#include \"zenoh-pico/api/macros.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#if Z_FEATURE_PUBLICATION == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/zenoh-pico-put\";\n    char *const default_value = \"Pub from Pico!\";\n    char *value = default_value;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring key expression '%s'...\\n\", keyexpr);\n    z_view_keyexpr_t vke;\n    if (z_view_keyexpr_from_str(&vke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    z_owned_keyexpr_t ke;\n    if (z_declare_keyexpr(z_loan(s), &ke, z_loan(vke)) < 0) {\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, value);\n\n    printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, value);\n    if (z_put(z_loan(s), z_loan(ke), z_move(payload), NULL) < 0) {\n        printf(\"Oh no! Put has failed...\\n\");\n    }\n    // Clean up\n    z_undeclare_keyexpr(z_loan(s), z_move(ke));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, char **value) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_querier.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <limits.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **selector, char **value, int *n,\n                      int *timeout_ms, bool *add_matching_listener);\n\n#if Z_FEATURE_MATCHING == 1\nvoid matching_status_handler(const z_matching_status_t *matching_status, void *arg) {\n    (void)arg;\n    if (matching_status->matching) {\n        printf(\"Querier has matching queryable.\\n\");\n    } else {\n        printf(\"Querier has NO MORE matching queryables.\\n\");\n    }\n}\n#endif\n\nint main(int argc, char **argv) {\n    char *selector = \"demo/example/**\";\n    char *value = NULL;\n    int n = INT_MAX;\n    int timeout_ms = 0;\n    bool add_matching_listener = false;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &selector, &value, &n, &timeout_ms, &add_matching_listener);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    const char *ke = selector;\n    size_t ke_len = strlen(ke);\n    const char *params = strchr(selector, '?');\n    if (params != NULL) {\n        ke_len = (size_t)(params - ke);\n        params += 1;\n    }\n\n    z_view_keyexpr_t keyexpr;\n    if (z_view_keyexpr_from_substr(&keyexpr, ke, ke_len) < 0) {\n        printf(\"%.*s is not a valid key expression\\n\", (int)ke_len, ke);\n        exit(-1);\n    }\n\n    printf(\"Declaring Querier on '%s'...\\n\", ke);\n    z_owned_querier_t querier;\n\n    z_querier_options_t opts;\n    z_querier_options_default(&opts);\n    opts.timeout_ms = (uint64_t)timeout_ms;\n\n    if (z_declare_querier(z_loan(s), &querier, z_loan(keyexpr), &opts) < 0) {\n        printf(\"Unable to declare Querier for key expression!\\n\");\n        exit(-1);\n    }\n\n    if (add_matching_listener) {\n#if Z_FEATURE_MATCHING == 1\n        z_owned_closure_matching_status_t callback;\n        z_closure(&callback, matching_status_handler, NULL, NULL);\n        z_querier_declare_background_matching_listener(z_loan(querier), z_move(callback));\n#else\n        printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_MATCHING but this example requires it.\\n\");\n        return -2;\n#endif\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    char buf[256];\n    for (int idx = 0; idx != n; ++idx) {\n        z_sleep_s(1);\n        sprintf(buf, \"[%4d] %s\", idx, value ? value : \"\");\n        printf(\"Querying '%s' with payload '%s'...\\n\", selector, buf);\n        z_querier_get_options_t get_options;\n        z_querier_get_options_default(&get_options);\n\n        if (value != NULL) {\n            z_owned_bytes_t payload;\n            z_bytes_copy_from_str(&payload, buf);\n            get_options.payload = z_move(payload);\n        }\n\n        z_owned_fifo_handler_reply_t handler;\n        z_owned_closure_reply_t closure;\n        z_fifo_channel_reply_new(&closure, &handler, 16);\n\n        z_querier_get(z_loan(querier), params, z_move(closure), &get_options);\n\n        z_owned_reply_t reply;\n        for (z_result_t res = z_recv(z_loan(handler), &reply); res == Z_OK; res = z_recv(z_loan(handler), &reply)) {\n            if (z_reply_is_ok(z_loan(reply))) {\n                const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n\n                z_view_string_t keystr;\n                z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n\n                z_owned_string_t replystr;\n                z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n                printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                       z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(replystr)),\n                       z_string_data(z_loan(replystr)));\n                z_drop(z_move(replystr));\n            } else {\n                printf(\">> Received an error\\n\");\n            }\n            z_drop(z_move(reply));\n        }\n        z_drop(z_move(handler));\n    }\n\n    z_drop(z_move(querier));\n    z_drop(z_move(s));\n\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **selector, char **value, int *n,\n                      int *timeout_ms, bool *add_matching_listener) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"s:v:e:m:l:n:t:a\")) != -1) {\n        switch (opt) {\n            case 's':\n                *selector = optarg;\n                break;\n            case 'v':\n                *value = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case 't':\n                *timeout_ms = atoi(optarg);\n                break;\n            case 'a':\n                *add_matching_listener = true;\n                break;\n            case '?':\n                if (optopt == 's' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 't' || optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\ntypedef enum _reply_kind_e { REPLY_DATA, REPLY_DELETE, REPLY_ERR } _reply_kind_e;\n\n#if Z_FEATURE_QUERYABLE == 1\nchar *keyexpr = \"demo/example/zenoh-pico-queryable\";\nchar *value = \"Queryable from Pico!\";\nchar *error = \"Demo error\";\nstatic int msg_nb = 0;\nstatic _reply_kind_e reply_kind = REPLY_DATA;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, char **val, int *n,\n                      _reply_kind_e *reply_kind);\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n\n    switch (reply_kind) {\n        case REPLY_DATA: {\n            // Reply value encoding\n            z_owned_bytes_t reply_payload;\n            z_bytes_from_static_str(&reply_payload, value);\n\n            z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n            break;\n        }\n        case REPLY_DELETE: {\n            z_query_reply_del(query, z_query_keyexpr(query), NULL);\n            break;\n        }\n        case REPLY_ERR: {\n            // Reply error encoding\n            z_owned_bytes_t reply_payload;\n            z_bytes_from_static_str(&reply_payload, error);\n\n            z_query_reply_err(query, z_move(reply_payload), NULL);\n            break;\n        }\n    }\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    int n = 0;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value, &n, &reply_kind);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        if ((n != 0) && (msg_nb >= n)) {\n            break;\n        }\n        sleep(1);\n    }\n\n    z_drop(z_move(qable));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, char **val, int *n,\n                      _reply_kind_e *repknd) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'v':\n                *val = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case 'd':\n                *repknd = REPLY_DELETE;\n                break;\n            case 'f':\n                *repknd = REPLY_ERR;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_queryable_attachment.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\ntypedef struct kv_pair_t {\n    z_owned_string_t key;\n    z_owned_string_t value;\n} kv_pair_t;\n\n#if Z_FEATURE_QUERYABLE == 1\nchar *keyexpr = \"demo/example/zenoh-pico-queryable\";\nchar *const default_value = \"Queryable from Pico!\";\nchar *value = default_value;\nint msg_nb = 0;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, char **val, int *n);\n\nvoid print_attachment(const kv_pair_t *kvp, size_t len) {\n    printf(\"    with attachment:\\n\");\n    for (size_t i = 0; i < len; i++) {\n        printf(\"     %zu: %.*s, %.*s\\n\", i, (int)z_string_len(z_loan(kvp[i].key)), z_string_data(z_loan(kvp[i].key)),\n               (int)z_string_len(z_loan(kvp[i].value)), z_string_data(z_loan(kvp[i].value)));\n    }\n}\n\nvoid drop_attachment(kv_pair_t *kvp, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        z_drop(z_move(kvp[i].key));\n        z_drop(z_move(kvp[i].value));\n    }\n}\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process encoding\n    z_owned_string_t encoding;\n    z_encoding_to_string(z_query_encoding(query), &encoding);\n    printf(\"    with encoding: %.*s\\n\", (int)z_string_len(z_loan(encoding)), z_string_data(z_loan(encoding)));\n\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"    with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n    z_drop(z_move(encoding));\n\n    // Check attachment\n    const z_loaned_bytes_t *attachment = z_query_attachment(query);\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(attachment);\n    size_t attachment_len;\n    if (ze_deserializer_deserialize_sequence_length(&deserializer, &attachment_len) == Z_OK) {\n        kv_pair_t *kvp = (kv_pair_t *)malloc(sizeof(kv_pair_t) * attachment_len);\n        for (size_t i = 0; i < attachment_len; ++i) {\n            ze_deserializer_deserialize_string(&deserializer, &kvp[i].key);\n            ze_deserializer_deserialize_string(&deserializer, &kvp[i].value);\n        }\n        if (attachment_len > 0) {\n            print_attachment(kvp, attachment_len);\n        }\n        drop_attachment(kvp, attachment_len);\n        free(kvp);\n    }\n\n    // Reply payload\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, value);\n\n    z_query_reply_options_t options;\n    z_query_reply_options_default(&options);\n\n    // Reply attachment\n    z_owned_bytes_t reply_attachment;\n    kv_pair_t kvs[1];\n    z_string_from_str(&kvs[0].key, \"reply_key\", NULL, NULL);\n    z_string_from_str(&kvs[0].value, \"reply_value\", NULL, NULL);\n    ze_owned_serializer_t serializer;\n    ze_serializer_empty(&serializer);\n    ze_serializer_serialize_sequence_length(z_loan_mut(serializer), 1);\n    ze_serializer_serialize_string(z_loan_mut(serializer), z_loan(kvs[0].key));\n    ze_serializer_serialize_string(z_loan_mut(serializer), z_loan(kvs[0].value));\n    ze_serializer_finish(z_move(serializer), &reply_attachment);\n    options.attachment = z_move(reply_attachment);\n    drop_attachment(kvs, 1);\n\n    // Reply encoding\n    z_owned_encoding_t reply_encoding;\n    z_encoding_from_str(&reply_encoding, \"zenoh/string;utf8\");\n    options.encoding = z_move(reply_encoding);\n\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), &options);\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    int n = 0;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value, &n);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        if ((n != 0) && (msg_nb >= n)) {\n            break;\n        }\n        sleep(1);\n    }\n\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, char **val, int *n) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'v':\n                *val = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_queryable_channel.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\nchar *keyexpr = \"demo/example/zenoh-pico-queryable\";\nchar *const default_value = \"Queryable from Pico!\";\nchar *value = default_value;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, char **val);\n\nint main(int argc, char **argv) {\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &value);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr);\n    z_owned_closure_query_t closure;\n    z_owned_ring_handler_query_t handler;\n    z_ring_channel_query_new(&closure, &handler, 10);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return -1;\n    }\n\n    z_owned_query_t query;\n    for (z_result_t res = z_recv(z_loan(handler), &query); res == Z_OK; res = z_recv(z_loan(handler), &query)) {\n        const z_loaned_query_t *q = z_loan(query);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_query_keyexpr(q), &keystr);\n        z_view_string_t params;\n        z_query_parameters(q, &params);\n        printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n               z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n        // Process value\n        z_owned_string_t payload_string;\n        z_bytes_to_string(z_query_payload(z_loan(query)), &payload_string);\n        if (z_string_len(z_loan(payload_string)) > 0) {\n            printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n                   z_string_data(z_loan(payload_string)));\n        }\n        z_drop(z_move(payload_string));\n\n        z_query_reply_options_t options;\n        z_query_reply_options_default(&options);\n        // Reply value encoding\n        z_owned_bytes_t reply_payload;\n        z_bytes_from_static_str(&reply_payload, value);\n\n        z_query_reply(q, z_query_keyexpr(q), z_move(reply_payload), &options);\n        z_drop(z_move(query));\n    }\n\n    z_drop(z_move(handler));\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, char **val) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'v':\n                *val = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_queryable_lat.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdatomic.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n\n#include \"zenoh-pico.h\"\n\ntypedef struct {\n    uint8_t *payload;\n    size_t payload_len;\n} z_stats_t;\n\n#define TEST_RUN_TIME_S 20\n\n#if Z_FEATURE_QUERYABLE == 1 && Z_FEATURE_MULTI_THREAD == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, size_t *pkt_size);\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    z_stats_t *stats = (z_stats_t *)ctx;\n\n    // Reply\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_buf(&reply_payload, stats->payload, stats->payload_len);\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n    z_drop(z_move(reply_payload));\n}\n\nvoid drop_stats(void *context) {\n    z_stats_t *stats = (z_stats_t *)context;\n    free(stats->payload);\n    free(context);\n}\n\nvoid *stop_task(void *ctx) {\n    z_sleep_s(TEST_RUN_TIME_S);\n    _Atomic int *stop_flag = (_Atomic int *)ctx;\n    atomic_store_explicit(stop_flag, 1, memory_order_relaxed);\n    return NULL;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"lat\";\n    size_t payload_len = 8;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &payload_len);\n    if (ret != 0) {\n        return ret;\n    }\n\n    z_stats_t *context = malloc(sizeof(z_stats_t));\n    context->payload_len = payload_len;\n    context->payload = (uint8_t *)malloc(context->payload_len);\n    memset(context->payload, 1, context->payload_len);\n\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n\n    // Declare Queryable\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, keyexpr);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, drop_stats, (void *)context);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return -1;\n    }\n    _Atomic int stop_flag;\n    atomic_store_explicit(&stop_flag, 0, memory_order_relaxed);\n    pthread_t task;\n    pthread_create(&task, NULL, stop_task, &stop_flag);\n\n    // Listen until stopped\n    while (atomic_load_explicit(&stop_flag, memory_order_relaxed) == 0) {\n        z_sleep_s(1);\n    }\n    pthread_join(task, NULL);\n    // Clean up\n    z_drop(z_move(qable));\n    z_drop(z_move(s));\n    exit(0);\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, size_t *pkt_size) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:s:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 's':\n                *pkt_size = (size_t)atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 's') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_loan(s)), z_string_data(z_loan(s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_move(config), z_move(closure), NULL);\n    sleep(1);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\nstatic int msg_nb = 0;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n);\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    int n = 0;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &n);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        if ((n != 0) && (msg_nb >= n)) {\n            break;\n        }\n        sleep(1);\n    }\n    // Clean up\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, int *n) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub_attachment.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <inttypes.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\ntypedef struct kv_pair_t {\n    z_owned_string_t key;\n    z_owned_string_t value;\n} kv_pair_t;\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\nstatic int msg_nb = 0;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n);\n\nvoid print_attachment(const kv_pair_t *kvp, size_t len) {\n    printf(\"    with attachment:\\n\");\n    for (size_t i = 0; i < len; i++) {\n        printf(\"     %zu: %.*s, %.*s\\n\", i, (int)z_string_len(z_loan(kvp[i].key)), z_string_data(z_loan(kvp[i].key)),\n               (int)z_string_len(z_loan(kvp[i].value)), z_string_data(z_loan(kvp[i].value)));\n    }\n}\n\nvoid drop_attachment(kv_pair_t *kvp, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        z_drop(z_move(kvp[i].key));\n        z_drop(z_move(kvp[i].value));\n    }\n}\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    z_owned_string_t encoding;\n    z_encoding_to_string(z_sample_encoding(sample), &encoding);\n\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    printf(\"    with encoding: %.*s\\n\", (int)z_string_len(z_loan(encoding)), z_string_data(z_loan(encoding)));\n\n    // Check timestamp\n    const z_timestamp_t *ts = z_sample_timestamp(sample);\n    if (ts != NULL) {\n        printf(\"    with timestamp: %\" PRIu64 \"\\n\", z_timestamp_ntp64_time(ts));\n    }\n    // Check attachment\n    const z_loaned_bytes_t *attachment = z_sample_attachment(sample);\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(attachment);\n    size_t attachment_len;\n    if (ze_deserializer_deserialize_sequence_length(&deserializer, &attachment_len) == Z_OK) {\n        kv_pair_t *kvp = (kv_pair_t *)malloc(sizeof(kv_pair_t) * attachment_len);\n        for (size_t i = 0; i < attachment_len; ++i) {\n            ze_deserializer_deserialize_string(&deserializer, &kvp[i].key);\n            ze_deserializer_deserialize_string(&deserializer, &kvp[i].value);\n        }\n        if (attachment_len > 0) {\n            print_attachment(kvp, attachment_len);\n        }\n        drop_attachment(kvp, attachment_len);\n        free(kvp);\n    }\n\n    z_drop(z_move(value));\n    z_drop(z_move(encoding));\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    int n = 0;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &n);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        if ((n != 0) && (msg_nb >= n)) {\n            break;\n        }\n        sleep(1);\n    }\n    // Clean up\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub_channel.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr);\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    z_fifo_channel_sample_new(&closure, &handler, 3);\n\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    z_owned_sample_t sample;\n    for (z_result_t res = z_recv(z_loan(handler), &sample); res == Z_OK; res = z_recv(z_loan(handler), &sample)) {\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n        z_owned_string_t value;\n        z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n        printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n               z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n        z_drop(z_move(value));\n        z_drop(z_move(sample));\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub_liveliness.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_LIVELINESS == 1\n\nstatic volatile int msg_nb = 0;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n, bool *history);\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t key_string;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_string);\n    switch (z_sample_kind(sample)) {\n        case Z_SAMPLE_KIND_PUT:\n            printf(\">> [LivelinessSubscriber] New alive token ('%.*s')\\n\", (int)z_string_len(z_loan(key_string)),\n                   z_string_data(z_loan(key_string)));\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            printf(\">> [LivelinessSubscriber] Dropped token ('%.*s')\\n\", (int)z_string_len(z_loan(key_string)),\n                   z_string_data(z_loan(key_string)));\n            break;\n    }\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"group1/**\";\n    bool history = false;\n    int n = 0;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &n, &history);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // Start admin space\n    if (zp_start_admin_space(z_loan_mut(s)) < 0) {\n        printf(\"Unable to start admin space\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n#endif\n\n    printf(\"Declaring liveliness subscriber on '%s'...\\n\", keyexpr);\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    z_owned_subscriber_t sub;\n\n    z_liveliness_subscriber_options_t sub_opt;\n    z_liveliness_subscriber_options_default(&sub_opt);\n    sub_opt.history = history;\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_liveliness_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), &sub_opt) < 0) {\n        printf(\"Unable to declare liveliness subscriber.\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        if (n != 0 && msg_nb >= n) {\n            break;\n        }\n        z_sleep_s(1);\n    }\n\n    // Clean up\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n, bool *history) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:n:h\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case 'h':\n                *history = true;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION and Z_FEATURE_LIVELINESS but this example \"\n        \"requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_MULTI_THREAD == 0\n\nstatic int msg_nb = 0;\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n);\n\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    int n = 2147483647;  // max int value by default\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &n);\n    if (ret != 0) {\n        return ret;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (msg_nb < n) {\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    return 0;\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **keyexpr, int *n) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *keyexpr = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'n':\n                *n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_SUBSCRIPTION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub_thr.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdatomic.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n\n#include \"zenoh-pico.h\"\n\n#define TEST_RUN_TIME_S 23\n\ntypedef struct {\n    _Atomic unsigned long count;\n} z_stats_t;\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_MULTI_THREAD == 1\n\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, unsigned long *freq, bool *is_peer);\n\nvoid on_sample(z_loaned_sample_t *sample, void *context) {\n    (void)sample;\n    z_stats_t *stats = (z_stats_t *)context;\n    atomic_fetch_add_explicit(&stats->count, 1, memory_order_relaxed);\n}\n\nvoid drop_stats(void *context) { free(context); }\n\nunsigned long cas_loop(z_stats_t *ctx, unsigned long value) {\n    unsigned long prev_val = atomic_load_explicit(&ctx->count, memory_order_relaxed);\n    unsigned long curr_val = prev_val;\n    while (curr_val != value) {\n        prev_val = curr_val;\n        if (atomic_compare_exchange_weak_explicit(&ctx->count, &curr_val, value, memory_order_acquire,\n                                                  memory_order_relaxed)) {\n            return prev_val;\n        }\n    }\n    return prev_val;\n}\n\nvoid *stop_task(void *ctx) {\n    z_sleep_s(TEST_RUN_TIME_S);\n    bool *stop_flag = (bool *)ctx;\n    *stop_flag = true;\n    return NULL;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"thr\";\n    unsigned long frequency = 10;\n    bool is_peer = false;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int ret = parse_args(argc, argv, &config, &keyexpr, &frequency, &is_peer);\n    if (ret != 0) {\n        return ret;\n    }\n\n    z_stats_t *context = malloc(sizeof(z_stats_t));\n    atomic_store_explicit(&context->count, 0, memory_order_relaxed);\n\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n\n    // Declare Subscriber/resource\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, on_sample, drop_stats, (void *)context);\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_background_subscriber(z_loan(s), z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create subscriber.\\n\");\n        exit(-1);\n    }\n    bool stop_flag = false;\n    pthread_t task;\n    pthread_create(&task, NULL, stop_task, &stop_flag);\n    unsigned long sleep_dur_us = 1000000 / frequency;\n    // Listen until stopped\n    while (!stop_flag) {\n        z_clock_t start = z_clock_now();\n        z_sleep_us(sleep_dur_us);\n        unsigned long elapsed = z_clock_elapsed_us(&start);\n        // Clear count\n        unsigned long count = cas_loop(context, 0);\n        if (count > 0) {\n            printf(\"%.3lf\\n\", (double)count * 1000000.0 / (double)elapsed);\n        }\n    }\n    // Clean up\n    z_drop(z_move(s));\n    exit(0);\n}\n\n// Note: All args can be specified multiple times. For \"-e\" it will append the list of endpoints, for the other it will\n// simply replace the previous value.\nstatic int parse_args(int argc, char **argv, z_owned_config_t *config, char **ke, unsigned long *freq, bool *is_peer) {\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:f:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                *ke = optarg;\n                break;\n            case 'e':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_CONNECT_KEY, optarg);\n                break;\n            case 'm':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_MODE_KEY, optarg);\n                if (strcmp(optarg, \"peer\") == 0) {\n                    *is_peer = true;\n                }\n                break;\n            case 'l':\n                zp_config_insert(z_loan_mut(*config), Z_CONFIG_LISTEN_KEY, optarg);\n                break;\n            case 'f':\n                *freq = (unsigned long)atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'f') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c11/z_sub_tls.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <getopt.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_LINK_TLS == 1\n\nstatic const char SERVER_CA_PEM[] =\n    \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTekNDQWpPZ0F3SUJBZ0lJVGN3djFOMTBu\"\n    \"cUV3RFFZSktvWklodmNOQVFFTEJRQXdJREVlTUJ3R0ExVUUKQXhNVmJXbHVhV05oSUhKdmIzUWdZ\"\n    \"MkVnTkdSall6Sm1NQ0FYRFRJek1ETXdOakUyTkRFd05sb1lEekl4TWpNdwpNekEyTVRZME1UQTJX\"\n    \"akFnTVI0d0hBWURWUVFERXhWdGFXNXBZMkVnY205dmRDQmpZU0EwWkdOak1tWXdnZ0VpCk1BMEdD\"\n    \"U3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzJXVWdON05NbFhJa25ldzFjWGlUV0dt\"\n    \"UzAKMVQxRWpjTk5EQXE3RHFaNy9aVlhyakQ0N3l4VHQ1RU9pT1hLL2NJTktOdzRacS9NS1F2cTlx\"\n    \"dStPYXg0bHdpVgpIYTBpOFNoR0xTdVlJMUhCbFh1NE1tdmRHKzMvU2p3WW9Hc0dhU2hyMHkvUUd6\"\n    \"RDNjRCtEUVpnL1JhYUlQSGxPCk1kbWlVWHhrTWN5NHFhMGhGSjFpbWxKZHEvNlRseDQ2WCswdlJD\"\n    \"aDhua2Vrdk9aUit0N1o1VTRqbjRYRTU0S2wKMFBpd2N5WDh2ZkRaM2VwYS9GU0hadlZRaWVNL2c1\"\n    \"WWg5T2pJS0NrZFdSZzd0RDBJRUdzYVcxMXRFUEo1U2lRcgptRHFkUm5lTXpaS3FZMHhDK1FxWFN2\"\n    \"SWx6cE9qaXU4UFlReDd4dWdhVUZFL25wS1JRZHZoOG9qSEpNZE5BZ01CCkFBR2pnWVl3Z1lNd0Rn\"\n    \"WURWUjBQQVFIL0JBUURBZ0tFTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQkJnZ3IKQmdFRkJR\"\n    \"Y0RBakFTQmdOVkhSTUJBZjhFQ0RBR0FRSC9BZ0VBTUIwR0ExVWREZ1FXQkJUWDQ2K3ArUG8xbnBF\"\n    \"NgpRTFE3bU1JKzgzczZxREFmQmdOVkhTTUVHREFXZ0JUWDQ2K3ArUG8xbnBFNlFMUTdtTUkrODNz\"\n    \"NnFEQU5CZ2txCmhraUc5dzBCQVFzRkFBT0NBUUVBYU4wSXZFQzY3N1BML0pYek1yWGN5QlY4OEl2\"\n    \"aW1sWU4wekN0NDhHWWxobXgKdkwxWVVERkxKRUI3SitkeUVSR0U1TjZCS0tER2JsQzRXaVRGZ0RN\"\n    \"TGNIRnNNR1JjMHY3ektQRjFQU0J3UllKaQp1YkFta3dkdW5HRzVwRFBVWXRURURQWE1sZ0NsWjBZ\"\n    \"eXFTRkpNT3FBNEl6UWc2ZXhWalh0VXhQcXp4Tmh5QzdTCnZsZ1V3UGJYNDZ1Tmk1ODFhOStMczJW\"\n    \"M2ZnMFpuaGtUU2N0WVpIR1pOZWgwTnNmN0FtOHhkVURZRy9iWmNWZWYKamJROWdwQ2hvc2RqRjBC\"\n    \"Z2JsbzdIU1VjdC8yVmErWWxZd1crV0ZqSlg4azRvTjZaVTVXNXhoZGZPOEN6bWd3awpVUzVrSi8r\"\n    \"MU0wdVI4elVoWkhMNjFGYnNkUHhFaitmWUtySHY0d29vK0E9PQotLS0tLUVORCBDRVJUSUZJQ0FU\"\n    \"RS0tLS0tCg==\";\n\nstatic const char SERVER_CERT_PEM[] =\n    \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURMakNDQWhhZ0F3SUJBZ0lJVzFtQXRKV0pB\"\n    \"Sll3RFFZSktvWklodmNOQVFFTEJRQXdJREVlTUJ3R0ExVUUKQXhNVmJXbHVhV05oSUhKdmIzUWdZ\"\n    \"MkVnTkdSall6Sm1NQ0FYRFRJek1ETXdOakUyTkRFd05sb1lEekl4TWpNdwpNekEyTVRZME1UQTJX\"\n    \"akFVTVJJd0VBWURWUVFERXdsc2IyTmhiR2h2YzNRd2dnRWlNQTBHQ1NxR1NJYjNEUUVCCkFRVUFB\"\n    \"NElCRHdBd2dnRUtBb0lCQVFDWU1MSktvb2MrWVJsS0VNZmVWMDlwWDlteUgzNGVVY1V1VDBmWFM4\"\n    \"bG0KUGxaL05XN21tNWxEd2E4RVVnNjFXdVhRdjJvdVFEcHRtSWNkZWIvdzRSVzkzWGZsa3luZzFY\"\n    \"YmQ5MU93UUJKZAorOFpWQmp6TDdoU1JrM1FQRHF4L0NWQlUvSTFHbVhLemI2Y1d6cTFmVGtPbjFX\"\n    \"TE5YZjIxSTZwNytOM3FITFBGCkpRZW9WcTFIQkJGY0FqVGdKbnB5UU52UkdMRHVMVEsrT3NXRUdp\"\n    \"YjJVOHFyZ2lSZGthQkxreEdYU2xHQUJsT28KY1F5Vy96T2hmNHB3YjJaL0pBZ2UybVJXNUljZXhD\"\n    \"UEJXaW50OHlkUHNvSkRkczhqNStBeVlDRDZIVWhIWDBPYgpRa3o3M09XN2YyUFFodVRLMnV6S3kw\"\n    \"WXo2bE5GdDJudXphV0MwNHdJVzNUN0FnTUJBQUdqZGpCME1BNEdBMVVkCkR3RUIvd1FFQXdJRm9E\"\n    \"QWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBUVlJS3dZQkJRVUhBd0l3REFZRFZSMFQKQVFIL0JB\"\n    \"SXdBREFmQmdOVkhTTUVHREFXZ0JUWDQ2K3ArUG8xbnBFNlFMUTdtTUkrODNzNnFEQVVCZ05WSFJF\"\n    \"RQpEVEFMZ2dsc2IyTmhiR2h2YzNRd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFBeHJtUVBHNTR5\"\n    \"YktnTVZsaU44Ck1nNXBvdlNkUElWVm5sVS9IT1ZHOXl4ekFPYXYveFFQMDAzTTR3cXBhdFd4STh0\"\n    \"UjFQY0x1WmYwRVBtY2RKZ2IKdFZsOW5aTVZadHZlUW5ZTWxVOFBwa0VWdTU2Vk00WnIzckg5bGlQ\"\n    \"UmxyMEpFQVhPRGRLdzc2a1dLem1kcVdaLwpyemh1cDNFazdpRVg2VDVqL2NQVXZUV3RNRDRWRUsy\"\n    \"STdmZ29LU0hJWDhNSVZ6cU03Y3Vib0dXUHRTM2VSTlhsCk1ndmFoQTRUd0xFWFBFZStWMVdBcTZu\"\n    \"U2I0ZzJxU1hXSURwSXN5L08xV0dTL3p6Um5Ldlh1OS85TmtYV3FaTWwKQzFMU3BpaVFVYVJTZ2xP\"\n    \"dllmL1p4NnIrNEJPUzRPYWFBcndIa2VjWlFxQlNDY0JMRUF5Yi9GYWFYZEJvd0kwVQpQUTQ9Ci0t\"\n    \"LS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\";\n\nstatic const char SERVER_KEY_PEM[] =\n    \"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBbURDeVNxS0hQ\"\n    \"bUVaU2hESDNsZFBhVi9ac2g5K0hsSEZMazlIMTB2SlpqNVdmelZ1CjVwdVpROEd2QkZJT3RWcmww\"\n    \"TDlxTGtBNmJaaUhIWG0vOE9FVnZkMTM1Wk1wNE5WMjNmZFRzRUFTWGZ2R1ZRWTgKeSs0VWtaTjBE\"\n    \"dzZzZndsUVZQeU5ScGx5czIrbkZzNnRYMDVEcDlWaXpWMzl0U09xZS9qZDZoeXp4U1VIcUZhdApS\"\n    \"d1FSWEFJMDRDWjZja0RiMFJpdzdpMHl2anJGaEJvbTlsUEtxNElrWFpHZ1M1TVJsMHBSZ0FaVHFI\"\n    \"RU1sdjh6Cm9YK0tjRzltZnlRSUh0cGtWdVNISHNRandWb3A3Zk1uVDdLQ1EzYlBJK2ZnTW1BZyto\"\n    \"MUlSMTlEbTBKTSs5emwKdTM5ajBJYmt5dHJzeXN0R00rcFRSYmRwN3MybGd0T01DRnQwK3dJREFR\"\n    \"QUJBb0lCQUROVFNPMnV2bG1sT1hnbgpES0RKWlRpdVlLYVh4RnJKVE94L1JFVXhnK3g5WFlKdExN\"\n    \"ZU05alZKbnBLZ2NlRnJsRkhBSERrWTVCdU44eE5YCnVnbXNmejZXOEJaMmVRc2dNb1JOSXVZdjFZ\"\n    \"SG9wVXlMVy9tU2cxRk5Iempzdy9QYjJrR3ZJcDRLcGdvcHYzb0wKbmFDa3JtQnRzSEorSGsvMmhV\"\n    \"cGw5Y0U4aU13VldjVmV2THp5SGk5OGpOeTFJRGRJUGhSdGwwZGhNaXFDNU1Scgo0Z0xKNWdOa0xZ\"\n    \"WDd4ZjN0dzVIbWZrL2JWTlByb3FaWERJUVZJN3JGdkl0WDU4Nm52UTNMTlFrbVcvRDJTaFpmCjNG\"\n    \"RXFNdTZFZEEyWWNjNFVaZ0FsUU5HVjBWQnJXV1ZYaXpPUSs5Z2pMbkJrM2tKanFmaWdDVTZORzk0\"\n    \"YlRKK0gKMFlJaHNHRUNnWUVBd2RTU3l1TVNPWGd6WlE3VnYrR3NObi83aXZpL0g4ZWIvbER6a3Nx\"\n    \"Uy9Kcm9BMmNpQW1IRwoyT0YzMGVVSktSZytTVHFCVHBPZlhnUzRRVWE4UUxTd0JTbndjdzY1Nzl4\"\n    \"OWJZR1VocUQyWXBhdzl1Q25PdWtBCkN3d2dnWjljRG1GMHRiNXJZanFrVzNiRlBxa0NuVEdiMHls\"\n    \"TUZhWVJoUkRVMjBpRzV0OFBRY2tDZ1lFQXlRRU0KS0sxOEZMUVVLaXZHclFnUDVJYjZJQzNteXps\"\n    \"SEd4RHpmb2JYR3BhUW50Rm5IWTdDeHAvNkJCdG1BU3p0OUp4dQpldG5yZXZtenJiS3FzTFRKU2cz\"\n    \"aXZiaXEwWVRMQUoxRnNackNwNzFkeDQ5WVIvNW85UUZpcTBuUW9LbndVVmViCi9ockRqTUFva05r\"\n    \"akZMNXZvdVhPNzExR1NTNll5TTRXekFLWkFxTUNnWUVBaHFHeGFHMDZqbUo0U0Z4NmliSWwKblNG\"\n    \"ZVJoUXJKTmJQK21DZUhycklSOThOQXJnUy9sYU4rTHo3TGZhSlcxcjBnSWE3cENtVGk0bDV0aFY4\"\n    \"MHZEdQpSbGZ3Sk9yNHFhdWNENER1K21nNVd4ZFNTZGlYTDZzQmxhclJ0VmRNYU15MmRUcVRlZ0pE\"\n    \"Z1NoSkx4SFR0LzNxClAweXpCV0o1VHRUM0ZHMFhEcXVtL0VrQ2dZQVlOSHdXV2UzYlFHUTlQOUJJ\"\n    \"L2ZPTC9ZVVpZdTJzQTFYQXVLWFoKMHJzTWhKMGR3dkc3NlhrakdoaXRiZTgyclFacXNudkxaM3Fu\"\n    \"OEhIbXRPRkJMa1FmR3RUM0s4bkdPVXVJNDJlRgpIN0haS1VDbHkybENJaXpaZERWQmt6NEFXdmFK\"\n    \"bFJjLzNsRTJIZDNFczZFNTJrVHZST1ZLaGR6MDZ4dVM4dDVqCjZ0d3FLUUtCZ1FDMDFBZWlXTDZS\"\n    \"em8reVpOelZnYnBlZURvZ2FaejVkdG1VUkRnQ1lIOHlGWDVlb0NLTEhmbkkKMm5ESW9xcGFIWTBM\"\n    \"dVgrZGludUgralA0dGx5bmRiYzJtdVhuSGQ5cjBhdHl0eEE2OWF5M3NTQTVXRnRmaTRlZgpFU0Vs\"\n    \"R082cVhFQTgyMVJwUXArMit1aEw5MCtpQzI5NGNQcWxTNUxEbXZUTXlwVkRIenJ4UFE9PQotLS0t\"\n    \"LUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=\";\n\nstatic int received_count = 0;\n\nstatic void data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)ctx;\n    z_view_string_t key;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(key)), z_string_data(z_loan(key)),\n           (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    received_count++;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"demo/example/**\";\n    int max_msgs = 0;\n    bool has_listen = false;\n    bool enable_mtls = false;\n    bool enable_verify_name = false;\n    const char *ca_path = NULL;\n    const char *listen_key_path = NULL;\n    const char *listen_cert_path = NULL;\n    const char *client_key_path = NULL;\n    const char *client_cert_path = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"hk:e:m:l:n:C:P:Q:R:S:MV\")) != -1) {\n        switch (opt) {\n            case 'h':\n                printf(\"Usage: %s [options]\\n\", argv[0]);\n                printf(\"  -k <keyexpr>  Key expression filter (default: demo/example/**)\\n\");\n                printf(\"  -n <count>    Stop after receiving <count> samples (default: infinite)\\n\");\n                printf(\"  -e <locator>  Add connect locator (e.g., tls/127.0.0.1:7447)\\n\");\n                printf(\"  -l <locator>  Set listen locator (e.g., tls/0.0.0.0:7447)\\n\");\n                printf(\"  -m <mode>     Session mode: client or peer (default: client)\\n\");\n                printf(\"  -C <file>     CA bundle path (optional; inline bundle used otherwise)\\n\");\n                printf(\"  -P <file>     Listener private key path (peers)\\n\");\n                printf(\"  -Q <file>     Listener certificate path (peers)\\n\");\n                printf(\"  -R <file>     Client private key path (mTLS)\\n\");\n                printf(\"  -S <file>     Client certificate path (mTLS)\\n\");\n                printf(\"  -M            Enable mutual TLS\\n\");\n                printf(\"  -V            Enable hostname verification\\n\");\n                z_drop(z_move(config));\n                return 0;\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'e':\n                if (zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, optarg) != Z_OK) {\n                    fprintf(stderr, \"Failed to add connect locator\\n\");\n                    z_drop(z_move(config));\n                    return -1;\n                }\n                break;\n            case 'm':\n                if (zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, optarg) != Z_OK) {\n                    fprintf(stderr, \"Failed to set session mode\\n\");\n                    z_drop(z_move(config));\n                    return -1;\n                }\n                break;\n            case 'l':\n                if (zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, optarg) != Z_OK) {\n                    fprintf(stderr, \"Failed to set listen locator\\n\");\n                    z_drop(z_move(config));\n                    return -1;\n                }\n                has_listen = true;\n                break;\n            case 'n':\n                max_msgs = atoi(optarg);\n                break;\n            case 'C':\n                ca_path = optarg;\n                break;\n            case 'P':\n                listen_key_path = optarg;\n                break;\n            case 'Q':\n                listen_cert_path = optarg;\n                break;\n            case 'R':\n                client_key_path = optarg;\n                break;\n            case 'S':\n                client_cert_path = optarg;\n                break;\n            case 'M':\n                enable_mtls = true;\n                break;\n            case 'V':\n                enable_verify_name = true;\n                break;\n            default:\n                z_drop(z_move(config));\n                return -1;\n        }\n    }\n\n    if (ca_path) {\n        if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY, ca_path) != Z_OK) {\n            fprintf(stderr, \"Failed to set CA certificate path\\n\");\n            z_drop(z_move(config));\n            return -1;\n        }\n    } else {\n        if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY, SERVER_CA_PEM) != Z_OK) {\n            fprintf(stderr, \"Failed to set inline CA certificate\\n\");\n            z_drop(z_move(config));\n            return -1;\n        }\n    }\n\n    if (has_listen) {\n        if (listen_key_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_KEY, listen_key_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set listener private key path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_BASE64_KEY, SERVER_KEY_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline listener private key\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n\n        if (listen_cert_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_CERTIFICATE_KEY, listen_cert_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set listener certificate path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_LISTEN_CERTIFICATE_BASE64_KEY, SERVER_CERT_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline listener certificate\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n    }\n\n    if (enable_mtls) {\n        if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_ENABLE_MTLS_KEY, \"true\") != Z_OK) {\n            fprintf(stderr, \"Failed to enable mTLS\\n\");\n            z_drop(z_move(config));\n            return -1;\n        }\n\n        if (client_key_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_KEY, client_key_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set client private key path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_BASE64_KEY, SERVER_KEY_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline client private key\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n\n        if (client_cert_path) {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_CERTIFICATE_KEY, client_cert_path) != Z_OK) {\n                fprintf(stderr, \"Failed to set client certificate path\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        } else {\n            if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_CONNECT_CERTIFICATE_BASE64_KEY, SERVER_CERT_PEM) !=\n                Z_OK) {\n                fprintf(stderr, \"Failed to set inline client certificate\\n\");\n                z_drop(z_move(config));\n                return -1;\n            }\n        }\n    }\n\n    if (zp_config_insert(z_loan_mut(config), Z_CONFIG_TLS_VERIFY_NAME_ON_CONNECT_KEY,\n                         enable_verify_name ? \"true\" : \"false\") != Z_OK) {\n        fprintf(stderr, \"Failed to configure hostname verification\\n\");\n        z_drop(z_move(config));\n        return -1;\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t session;\n    if (z_open(&session, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        z_session_drop(z_session_move(&session));\n        return -1;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(session), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        z_session_drop(z_session_move(&session));\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (max_msgs == 0 || received_count < max_msgs) {\n        sleep(1);\n    }\n\n    z_drop(z_move(sub));\n    z_session_drop(z_session_move(&session));\n    return 0;\n}\n\n#else\nint main(void) {\n#if Z_FEATURE_SUBSCRIPTION != 1\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n#elif Z_FEATURE_LINK_TLS != 1\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_LINK_TLS but this example requires it.\\n\");\n#endif\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_get.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1\nz_owned_condvar_t cond;\nz_owned_mutex_t mutex;\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    printf(\">> Received query final notification\\n\");\n    z_condvar_signal(z_condvar_loan_mut(&cond));\n    z_condvar_drop(z_condvar_move(&cond));\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n               z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&replystr)),\n               z_string_data(z_string_loan(&replystr)));\n        z_string_drop(z_string_move(&replystr));\n    } else {\n        printf(\">> Received an error\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/**\";\n    const char *mode = \"client\";\n    const char *clocator = NULL;\n    const char *llocator = NULL;\n    const char *value = NULL;\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:v:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case 'v':\n                value = optarg;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'v' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_mutex_init(&mutex);\n    z_condvar_init(&cond);\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    z_mutex_lock(z_mutex_loan_mut(&mutex));\n    printf(\"Sending Query '%s'...\\n\", keyexpr);\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    // Value encoding\n    z_owned_bytes_t payload;\n    if (value != NULL) {\n        z_bytes_from_static_str(&payload, value);\n        opts.payload = z_bytes_move(&payload);\n    }\n    z_owned_closure_reply_t callback;\n    z_closure_reply(&callback, reply_handler, reply_dropper, NULL);\n    if (z_get(z_session_loan(&s), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&callback), &opts) < 0) {\n        printf(\"Unable to send query.\\n\");\n        return -1;\n    }\n    z_condvar_wait(z_condvar_loan_mut(&cond), z_mutex_loan_mut(&mutex));\n    z_mutex_unlock(z_mutex_loan_mut(&mutex));\n\n    z_session_drop(z_session_move(&s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_info.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <signal.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\nvoid print_zid(const z_id_t *id, void *ctx) {\n    (void)(ctx);\n    z_owned_string_t id_str;\n    z_id_to_string(id, &id_str);\n    printf(\" %.*s\\n\", (int)z_string_len(z_string_loan(&id_str)), z_string_data(z_string_loan(&id_str)));\n    z_string_drop(z_string_move(&id_str));\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic const char *bool_to_str(bool value) { return value ? \"true\" : \"false\"; }\n\nstatic void print_transport(z_loaned_transport_t *transport, void *ctx) {\n    (void)(ctx);\n    z_id_t zid = z_transport_zid(transport);\n    z_owned_string_t id_str;\n    z_id_to_string(&zid, &id_str);\n    z_view_string_t whatami;\n    z_whatami_to_view_string(z_transport_whatami(transport), &whatami);\n\n    printf(\"  transport{zid=%.*s, whatami=%.*s, is_qos=%s, is_multicast=%s, is_shm=%s}\\n\",\n           (int)z_string_len(z_string_loan(&id_str)), z_string_data(z_string_loan(&id_str)),\n           (int)z_string_len(z_view_string_loan(&whatami)), z_string_data(z_view_string_loan(&whatami)),\n           bool_to_str(z_transport_is_qos(transport)), bool_to_str(z_transport_is_multicast(transport)),\n           bool_to_str(z_transport_is_shm(transport)));\n    z_string_drop(z_string_move(&id_str));\n}\n\nstatic void print_link(z_loaned_link_t *link, void *ctx) {\n    (void)(ctx);\n    z_id_t zid = z_link_zid(link);\n    z_owned_string_t id_str;\n    z_id_to_string(&zid, &id_str);\n    z_owned_string_t src;\n    z_owned_string_t dst;\n    bool has_src = z_link_src(link, &src) == 0;\n    bool has_dst = z_link_dst(link, &dst) == 0;\n\n    printf(\"  link{zid=%.*s\", (int)z_string_len(z_string_loan(&id_str)), z_string_data(z_string_loan(&id_str)));\n    printf(\", src=\");\n    if (has_src) {\n        printf(\"%.*s\", (int)z_string_len(z_string_loan(&src)), z_string_data(z_string_loan(&src)));\n    } else {\n        printf(\"<n/a>\");\n    }\n    printf(\", dst=\");\n    if (has_dst) {\n        printf(\"%.*s\", (int)z_string_len(z_string_loan(&dst)), z_string_data(z_string_loan(&dst)));\n    } else {\n        printf(\"<n/a>\");\n    }\n    z_owned_string_t group;\n    z_link_group(link, &group);\n    z_owned_string_t auth_id;\n    z_link_auth_identifier(link, &auth_id);\n    z_owned_string_array_t interfaces;\n    z_link_interfaces(link, &interfaces);\n    uint8_t prio_min, prio_max;\n    bool has_prio = z_link_priorities(link, &prio_min, &prio_max);\n    z_reliability_t reliability;\n    bool has_rel = z_link_reliability(link, &reliability);\n\n    if (z_string_len(z_string_loan(&group)) > 0) {\n        printf(\", group=%.*s\", (int)z_string_len(z_string_loan(&group)), z_string_data(z_string_loan(&group)));\n    }\n    if (z_string_len(z_string_loan(&auth_id)) > 0) {\n        printf(\", auth_id=%.*s\", (int)z_string_len(z_string_loan(&auth_id)), z_string_data(z_string_loan(&auth_id)));\n    }\n    printf(\", interfaces=[\");\n    size_t iface_len = z_string_array_len(z_string_array_loan(&interfaces));\n    for (size_t i = 0; i < iface_len; i++) {\n        const z_loaned_string_t *iface = z_string_array_get(z_string_array_loan(&interfaces), i);\n        if (i > 0) printf(\", \");\n        printf(\"%.*s\", (int)z_string_len(iface), z_string_data(iface));\n    }\n    printf(\"]\");\n    if (has_prio) {\n        printf(\", priorities=[%u, %u]\", (unsigned)prio_min, (unsigned)prio_max);\n    }\n    if (has_rel) {\n        printf(\", reliability=%s\", (reliability == Z_RELIABILITY_RELIABLE) ? \"reliable\" : \"best_effort\");\n    }\n    printf(\", mtu=%u, is_streamed=%s, is_reliable=%s}\\n\", (unsigned)z_link_mtu(link),\n           bool_to_str(z_link_is_streamed(link)), bool_to_str(z_link_is_reliable(link)));\n\n    z_string_drop(z_string_move(&id_str));\n    if (has_src) {\n        z_string_drop(z_string_move(&src));\n    }\n    if (has_dst) {\n        z_string_drop(z_string_move(&dst));\n    }\n    z_string_drop(z_string_move(&group));\n    z_string_drop(z_string_move(&auth_id));\n    z_string_array_drop(z_string_array_move(&interfaces));\n}\n\nstatic volatile bool running = true;\n\nstatic void handle_signal(int signo) {\n    (void)signo;\n    running = false;\n}\n\nstatic void transport_event_handler(z_loaned_transport_event_t *event, void *ctx) {\n    (void)ctx;\n    z_sample_kind_t kind = z_transport_event_kind(event);\n    const z_loaned_transport_t *transport = z_transport_event_transport(event);\n    printf(\">> [Transport Event] %s:\\n\", (kind == Z_SAMPLE_KIND_PUT) ? \"Opened\" : \"Closed\");\n    print_transport((z_loaned_transport_t *)transport, NULL);\n}\n\nstatic void link_event_handler(z_loaned_link_event_t *event, void *ctx) {\n    (void)ctx;\n    z_sample_kind_t kind = z_link_event_kind(event);\n    const z_loaned_link_t *link = z_link_event_link(event);\n    printf(\">> [Link Event] %s:\\n\", (kind == Z_SAMPLE_KIND_PUT) ? \"Opened\" : \"Closed\");\n    print_link((z_loaned_link_t *)link, NULL);\n}\n#endif\n\nint main(int argc, char **argv) {\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    char *llocator = NULL;\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case '?':\n                if (optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_id_t self_id = z_info_zid(z_session_loan(&s));\n    printf(\"Own ID:\");\n    print_zid(&self_id, NULL);\n\n    printf(\"Routers IDs:\\n\");\n    z_owned_closure_zid_t callback;\n    z_closure_zid(&callback, print_zid, NULL, NULL);\n    z_info_routers_zid(z_session_loan(&s), z_closure_zid_move(&callback));\n\n    // `callback` has been `z_move`d just above, so it's safe to reuse the variable,\n    // we'll just have to make sure we `z_move` it again to avoid mem-leaks.\n    printf(\"Peers IDs:\\n\");\n    z_owned_closure_zid_t callback2;\n    z_closure_zid(&callback2, print_zid, NULL, NULL);\n    z_info_peers_zid(z_session_loan(&s), z_closure_zid_move(&callback2));\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    printf(\"Connected transports:\\n\");\n    z_owned_closure_transport_t transport_cb;\n    z_closure_transport(&transport_cb, print_transport, NULL, NULL);\n    if (z_info_transports(z_session_loan(&s), z_closure_transport_move(&transport_cb)) < 0) {\n        printf(\"Unable to fetch connected transports\\n\");\n        z_session_drop(z_session_move(&s));\n        return -1;\n    }\n\n    printf(\"Connected links:\\n\");\n    z_owned_closure_link_t link_cb;\n    z_closure_link(&link_cb, print_link, NULL, NULL);\n    if (z_info_links(z_session_loan(&s), z_closure_link_move(&link_cb), NULL) < 0) {\n        printf(\"Unable to fetch connected links\\n\");\n        z_session_drop(z_session_move(&s));\n        return -1;\n    }\n\n    // Register transport event listener (background, no history to avoid duplicating already-printed items)\n    printf(\"Declaring transport events listener...\\n\");\n    z_owned_closure_transport_event_t te_cb;\n    z_closure_transport_event(&te_cb, transport_event_handler, NULL, NULL);\n    z_transport_events_listener_options_t te_opts;\n    z_transport_events_listener_options_default(&te_opts);\n    te_opts.history = false;\n    if (z_declare_background_transport_events_listener(z_session_loan(&s), z_closure_transport_event_move(&te_cb),\n                                                       &te_opts) < 0) {\n        printf(\"Unable to declare transport events listener\\n\");\n        z_session_drop(z_session_move(&s));\n        return -1;\n    }\n\n    // Register link event listener (non-background so we can undeclare it)\n    printf(\"Declaring link events listener...\\n\");\n    z_owned_closure_link_event_t le_cb;\n    z_closure_link_event(&le_cb, link_event_handler, NULL, NULL);\n    z_link_events_listener_options_t le_opts;\n    z_link_events_listener_options_default(&le_opts);\n    le_opts.history = false;\n    z_owned_link_events_listener_t le_listener;\n    if (z_declare_link_events_listener(z_session_loan(&s), &le_listener, z_closure_link_event_move(&le_cb), &le_opts) <\n        0) {\n        printf(\"Unable to declare link events listener\\n\");\n        z_session_drop(z_session_move(&s));\n        return -1;\n    }\n\n    signal(SIGINT, handle_signal);\n    signal(SIGTERM, handle_signal);\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (running) {\n        z_sleep_s(1);\n    }\n\n    z_link_events_listener_drop(z_link_events_listener_move(&le_listener));\n#endif\n\n    z_session_drop(z_session_move(&s));\n    return 0;\n}\n"
  },
  {
    "path": "examples/unix/c99/z_ping.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 1\n\n#define DEFAULT_PKT_SIZE 8\n#define DEFAULT_PING_NB 100\n#define DEFAULT_WARMUP_MS 1000\n\nstatic z_owned_condvar_t cond;\nstatic z_owned_mutex_t mutex;\n\nvoid callback(z_loaned_sample_t* sample, void* context) {\n    (void)sample;\n    (void)context;\n    z_condvar_signal(z_condvar_loan_mut(&cond));\n}\nvoid drop(void* context) {\n    (void)context;\n    z_condvar_drop(z_condvar_move(&cond));\n}\n\nstruct args_t {\n    unsigned int size;             // -s\n    unsigned int number_of_pings;  // -n\n    unsigned int warmup_ms;        // -w\n    uint8_t help_requested;        // -h\n};\nstruct args_t parse_args(int argc, char** argv);\n\nint main(int argc, char** argv) {\n    struct args_t args = parse_args(argc, argv);\n    if (args.help_requested) {\n        printf(\n            \"\\\n\t\t-n (optional, int, default=%d): the number of pings to be attempted\\n\\\n\t\t-s (optional, int, default=%d): the size of the payload embedded in the ping and repeated by the pong\\n\\\n\t\t-w (optional, int, default=%d): the warmup time in ms during which pings will be emitted but not measured\\n\\\n\t\t-c (optional, string): the path to a configuration file for the session. If this option isn't passed, the default configuration will be used.\\n\\\n\t\t\",\n            DEFAULT_PKT_SIZE, DEFAULT_PING_NB, DEFAULT_WARMUP_MS);\n        return 1;\n    }\n    z_mutex_init(&mutex);\n    z_condvar_init(&cond);\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_session_t session;\n    if (z_open(&session, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ping;\n    z_view_keyexpr_from_str_unchecked(&ping, \"test/ping\");\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_session_loan(&session), &pub, z_view_keyexpr_loan(&ping), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t pong;\n    z_view_keyexpr_from_str_unchecked(&pong, \"test/pong\");\n    z_owned_closure_sample_t respond;\n    z_closure_sample(&respond, callback, drop, NULL);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_session_loan(&session), &sub, z_view_keyexpr_loan(&pong),\n                             z_closure_sample_move(&respond), NULL) < 0) {\n        printf(\"Unable to declare subscriber for key expression.\\n\");\n        return -1;\n    }\n\n    uint8_t* data = (uint8_t*)z_malloc(args.size);\n    for (unsigned int i = 0; i < args.size; i++) {\n        data[i] = (uint8_t)(i % 10);\n    }\n    z_mutex_lock(z_mutex_loan_mut(&mutex));\n    if (args.warmup_ms) {\n        printf(\"Warming up for %dms...\\n\", args.warmup_ms);\n        z_clock_t warmup_start = z_clock_now();\n        unsigned long elapsed_us = 0;\n        while (elapsed_us < args.warmup_ms * 1000) {\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_from_buf(&payload, data, args.size, NULL, NULL);\n\n            z_publisher_put(z_publisher_loan(&pub), z_bytes_move(&payload), NULL);\n            z_condvar_wait(z_condvar_loan_mut(&cond), z_mutex_loan_mut(&mutex));\n            elapsed_us = z_clock_elapsed_us(&warmup_start);\n        }\n    }\n    unsigned long* results = (unsigned long*)z_malloc(sizeof(unsigned long) * args.number_of_pings);\n    for (unsigned int i = 0; i < args.number_of_pings; i++) {\n        z_clock_t measure_start = z_clock_now();\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_from_buf(&payload, data, args.size, NULL, NULL);\n\n        z_publisher_put(z_publisher_loan(&pub), z_bytes_move(&payload), NULL);\n        z_condvar_wait(z_condvar_loan_mut(&cond), z_mutex_loan_mut(&mutex));\n        results[i] = z_clock_elapsed_us(&measure_start);\n    }\n    for (unsigned int i = 0; i < args.number_of_pings; i++) {\n        printf(\"%d bytes: seq=%d rtt=%luµs, lat=%luµs\\n\", args.size, i, results[i], results[i] / 2);\n    }\n    z_mutex_unlock(z_mutex_loan_mut(&mutex));\n    z_free(results);\n    z_free(data);\n    z_subscriber_drop(z_subscriber_move(&sub));\n    z_publisher_drop(z_publisher_move(&pub));\n\n    z_session_drop(z_session_move(&session));\n}\n\nchar* getopt(int argc, char** argv, char option) {\n    for (int i = 0; i < argc; i++) {\n        size_t len = strlen(argv[i]);\n        if (len >= 2 && argv[i][0] == '-' && argv[i][1] == option) {\n            if (len > 2 && argv[i][2] == '=') {\n                return argv[i] + 3;\n            } else if (i + 1 < argc) {\n                return argv[i + 1];\n            }\n        }\n    }\n    return NULL;\n}\n\nstruct args_t parse_args(int argc, char** argv) {\n    for (int i = 0; i < argc; i++) {\n        if (strcmp(argv[i], \"-h\") == 0) {\n            return (struct args_t){.help_requested = 1};\n        }\n    }\n    char* arg = getopt(argc, argv, 's');\n    unsigned int size = DEFAULT_PKT_SIZE;\n    if (arg) {\n        size = (unsigned int)atoi(arg);\n    }\n    arg = getopt(argc, argv, 'n');\n    unsigned int number_of_pings = DEFAULT_PING_NB;\n    if (arg) {\n        number_of_pings = (unsigned int)atoi(arg);\n    }\n    arg = getopt(argc, argv, 'w');\n    unsigned int warmup_ms = DEFAULT_WARMUP_MS;\n    if (arg) {\n        warmup_ms = (unsigned int)atoi(arg);\n    }\n    return (struct args_t){\n        .help_requested = 0,\n        .size = size,\n        .number_of_pings = number_of_pings,\n        .warmup_ms = warmup_ms,\n    };\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION or Z_FEATURE_PUBLICATION or \"\n        \"Z_FEATURE_MULTI_THREAD but this example requires them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_pong.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"stdio.h\"\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/primitives.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\nvoid callback(z_loaned_sample_t* sample, void* context) {\n    const z_loaned_publisher_t* pub = z_publisher_loan((z_owned_publisher_t*)context);\n    z_owned_bytes_t payload;\n    z_bytes_clone(&payload, z_sample_payload(sample));\n    z_publisher_put(pub, z_bytes_move(&payload), NULL);\n}\n\nvoid drop(void* context) {\n    z_owned_publisher_t* pub = (z_owned_publisher_t*)context;\n    z_publisher_drop(z_publisher_move(pub));\n    // A note on lifetimes:\n    //  here, `sub` takes ownership of `pub` and will drop it before returning from its own `drop`,\n    //  which makes passing a pointer to the stack safe as long as `sub` is dropped in a scope where `pub` is still\n    //  valid.\n}\n\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_session_t session;\n    if (z_open(&session, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t pong;\n    z_view_keyexpr_from_str_unchecked(&pong, \"test/pong\");\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_session_loan(&session), &pub, z_view_keyexpr_loan(&pong), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ping;\n    z_view_keyexpr_from_str_unchecked(&ping, \"test/ping\");\n    z_owned_closure_sample_t respond;\n    z_closure_sample(&respond, callback, drop, (void*)(&pub));\n\n    if (z_declare_background_subscriber(z_session_loan(&session), z_view_keyexpr_loan(&ping),\n                                        z_closure_sample_move(&respond), NULL) < 0) {\n        printf(\"Unable to declare subscriber for key expression.\\n\");\n        return -1;\n    }\n\n    while (getchar() != 'q') {\n    }\n\n    z_session_drop(z_session_move(&session));\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION or Z_FEATURE_PUBLICATION but this example \"\n        \"requires them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_pub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    const char *value = \"Pub from Pico!\";\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    char *llocator = NULL;\n    int n = 2147483647;  // max int value by default\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'v':\n                value = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case 'n':\n                n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_publisher(z_session_loan(&s), &pub, z_view_keyexpr_loan(&ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    char *buf = (char *)malloc(256);\n    for (int idx = 0; idx < n; ++idx) {\n        z_sleep_s(1);\n        snprintf(buf, 256, \"[%4d] %s\", idx, value);\n        printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put(z_publisher_loan(&pub), z_bytes_move(&payload), NULL);\n    }\n    // Clean up\n    z_publisher_drop(z_publisher_move(&pub));\n    z_session_drop(z_session_move(&s));\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_pub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 0\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    const char *value = \"Pub from Pico!\";\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    char *llocator = NULL;\n    int n = 2147483647;  // max int value by default\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'v':\n                value = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case 'n':\n                n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' ||\n                    optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_publisher(z_session_loan(&s), &pub, z_view_keyexpr_loan(&ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    char *buf = (char *)malloc(256);\n    z_clock_t now = z_clock_now();\n    for (int idx = 0; idx < n;) {\n        if (z_clock_elapsed_ms(&now) > 1000) {\n            snprintf(buf, 256, \"[%4d] %s\", idx, value);\n            printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_copy_from_str(&payload, buf);\n\n            z_publisher_put(z_publisher_loan(&pub), z_bytes_move(&payload), NULL);\n            ++idx;\n\n            now = z_clock_now();\n        }\n        z_sleep_ms(50);\n        zp_spin_once(z_session_loan(&s));\n    }\n\n    z_publisher_drop(z_publisher_move(&pub));\n    z_session_drop(z_session_move(&s));\n    free(buf);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_PUBLICATION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_pull.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/**\";\n    char *locator = NULL;\n    size_t interval = 5000;\n    size_t size = 3;\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:i:s:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'e':\n                locator = optarg;\n                break;\n            case 'i':\n                interval = (size_t)atoi(optarg);\n                break;\n            case 's':\n                size = (size_t)atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'i' || optopt == 's') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (locator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, size);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&closure),\n                             NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", interval, size);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_ring_handler_sample_try_recv(z_ring_handler_sample_loan(&handler), &sample); res == Z_OK;\n             res = z_ring_handler_sample_try_recv(z_ring_handler_sample_loan(&handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_sample_loan(&sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_sample_loan(&sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n                   z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&value)),\n                   z_string_data(z_string_loan(&value)));\n            z_string_drop(z_string_move(&value));\n            z_sample_drop(z_sample_move(&sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", interval);\n            z_sleep_ms(interval);\n        } else {\n            break;\n        }\n    }\n\n    z_subscriber_drop(z_subscriber_move(&sub));\n    z_ring_handler_sample_drop(z_ring_handler_sample_move(&handler));\n\n    z_session_drop(z_session_move(&s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_put.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/zenoh-pico-put\";\n    const char *value = \"Pub from Pico!\";\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    char *llocator = NULL;\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:v:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'v':\n                value = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring key expression '%s'...\\n\", keyexpr);\n    z_view_keyexpr_t vke;\n    if (z_view_keyexpr_from_str(&vke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    z_owned_keyexpr_t ke;\n    if (z_declare_keyexpr(z_session_loan(&s), &ke, z_view_keyexpr_loan(&vke)) < 0) {\n        printf(\"Unable to declare key expression!\\n\");\n        z_session_drop(z_session_move(&s));\n        return -1;\n    }\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, value);\n\n    printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, value);\n    if (z_put(z_session_loan(&s), z_keyexpr_loan(&ke), z_bytes_move(&payload), NULL) < 0) {\n        printf(\"Oh no! Put has failed...\\n\");\n    }\n\n    // Clean up\n    z_undeclare_keyexpr(z_session_loan(&s), z_keyexpr_move(&ke));\n    z_session_drop(z_session_move(&s));\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\nconst char *keyexpr = \"demo/example/zenoh-pico-queryable\";\nconst char *value = \"Queryable from Pico!\";\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n           z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_view_string_loan(&params)),\n           z_string_data(z_view_string_loan(&params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_string_loan(&payload_string)) > 1) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_string_loan(&payload_string)),\n               z_string_data(z_string_loan(&payload_string)));\n    }\n    z_string_drop(z_string_move(&payload_string));\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, value);\n\n    z_query_reply(query, z_query_keyexpr(query), z_bytes_move(&reply_payload), NULL);\n}\n\nint main(int argc, char **argv) {\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    const char *llocator = NULL;\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:v:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'v':\n                value = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'v' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    z_owned_closure_query_t callback;\n    z_closure_query(&callback, query_handler, NULL, NULL);\n\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_session_loan(&s), &qable, z_view_keyexpr_loan(&ke), z_closure_query_move(&callback),\n                            NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        sleep(1);\n    }\n\n    z_queryable_drop(z_queryable_move(&qable));\n\n    z_session_drop(z_session_move(&s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_view_string_loan(&s)), z_string_data(z_view_string_loan(&s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure_hello(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_config_move(&config), z_closure_hello_move(&closure), NULL);\n    sleep(1);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_sub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    (void)(arg);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n           z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&value)),\n           z_string_data(z_string_loan(&value)));\n    z_string_drop(z_string_move(&value));\n}\n\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/**\";\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    char *llocator = NULL;\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure_sample(&callback, data_handler, NULL, NULL);\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&callback),\n                             NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        sleep(1);\n    }\n\n    z_subscriber_drop(z_subscriber_move(&sub));\n\n    z_session_drop(z_session_move(&s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/unix/c99/z_sub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_MULTI_THREAD == 0\n\nstatic int msg_nb = 0;\n\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    (void)(arg);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_view_string_loan(&keystr)),\n           z_string_data(z_view_string_loan(&keystr)), (int)z_string_len(z_string_loan(&value)),\n           z_string_data(z_string_loan(&value)));\n    z_string_drop(z_string_move(&value));\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    const char *keyexpr = \"demo/example/**\";\n    const char *mode = \"client\";\n    char *clocator = NULL;\n    char *llocator = NULL;\n    int n = 2147483647;  // max int value by default\n\n    int opt;\n    while ((opt = getopt(argc, argv, \"k:e:m:l:n:\")) != -1) {\n        switch (opt) {\n            case 'k':\n                keyexpr = optarg;\n                break;\n            case 'e':\n                clocator = optarg;\n                break;\n            case 'm':\n                mode = optarg;\n                break;\n            case 'l':\n                llocator = optarg;\n                break;\n            case 'n':\n                n = atoi(optarg);\n                break;\n            case '?':\n                if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'n') {\n                    fprintf(stderr, \"Option -%c requires an argument.\\n\", optopt);\n                } else {\n                    fprintf(stderr, \"Unknown option `-%c'.\\n\", optopt);\n                }\n                return 1;\n            default:\n                return -1;\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_MODE_KEY, mode);\n    if (clocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_config_loan_mut(&config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_config_move(&config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure_sample(&callback, data_handler, NULL, NULL);\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_session_loan(&s), &sub, z_view_keyexpr_loan(&ke), z_closure_sample_move(&callback),\n                             NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (msg_nb < n) {\n        z_sleep_ms(50);\n        zp_spin_once(z_session_loan(&s));\n    }\n    z_subscriber_drop(z_subscriber_move(&sub));\n    z_session_drop(z_session_move(&s));\n    return 0;\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_SUBSCRIPTION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_get.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1\nz_owned_condvar_t cond;\nz_owned_mutex_t mutex;\n\nvoid reply_dropper(void *ctx) {\n    (void)(ctx);\n    printf(\">> Received query final notification\\n\");\n    z_condvar_signal(z_loan_mut(cond));\n    z_drop(z_move(cond));\n}\n\nvoid reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    (void)(ctx);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\">> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n               (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n        z_drop(z_move(replystr));\n    } else {\n        printf(\">> Received an error\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/**\";\n    const char *locator = NULL;\n    const char *value = NULL;\n\n    z_mutex_init(&mutex);\n    z_condvar_init(&cond);\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    z_mutex_lock(z_loan_mut(mutex));\n    printf(\"Sending Query '%s'...\\n\", keyexpr);\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    // Value encoding\n    z_owned_bytes_t payload;\n    if (value != NULL) {\n        z_bytes_from_static_str(&payload, value);\n        opts.payload = z_move(payload);\n    }\n    z_owned_closure_reply_t callback;\n    z_closure(&callback, reply_handler, reply_dropper, NULL);\n    if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n        printf(\"Unable to send query.\\n\");\n        return -1;\n    }\n    z_condvar_wait(z_loan_mut(cond), z_loan_mut(mutex));\n    z_mutex_unlock(z_loan_mut(mutex));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires \"\n        \"them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_info.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\nvoid print_zid(const z_id_t *id, void *ctx) {\n    (void)(ctx);\n    z_owned_string_t id_str;\n    z_id_to_string(id, &id_str);\n    printf(\" %.*s\\n\", (int)z_string_len(z_loan(id_str)), z_string_data(z_loan(id_str)));\n    z_drop(z_move(id_str));\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *mode = \"client\";\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_id_t self_id = z_info_zid(z_loan(s));\n    printf(\"Own ID:\");\n    print_zid(&self_id, NULL);\n\n    printf(\"Routers IDs:\\n\");\n    z_owned_closure_zid_t callback;\n    z_closure(&callback, print_zid, NULL, NULL);\n    z_info_routers_zid(z_loan(s), z_move(callback));\n\n    // `callback` has been `z_move`d just above, so it's safe to reuse the variable,\n    // we'll just have to make sure we `z_move` it again to avoid mem-leaks.\n    printf(\"Peers IDs:\\n\");\n    z_owned_closure_zid_t callback2;\n    z_closure(&callback2, print_zid, NULL, NULL);\n    z_info_peers_zid(z_loan(s), z_move(callback2));\n\n    z_drop(z_move(s));\n}\n"
  },
  {
    "path": "examples/windows/z_ping.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\n\n#define DEFAULT_PKT_SIZE 8\n#define DEFAULT_PING_NB 100\n#define DEFAULT_WARMUP_MS 1000\n\nstatic z_owned_condvar_t cond;\nstatic z_owned_mutex_t mutex;\n\nvoid callback(z_loaned_sample_t* sample, void* context) {\n    (void)sample;\n    (void)context;\n    z_condvar_signal(z_loan_mut(cond));\n}\nvoid drop(void* context) {\n    (void)context;\n    z_drop(z_move(cond));\n}\n\nstruct args_t {\n    unsigned int size;             // -s\n    unsigned int number_of_pings;  // -n\n    unsigned int warmup_ms;        // -w\n    uint8_t help_requested;        // -h\n};\nstruct args_t parse_args(int argc, char** argv);\n\nint main(int argc, char** argv) {\n    struct args_t args = parse_args(argc, argv);\n    if (args.help_requested) {\n        printf(\n            \"\\\n\t\t-n (optional, int, default=%d): the number of pings to be attempted\\n\\\n\t\t-s (optional, int, default=%d): the size of the payload embedded in the ping and repeated by the pong\\n\\\n\t\t-w (optional, int, default=%d): the warmup time in ms during which pings will be emitted but not measured\\n\\\n\t\t-c (optional, string): the path to a configuration file for the session. If this option isn't passed, the default configuration will be used.\\n\\\n\t\t\",\n            DEFAULT_PKT_SIZE, DEFAULT_PING_NB, DEFAULT_WARMUP_MS);\n        return 1;\n    }\n    z_mutex_init(&mutex);\n    z_condvar_init(&cond);\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_session_t session;\n    if (z_open(&session, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ping;\n    z_view_keyexpr_from_str_unchecked(&ping, \"test/ping\");\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(session), &pub, z_loan(ping), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t pong;\n    z_view_keyexpr_from_str_unchecked(&pong, \"test/pong\");\n    z_owned_closure_sample_t respond;\n    z_closure(&respond, callback, drop, NULL);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(session), &sub, z_loan(pong), z_move(respond), NULL) < 0) {\n        printf(\"Unable to declare subscriber for key expression.\\n\");\n        return -1;\n    }\n\n    uint8_t* data = (uint8_t*)z_malloc(args.size);\n    for (unsigned int i = 0; i < args.size; i++) {\n        data[i] = i % 10;\n    }\n    z_mutex_lock(z_loan_mut(mutex));\n    if (args.warmup_ms) {\n        printf(\"Warming up for %dms...\\n\", args.warmup_ms);\n        z_clock_t warmup_start = z_clock_now();\n        unsigned long elapsed_us = 0;\n        while (elapsed_us < args.warmup_ms * 1000) {\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_from_buf(&payload, data, args.size, NULL, NULL);\n\n            z_publisher_put(z_loan(pub), z_move(payload), NULL);\n            z_condvar_wait(z_loan_mut(cond), z_loan_mut(mutex));\n            elapsed_us = z_clock_elapsed_us(&warmup_start);\n        }\n    }\n    unsigned long* results = (unsigned long*)z_malloc(sizeof(unsigned long) * args.number_of_pings);\n    for (unsigned int i = 0; i < args.number_of_pings; i++) {\n        z_clock_t measure_start = z_clock_now();\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_from_buf(&payload, data, args.size, NULL, NULL);\n\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n        z_condvar_wait(z_loan_mut(cond), z_loan_mut(mutex));\n        results[i] = z_clock_elapsed_us(&measure_start);\n    }\n    for (unsigned int i = 0; i < args.number_of_pings; i++) {\n        printf(\"%d bytes: seq=%d rtt=%luus, lat=%luus\\n\", args.size, i, results[i], results[i] / 2);\n    }\n    z_mutex_unlock(z_loan_mut(mutex));\n    z_free(results);\n    z_free(data);\n    z_drop(z_move(pub));\n    z_drop(z_move(sub));\n\n    z_drop(z_move(session));\n}\n\nchar* getopt(int argc, char** argv, char option) {\n    for (int i = 0; i < argc; i++) {\n        size_t len = strlen(argv[i]);\n        if (len >= 2 && argv[i][0] == '-' && argv[i][1] == option) {\n            if (len > 2 && argv[i][2] == '=') {\n                return argv[i] + 3;\n            } else if (i + 1 < argc) {\n                return argv[i + 1];\n            }\n        }\n    }\n    return NULL;\n}\n\nstruct args_t parse_args(int argc, char** argv) {\n    for (int i = 0; i < argc; i++) {\n        if (strcmp(argv[i], \"-h\") == 0) {\n            return (struct args_t){.help_requested = 1};\n        }\n    }\n    char* arg = getopt(argc, argv, 's');\n    unsigned int size = DEFAULT_PKT_SIZE;\n    if (arg) {\n        size = atoi(arg);\n    }\n    arg = getopt(argc, argv, 'n');\n    unsigned int number_of_pings = DEFAULT_PING_NB;\n    if (arg) {\n        number_of_pings = atoi(arg);\n    }\n    arg = getopt(argc, argv, 'w');\n    unsigned int warmup_ms = DEFAULT_WARMUP_MS;\n    if (arg) {\n        warmup_ms = atoi(arg);\n    }\n    return (struct args_t){\n        .help_requested = 0,\n        .size = size,\n        .number_of_pings = number_of_pings,\n        .warmup_ms = warmup_ms,\n    };\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION or Z_FEATURE_PUBLICATION but this example \"\n        \"requires them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_pong.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"stdio.h\"\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\nvoid callback(z_loaned_sample_t* sample, void* context) {\n    const z_loaned_publisher_t* pub = z_loan(*(z_owned_publisher_t*)context);\n    z_owned_bytes_t payload;\n    z_bytes_clone(&payload, z_sample_payload(sample));\n    z_publisher_put(pub, z_move(payload), NULL);\n}\nvoid drop(void* context) {\n    z_owned_publisher_t* pub = (z_owned_publisher_t*)context;\n    z_drop(z_move(*pub));\n    // A note on lifetimes:\n    //  here, `sub` takes ownership of `pub` and will drop it before returning from its own `drop`,\n    //  which makes passing a pointer to the stack safe as long as `sub` is dropped in a scope where `pub` is still\n    //  valid.\n}\n\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_session_t session;\n    if (z_open(&session, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t pong;\n    z_view_keyexpr_from_str_unchecked(&pong, \"test/pong\");\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(session), &pub, z_loan(pong), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ping;\n    z_view_keyexpr_from_str_unchecked(&ping, \"test/ping\");\n    z_owned_closure_sample_t respond;\n    z_closure(&respond, callback, drop, (void*)(&pub));\n\n    if (z_declare_background_subscriber(z_loan(session), z_loan(ping), z_move(respond), NULL) < 0) {\n        printf(\"Unable to declare subscriber for key expression.\\n\");\n        return -1;\n    }\n\n    while (getchar() != 'q') {\n    }\n    z_drop(z_move(session));\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION or Z_FEATURE_PUBLICATION but this example \"\n        \"requires them.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_pub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    const char *value = \"Pub from Pico!\";\n    const char *mode = \"client\";\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    char *buf = (char *)malloc(256);\n    for (int idx = 0; 1; ++idx) {\n        z_sleep_s(1);\n        snprintf(buf, 256, \"[%4d] %s\", idx, value);\n        printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_from_str(&payload, buf, NULL, NULL);\n\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n\n    // Clean-up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    free(buf);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_pub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#define N 2147483647  // max int value by default\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_MULTI_THREAD == 0\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/zenoh-pico-pub\";\n    const char *value = \"Pub from Pico!\";\n    const char *mode = \"client\";\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring publisher for '%s'...\\n\", keyexpr);\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    char *buf = (char *)malloc(256);\n    z_clock_t now = z_clock_now();\n    for (int idx = 0; idx < N;) {\n        if (z_clock_elapsed_ms(&now) > 1000) {\n            snprintf(buf, 256, \"[%4d] %s\", idx, value);\n            printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, buf);\n\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_copy_from_str(&payload, buf);\n\n            z_publisher_put(z_loan(pub), z_move(payload), NULL);\n            ++idx;\n\n            now = z_clock_now();\n        }\n\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n\n    z_drop(z_move(pub));\n\n    z_drop(z_move(s));\n\n    free(buf);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_PUBLICATION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_pull.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/**\";\n    char *locator = NULL;\n    size_t interval = 5000;\n    size_t size = 3;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, size);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", interval, size);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &sample); res == Z_OK; res = z_try_recv(z_loan(handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n            z_drop(z_move(value));\n            z_drop(z_move(sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", interval);\n            z_sleep_ms(interval);\n        } else {\n            break;\n        }\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_put.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_PUBLICATION == 1\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/zenoh-pico-put\";\n    const char *value = \"Pub from Pico!\";\n    const char *mode = \"client\";\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    printf(\"Declaring key expression '%s'...\\n\", keyexpr);\n    z_view_keyexpr_t vke;\n    if (z_view_keyexpr_from_str(&vke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    z_owned_keyexpr_t ke;\n    if (z_declare_keyexpr(z_loan(s), &ke, z_loan(vke)) < 0) {\n        printf(\"Unable to declare key expression!\\n\");\n        z_drop(z_move(s));\n        return -1;\n    }\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, value);\n\n    printf(\"Putting Data ('%s': '%s')...\\n\", keyexpr, value);\n    if (z_put(z_loan(s), z_loan(ke), z_move(payload), NULL) < 0) {\n        printf(\"Oh no! Put has failed...\\n\");\n    }\n\n    // Clean up\n    z_undeclare_keyexpr(z_loan(s), z_move(ke));\n    z_drop(z_move(s));\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\nconst char *keyexpr = \"demo/example/zenoh-pico-queryable\";\nconst char *value = \"Queryable from Pico!\";\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, value);\n\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create queryable.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        Sleep(1);\n    }\n\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_loan(s)), z_string_data(z_loan(s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_move(config), z_move(closure), NULL);\n    Sleep(1);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_sub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/**\";\n    const char *mode = \"client\";\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (1) {\n        Sleep(1);\n    }\n\n    z_drop(z_move(sub));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/windows/z_sub_st.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <ctype.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#define N 2147483647  // max int value by default\nint msg_nb = 0;\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_MULTI_THREAD == 0\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    msg_nb++;\n}\n\nint main(int argc, char **argv) {\n    (void)(argc);\n    (void)(argv);\n    const char *keyexpr = \"demo/example/**\";\n    const char *mode = \"client\";\n    char *locator = NULL;\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    if (locator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, locator);\n    }\n\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    if (z_view_keyexpr_from_str(&ke, keyexpr) < 0) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr);\n        return -1;\n    }\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Press CTRL-C to quit...\\n\");\n    while (msg_nb < N) {\n        z_sleep_ms(50);\n        zp_spin_once(z_loan(s));\n    }\n\n    z_drop(z_move(sub));\n\n    z_drop(z_move(s));\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\n        \"ERROR: Zenoh pico must be compiled with Z_FEATURE_SUBSCRIPTION = 1 and Z_FEATURE_MULTI_THREAD = 0 to run this \"\n        \"example.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/zephyr/z_get.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERY == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n#define VALUE \"\"\n\nvoid reply_dropper(void *ctx) { printf(\" >> Received query final notification\\n\"); }\n\nvoid reply_handler(z_loaned_reply_t *oreply, void *ctx) {\n    if (z_reply_is_ok(oreply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(oreply);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n\n        printf(\" >> Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)),\n               (int)z_string_len(z_loan(replystr)), z_string_data(z_loan(replystr)));\n        z_drop(z_move(replystr));\n    } else {\n        printf(\" >> Received an error\\n\");\n    }\n}\n\nint main(int argc, char **argv) {\n    sleep(5);\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n\n    while (1) {\n        sleep(5);\n        printf(\"Sending Query '%s'...\\n\", KEYEXPR);\n        z_get_options_t opts;\n        z_get_options_default(&opts);\n        opts.target = Z_QUERY_TARGET_ALL;\n        // Value encoding\n        z_owned_bytes_t payload;\n        if (strcmp(VALUE, \"\") != 0) {\n            z_bytes_from_static_str(&payload, VALUE);\n            opts.payload = z_move(payload);\n        }\n        z_owned_closure_reply_t callback;\n        z_closure(&callback, reply_handler, reply_dropper, NULL);\n        z_view_keyexpr_t ke;\n        z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n        if (z_get(z_loan(s), z_loan(ke), \"\", z_move(callback), &opts) < 0) {\n            printf(\"Unable to send query.\\n\");\n            return -1;\n        }\n    }\n\n    printf(\"Closing Zenoh Session...\");\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/zephyr/z_pub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <zenoh-pico.h>\n\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-pub\"\n#define VALUE \"[STSTM32]{nucleo-F767ZI} Pub from Zenoh-Pico!\"\n\n#if Z_FEATURE_PUBLICATION == 1\nint main(int argc, char **argv) {\n    sleep(5);\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring publisher for '%s'...\", KEYEXPR);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    z_owned_publisher_t pub;\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n\n    char buf[256];\n    for (int idx = 0; 1; ++idx) {\n        sleep(1);\n        sprintf(buf, \"[%4d] %s\", idx, VALUE);\n        printf(\"Putting Data ('%s': '%s')...\\n\", KEYEXPR, buf);\n\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_drop(z_move(pub));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/zephyr/z_pull.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nconst size_t INTERVAL = 5000;\nconst size_t SIZE = 3;\n\nint main(int argc, char **argv) {\n    sleep(5);\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring Subscriber on '%s'...\\n\", KEYEXPR);\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, SIZE);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(closure), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n\n    printf(\"Pulling data every %zu ms... Ring size: %zd\\n\", INTERVAL, SIZE);\n    z_owned_sample_t sample;\n    while (true) {\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &sample); res == Z_OK; res = z_try_recv(z_loan(handler), &sample)) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            z_owned_string_t value;\n            z_bytes_to_string(z_sample_payload(z_loan(sample)), &value);\n            printf(\">> [Subscriber] Pulled ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n            z_drop(z_move(value));\n            z_drop(z_move(sample));\n        }\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\">> [Subscriber] Nothing to pull... sleep for %zu ms\\n\", INTERVAL);\n            z_sleep_ms(INTERVAL);\n        } else {\n            break;\n        }\n    }\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/zephyr/z_queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_QUERYABLE == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/zenoh-pico-queryable\"\n#define VALUE \"[STSTM32]{nucleo-F767ZI} Queryable from Zenoh-Pico!\"\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable handler] Received Query '%.*s%.*s'\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Process value\n    z_owned_string_t payload_string;\n    z_bytes_to_string(z_query_payload(query), &payload_string);\n    if (z_string_len(z_loan(payload_string)) > 0) {\n        printf(\"     with value '%.*s'\\n\", (int)z_string_len(z_loan(payload_string)),\n               z_string_data(z_loan(payload_string)));\n    }\n    z_drop(z_move(payload_string));\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, VALUE);\n\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n}\n\nint main(int argc, char **argv) {\n    sleep(5);\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n\n    // Declare Zenoh queryable\n    printf(\"Declaring Queryable on %s...\", KEYEXPR);\n    z_owned_closure_query_t callback;\n    z_closure(&callback, query_handler, NULL, NULL);\n    z_owned_queryable_t qable;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    if (z_declare_queryable(z_loan(s), &qable, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare queryable.\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n    printf(\"Zenoh setup finished!\\n\");\n\n    while (1) {\n        sleep(1);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_drop(z_move(qable));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/zephyr/z_scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SCOUTING == 1\nvoid fprintzid(FILE *stream, z_id_t zid) {\n    unsigned int zidlen = _z_id_len(zid);\n    if (zidlen == 0) {\n        fprintf(stream, \"None\");\n    } else {\n        fprintf(stream, \"Some(\");\n        for (unsigned int i = 0; i < zidlen; i++) {\n            fprintf(stream, \"%02X\", (int)zid.id[i]);\n        }\n        fprintf(stream, \")\");\n    }\n}\n\nvoid fprintwhatami(FILE *stream, z_whatami_t whatami) {\n    z_view_string_t s;\n    z_whatami_to_view_string(whatami, &s);\n    fprintf(stream, \"\\\"%.*s\\\"\", (int)z_string_len(z_loan(s)), z_string_data(z_loan(s)));\n}\n\nvoid fprintlocators(FILE *stream, const z_loaned_string_array_t *locs) {\n    fprintf(stream, \"[\");\n    for (unsigned int i = 0; i < z_string_array_len(locs); i++) {\n        fprintf(stream, \"\\\"\");\n        const z_loaned_string_t *str = z_string_array_get(locs, i);\n        fprintf(stream, \"%.*s\", (int)z_string_len(str), z_string_data(str));\n        fprintf(stream, \"\\\"\");\n        if (i < z_string_array_len(locs) - 1) {\n            fprintf(stream, \", \");\n        }\n    }\n    fprintf(stream, \"]\");\n}\n\nvoid fprinthello(FILE *stream, const z_loaned_hello_t *hello) {\n    fprintf(stream, \"Hello { zid: \");\n    fprintzid(stream, z_hello_zid(hello));\n    fprintf(stream, \", whatami: \");\n    fprintwhatami(stream, z_hello_whatami(hello));\n    fprintf(stream, \", locators: \");\n    fprintlocators(stream, zp_hello_locators(hello));\n    fprintf(stream, \" }\");\n}\n\nvoid callback(z_loaned_hello_t *hello, void *context) {\n    fprinthello(stdout, hello);\n    fprintf(stdout, \"\\n\");\n    (*(int *)context)++;\n}\n\nvoid drop(void *context) {\n    int count = *(int *)context;\n    free(context);\n    if (!count) {\n        printf(\"Did not find any zenoh process.\\n\");\n    } else {\n        printf(\"Dropping scout results.\\n\");\n    }\n}\n\nint main(void) {\n    sleep(5);\n\n    int *context = (int *)malloc(sizeof(int));\n    *context = 0;\n    z_owned_config_t config;\n    z_config_default(&config);\n    z_owned_closure_hello_t closure;\n    z_closure_hello(&closure, callback, drop, context);\n    printf(\"Scouting...\\n\");\n    z_scout(z_config_move(&config), z_closure_hello_move(&closure), NULL);\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SCOUTING but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "examples/zephyr/z_sub.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n#define CLIENT_OR_PEER 0  // 0: Client mode; 1: Peer mode\n#if CLIENT_OR_PEER == 0\n#define MODE \"client\"\n#define LOCATOR \"\"  // If empty, it will scout\n#elif CLIENT_OR_PEER == 1\n#define MODE \"peer\"\n#define LOCATOR \"udp/224.0.0.225:7447#iface=en0\"\n#else\n#error \"Unknown Zenoh operation mode. Check CLIENT_OR_PEER value.\"\n#endif\n\n#define KEYEXPR \"demo/example/**\"\n\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\" >> [Subscriber handler] Received ('%.*s': '%.*s')\\n\", (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n}\n\nint main(int argc, char **argv) {\n    sleep(5);\n\n    // Initialize Zenoh Session and other parameters\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, MODE);\n    if (strcmp(LOCATOR, \"\") != 0) {\n        if (strcmp(MODE, \"client\") == 0) {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, LOCATOR);\n        } else {\n            zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, LOCATOR);\n        }\n    }\n\n    // Open Zenoh session\n    printf(\"Opening Zenoh Session...\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    printf(\"OK\\n\");\n\n    printf(\"Declaring Subscriber on '%s'...\", KEYEXPR);\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str_unchecked(&ke, KEYEXPR);\n    z_owned_subscriber_t sub;\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n    printf(\"OK!\\n\");\n\n    while (1) {\n        sleep(1);\n    }\n\n    printf(\"Closing Zenoh Session...\");\n    z_drop(z_move(sub));\n\n    z_drop(z_move(s));\n    printf(\"OK!\\n\");\n\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "extra_script.py",
    "content": "#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\nimport os\nimport subprocess\n\nImport('env', 'projenv')\n\nSRC_FILTER = []\nCPPDEFINES = []\nZP_PLATFORM = None\n\nBASE_SRC_FILTER = [\n    \"+<*>\",\n    \"-<tests/>\",\n    \"-<example/>\",\n    \"-<system/>\",\n    \"+<system/common/>\",\n    \"+<system/socket/>\",\n]\n\n\ndef _platform_src_filter(system_dir):\n    return BASE_SRC_FILTER + [f\"+<{system_dir}/>\"]\n\nFRAMEWORK = env.get(\"PIOFRAMEWORK\")[0]\nPLATFORM = env.get(\"PIOPLATFORM\")\nBOARD = env.get(\"PIOENV\")\nZENOH_GENERIC = env.get(\"ZENOH_GENERIC\", \"0\")\nif ZENOH_GENERIC == \"1\":\n    FRAMEWORK = 'generic'\n    PLATFORM = 'generic'\n    BOARD = 'generic'\n\nif FRAMEWORK == 'zephyr':\n    SRC_FILTER = _platform_src_filter(\"system/zephyr\")\n    ZP_PLATFORM = \"zephyr\"\n    CPPDEFINES = [\n        \"ZENOH_ZEPHYR\",\n    ]\n\nelif FRAMEWORK == 'arduino':\n    PLATFORM = env.get(\"PIOPLATFORM\")\n    if PLATFORM == 'espressif32':\n        SRC_FILTER = _platform_src_filter(\"system/arduino/esp32\")\n        ZP_PLATFORM = \"arduino_esp32\"\n        CPPDEFINES = [\n            \"ZENOH_ARDUINO_ESP32\",\n            \"ZENOH_COMPILER_GCC\",\n            \"ZENOH_C_STANDARD=99\",\n        ]\n    if PLATFORM == 'ststm32':\n        BOARD = env.get(\"PIOENV\")\n        if BOARD == 'opencr':\n            SRC_FILTER = _platform_src_filter(\"system/arduino/opencr\")\n            ZP_PLATFORM = \"opencr\"\n            CPPDEFINES = [\n                \"ZENOH_ARDUINO_OPENCR\",\n                \"ZENOH_C_STANDARD=99\",\n                \"Z_FEATURE_MULTI_THREAD=0\",\n            ]\n\nelif FRAMEWORK == 'espidf':\n    SRC_FILTER = _platform_src_filter(\"system/espidf\")\n    ZP_PLATFORM = \"espidf\"\n    CPPDEFINES = [\n        \"ZENOH_ESPIDF\",\n    ]\n\nelif FRAMEWORK == 'mbed':\n    SRC_FILTER = _platform_src_filter(\"system/mbed\")\n    ZP_PLATFORM = \"mbed\"\n    CPPDEFINES = [\n        \"ZENOH_MBED\",\n        \"ZENOH_C_STANDARD=99\",\n    ]\nelif FRAMEWORK == 'generic':\n    SRC_FILTER = BASE_SRC_FILTER\n    CPPDEFINES = [\"ZENOH_GENERIC\"]\n\nenv.Append(SRC_FILTER=SRC_FILTER)\nenv.Append(CPPDEFINES=CPPDEFINES)\n\n# pass flags to the main project environment\nprojenv.Append(CPPDEFINES=CPPDEFINES)\n\n# pass flags to a global build environment (for all libraries, etc)\nglobal_env = DefaultEnvironment()\nglobal_env.Append(CPPDEFINES=CPPDEFINES)\n\n# Run CMake for zenoh-pico\n\n# Default embedded buffer values\ndefault_args = [\"-DFRAG_MAX_SIZE=4096\", \"-DBATCH_UNICAST_SIZE=2048\", \"-DBATCH_MULTICAST_SIZE=2048\"]\n\n# Get the additional CMake arguments from the environment\ncmake_extra_args = env.BoardConfig().get(\"build.cmake_extra_args\", \"\")\ncmake_extra_args_list = cmake_extra_args.split()\n\n\ndef _has_cmake_arg(name):\n    prefix = f\"{name}=\"\n    return any(arg.startswith(prefix) for arg in cmake_extra_args_list)\n\n\nif (\n    ZP_PLATFORM is not None\n    and not _has_cmake_arg(\"-DZP_PLATFORM\")\n):\n    cmake_extra_args_list.append(f\"-DZP_PLATFORM={ZP_PLATFORM}\")\n\n# Add default value if needed\nfor default in default_args:\n    arg_name = default.split('=')[0]\n    if not any(arg.startswith(arg_name) for arg in cmake_extra_args_list):\n        cmake_extra_args_list.append(default)\n\n# Define the source and binary directories\nsource_dir = os.getcwd()\nbuild_dir = os.path.join(source_dir, \"build\")\nos.makedirs(build_dir, exist_ok=True)\ngenerated_include_dir = os.path.join(build_dir, \"include\")\nfor build_env in (env, projenv, global_env):  # pylint: disable=undefined-variable\n    build_env.Prepend(CPPPATH=[generated_include_dir])\n    build_env.Prepend(CCFLAGS=[f\"-I{generated_include_dir}\"])\n# Run the CMake command with the source and binary directories\nprint(\"Run command: cmake\", source_dir, cmake_extra_args_list)\nsubprocess.run([\"cmake\", source_dir] + cmake_extra_args_list, cwd=build_dir, check=True)\n"
  },
  {
    "path": "include/zenoh-pico/api/admin_space.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_API_ADMIN_SPACE_H\n#define ZENOH_PICO_API_ADMIN_SPACE_H\n\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/list.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_ADMIN_SPACE == 1\n\n/**\n * Starts the admin space for a session.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to start the admin space on.\n *\n * Return:\n *   ``0`` if start operation is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t zp_start_admin_space(z_loaned_session_t *zs);\n\n/**\n * Stops the admin space for a session.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to stop the admin space on.\n *\n * Return:\n *   ``0`` if stop operation is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t zp_stop_admin_space(z_loaned_session_t *zs);\n\ntypedef struct {\n    z_owned_keyexpr_t ke;\n    z_owned_bytes_t payload;\n} _ze_admin_space_reply_t;\n\nvoid _ze_admin_space_reply_clear(_ze_admin_space_reply_t *reply);\n\n_Z_ELEM_DEFINE(_ze_admin_space_reply, _ze_admin_space_reply_t, _z_noop_size, _ze_admin_space_reply_clear, _z_noop_copy,\n               _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_LIST_DEFINE(_ze_admin_space_reply, _ze_admin_space_reply_t)\n\n#endif  // Z_FEATURE_ADMIN_SPACE == 1\n#endif  // Z_FEATURE_UNSTABLE_API\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_API_ADMIN_SPACE_H */\n"
  },
  {
    "path": "include/zenoh-pico/api/advanced_publisher.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef INCLUDE_ZENOH_PICO_API_ADVANCED_PUBLISHER_H\n#define INCLUDE_ZENOH_PICO_API_ADVANCED_PUBLISHER_H\n\n#include <stdbool.h>\n\n#include \"olv_macros.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/advanced_cache.h\"\n#include \"zenoh-pico/collections/atomic.h\"\n#include \"zenoh-pico/collections/seqnumber.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef enum {\n    _ZE_ADVANCED_PUBLISHER_SEQUENCING_NONE = 0,\n    _ZE_ADVANCED_PUBLISHER_SEQUENCING_TIMESTAMP = 1,\n    _ZE_ADVANCED_PUBLISHER_SEQUENCING_SEQUENCE_NUMBER = 2\n} _ze_advanced_publisher_sequencing_t;\n\n/**\n * Whatami values, defined as a bitmask.\n *\n * Enumerators:\n *   ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE: Disable heartbeat-based last sample miss detection.\n *   ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_PERIODIC: Allow last sample miss detection through periodic\n *     heartbeat. Periodically send the last published Sample's sequence number to allow last sample recovery.\n *   ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_SPORADIC: Allow last sample miss detection through sporadic\n *     heartbeat. Each period, the last published Sample's sequence number is sent with\n *     `Z_CONGESTION_CONTROL_DROP` but only if it changed since last period.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef enum {\n    ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE,\n    ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_PERIODIC,\n    ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_SPORADIC,\n} ze_advanced_publisher_heartbeat_mode_t;\n#define ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_DEFAULT ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE\n\ntypedef struct _ze_advanced_publisher_state_t {\n    _z_atomic_size_t _seqnumber;\n    ze_advanced_publisher_heartbeat_mode_t _heartbeat_mode;\n    _z_session_weak_t _zn;\n    z_owned_publisher_t _publisher;\n    _z_fut_handle_t _state_publisher_task_handle;\n    uint64_t _heartbeat_period_ms;\n    uint32_t _last_published_sn;\n} _ze_advanced_publisher_state_t;\n\nvoid _ze_advanced_publisher_state_clear(_ze_advanced_publisher_state_t *state);\n\n_Z_REFCOUNT_DEFINE_NO_FROM_VAL(_ze_advanced_publisher_state, _ze_advanced_publisher_state)\n\ntypedef struct {\n    z_owned_publisher_t _publisher;\n    _ze_advanced_cache_t *_cache;\n    bool _has_liveliness;\n    z_owned_liveliness_token_t _liveliness;\n    _ze_advanced_publisher_sequencing_t _sequencing;\n    _ze_advanced_publisher_state_rc_t _state;\n} _ze_advanced_publisher_t;\n\n_Z_OWNED_TYPE_VALUE_PREFIX(ze, _ze_advanced_publisher_t, advanced_publisher)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_TAKE_FROM_LOANED_DEF_PREFIX(ze, advanced_publisher)\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n\n/**************** Advanced Publisher ****************/\n\n/**\n * Represents the set of options for sample miss detection on an advanced publisher.\n *\n * Members:\n *   bool is_enabled: Must be set to ``true``, to enable sample miss detection by adding\n *     sequence numbers.\n *   enum ze_advanced_publisher_heartbeat_mode_t heartbeat_mode: Allow last sample miss\n *     detection through sporadic or periodic heartbeat.\n *   uint64_t heartbeat_period_ms: If heartbeat_mode is not ``NONE``, the publisher will send\n *     heartbeats with the specified period, which can be used by Advanced Subscribers for last\n *     sample(s) miss detection (if last sample miss detection with zero query period is enabled).\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    bool is_enabled;\n    ze_advanced_publisher_heartbeat_mode_t heartbeat_mode;\n    uint64_t heartbeat_period_ms;\n} ze_advanced_publisher_sample_miss_detection_options_t;\n\n/**\n * Represents the set of options that can be applied to an advanced publisher,\n * upon its declaration via :c:func:`ze_declare_advanced_publisher`.\n *\n * Members:\n *   z_publisher_options_t publisher_options: Base publisher options.\n *   ze_advanced_publisher_cache_options_t cache: Publisher cache settings.\n *   ze_advanced_publisher_sample_miss_detection_options_t sample_miss_detection: Allow\n *     matching Subscribers to detect lost samples and optionally ask for retransmission.\n *     Retransmission can only be done if history is enabled on subscriber side.\n *   bool publisher_detection: Allow this publisher to be detected through liveliness.\n *   z_loaned_keyexpr_t *publisher_detection_metadata: An optional key expression to be added\n *     to the liveliness token key expression. It can be used to convey meta data.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    z_publisher_options_t publisher_options;\n    ze_advanced_publisher_cache_options_t cache;\n    ze_advanced_publisher_sample_miss_detection_options_t sample_miss_detection;\n    bool publisher_detection;\n    z_loaned_keyexpr_t *publisher_detection_metadata;\n} ze_advanced_publisher_options_t;\n\n/**\n * Builds a :c:type:`ze_advanced_publisher_cache_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_publisher_cache_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_publisher_cache_options_default(ze_advanced_publisher_cache_options_t *options);\n\n/**\n * Builds a :c:type:`ze_advanced_publisher_sample_miss_detection_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_publisher_sample_miss_detection_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_publisher_sample_miss_detection_options_default(\n    ze_advanced_publisher_sample_miss_detection_options_t *options);\n\n/**\n * Builds a :c:type:`ze_advanced_publisher_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_publisher_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_publisher_options_default(ze_advanced_publisher_options_t *options);\n\n/**\n * Declares an advanced publisher for a given keyexpr.\n *\n * Data can be put and deleted with this advanced publisher with the help of the\n * :c:func:`ze_advanced_publisher_put` and :c:func:`ze_advanced_publisher_delete` functions.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the advanced publisher through.\n *   pub: Pointer to an uninitialized :c:type:`ze_owned_advanced_publisher_t`.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the advanced publisher with.\n *   options: Pointer to a :c:type:`ze_advanced_publisher_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_declare_advanced_publisher(const z_loaned_session_t *zs, ze_owned_advanced_publisher_t *pub,\n                                         const z_loaned_keyexpr_t *keyexpr,\n                                         const ze_advanced_publisher_options_t *options);\n\n/**\n * Undeclares the advanced publisher.\n *\n * Parameters:\n *   pub: Moved :c:type:`ze_owned_advanced_publisher_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_undeclare_advanced_publisher(ze_moved_advanced_publisher_t *pub);\n\n/**\n * Represents the set of options passed to the `ze_advanced_publisher_put()` function.\n *\n * Members:\n *   z_publisher_put_options_t put_options: Base put options.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    z_publisher_put_options_t put_options;\n} ze_advanced_publisher_put_options_t;\n\n/**\n * Builds a :c:type:`ze_advanced_publisher_put_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_publisher_put_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_publisher_put_options_default(ze_advanced_publisher_put_options_t *options);\n\n/**\n * Represents the set of options passed to the `ze_advanced_publisher_delete()` function.\n *\n * Members:\n *   z_publisher_delete_options_t delete_options: Base delete options.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    z_publisher_delete_options_t delete_options;\n} ze_advanced_publisher_delete_options_t;\n\n/**\n * Builds a :c:type:`ze_advanced_publisher_delete_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_publisher_delete_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_publisher_delete_options_default(ze_advanced_publisher_delete_options_t *options);\n\n/**\n * Puts data for the keyexpr bound to the given advanced publisher.\n *\n * Parameters:\n *   pub: Pointer to a :c:type:`ze_loaned_advanced_publisher_t` from where to put the data.\n *   payload: Moved :c:type:`z_owned_bytes_t` containing the data to put.\n *   options: Pointer to a :c:type:`ze_advanced_publisher_put_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_publisher_put(const ze_loaned_advanced_publisher_t *pub, z_moved_bytes_t *payload,\n                                     const ze_advanced_publisher_put_options_t *options);\n\n/**\n * Deletes data from the keyexpr bound to the given advanced publisher.\n *\n * Parameters:\n *   pub: Pointer to a :c:type:`ze_loaned_advanced_publisher_t` from where to delete the data.\n *   options: Pointer to a :c:type:`ze_advanced_publisher_delete_options_t` to configure the delete operation.\n *\n * Return:\n *   ``0`` if delete operation is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_publisher_delete(const ze_loaned_advanced_publisher_t *pub,\n                                        const ze_advanced_publisher_delete_options_t *options);\n\n/**\n * Gets the keyexpr from an advanced publisher.\n *\n * Parameters:\n *   publisher: Pointer to a :c:type:`ze_loaned_advanced_publisher_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a :c:type:`z_loaned_keyexpr_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nconst z_loaned_keyexpr_t *ze_advanced_publisher_keyexpr(const ze_loaned_advanced_publisher_t *pub);\n\n/**\n * Gets the entity global Id from an advanced publisher.\n *\n * Parameters:\n *   publisher: Pointer to a :c:type:`ze_loaned_advanced_publisher_t` to get the entity global Id from.\n *\n * Return:\n *   The entity global Id wrapped as a :c:type:`z_entity_global_global_id_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_entity_global_id_t ze_advanced_publisher_id(const ze_loaned_advanced_publisher_t *pub);\n\n#if Z_FEATURE_MATCHING == 1\n/**\n * Gets advanced publisher matching status - i.e. if there are any subscribers matching its key expression.\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_publisher_get_matching_status(const ze_loaned_advanced_publisher_t *publisher,\n                                                     z_matching_status_t *matching_status);\n\n/**\n * Constructs matching listener, registering a callback for notifying subscribers matching with a given advanced\n * publisher.\n *\n * Parameters:\n *   publisher: An advanced publisher to associate with matching listener.\n *   matching_listener: An uninitialized memory location where matching listener will be constructed. The matching\n *     listener's callback will be automatically dropped when the publisher is dropped.\n *   callback: A closure that will be called every time the matching status of the publisher changes (If last subscriber\n *     disconnects or when the first subscriber connects).\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_publisher_declare_matching_listener(const ze_loaned_advanced_publisher_t *publisher,\n                                                           z_owned_matching_listener_t *matching_listener,\n                                                           z_moved_closure_matching_status_t *callback);\n\n/**\n * Declares a matching listener, registering a callback for notifying subscribers matching with a given advanced\n * publisher. The callback will be run in the background until the corresponding advanced publisher is dropped.\n *\n * Parameters:\n *   publisher: An advanced publisher to associate with matching listener.\n *   callback: A closure that will be called every time the matching status of the publisher changes (If last subscriber\n *     disconnects or when the first subscriber connects).\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_publisher_declare_background_matching_listener(const ze_loaned_advanced_publisher_t *publisher,\n                                                                      z_moved_closure_matching_status_t *callback);\n#endif  // Z_FEATURE_MATCHING == 1\n#endif  // Z_FEATURE_ADVANCED_PUBLICATION == 1\n#endif  // Z_FEATURE_UNSTABLE_API\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // INCLUDE_ZENOH_PICO_API_ADVANCED_PUBLISHER_H\n"
  },
  {
    "path": "include/zenoh-pico/api/advanced_subscriber.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef INCLUDE_ZENOH_PICO_API_ADVANCED_SUBSCRIBER_H\n#define INCLUDE_ZENOH_PICO_API_ADVANCED_SUBSCRIBER_H\n\n#include \"olv_macros.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/hashmap.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/collections/sortedmap.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic inline size_t _z_uint32_size(const uint32_t *e) {\n    _ZP_UNUSED(e);\n    return sizeof(uint32_t);\n}\nstatic inline void _z_uint32_copy(uint32_t *dst, const uint32_t *src) { *dst = *src; }\nstatic inline int _z_uint32_cmp(const uint32_t *left, const uint32_t *right) {\n    if (*left < *right) return -1;\n    if (*left > *right) return 1;\n    return 0;\n}\n_Z_ELEM_DEFINE(_z_uint32, uint32_t, _z_uint32_size, _z_noop_clear, _z_uint32_copy, _z_noop_move, _z_noop_eq,\n               _z_uint32_cmp, _z_noop_hash)\n_Z_SORTEDMAP_DEFINE(_z_uint32, _z_sample, uint32_t, _z_sample_t)\n\n_Z_SORTEDMAP_DEFINE(_z_timestamp, _z_sample, _z_timestamp_t, _z_sample_t)\n\ntypedef struct {\n    _z_session_weak_t _zn;\n    bool _has_last_delivered;\n    uint32_t _last_delivered;\n    uint64_t _pending_queries;\n    _z_uint32__z_sample_sortedmap_t _pending_samples;\n    _z_fut_handle_t _periodic_query_handle;\n    z_owned_keyexpr_t _query_keyexpr;\n} _ze_advanced_subscriber_sequenced_state_t;\n\nstatic inline size_t _ze_advanced_subscriber_sequenced_state_size(_ze_advanced_subscriber_sequenced_state_t *s) {\n    _ZP_UNUSED(s);\n    return sizeof(_ze_advanced_subscriber_sequenced_state_t);\n}\nvoid _ze_advanced_subscriber_sequenced_state_clear(_ze_advanced_subscriber_sequenced_state_t *s);\n\n_Z_ELEM_DEFINE(_ze_advanced_subscriber_sequenced_state, _ze_advanced_subscriber_sequenced_state_t,\n               _ze_advanced_subscriber_sequenced_state_size, _ze_advanced_subscriber_sequenced_state_clear,\n               _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n\ntypedef struct {\n    bool _has_last_delivered;\n    _z_timestamp_t _last_delivered;\n    uint64_t _pending_queries;\n    _z_timestamp__z_sample_sortedmap_t _pending_samples;\n} _ze_advanced_subscriber_timestamped_state_t;\n\nstatic inline size_t _ze_advanced_subscriber_timestamped_state_size(_ze_advanced_subscriber_timestamped_state_t *s) {\n    _ZP_UNUSED(s);\n    return sizeof(_ze_advanced_subscriber_timestamped_state_t);\n}\nvoid _ze_advanced_subscriber_timestamped_state_clear(_ze_advanced_subscriber_timestamped_state_t *s);\n\n_Z_ELEM_DEFINE(_ze_advanced_subscriber_timestamped_state, _ze_advanced_subscriber_timestamped_state_t,\n               _ze_advanced_subscriber_timestamped_state_size, _ze_advanced_subscriber_timestamped_state_clear,\n               _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n\n_Z_HASHMAP_DEFINE(_z_entity_global_id, _ze_advanced_subscriber_sequenced_state, _z_entity_global_id_t,\n                  _ze_advanced_subscriber_sequenced_state_t)\n_Z_HASHMAP_DEFINE(_z_id, _ze_advanced_subscriber_timestamped_state, z_id_t, _ze_advanced_subscriber_timestamped_state_t)\n\nstatic inline _ze_closure_miss_t _ze_closure_miss_null(void) {\n    _ze_closure_miss_t miss = {0};\n    return miss;\n}\nstatic inline void _ze_closure_miss_drop(_ze_closure_miss_t *closure) {\n    if (closure->drop != NULL) {\n        closure->drop(closure->context);\n    }\n    *closure = _ze_closure_miss_null();\n}\n\nstatic inline void _ze_closure_miss_copy(_ze_closure_miss_t *dst, const _ze_closure_miss_t *src) { *dst = *src; }\nstatic inline void _ze_closure_miss_move(_ze_closure_miss_t *dst, _ze_closure_miss_t *src) {\n    *dst = *src;\n    *src = _ze_closure_miss_null();\n}\n\n_Z_ELEM_DEFINE(_ze_closure_miss, _ze_closure_miss_t, _z_noop_size, _ze_closure_miss_drop, _ze_closure_miss_copy,\n               _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_ze_closure_miss, _ze_closure_miss_t)\n\ntypedef struct {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_owned_mutex_t _mutex;\n#endif\n    size_t _next_id;\n    uint64_t _global_pending_queries;\n    _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_t _sequenced_states;\n    _z_id__ze_advanced_subscriber_timestamped_state_hashmap_t _timestamped_states;\n    _z_session_weak_t _zn;\n    z_owned_keyexpr_t _keyexpr;\n    bool _retransmission;\n    bool _has_period;\n    uint64_t _period_ms;\n    size_t _history_depth;\n    uint64_t _history_age;\n    z_query_target_t _query_target;\n    uint64_t _query_timeout;\n    _z_closure_sample_callback_t _callback;\n    _z_drop_handler_t _dropper;\n    void *_ctx;\n    _ze_closure_miss_intmap_t _miss_handlers;\n    bool _has_token;\n    z_owned_liveliness_token_t _token;\n    z_owned_cancellation_token_t _cancellation_token;\n    bool _is_undeclaring;\n} _ze_advanced_subscriber_state_t;\n\n_ze_advanced_subscriber_state_t _ze_advanced_subscriber_state_null(void);\nvoid _ze_advanced_subscriber_state_clear(_ze_advanced_subscriber_state_t *state);\n\n_Z_REFCOUNT_DEFINE(_ze_advanced_subscriber_state, _ze_advanced_subscriber_state)\n\ntypedef struct {\n    z_owned_subscriber_t _subscriber;\n    bool _has_liveliness_subscriber;\n    z_owned_subscriber_t _liveliness_subscriber;\n    bool _has_heartbeat_subscriber;\n    z_owned_subscriber_t _heartbeat_subscriber;\n    _ze_advanced_subscriber_state_rc_t _state;\n} _ze_advanced_subscriber_t;\n\n_Z_OWNED_TYPE_VALUE_PREFIX(ze, _ze_advanced_subscriber_t, advanced_subscriber)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_TAKE_FROM_LOANED_DEF_PREFIX(ze, advanced_subscriber)\n\ntypedef struct {\n    size_t _id;\n    _ze_advanced_subscriber_state_weak_t _statesref;\n} _ze_sample_miss_listener_t;\n\nstatic inline _ze_sample_miss_listener_t _ze_sample_miss_listener_null(void) { return (_ze_sample_miss_listener_t){0}; }\nstatic inline bool _ze_sample_miss_listener_check(const _ze_sample_miss_listener_t *miss_listener) {\n    return !_Z_SIMPLE_RC_IS_NULL(&miss_listener->_statesref);\n}\n\n_Z_OWNED_TYPE_VALUE_PREFIX(ze, _ze_sample_miss_listener_t, sample_miss_listener)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_TAKE_FROM_LOANED_DEF_PREFIX(ze, sample_miss_listener)\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_ADVANCED_SUBSCRIPTION == 1\n\n/**\n * Settings for retrieving historical data for Advanced Subscriber.\n *\n * Members:\n *   bool is_enabled: Must be set to ``true``, to enable the history data recovery.\n *   bool detect_late_publishers: Enable detection of late joiner publishers and query for\n *     their historical data. Late joiner detection can only be achieved for Publishers that\n *     enable publisher_detection. History can only be retransmitted by Publishers that enable\n *     caching.\n *   size_t max_samples: Number of samples to query for each resource. ``0`` corresponds to no\n *     limit on number of samples.\n *   uint64_t max_age_ms: Maximum age of samples to query. ``0`` corresponds to no limit on samples'\n *     age.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    bool is_enabled;\n    bool detect_late_publishers;\n    size_t max_samples;\n    uint64_t max_age_ms;\n} ze_advanced_subscriber_history_options_t;\n\n/**\n * Settings for detection of the last sample(s) miss by Advanced Subscriber.\n *\n * Members:\n *   bool is_enabled: Must be set to ``true``, to enable the last sample(s) miss detection.\n *   uint64_t periodic_queries_period_ms: Period for queries for not yet received Samples.\n *     These queries allow to retrieve the last Sample(s) if the last Sample(s) is/are lost.\n *     So it is useful for sporadic publications but useless for periodic publications with a\n *     period smaller or equal to this period. If set to 0, the last sample(s) miss detection\n *     will be performed based on publisher's heartbeat if the latter is enabled.\n *\n * Note: periodic queries require the periodic scheduler to be started via :c:func:`zp_start_periodic_scheduler_task`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    bool is_enabled;\n    uint64_t periodic_queries_period_ms;\n} ze_advanced_subscriber_last_sample_miss_detection_options_t;\n\n/**\n * Settings for recovering lost messages for Advanced Subscriber.\n *\n * Members:\n *   bool is_enabled: Must be set to ``true``, to enable the lost sample recovery.\n *   ze_advanced_subscriber_last_sample_miss_detection_options_t last_sample_miss_detection:\n *     Setting for detecting last sample(s) miss. Note that it does not affect intermediate sample\n *     miss detection/retrieval (which is performed automatically as long as recovery is enabled).\n *     If this option is disabled, subscriber will be unable to detect/request retransmission of\n *     missed sample until it receives a more recent one from the same publisher.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    bool is_enabled;\n    ze_advanced_subscriber_last_sample_miss_detection_options_t last_sample_miss_detection;\n} ze_advanced_subscriber_recovery_options_t;\n\n/**\n * Represents the set of options that can be applied to an advanced subscriber,\n * upon its declaration via :c:func:`ze_declare_advanced_subscriber`.\n *\n * Members:\n *   z_subscriber_options_t subscriber_options: Base subscriber options.\n *   ze_advanced_subscriber_history_options_t history: Settings for querying historical data.\n *     History can only be retransmitted by Publishers that enable caching.\n *   ze_advanced_subscriber_recovery_options_t recovery: Settings for retransmission of detected\n *     lost Samples. Retransmission of lost samples can only be done by Publishers that enable\n *     caching and sample_miss_detection.\n *   uint64_t query_timeout_ms: Timeout to be used for history and recovery queries.  Default value\n *     will be used if set to ``0``.\n *   bool subscriber_detection: Allow this subscriber to be detected through liveliness.\n *   const z_loaned_keyexpr_t *subscriber_detection_metadata: An optional key expression to be added\n *     to the liveliness token key expression. It can be used to convey meta data.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    z_subscriber_options_t subscriber_options;\n    ze_advanced_subscriber_history_options_t history;\n    ze_advanced_subscriber_recovery_options_t recovery;\n    uint64_t query_timeout_ms;\n    bool subscriber_detection;\n    const z_loaned_keyexpr_t *subscriber_detection_metadata;\n} ze_advanced_subscriber_options_t;\n\n/**\n * Declares an advanced subscriber for a given keyexpr. Note that dropping the subscriber drops its\n * callback.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the advanced subscriber through.\n *   subscriber: Pointer to an uninitialized :c:type:`ze_owned_advanced_subscriber_t`.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to subscribe to.\n *   callback: Pointer to a :c:type:`z_moved_closure_sample_t` that will be called each time a data\n *     matching the subscribed expression is received.\n *   options: Pointer to a :c:type:`ze_advanced_subscriber_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_declare_advanced_subscriber(const z_loaned_session_t *zs, ze_owned_advanced_subscriber_t *subscriber,\n                                          const z_loaned_keyexpr_t *keyexpr, z_moved_closure_sample_t *callback,\n                                          ze_advanced_subscriber_options_t *options);\n\n/**\n * Declares a background advanced subscriber. Subscriber callback will be called to process the messages,\n * until the corresponding session is closed or dropped.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the advanced subscriber through.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to subscribe to.\n *   callback: Pointer to a :c:type:`z_moved_closure_sample_t` that will be called each time a data\n *     matching the subscribed expression is received.\n *   options: Pointer to a :c:type:`ze_advanced_subscriber_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_declare_background_advanced_subscriber(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                                     z_moved_closure_sample_t *callback,\n                                                     ze_advanced_subscriber_options_t *options);\n\n/**\n * Undeclares the advanced subscriber.\n *\n * Parameters:\n *   subscriber: Moved :c:type:`ze_owned_advanced_subscriber_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_undeclare_advanced_subscriber(ze_moved_advanced_subscriber_t *subscriber);\n\n/**\n * Gets the keyexpr from an advanced subscriber.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`ze_loaned_advanced_subscriber_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a :c:type:`z_loaned_keyexpr_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nconst z_loaned_keyexpr_t *ze_advanced_subscriber_keyexpr(const ze_loaned_advanced_subscriber_t *subscriber);\n\n/**\n * Gets the entity global Id from an advanced subscriber.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`ze_loaned_advanced_subscriber_t` to get the entity global Id from.\n *\n * Return:\n *   The entity gloabl Id wrapped as a :c:type:`z_entity_global_global_id_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_entity_global_id_t ze_advanced_subscriber_id(const ze_loaned_advanced_subscriber_t *subscriber);\n\n/**\n * Declares a sample miss listener, registering a callback for notifying subscriber about missed samples.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`ze_loaned_advanced_subscriber_t` instance to associate with sample miss listener.\n *   sample_miss_listener: Pointer to an uninitialized :c:type:`ze_owned_sample_miss_listener_t` where sample miss\n *     listener will be constructed. The sample miss listener's callback will be automatically dropped when the\n * subscriber is dropped. callback: Pointer to a :c:type:`ze_moved_closure_miss_t` that will be called every time a\n * sample miss is detected.\n *\n * Return:\n *   ``0`` if successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_subscriber_declare_sample_miss_listener(const ze_loaned_advanced_subscriber_t *subscriber,\n                                                               ze_owned_sample_miss_listener_t *sample_miss_listener,\n                                                               ze_moved_closure_miss_t *callback);\n\n/**\n * Declares a sample miss listener, registering a callback for notifying subscriber about missed samples.\n * The callback will be run in the background until the corresponding subscriber is dropped.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`ze_loaned_advanced_subscriber_t` instance to associate with sample miss listener.\n *   callback: Pointer to a :c:type:`ze_moved_closure_miss_t` that will be called every time a sample miss is detected.\n *\n * Return:\n *   ``0`` if successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_subscriber_declare_background_sample_miss_listener(\n    const ze_loaned_advanced_subscriber_t *subscriber, ze_moved_closure_miss_t *callback);\n\n/**\n * Undeclares the given sample miss listener, droping and invalidating it.\n *\n * Parameters:\n *   sample_miss_listener: Moved :c:type:`ze_moved_sample_miss_listener_t` to undeclare\n *\n * Return:\n *   ``0`` if successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_undeclare_sample_miss_listener(ze_moved_sample_miss_listener_t *sample_miss_listener);\n\n/**\n * Declares a liveliness token listener for matching publishers detection. Only advanced publishers, enabling publisher\n * detection can be detected.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`ze_loaned_advanced_subscriber_t` instance.\n *   liveliness_subscriber: Pointer to an uninitialized :c:type:`z_owned_subscriber_t` where the liveliness subscriber\n *     will be constructed.\n *   callback: Pointer to a :c:type:`z_moved_closure_sample_t` that will be called each time a liveliness token status\n *     is changed.\n *   options: Pointer to a :c:type:`z_liveliness_subscriber_options_t` to configure the liveliness subscriber.\n *\n * Return:\n *   ``0`` if successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_subscriber_detect_publishers(const ze_loaned_advanced_subscriber_t *subscriber,\n                                                    z_owned_subscriber_t *liveliness_subscriber,\n                                                    z_moved_closure_sample_t *callback,\n                                                    z_liveliness_subscriber_options_t *options);\n\n/**\n * Declares a background subscriber on liveliness tokens of matching publishers. Subscriber callback will be called to\n * process the messages, until the corresponding session is closed or dropped. Only advanced publishers, enabling\n * publisher detection can be detected.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`ze_loaned_advanced_subscriber_t` instance.\n *   callback: Pointer to a :c:type:`z_moved_closure_sample_t` that will be called each time a liveliness token status\n *     is changed.\n *   options: Pointer to a :c:type:`z_liveliness_subscriber_options_t` to configure the liveliness subscriber.\n *\n * Return:\n *   ``0`` if successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_advanced_subscriber_detect_publishers_background(const ze_loaned_advanced_subscriber_t *subscriber,\n                                                               z_moved_closure_sample_t *callback,\n                                                               z_liveliness_subscriber_options_t *options);\n\n/**\n * Builds a :c:type:`ze_advanced_subscriber_history_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_subscriber_history_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_subscriber_history_options_default(ze_advanced_subscriber_history_options_t *options);\n\n/**\n * Builds a :c:type:`ze_advanced_subscriber_recovery_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_subscriber_recovery_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_subscriber_recovery_options_default(ze_advanced_subscriber_recovery_options_t *options);\n\n/**\n * Builds a :c:type:`ze_advanced_subscriber_last_sample_miss_detection_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_subscriber_last_sample_miss_detection_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_subscriber_last_sample_miss_detection_options_default(\n    ze_advanced_subscriber_last_sample_miss_detection_options_t *options);\n\n/**\n * Builds a :c:type:`ze_advanced_subscriber_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`ze_advanced_subscriber_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_advanced_subscriber_options_default(ze_advanced_subscriber_options_t *options);\n\n#endif  // Z_FEATURE_ADVANCED_SUBSCRIPTION == 1\n#endif  // Z_FEATURE_UNSTABLE_API\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // INCLUDE_ZENOH_PICO_API_ADVANCED_SUBSCRIBER_H\n"
  },
  {
    "path": "include/zenoh-pico/api/constants.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_API_CONSTANTS_H\n#define ZENOH_PICO_API_CONSTANTS_H\n\n#define Z_SELECTOR_TIME \"_time=\"\n#define Z_SELECTOR_QUERY_MATCH \"_anyke\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * What bitmask for scouting.\n *\n * Enumerators:\n *   Z_WHAT_ROUTER: Router.\n *   Z_WHAT_PEER: Peer.\n *   Z_WHAT_CLIENT: Client.\n */\ntypedef enum {\n    Z_WHAT_ROUTER = 0x01,  // Router\n    Z_WHAT_PEER = 0x02,    // Peer\n    Z_WHAT_CLIENT = 0x04,  // Client\n    Z_WHAT_ROUTER_PEER = (0x01 | 0x02),\n    Z_WHAT_ROUTER_CLIENT = (0x01 | 0x04),\n    Z_WHAT_PEER_CLIENT = (0x02 | 0x04),\n    Z_WHAT_ROUTER_PEER_CLIENT = ((0x01 | 0x02) | 0x04),\n} z_what_t;\n\n/**\n * Whatami values, defined as a bitmask.\n *\n * Enumerators:\n *   Z_WHATAMI_ROUTER: Bitmask to filter Zenoh routers.\n *   Z_WHATAMI_PEER: Bitmask to filter for Zenoh peers.\n *   Z_WHATAMI_CLIENT: Bitmask to filter for Zenoh clients.\n */\ntypedef enum z_whatami_t {\n    Z_WHATAMI_ROUTER = 0x01,\n    Z_WHATAMI_PEER = 0x02,\n    Z_WHATAMI_CLIENT = 0x04,\n} z_whatami_t;\n#define Z_WHATAMI_DEFAULT Z_WHATAMI_ROUTER;\n\n/**\n * The locality of samples to be received by subscribers or targeted by publishers.\n *\n * Enumerators:\n *   Z_LOCALITY_ANY: Allow both session-local and remote traffic.\n *   Z_LOCALITY_SESSION_LOCAL: Allow session-local traffic only.\n *   Z_LOCALITY_REMOTE: Allow remote traffic only.\n */\ntypedef enum z_locality_t {\n    Z_LOCALITY_ANY = 0,\n    Z_LOCALITY_SESSION_LOCAL = 1,\n    Z_LOCALITY_REMOTE = 2,\n} z_locality_t;\n\nstatic inline z_locality_t z_locality_default(void) { return Z_LOCALITY_ANY; }\n\n/**\n * Status values for keyexpr canonization operation.\n * Used as return value of canonization-related functions,\n * like :c:func:`z_keyexpr_is_canon` or :c:func:`z_keyexpr_canonize`.\n *\n * Enumerators:\n *   Z_KEYEXPR_CANON_SUCCESS: The key expression is canon.\n *   Z_KEYEXPR_CANON_LONE_DOLLAR_STAR: The key contains a ``$*`` chunk, which must be replaced by ``*``.\n *   Z_KEYEXPR_CANON_SINGLE_STAR_AFTER_DOUBLE_STAR: The key contains ``** / *``, which must be replaced by ``* / **``.\n *   Z_KEYEXPR_CANON_DOUBLE_STAR_AFTER_DOUBLE_STAR: The key contains ``** / **``, which must be replaced by ``**``.\n *   Z_KEYEXPR_CANON_EMPTY_CHUNK: The key contains empty chunks.\n *   Z_KEYEXPR_CANON_STARS_IN_CHUNK: The key contains a ``*`` in a chunk without being escaped by a DSL, which is\n *     forbidden.\n *   Z_KEYEXPR_CANON_DOLLAR_AFTER_DOLLAR_OR_STAR: The key contains ``$*$`` or ``$$``, which is forbidden.\n *   Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK: The key contains ``#`` or ``?``, which is forbidden.\n *   Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR: The key contains a ``$`` which is not bound to a DSL.\n */\ntypedef enum {\n    Z_KEYEXPR_CANON_SUCCESS = 0,\n    Z_KEYEXPR_CANON_LONE_DOLLAR_STAR = -1,\n    Z_KEYEXPR_CANON_SINGLE_STAR_AFTER_DOUBLE_STAR = -2,\n    Z_KEYEXPR_CANON_DOUBLE_STAR_AFTER_DOUBLE_STAR = -3,\n    Z_KEYEXPR_CANON_EMPTY_CHUNK = -4,\n    Z_KEYEXPR_CANON_STARS_IN_CHUNK = -5,\n    Z_KEYEXPR_CANON_DOLLAR_AFTER_DOLLAR_OR_STAR = -6,\n    Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK = -7,\n    Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR = -8\n} zp_keyexpr_canon_status_t;\n\n/**\n * Intersection level of two key expressions.\n *\n * Enumerators:\n *   Z_KEYEXPR_INTERSECTION_LEVEL_DISJOINT: The two key expressions do not intersect.\n *   Z_KEYEXPR_INTERSECTION_LEVEL_INTERSECTS: The two key expressions intersect, i.e. there exists at least one key\n *     expression that is included by both.\n *   Z_KEYEXPR_INTERSECTION_LEVEL_INCLUDES: The first key expression is the superset of the second one.\n *   Z_KEYEXPR_INTERSECTION_LEVEL_EQUALS: The two key expressions are equal.\n */\ntypedef enum {\n    Z_KEYEXPR_INTERSECTION_LEVEL_DISJOINT = 0,\n    Z_KEYEXPR_INTERSECTION_LEVEL_INTERSECTS = 1,\n    Z_KEYEXPR_INTERSECTION_LEVEL_INCLUDES = 2,\n    Z_KEYEXPR_INTERSECTION_LEVEL_EQUALS = 3,\n} z_keyexpr_intersection_level_t;\n\n/**\n * Key expression constant strings.\n */\n#define _Z_KEYEXPR_AT \"@\"\n#define _Z_KEYEXPR_AT_LEN (sizeof(_Z_KEYEXPR_AT) - 1)\n#define _Z_KEYEXPR_ADV_PREFIX \"@adv\"\n#define _Z_KEYEXPR_ADV_PREFIX_LEN (sizeof(_Z_KEYEXPR_ADV_PREFIX) - 1)\n#define _Z_KEYEXPR_PUB \"pub\"\n#define _Z_KEYEXPR_PUB_LEN (sizeof(_Z_KEYEXPR_PUB) - 1)\n#define _Z_KEYEXPR_SUB \"sub\"\n#define _Z_KEYEXPR_SUB_LEN (sizeof(_Z_KEYEXPR_SUB) - 1)\n#define _Z_KEYEXPR_UHLC \"uhlc\"\n#define _Z_KEYEXPR_UHLC_LEN (sizeof(_Z_KEYEXPR_UHLC) - 1)\n#define _Z_KEYEXPR_EMPTY \"_\"\n#define _Z_KEYEXPR_EMPTY_LEN (sizeof(_Z_KEYEXPR_EMPTY) - 1)\n#define _Z_KEYEXPR_STAR \"*\"\n#define _Z_KEYEXPR_STAR_LEN (sizeof(_Z_KEYEXPR_STAR) - 1)\n#define _Z_KEYEXPR_STARSTAR \"**\"\n#define _Z_KEYEXPR_STARSTAR_LEN (sizeof(_Z_KEYEXPR_STARSTAR) - 1)\n#define _Z_KEYEXPR_SESSION \"session\"\n#define _Z_KEYEXPR_SESSION_LEN (sizeof(_Z_KEYEXPR_SESSION) - 1)\n#define _Z_KEYEXPR_PICO \"pico\"\n#define _Z_KEYEXPR_PICO_LEN (sizeof(_Z_KEYEXPR_PICO) - 1)\n#define _Z_KEYEXPR_TRANSPORTS \"transports\"\n#define _Z_KEYEXPR_TRANSPORTS_LEN (sizeof(_Z_KEYEXPR_TRANSPORTS) - 1)\n#define _Z_KEYEXPR_TRANSPORT_UNICAST \"transport/unicast\"\n#define _Z_KEYEXPR_TRANSPORT_UNICAST_LEN (sizeof(_Z_KEYEXPR_TRANSPORT_UNICAST) - 1)\n#define _Z_KEYEXPR_TRANSPORT_MULTICAST \"transport/multicast\"\n#define _Z_KEYEXPR_TRANSPORT_MULTICAST_LEN (sizeof(_Z_KEYEXPR_TRANSPORT_MULTICAST) - 1)\n#define _Z_KEYEXPR_TRANSPORT_RAWETH \"transport/raweth\"\n#define _Z_KEYEXPR_TRANSPORT_RAWETH_LEN (sizeof(_Z_KEYEXPR_TRANSPORT_RAWETH) - 1)\n#define _Z_KEYEXPR_LINK \"link\"\n#define _Z_KEYEXPR_LINK_LEN (sizeof(_Z_KEYEXPR_LINK) - 1)\n#define _Z_KEYEXPR_PEERS \"peers\"\n#define _Z_KEYEXPR_PEERS_LEN (sizeof(_Z_KEYEXPR_PEERS) - 1)\n#define _Z_KEYEXPR_SEPARATOR \"/\"\n#define _Z_KEYEXPR_SEPARATOR_LEN (sizeof(_Z_KEYEXPR_SEPARATOR) - 1)\n\n/**\n * Sample kind values.\n *\n * Enumerators:\n *   Z_SAMPLE_KIND_PUT: The Sample was issued by a ``put`` operation.\n *   Z_SAMPLE_KIND_DELETE: The Sample was issued by a ``delete`` operation.\n */\ntypedef enum {\n    Z_SAMPLE_KIND_PUT = 0,\n    Z_SAMPLE_KIND_DELETE = 1,\n    Z_SAMPLE_KIND_DEFAULT = Z_SAMPLE_KIND_PUT\n} z_sample_kind_t;\n\n/**\n * Consolidation mode values.\n *\n * Enumerators:\n *   Z_CONSOLIDATION_MODE_AUTO: Let Zenoh decide the best consolidation mode depending on the query selector.\n *   Z_CONSOLIDATION_MODE_NONE: No consolidation is applied. Replies may come in any order and any number.\n *   Z_CONSOLIDATION_MODE_MONOTONIC: It guarantees that any reply for a given key expression will be monotonic in time\n *     w.r.t. the previous received replies for the same key expression. I.e., for the same key expression multiple\n *     replies may be received. It is guaranteed that two replies received at t1 and t2 will have timestamp\n *     ts2 > ts1. It optimizes latency.\n *   Z_CONSOLIDATION_MODE_LATEST: It guarantees unicity of replies for the same key expression.\n *     It optimizes bandwidth.\n */\ntypedef enum {\n    Z_CONSOLIDATION_MODE_AUTO = -1,\n    Z_CONSOLIDATION_MODE_NONE = 0,\n    Z_CONSOLIDATION_MODE_MONOTONIC = 1,\n    Z_CONSOLIDATION_MODE_LATEST = 2,\n    Z_CONSOLIDATION_MODE_DEFAULT = Z_CONSOLIDATION_MODE_AUTO\n} z_consolidation_mode_t;\n\n/**\n * Reliability values.\n *\n * Enumerators:\n *   Z_RELIABILITY_BEST_EFFORT: Defines reliability as ``BEST_EFFORT``\n *   Z_RELIABILITY_RELIABLE: Defines reliability as ``RELIABLE``\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef enum {\n    Z_RELIABILITY_BEST_EFFORT = 1,\n    Z_RELIABILITY_RELIABLE = 0,\n    Z_RELIABILITY_DEFAULT = Z_RELIABILITY_RELIABLE\n} z_reliability_t;\n\n/**\n * Congestion control values.\n *\n * Enumerators:\n *   Z_CONGESTION_CONTROL_BLOCK: Defines congestion control as ``BLOCK``. Messages are not dropped in case of\n *     congestion control.\n *   Z_CONGESTION_CONTROL_DROP: Defines congestion control as ``DROP``. Messages are dropped in case\n *     of congestion control.\n */\ntypedef enum {\n    Z_CONGESTION_CONTROL_BLOCK = 1,\n    Z_CONGESTION_CONTROL_DROP = 0,\n    Z_CONGESTION_CONTROL_DEFAULT = Z_CONGESTION_CONTROL_DROP\n} z_congestion_control_t;\n\nstatic inline z_congestion_control_t z_internal_congestion_control_default_push(void) {\n    return Z_CONGESTION_CONTROL_DROP;\n}\nstatic inline z_congestion_control_t z_internal_congestion_control_default_request(void) {\n    return Z_CONGESTION_CONTROL_BLOCK;\n}\n\n/**\n * Priority of Zenoh messages values.\n *\n * Enumerators:\n *   _Z_PRIORITY_CONTROL: Priority for ``Control`` messages.\n *   Z_PRIORITY_REAL_TIME: Priority for ``RealTime`` messages.\n *   Z_PRIORITY_INTERACTIVE_HIGH: Highest priority for ``Interactive`` messages.\n *   Z_PRIORITY_INTERACTIVE_LOW: Lowest priority for ``Interactive`` messages.\n *   Z_PRIORITY_DATA_HIGH: Highest priority for ``Data`` messages.\n *   Z_PRIORITY_DATA: Default priority for ``Data`` messages.\n *   Z_PRIORITY_DATA_LOW: Lowest priority for ``Data`` messages.\n *   Z_PRIORITY_BACKGROUND: Priority for ``Background traffic`` messages.\n */\ntypedef enum {\n    _Z_PRIORITY_CONTROL = 0,\n    Z_PRIORITY_REAL_TIME = 1,\n    Z_PRIORITY_INTERACTIVE_HIGH = 2,\n    Z_PRIORITY_INTERACTIVE_LOW = 3,\n    Z_PRIORITY_DATA_HIGH = 4,\n    Z_PRIORITY_DATA = 5,\n    Z_PRIORITY_DATA_LOW = 6,\n    Z_PRIORITY_BACKGROUND = 7,\n    Z_PRIORITY_DEFAULT = Z_PRIORITY_DATA\n} z_priority_t;\n\n/**\n * Query target values.\n *\n * Enumerators:\n *   Z_QUERY_TARGET_BEST_MATCHING: The nearest complete queryable if any else all matching queryables.\n *   Z_QUERY_TARGET_ALL: All matching queryables.\n *   Z_QUERY_TARGET_ALL_COMPLETE: A set of complete queryables.\n */\ntypedef enum {\n    Z_QUERY_TARGET_BEST_MATCHING = 0,\n    Z_QUERY_TARGET_ALL = 1,\n    Z_QUERY_TARGET_ALL_COMPLETE = 2,\n    Z_QUERY_TARGET_DEFAULT = Z_QUERY_TARGET_BEST_MATCHING\n} z_query_target_t;\n\n/**\n * The kinds of accepted query replies.\n *\n * The queryable may serve glob-like key expressions.\n * E.g., the queryable may be declared with the key expression `foo/b$*`.\n * At the same time, it may send replies with more specific key expressions, e.g., `foo/bar` or `foo/baz`.\n * This may cause a situation when the queryable receives a query with the key expression `foo/bar`\n * and replies to it with the key expression `foo/baz`.\n * By default, this behavior is not allowed. Calling `z_query_reply` value on a query for `foo/bar` with key expression\n * `foo/baz` will result in an error on the sending side. But if the query is sent with the `accept_replies` flag set to\n * `Z_REPLY_KEYEXPR_ANY` in either `z_get_options_t` or `z_querier_options_t`, then the reply with a disjoint key\n * expression will be accepted for this query.\n *\n * The queryable may check whether disjoint replies are allowed for a query with `z_query_accepts_replies` function.\n *\n * Enumerators:\n *   Z_REPLY_KEYEXPR_ANY: Accept replies on any key expression.\n *   Z_REPLY_KEYEXPR_MATCHING_QUERY: Accept replies only to intersecting key expressions intersecting with query's own\n * key expression.\n */\ntypedef enum z_reply_keyexpr_t {\n    Z_REPLY_KEYEXPR_ANY = 0,\n    Z_REPLY_KEYEXPR_MATCHING_QUERY = 1,\n    Z_REPLY_KEYEXPR_DEFAULT = Z_REPLY_KEYEXPR_MATCHING_QUERY\n} z_reply_keyexpr_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_API_CONSTANTS_H */\n"
  },
  {
    "path": "include/zenoh-pico/api/encoding.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_API_ENCODING_H\n#define ZENOH_PICO_API_ENCODING_H\n\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/**\n * Default encoding values used by Zenoh.\n *\n * An encoding has a similar role to Content-type in HTTP: it indicates, when present, how data should be interpreted by\n * the application.\n *\n * Please note the Zenoh protocol does not impose any encoding value nor it operates on it.\n * It can be seen as some optional metadata that is carried over by Zenoh in such a way the application may perform\n * different operations depending on the encoding value.\n *\n * A set of associated constants are provided to cover the most common encodings for user convenience.\n * This is particularly useful in helping Zenoh to perform additional wire-level optimizations.\n *\n * Register your encoding metadata from a string with :c:func:`z_encoding_from_str`. To get the optimization, you need\n * Z_FEATURE_ENCODING_VALUES to 1 and your string should follow the format: \"<constant>;<optional additional data>\"\n *\n * E.g: \"text/plain;utf8\"\n *\n * Or you can set the value to the constants directly with this list of constants:\n */\n\n#if Z_FEATURE_ENCODING_VALUES == 1\n// - Below are Primitives types, supported in all Zenoh bindings\n/**\n * Just some bytes.\n *\n * Constant alias for string: `\"zenoh/bytes\"`.\n *\n * This encoding supposes that the payload was created with c:func:`z_bytes_from_buf`, c:func:`z_bytes_from_slice` or\n * similar functions and its data can be accessed via c:func:`z_bytes_to_slice`.\n */\nconst z_loaned_encoding_t *z_encoding_zenoh_bytes(void);\nextern const z_owned_encoding_t ZP_ENCODING_ZENOH_BYTES;\n\n/**\n * A UTF-8 string.\n * Constant alias for string: `\"zenoh/string\"`.\n *\n * This encoding supposes that the payload was created with c:func:`z_bytes_from_str`, c:func:`z_bytes_from_string` or\n * similar functions and its data can be accessed via c:func:`z_bytes_to_string`.\n */\nconst z_loaned_encoding_t *z_encoding_zenoh_string(void);\nextern const z_owned_encoding_t ZP_ENCODING_ZENOH_STRING;\n\n/**\n * Zenoh serialized data.\n * Constant alias for string: `\"zenoh/serialized\"`.\n *\n * This encoding supposes that the payload was created with serialization functions.\n * The `schema` field may contain the details of serialziation format.\n */\nconst z_loaned_encoding_t *z_encoding_zenoh_serialized(void);\nextern const z_owned_encoding_t ZP_ENCODING_ZENOH_SERIALIZED;\n\n/**\n * An application-specific stream of bytes.\n * Constant alias for string: `\"application/octet-stream\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_octet_stream(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_OCTET_STREAM;\n\n/**\n * A textual file.\n * Constant alias for string: `\"text/plain\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_plain(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_PLAIN;\n\n/**\n * JSON data intended to be consumed by an application.\n * Constant alias for string: `\"application/json\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_json(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_JSON;\n\n/**\n * JSON data intended to be human readable.\n * Constant alias for string: `\"text/json\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_json(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_JSON;\n\n/**\n * A Common Data Representation (CDR)-encoded data.\n * Constant alias for string: `\"application/cdr\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_cdr(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_CDR;\n\n/**\n * A Concise Binary Object Representation (CBOR)-encoded data.\n * Constant alias for string: `\"application/cbor\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_cbor(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_CBOR;\n\n/**\n * YAML data intended to be consumed by an application.\n * Constant alias for string: `\"application/yaml\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_yaml(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_YAML;\n\n/**\n * YAML data intended to be human readable.\n * Constant alias for string: `\"text/yaml\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_yaml(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_YAML;\n\n/**\n * JSON5 encoded data that are human readable.\n * Constant alias for string: `\"text/json5\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_json5(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_JSON5;\n\n/**\n * A Python object serialized using `pickle <https://docs.python.org/3/library/pickle.html>`_.\n * Constant alias for string: `\"application/python-serialized-object\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_python_serialized_object(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_PYTHON_SERIALIZED_OBJECT;\n\n/**\n * An application-specific protobuf-encoded data.\n * Constant alias for string: `\"application/protobuf\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_protobuf(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_PROTOBUF;\n\n/**\n * A Java serialized object.\n * Constant alias for string: `\"application/java-serialized-object\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_java_serialized_object(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_JAVA_SERIALIZED_OBJECT;\n\n/**\n * An `openmetrics <https://github.com/OpenObservability/OpenMetrics>`_ data, commonly used by\n * `Prometheus <https://prometheus.io/>`_.\n * Constant alias for string: `\"application/openmetrics-text\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_openmetrics_text(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_OPENMETRICS_TEXT;\n\n/**\n * A Portable Network Graphics (PNG) image.\n * Constant alias for string: `\"image/png\"`.\n */\nconst z_loaned_encoding_t *z_encoding_image_png(void);\nextern const z_owned_encoding_t ZP_ENCODING_IMAGE_PNG;\n\n/**\n * A Joint Photographic Experts Group (JPEG) image.\n * Constant alias for string: `\"image/jpeg\"`.\n */\nconst z_loaned_encoding_t *z_encoding_image_jpeg(void);\nextern const z_owned_encoding_t ZP_ENCODING_IMAGE_JPEG;\n\n/**\n * A Graphics Interchange Format (GIF) image.\n * Constant alias for string: `\"image/gif\"`.\n */\nconst z_loaned_encoding_t *z_encoding_image_gif(void);\nextern const z_owned_encoding_t ZP_ENCODING_IMAGE_GIF;\n\n/**\n * A BitMap (BMP) image.\n * Constant alias for string: `\"image/bmp\"`.\n */\nconst z_loaned_encoding_t *z_encoding_image_bmp(void);\nextern const z_owned_encoding_t ZP_ENCODING_IMAGE_BMP;\n\n/**\n * A Web Portable (WebP) image.\n * Constant alias for string: `\"image/webp\"`.\n */\nconst z_loaned_encoding_t *z_encoding_image_webp(void);\nextern const z_owned_encoding_t ZP_ENCODING_IMAGE_WEBP;\n\n/**\n * An XML file intended to be consumed by an application.\n * Constant alias for string: `\"application/xml\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_xml(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_XML;\n\n/**\n * An encoded list of tuples, each consisting of a name and a value.\n * Constant alias for string: `\"application/x-www-form-urlencoded\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_x_www_form_urlencoded(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_X_WWW_FORM_URLENCODED;\n\n/**\n * An HTML file.\n * Constant alias for string: `\"text/html\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_html(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_HTML;\n\n/**\n * An XML file that is human-readable.\n * Constant alias for string: `\"text/xml\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_xml(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_XML;\n\n/**\n * A CSS file.\n * Constant alias for string: `\"text/css\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_css(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_CSS;\n\n/**\n * A JavaScript file.\n * Constant alias for string: `\"text/javascript\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_javascript(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_JAVASCRIPT;\n\n/**\n * A Markdown file.\n * Constant alias for string: `\"text/markdown\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_markdown(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_MARKDOWN;\n\n/**\n * A CSV file.\n * Constant alias for string: `\"text/csv\"`.\n */\nconst z_loaned_encoding_t *z_encoding_text_csv(void);\nextern const z_owned_encoding_t ZP_ENCODING_TEXT_CSV;\n\n/**\n * An application-specific SQL query.\n * Constant alias for string: `\"application/sql\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_sql(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_SQL;\n\n/**\n * Constrained Application Protocol (CoAP) data intended for CoAP-to-HTTP and HTTP-to-CoAP proxies.\n * Constant alias for string: `\"application/coap-payload\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_coap_payload(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_COAP_PAYLOAD;\n\n/**\n * Defines a JSON document structure for expressing a sequence of operations to apply to a JSON document.\n * Constant alias for string: `\"application/json-patch+json\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_json_patch_json(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_JSON_PATCH_JSON;\n\n/**\n * A JSON text sequence consists of any number of JSON texts, all encoded in UTF-8.\n * Constant alias for string: `\"application/json-seq\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_json_seq(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_JSON_SEQ;\n\n/**\n * A JSONPath defines a string syntax for selecting and extracting JSON values from within a given JSON value.\n * Constant alias for string: `\"application/jsonpath\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_jsonpath(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_JSONPATH;\n\n/**\n * A JSON Web Token (JWT).\n * Constant alias for string: `\"application/jwt\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_jwt(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_JWT;\n\n/**\n * An application-specific MPEG-4 encoded data, either audio or video.\n * Constant alias for string: `\"application/mp4\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_mp4(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_MP4;\n\n/**\n * A SOAP 1.2 message serialized as XML 1.0.\n * Constant alias for string: `\"application/soap+xml\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_soap_xml(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_SOAP_XML;\n\n/**\n * A YANG-encoded data commonly used by the Network Configuration Protocol (NETCONF).\n * Constant alias for string: `\"application/yang\"`.\n */\nconst z_loaned_encoding_t *z_encoding_application_yang(void);\nextern const z_owned_encoding_t ZP_ENCODING_APPLICATION_YANG;\n\n/**\n * A MPEG-4 Advanced Audio Coding (AAC) media.\n * Constant alias for string: `\"audio/aac\"`.\n */\nconst z_loaned_encoding_t *z_encoding_audio_aac(void);\nextern const z_owned_encoding_t ZP_ENCODING_AUDIO_AAC;\n\n/**\n * A Free Lossless Audio Codec (FLAC) media.\n * Constant alias for string: `\"audio/flac\"`.\n */\nconst z_loaned_encoding_t *z_encoding_audio_flac(void);\nextern const z_owned_encoding_t ZP_ENCODING_AUDIO_FLAC;\n\n/**\n * An audio codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority.\n * Constant alias for string: `\"audio/mp4\"`.\n */\nconst z_loaned_encoding_t *z_encoding_audio_mp4(void);\nextern const z_owned_encoding_t ZP_ENCODING_AUDIO_MP4;\n\n/**\n * An Ogg-encapsulated audio stream.\n * Constant alias for string: `\"audio/ogg\"`.\n */\nconst z_loaned_encoding_t *z_encoding_audio_ogg(void);\nextern const z_owned_encoding_t ZP_ENCODING_AUDIO_OGG;\n\n/**\n * A Vorbis-encoded audio stream.\n * Constant alias for string: `\"audio/vorbis\"`.\n */\nconst z_loaned_encoding_t *z_encoding_audio_vorbis(void);\nextern const z_owned_encoding_t ZP_ENCODING_AUDIO_VORBIS;\n\n/**\n * A h261-encoded video stream.\n * Constant alias for string: `\"video/h261\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_h261(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_H261;\n\n/**\n * A h263-encoded video stream.\n * Constant alias for string: `\"video/h263\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_h263(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_H263;\n\n/**\n * A h264-encoded video stream.\n * Constant alias for string: `\"video/h264\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_h264(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_H264;\n\n/**\n * A h265-encoded video stream.\n * Constant alias for string: `\"video/h265\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_h265(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_H265;\n\n/**\n * A h266-encoded video stream.\n * Constant alias for string: `\"video/h266\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_h266(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_H266;\n\n/**\n * A video codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority.\n * Constant alias for string: `\"video/mp4\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_mp4(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_MP4;\n\n/**\n * An Ogg-encapsulated video stream.\n * Constant alias for string: `\"video/ogg\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_ogg(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_OGG;\n\n/**\n * An uncompressed, studio-quality video stream.\n * Constant alias for string: `\"video/raw\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_raw(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_RAW;\n\n/**\n * A VP8-encoded video stream.\n * Constant alias for string: `\"video/vp8\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_vp8(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_VP8;\n\n/**\n * A VP9-encoded video stream.\n * Constant alias for string: `\"video/vp9\"`.\n */\nconst z_loaned_encoding_t *z_encoding_video_vp9(void);\nextern const z_owned_encoding_t ZP_ENCODING_VIDEO_VP9;\n\n/**\n * Returns a loaned default `z_loaned_encoding_t`.\n */\nconst z_loaned_encoding_t *z_encoding_loan_default(void);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_API_ENCODING_H */\n"
  },
  {
    "path": "include/zenoh-pico/api/handlers.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef INCLUDE_ZENOH_PICO_API_HANDLERS_H\n#define INCLUDE_ZENOH_PICO_API_HANDLERS_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/fifo_mt.h\"\n#include \"zenoh-pico/collections/ring_mt.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n// -- Channel\n#define _Z_CHANNEL_DEFINE_IMPL(handler_type, handler_name, handler_new_f_name, callback_type, callback_new_f,        \\\n                               collection_type, collection_new_f, collection_clear_f, collection_push_f,             \\\n                               collection_pull_f, collection_try_pull_f, collection_close_f, elem_owned_type,        \\\n                               elem_loaned_type, elem_take_f, elem_move_f, elem_drop_f, elem_null_f)                 \\\n    typedef struct {                                                                                                 \\\n        collection_type collection;                                                                                  \\\n    } handler_type;                                                                                                  \\\n                                                                                                                     \\\n    static inline void _z_##handler_name##_elem_free(void **elem) {                                                  \\\n        elem_drop_f(elem_move_f((elem_owned_type *)*elem));                                                          \\\n        z_free(*elem);                                                                                               \\\n        *elem = NULL;                                                                                                \\\n    }                                                                                                                \\\n    static inline void _z_##handler_name##_elem_move(void *dst, void *src) {                                         \\\n        memcpy(dst, src, sizeof(elem_owned_type));                                                                   \\\n        z_free(src);                                                                                                 \\\n    }                                                                                                                \\\n                                                                                                                     \\\n    static inline void _z_##handler_name##_clear(handler_type *handler) {                                            \\\n        if (handler != NULL) {                                                                                       \\\n            collection_clear_f(&handler->collection, _z_##handler_name##_elem_free);                                 \\\n        }                                                                                                            \\\n    }                                                                                                                \\\n    _Z_REFCOUNT_DEFINE(_z_##handler_name, _z_##handler_name)                                                         \\\n    _Z_OWNED_TYPE_RC(_z_##handler_name##_rc_t, handler_name)                                                         \\\n    _Z_OWNED_FUNCTIONS_RC_INLINE_IMPL(handler_name)                                                                  \\\n    static inline void _z_##handler_name##_close(void *context) {                                                    \\\n        _z_##handler_name##_rc_t *handler = (_z_##handler_name##_rc_t *)context;                                     \\\n        if (_z_rc_strong_count(handler->_cnt) > 1) {                                                                 \\\n            z_result_t ret = collection_close_f(&_Z_RC_IN_VAL(handler)->collection);                                 \\\n            if (ret < 0) {                                                                                           \\\n                _Z_ERROR(\"%s failed: %i\", #collection_push_f, ret);                                                  \\\n            }                                                                                                        \\\n        }                                                                                                            \\\n        _z_##handler_name##_rc_drop(handler);                                                                        \\\n        z_free(handler);                                                                                             \\\n    }                                                                                                                \\\n    static inline void _z_##handler_name##_send(elem_loaned_type *elem, void *context) {                             \\\n        _z_##handler_name##_rc_t *handler = (_z_##handler_name##_rc_t *)context;                                     \\\n        if (_z_rc_strong_count(handler->_cnt) > 1) {                                                                 \\\n            elem_owned_type *internal_elem = (elem_owned_type *)z_malloc(sizeof(elem_owned_type));                   \\\n            if (internal_elem == NULL) {                                                                             \\\n                _Z_ERROR(\"Out of memory\");                                                                           \\\n                return;                                                                                              \\\n            }                                                                                                        \\\n            elem_take_f(internal_elem, elem);                                                                        \\\n            z_result_t ret =                                                                                         \\\n                collection_push_f(internal_elem, &_Z_RC_IN_VAL(handler)->collection, _z_##handler_name##_elem_free); \\\n            if (ret != _Z_RES_OK) {                                                                                  \\\n                _Z_ERROR(\"%s failed: %i\", #collection_push_f, ret);                                                  \\\n            }                                                                                                        \\\n        }                                                                                                            \\\n    }                                                                                                                \\\n                                                                                                                     \\\n    static inline z_result_t handler_new_f_name(callback_type *callback, z_owned_##handler_name##_t *handler,        \\\n                                                size_t capacity) {                                                   \\\n        if (capacity < 1) {                                                                                          \\\n            _Z_ERROR_RETURN(_Z_ERR_INVALID);                                                                         \\\n        }                                                                                                            \\\n        _z_##handler_name##_t h;                                                                                     \\\n        _Z_RETURN_IF_ERR(collection_new_f(&h.collection, capacity));                                                 \\\n        handler->_rc = _z_##handler_name##_rc_new_from_val(&h);                                                      \\\n        if (_Z_RC_IS_NULL(&handler->_rc)) {                                                                          \\\n            _z_##handler_name##_clear(&h);                                                                           \\\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);                                                            \\\n        }                                                                                                            \\\n        _z_##handler_name##_rc_t *h_copy = _z_##handler_name##_rc_clone_as_ptr(&handler->_rc);                       \\\n        if (h_copy == NULL) {                                                                                        \\\n            _z_##handler_name##_rc_drop(&handler->_rc);                                                              \\\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);                                                            \\\n        }                                                                                                            \\\n        callback_new_f(callback, _z_##handler_name##_send, _z_##handler_name##_close, h_copy);                       \\\n        return _Z_RES_OK;                                                                                            \\\n    }                                                                                                                \\\n    static inline z_result_t z_##handler_name##_recv(const z_loaned_##handler_name##_t *handler,                     \\\n                                                     elem_owned_type *elem) {                                        \\\n        elem_null_f(elem);                                                                                           \\\n        z_result_t ret = collection_pull_f(elem, (collection_type *)(&_Z_RC_IN_VAL(handler)->collection),            \\\n                                           _z_##handler_name##_elem_move);                                           \\\n        if (ret == _Z_RES_CHANNEL_CLOSED) {                                                                          \\\n            return Z_CHANNEL_DISCONNECTED;                                                                           \\\n        }                                                                                                            \\\n        if (ret != _Z_RES_OK) {                                                                                      \\\n            _Z_ERROR(\"%s failed: %i\", #collection_pull_f, ret);                                                      \\\n            return ret;                                                                                              \\\n        }                                                                                                            \\\n        return _Z_RES_OK;                                                                                            \\\n    }                                                                                                                \\\n    static inline z_result_t z_##handler_name##_try_recv(const z_loaned_##handler_name##_t *handler,                 \\\n                                                         elem_owned_type *elem) {                                    \\\n        elem_null_f(elem);                                                                                           \\\n        z_result_t ret = collection_try_pull_f(elem, (collection_type *)(&_Z_RC_IN_VAL(handler)->collection),        \\\n                                               _z_##handler_name##_elem_move);                                       \\\n        if (ret == _Z_RES_CHANNEL_CLOSED) {                                                                          \\\n            return Z_CHANNEL_DISCONNECTED;                                                                           \\\n        } else if (ret == _Z_RES_CHANNEL_NODATA) {                                                                   \\\n            return Z_CHANNEL_NODATA;                                                                                 \\\n        }                                                                                                            \\\n        if (ret != _Z_RES_OK) {                                                                                      \\\n            _Z_ERROR(\"%s failed: %i\", #collection_try_pull_f, ret);                                                  \\\n            return ret;                                                                                              \\\n        }                                                                                                            \\\n        return _Z_RES_OK;                                                                                            \\\n    }\n\n#define _Z_CHANNEL_DEFINE(item_name, kind_name)                                                             \\\n    _Z_CHANNEL_DEFINE_IMPL(/* handler_type                    */ _z_##kind_name##_handler_##item_name##_t,  \\\n                           /* handler_name                    */ kind_name##_handler_##item_name,           \\\n                           /* handler_new_f_name              */ z_##kind_name##_channel_##item_name##_new, \\\n                           /* callback_type                   */ z_owned_closure_##item_name##_t,           \\\n                           /* callback_new_f                  */ z_closure_##item_name,                     \\\n                           /* collection_type                 */ _z_##kind_name##_mt_t,                     \\\n                           /* collection_new_f                */ _z_##kind_name##_mt_init,                  \\\n                           /* collection_clear_f               */ _z_##kind_name##_mt_clear,                \\\n                           /* collection_push_f               */ _z_##kind_name##_mt_push,                  \\\n                           /* collection_pull_f               */ _z_##kind_name##_mt_pull,                  \\\n                           /* collection_try_pull_f           */ _z_##kind_name##_mt_try_pull,              \\\n                           /* collection_close_f              */ _z_##kind_name##_mt_close,                 \\\n                           /* elem_owned_type                 */ z_owned_##item_name##_t,                   \\\n                           /* elem_loaned_type                */ z_loaned_##item_name##_t,                  \\\n                           /* elem_take_f                     */ z_##item_name##_take_from_loaned,          \\\n                           /* elem_move_f                     */ z_##item_name##_move,                      \\\n                           /* elem_drop_f                     */ z_##item_name##_drop,                      \\\n                           /* elem_null_f                     */ z_internal_##item_name##_null)\n\n#define _Z_CHANNEL_DUMMY_IMPL(handler_type, handler_name, item_name)                                            \\\n    _Z_OWNED_TYPE_VALUE(handler_type, handler_name)                                                             \\\n    static inline void _z_##handler_name##_clear(handler_type *handler) { _ZP_UNUSED(handler); }                \\\n    static inline bool _z_##handler_name##_check(const handler_type *handler) {                                 \\\n        _ZP_UNUSED(handler);                                                                                    \\\n        return false;                                                                                           \\\n    }                                                                                                           \\\n    static inline handler_type _z_##handler_name##_null(void) {                                                 \\\n        handler_type h = {0};                                                                                   \\\n        return h;                                                                                               \\\n    }                                                                                                           \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_INLINE_IMPL(handler_type, handler_name, _z_##handler_name##_check, \\\n                                                         _z_##handler_name##_null, _z_##handler_name##_clear)   \\\n    static inline z_result_t z_##handler_name##_try_recv(const z_loaned_##handler_name##_t *handler,            \\\n                                                         z_owned_##item_name##_t *e) {                          \\\n        _ZP_UNUSED(handler);                                                                                    \\\n        _ZP_UNUSED(e);                                                                                          \\\n        return Z_CHANNEL_DISCONNECTED;                                                                          \\\n    }                                                                                                           \\\n    static inline z_result_t z_##handler_name##_recv(const z_loaned_##handler_name##_t *handler,                \\\n                                                     z_owned_##item_name##_t *e) {                              \\\n        _ZP_UNUSED(handler);                                                                                    \\\n        _ZP_UNUSED(e);                                                                                          \\\n        return Z_CHANNEL_DISCONNECTED;                                                                          \\\n    }\n\n#define _Z_CHANNEL_DEFINE_DUMMY(item_name, kind_name) \\\n    typedef struct {                                  \\\n        uint8_t _foo;                                 \\\n    } _z_##kind_name##_handler_##item_name##_t;       \\\n    _Z_CHANNEL_DUMMY_IMPL(_z_##kind_name##_handler_##item_name##_t, kind_name##_handler_##item_name, item_name)\n\n// This macro defines:\n//   z_ring_channel_sample_new()\n//   z_owned_ring_handler_sample_t/z_loaned_ring_handler_sample_t\n_Z_CHANNEL_DEFINE(sample, ring)\n\n// This macro defines:\n//   z_fifo_channel_sample_new()\n//   z_owned_fifo_handler_sample_t/z_loaned_fifo_handler_sample_t\n_Z_CHANNEL_DEFINE(sample, fifo)\n\n#if Z_FEATURE_QUERYABLE == 1\n// This macro defines:\n//   z_ring_channel_query_new()\n//   z_owned_ring_handler_query_t/z_loaned_ring_handler_query_t\n_Z_CHANNEL_DEFINE(query, ring)\n\n// This macro defines:\n//   z_fifo_channel_query_new()\n//   z_owned_fifo_handler_query_t/z_loaned_fifo_handler_query_t\n_Z_CHANNEL_DEFINE(query, fifo)\n#else   // Z_FEATURE_QUERYABLE\n_Z_CHANNEL_DEFINE_DUMMY(query, ring)\n_Z_CHANNEL_DEFINE_DUMMY(query, fifo)\n#endif  // Z_FEATURE_QUERYABLE\n\n#if Z_FEATURE_QUERY == 1\n// This macro defines:\n//   z_ring_channel_reply_new()\n//   z_owned_ring_handler_reply_t/z_loaned_ring_handler_reply_t\n_Z_CHANNEL_DEFINE(reply, ring)\n\n// This macro defines:\n//   z_fifo_channel_reply_new()\n//   z_owned_fifo_handler_reply_t/z_loaned_fifo_handler_reply_t\n_Z_CHANNEL_DEFINE(reply, fifo)\n#else   // Z_FEATURE_QUERY\n_Z_CHANNEL_DEFINE_DUMMY(reply, ring)\n_Z_CHANNEL_DEFINE_DUMMY(reply, fifo)\n#endif  // Z_FEATURE_QUERY\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // INCLUDE_ZENOH_PICO_API_HANDLERS_H\n"
  },
  {
    "path": "include/zenoh-pico/api/liveliness.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef INCLUDE_ZENOH_PICO_API_LIVELINESS_H\n#define INCLUDE_ZENOH_PICO_API_LIVELINESS_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"olv_macros.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    uint32_t _id;\n    _z_session_weak_t _zn;\n} _z_liveliness_token_t;\n\n_z_liveliness_token_t _z_liveliness_token_null(void);\n_Z_OWNED_TYPE_VALUE(_z_liveliness_token_t, liveliness_token)\n_Z_OWNED_FUNCTIONS_DEF(liveliness_token)\n\n#if Z_FEATURE_LIVELINESS == 1\n\n/**************** Liveliness Token ****************/\n\n/**\n * The options for :c:func:`z_liveliness_declare_token()`.\n */\ntypedef struct z_liveliness_token_options_t {\n    uint8_t __dummy;\n} z_liveliness_token_options_t;\n\n/**\n * Constructs default value for :c:type:`z_liveliness_token_options_t`.\n */\nz_result_t z_liveliness_token_options_default(z_liveliness_token_options_t *options);\n\n/**\n * Constructs and declares a liveliness token on the network.\n *\n * Liveliness token subscribers on an intersecting key expression will receive a PUT sample when connectivity\n * is achieved, and a DELETE sample if it's lost.\n *\n * Parameters:\n *   zs: A Zenos session to declare the liveliness token.\n *   token: An uninitialized memory location where liveliness token will be constructed.\n *   keyexpr: A keyexpr to declare a liveliess token for.\n *   options: Liveliness token declaration options.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_liveliness_declare_token(const z_loaned_session_t *zs, z_owned_liveliness_token_t *token,\n                                      const z_loaned_keyexpr_t *keyexpr, const z_liveliness_token_options_t *options);\n\n/**\n * Undeclare a liveliness token, notifying subscribers of its destruction.\n *\n * Parameters:\n *   token: Moved :c:type:`z_owned_liveliness_token_t` to undeclare.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_liveliness_undeclare_token(z_moved_liveliness_token_t *token);\n\n/**************** Liveliness Subscriber ****************/\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n/**\n * The options for :c:func:`z_liveliness_declare_subscriber()`\n */\ntypedef struct z_liveliness_subscriber_options_t {\n    bool history;\n} z_liveliness_subscriber_options_t;\n\n/**\n * Constucts default value for :c:type:`z_liveliness_subscriber_options_t`.\n */\nz_result_t z_liveliness_subscriber_options_default(z_liveliness_subscriber_options_t *options);\n\n/**\n * Declares a subscriber on liveliness tokens that intersect `keyexpr`.\n *\n * Parameters:\n *   zs: The Zenoh session.\n *   sub: An uninitialized memory location where subscriber will be constructed.\n *   keyexpr: The key expression to subscribe to.\n *   callback: The callback function that will be called each time a liveliness token status is changed.\n *   options: The options to be passed to the liveliness subscriber declaration.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_liveliness_declare_subscriber(const z_loaned_session_t *zs, z_owned_subscriber_t *sub,\n                                           const z_loaned_keyexpr_t *keyexpr, z_moved_closure_sample_t *callback,\n                                           z_liveliness_subscriber_options_t *options);\n/**\n * Declares a background subscriber on liveliness tokens that intersect `keyexpr`.\n * Subscriber callback will be called to process the messages, until the corresponding session is closed or dropped.\n *\n * Parameters:\n *   zs: The Zenoh session.\n *   keyexpr: The key expression to subscribe to.\n *   callback: The callback function that will be called each time a liveliness token status is changed.\n *   options: The options to be passed to the liveliness subscriber declaration.\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n */\nz_result_t z_liveliness_declare_background_subscriber(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                                      z_moved_closure_sample_t *callback,\n                                                      z_liveliness_subscriber_options_t *options);\n\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n/**************** Liveliness Query ****************/\n\n#if Z_FEATURE_QUERY == 1\n/**\n * The options for :c:func:`z_liveliness_get()`\n *\n * Members:\n *   uint64_t timeout_ms: Liveliness query timeout in milliseconds. 0 corresponds to default get request timeout.\n *   z_moved_cancellation_token_t *cancellation_token: Token to allow cancelling get operation (unstable).\n */\ntypedef struct z_liveliness_get_options_t {\n    uint64_t timeout_ms;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_moved_cancellation_token_t *cancellation_token;\n#endif\n} z_liveliness_get_options_t;\n\n/**\n * Constructs default value :c:type:`z_liveliness_get_options_t`.\n */\nz_result_t z_liveliness_get_options_default(z_liveliness_get_options_t *options);\n\n/**\n * Queries liveliness tokens currently on the network with a key expression intersecting with `keyexpr`.\n *\n * Parameters:\n *   zs: The Zenoh session.\n *   keyexpr: The key expression to query liveliness tokens for.\n *   callback: The callback function that will be called for each received reply.\n *   options: Additional options for the liveliness get operation.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_liveliness_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                            z_moved_closure_reply_t *callback, z_liveliness_get_options_t *options);\n\n#endif  // Z_FEATURE_QUERY == 1\n\n#endif  // Z_FEATURE_LIVELINESS == 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // INCLUDE_ZENOH_PICO_API_LIVELINESS_H\n"
  },
  {
    "path": "include/zenoh-pico/api/macros.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_API_MACROS_H\n#define ZENOH_PICO_API_MACROS_H\n\n#include \"zenoh-pico/api/advanced_publisher.h\"\n#include \"zenoh-pico/api/advanced_subscriber.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/serialization.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#if ZENOH_C_STANDARD != 99\n\n#ifndef __cplusplus\n\n// clang-format off\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_LOAN \\\n    , z_owned_transport_t : z_transport_loan                                    \\\n    , z_owned_link_t : z_link_loan                                              \\\n    , z_owned_transport_event_t : z_transport_event_loan                        \\\n    , z_owned_link_event_t : z_link_event_loan                                  \\\n    , z_owned_transport_events_listener_t : z_transport_events_listener_loan    \\\n    , z_owned_link_events_listener_t : z_link_events_listener_loan              \\\n    , z_owned_closure_transport_t : z_closure_transport_loan                    \\\n    , z_owned_closure_link_t : z_closure_link_loan                              \\\n    , z_owned_closure_transport_event_t : z_closure_transport_event_loan        \\\n    , z_owned_closure_link_event_t : z_closure_link_event_loan\n#else\n#define _Z_GENERIC_CONNECTIVITY_LOAN\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_LOAN_MUT \\\n    , z_owned_transport_t : z_transport_loan_mut                                    \\\n    , z_owned_link_t : z_link_loan_mut                                              \\\n    , z_owned_transport_event_t : z_transport_event_loan_mut                        \\\n    , z_owned_link_event_t : z_link_event_loan_mut                                  \\\n    , z_owned_transport_events_listener_t : z_transport_events_listener_loan_mut    \\\n    , z_owned_link_events_listener_t : z_link_events_listener_loan_mut\n#else\n#define _Z_GENERIC_CONNECTIVITY_LOAN_MUT\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_DROP \\\n    , z_moved_transport_t* : z_transport_drop                                    \\\n    , z_moved_link_t* : z_link_drop                                              \\\n    , z_moved_transport_event_t* : z_transport_event_drop                        \\\n    , z_moved_link_event_t* : z_link_event_drop                                  \\\n    , z_moved_transport_events_listener_t* : z_transport_events_listener_drop    \\\n    , z_moved_link_events_listener_t* : z_link_events_listener_drop              \\\n    , z_moved_closure_transport_t* : z_closure_transport_drop                    \\\n    , z_moved_closure_link_t* : z_closure_link_drop                              \\\n    , z_moved_closure_transport_event_t* : z_closure_transport_event_drop        \\\n    , z_moved_closure_link_event_t* : z_closure_link_event_drop\n#else\n#define _Z_GENERIC_CONNECTIVITY_DROP\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_CHECK \\\n    , z_owned_transport_t : z_internal_transport_check                                    \\\n    , z_owned_link_t : z_internal_link_check                                              \\\n    , z_owned_transport_event_t : z_internal_transport_event_check                        \\\n    , z_owned_link_event_t : z_internal_link_event_check                                  \\\n    , z_owned_transport_events_listener_t : z_internal_transport_events_listener_check    \\\n    , z_owned_link_events_listener_t : z_internal_link_events_listener_check              \\\n    , z_owned_closure_transport_t : z_internal_closure_transport_check                    \\\n    , z_owned_closure_link_t : z_internal_closure_link_check                              \\\n    , z_owned_closure_transport_event_t : z_internal_closure_transport_event_check        \\\n    , z_owned_closure_link_event_t : z_internal_closure_link_event_check\n#else\n#define _Z_GENERIC_CONNECTIVITY_CHECK\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_MOVE \\\n    , z_owned_transport_t : z_transport_move                                    \\\n    , z_owned_link_t : z_link_move                                              \\\n    , z_owned_transport_event_t : z_transport_event_move                        \\\n    , z_owned_link_event_t : z_link_event_move                                  \\\n    , z_owned_transport_events_listener_t : z_transport_events_listener_move    \\\n    , z_owned_link_events_listener_t : z_link_events_listener_move              \\\n    , z_owned_closure_transport_t : z_closure_transport_move                    \\\n    , z_owned_closure_link_t : z_closure_link_move                              \\\n    , z_owned_closure_transport_event_t : z_closure_transport_event_move        \\\n    , z_owned_closure_link_event_t : z_closure_link_event_move\n#else\n#define _Z_GENERIC_CONNECTIVITY_MOVE\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_TAKE \\\n    , z_owned_transport_t *: z_transport_take                                    \\\n    , z_owned_link_t *: z_link_take                                              \\\n    , z_owned_transport_event_t *: z_transport_event_take                        \\\n    , z_owned_link_event_t *: z_link_event_take                                  \\\n    , z_owned_transport_events_listener_t *: z_transport_events_listener_take    \\\n    , z_owned_link_events_listener_t *: z_link_events_listener_take              \\\n    , z_owned_closure_transport_t *: z_closure_transport_take                    \\\n    , z_owned_closure_link_t *: z_closure_link_take                              \\\n    , z_owned_closure_transport_event_t *: z_closure_transport_event_take        \\\n    , z_owned_closure_link_event_t *: z_closure_link_event_take\n#else\n#define _Z_GENERIC_CONNECTIVITY_TAKE\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_CLONE \\\n    , z_owned_transport_t* : z_transport_clone              \\\n    , z_owned_link_t* : z_link_clone                        \\\n    , z_owned_transport_event_t* : z_transport_event_clone  \\\n    , z_owned_link_event_t* : z_link_event_clone\n#else\n#define _Z_GENERIC_CONNECTIVITY_CLONE\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_TAKE_FROM_LOANED \\\n    , z_owned_transport_t* : z_transport_take_from_loaned              \\\n    , z_owned_link_t* : z_link_take_from_loaned                        \\\n    , z_owned_transport_event_t* : z_transport_event_take_from_loaned  \\\n    , z_owned_link_event_t* : z_link_event_take_from_loaned\n#else\n#define _Z_GENERIC_CONNECTIVITY_TAKE_FROM_LOANED\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_NULL \\\n    , z_owned_transport_t * : z_internal_transport_null                                    \\\n    , z_owned_link_t * : z_internal_link_null                                              \\\n    , z_owned_transport_event_t * : z_internal_transport_event_null                        \\\n    , z_owned_link_event_t * : z_internal_link_event_null                                  \\\n    , z_owned_transport_events_listener_t * : z_internal_transport_events_listener_null    \\\n    , z_owned_link_events_listener_t * : z_internal_link_events_listener_null              \\\n    , z_owned_closure_transport_t * : z_internal_closure_transport_null                    \\\n    , z_owned_closure_link_t * : z_internal_closure_link_null                              \\\n    , z_owned_closure_transport_event_t * : z_internal_closure_transport_event_null        \\\n    , z_owned_closure_link_event_t * : z_internal_closure_link_event_null\n#else\n#define _Z_GENERIC_CONNECTIVITY_NULL\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#define _Z_GENERIC_CONNECTIVITY_CALL \\\n    , z_loaned_closure_transport_t : z_closure_transport_call              \\\n    , z_loaned_closure_link_t : z_closure_link_call                        \\\n    , z_loaned_closure_transport_event_t : z_closure_transport_event_call  \\\n    , z_loaned_closure_link_event_t : z_closure_link_event_call\n#else\n#define _Z_GENERIC_CONNECTIVITY_CALL\n#endif\n\n/**\n * Defines a generic function for loaning any of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   x: The instance to loan.\n *\n * Returns:\n *   Returns the loaned type associated with `x`.\n */\n\n#define z_loan(x) _Generic((x), \\\n                  z_owned_keyexpr_t : z_keyexpr_loan,                                  \\\n                  z_view_keyexpr_t : z_view_keyexpr_loan,                              \\\n                  z_owned_config_t : z_config_loan,                                    \\\n                  z_owned_session_t : z_session_loan,                                  \\\n                  z_owned_subscriber_t : z_subscriber_loan,                            \\\n                  z_owned_publisher_t : z_publisher_loan,                              \\\n                  ze_owned_advanced_subscriber_t : ze_advanced_subscriber_loan,        \\\n                  ze_owned_advanced_publisher_t : ze_advanced_publisher_loan,          \\\n                  z_owned_querier_t : z_querier_loan,                                  \\\n                  z_owned_matching_listener_t : z_matching_listener_loan,              \\\n                  ze_owned_sample_miss_listener_t : ze_sample_miss_listener_loan,      \\\n                  z_owned_queryable_t : z_queryable_loan,                              \\\n                  z_owned_liveliness_token_t : z_liveliness_token_loan,                \\\n                  z_owned_reply_t : z_reply_loan,                                      \\\n                  z_owned_hello_t : z_hello_loan,                                      \\\n                  z_owned_string_t : z_string_loan,                                    \\\n                  z_view_string_t : z_view_string_loan,                                \\\n                  z_owned_string_array_t : z_string_array_loan,                        \\\n                  z_owned_sample_t : z_sample_loan,                                    \\\n                  z_owned_query_t : z_query_loan,                                      \\\n                  z_owned_slice_t : z_slice_loan,                                      \\\n                  z_view_slice_t : z_view_slice_loan,                                  \\\n                  z_owned_bytes_t : z_bytes_loan,                                      \\\n                  z_owned_encoding_t : z_encoding_loan,                                \\\n                  z_owned_task_t : z_task_loan,                                        \\\n                  z_owned_mutex_t : z_mutex_loan,                                      \\\n                  z_owned_condvar_t : z_condvar_loan,                                  \\\n                  z_owned_fifo_handler_query_t : z_fifo_handler_query_loan,            \\\n                  z_owned_fifo_handler_reply_t : z_fifo_handler_reply_loan,            \\\n                  z_owned_fifo_handler_sample_t : z_fifo_handler_sample_loan,          \\\n                  z_owned_ring_handler_query_t : z_ring_handler_query_loan,            \\\n                  z_owned_ring_handler_reply_t : z_ring_handler_reply_loan,            \\\n                  z_owned_ring_handler_sample_t : z_ring_handler_sample_loan,          \\\n                  z_owned_reply_err_t : z_reply_err_loan,                              \\\n                  z_owned_closure_sample_t : z_closure_sample_loan,                    \\\n                  z_owned_closure_reply_t : z_closure_reply_loan,                      \\\n                  z_owned_closure_query_t : z_closure_query_loan,                      \\\n                  z_owned_closure_hello_t : z_closure_hello_loan,                      \\\n                  z_owned_closure_zid_t : z_closure_zid_loan,                          \\\n                  z_owned_closure_matching_status_t : z_closure_matching_status_loan,  \\\n                  ze_owned_closure_miss_t : ze_closure_miss_loan,                      \\\n                  ze_owned_serializer_t : ze_serializer_loan,                          \\\n                  z_owned_bytes_writer_t : z_bytes_writer_loan,                        \\\n                  z_owned_cancellation_token_t : z_cancellation_token_loan             \\\n                  _Z_GENERIC_CONNECTIVITY_LOAN                                         \\\n            )(&x)\n\n#define z_loan_mut(x) _Generic((x), \\\n                  z_owned_keyexpr_t : z_keyexpr_loan_mut,                              \\\n                  z_owned_config_t : z_config_loan_mut,                                \\\n                  z_owned_session_t : z_session_loan_mut,                              \\\n                  z_owned_publisher_t : z_publisher_loan_mut,                          \\\n                  ze_owned_advanced_publisher_t : ze_advanced_publisher_loan_mut,      \\\n                  ze_owned_advanced_subscriber_t : ze_advanced_subscriber_loan_mut,    \\\n                  z_owned_querier_t : z_querier_loan_mut,                              \\\n                  z_owned_matching_listener_t : z_matching_listener_loan_mut,          \\\n                  ze_owned_sample_miss_listener_t : ze_sample_miss_listener_loan_mut,  \\\n                  z_owned_queryable_t : z_queryable_loan_mut,                          \\\n                  z_owned_liveliness_token_t : z_liveliness_token_loan_mut,            \\\n                  z_owned_subscriber_t : z_subscriber_loan_mut,                        \\\n                  z_owned_reply_t : z_reply_loan_mut,                                  \\\n                  z_owned_hello_t : z_hello_loan_mut,                                  \\\n                  z_owned_string_t : z_string_loan_mut,                                \\\n                  z_view_string_t : z_view_string_loan_mut,                            \\\n                  z_owned_string_array_t : z_string_array_loan_mut,                    \\\n                  z_owned_sample_t : z_sample_loan_mut,                                \\\n                  z_owned_query_t : z_query_loan_mut,                                  \\\n                  z_owned_slice_t : z_slice_loan_mut,                                  \\\n                  z_view_slice_t : z_view_slice_loan_mut,                              \\\n                  z_owned_bytes_t : z_bytes_loan_mut,                                  \\\n                  z_owned_task_t : z_task_loan_mut,                                    \\\n                  z_owned_mutex_t : z_mutex_loan_mut,                                  \\\n                  z_owned_condvar_t : z_condvar_loan_mut,                              \\\n                  z_owned_reply_err_t : z_reply_err_loan_mut,                          \\\n                  ze_owned_serializer_t : ze_serializer_loan_mut,                      \\\n                  z_owned_bytes_writer_t : z_bytes_writer_loan_mut,                    \\\n                  z_owned_cancellation_token_t : z_cancellation_token_loan_mut         \\\n                  _Z_GENERIC_CONNECTIVITY_LOAN_MUT                                     \\\n            )(&x)\n\n/**\n * Defines a generic function for dropping any of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   x: The instance to drop.\n */\n#define z_drop(x) _Generic((x), \\\n                  z_moved_keyexpr_t* : z_keyexpr_drop,                                 \\\n                  z_moved_config_t* : z_config_drop,                                   \\\n                  z_moved_session_t* : z_session_drop,                                 \\\n                  z_moved_subscriber_t* : z_subscriber_drop,                           \\\n                  z_moved_publisher_t* : z_publisher_drop,                             \\\n                  ze_moved_advanced_subscriber_t* : ze_advanced_subscriber_drop,       \\\n                  ze_moved_advanced_publisher_t* : ze_advanced_publisher_drop,         \\\n                  z_moved_querier_t* : z_querier_drop,                                 \\\n                  z_moved_matching_listener_t* : z_matching_listener_drop,             \\\n                  ze_moved_sample_miss_listener_t* : ze_sample_miss_listener_drop,     \\\n                  z_moved_queryable_t* : z_queryable_drop,                             \\\n                  z_moved_liveliness_token_t* : z_liveliness_token_drop,               \\\n                  z_moved_reply_t* : z_reply_drop,                                     \\\n                  z_moved_hello_t* : z_hello_drop,                                     \\\n                  z_moved_string_t* : z_string_drop,                                   \\\n                  z_moved_string_array_t* : z_string_array_drop,                       \\\n                  z_moved_sample_t* : z_sample_drop,                                   \\\n                  z_moved_query_t* : z_query_drop,                                     \\\n                  z_moved_encoding_t* : z_encoding_drop,                               \\\n                  z_moved_slice_t* : z_slice_drop,                                     \\\n                  z_moved_bytes_t* : z_bytes_drop,                                     \\\n                  z_moved_closure_sample_t* : z_closure_sample_drop,                   \\\n                  z_moved_closure_query_t* : z_closure_query_drop,                     \\\n                  z_moved_closure_reply_t* : z_closure_reply_drop,                     \\\n                  z_moved_closure_hello_t* : z_closure_hello_drop,                     \\\n                  z_moved_closure_zid_t* : z_closure_zid_drop,                         \\\n                  z_moved_closure_matching_status_t* : z_closure_matching_status_drop, \\\n                  ze_moved_closure_miss_t* : ze_closure_miss_drop,                     \\\n                  z_moved_task_t* : z_task_join,                                       \\\n                  z_moved_mutex_t* : z_mutex_drop,                                     \\\n                  z_moved_condvar_t* : z_condvar_drop,                                 \\\n                  z_moved_fifo_handler_query_t* : z_fifo_handler_query_drop,           \\\n                  z_moved_fifo_handler_reply_t* : z_fifo_handler_reply_drop,           \\\n                  z_moved_fifo_handler_sample_t* : z_fifo_handler_sample_drop,         \\\n                  z_moved_ring_handler_query_t* : z_ring_handler_query_drop,           \\\n                  z_moved_ring_handler_reply_t* : z_ring_handler_reply_drop,           \\\n                  z_moved_ring_handler_sample_t* : z_ring_handler_sample_drop,         \\\n                  z_moved_reply_err_t* : z_reply_err_drop,                             \\\n                  ze_moved_serializer_t* : ze_serializer_drop,                         \\\n                  z_moved_bytes_writer_t* : z_bytes_writer_drop,                       \\\n                  z_moved_cancellation_token_t* : z_cancellation_token_drop            \\\n                  _Z_GENERIC_CONNECTIVITY_DROP                                         \\\n            )(x)\n\n/**\n * Defines a generic function for checking the validity of any of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   x: The instance to check.\n *\n * Returns:\n *   Returns ``true`` if valid, or ``false`` otherwise.\n */\n\n#define z_internal_check(x) _Generic((x), \\\n                  z_owned_keyexpr_t : z_internal_keyexpr_check,                                  \\\n                  z_owned_reply_err_t : z_internal_reply_err_check,                              \\\n                  z_owned_config_t : z_internal_config_check,                                    \\\n                  z_owned_session_t : z_internal_session_check,                                  \\\n                  z_owned_subscriber_t : z_internal_subscriber_check,                            \\\n                  z_owned_publisher_t : z_internal_publisher_check,                              \\\n                  ze_owned_advanced_subscriber_t : ze_internal_advanced_subscriber_check,        \\\n                  ze_owned_advanced_publisher_t : ze_internal_advanced_publisher_check,          \\\n                  z_owned_querier_t : z_internal_querier_check,                                  \\\n                  z_owned_matching_listener_t : z_internal_matching_listener_check,              \\\n                  ze_owned_sample_miss_listener_t : ze_internal_sample_miss_listener_check,      \\\n                  z_owned_queryable_t : z_internal_queryable_check,                              \\\n                  z_owned_liveliness_token_t : z_internal_liveliness_token_check,                \\\n                  z_owned_reply_t : z_internal_reply_check,                                      \\\n                  z_owned_hello_t : z_internal_hello_check,                                      \\\n                  z_owned_string_t : z_internal_string_check,                                    \\\n                  z_owned_string_array_t : z_internal_string_array_check,                        \\\n                  z_owned_closure_sample_t : z_internal_closure_sample_check,                    \\\n                  z_owned_closure_query_t : z_internal_closure_query_check,                      \\\n                  z_owned_closure_reply_t : z_internal_closure_reply_check,                      \\\n                  z_owned_closure_hello_t : z_internal_closure_hello_check,                      \\\n                  z_owned_closure_zid_t : z_internal_closure_zid_check,                          \\\n                  z_owned_closure_matching_status_t : z_internal_closure_matching_status_check,  \\\n                  ze_owned_closure_miss_t : ze_internal_closure_miss_check,                      \\\n                  z_owned_slice_t : z_internal_slice_check,                                      \\\n                  z_owned_bytes_t : z_internal_bytes_check,                                      \\\n                  z_owned_sample_t : z_internal_sample_check,                                    \\\n                  z_owned_query_t : z_internal_query_check,                                      \\\n                  z_owned_encoding_t : z_internal_encoding_check,                                \\\n                  ze_owned_serializer_t : ze_internal_serializer_check,                          \\\n                  z_owned_bytes_writer_t : z_internal_bytes_writer_check,                        \\\n                  z_owned_cancellation_token_t : z_internal_cancellation_token_check             \\\n                  _Z_GENERIC_CONNECTIVITY_CHECK                                                  \\\n            )(&x)\n\n/**\n * Defines a generic function for calling closure stored in any of ``z_owned_closure_X_t``\n *\n * Parameters:\n *   x: The closure to call\n */\n#define z_call(x, ...) \\\n    _Generic((x), z_loaned_closure_sample_t : z_closure_sample_call,                   \\\n                  z_loaned_closure_query_t : z_closure_query_call,                     \\\n                  z_loaned_closure_reply_t : z_closure_reply_call,                     \\\n                  z_loaned_closure_hello_t : z_closure_hello_call,                     \\\n                  z_loaned_closure_zid_t : z_closure_zid_call,                         \\\n                  z_loaned_closure_matching_status_t : z_closure_matching_status_call, \\\n                  ze_loaned_closure_miss_t : ze_closure_miss_call                      \\\n                  _Z_GENERIC_CONNECTIVITY_CALL                                         \\\n            ) (&x, __VA_ARGS__)\n\n#define z_try_recv(x, ...) \\\n    _Generic((x), \\\n        const z_loaned_fifo_handler_query_t* : z_fifo_handler_query_try_recv, \\\n        const z_loaned_fifo_handler_reply_t* : z_fifo_handler_reply_try_recv, \\\n        const z_loaned_fifo_handler_sample_t* : z_fifo_handler_sample_try_recv, \\\n        const z_loaned_ring_handler_query_t* : z_ring_handler_query_try_recv, \\\n        const z_loaned_ring_handler_reply_t* : z_ring_handler_reply_try_recv, \\\n        const z_loaned_ring_handler_sample_t* : z_ring_handler_sample_try_recv \\\n    )(x, __VA_ARGS__)\n\n#define z_recv(x, ...) \\\n    _Generic((x), \\\n        const z_loaned_fifo_handler_query_t* : z_fifo_handler_query_recv, \\\n        const z_loaned_fifo_handler_reply_t* : z_fifo_handler_reply_recv, \\\n        const z_loaned_fifo_handler_sample_t* : z_fifo_handler_sample_recv, \\\n        const z_loaned_ring_handler_query_t* : z_ring_handler_query_recv, \\\n        const z_loaned_ring_handler_reply_t* : z_ring_handler_reply_recv, \\\n        const z_loaned_ring_handler_sample_t* : z_ring_handler_sample_recv \\\n    )(x, __VA_ARGS__)\n\n/**\n * Defines a generic function for moving any of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   x: The instance to move.\n *\n * Returns:\n *   Returns the instance associated with `x`.\n */\n#define z_move(x) _Generic((x), \\\n                  z_owned_keyexpr_t : z_keyexpr_move,                                   \\\n                  z_owned_config_t : z_config_move,                                     \\\n                  z_owned_session_t : z_session_move,                                   \\\n                  z_owned_subscriber_t : z_subscriber_move,                             \\\n                  z_owned_publisher_t : z_publisher_move,                               \\\n                  ze_owned_advanced_subscriber_t : ze_advanced_subscriber_move,         \\\n                  ze_owned_advanced_publisher_t : ze_advanced_publisher_move,           \\\n                  z_owned_querier_t : z_querier_move,                                   \\\n                  z_owned_matching_listener_t: z_matching_listener_move,                \\\n                  ze_owned_sample_miss_listener_t: ze_sample_miss_listener_move,        \\\n                  z_owned_queryable_t : z_queryable_move,                               \\\n                  z_owned_liveliness_token_t : z_liveliness_token_move,                 \\\n                  z_owned_reply_t : z_reply_move,                                       \\\n                  z_owned_hello_t : z_hello_move,                                       \\\n                  z_owned_string_t : z_string_move,                                     \\\n                  z_owned_string_array_t : z_string_array_move,                         \\\n                  z_owned_closure_sample_t : z_closure_sample_move,                     \\\n                  z_owned_closure_query_t : z_closure_query_move,                       \\\n                  z_owned_closure_reply_t : z_closure_reply_move,                       \\\n                  z_owned_closure_hello_t : z_closure_hello_move,                       \\\n                  z_owned_closure_zid_t  : z_closure_zid_move,                          \\\n                  z_owned_closure_matching_status_t  : z_closure_matching_status_move,  \\\n                  ze_owned_closure_miss_t  : ze_closure_miss_move,                      \\\n                  z_owned_sample_t : z_sample_move,                                     \\\n                  z_owned_query_t : z_query_move,                                       \\\n                  z_owned_slice_t : z_slice_move,                                       \\\n                  z_owned_bytes_t : z_bytes_move,                                       \\\n                  z_owned_encoding_t : z_encoding_move,                                 \\\n                  z_owned_task_t : z_task_move,                                         \\\n                  z_owned_mutex_t : z_mutex_move,                                       \\\n                  z_owned_condvar_t : z_condvar_move,                                   \\\n                  z_owned_ring_handler_query_t : z_ring_handler_query_move,             \\\n                  z_owned_ring_handler_reply_t : z_ring_handler_reply_move,             \\\n                  z_owned_ring_handler_sample_t : z_ring_handler_sample_move,           \\\n                  z_owned_fifo_handler_query_t : z_fifo_handler_query_move,             \\\n                  z_owned_fifo_handler_reply_t : z_fifo_handler_reply_move,             \\\n                  z_owned_fifo_handler_sample_t : z_fifo_handler_sample_move,           \\\n                  z_owned_reply_err_t : z_reply_err_move,                               \\\n                  ze_owned_serializer_t : ze_serializer_move,                           \\\n                  z_owned_bytes_writer_t : z_bytes_writer_move,                         \\\n                  z_owned_cancellation_token_t : z_cancellation_token_move              \\\n                  _Z_GENERIC_CONNECTIVITY_MOVE                                         \\\n            )(&x)\n\n/**\n * Defines a generic function for extracting the ``z_owned_X_t`` type from ``z_moved_X_t``\n *\n * Parameters:\n *   x: The pointer to destinaton ``z_owned_X_t``\n *   src: The source ``z_moved_X_t``\n *\n * Returns:\n *   Returns the instance associated with `x`.\n */\n#define z_take(this_, x)                                                       \\\n    _Generic((this_),                                                          \\\n        z_owned_bytes_t *: z_bytes_take,                                       \\\n        z_owned_closure_hello_t *: z_closure_hello_take,                       \\\n        z_owned_closure_query_t *: z_closure_query_take,                       \\\n        z_owned_closure_reply_t *: z_closure_reply_take,                       \\\n        z_owned_closure_sample_t *: z_closure_sample_take,                     \\\n        z_owned_closure_zid_t * : z_closure_zid_take,                          \\\n        z_owned_closure_matching_status_t * : z_closure_matching_status_take,  \\\n        ze_owned_closure_miss_t * : ze_closure_miss_take,                      \\\n        z_owned_condvar_t *: z_condvar_take,                                   \\\n        z_owned_config_t *: z_config_take,                                     \\\n        z_owned_encoding_t *: z_encoding_take,                                 \\\n        z_owned_fifo_handler_query_t *: z_fifo_handler_query_take,             \\\n        z_owned_fifo_handler_reply_t *: z_fifo_handler_reply_take,             \\\n        z_owned_fifo_handler_sample_t *: z_fifo_handler_sample_take,           \\\n        z_owned_hello_t *: z_hello_take,                                       \\\n        z_owned_keyexpr_t *: z_keyexpr_take,                                   \\\n        z_owned_mutex_t *: z_mutex_take,                                       \\\n        z_owned_publisher_t *: z_publisher_take,                               \\\n        ze_owned_advanced_publisher_t *: ze_advanced_publisher_take,           \\\n        z_owned_querier_t *: z_querier_take,                                   \\\n        z_owned_matching_listener_t *: z_matching_listener_take,               \\\n        ze_owned_sample_miss_listener_t *: ze_sample_miss_listener_take,       \\\n        z_owned_query_t *: z_query_take,                                       \\\n        z_owned_queryable_t *: z_queryable_take,                               \\\n        z_owned_liveliness_token_t *: z_liveliness_token_take,                 \\\n        z_owned_reply_t *: z_reply_take,                                       \\\n        z_owned_reply_err_t *: z_reply_err_take,                               \\\n        z_owned_ring_handler_query_t *: z_ring_handler_query_take,             \\\n        z_owned_ring_handler_reply_t *: z_ring_handler_reply_take,             \\\n        z_owned_ring_handler_sample_t *: z_ring_handler_sample_take,           \\\n        z_owned_sample_t *: z_sample_take,                                     \\\n        z_owned_session_t *: z_session_take,                                   \\\n        z_owned_slice_t *: z_slice_take,                                       \\\n        z_owned_string_array_t *: z_string_array_take,                         \\\n        z_owned_string_t *: z_string_take,                                     \\\n        z_owned_subscriber_t *: z_subscriber_take,                             \\\n        ze_owned_serializer_t *: ze_serializer_take,                           \\\n        z_owned_bytes_writer_t *: z_bytes_writer_take,                         \\\n        z_owned_cancellation_token_t *: z_cancellation_token_take              \\\n        _Z_GENERIC_CONNECTIVITY_TAKE                                         \\\n    )(this_, x)\n\n/**\n * Defines a generic function for cloning of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   dst: The clone destination.\n *   src: The instance to clone.\n *\n * Returns:\n *   `0` in case of success, negative error code otherwise.\n */\n#define z_clone(dst, src) _Generic((dst),                                    \\\n                  z_owned_keyexpr_t* : z_keyexpr_clone,                      \\\n                  z_owned_query_t* : z_query_clone,                          \\\n                  z_owned_sample_t* : z_sample_clone,                        \\\n                  z_owned_bytes_t* : z_bytes_clone,                          \\\n                  z_owned_encoding_t* : z_encoding_clone,                    \\\n                  z_owned_reply_err_t* : z_reply_err_clone,                  \\\n                  z_owned_reply_t* : z_reply_clone,                          \\\n                  z_owned_hello_t* : z_hello_clone,                          \\\n                  z_owned_string_t* : z_string_clone,                        \\\n                  z_owned_slice_t* : z_slice_clone,                          \\\n                  z_owned_string_array_t* : z_string_array_clone,            \\\n                  z_owned_config_t* : z_config_clone,                        \\\n                  z_owned_cancellation_token_t* : z_cancellation_token_clone \\\n                  _Z_GENERIC_CONNECTIVITY_CLONE                              \\\n            )(dst, src)\n\n/**\n * Defines a generic function for moving of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   dst: The take destination.\n *   src: The instance to take contents from.\n *\n * Returns:\n *   `0` in case of success, negative error code otherwise.\n */\n#define z_take_from_loaned(dst, src) _Generic((dst),                               \\\n                  z_owned_keyexpr_t* : z_keyexpr_take_from_loaned,                 \\\n                  z_owned_query_t* : z_query_take_from_loaned,                     \\\n                  z_owned_sample_t* : z_sample_take_from_loaned,                   \\\n                  z_owned_bytes_t* : z_bytes_take_from_loaned,                     \\\n                  z_owned_encoding_t* : z_encoding_take_from_loaned,               \\\n                  z_owned_reply_err_t* : z_reply_err_take_from_loaned,             \\\n                  z_owned_reply_t* : z_reply_take_from_loaned,                     \\\n                  z_owned_hello_t* : z_hello_take_from_loaned,                     \\\n                  z_owned_string_t* : z_string_take_from_loaned,                   \\\n                  z_owned_slice_t* : z_slice_take_from_loaned,                     \\\n                  z_owned_string_array_t* : z_string_array_take_from_loaned,       \\\n                  z_owned_config_t* : z_config_take_from_loaned,                   \\\n                  z_owned_bytes_writer_t* : z_bytes_writer_take_from_loaned,       \\\n                  ze_owned_serializer_t* : ze_serializer_take_from_loaned,         \\\n                  z_cancellation_token_t* : z_cancellation_token_take_from_loaned  \\\n                  _Z_GENERIC_CONNECTIVITY_TAKE_FROM_LOANED                       \\\n            )(dst, src)\n\n/**\n * Defines a generic function for making null object of any of the ``z_owned_X_t`` types.\n *\n * Parameters:\n *   x: The instance to nullify.\n */\n#define z_internal_null(x) _Generic((x), \\\n                  z_owned_session_t * : z_internal_session_null,                                  \\\n                  z_owned_publisher_t * : z_internal_publisher_null,                              \\\n                  ze_owned_advanced_subscriber_t * : ze_internal_advanced_subscriber_null,        \\\n                  ze_owned_advanced_publisher_t * : ze_internal_advanced_publisher_null,          \\\n                  z_owned_querier_t * : z_internal_querier_null,                                  \\\n                  z_owned_matching_listener_t * : z_internal_matching_listener_null,              \\\n                  ze_owned_sample_miss_listener_t * : ze_internal_sample_miss_listener_null,      \\\n                  z_owned_keyexpr_t * : z_internal_keyexpr_null,                                  \\\n                  z_owned_config_t * : z_internal_config_null,                                    \\\n                  z_owned_subscriber_t * : z_internal_subscriber_null,                            \\\n                  z_owned_queryable_t * : z_internal_queryable_null,                              \\\n                  z_owned_liveliness_token_t * : z_internal_liveliness_token_null,                \\\n                  z_owned_query_t * : z_internal_query_null,                                      \\\n                  z_owned_reply_t * : z_internal_reply_null,                                      \\\n                  z_owned_hello_t * : z_internal_hello_null,                                      \\\n                  z_owned_string_t * : z_internal_string_null,                                    \\\n                  z_owned_string_array_t * : z_internal_string_array_null,                        \\\n                  z_owned_slice_t  *: z_internal_slice_null,                                      \\\n                  z_owned_bytes_t  *: z_internal_bytes_null,                                      \\\n                  z_owned_closure_sample_t * : z_internal_closure_sample_null,                    \\\n                  z_owned_closure_query_t * : z_internal_closure_query_null,                      \\\n                  z_owned_closure_reply_t * : z_internal_closure_reply_null,                      \\\n                  z_owned_closure_hello_t * : z_internal_closure_hello_null,                      \\\n                  z_owned_closure_zid_t * : z_internal_closure_zid_null,                          \\\n                  z_owned_closure_matching_status_t * : z_internal_closure_matching_status_null,  \\\n                  ze_owned_closure_miss_t * : ze_internal_closure_miss_null,                      \\\n                  z_owned_sample_t * : z_internal_sample_null,                                    \\\n                  z_owned_encoding_t * : z_internal_encoding_null,                                \\\n                  z_owned_reply_err_t * : z_internal_reply_err_null,                              \\\n                  ze_owned_serializer_t * : ze_internal_serializer_null,                          \\\n                  z_owned_bytes_writer_t * : z_internal_bytes_writer_null,                        \\\n                  z_owned_cancellation_token_t * : z_internal_cancellation_token_null             \\\n                  _Z_GENERIC_CONNECTIVITY_NULL                                                    \\\n            )(x)\n\n// clang-format on\n\n#define _z_closure_overloader(closure, callback, dropper, ctx, ...) \\\n    do {                                                            \\\n        (closure)->_val.call = callback;                            \\\n        (closure)->_val.drop = dropper;                             \\\n        (closure)->_val.context = ctx;                              \\\n    } while (0);\n\n/**\n * Defines a variadic macro to ease the definition of callback closures.\n *\n * Parameters:\n *   callback: the typical ``callback`` function. ``context`` will be passed as its last argument.\n *   dropper: allows the callback's state to be freed. ``context`` will be passed as its last argument.\n *   context: a pointer to an arbitrary state.\n *\n * Returns:\n *   Returns the new closure.\n */\n#define z_closure(...) _z_closure_overloader(__VA_ARGS__, 0, 0, 0)\n\n#else  // __cplusplus\n\n// clang-format off\n\n// z_loan definition\ninline const z_loaned_keyexpr_t* z_loan(const z_owned_keyexpr_t& x) { return z_keyexpr_loan(&x); }\ninline const z_loaned_keyexpr_t* z_loan(const z_view_keyexpr_t& x) { return z_view_keyexpr_loan(&x); }\ninline const z_loaned_config_t* z_loan(const z_owned_config_t& x) { return z_config_loan(&x); }\ninline const z_loaned_session_t* z_loan(const z_owned_session_t& x) { return z_session_loan(&x); }\ninline const z_loaned_subscriber_t* z_loan(const z_owned_subscriber_t& x) { return z_subscriber_loan(&x); }\ninline const z_loaned_publisher_t* z_loan(const z_owned_publisher_t& x) { return z_publisher_loan(&x); }\ninline const ze_loaned_advanced_subscriber_t* z_loan(const ze_owned_advanced_subscriber_t& x) { return ze_advanced_subscriber_loan(&x); }\ninline const ze_loaned_advanced_publisher_t* z_loan(const ze_owned_advanced_publisher_t& x) { return ze_advanced_publisher_loan(&x); }\ninline const z_loaned_querier_t* z_loan(const z_owned_querier_t& x) { return z_querier_loan(&x); }\ninline const z_loaned_matching_listener_t* z_loan(const z_owned_matching_listener_t& x) { return z_matching_listener_loan(&x); }\ninline const ze_loaned_sample_miss_listener_t* z_loan(const ze_owned_sample_miss_listener_t& x) { return ze_sample_miss_listener_loan(&x); }\ninline const z_loaned_queryable_t* z_loan(const z_owned_queryable_t& x) { return z_queryable_loan(&x); }\ninline const z_loaned_liveliness_token_t* z_loan(const z_owned_liveliness_token_t& x) { return z_liveliness_token_loan(&x); }\ninline const z_loaned_reply_t* z_loan(const z_owned_reply_t& x) { return z_reply_loan(&x); }\ninline const z_loaned_hello_t* z_loan(const z_owned_hello_t& x) { return z_hello_loan(&x); }\ninline const z_loaned_string_t* z_loan(const z_owned_string_t& x) { return z_string_loan(&x); }\ninline const z_loaned_string_t* z_loan(const z_view_string_t& x) { return z_view_string_loan(&x); }\ninline const z_loaned_string_array_t* z_loan(const z_owned_string_array_t& x) { return z_string_array_loan(&x); }\ninline const z_loaned_sample_t* z_loan(const z_owned_sample_t& x) { return z_sample_loan(&x); }\ninline const z_loaned_query_t* z_loan(const z_owned_query_t& x) { return z_query_loan(&x); }\ninline const z_loaned_slice_t* z_loan(const z_owned_slice_t& x) { return z_slice_loan(&x); }\ninline const z_loaned_slice_t* z_loan(const z_view_slice_t& x) { return z_view_slice_loan(&x); }\ninline const z_loaned_bytes_t* z_loan(const z_owned_bytes_t& x) { return z_bytes_loan(&x); }\ninline const z_loaned_encoding_t* z_loan(const z_owned_encoding_t& x) { return z_encoding_loan(&x); }\ninline const z_loaned_task_t* z_loan(const z_owned_task_t& x) { return z_task_loan(&x); }\ninline const z_loaned_mutex_t* z_loan(const z_owned_mutex_t& x) { return z_mutex_loan(&x); }\ninline const z_loaned_condvar_t* z_loan(const z_owned_condvar_t& x) { return z_condvar_loan(&x); }\ninline const z_loaned_reply_err_t* z_loan(const z_owned_reply_err_t& x) { return z_reply_err_loan(&x); }\ninline const z_loaned_closure_sample_t* z_loan(const z_owned_closure_sample_t& x) { return z_closure_sample_loan(&x); }\ninline const z_loaned_closure_reply_t* z_loan(const z_owned_closure_reply_t& x) { return z_closure_reply_loan(&x); }\ninline const z_loaned_closure_query_t* z_loan(const z_owned_closure_query_t& x) { return z_closure_query_loan(&x); }\ninline const z_loaned_closure_hello_t* z_loan(const z_owned_closure_hello_t& x) { return z_closure_hello_loan(&x); }\ninline const z_loaned_closure_zid_t* z_loan(const z_owned_closure_zid_t& x) { return z_closure_zid_loan(&x); }\ninline const z_loaned_closure_matching_status_t* z_loan(const z_owned_closure_matching_status_t& x) { return z_closure_matching_status_loan(&x); }\ninline const ze_loaned_closure_miss_t* z_loan(const ze_owned_closure_miss_t& x) { return ze_closure_miss_loan(&x); }\ninline const z_loaned_fifo_handler_query_t* z_loan(const z_owned_fifo_handler_query_t& x) { return z_fifo_handler_query_loan(&x); }\ninline const z_loaned_fifo_handler_reply_t* z_loan(const z_owned_fifo_handler_reply_t& x) { return z_fifo_handler_reply_loan(&x); }\ninline const z_loaned_fifo_handler_sample_t* z_loan(const z_owned_fifo_handler_sample_t& x) { return z_fifo_handler_sample_loan(&x); }\ninline const z_loaned_ring_handler_query_t* z_loan(const z_owned_ring_handler_query_t& x) { return z_ring_handler_query_loan(&x); }\ninline const z_loaned_ring_handler_reply_t* z_loan(const z_owned_ring_handler_reply_t& x) { return z_ring_handler_reply_loan(&x); }\ninline const z_loaned_ring_handler_sample_t* z_loan(const z_owned_ring_handler_sample_t& x) { return z_ring_handler_sample_loan(&x); }\ninline const z_loaned_bytes_writer_t* z_loan(const z_owned_bytes_writer_t& x) { return z_bytes_writer_loan(&x); }\ninline const ze_loaned_serializer_t* z_loan(const ze_owned_serializer_t& x) { return ze_serializer_loan(&x); }\ninline const z_loaned_cancellation_token_t* z_loan(const z_owned_cancellation_token_t& x) { return z_cancellation_token_loan(&x); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline const z_loaned_transport_t* z_loan(const z_owned_transport_t& x) { return z_transport_loan(&x); }\ninline const z_loaned_link_t* z_loan(const z_owned_link_t& x) { return z_link_loan(&x); }\ninline const z_loaned_transport_event_t* z_loan(const z_owned_transport_event_t& x) { return z_transport_event_loan(&x); }\ninline const z_loaned_link_event_t* z_loan(const z_owned_link_event_t& x) { return z_link_event_loan(&x); }\ninline const z_loaned_transport_events_listener_t* z_loan(const z_owned_transport_events_listener_t& x) { return z_transport_events_listener_loan(&x); }\ninline const z_loaned_link_events_listener_t* z_loan(const z_owned_link_events_listener_t& x) { return z_link_events_listener_loan(&x); }\ninline const z_loaned_closure_transport_t* z_loan(const z_owned_closure_transport_t& x) { return z_closure_transport_loan(&x); }\ninline const z_loaned_closure_link_t* z_loan(const z_owned_closure_link_t& x) { return z_closure_link_loan(&x); }\ninline const z_loaned_closure_transport_event_t* z_loan(const z_owned_closure_transport_event_t& x) { return z_closure_transport_event_loan(&x); }\ninline const z_loaned_closure_link_event_t* z_loan(const z_owned_closure_link_event_t& x) { return z_closure_link_event_loan(&x); }\n#endif\n\n// z_loan_mut definition\ninline z_loaned_keyexpr_t* z_loan_mut(z_owned_keyexpr_t& x) { return z_keyexpr_loan_mut(&x); }\ninline z_loaned_keyexpr_t* z_loan_mut(z_view_keyexpr_t& x) { return z_view_keyexpr_loan_mut(&x); }\ninline z_loaned_config_t* z_loan_mut(z_owned_config_t& x) { return z_config_loan_mut(&x); }\ninline z_loaned_session_t* z_loan_mut(z_owned_session_t& x) { return z_session_loan_mut(&x); }\ninline z_loaned_publisher_t* z_loan_mut(z_owned_publisher_t& x) { return z_publisher_loan_mut(&x); }\ninline ze_loaned_advanced_publisher_t* z_loan_mut(ze_owned_advanced_publisher_t& x) { return ze_advanced_publisher_loan_mut(&x); }\ninline z_loaned_querier_t* z_loan_mut(z_owned_querier_t& x) { return z_querier_loan_mut(&x); }\ninline z_loaned_matching_listener_t* z_loan_mut(z_owned_matching_listener_t& x) { return z_matching_listener_loan_mut(&x); }\ninline ze_loaned_sample_miss_listener_t* z_loan_mut(ze_owned_sample_miss_listener_t& x) { return ze_sample_miss_listener_loan_mut(&x); }\ninline z_loaned_queryable_t* z_loan_mut(z_owned_queryable_t& x) { return z_queryable_loan_mut(&x); }\ninline z_loaned_liveliness_token_t* z_loan_mut(z_owned_liveliness_token_t& x) { return z_liveliness_token_loan_mut(&x); }\ninline z_loaned_subscriber_t* z_loan_mut(z_owned_subscriber_t& x) { return z_subscriber_loan_mut(&x); }\ninline ze_loaned_advanced_subscriber_t* z_loan_mut(ze_owned_advanced_subscriber_t& x) { return ze_advanced_subscriber_loan_mut(&x); }\ninline z_loaned_reply_t* z_loan_mut(z_owned_reply_t& x) { return z_reply_loan_mut(&x); }\ninline z_loaned_hello_t* z_loan_mut(z_owned_hello_t& x) { return z_hello_loan_mut(&x); }\ninline z_loaned_string_t* z_loan_mut(z_owned_string_t& x) { return z_string_loan_mut(&x); }\ninline z_loaned_string_t* z_loan_mut(z_view_string_t& x) { return z_view_string_loan_mut(&x); }\ninline z_loaned_slice_t* z_loan_mut(z_view_slice_t& x) { return z_view_slice_loan_mut(&x); }\ninline z_loaned_string_array_t* z_loan_mut(z_owned_string_array_t& x) { return z_string_array_loan_mut(&x); }\ninline z_loaned_sample_t* z_loan_mut(z_owned_sample_t& x) { return z_sample_loan_mut(&x); }\ninline z_loaned_query_t* z_loan_mut(z_owned_query_t& x) { return z_query_loan_mut(&x); }\ninline z_loaned_slice_t* z_loan_mut(z_owned_slice_t& x) { return z_slice_loan_mut(&x); }\ninline z_loaned_bytes_t* z_loan_mut(z_owned_bytes_t& x) { return z_bytes_loan_mut(&x); }\ninline z_loaned_encoding_t* z_loan_mut(z_owned_encoding_t& x) { return z_encoding_loan_mut(&x); }\ninline z_loaned_task_t* z_loan_mut(z_owned_task_t& x) { return z_task_loan_mut(&x); }\ninline z_loaned_mutex_t* z_loan_mut(z_owned_mutex_t& x) { return z_mutex_loan_mut(&x); }\ninline z_loaned_condvar_t* z_loan_mut(z_owned_condvar_t& x) { return z_condvar_loan_mut(&x); }\ninline z_loaned_reply_err_t* z_loan_mut(z_owned_reply_err_t& x) { return z_reply_err_loan_mut(&x); }\ninline z_loaned_bytes_writer_t* z_loan_mut(z_owned_bytes_writer_t& x) { return z_bytes_writer_loan_mut(&x); }\ninline ze_loaned_serializer_t* z_loan_mut(ze_owned_serializer_t& x) { return ze_serializer_loan_mut(&x); }\ninline z_loaned_cancellation_token_t* z_loan_mut(z_owned_cancellation_token_t& x) { return z_cancellation_token_loan_mut(&x); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline z_loaned_transport_t* z_loan_mut(z_owned_transport_t& x) { return z_transport_loan_mut(&x); }\ninline z_loaned_link_t* z_loan_mut(z_owned_link_t& x) { return z_link_loan_mut(&x); }\ninline z_loaned_transport_event_t* z_loan_mut(z_owned_transport_event_t& x) { return z_transport_event_loan_mut(&x); }\ninline z_loaned_link_event_t* z_loan_mut(z_owned_link_event_t& x) { return z_link_event_loan_mut(&x); }\ninline z_loaned_transport_events_listener_t* z_loan_mut(z_owned_transport_events_listener_t& x) { return z_transport_events_listener_loan_mut(&x); }\ninline z_loaned_link_events_listener_t* z_loan_mut(z_owned_link_events_listener_t& x) { return z_link_events_listener_loan_mut(&x); }\n#endif\n\n// z_drop definition\ninline void z_drop(z_moved_session_t* v) { z_session_drop(v); }\ninline void z_drop(z_moved_publisher_t* v) { z_publisher_drop(v); }\ninline void z_drop(ze_moved_advanced_publisher_t* v) { ze_advanced_publisher_drop(v); }\ninline void z_drop(z_moved_querier_t* v) { z_querier_drop(v); }\ninline void z_drop(z_moved_matching_listener_t* v) { z_matching_listener_drop(v); }\ninline void z_drop(ze_moved_sample_miss_listener_t* v) { ze_sample_miss_listener_drop(v); }\ninline void z_drop(z_moved_keyexpr_t* v) { z_keyexpr_drop(v); }\ninline void z_drop(z_moved_config_t* v) { z_config_drop(v); }\ninline void z_drop(z_moved_subscriber_t* v) { z_subscriber_drop(v); }\ninline void z_drop(ze_moved_advanced_subscriber_t* v) { ze_advanced_subscriber_drop(v); }\ninline void z_drop(z_moved_queryable_t* v) { z_queryable_drop(v); }\ninline void z_drop(z_moved_liveliness_token_t* v) { z_liveliness_token_drop(v); }\ninline void z_drop(z_moved_reply_t* v) { z_reply_drop(v); }\ninline void z_drop(z_moved_hello_t* v) { z_hello_drop(v); }\ninline void z_drop(z_moved_string_t* v) { z_string_drop(v); }\ninline void z_drop(z_moved_slice_t* v) { z_slice_drop(v); }\ninline void z_drop(z_moved_string_array_t* v) { z_string_array_drop(v); }\ninline void z_drop(z_moved_sample_t* v) { z_sample_drop(v); }\ninline void z_drop(z_moved_query_t* v) { z_query_drop(v); }\ninline void z_drop(z_moved_bytes_t* v) { z_bytes_drop(v); }\ninline void z_drop(z_moved_encoding_t* v) { z_encoding_drop(v); }\ninline void z_drop(z_moved_mutex_t* v) { z_mutex_drop(v); }\ninline void z_drop(z_moved_condvar_t* v) { z_condvar_drop(v); }\ninline void z_drop(z_moved_reply_err_t* v) { z_reply_err_drop(v); }\ninline void z_drop(z_moved_closure_sample_t* v) { z_closure_sample_drop(v); }\ninline void z_drop(z_moved_closure_query_t* v) { z_closure_query_drop(v); }\ninline void z_drop(z_moved_closure_reply_t* v) { z_closure_reply_drop(v); }\ninline void z_drop(z_moved_closure_hello_t* v) { z_closure_hello_drop(v); }\ninline void z_drop(z_moved_closure_zid_t* v) { z_closure_zid_drop(v); }\ninline void z_drop(z_moved_closure_matching_status_t* v) { z_closure_matching_status_drop(v); }\ninline void z_drop(ze_moved_closure_miss_t* v) { ze_closure_miss_drop(v); }\ninline void z_drop(z_moved_ring_handler_sample_t* v) { z_ring_handler_sample_drop(v); }\ninline void z_drop(z_moved_fifo_handler_sample_t* v) { z_fifo_handler_sample_drop(v); }\ninline void z_drop(z_moved_ring_handler_query_t* v) { z_ring_handler_query_drop(v); }\ninline void z_drop(z_moved_fifo_handler_query_t* v) { z_fifo_handler_query_drop(v); }\ninline void z_drop(z_moved_ring_handler_reply_t* v) { z_ring_handler_reply_drop(v); }\ninline void z_drop(z_moved_fifo_handler_reply_t* v) { z_fifo_handler_reply_drop(v); }\ninline void z_drop(z_moved_bytes_writer_t* v) { z_bytes_writer_drop(v); }\ninline void z_drop(ze_moved_serializer_t* v) { ze_serializer_drop(v); }\ninline void z_drop(z_moved_cancellation_token_t* v) { z_cancellation_token_drop(v); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline void z_drop(z_moved_transport_t* v) { z_transport_drop(v); }\ninline void z_drop(z_moved_link_t* v) { z_link_drop(v); }\ninline void z_drop(z_moved_transport_event_t* v) { z_transport_event_drop(v); }\ninline void z_drop(z_moved_link_event_t* v) { z_link_event_drop(v); }\ninline void z_drop(z_moved_transport_events_listener_t* v) { z_transport_events_listener_drop(v); }\ninline void z_drop(z_moved_link_events_listener_t* v) { z_link_events_listener_drop(v); }\ninline void z_drop(z_moved_closure_transport_t* v) { z_closure_transport_drop(v); }\ninline void z_drop(z_moved_closure_link_t* v) { z_closure_link_drop(v); }\ninline void z_drop(z_moved_closure_transport_event_t* v) { z_closure_transport_event_drop(v); }\ninline void z_drop(z_moved_closure_link_event_t* v) { z_closure_link_event_drop(v); }\n#endif\n\n// z_internal_null definition\ninline void z_internal_null(z_owned_session_t* v) { z_internal_session_null(v); }\ninline void z_internal_null(z_owned_publisher_t* v) { z_internal_publisher_null(v); }\ninline void z_internal_null(ze_owned_advanced_publisher_t* v) { ze_internal_advanced_publisher_null(v); }\ninline void z_internal_null(z_owned_querier_t* v) { z_internal_querier_null(v); }\ninline void z_internal_null(z_owned_matching_listener_t* v) { z_internal_matching_listener_null(v); }\ninline void z_internal_null(ze_owned_sample_miss_listener_t* v) { ze_internal_sample_miss_listener_null(v); }\ninline void z_internal_null(z_owned_keyexpr_t* v) { z_internal_keyexpr_null(v); }\ninline void z_internal_null(z_owned_config_t* v) { z_internal_config_null(v); }\ninline void z_internal_null(z_owned_subscriber_t* v) { z_internal_subscriber_null(v); }\ninline void z_internal_null(ze_owned_advanced_subscriber_t* v) { ze_internal_advanced_subscriber_null(v); }\ninline void z_internal_null(z_owned_queryable_t* v) { z_internal_queryable_null(v); }\ninline void z_internal_null(z_owned_liveliness_token_t* v) { z_internal_liveliness_token_null(v); }\ninline void z_internal_null(z_owned_query_t* v) { z_internal_query_null(v); }\ninline void z_internal_null(z_owned_sample_t* v) { z_internal_sample_null(v); }\ninline void z_internal_null(z_owned_reply_t* v) { z_internal_reply_null(v); }\ninline void z_internal_null(z_owned_hello_t* v) { z_internal_hello_null(v); }\ninline void z_internal_null(z_owned_string_t* v) { z_internal_string_null(v); }\ninline void z_internal_null(z_owned_bytes_t* v) { z_internal_bytes_null(v); }\ninline void z_internal_null(z_owned_encoding_t* v) { z_internal_encoding_null(v); }\ninline void z_internal_null(z_owned_reply_err_t* v) { z_internal_reply_err_null(v); }\ninline void z_internal_null(z_owned_closure_sample_t* v) { z_internal_closure_sample_null(v); }\ninline void z_internal_null(z_owned_closure_query_t* v) { z_internal_closure_query_null(v); }\ninline void z_internal_null(z_owned_closure_reply_t* v) { z_internal_closure_reply_null(v); }\ninline void z_internal_null(z_owned_closure_hello_t* v) { z_internal_closure_hello_null(v); }\ninline void z_internal_null(z_owned_closure_zid_t* v) { z_internal_closure_zid_null(v); }\ninline void z_internal_null(z_owned_closure_matching_status_t* v) { z_internal_closure_matching_status_null(v); }\ninline void z_internal_null(ze_owned_closure_miss_t* v) { ze_internal_closure_miss_null(v); }\ninline void z_internal_null(z_owned_ring_handler_query_t* v) { return z_internal_ring_handler_query_null(v); }\ninline void z_internal_null(z_owned_ring_handler_reply_t* v) { return z_internal_ring_handler_reply_null(v); }\ninline void z_internal_null(z_owned_ring_handler_sample_t* v) { return z_internal_ring_handler_sample_null(v); }\ninline void z_internal_null(z_owned_fifo_handler_query_t* v) { return z_internal_fifo_handler_query_null(v); }\ninline void z_internal_null(z_owned_fifo_handler_reply_t* v) { return z_internal_fifo_handler_reply_null(v); }\ninline void z_internal_null(z_owned_fifo_handler_sample_t* v) { return z_internal_fifo_handler_sample_null(v); }\ninline void z_internal_null(z_owned_bytes_writer_t* v) { return z_internal_bytes_writer_null(v); }\ninline void z_internal_null(ze_owned_serializer_t* v) { return ze_internal_serializer_null(v); }\ninline void z_internal_null(z_owned_cancellation_token_t* v) { return z_internal_cancellation_token_null(v); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline void z_internal_null(z_owned_transport_t* v) { z_internal_transport_null(v); }\ninline void z_internal_null(z_owned_link_t* v) { z_internal_link_null(v); }\ninline void z_internal_null(z_owned_transport_event_t* v) { z_internal_transport_event_null(v); }\ninline void z_internal_null(z_owned_link_event_t* v) { z_internal_link_event_null(v); }\ninline void z_internal_null(z_owned_transport_events_listener_t* v) { z_internal_transport_events_listener_null(v); }\ninline void z_internal_null(z_owned_link_events_listener_t* v) { z_internal_link_events_listener_null(v); }\ninline void z_internal_null(z_owned_closure_transport_t* v) { z_internal_closure_transport_null(v); }\ninline void z_internal_null(z_owned_closure_link_t* v) { z_internal_closure_link_null(v); }\ninline void z_internal_null(z_owned_closure_transport_event_t* v) { z_internal_closure_transport_event_null(v); }\ninline void z_internal_null(z_owned_closure_link_event_t* v) { z_internal_closure_link_event_null(v); }\n#endif\n\n// z_internal_check definition\ninline bool z_internal_check(const z_owned_session_t& v) { return z_internal_session_check(&v); }\ninline bool z_internal_check(const z_owned_publisher_t& v) { return z_internal_publisher_check(&v); }\ninline bool z_internal_check(const ze_owned_advanced_publisher_t& v) { return ze_internal_advanced_publisher_check(&v); }\ninline bool z_internal_check(const z_owned_querier_t& v) { return z_internal_querier_check(&v); }\ninline bool z_internal_check(const z_owned_matching_listener_t& v) { return z_internal_matching_listener_check(&v); }\ninline bool z_internal_check(const ze_owned_sample_miss_listener_t& v) { return ze_internal_sample_miss_listener_check(&v); }\ninline bool z_internal_check(const z_owned_keyexpr_t& v) { return z_internal_keyexpr_check(&v); }\ninline bool z_internal_check(const z_owned_config_t& v) { return z_internal_config_check(&v); }\ninline bool z_internal_check(const z_owned_subscriber_t& v) { return z_internal_subscriber_check(&v); }\ninline bool z_internal_check(const ze_owned_advanced_subscriber_t& v) { return ze_internal_advanced_subscriber_check(&v); }\ninline bool z_internal_check(const z_owned_queryable_t& v) { return z_internal_queryable_check(&v); }\ninline bool z_internal_check(const z_owned_liveliness_token_t& v) { return z_internal_liveliness_token_check(&v); }\ninline bool z_internal_check(const z_owned_reply_t& v) { return z_internal_reply_check(&v); }\ninline bool z_internal_check(const z_owned_query_t& v) { return z_internal_query_check(&v); }\ninline bool z_internal_check(const z_owned_hello_t& v) { return z_internal_hello_check(&v); }\ninline bool z_internal_check(const z_owned_string_t& v) { return z_internal_string_check(&v); }\ninline bool z_internal_check(const z_owned_sample_t& v) { return z_internal_sample_check(&v); }\ninline bool z_internal_check(const z_owned_bytes_t& v) { return z_internal_bytes_check(&v); }\ninline bool z_internal_check(const z_owned_encoding_t& v) { return z_internal_encoding_check(&v); }\ninline bool z_internal_check(const z_owned_reply_err_t& v) { return z_internal_reply_err_check(&v); }\ninline bool z_internal_check(const z_owned_fifo_handler_query_t& v) { return z_internal_fifo_handler_query_check(&v); }\ninline bool z_internal_check(const z_owned_fifo_handler_reply_t& v) { return z_internal_fifo_handler_reply_check(&v); }\ninline bool z_internal_check(const z_owned_fifo_handler_sample_t& v) { return z_internal_fifo_handler_sample_check(&v); }\ninline bool z_internal_check(const z_owned_ring_handler_query_t& v) { return z_internal_ring_handler_query_check(&v); }\ninline bool z_internal_check(const z_owned_ring_handler_reply_t& v) { return z_internal_ring_handler_reply_check(&v); }\ninline bool z_internal_check(const z_owned_ring_handler_sample_t& v) { return z_internal_ring_handler_sample_check(&v); }\ninline bool z_internal_check(const z_owned_bytes_writer_t& v) { return z_internal_bytes_writer_check(&v); }\ninline bool z_internal_check(const ze_owned_serializer_t& v) { return ze_internal_serializer_check(&v); }\ninline bool z_internal_check(const z_owned_cancellation_token_t& v) { return z_internal_cancellation_token_check(&v); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline bool z_internal_check(const z_owned_transport_t& v) { return z_internal_transport_check(&v); }\ninline bool z_internal_check(const z_owned_link_t& v) { return z_internal_link_check(&v); }\ninline bool z_internal_check(const z_owned_transport_event_t& v) { return z_internal_transport_event_check(&v); }\ninline bool z_internal_check(const z_owned_link_event_t& v) { return z_internal_link_event_check(&v); }\ninline bool z_internal_check(const z_owned_transport_events_listener_t& v) { return z_internal_transport_events_listener_check(&v); }\ninline bool z_internal_check(const z_owned_link_events_listener_t& v) { return z_internal_link_events_listener_check(&v); }\ninline bool z_internal_check(const z_owned_closure_transport_t& v) { return z_internal_closure_transport_check(&v); }\ninline bool z_internal_check(const z_owned_closure_link_t& v) { return z_internal_closure_link_check(&v); }\ninline bool z_internal_check(const z_owned_closure_transport_event_t& v) { return z_internal_closure_transport_event_check(&v); }\ninline bool z_internal_check(const z_owned_closure_link_event_t& v) { return z_internal_closure_link_event_check(&v); }\n#endif\n\n// z_call definition\ninline void z_call(const z_loaned_closure_sample_t &closure, z_loaned_sample_t *sample) \n    { z_closure_sample_call(&closure, sample); }\ninline void z_call(const z_loaned_closure_query_t &closure, z_loaned_query_t *query)\n    { z_closure_query_call(&closure, query); }\ninline void z_call(const z_loaned_closure_reply_t &closure, z_loaned_reply_t *reply)\n    { z_closure_reply_call(&closure, reply); }\ninline void z_call(const z_loaned_closure_hello_t &closure, z_loaned_hello_t *hello)\n    { z_closure_hello_call(&closure, hello); }\ninline void z_call(const z_loaned_closure_zid_t &closure, const z_id_t *zid)\n    { z_closure_zid_call(&closure, zid); }\ninline void z_call(const z_loaned_closure_matching_status_t &closure, const z_matching_status_t *status)\n    { z_closure_matching_status_call(&closure, status); }\ninline void z_call(const ze_loaned_closure_miss_t &closure, const ze_miss_t *miss)\n    { ze_closure_miss_call(&closure, miss); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline void z_call(const z_loaned_closure_transport_t &closure, z_loaned_transport_t *transport)\n    { z_closure_transport_call(&closure, transport); }\ninline void z_call(const z_loaned_closure_link_t &closure, z_loaned_link_t *link)\n    { z_closure_link_call(&closure, link); }\ninline void z_call(const z_loaned_closure_transport_event_t &closure, z_loaned_transport_event_t *event)\n    { z_closure_transport_event_call(&closure, event); }\ninline void z_call(const z_loaned_closure_link_event_t &closure, z_loaned_link_event_t *event)\n    { z_closure_link_event_call(&closure, event); }\n#endif\n\ninline void z_closure(\n    z_owned_closure_hello_t* closure,\n    void (*call)(z_loaned_hello_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_query_t* closure,\n    void (*call)(z_loaned_query_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_reply_t* closure,\n    void (*call)(z_loaned_reply_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_sample_t* closure,\n    void (*call)(z_loaned_sample_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_zid_t* closure,\n    void (*call)(const z_id_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_matching_status_t* closure,\n    void (*call)(const z_matching_status_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    ze_owned_closure_miss_t* closure,\n    void (*call)(const ze_miss_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\n#if Z_FEATURE_CONNECTIVITY == 1\ninline void z_closure(\n    z_owned_closure_transport_t* closure,\n    void (*call)(z_loaned_transport_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_link_t* closure,\n    void (*call)(z_loaned_link_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_transport_event_t* closure,\n    void (*call)(z_loaned_transport_event_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\ninline void z_closure(\n    z_owned_closure_link_event_t* closure,\n    void (*call)(z_loaned_link_event_t*, void*),\n    void (*drop)(void*),\n    void *context) {\n    closure->_val.context = context;\n    closure->_val.drop = drop;\n    closure->_val.call = call;\n}\n#endif\n\ninline z_result_t z_try_recv(const z_loaned_fifo_handler_query_t* this_, z_owned_query_t* query) {\n    return z_fifo_handler_query_try_recv(this_, query);\n}\ninline z_result_t z_try_recv(const z_loaned_fifo_handler_reply_t* this_, z_owned_reply_t* reply) {\n    return z_fifo_handler_reply_try_recv(this_, reply);\n}\ninline z_result_t z_try_recv(const z_loaned_fifo_handler_sample_t* this_, z_owned_sample_t* sample) {\n    return z_fifo_handler_sample_try_recv(this_, sample);\n}\ninline z_result_t z_try_recv(const z_loaned_ring_handler_query_t* this_, z_owned_query_t* query) {\n    return z_ring_handler_query_try_recv(this_, query);\n}\ninline z_result_t z_try_recv(const z_loaned_ring_handler_reply_t* this_, z_owned_reply_t* reply) {\n    return z_ring_handler_reply_try_recv(this_, reply);\n}\ninline z_result_t z_try_recv(const z_loaned_ring_handler_sample_t* this_, z_owned_sample_t* sample) {\n    return z_ring_handler_sample_try_recv(this_, sample);\n}\n\n\ninline z_result_t z_recv(const z_loaned_fifo_handler_query_t* this_, z_owned_query_t* query) {\n    return z_fifo_handler_query_recv(this_, query);\n}\ninline z_result_t z_recv(const z_loaned_fifo_handler_reply_t* this_, z_owned_reply_t* reply) {\n    return z_fifo_handler_reply_recv(this_, reply);\n}\ninline z_result_t z_recv(const z_loaned_fifo_handler_sample_t* this_, z_owned_sample_t* sample) {\n    return z_fifo_handler_sample_recv(this_, sample);\n}\ninline z_result_t z_recv(const z_loaned_ring_handler_query_t* this_, z_owned_query_t* query) {\n    return z_ring_handler_query_recv(this_, query);\n}\ninline z_result_t z_recv(const z_loaned_ring_handler_reply_t* this_, z_owned_reply_t* reply) {\n    return z_ring_handler_reply_recv(this_, reply);\n}\ninline z_result_t z_recv(const z_loaned_ring_handler_sample_t* this_, z_owned_sample_t* sample) {\n    return z_ring_handler_sample_recv(this_, sample);\n}\n\n// clang-format on\n\ninline z_moved_bytes_t* z_move(z_owned_bytes_t& x) { return z_bytes_move(&x); }\ninline z_moved_closure_hello_t* z_move(z_owned_closure_hello_t& closure) { return z_closure_hello_move(&closure); }\ninline z_moved_closure_query_t* z_move(z_owned_closure_query_t& closure) { return z_closure_query_move(&closure); }\ninline z_moved_closure_reply_t* z_move(z_owned_closure_reply_t& closure) { return z_closure_reply_move(&closure); }\ninline z_moved_closure_sample_t* z_move(z_owned_closure_sample_t& closure) { return z_closure_sample_move(&closure); }\ninline z_moved_closure_zid_t* z_move(z_owned_closure_zid_t& closure) { return z_closure_zid_move(&closure); }\ninline z_moved_closure_matching_status_t* z_move(z_owned_closure_matching_status_t& closure) {\n    return z_closure_matching_status_move(&closure);\n}\ninline ze_moved_closure_miss_t* z_move(ze_owned_closure_miss_t& closure) { return ze_closure_miss_move(&closure); }\ninline z_moved_config_t* z_move(z_owned_config_t& x) { return z_config_move(&x); }\ninline z_moved_encoding_t* z_move(z_owned_encoding_t& x) { return z_encoding_move(&x); }\ninline z_moved_reply_err_t* z_move(z_owned_reply_err_t& x) { return z_reply_err_move(&x); }\ninline z_moved_hello_t* z_move(z_owned_hello_t& x) { return z_hello_move(&x); }\ninline z_moved_keyexpr_t* z_move(z_owned_keyexpr_t& x) { return z_keyexpr_move(&x); }\ninline z_moved_publisher_t* z_move(z_owned_publisher_t& x) { return z_publisher_move(&x); }\ninline ze_moved_advanced_publisher_t* z_move(ze_owned_advanced_publisher_t& x) {\n    return ze_advanced_publisher_move(&x);\n}\ninline z_moved_querier_t* z_move(z_owned_querier_t& x) { return z_querier_move(&x); }\ninline z_moved_matching_listener_t* z_move(z_owned_matching_listener_t& x) { return z_matching_listener_move(&x); }\ninline ze_moved_sample_miss_listener_t* z_move(ze_owned_sample_miss_listener_t& x) {\n    return ze_sample_miss_listener_move(&x);\n}\ninline z_moved_query_t* z_move(z_owned_query_t& x) { return z_query_move(&x); }\ninline z_moved_queryable_t* z_move(z_owned_queryable_t& x) { return z_queryable_move(&x); }\ninline z_moved_liveliness_token_t* z_move(z_owned_liveliness_token_t& x) { return z_liveliness_token_move(&x); }\ninline z_moved_reply_t* z_move(z_owned_reply_t& x) { return z_reply_move(&x); }\ninline z_moved_sample_t* z_move(z_owned_sample_t& x) { return z_sample_move(&x); }\ninline z_moved_session_t* z_move(z_owned_session_t& x) { return z_session_move(&x); }\ninline z_moved_slice_t* z_move(z_owned_slice_t& x) { return z_slice_move(&x); }\ninline z_moved_string_array_t* z_move(z_owned_string_array_t& x) { return z_string_array_move(&x); }\ninline z_moved_string_t* z_move(z_owned_string_t& x) { return z_string_move(&x); }\ninline z_moved_subscriber_t* z_move(z_owned_subscriber_t& x) { return z_subscriber_move(&x); }\ninline ze_moved_advanced_subscriber_t* z_move(ze_owned_advanced_subscriber_t& x) {\n    return ze_advanced_subscriber_move(&x);\n}\ninline z_moved_fifo_handler_query_t* z_move(z_owned_fifo_handler_query_t& x) { return z_fifo_handler_query_move(&x); }\ninline z_moved_fifo_handler_reply_t* z_move(z_owned_fifo_handler_reply_t& x) { return z_fifo_handler_reply_move(&x); }\ninline z_moved_fifo_handler_sample_t* z_move(z_owned_fifo_handler_sample_t& x) {\n    return z_fifo_handler_sample_move(&x);\n}\ninline z_moved_ring_handler_query_t* z_move(z_owned_ring_handler_query_t& x) { return z_ring_handler_query_move(&x); }\ninline z_moved_ring_handler_reply_t* z_move(z_owned_ring_handler_reply_t& x) { return z_ring_handler_reply_move(&x); }\ninline z_moved_ring_handler_sample_t* z_move(z_owned_ring_handler_sample_t& x) {\n    return z_ring_handler_sample_move(&x);\n}\ninline z_moved_bytes_writer_t* z_move(z_owned_bytes_writer_t& x) { return z_bytes_writer_move(&x); }\ninline ze_moved_serializer_t* z_move(ze_owned_serializer_t& x) { return ze_serializer_move(&x); }\ninline z_moved_cancellation_token_t* z_move(z_owned_cancellation_token_t& x) { return z_cancellation_token_move(&x); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline z_moved_transport_t* z_move(z_owned_transport_t& x) { return z_transport_move(&x); }\ninline z_moved_link_t* z_move(z_owned_link_t& x) { return z_link_move(&x); }\ninline z_moved_transport_event_t* z_move(z_owned_transport_event_t& x) { return z_transport_event_move(&x); }\ninline z_moved_link_event_t* z_move(z_owned_link_event_t& x) { return z_link_event_move(&x); }\ninline z_moved_transport_events_listener_t* z_move(z_owned_transport_events_listener_t& x) {\n    return z_transport_events_listener_move(&x);\n}\ninline z_moved_link_events_listener_t* z_move(z_owned_link_events_listener_t& x) {\n    return z_link_events_listener_move(&x);\n}\ninline z_moved_closure_transport_t* z_move(z_owned_closure_transport_t& x) { return z_closure_transport_move(&x); }\ninline z_moved_closure_link_t* z_move(z_owned_closure_link_t& x) { return z_closure_link_move(&x); }\ninline z_moved_closure_transport_event_t* z_move(z_owned_closure_transport_event_t& x) {\n    return z_closure_transport_event_move(&x);\n}\ninline z_moved_closure_link_event_t* z_move(z_owned_closure_link_event_t& x) { return z_closure_link_event_move(&x); }\n#endif\n\n// z_take definition\ninline void z_take(z_owned_session_t* this_, z_moved_session_t* v) { return z_session_take(this_, v); }\ninline void z_take(z_owned_publisher_t* this_, z_moved_publisher_t* v) { return z_publisher_take(this_, v); }\ninline void z_take(ze_owned_advanced_publisher_t* this_, ze_moved_advanced_publisher_t* v) {\n    return ze_advanced_publisher_take(this_, v);\n}\ninline void z_take(z_owned_querier_t* this_, z_moved_querier_t* v) { return z_querier_take(this_, v); }\ninline void z_take(z_owned_matching_listener_t* this_, z_moved_matching_listener_t* v) {\n    return z_matching_listener_take(this_, v);\n}\ninline void z_take(ze_owned_sample_miss_listener_t* this_, ze_moved_sample_miss_listener_t* v) {\n    return ze_sample_miss_listener_take(this_, v);\n}\ninline void z_take(z_owned_keyexpr_t* this_, z_moved_keyexpr_t* v) { z_keyexpr_take(this_, v); }\ninline void z_take(z_owned_config_t* this_, z_moved_config_t* v) { z_config_take(this_, v); }\ninline void z_take(z_owned_subscriber_t* this_, z_moved_subscriber_t* v) { return z_subscriber_take(this_, v); }\ninline void z_take(ze_owned_advanced_subscriber_t* this_, ze_moved_advanced_subscriber_t* v) {\n    return ze_advanced_subscriber_take(this_, v);\n}\ninline void z_take(z_owned_queryable_t* this_, z_moved_queryable_t* v) { return z_queryable_take(this_, v); }\ninline void z_take(z_owned_liveliness_token_t* this_, z_moved_liveliness_token_t* v) {\n    return z_liveliness_token_take(this_, v);\n}\ninline void z_take(z_owned_reply_t* this_, z_moved_reply_t* v) { z_reply_take(this_, v); }\ninline void z_take(z_owned_hello_t* this_, z_moved_hello_t* v) { z_hello_take(this_, v); }\ninline void z_take(z_owned_string_t* this_, z_moved_string_t* v) { z_string_take(this_, v); }\ninline void z_take(z_owned_slice_t* this_, z_moved_slice_t* v) { z_slice_take(this_, v); }\ninline void z_take(z_owned_string_array_t* this_, z_moved_string_array_t* v) { z_string_array_take(this_, v); }\ninline void z_take(z_owned_sample_t* this_, z_moved_sample_t* v) { z_sample_take(this_, v); }\ninline void z_take(z_owned_query_t* this_, z_moved_query_t* v) { z_query_take(this_, v); }\ninline void z_take(z_owned_bytes_t* this_, z_moved_bytes_t* v) { z_bytes_take(this_, v); }\ninline void z_take(z_owned_encoding_t* this_, z_moved_encoding_t* v) { z_encoding_take(this_, v); }\ninline void z_take(z_owned_mutex_t* this_, z_moved_mutex_t* v) { z_mutex_take(this_, v); }\ninline void z_take(z_owned_condvar_t* this_, z_moved_condvar_t* v) { z_condvar_take(this_, v); }\ninline void z_take(z_owned_reply_err_t* this_, z_moved_reply_err_t* v) { z_reply_err_take(this_, v); }\ninline void z_take(z_owned_closure_sample_t* this_, z_moved_closure_sample_t* v) { z_closure_sample_take(this_, v); }\ninline void z_take(z_owned_closure_query_t* this_, z_moved_closure_query_t* v) { z_closure_query_take(this_, v); }\ninline void z_take(z_owned_closure_reply_t* this_, z_moved_closure_reply_t* v) { z_closure_reply_take(this_, v); }\ninline void z_take(z_owned_closure_hello_t* this_, z_moved_closure_hello_t* v) { z_closure_hello_take(this_, v); }\ninline void z_take(z_owned_closure_zid_t* this_, z_moved_closure_zid_t* v) { z_closure_zid_take(this_, v); }\ninline void z_take(z_owned_closure_matching_status_t* this_, z_moved_closure_matching_status_t* v) {\n    z_closure_matching_status_take(this_, v);\n}\ninline void z_take(ze_owned_closure_miss_t* this_, ze_moved_closure_miss_t* v) { ze_closure_miss_take(this_, v); }\ninline void z_take(z_owned_ring_handler_sample_t* this_, z_moved_ring_handler_sample_t* v) {\n    z_ring_handler_sample_take(this_, v);\n}\ninline void z_take(z_owned_fifo_handler_sample_t* this_, z_moved_fifo_handler_sample_t* v) {\n    z_fifo_handler_sample_take(this_, v);\n}\ninline void z_take(z_owned_ring_handler_query_t* this_, z_moved_ring_handler_query_t* v) {\n    z_ring_handler_query_take(this_, v);\n}\ninline void z_take(z_owned_fifo_handler_query_t* this_, z_moved_fifo_handler_query_t* v) {\n    z_fifo_handler_query_take(this_, v);\n}\ninline void z_take(z_owned_ring_handler_reply_t* this_, z_moved_ring_handler_reply_t* v) {\n    z_ring_handler_reply_take(this_, v);\n}\ninline void z_take(z_owned_fifo_handler_reply_t* this_, z_moved_fifo_handler_reply_t* v) {\n    z_fifo_handler_reply_take(this_, v);\n}\ninline void z_take(z_owned_bytes_writer_t* this_, z_moved_bytes_writer_t* v) { z_bytes_writer_take(this_, v); }\ninline void z_take(ze_owned_serializer_t* this_, ze_moved_serializer_t* v) { ze_serializer_take(this_, v); }\ninline void z_take(z_owned_cancellation_token_t* this_, z_moved_cancellation_token_t* v) {\n    z_cancellation_token_take(this_, v);\n}\n#if Z_FEATURE_CONNECTIVITY == 1\ninline void z_take(z_owned_transport_t* this_, z_moved_transport_t* v) { z_transport_take(this_, v); }\ninline void z_take(z_owned_link_t* this_, z_moved_link_t* v) { z_link_take(this_, v); }\ninline void z_take(z_owned_transport_event_t* this_, z_moved_transport_event_t* v) { z_transport_event_take(this_, v); }\ninline void z_take(z_owned_link_event_t* this_, z_moved_link_event_t* v) { z_link_event_take(this_, v); }\ninline void z_take(z_owned_transport_events_listener_t* this_, z_moved_transport_events_listener_t* v) {\n    z_transport_events_listener_take(this_, v);\n}\ninline void z_take(z_owned_link_events_listener_t* this_, z_moved_link_events_listener_t* v) {\n    z_link_events_listener_take(this_, v);\n}\ninline void z_take(z_owned_closure_transport_t* this_, z_moved_closure_transport_t* v) {\n    z_closure_transport_take(this_, v);\n}\ninline void z_take(z_owned_closure_link_t* this_, z_moved_closure_link_t* v) { z_closure_link_take(this_, v); }\ninline void z_take(z_owned_closure_transport_event_t* this_, z_moved_closure_transport_event_t* v) {\n    z_closure_transport_event_take(this_, v);\n}\ninline void z_take(z_owned_closure_link_event_t* this_, z_moved_closure_link_event_t* v) {\n    z_closure_link_event_take(this_, v);\n}\n#endif\n\n// z_clone definition\ninline z_result_t z_clone(z_owned_bytes_t* dst, const z_loaned_bytes_t* this_) { return z_bytes_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_config_t* dst, const z_loaned_config_t* this_) { return z_config_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_encoding_t* dst, const z_loaned_encoding_t* this_) {\n    return z_encoding_clone(dst, this_);\n}\ninline z_result_t z_clone(z_owned_keyexpr_t* dst, const z_loaned_keyexpr_t* this_) {\n    return z_keyexpr_clone(dst, this_);\n}\ninline z_result_t z_clone(z_owned_query_t* dst, const z_loaned_query_t* this_) { return z_query_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_reply_t* dst, const z_loaned_reply_t* this_) { return z_reply_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_reply_err_t* dst, const z_loaned_reply_err_t* this_) {\n    return z_reply_err_clone(dst, this_);\n}\ninline z_result_t z_clone(z_owned_sample_t* dst, const z_loaned_sample_t* this_) { return z_sample_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_slice_t* dst, const z_loaned_slice_t* this_) { return z_slice_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_string_t* dst, const z_loaned_string_t* this_) { return z_string_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_string_array_t* dst, const z_loaned_string_array_t* this_) {\n    return z_string_array_clone(dst, this_);\n}\ninline z_result_t z_clone(z_owned_hello_t* dst, const z_loaned_hello_t* this_) { return z_hello_clone(dst, this_); }\n#if Z_FEATURE_CONNECTIVITY == 1\ninline z_result_t z_clone(z_owned_transport_t* dst, const z_loaned_transport_t* this_) {\n    return z_transport_clone(dst, this_);\n}\ninline z_result_t z_clone(z_owned_link_t* dst, const z_loaned_link_t* this_) { return z_link_clone(dst, this_); }\ninline z_result_t z_clone(z_owned_transport_event_t* dst, const z_loaned_transport_event_t* this_) {\n    return z_transport_event_clone(dst, this_);\n}\ninline z_result_t z_clone(z_owned_link_event_t* dst, const z_loaned_link_event_t* this_) {\n    return z_link_event_clone(dst, this_);\n}\n#endif\n\n// z_take_from_loaned definition\ninline z_result_t z_take_from_loaned(z_owned_bytes_t* dst, z_loaned_bytes_t* this_) {\n    return z_bytes_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_config_t* dst, z_loaned_config_t* this_) {\n    return z_config_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_encoding_t* dst, z_loaned_encoding_t* this_) {\n    return z_encoding_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_keyexpr_t* dst, z_loaned_keyexpr_t* this_) {\n    return z_keyexpr_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_query_t* dst, z_loaned_query_t* this_) {\n    return z_query_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_reply_t* dst, z_loaned_reply_t* this_) {\n    return z_reply_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_reply_err_t* dst, z_loaned_reply_err_t* this_) {\n    return z_reply_err_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_sample_t* dst, z_loaned_sample_t* this_) {\n    return z_sample_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_slice_t* dst, z_loaned_slice_t* this_) {\n    return z_slice_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_string_t* dst, z_loaned_string_t* this_) {\n    return z_string_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_string_array_t* dst, z_loaned_string_array_t* this_) {\n    return z_string_array_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_hello_t* dst, z_loaned_hello_t* this_) {\n    return z_hello_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_bytes_writer_t* dst, z_loaned_bytes_writer_t* this_) {\n    return z_bytes_writer_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(ze_owned_serializer_t* dst, ze_loaned_serializer_t* this_) {\n    return ze_serializer_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_cancellation_token_t* dst, z_loaned_cancellation_token_t* this_) {\n    return z_cancellation_token_take_from_loaned(dst, this_);\n}\n#if Z_FEATURE_CONNECTIVITY == 1\ninline z_result_t z_take_from_loaned(z_owned_transport_t* dst, z_loaned_transport_t* this_) {\n    return z_transport_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_link_t* dst, z_loaned_link_t* this_) {\n    return z_link_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_transport_event_t* dst, z_loaned_transport_event_t* this_) {\n    return z_transport_event_take_from_loaned(dst, this_);\n}\ninline z_result_t z_take_from_loaned(z_owned_link_event_t* dst, z_loaned_link_event_t* this_) {\n    return z_link_event_take_from_loaned(dst, this_);\n}\n#endif\n\ntemplate <class T>\nstruct z_loaned_to_owned_type_t {};\ntemplate <class T>\nstruct z_owned_to_loaned_type_t {};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_bytes_t> {\n    typedef z_owned_bytes_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_bytes_t> {\n    typedef z_loaned_bytes_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_config_t> {\n    typedef z_owned_config_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_config_t> {\n    typedef z_loaned_config_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_encoding_t> {\n    typedef z_owned_encoding_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_encoding_t> {\n    typedef z_loaned_encoding_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_reply_err_t> {\n    typedef z_owned_reply_err_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_reply_err_t> {\n    typedef z_loaned_reply_err_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_hello_t> {\n    typedef z_owned_hello_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_hello_t> {\n    typedef z_loaned_hello_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_keyexpr_t> {\n    typedef z_owned_keyexpr_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_keyexpr_t> {\n    typedef z_loaned_keyexpr_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_publisher_t> {\n    typedef z_owned_publisher_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_publisher_t> {\n    typedef z_loaned_publisher_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<ze_loaned_advanced_publisher_t> {\n    typedef ze_owned_advanced_publisher_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<ze_owned_advanced_publisher_t> {\n    typedef ze_loaned_advanced_publisher_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_querier_t> {\n    typedef z_owned_querier_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_querier_t> {\n    typedef z_loaned_querier_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_matching_listener_t> {\n    typedef z_owned_matching_listener_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_matching_listener_t> {\n    typedef z_loaned_matching_listener_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<ze_loaned_sample_miss_listener_t> {\n    typedef ze_owned_sample_miss_listener_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<ze_owned_sample_miss_listener_t> {\n    typedef ze_loaned_sample_miss_listener_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_query_t> {\n    typedef z_owned_query_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_query_t> {\n    typedef z_loaned_query_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_queryable_t> {\n    typedef z_owned_queryable_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_queryable_t> {\n    typedef z_loaned_queryable_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_liveliness_token_t> {\n    typedef z_owned_liveliness_token_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_liveliness_token_t> {\n    typedef z_loaned_liveliness_token_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_reply_t> {\n    typedef z_owned_reply_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_reply_t> {\n    typedef z_loaned_reply_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_sample_t> {\n    typedef z_owned_sample_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_sample_t> {\n    typedef z_loaned_sample_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_session_t> {\n    typedef z_owned_session_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_session_t> {\n    typedef z_loaned_session_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_slice_t> {\n    typedef z_owned_slice_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_slice_t> {\n    typedef z_loaned_slice_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_string_array_t> {\n    typedef z_owned_string_array_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_string_array_t> {\n    typedef z_loaned_string_array_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_string_t> {\n    typedef z_owned_string_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_string_t> {\n    typedef z_loaned_string_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_subscriber_t> {\n    typedef z_owned_subscriber_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_subscriber_t> {\n    typedef z_loaned_subscriber_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<ze_loaned_advanced_subscriber_t> {\n    typedef ze_owned_advanced_subscriber_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<ze_owned_advanced_subscriber_t> {\n    typedef ze_loaned_advanced_subscriber_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_sample_t> {\n    typedef z_loaned_closure_sample_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_sample_t> {\n    typedef z_owned_closure_sample_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_reply_t> {\n    typedef z_loaned_closure_reply_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_reply_t> {\n    typedef z_owned_closure_reply_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_query_t> {\n    typedef z_loaned_closure_query_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_query_t> {\n    typedef z_owned_closure_query_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_hello_t> {\n    typedef z_loaned_closure_hello_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_hello_t> {\n    typedef z_owned_closure_hello_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_zid_t> {\n    typedef z_loaned_closure_zid_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_zid_t> {\n    typedef z_owned_closure_zid_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_matching_status_t> {\n    typedef z_loaned_closure_matching_status_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_matching_status_t> {\n    typedef z_owned_closure_matching_status_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<ze_owned_closure_miss_t> {\n    typedef ze_loaned_closure_miss_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<ze_loaned_closure_miss_t> {\n    typedef ze_owned_closure_miss_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_fifo_handler_query_t> {\n    typedef z_owned_fifo_handler_query_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_fifo_handler_query_t> {\n    typedef z_loaned_fifo_handler_query_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_fifo_handler_reply_t> {\n    typedef z_owned_fifo_handler_reply_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_fifo_handler_reply_t> {\n    typedef z_loaned_fifo_handler_reply_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_fifo_handler_sample_t> {\n    typedef z_owned_fifo_handler_sample_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_fifo_handler_sample_t> {\n    typedef z_loaned_fifo_handler_sample_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_ring_handler_query_t> {\n    typedef z_owned_ring_handler_query_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_ring_handler_query_t> {\n    typedef z_loaned_ring_handler_query_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_ring_handler_reply_t> {\n    typedef z_owned_ring_handler_reply_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_ring_handler_reply_t> {\n    typedef z_loaned_ring_handler_reply_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_ring_handler_sample_t> {\n    typedef z_owned_ring_handler_sample_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_ring_handler_sample_t> {\n    typedef z_loaned_ring_handler_sample_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_bytes_writer_t> {\n    typedef z_owned_bytes_writer_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_bytes_writer_t> {\n    typedef z_loaned_bytes_writer_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<ze_loaned_serializer_t> {\n    typedef ze_owned_serializer_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<ze_owned_serializer_t> {\n    typedef ze_loaned_serializer_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_cancellation_token_t> {\n    typedef z_owned_cancellation_token_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_cancellation_token_t> {\n    typedef z_loaned_cancellation_token_t type;\n};\n\n#if Z_FEATURE_CONNECTIVITY == 1\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_transport_t> {\n    typedef z_owned_transport_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_transport_t> {\n    typedef z_loaned_transport_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_link_t> {\n    typedef z_owned_link_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_link_t> {\n    typedef z_loaned_link_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_transport_event_t> {\n    typedef z_owned_transport_event_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_transport_event_t> {\n    typedef z_loaned_transport_event_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_link_event_t> {\n    typedef z_owned_link_event_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_link_event_t> {\n    typedef z_loaned_link_event_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_transport_events_listener_t> {\n    typedef z_owned_transport_events_listener_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_transport_events_listener_t> {\n    typedef z_loaned_transport_events_listener_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_link_events_listener_t> {\n    typedef z_owned_link_events_listener_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_link_events_listener_t> {\n    typedef z_loaned_link_events_listener_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_transport_t> {\n    typedef z_owned_closure_transport_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_transport_t> {\n    typedef z_loaned_closure_transport_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_link_t> {\n    typedef z_owned_closure_link_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_link_t> {\n    typedef z_loaned_closure_link_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_transport_event_t> {\n    typedef z_owned_closure_transport_event_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_transport_event_t> {\n    typedef z_loaned_closure_transport_event_t type;\n};\ntemplate <>\nstruct z_loaned_to_owned_type_t<z_loaned_closure_link_event_t> {\n    typedef z_owned_closure_link_event_t type;\n};\ntemplate <>\nstruct z_owned_to_loaned_type_t<z_owned_closure_link_event_t> {\n    typedef z_loaned_closure_link_event_t type;\n};\n#endif\n\n#endif\n\n#endif /* ZENOH_C_STANDARD != 99 */\n\n#endif /* ZENOH_PICO_API_MACROS_H */\n"
  },
  {
    "path": "include/zenoh-pico/api/olv_macros.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef INCLUDE_ZENOH_PICO_API_OLV_MACROS_H\n#define INCLUDE_ZENOH_PICO_API_OLV_MACROS_H\n\n// Gets internal value from refcounted type (e.g. z_loaned_session_t, z_query_t)\n#define _Z_RC_IN_VAL(arg) ((arg)->_val)\n\n// Checks if refcounted type is initialized\n#define _Z_RC_IS_NULL(arg) ((arg)->_cnt == NULL)\n\n// Gets internal value from refcounted owned type (e.g. z_owned_session_t, z_owned_query_t)\n#define _Z_OWNED_RC_IN_VAL(arg) ((arg)->_rc._val)\n\n// Checks if simple refcounted type is initialized\n#define _Z_SIMPLE_RC_IS_NULL(arg) ((arg)->_val == NULL)\n\n// Owned/Loaned/View type macros\n//\n// !!! FOR INTERNAL USAGE ONLY !!!\n\n#define _Z_MOVED_TYPE_PREFIX(prefix, name) \\\n    typedef struct {                       \\\n        prefix##_owned_##name##_t _this;   \\\n    } prefix##_moved_##name##_t;\n\n#define _Z_LOANED_TYPE_PREFIX(prefix, type, name) typedef type prefix##_loaned_##name##_t;\n\n// For value types\n#define _Z_OWNED_TYPE_VALUE_PREFIX(prefix, type, name) \\\n    typedef struct {                                   \\\n        type _val;                                     \\\n    } prefix##_owned_##name##_t;                       \\\n    _Z_LOANED_TYPE_PREFIX(prefix, type, name)          \\\n    _Z_MOVED_TYPE_PREFIX(prefix, name)\n\n#define _Z_OWNED_TYPE_VALUE(type, name) _Z_OWNED_TYPE_VALUE_PREFIX(z, type, name)\n\n// For refcounted types\n#define _Z_OWNED_TYPE_RC_PREFIX(prefix, type, name) \\\n    typedef struct {                                \\\n        type _rc;                                   \\\n    } prefix##_owned_##name##_t;                    \\\n    _Z_LOANED_TYPE_PREFIX(prefix, type, name)       \\\n    _Z_MOVED_TYPE_PREFIX(prefix, name)\n\n#define _Z_OWNED_TYPE_RC(type, name) _Z_OWNED_TYPE_RC_PREFIX(z, type, name)\n\n#define _Z_VIEW_TYPE(type, name) \\\n    typedef struct {             \\\n        type _val;               \\\n    } z_view_##name##_t;\n\n#define _Z_OWNED_FUNCTIONS_NO_COPY_NO_TAKE_FROM_LOANED_DEF_PREFIX(prefix, name)                     \\\n    void prefix##_internal_##name##_null(prefix##_owned_##name##_t *obj);                           \\\n    bool prefix##_internal_##name##_check(const prefix##_owned_##name##_t *obj);                    \\\n    const prefix##_loaned_##name##_t *prefix##_##name##_loan(const prefix##_owned_##name##_t *obj); \\\n    prefix##_loaned_##name##_t *prefix##_##name##_loan_mut(prefix##_owned_##name##_t *obj);         \\\n    prefix##_moved_##name##_t *prefix##_##name##_move(prefix##_owned_##name##_t *obj);              \\\n    void prefix##_##name##_take(prefix##_owned_##name##_t *obj, prefix##_moved_##name##_t *src);    \\\n    void prefix##_##name##_drop(prefix##_moved_##name##_t *obj);\n\n#define _Z_OWNED_FUNCTIONS_NO_COPY_DEF_PREFIX(prefix, name)                 \\\n    _Z_OWNED_FUNCTIONS_NO_COPY_NO_TAKE_FROM_LOANED_DEF_PREFIX(prefix, name) \\\n    z_result_t prefix##_##name##_take_from_loaned(prefix##_owned_##name##_t *dst, prefix##_loaned_##name##_t *src);\n\n#define _Z_OWNED_FUNCTIONS_DEF_PREFIX(prefix, name)     \\\n    _Z_OWNED_FUNCTIONS_NO_COPY_DEF_PREFIX(prefix, name) \\\n    z_result_t prefix##_##name##_clone(prefix##_owned_##name##_t *obj, const prefix##_loaned_##name##_t *src);\n\n#define _Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(name) _Z_OWNED_FUNCTIONS_NO_COPY_NO_TAKE_FROM_LOANED_DEF_PREFIX(z, name)\n#define _Z_OWNED_FUNCTIONS_NO_COPY_DEF(name) _Z_OWNED_FUNCTIONS_NO_COPY_DEF_PREFIX(z, name)\n#define _Z_OWNED_FUNCTIONS_DEF(name) _Z_OWNED_FUNCTIONS_DEF_PREFIX(z, name)\n\n#define _Z_OWNED_FUNCTIONS_SYSTEM_DEF(name)                                    \\\n    void z_internal_##name##_null(z_owned_##name##_t *obj);                    \\\n    void z_##name##_take(z_owned_##name##_t *obj, z_moved_##name##_t *src);    \\\n    const z_loaned_##name##_t *z_##name##_loan(const z_owned_##name##_t *obj); \\\n    z_loaned_##name##_t *z_##name##_loan_mut(z_owned_##name##_t *obj);         \\\n    z_moved_##name##_t *z_##name##_move(z_owned_##name##_t *obj);\n\n#define _Z_VIEW_FUNCTIONS_DEF(name)                                                 \\\n    bool z_view_##name##_is_empty(const z_view_##name##_t *obj);                    \\\n    const z_loaned_##name##_t *z_view_##name##_loan(const z_view_##name##_t *name); \\\n    z_loaned_##name##_t *z_view_##name##_loan_mut(z_view_##name##_t *name);         \\\n    void z_view_##name##_empty(z_view_##name##_t *name);\n\n#define _ZP_NOTHING\n\n#define _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX_INNER(prefix, name, attribute)                             \\\n    attribute prefix##_moved_##name##_t *prefix##_##name##_move(prefix##_owned_##name##_t *obj) {           \\\n        return (prefix##_moved_##name##_t *)(obj);                                                          \\\n    }                                                                                                       \\\n    attribute void prefix##_##name##_take(prefix##_owned_##name##_t *obj, prefix##_moved_##name##_t *src) { \\\n        *obj = src->_this;                                                                                  \\\n        prefix##_internal_##name##_null(&src->_this);                                                       \\\n    }\n\n#define _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE(name) _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX_INNER(z, name, _ZP_NOTHING)\n\n#define _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX(prefix, name) \\\n    _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX_INNER(prefix, name, _ZP_NOTHING)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_drop, \\\n                                                                   attribute)                                   \\\n    attribute void prefix##_internal_##name##_null(prefix##_owned_##name##_t *obj) { obj->_val = f_null(); }    \\\n    _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX_INNER(prefix, name, attribute)                                     \\\n    attribute bool prefix##_internal_##name##_check(const prefix##_owned_##name##_t *obj) {                     \\\n        return f_check((&obj->_val));                                                                           \\\n    }                                                                                                           \\\n    attribute const prefix##_loaned_##name##_t *prefix##_##name##_loan(const prefix##_owned_##name##_t *obj) {  \\\n        return &obj->_val;                                                                                      \\\n    }                                                                                                           \\\n    attribute prefix##_loaned_##name##_t *prefix##_##name##_loan_mut(prefix##_owned_##name##_t *obj) {          \\\n        return &obj->_val;                                                                                      \\\n    }                                                                                                           \\\n    attribute void prefix##_##name##_drop(prefix##_moved_##name##_t *obj) {                                     \\\n        if (obj != NULL) f_drop((&obj->_this._val));                                                            \\\n    }\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_move, f_drop,        \\\n                                                           attribute)                                                  \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_drop, attribute) \\\n    attribute z_result_t prefix##_##name##_take_from_loaned(prefix##_owned_##name##_t *obj,                            \\\n                                                            prefix##_loaned_##name##_t *src) {                         \\\n        return f_move((&obj->_val), src);                                                                              \\\n    }\n\n#define _Z_OWNED_FUNCTIONS_VALUE_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_copy, f_move, f_drop,        \\\n                                                   attribute)                                                          \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_move, f_drop, attribute) \\\n    attribute z_result_t prefix##_##name##_clone(prefix##_owned_##name##_t *obj,                                       \\\n                                                 const prefix##_loaned_##name##_t *src) {                              \\\n        return f_copy((&obj->_val), src);                                                                              \\\n    }\n\n#define _Z_OWNED_FUNCTIONS_VALUE_IMP_PREFIX(prefix, type, name, f_check, f_null, f_copy, f_move, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_IMPL_PREFIX_INNER(z, type, name, f_check, f_null, f_copy, f_move, f_drop, _ZP_NOTHING)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX(prefix, type, name, f_check, f_null, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_drop, _ZP_NOTHING)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX(prefix, type, name, f_check, f_null, f_move, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX_INNER(prefix, type, name, f_check, f_null, f_move, f_drop, _ZP_NOTHING)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(type, name, f_check, f_null, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX(z, type, name, f_check, f_null, f_drop)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL(type, name, f_check, f_null, f_move, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX(z, type, name, f_check, f_null, f_move, f_drop)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_IMPL(type, name, f_check, f_null, f_copy, f_move, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_IMP_PREFIX(z, type, name, f_check, f_null, f_copy, f_move, f_drop)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_INLINE_IMPL(type, name, f_check, f_null, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX_INNER(z, type, name, f_check, f_null, f_drop, static inline)\n\n#define _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_INLINE_IMPL(type, name, f_check, f_null, f_move, f_drop) \\\n    _Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX_INNER(z, type, name, f_check, f_null, f_move, f_drop, static inline)\n\n#define _Z_OWNED_FUNCTIONS_RC_IMPL_CLONE_DROP_INNER(name, attribute)                                 \\\n    attribute z_result_t z_##name##_clone(z_owned_##name##_t *obj, const z_loaned_##name##_t *src) { \\\n        z_result_t ret = _Z_RES_OK;                                                                  \\\n        obj->_rc = _z_##name##_rc_clone((z_loaned_##name##_t *)src);                                 \\\n        if (_Z_RC_IS_NULL(&obj->_rc)) {                                                              \\\n            _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);                                               \\\n            ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;                                                       \\\n        }                                                                                            \\\n        return ret;                                                                                  \\\n    }                                                                                                \\\n    attribute void z_##name##_drop(z_moved_##name##_t *obj) {                                        \\\n        if (obj != NULL && !_Z_RC_IS_NULL(&obj->_this._rc)) {                                        \\\n            _z_##name##_rc_drop(&obj->_this._rc);                                                    \\\n        }                                                                                            \\\n    }\n\n#define _Z_OWNED_FUNCTIONS_RC_IMPL_NULL_CHECK_LOAN_INNER(name, attribute)                                         \\\n    attribute void z_internal_##name##_null(z_owned_##name##_t *val) { val->_rc = _z_##name##_rc_null(); }        \\\n    attribute bool z_internal_##name##_check(const z_owned_##name##_t *val) { return !_Z_RC_IS_NULL(&val->_rc); } \\\n    attribute const z_loaned_##name##_t *z_##name##_loan(const z_owned_##name##_t *val) { return &val->_rc; }     \\\n    attribute z_loaned_##name##_t *z_##name##_loan_mut(z_owned_##name##_t *val) { return &val->_rc; }\n\n#define _Z_OWNED_FUNCTIONS_RC_IMPL_INNER(name, attribute)             \\\n    _Z_OWNED_FUNCTIONS_RC_IMPL_NULL_CHECK_LOAN_INNER(name, attribute) \\\n    _Z_OWNED_FUNCTIONS_RC_IMPL_CLONE_DROP_INNER(name, attribute)      \\\n    _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX_INNER(z, name, attribute)\n\n#define _Z_OWNED_FUNCTIONS_RC_IMPL_NO_DROP_CLONE_INNER(name, attribute) \\\n    _Z_OWNED_FUNCTIONS_RC_IMPL_NULL_CHECK_LOAN_INNER(name, attribute)   \\\n    _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX_INNER(z, name, attribute)\n\n#define _Z_OWNED_FUNCTIONS_RC_IMPL(name) _Z_OWNED_FUNCTIONS_RC_IMPL_INNER(name, _ZP_NOTHING)\n#define _Z_OWNED_FUNCTIONS_RC_INLINE_IMPL(name) _Z_OWNED_FUNCTIONS_RC_IMPL_INNER(name, static inline)\n\n#define _Z_OWNED_FUNCTIONS_RC_IMPL_NO_DROP_CLONE(name) _Z_OWNED_FUNCTIONS_RC_IMPL_NO_DROP_CLONE_INNER(name, _ZP_NOTHING)\n\n#define _Z_OWNED_FUNCTIONS_SYSTEM_IMPL(type, name)                                                   \\\n    _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE(name)                                                          \\\n    void z_internal_##name##_null(z_owned_##name##_t *obj) { (void)obj; }                            \\\n    const z_loaned_##name##_t *z_##name##_loan(const z_owned_##name##_t *obj) { return &obj->_val; } \\\n    z_loaned_##name##_t *z_##name##_loan_mut(z_owned_##name##_t *obj) { return &obj->_val; }\n\n#define _Z_VIEW_FUNCTIONS_IMPL(type, name, f_check, f_null)                                              \\\n    bool z_view_##name##_is_empty(const z_view_##name##_t *obj) { return !f_check((&obj->_val)); }       \\\n    const z_loaned_##name##_t *z_view_##name##_loan(const z_view_##name##_t *obj) { return &obj->_val; } \\\n    z_loaned_##name##_t *z_view_##name##_loan_mut(z_view_##name##_t *obj) { return &obj->_val; }         \\\n    void z_view_##name##_empty(z_view_##name##_t *obj) { obj->_val = f_null(); }\n\n#define _Z_OWNED_FUNCTIONS_CLOSURE_DEF_PREFIX(prefix, name)                                      \\\n    void prefix##_internal_##name##_null(prefix##_owned_##name##_t *name);                       \\\n    bool prefix##_internal_##name##_check(const prefix##_owned_##name##_t *val);                 \\\n    prefix##_moved_##name##_t *prefix##_##name##_move(prefix##_owned_##name##_t *val);           \\\n    void prefix##_##name##_take(prefix##_owned_##name##_t *obj, prefix##_moved_##name##_t *src); \\\n    void prefix##_##name##_drop(prefix##_moved_##name##_t *obj);                                 \\\n    const prefix##_loaned_##name##_t *prefix##_##name##_loan(const prefix##_owned_##name##_t *val);\n\n#define _Z_OWNED_FUNCTIONS_CLOSURE_DEF(name) _Z_OWNED_FUNCTIONS_CLOSURE_DEF_PREFIX(z, name)\n\n// For value types\n#define _Z_OWNED_TYPE_VALUE_PREFIX(prefix, type, name) \\\n    typedef struct {                                   \\\n        type _val;                                     \\\n    } prefix##_owned_##name##_t;                       \\\n    _Z_LOANED_TYPE_PREFIX(prefix, type, name)          \\\n    _Z_MOVED_TYPE_PREFIX(prefix, name)\n\n#define _Z_OWNED_FUNCTIONS_CLOSURE_IMPL_PREFIX(prefix, name, f_call, f_drop)                                       \\\n    _Z_OWNED_FUNCTIONS_IMPL_MOVE_TAKE_PREFIX(prefix, name)                                                         \\\n    void prefix##_internal_##name##_null(prefix##_owned_##name##_t *val) {                                         \\\n        val->_val.call = NULL;                                                                                     \\\n        val->_val.drop = NULL;                                                                                     \\\n        val->_val.context = NULL;                                                                                  \\\n    }                                                                                                              \\\n    bool prefix##_internal_##name##_check(const prefix##_owned_##name##_t *val) { return val->_val.call != NULL; } \\\n    void prefix##_##name##_drop(prefix##_moved_##name##_t *obj) {                                                  \\\n        if (obj->_this._val.drop != NULL) {                                                                        \\\n            (obj->_this._val.drop)(obj->_this._val.context);                                                       \\\n            obj->_this._val.drop = NULL;                                                                           \\\n        }                                                                                                          \\\n        obj->_this._val.call = NULL;                                                                               \\\n        obj->_this._val.context = NULL;                                                                            \\\n    }                                                                                                              \\\n    const prefix##_loaned_##name##_t *prefix##_##name##_loan(const prefix##_owned_##name##_t *val) {               \\\n        return &val->_val;                                                                                         \\\n    }                                                                                                              \\\n    z_result_t prefix##_##name(prefix##_owned_##name##_t *closure, f_call call, f_drop drop, void *context) {      \\\n        closure->_val.call = call;                                                                                 \\\n        closure->_val.drop = drop;                                                                                 \\\n        closure->_val.context = context;                                                                           \\\n                                                                                                                   \\\n        return _Z_RES_OK;                                                                                          \\\n    }\n\n#define _Z_OWNED_FUNCTIONS_CLOSURE_IMPL(name, f_call, f_drop) \\\n    _Z_OWNED_FUNCTIONS_CLOSURE_IMPL_PREFIX(z, name, f_call, f_drop)\n\n#endif /* INCLUDE_ZENOH_PICO_API_OLV_MACROS_H */\n"
  },
  {
    "path": "include/zenoh-pico/api/primitives.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_API_PRIMITIVES_H\n#define INCLUDE_ZENOH_PICO_API_PRIMITIVES_H\n\n#ifndef SPHINX_DOCS\n// For some reason sphinx/clang doesn't handle bool types correctly if stdbool.h is included\n#include <stdbool.h>\n#endif\n#include <stdint.h>\n\n#include \"olv_macros.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/advanced_cache.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/net/subscribe.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Builds a :c:type:`z_view_string_t` by wrapping a ``const char *`` string.\n *\n * Parameters:\n *   str: Pointer to an uninitialized :c:type:`z_view_string_t`.\n *   value: Pointer to a null terminated string.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_view_string_from_str(z_view_string_t *str, const char *value);\n\n/**\n * Builds a :c:type:`z_view_string_t` by wrapping a ``const char *`` substring.\n *\n * Parameters:\n *   str: Pointer to an uninitialized :c:type:`z_view_string_t`.\n *   value: Pointer to a null terminated string.\n *   len: Size of the string.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_view_string_from_substr(z_view_string_t *str, const char *value, size_t len);\n\n/**\n * Builds a :c:type:`z_keyexpr_t` from a null-terminated string.\n * It is a loaned key expression that aliases ``name``.\n * This function will fail if the string is not in canon form.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_view_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr as a null terminated string.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_view_keyexpr_from_str(z_view_keyexpr_t *keyexpr, const char *name);\n\n/**\n * Builds a :c:type:`z_keyexpr_t` from a null-terminated string.\n * It is a loaned key expression that aliases ``name``.\n * Input key expression is not checked for correctness.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_view_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr as a null terminated string.\n */\nvoid z_view_keyexpr_from_str_unchecked(z_view_keyexpr_t *keyexpr, const char *name);\n\n/**\n * Builds a :c:type:`z_view_keyexpr_t` from a null-terminated string with auto canonization.\n * It is a loaned key expression that aliases ``name``.\n * The string is canonized in-place before being passed to keyexpr, possibly shortening it by modifying len.\n * May SEGFAULT if `name` is NULL or lies in read-only memory (as values initialized with string literals do).\n * `name` must outlive the constructed key expression.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_view_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr as a null terminated string.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_view_keyexpr_from_str_autocanonize(z_view_keyexpr_t *keyexpr, char *name);\n\n/**\n * Builds a :c:type:`z_keyexpr_t` by aliasing a substring.\n * It is a loaned key expression that aliases ``name``.\n * This function will fail if the string is not in canon form.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_view_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr.\n *   len: Size of the string.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_view_keyexpr_from_substr(z_view_keyexpr_t *keyexpr, const char *name, size_t len);\n\n/**\n * Builds a :c:type:`z_view_keyexpr_t` from a substring with auto canonization.\n * It is a loaned key expression that aliases ``name``.\n * The string is canonized in-place before being passed to keyexpr, possibly shortening it by modifying len.\n * May SEGFAULT if `name` is NULL or lies in read-only memory (as values initialized with string literals do).\n * `name` must outlive the constructed key expression.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_view_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr.\n *   len: Pointer to the size of the string.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_view_keyexpr_from_substr_autocanonize(z_view_keyexpr_t *keyexpr, char *name, size_t *len);\n\n/**\n * Builds a :c:type:`z_keyexpr_t` from a substring.\n * It is a loaned key expression that aliases ``name``.\n * Input key expression is not checked for correctness.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_view_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr.\n *   len: Size of the string.\n */\nvoid z_view_keyexpr_from_substr_unchecked(z_view_keyexpr_t *keyexpr, const char *name, size_t len);\n\n/**\n * Gets a string view from a :c:type:`z_keyexpr_t`.\n *\n * Parameters:\n *   keyexpr: Pointer to a loaned instance of :c:type:`z_keyexpr_t`.\n *   str: Pointer to an uninitialized :c:type:`z_view_string_t`.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_as_view_string(const z_loaned_keyexpr_t *keyexpr, z_view_string_t *str);\n\n/**\n * Constructs key expression by concatenation of key expression in `left` with a string in `right`.\n *\n * To avoid odd behaviors, concatenating a key expression starting with `*` to one ending with `*` is forbidden by this\n * operation, as this would extremely likely cause bugs.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t` to store the keyexpr.\n *   left: Pointer to :c:type:`z_loaned_keyexpr_t` to keyexpr to concatenate to.\n *   right: Pointer to the start of the substring that will be concatenated.\n *   len: Length of the substring to concatenate.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_concat(z_owned_keyexpr_t *key, const z_loaned_keyexpr_t *left, const char *right, size_t len);\n\n/**\n * Constructs key expression by performing path-joining (automatically inserting '/'). The resulting key expression is\n * automatically canonized.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t` to store the keyexpr.\n *   left: Pointer to :c:type:`z_loaned_keyexpr_t` to the left part of the resulting key expression.\n *   right: Pointer to :c:type:`z_loaned_keyexpr_t` to the right part of the resulting key expression.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_join(z_owned_keyexpr_t *key, const z_loaned_keyexpr_t *left, const z_loaned_keyexpr_t *right);\n\n/**\n * Appends the suffix portion of a key expression to another key expression (automatically inserting '/').\n *\n * Only the suffix portion of the key expression is preserved. All other components of the resulting key\n * expression will be discarded.\n * The resulting key expression is automatically canonized.\n *\n * Parameters:\n *   prefix: Pointer to :c:type:`z_owned_keyexpr_t` to the key expression to append to.\n *   right: Pointer to :c:type:`z_loaned_keyexpr_t` whose suffix will be appended.\n *\n * Return:\n *   ``0`` if the append was successful; a ``negative value`` otherwise.\n */\nz_result_t _z_keyexpr_append_suffix(z_owned_keyexpr_t *prefix, const z_loaned_keyexpr_t *right);\n\n/**\n * Appends a string segment to a key expression (automatically inserting '/'). The resulting key expression is\n * automatically canonized.\n *\n * Parameters:\n *   prefix: Pointer to :c:type:`z_owned_keyexpr_t` to the key expression to append to.\n *   right: Pointer to a character array representing the string to append.\n *   len: Length of the string segment in ``right`` to append.\n *\n * Return:\n *   ``0`` if append successful, ``negative value`` otherwise.\n */\nz_result_t _z_keyexpr_append_substr(z_owned_keyexpr_t *prefix, const char *right, size_t len);\n\n/**\n * Appends a null-terminated string to a key expression (automatically inserting '/'). The resulting key expression is\n * automatically canonized.\n *\n * Parameters:\n *   prefix: Pointer to :c:type:`z_owned_keyexpr_t` to the key expression to append to.\n *   right: Pointer to a null-terminated string to append.\n *\n * Return:\n *   ``0`` if append successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t _z_keyexpr_append_str(z_owned_keyexpr_t *prefix, const char *right) {\n    // SAFETY: right is documented to be null-terminated.\n    // Flawfinder: ignore [CWE-126]\n    return _z_keyexpr_append_substr(prefix, right, right ? strlen(right) : 0);\n}\n\n/**\n * Appends multiple null-terminated strings to a key expression (automatically inserting '/' between each component).\n * The resulting key expression is automatically canonized.\n *\n * Parameters:\n *   prefix: Pointer to :c:type:`z_owned_keyexpr_t` representing the key expression to append to.\n *   strs: Array of ``count`` null-terminated strings to append, in order.\n *   count: Number of strings in the array.\n *\n * Return:\n *   ``0`` if all appends were successful, ``negative value`` if any append failed.\n */\nz_result_t _z_keyexpr_append_str_array(z_owned_keyexpr_t *prefix, const char *strs[], size_t count);\n\n#define _Z_KEYEXPR_APPEND_STR_ARRAY(prefix, ...)                       \\\n    _z_keyexpr_append_str_array(prefix, (const char *[]){__VA_ARGS__}, \\\n                                sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *))\n\n/**\n * Returns the relation between `left` and `right` from the `left`'s point of view.\n *\n * Note that this is slower than `z_keyexpr_intersects` and `keyexpr_includes`, so you should favor these methods for\n * most applications.\n *\n * Parameters:\n *   left: Pointer to :c:type:`z_loaned_keyexpr_t` representing left key expression.\n *   right: Pointer to :c:type:`z_loaned_keyexpr_t` representing right key expression.\n *\n * Return:\n *   Relation between `left` and `right` from the `left`'s point of view.\n */\nz_keyexpr_intersection_level_t z_keyexpr_relation_to(const z_loaned_keyexpr_t *left, const z_loaned_keyexpr_t *right);\n\n/**\n * Checks if a given keyexpr is valid and in canonical form.\n *\n * Parameters:\n *   start: Pointer to the keyexpr in its string representation as a non-null terminated string.\n *   len: Number of characters in ``start``.\n *\n * Return:\n *   ``0`` if the passed string is a valid (and canon) key expression, or a ``negative value`` otherwise.\n *   Error codes are defined in :c:enum:`zp_keyexpr_canon_status_t`.\n */\nz_result_t z_keyexpr_is_canon(const char *start, size_t len);\n\n/**\n * Canonizes of a given keyexpr in string representation.\n * The canonization is performed over the passed string, possibly shortening it by modifying ``len``.\n *\n * Parameters:\n *   start: Pointer to the keyexpr in its string representation as a non-null terminated string.\n *   len: Number of characters in ``start``.\n *\n * Return:\n *   ``0`` if canonization successful, or a ``negative value`` otherwise.\n *   Error codes are defined in :c:enum:`zp_keyexpr_canon_status_t`.\n */\nz_result_t z_keyexpr_canonize(char *start, size_t *len);\n\n/**\n * Canonizes of a given keyexpr in string representation.\n * The canonization is performed over the passed string, possibly shortening it by setting null at the end.\n *\n * Parameters:\n *   start: Pointer to the keyexpr in its string representation as a null terminated string.\n *\n * Return:\n *   ``0`` if canonization successful, or a ``negative value`` otherwise.\n *   Error codes are defined in :c:enum:`zp_keyexpr_canon_status_t`.\n */\nz_result_t z_keyexpr_canonize_null_terminated(char *start);\n\n/**\n * Checks if a given keyexpr contains another keyexpr in its set.\n *\n * Parameters:\n *   l: Pointer to a :c:type:`z_loaned_keyexpr_t`.\n *   r: Pointer to a :c:type:`z_loaned_keyexpr_t`.\n *\n * Return:\n *   ``true`` if ``l`` includes ``r``, i.e. the set defined by ``l`` contains every key belonging to the set\n *   defined by ``r``. Otherwise, returns ``false``.\n */\nbool z_keyexpr_includes(const z_loaned_keyexpr_t *l, const z_loaned_keyexpr_t *r);\n\n/**\n * Checks if a given keyexpr intersects with another keyexpr.\n *\n * Parameters:\n *   l: Pointer to a :c:type:`z_loaned_keyexpr_t`.\n *   r: Pointer to a :c:type:`z_loaned_keyexpr_t`.\n *\n * Return:\n *   ``true`` if keyexprs intersect, i.e. there exists at least one key which is contained in both of the\n *   sets defined by ``l`` and ``r``. Otherwise, returns ``false``.\n */\nbool z_keyexpr_intersects(const z_loaned_keyexpr_t *l, const z_loaned_keyexpr_t *r);\n\n/**\n * Checks if two keyexpr are equal.\n *\n * Parameters:\n *   l: Pointer to a :c:type:`z_loaned_keyexpr_t`.\n *   r: Pointer to a :c:type:`z_loaned_keyexpr_t`.\n *\n * Return:\n *   ``true`` if both ``l`` and ``r`` are equal. Otherwise, returns  ``false``.\n */\nbool z_keyexpr_equals(const z_loaned_keyexpr_t *l, const z_loaned_keyexpr_t *r);\n\n/**\n * Builds a new, zenoh-allocated, default configuration.\n * It consists in a default set of properties for zenoh session configuration.\n *\n * Parameters:\n *   config: Pointer to uninitialized :c:type:`z_owned_config_t`.\n *\n * Return:\n *   ``0`` in case of success, or a ``negative value`` otherwise.\n */\nz_result_t z_config_default(z_owned_config_t *config);\n\n/**\n * Gets the property with the given integer key from the configuration.\n *\n * Parameters:\n *   config: Pointer to a :c:type:`z_loaned_config_t` to get the property from.\n *   key: Integer key of the requested property.\n *\n * Return:\n *   The requested property value.\n */\nconst char *zp_config_get(const z_loaned_config_t *config, uint8_t key);\n\n/**\n * Inserts or replaces the property with the given integer key in the configuration.\n *\n * Parameters:\n *   config: Pointer to a :c:type:`z_loaned_config_t` to modify.\n *   key: Integer key of the property to be inserted.\n *   value: Property value to be inserted.\n *\n * Return:\n *   ``0`` if insertion is successful, ``negative value`` otherwise.\n */\nz_result_t zp_config_insert(z_loaned_config_t *config, uint8_t key, const char *value);\n\n/**\n * Builds a :c:type:`z_owned_encoding_t` from a null terminated string.\n *\n * Parameters:\n *   encoding: Pointer to an uninitialized :c:type:`z_owned_encoding_t`.\n *   s: Pointer to the null terminated string to use.\n *\n * Return:\n *   ``0`` if creation is successful,``negative value`` otherwise.\n */\nz_result_t z_encoding_from_str(z_owned_encoding_t *encoding, const char *s);\n\n/**\n * Builds a :c:type:`z_owned_encoding_t` from a null terminated string.\n *\n * Parameters:\n *   encoding: Pointer to an uninitialized :c:type:`z_owned_encoding_t`.\n *   s: Pointer to the string to use.\n *   len: Number of characters from the string s to use.\n *\n * Return:\n *   ``0`` if creation is successful,``negative value`` otherwise.\n */\nz_result_t z_encoding_from_substr(z_owned_encoding_t *encoding, const char *s, size_t len);\n\n/**\n * Sets a schema to this encoding from a null-terminated string. Zenoh does not define what a schema is and its\n * semantics is left to the implementer. E.g. a common schema for `text/plain` encoding is `utf-8`.\n *\n * Parameters:\n *   encoding: Pointer to initialized :c:type:`z_loaned_encoding_t`.\n *   schema: Pointer to the null terminated string to use as a schema.\n *\n * Return:\n *   ``0`` in case of success,``negative value`` otherwise.\n */\nz_result_t z_encoding_set_schema_from_str(z_loaned_encoding_t *encoding, const char *schema);\n\n/**\n * Sets a schema to this encoding from a substring. Zenoh does not define what a schema is and its semantics is left\n * to the implementer. E.g. a common schema for `text/plain` encoding is `utf-8`.\n *\n * Parameters:\n *   encoding: Pointer to initialized :c:type:`z_loaned_encoding_t`.\n *   schema: Pointer to the substring start.\n *   len: Number of characters to consider.\n *\n * Return:\n *   ``0`` if in case of success,``negative value`` otherwise.\n */\nz_result_t z_encoding_set_schema_from_substr(z_loaned_encoding_t *encoding, const char *schema, size_t len);\n\n/**\n * Builds a string from a :c:type:`z_loaned_encoding_t`.\n *\n * Parameters:\n *   encoding: Pointer to the :c:type:`z_loaned_encoding_t` to use.\n *   string: Pointer to an uninitialized :c:type:`z_owned_string_t` to store the string.\n *\n * Return:\n *   ``0`` if creation is successful,``negative value`` otherwise.\n */\nz_result_t z_encoding_to_string(const z_loaned_encoding_t *encoding, z_owned_string_t *string);\n\n/**\n * Checks if two encodings are equal.\n *\n * Parameters:\n *   left: Pointer to the first :c:type:`z_loaned_encoding_t` to compare.\n *   right: Pointer to the second :c:type:`z_loaned_encoding_t` to compare.\n *\n * Return:\n *   ``true`` if `left` equals `right`, ``false`` otherwise.\n */\nbool z_encoding_equals(const z_loaned_encoding_t *left, const z_loaned_encoding_t *right);\n\n/**\n * Gets the bytes data from a reply error payload by aliasing it.\n *\n * Parameters:\n *   reply_err: Pointer to a :c:type:`z_loaned_reply_err_t` to get data from.\n *\n * Return:\n *   Pointer to the data as a :c:type:`z_loaned_bytes_t`.\n */\nconst z_loaned_bytes_t *z_reply_err_payload(const z_loaned_reply_err_t *reply_err);\n\n/**\n * Gets a reply error encoding by aliasing it.\n *\n * Parameters:\n *   reply_err: Pointer to the :c:type:`z_loaned_reply_err_t` to get the encoding from.\n *\n * Return:\n *   Pointer to the encoding as a :c:type:`z_loaned_encoding_t`.\n */\nconst z_loaned_encoding_t *z_reply_err_encoding(const z_loaned_reply_err_t *reply_err);\n\n/**\n * Builds a :c:type:`z_owned_slice_t` by copying a buffer into it.\n *\n * Parameters:\n *   slice: Pointer to an uninitialized :c:type:`z_owned_slice_t`.\n *   data: Pointer to the data that will be copied into slice.\n *   len: Number of bytes to copy.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_slice_copy_from_buf(z_owned_slice_t *slice, const uint8_t *data, size_t len);\n\n/**\n * Builds a :c:type:`z_owned_slice_t` by transferring ownership over a data to it.\n *\n * Parameters:\n *   slice: Pointer to an uninitialized :c:type:`z_owned_slice_t`.\n *   data: Pointer to the data to be owned by `slice`.\n *   len: Number of bytes in `data`.\n *   deleter: A thread-safe delete function to free the `data`. Will be called once when `slice` is dropped.\n *     Can be NULL in the case where `data` is allocated in static memory.\n *   context: An optional context to be passed to the `deleter`.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_slice_from_buf(z_owned_slice_t *slice, uint8_t *data, size_t len,\n                            void (*deleter)(void *data, void *context), void *context);\n\n/**\n * Builds a :c:type:`z_view_slice_t`.\n *\n * Parameters:\n *   slice: Pointer to an uninitialized :c:type:`z_view_slice_t`.\n *   data: Pointer to the data to be pointed by `slice`.\n *   len: Number of bytes in `data`.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_view_slice_from_buf(z_view_slice_t *slice, const uint8_t *data, size_t len);\n\n/**\n * Builds an empty :c:type:`z_owned_slice_t`.\n *\n * Parameters:\n *   slice: Pointer to an uninitialized :c:type:`z_owned_slice_t`.\n */\nvoid z_slice_empty(z_owned_slice_t *slice);\n\n/**\n * Gets date pointer of a bytes array.\n *\n * Parameters:\n *   slice: Pointer to a :c:type:`z_loaned_slice_t` to get data from.\n *\n * Return:\n *   The data pointer.\n */\nconst uint8_t *z_slice_data(const z_loaned_slice_t *slice);\n\n/**\n * Gets the total number of bytes in a bytes array.\n *\n * Parameters:\n *   slice: Pointer to a :c:type:`z_loaned_slice_t` to get length from.\n *\n * Return:\n *   The number of bytes.\n */\nsize_t z_slice_len(const z_loaned_slice_t *slice);\n\n/**\n * Checks if slice is empty\n *\n * Parameters:\n *   slice: Pointer to a :c:type:`z_loaned_slice_t` to check.\n *\n * Return:\n *   ``true`` if the container is empty, ``false`` otherwise.\n */\nbool z_slice_is_empty(const z_loaned_slice_t *slice);\n\n/**\n * Converts data into a :c:type:`z_owned_slice_t`\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to decode.\n *   dst: Pointer to an uninitialized :c:type:`z_owned_slice_t` to contain the decoded slice.\n *\n * Return:\n *   ``0`` if decode is successful, or a ``negative value`` otherwise.\n */\nz_result_t z_bytes_to_slice(const z_loaned_bytes_t *bytes, z_owned_slice_t *dst);\n\n/**\n * Converts data into a :c:type:`z_owned_string_t`\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to decode.\n *   str: Pointer to an uninitialized :c:type:`z_owned_string_t` to contain the decoded string.\n *\n * Return:\n *   ``0`` if decode is successful, or a ``negative value`` otherwise.\n */\nz_result_t z_bytes_to_string(const z_loaned_bytes_t *bytes, z_owned_string_t *str);\n\n/**\n * Converts a slice into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded slice.\n *   slice: Pointer to the slice to convert. The slice will be consumed upon function return.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_from_slice(z_owned_bytes_t *bytes, z_moved_slice_t *slice);\n\n/**\n * Converts a slice into a :c:type:`z_owned_bytes_t` by copying.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded slice.\n *   slice: Pointer to the slice to convert.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_copy_from_slice(z_owned_bytes_t *bytes, const z_loaned_slice_t *slice);\n\n/**\n * Converts data into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded data.\n *   data: Pointer to the data to convert. Ownership is transferred to the `bytes`.\n *   len: Number of bytes to consider.\n *   deleter: A thread-safe delete function to free the `data`. Will be called once when `bytes` is dropped.\n *     Can be NULL in the case where `data` is allocated in static memory.\n *   context: An optional context to be passed to the `deleter`.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_from_buf(z_owned_bytes_t *bytes, uint8_t *data, size_t len,\n                            void (*deleter)(void *data, void *context), void *context);\n\n/**\n * Converts data into a :c:type:`z_owned_bytes_t` by copying.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded data.\n *   data: Pointer to the data to convert.\n *   len: Number of bytes to consider.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_copy_from_buf(z_owned_bytes_t *bytes, const uint8_t *data, size_t len);\n\n/**\n * Converts statically allocated constant data into a :c:type:`z_owned_bytes_t` by aliasing.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded data.\n *   data: Pointer to the statically allocated constant data to encode.\n *   len: Number of bytes to consider.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_from_static_buf(z_owned_bytes_t *bytes, const uint8_t *data, size_t len);\n\n/**\n * Converts a string into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded string.\n *   s: Pointer to the string to convert. The string will be consumed upon function return.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_from_string(z_owned_bytes_t *bytes, z_moved_string_t *s);\n\n/**\n * Converts a string into a :c:type:`z_owned_bytes_t` by copying.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded string.\n *   s: Pointer to the string to convert.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_copy_from_string(z_owned_bytes_t *bytes, const z_loaned_string_t *s);\n\n/**\n * Converts a null-terminated string into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded string.\n *   value: Pointer to the string to converts. Ownership is transferred to the `bytes`.\n *   deleter: A thread-safe delete function to free the `value`. Will be called once when `bytes` is dropped.\n *     Can be NULL in the case where `value` is allocated in static memory.\n *   context: An optional context to be passed to the `deleter`.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_from_str(z_owned_bytes_t *bytes, char *value, void (*deleter)(void *value, void *context),\n                            void *context);\n\n/**\n * Converts a null-terminated string into a :c:type:`z_owned_bytes_t` by copying.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded string.\n *   value: Pointer to the string to converts.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_copy_from_str(z_owned_bytes_t *bytes, const char *value);\n\n/**\n * Converts a statically allocated constant null-terminated string into a :c:type:`z_owned_bytes_t` by aliasing.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded string.\n *   value: Pointer to the statically allocated constant string to convert.\n *\n * Return:\n *   ``0`` if conversion is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_from_static_str(z_owned_bytes_t *bytes, const char *value);\n\n/**\n * Constructs an empty payload.\n *\n * Parameters:\n *   bytes: Pointer to an unitialized :c:type:`z_loaned_bytes_t` instance.\n */\nvoid z_bytes_empty(z_owned_bytes_t *bytes);\n\n/**\n * Returns total number of bytes in the container.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to decode.\n *\n * Return:\n *   Number of the bytes in the container.\n */\nsize_t z_bytes_len(const z_loaned_bytes_t *bytes);\n\n/**\n * Checks if container is empty\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to decode.\n *\n * Return:\n *   ``true`` if conainer is empty,  ``false`` otherwise.\n */\nbool z_bytes_is_empty(const z_loaned_bytes_t *bytes);\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n/**\n * Attempts to get a contiguous view to the underlying bytes (unstable).\n *\n * This is only possible if data is not fragmented, otherwise the function will fail.\n * In case of fragmented data, consider using `z_bytes_get_slice_iterator()`.\n *\n * Parameters:\n *   bytes: An instance of Zenoh data.\n *   view: An uninitialized memory location where a contiguous view on data will be constructed.\n *\n * Return:\n *   ``0`` in case of success, ``negative value`` otherwise.\n */\nz_result_t z_bytes_get_contiguous_view(const z_loaned_bytes_t *bytes, z_view_slice_t *view);\n#endif\n\n/**\n * Returns an iterator on raw bytes slices contained in the `z_loaned_bytes_t`.\n *\n * Zenoh may store data in non-contiguous regions of memory, this iterator\n * then allows to access raw data directly without any attempt of deserializing it.\n * Please note that no guarantee is provided on the internal memory layout.\n * The only provided guarantee is on the bytes order that is preserved.\n *\n * Parameters:\n *   bytes: Data to iterate over.\n *\n * Return:\n *   The constructed :c:type:`z_bytes_slice_iterator_t`.\n */\nz_bytes_slice_iterator_t z_bytes_get_slice_iterator(const z_loaned_bytes_t *bytes);\n\n/**\n * Constructs :c:type:`z_view_slice_t` providing view to the next slice.\n *\n * Parameters:\n *   iter: An iterator over slices of serialized data.\n *   out: An uninitialized :c:type:`z_view_slice_t` that will contain next slice.\n *\n * Return:\n *   ``false`` when iterator reaches the end,  ``true`` otherwise.\n */\nbool z_bytes_slice_iterator_next(z_bytes_slice_iterator_t *iter, z_view_slice_t *out);\n\n/**\n * Returns a reader for the `bytes`.\n *\n * The `bytes` should outlive the reader and should not be modified, while reader is in use.\n *\n * Parameters:\n *   bytes: Data to read.\n *\n * Return:\n *   The constructed :c:type:`z_bytes_reader_t`.\n */\nz_bytes_reader_t z_bytes_get_reader(const z_loaned_bytes_t *bytes);\n\n/**\n * Reads data into specified destination.\n *\n * Parameters:\n *   reader: Data reader to read from.\n *   dst: Buffer where the read data is written.\n *   len: Maximum number of bytes to read.\n *\n * Return:\n *   Number of bytes read. If return value is smaller than `len`, it means that the end of the data was reached.\n */\nsize_t z_bytes_reader_read(z_bytes_reader_t *reader, uint8_t *dst, size_t len);\n\n/**\n * Sets the `reader` position indicator for the payload to the value pointed to by offset.\n * The new position is exactly `offset` bytes measured from the beginning of the payload if origin is `SEEK_SET`,\n * from the current reader position if origin is `SEEK_CUR`, and from the end of the payload if origin is `SEEK_END`.\n *\n * Parameters:\n *   reader: Data reader to reposition.\n *   offset: New position ffset in bytes.\n *   origin: Origin for the new position.\n *\n * Return:\n *   ``0`` in case of success, ``negative value`` otherwise.\n */\nz_result_t z_bytes_reader_seek(z_bytes_reader_t *reader, int64_t offset, int origin);\n\n/**\n * Gets the read position indicator.\n *\n * Parameters:\n *   reader: Data reader to get position of.\n *\n * Return:\n *   Read position indicator on success or -1L if failure occurs.\n */\nint64_t z_bytes_reader_tell(z_bytes_reader_t *reader);\n\n/**\n * Gets number of bytes that can still be read.\n *\n * Parameters:\n *   reader: Data reader.\n *\n * Return:\n *   Number of bytes that can still be read.\n */\nsize_t z_bytes_reader_remaining(const z_bytes_reader_t *reader);\n\n/**\n * Constructs an empty writer for payload.\n *\n * Parameters:\n *   writer: An uninitialized memory location where writer is to be constructed.\n *\n * Return:\n *   ``0`` in case of success, ``negative value`` otherwise.\n */\nz_result_t z_bytes_writer_empty(z_owned_bytes_writer_t *writer);\n\n/**\n * Finishes writing and returns underlying bytes.\n *\n * Parameters:\n *   writer: A data writer.\n *   bytes: An uninitialized memory location where bytes is to be constructed.\n */\nvoid z_bytes_writer_finish(z_moved_bytes_writer_t *writer, z_owned_bytes_t *bytes);\n\n/**\n * Writes `len` bytes from `src` into underlying :c:type:`z_loaned_bytes_t`.\n *\n * Parameters:\n *   writer: A data writer.\n *   src: Buffer to write from.\n *   len: Number of bytes to write.\n *\n * Return:\n *   ``0`` if write is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_writer_write_all(z_loaned_bytes_writer_t *writer, const uint8_t *src, size_t len);\n\n/**\n * Appends bytes.\n * This allows to compose a serialized data out of multiple `z_owned_bytes_t` that may point to different memory\n * regions. Said in other terms, it allows to create a linear view on different memory regions without copy.\n *\n * Parameters:\n *   writer: A data writer.\n *   bytes: A data to append.\n *\n * Return:\n *   ``0`` if write is successful, ``negative value`` otherwise.\n */\nz_result_t z_bytes_writer_append(z_loaned_bytes_writer_t *writer, z_moved_bytes_t *bytes);\n\n/**\n * Create timestamp.\n *\n * Parameters:\n *   ts: An uninitialized :c:type:`z_timestamp_t`.\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to get the id from.\n *\n * Return:\n *   ``0`` if encode is successful, ``negative value`` otherwise (for example if RTC is not available on the system).\n */\nz_result_t z_timestamp_new(z_timestamp_t *ts, const z_loaned_session_t *zs);\n\n/**\n * Returns NTP64 time associated with this timestamp.\n *\n * Parameters:\n *   ts: Pointer to the valid :c:type:`z_timestamp_t`.\n *\n * Return:\n *   NTP64 time value\n */\nuint64_t z_timestamp_ntp64_time(const z_timestamp_t *ts);\n\n/**\n * Returns id associated with this timestamp.\n *\n * Parameters:\n *   ts: Pointer to the valid :c:type:`z_timestamp_t`.\n *\n * Return:\n *   Associated id represented by c:type:`z_id_t`\n */\nz_id_t z_timestamp_id(const z_timestamp_t *ts);\n\n/**\n * Creates an entity global id.\n *\n * Parameters:\n *   gid: An uninitialized :c:type:`z_entity_global_id_t`.\n *   zid: Pointer to a :c:type:`z_id_t` zenoh id.\n *   eid: :c:type:`uint32_t` entity id.\n */\nz_result_t z_entity_global_id_new(z_entity_global_id_t *gid, const z_id_t *zid, uint32_t eid);\n\n/**\n * Returns the entity id of the entity global id.\n *\n * Parameters:\n *   gid: Pointer to the valid :c:type:`z_entity_global_id_t`.\n *\n * Return:\n *   Entity id represented by c:type:`uint32_t`.\n */\nuint32_t z_entity_global_id_eid(const z_entity_global_id_t *gid);\n\n/**\n * Returns the zenoh id of entity global id.\n *\n * Parameters:\n *   gid: Pointer to the valid :c:type:`z_entity_global_id_t`.\n *\n * Return:\n *   Zenoh id represented by c:type:`z_id_t`.\n */\nz_id_t z_entity_global_id_zid(const z_entity_global_id_t *gid);\n\n/**\n * Constructs a new source info.\n *\n * Parameters:\n *   source_id: Non-null pointer to a :c:type:`z_entity_global_id_t` global entity id.\n *   source_sn: :c:type:`uint32_t` sequence number.\n *\n * Return:\n *   Source info.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_source_info_t z_source_info_new(const z_entity_global_id_t *source_id, uint32_t source_sn);\n\n/**\n * Returns the sequence number associated with this source info.\n *\n * Parameters:\n *   info: Pointer to the :c:type:`z_source_info_t` to get the sequence number from.\n *\n * Return:\n *   :c:type:`uint32_t` sequence number.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nuint32_t z_source_info_sn(const z_source_info_t *info);\n\n/**\n * Returns the id associated with this source info.\n *\n * Parameters:\n *   info: Pointer to the :c:type:`z_source_info_t` to get the id from.\n *\n * Return:\n *   Global entity ID as a :c:type:`z_entity_global_id_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_entity_global_id_t z_source_info_id(const z_source_info_t *info);\n\n/**\n * Builds a default query target.\n *\n * Return:\n *   The constructed :c:type:`z_query_target_t`.\n */\nz_query_target_t z_query_target_default(void);\n\n/**\n * Builds a default query reply key expression type.\n *\n * Return:\n *   The constructed :c:type:`z_reply_keyexpr_t`.\n */\nz_reply_keyexpr_t z_reply_keyexpr_default(void);\n\n/**\n * Builds an automatic query consolidation :c:type:`z_query_consolidation_t`.\n *\n * A query consolidation strategy will automatically be selected depending on the query selector.\n * If selector contains time range properties, no consolidation is performed.\n * Otherwise the :c:func:`z_query_consolidation_latest` strategy is used.\n *\n * Return:\n *   The constructed :c:type:`z_query_consolidation_t`.\n */\nz_query_consolidation_t z_query_consolidation_auto(void);\n\n/**\n * Builds a default :c:type:`z_query_consolidation_t`.\n *\n * Return:\n *   The constructed :c:type:`z_query_consolidation_t`.\n */\nz_query_consolidation_t z_query_consolidation_default(void);\n\n/**\n * Builds a latest query consolidation :c:type:`z_query_consolidation_t`.\n *\n * This strategy optimizes bandwidth on all links in the system but will provide a very poor latency.\n *\n * Return:\n *   The constructed :c:type:`z_query_consolidation_t`.\n */\nz_query_consolidation_t z_query_consolidation_latest(void);\n\n/**\n * Builds a monotonic query consolidation :c:type:`z_query_consolidation_t`.\n *\n * This strategy offers the best latency. Replies are directly transmitted to the application when received\n * without needing to wait for all replies. This mode does not guarantee that there will be no duplicates.\n *\n * Return:\n *   The constructed :c:type:`z_query_consolidation_t`.\n */\nz_query_consolidation_t z_query_consolidation_monotonic(void);\n\n/**\n * Builds a no query consolidation :c:type:`z_query_consolidation_t`.\n *\n * This strategy is useful when querying timeseries data bases or when using quorums.\n *\n * Return:\n *   The constructed :c:type:`z_query_consolidation_t`.\n */\nz_query_consolidation_t z_query_consolidation_none(void);\n\n/**\n * Gets a query parameters field.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the parameters from.\n *   parameters: Pointer to an uninitialized :c:type:`z_view_string_t` to contain the parameters.\n */\nvoid z_query_parameters(const z_loaned_query_t *query, z_view_string_t *parameters);\n\n/**\n * Queries may or may not accept replies on key expressions that do not intersect with their own key expression.\n * This getter allows you to check whether or not a specific query does so.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the target from.\n *\n * Return:\n *   The query reply key expression type as a :c:type:`z_reply_keyexpr_t`.\n */\nz_reply_keyexpr_t z_query_accepts_replies(const z_loaned_query_t *query);\n\n/**\n * Gets a query payload by aliasing it.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the value from.\n *\n * Return:\n *   Pointer to the payload as a :c:type:`z_loaned_bytes_t`.\n */\nconst z_loaned_bytes_t *z_query_payload(const z_loaned_query_t *query);\n\n/**\n * Gets a query encoding by aliasing it.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the value from.\n *\n * Return:\n *   Pointer to the encoding as a :c:type:`z_loaned_encoding_t`.\n */\nconst z_loaned_encoding_t *z_query_encoding(const z_loaned_query_t *query);\n\n/**\n * Gets a query attachment value by aliasing it.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the attachment from.\n *\n * Return:\n *   Pointer to the attachment as a :c:type:`z_loaned_bytes_t`.\n */\nconst z_loaned_bytes_t *z_query_attachment(const z_loaned_query_t *query);\n\n/**\n * Gets a query keyexpr by aliasing it.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a:c:type:`z_keyexpr_t`.\n */\nconst z_loaned_keyexpr_t *z_query_keyexpr(const z_loaned_query_t *query);\n\n/**\n * Gets a query source info by aliasing it.\n *\n * Parameters:\n *   query: Pointer to the :c:type:`z_loaned_query_t` to get the value from.\n *\n * Return:\n *   Pointer to the source info as a :c:type:`z_source_info_t`. Will return NULL if source info was not set by querier.\n */\nconst z_source_info_t *z_query_source_info(const z_loaned_query_t *query);\n\n/**\n * Builds a new sample closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_sample_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n */\nz_result_t z_closure_sample(z_owned_closure_sample_t *closure, z_closure_sample_callback_t call,\n                            z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a sample closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`z_loaned_closure_sample_t` to call.\n *   sample: Pointer to the :c:type:`z_loaned_sample_t` to pass to the closure.\n */\nvoid z_closure_sample_call(const z_loaned_closure_sample_t *closure, z_loaned_sample_t *sample);\n\n/**\n * Builds a new query closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_query_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n */\nz_result_t z_closure_query(z_owned_closure_query_t *closure, z_closure_query_callback_t call,\n                           z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a query closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`z_loaned_closure_query_t` to call.\n *   query: Pointer to the :c:type:`z_loaned_query_t` to pass to the closure.\n */\nvoid z_closure_query_call(const z_loaned_closure_query_t *closure, z_loaned_query_t *query);\n\n/**\n * Builds a new reply closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_reply_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n */\nz_result_t z_closure_reply(z_owned_closure_reply_t *closure, z_closure_reply_callback_t call,\n                           z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a reply closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`z_loaned_closure_reply_t` to call.\n *   reply: Pointer to the :c:type:`z_loaned_reply_t` to pass to the closure.\n */\nvoid z_closure_reply_call(const z_loaned_closure_reply_t *closure, z_loaned_reply_t *reply);\n\n/**\n * Builds a new hello closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_hello_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n */\nz_result_t z_closure_hello(z_owned_closure_hello_t *closure, z_closure_hello_callback_t call,\n                           z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a hello closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`z_loaned_closure_hello_t` to call.\n *   hello: Pointer to the :c:type:`z_loaned_hello_t` to pass to the closure.\n */\nvoid z_closure_hello_call(const z_loaned_closure_hello_t *closure, z_loaned_hello_t *hello);\n\n/**\n * Builds a new zid closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_zid_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n */\nz_result_t z_closure_zid(z_owned_closure_zid_t *closure, z_closure_zid_callback_t call, z_closure_drop_callback_t drop,\n                         void *context);\n\n/**\n * Calls a zid closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`z_loaned_closure_zid_t` to call.\n *   zid: Pointer to the :c:type:`z_id_t` to pass to the closure.\n */\nvoid z_closure_zid_call(const z_loaned_closure_zid_t *closure, const z_id_t *id);\n\n#if Z_FEATURE_CONNECTIVITY == 1\n/**\n * Builds a new transport closure.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_transport_t`.\n *   call: Pointer to the callback function.\n *   drop: Pointer to callback-state cleanup function.\n *   context: Pointer to arbitrary callback state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_closure_transport(z_owned_closure_transport_t *closure, z_closure_transport_callback_t call,\n                               z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a transport closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_closure_transport_call(const z_loaned_closure_transport_t *closure, z_loaned_transport_t *transport);\n\n/**\n * Builds a new link closure.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_link_t`.\n *   call: Pointer to the callback function.\n *   drop: Pointer to callback-state cleanup function.\n *   context: Pointer to arbitrary callback state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_closure_link(z_owned_closure_link_t *closure, z_closure_link_callback_t call,\n                          z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a link closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_closure_link_call(const z_loaned_closure_link_t *closure, z_loaned_link_t *link);\n\n/**\n * Builds a new transport event closure.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_transport_event_t`.\n *   call: Pointer to the callback function.\n *   drop: Pointer to callback-state cleanup function.\n *   context: Pointer to arbitrary callback state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_closure_transport_event(z_owned_closure_transport_event_t *closure,\n                                     z_closure_transport_event_callback_t call, z_closure_drop_callback_t drop,\n                                     void *context);\n\n/**\n * Calls a transport event closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_closure_transport_event_call(const z_loaned_closure_transport_event_t *closure,\n                                    z_loaned_transport_event_t *event);\n\n/**\n * Builds a new link event closure.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_link_event_t`.\n *   call: Pointer to the callback function.\n *   drop: Pointer to callback-state cleanup function.\n *   context: Pointer to arbitrary callback state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_closure_link_event(z_owned_closure_link_event_t *closure, z_closure_link_event_callback_t call,\n                                z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a link event closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_closure_link_event_call(const z_loaned_closure_link_event_t *closure, z_loaned_link_event_t *event);\n#endif\n\n/**\n * Builds a new matching status closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`z_owned_closure_matching_status_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n */\nz_result_t z_closure_matching_status(z_owned_closure_matching_status_t *closure,\n                                     z_closure_matching_status_callback_t call, z_closure_drop_callback_t drop,\n                                     void *context);\n\n/**\n * Calls a matching status closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`z_loaned_closure_matching_status_t` to call.\n *   status: Pointer to the :c:type:`z_matching_status_t` to pass to the closure.\n */\nvoid z_closure_matching_status_call(const z_loaned_closure_matching_status_t *closure,\n                                    const z_matching_status_t *status);\n\n/**\n * Builds a new sample miss closure.\n * It consists of a structure that contains all the elements for stateful, memory-leak-free callbacks.\n *\n * Parameters:\n *   closure: Pointer to an uninitialized :c:type:`ze_owned_closure_miss_t`.\n *   call: Pointer to the callback function. ``context`` will be passed as its last argument.\n *   drop: Pointer to the function that will free the callback state. ``context`` will be passed as its last argument.\n *   context: Pointer to an arbitrary state.\n *\n * Return:\n *   ``0`` in case of success, negative error code otherwise\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t ze_closure_miss(ze_owned_closure_miss_t *closure, ze_closure_miss_callback_t call,\n                           z_closure_drop_callback_t drop, void *context);\n\n/**\n * Calls a sample miss closure.\n *\n * Parameters:\n *   closure: Pointer to the :c:type:`ze_loaned_closure_miss_t` to call.\n *   status: Pointer to the :c:type:`ze_miss_t` to pass to the closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nvoid ze_closure_miss_call(const ze_loaned_closure_miss_t *closure, const ze_miss_t *miss);\n\n/**************** Loans ****************/\n_Z_OWNED_FUNCTIONS_DEF(string)\n_Z_OWNED_FUNCTIONS_DEF(keyexpr)\n_Z_OWNED_FUNCTIONS_DEF(config)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(session)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(subscriber)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(publisher)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(querier)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(matching_listener)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(queryable)\n_Z_OWNED_FUNCTIONS_DEF(hello)\n_Z_OWNED_FUNCTIONS_DEF(reply)\n_Z_OWNED_FUNCTIONS_DEF(string_array)\n_Z_OWNED_FUNCTIONS_DEF(sample)\n_Z_OWNED_FUNCTIONS_DEF(query)\n_Z_OWNED_FUNCTIONS_DEF(slice)\n_Z_OWNED_FUNCTIONS_DEF(bytes)\n_Z_OWNED_FUNCTIONS_NO_COPY_DEF(bytes_writer)\n_Z_OWNED_FUNCTIONS_DEF(reply_err)\n_Z_OWNED_FUNCTIONS_DEF(encoding)\n\n_Z_OWNED_FUNCTIONS_DEF(cancellation_token)\n\n#if Z_FEATURE_CONNECTIVITY == 1\n_Z_OWNED_FUNCTIONS_DEF(transport)\n_Z_OWNED_FUNCTIONS_DEF(link)\n_Z_OWNED_FUNCTIONS_DEF(transport_event)\n_Z_OWNED_FUNCTIONS_DEF(link_event)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(transport_events_listener)\n_Z_OWNED_FUNCTIONS_NO_COPY_NO_MOVE_DEF(link_events_listener)\n#endif\n\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_sample)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_query)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_reply)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_hello)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_zid)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_matching_status)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF_PREFIX(ze, closure_miss)\n#if Z_FEATURE_CONNECTIVITY == 1\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_transport)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_link)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_transport_event)\n_Z_OWNED_FUNCTIONS_CLOSURE_DEF(closure_link_event)\n#endif\n\n_Z_VIEW_FUNCTIONS_DEF(keyexpr)\n_Z_VIEW_FUNCTIONS_DEF(string)\n_Z_VIEW_FUNCTIONS_DEF(slice)\n\n/**\n * Loans a :c:type:`z_owned_sample_t`.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_owned_sample_t` to loan.\n *\n * Return:\n *   Pointer to the loaned sample as a :c:type:`z_loaned_sample_t`.\n */\nconst z_loaned_sample_t *z_sample_loan(const z_owned_sample_t *sample);\n\n/**\n * Gets data from a :c:type:`z_loaned_string_t`.\n *\n * Parameters:\n *   str: Pointer to a :c:type:`z_loaned_string_t` to get data from.\n *\n * Return:\n *   Pointer to the string data.\n */\nconst char *z_string_data(const z_loaned_string_t *str);\n\n/**\n * Gets string length from a :c:type:`z_loaned_string_t`.\n *\n * Parameters:\n *   str: Pointer to a :c:type:`z_loaned_string_t` to get length from.\n *\n * Return:\n *   Length of the string.\n */\nsize_t z_string_len(const z_loaned_string_t *str);\n\n/**\n * Builds a :c:type:`z_string_t` by copying a ``const char *`` string.\n *\n * Parameters:\n *   str: Pointer to an uninitialized :c:type:`z_owned_string_t`.\n *   value: Pointer to a null terminated string to be copied.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_string_copy_from_str(z_owned_string_t *str, const char *value);\n\n/**\n * Builds a :c:type:`z_owned_string_t` by transferring ownership over a null-terminated string to it.\n *\n * Parameters:\n *   str: Pointer to an uninitialized :c:type:`z_owned_string_t`.\n *   value: Pointer to a null terminated string to be owned by `str`.\n *   deleter: A thread-safe delete function to free the `value`. Will be called once when `str` is dropped.\n *     Can be NULL in the case where `value` is allocated in static memory.\n *   context: An optional context to be passed to the `deleter`.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_string_from_str(z_owned_string_t *str, char *value, void (*deleter)(void *value, void *context),\n                             void *context);\n\n/**\n * Builds an empty :c:type:`z_owned_string_t`.\n *\n * Parameters:\n *   str: Pointer to an uninitialized :c:type:`z_owned_string_t`.\n */\nvoid z_string_empty(z_owned_string_t *str);\n\n/**\n * Builds a :c:type:`z_string_t` by wrapping a substring specified by ``const char *`` and length `len`.\n *\n * Parameters:\n *   str: Pointer to an uninitialized :c:type:`z_owned_string_t`.\n *   value: Pointer to a string.\n *   len: String size.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_string_copy_from_substr(z_owned_string_t *str, const char *value, size_t len);\n\n/**\n * Checks if string is empty\n *\n * Parameters:\n *   str: Pointer to a :c:type:`z_loaned_string_t` to check.\n *\n * Return:\n *  ``true`` if the string is empty, ``false`` otherwise.\n */\nbool z_string_is_empty(const z_loaned_string_t *str);\n\n/**\n * Returns :c:type:`z_loaned_slice_t` for the string\n *\n * Parameters:\n *   str: Pointer to a :c:type:`z_loaned_string_t` to get a slice.\n *\n * Return:\n *   slice containing string data\n */\nconst z_loaned_slice_t *z_string_as_slice(const z_loaned_string_t *str);\n\n/**\n * Returns default :c:type:`z_priority_t` value\n */\nz_priority_t z_priority_default(void);\n\n#if Z_FEATURE_SCOUTING == 1\n/**\n * Returns id of Zenoh entity that transmitted hello message.\n *\n * Parameters:\n *   hello: Pointer to a :c:type:`z_loaned_hello_t` message.\n *\n * Return:\n *   Id of the Zenoh entity that transmitted hello message.\n */\nz_id_t z_hello_zid(const z_loaned_hello_t *hello);\n\n/**\n * Returns type of Zenoh entity that transmitted hello message.\n *\n * Parameters:\n *   hello: Pointer to a :c:type:`z_loaned_hello_t` message.\n *\n * Return:\n *   Type of the Zenoh entity that transmitted hello message.\n */\nz_whatami_t z_hello_whatami(const z_loaned_hello_t *hello);\n\n/**\n * Returns an array of locators of Zenoh entity that sent hello message.\n *\n * Parameters:\n *   hello: Pointer to a :c:type:`z_loaned_hello_t` message.\n *\n * Return:\n *   :c:type:`z_loaned_string_array_t` containing locators.\n */\nconst z_loaned_string_array_t *zp_hello_locators(const z_loaned_hello_t *hello);\n\n/**\n * Constructs an array of locators of Zenoh entity that sent hello message.\n *\n * Note that it is a method for zenoh-c compatiblity, in zenoh-pico :c:func:`zp_hello_locators`\n * can be used.\n *\n * Parameters:\n *   hello: Pointer to a :c:type:`z_loaned_hello_t` message.\n *   locators_out: An uninitialized memory location where :c:type:`z_owned_string_array_t` will be constructed.\n */\nvoid z_hello_locators(const z_loaned_hello_t *hello, z_owned_string_array_t *locators_out);\n\n/**\n * Constructs a non-owned non-null-terminated string from the kind of zenoh entity.\n *\n * The string has static storage (i.e. valid until the end of the program).\n *\n * Parameters:\n *   whatami: A whatami bitmask of zenoh entity kind.\n *   str_out: An uninitialized memory location where strring will be constructed.\n *\n * Return:\n *   ``0`` in case of success, ``negative value`` otherwise.\n */\nz_result_t z_whatami_to_view_string(z_whatami_t whatami, z_view_string_t *str_out);\n\n/************* Primitives **************/\n\n/**\n * Scouts for other Zenoh entities like routers and/or peers.\n *\n * Parameters:\n *   config: Moved :c:type:`z_owned_config_t` to configure the scouting with.\n *   callback: Moved :c:type:`z_owned_closure_hello_t` callback.\n *   options: Pointer to a :c:type:`z_scout_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if scouting was successfully triggered, ``negative value`` otherwise.\n */\nz_result_t z_scout(z_moved_config_t *config, z_moved_closure_hello_t *callback, const z_scout_options_t *options);\n\n/**\n * Builds a :c:type:`z_scout_options_t` with default value.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_scout_options_t`.\n */\nvoid z_scout_options_default(z_scout_options_t *options);\n#endif\n\n/**\n * Opens a Zenoh session.\n *\n * See :doc:`/config` for the configuration options that affect this operation.\n *\n * Parameters:\n *   zs: Pointer to an uninitialized :c:type:`z_owned_session_t` to store the session info.\n *   config: Moved :c:type:`z_owned_config_t` to configure the session with.\n *   options: Pointer to a :c:type:`z_open_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if open is successful, ``negative value`` otherwise.\n */\nz_result_t z_open(z_owned_session_t *zs, z_moved_config_t *config, const z_open_options_t *options);\n\n/**\n * Builds a :c:type:`z_open_options_t` with default value.\n */\nvoid z_open_options_default(z_open_options_t *options);\n\n/**\n * Closes a Zenoh session.\n *\n * Parameters:\n *   zs: Loaned :c:type:`z_owned_session_t` to close.\n *   options: Pointer to a :c:type:`z_close_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if close is successful, ``negative value`` otherwise.\n */\nz_result_t z_close(z_loaned_session_t *zs, const z_close_options_t *options);\n\n/**\n * Checks if Zenoh session is closed.\n *\n * Parameters:\n *   zs: Loaned :c:type:`z_owned_session_t`.\n *\n * Return:\n *   ``true`` if session is closed, ``false`` otherwise.\n */\nbool z_session_is_closed(const z_loaned_session_t *zs);\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * Gets the entity global Id of Zenoh session (unstable).\n *\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to get the id from.\n *\n * Return:\n *   The entity global Id of the session as :c:type:`z_entity_t`.\n */\nz_entity_global_id_t z_session_id(const z_loaned_session_t *zs);\n#endif\n/**\n * Fetches Zenoh IDs of all connected peers.\n *\n * The callback will be called once for each ID. It is guaranteed to never be called concurrently,\n * and to be dropped before this function exits.\n *\n * Parameters:\n *   zs: Pointer to :c:type:`z_loaned_session_t` to fetch peer id from.\n *   callback: Moved :c:type:`z_owned_closure_zid_t` callback.\n *\n * Return:\n *   ``0`` if operation was successfully triggered, ``negative value`` otherwise.\n */\nz_result_t z_info_peers_zid(const z_loaned_session_t *zs, z_moved_closure_zid_t *callback);\n\n/**\n * Fetches Zenoh IDs of all connected routers.\n *\n * The callback will be called once for each ID. It is guaranteed to never be called concurrently,\n * and to be dropped before this function exits.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to fetch router id from.\n *   callback: Moved :c:type:`z_owned_closure_zid_t` callback.\n *\n * Return:\n *   ``0`` if operation was successfully triggered, ``negative value`` otherwise.\n */\nz_result_t z_info_routers_zid(const z_loaned_session_t *zs, z_moved_closure_zid_t *callback);\n\n/**\n * Gets the local Zenoh ID associated to a given Zenoh session.\n *\n * If this function returns an array of 16 zeros, this means the session is invalid.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to get the id from.\n *\n * Return:\n *   The local Zenoh ID of the session as :c:type:`z_id_t`.\n */\nz_id_t z_info_zid(const z_loaned_session_t *zs);\n\nstatic inline void _z_transport_link_properties_from_transport(const _z_transport_common_t *transport, uint16_t *mtu,\n                                                               bool *is_streamed, bool *is_reliable) {\n    *mtu = 0;\n    *is_streamed = false;\n    *is_reliable = false;\n\n    if (transport != NULL && transport->_link != NULL) {\n        *mtu = transport->_link->_mtu;\n        *is_streamed = transport->_link->_cap._flow == Z_LINK_CAP_FLOW_STREAM;\n        *is_reliable = transport->_link->_cap._is_reliable;\n    }\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nvoid _z_info_transport_from_peer(_z_info_transport_t *out, const _z_transport_peer_common_t *peer, bool is_multicast);\nbool _z_info_transport_filter_match(const _z_info_transport_t *transport, const _z_info_transport_t *filter);\n\n/**\n * Fetches all currently connected transports.\n *\n * The callback is called once for each transport and is dropped before this function exits.\n *\n * Parameters:\n *   zs: Pointer to :c:type:`z_loaned_session_t`.\n *   callback: Moved :c:type:`z_owned_closure_transport_t` callback.\n *\n * Return:\n *   ``0`` if operation was successfully triggered, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_info_transports(const z_loaned_session_t *zs, z_moved_closure_transport_t *callback);\n\n/**\n * Constructs default value for :c:type:`z_info_links_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_info_links_options_default(z_info_links_options_t *options);\n\n/**\n * Fetches all currently connected links.\n *\n * The callback is called once for each link and is dropped before this function exits.\n *\n * Parameters:\n *   zs: Pointer to :c:type:`z_loaned_session_t`.\n *   callback: Moved :c:type:`z_owned_closure_link_t` callback.\n *   options: Optional :c:type:`z_info_links_options_t`.\n *\n * Return:\n *   ``0`` if operation was successfully triggered, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_info_links(const z_loaned_session_t *zs, z_moved_closure_link_t *callback,\n                        z_info_links_options_t *options);\n\n/**\n * Constructs default value for :c:type:`z_transport_events_listener_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_transport_events_listener_options_default(z_transport_events_listener_options_t *options);\n\n/**\n * Declares a transport events listener.\n *\n * Parameters:\n *   zs: Pointer to :c:type:`z_loaned_session_t`.\n *   listener: Uninitialized location where listener will be constructed.\n *   callback: Moved :c:type:`z_owned_closure_transport_event_t`.\n *   options: Optional :c:type:`z_transport_events_listener_options_t`.\n *\n * Return:\n *   ``0`` on success, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_declare_transport_events_listener(const z_loaned_session_t *zs,\n                                               z_owned_transport_events_listener_t *listener,\n                                               z_moved_closure_transport_event_t *callback,\n                                               const z_transport_events_listener_options_t *options);\n\n/**\n * Declares a background transport events listener.\n *\n * The listener runs in background and cannot be undeclared explicitly.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_declare_background_transport_events_listener(const z_loaned_session_t *zs,\n                                                          z_moved_closure_transport_event_t *callback,\n                                                          const z_transport_events_listener_options_t *options);\n\n/**\n * Undeclares a transport events listener.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_undeclare_transport_events_listener(z_moved_transport_events_listener_t *listener);\n\n/**\n * Constructs default value for :c:type:`z_link_events_listener_options_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_link_events_listener_options_default(z_link_events_listener_options_t *options);\n\n/**\n * Declares a link events listener.\n *\n * Parameters:\n *   zs: Pointer to :c:type:`z_loaned_session_t`.\n *   listener: Uninitialized location where listener will be constructed.\n *   callback: Moved :c:type:`z_owned_closure_link_event_t`.\n *   options: Optional :c:type:`z_link_events_listener_options_t`.\n *\n * Return:\n *   ``0`` on success, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_declare_link_events_listener(const z_loaned_session_t *zs, z_owned_link_events_listener_t *listener,\n                                          z_moved_closure_link_event_t *callback,\n                                          z_link_events_listener_options_t *options);\n\n/**\n * Declares a background link events listener.\n *\n * The listener runs in background and cannot be undeclared explicitly.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_declare_background_link_events_listener(const z_loaned_session_t *zs,\n                                                     z_moved_closure_link_event_t *callback,\n                                                     z_link_events_listener_options_t *options);\n\n/**\n * Undeclares a link events listener.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_undeclare_link_events_listener(z_moved_link_events_listener_t *listener);\n\n/**\n * Gets a transport remote Zenoh ID.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_id_t z_transport_zid(const z_loaned_transport_t *transport);\n\n/**\n * Gets a transport remote entity kind.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_whatami_t z_transport_whatami(const z_loaned_transport_t *transport);\n\n/**\n * Returns whether QoS is enabled for this transport.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_transport_is_qos(const z_loaned_transport_t *transport);\n\n/**\n * Returns whether this transport is multicast.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_transport_is_multicast(const z_loaned_transport_t *transport);\n\n/**\n * Returns whether shared memory is enabled for this transport.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_transport_is_shm(const z_loaned_transport_t *transport);\n\n/**\n * Gets a link remote Zenoh ID.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_id_t z_link_zid(const z_loaned_link_t *link);\n\n/**\n * Gets a link source endpoint string.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_link_src(const z_loaned_link_t *link, z_owned_string_t *str_out);\n\n/**\n * Gets a link destination endpoint string.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_result_t z_link_dst(const z_loaned_link_t *link, z_owned_string_t *str_out);\n\n/**\n * Gets a link MTU.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nuint16_t z_link_mtu(const z_loaned_link_t *link);\n\n/**\n * Returns whether the link is stream-based.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_link_is_streamed(const z_loaned_link_t *link);\n\n/**\n * Returns whether the link transport is reliable.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_link_is_reliable(const z_loaned_link_t *link);\n\n/**\n * Gets a link group string.\n *\n * Parameters:\n *   link: Pointer to a :c:type:`z_loaned_link_t`.\n *   str_out: Pointer to an uninitialized :c:type:`z_owned_string_t` to store the result.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_link_group(const z_loaned_link_t *link, z_owned_string_t *str_out);\n\n/**\n * Gets a link auth identifier string.\n *\n * Parameters:\n *   link: Pointer to a :c:type:`z_loaned_link_t`.\n *   str_out: Pointer to an uninitialized :c:type:`z_owned_string_t` to store the result.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_link_auth_identifier(const z_loaned_link_t *link, z_owned_string_t *str_out);\n\n/**\n * Gets link interfaces.\n *\n * Parameters:\n *   link: Pointer to a :c:type:`z_loaned_link_t`.\n *   interfaces_out: Pointer to an uninitialized :c:type:`z_owned_string_array_t` to store the result.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nvoid z_link_interfaces(const z_loaned_link_t *link, z_owned_string_array_t *interfaces_out);\n\n/**\n * Gets link priority range.\n *\n * Parameters:\n *   link: Pointer to a :c:type:`z_loaned_link_t`.\n *   min_out: Pointer to store the minimum priority value.\n *   max_out: Pointer to store the maximum priority value.\n *\n * Return:\n *   ``true`` if link has priority information, ``false`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_link_priorities(const z_loaned_link_t *link, uint8_t *min_out, uint8_t *max_out);\n\n/**\n * Gets link reliability.\n *\n * Parameters:\n *   link: Pointer to a :c:type:`z_loaned_link_t`.\n *   reliability_out: Pointer to store the reliability value.\n *\n * Return:\n *   ``true`` if link has reliability information, ``false`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nbool z_link_reliability(const z_loaned_link_t *link, z_reliability_t *reliability_out);\n\n/**\n * Gets transport event kind.\n *\n * Returns ``Z_SAMPLE_KIND_PUT`` when a transport is connected and ``Z_SAMPLE_KIND_DELETE`` when disconnected.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_sample_kind_t z_transport_event_kind(const z_loaned_transport_event_t *event);\n\n/**\n * Gets transport event transport.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nconst z_loaned_transport_t *z_transport_event_transport(const z_loaned_transport_event_t *event);\n\n/**\n * Gets mutable transport event transport.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_loaned_transport_t *z_transport_event_transport_mut(z_loaned_transport_event_t *event);\n\n/**\n * Gets link event kind.\n *\n * Returns ``Z_SAMPLE_KIND_PUT`` when a link is added and ``Z_SAMPLE_KIND_DELETE`` when removed.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_sample_kind_t z_link_event_kind(const z_loaned_link_event_t *event);\n\n/**\n * Gets link event link.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nconst z_loaned_link_t *z_link_event_link(const z_loaned_link_event_t *event);\n\n/**\n * Gets mutable link event link.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\nz_loaned_link_t *z_link_event_link_mut(z_loaned_link_event_t *event);\n#endif\n\n/**\n * Converts a Zenoh ID into a string for print purposes.\n *\n * Parameters:\n *   id: Pointer to the id to convert.\n *   str: Pointer to uninitialized :c:type:`z_owned_string_t` to store the string.\n *\n * Return:\n *   ``0`` if operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_id_to_string(const z_id_t *id, z_owned_string_t *str);\n\n/**\n * Gets the keyexpr from a sample by aliasing it.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a :c:type:`z_loaned_keyexpr_t`.\n */\nconst z_loaned_keyexpr_t *z_sample_keyexpr(const z_loaned_sample_t *sample);\n\n/**\n * Gets the payload of a sample by aliasing it.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the payload from.\n *\n * Return:\n *   The payload wrapped as a :c:type:`z_loaned_bytes_t`.\n */\nconst z_loaned_bytes_t *z_sample_payload(const z_loaned_sample_t *sample);\n\n/**\n * Gets the timestamp of a sample by aliasing it.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the timestamp from.\n *\n * Return:\n *   The pointer to timestamp wrapped as a :c:type:`z_timestamp_t`. Returns NULL if no timestamp was set.\n */\nconst z_timestamp_t *z_sample_timestamp(const z_loaned_sample_t *sample);\n\n/**\n * Gets the encoding of a sample by aliasing it.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the encoding from.\n *\n * Return:\n *   The encoding wrapped as a :c:type:`z_loaned_encoding_t`.\n */\nconst z_loaned_encoding_t *z_sample_encoding(const z_loaned_sample_t *sample);\n\n/**\n * Gets the kind of a sample by aliasing it.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the kind from.\n *\n * Return:\n *   The sample kind wrapped as a :c:type:`z_sample_kind_t`.\n */\nz_sample_kind_t z_sample_kind(const z_loaned_sample_t *sample);\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * Gets the reliability a sample was received with (unstable).\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the reliability from.\n *\n * Return:\n *   The reliability wrapped as a :c:type:`z_reliability_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_reliability_t z_sample_reliability(const z_loaned_sample_t *sample);\n\n/**\n * Gets the source info for the sample (unstable).\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the source info from.\n *\n * Return:\n *   The source info wrapped as a :c:type:`z_source_info_t`. Will return NULL if source info was not set by sender.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nconst z_source_info_t *z_sample_source_info(const z_loaned_sample_t *sample);\n#endif\n\n/**\n * Got a sample qos congestion control value.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the congestion control from.\n *\n * Return:\n *   The congestion control wrapped as a :c:type:`z_congestion_control_t`.\n */\nz_congestion_control_t z_sample_congestion_control(const z_loaned_sample_t *sample);\n\n/**\n * Got whether sample qos express flag was set or not.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the express flag from.\n *\n * Return:\n *   The express flag value.\n */\nbool z_sample_express(const z_loaned_sample_t *sample);\n\n/**\n * Gets sample qos priority value.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the qos priority from.\n *\n * Return:\n *   The priority wrapped as a :c:type:`z_priority_t`.\n */\nz_priority_t z_sample_priority(const z_loaned_sample_t *sample);\n\n/**\n * Gets the attachment of a sample by aliasing it.\n *\n * Parameters:\n *   sample: Pointer to a :c:type:`z_loaned_sample_t` to get the attachment from.\n *\n * Return:\n *   Pointer to the attachment as a :c:type:`z_loaned_bytes_t`.\n */\nconst z_loaned_bytes_t *z_sample_attachment(const z_loaned_sample_t *sample);\n\n#if Z_FEATURE_PUBLICATION == 1\n/**\n * Builds a :c:type:`z_put_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_put_options_t`.\n */\nvoid z_put_options_default(z_put_options_t *options);\n\n/**\n * Builds a :c:type:`z_delete_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_delete_options_t`.\n */\nvoid z_delete_options_default(z_delete_options_t *options);\n\n/**\n * Puts data for a given keyexpr.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to put the data through.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to put the data for.\n *   payload: Moved :c:type:`z_owned_bytes_t` containing the data to put.\n *   options: Pointer to a :c:type:`z_put_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_put(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, z_moved_bytes_t *payload,\n                 const z_put_options_t *options);\n\n/**\n * Deletes data for a given keyexpr.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to delete the data through.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to delete the data for.\n *   options: Pointer to a :c:type:`z_delete_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if delete operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_delete(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, const z_delete_options_t *options);\n\n/**\n * Builds a :c:type:`z_publisher_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_delete_options_t`.\n */\nvoid z_publisher_options_default(z_publisher_options_t *options);\n\n/**\n * Declares a publisher for a given keyexpr.\n *\n * Data can be put and deleted with this publisher with the help of the\n * :c:func:`z_publisher_put` and :c:func:`z_publisher_delete` functions.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the publisher through.\n *   pub: Pointer to an uninitialized :c:type:`z_owned_publisher_t`.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the publisher with.\n *   options: Pointer to a :c:type:`z_publisher_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n */\nz_result_t z_declare_publisher(const z_loaned_session_t *zs, z_owned_publisher_t *pub,\n                               const z_loaned_keyexpr_t *keyexpr, const z_publisher_options_t *options);\n\n/**\n * Undeclares the publisher.\n *\n * Parameters:\n *   pub: Moved :c:type:`z_owned_publisher_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n */\nz_result_t z_undeclare_publisher(z_moved_publisher_t *pub);\n\n/**\n * Builds a :c:type:`z_publisher_put_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_publisher_put_options_t`.\n */\nvoid z_publisher_put_options_default(z_publisher_put_options_t *options);\n\n/**\n * Builds a :c:type:`z_publisher_delete_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_publisher_delete_options_t`.\n */\nvoid z_publisher_delete_options_default(z_publisher_delete_options_t *options);\n\n/**\n * Puts data for the keyexpr bound to the given publisher.\n *\n * Parameters:\n *   pub: Pointer to a :c:type:`z_loaned_publisher_t` from where to put the data.\n *   payload: Moved :c:type:`z_owned_bytes_t` containing the data to put.\n *   options: Pointer to a :c:type:`z_publisher_put_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_publisher_put(const z_loaned_publisher_t *pub, z_moved_bytes_t *payload,\n                           const z_publisher_put_options_t *options);\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\nz_result_t _z_publisher_put_impl(const z_loaned_publisher_t *pub, z_moved_bytes_t *payload,\n                                 const z_publisher_put_options_t *options, _ze_advanced_cache_t *cache);\n#else\nz_result_t _z_publisher_put_impl(const z_loaned_publisher_t *pub, z_moved_bytes_t *payload,\n                                 const z_publisher_put_options_t *options);\n#endif\n\n/**\n * Deletes data from the keyexpr bound to the given publisher.\n *\n * Parameters:\n *   pub: Pointer to a :c:type:`z_loaned_publisher_t` from where to delete the data.\n *   options: Pointer to a :c:type:`z_publisher_delete_options_t` to configure the delete operation.\n *\n * Return:\n *   ``0`` if delete operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_publisher_delete(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options);\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\nz_result_t _z_publisher_delete_impl(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options,\n                                    _ze_advanced_cache_t *cache);\n#else\nz_result_t _z_publisher_delete_impl(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options);\n#endif\n\n/**\n * Gets the keyexpr from a publisher.\n *\n * Parameters:\n *   publisher: Pointer to a :c:type:`z_loaned_publisher_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a :c:type:`z_loaned_keyexpr_t`.\n */\nconst z_loaned_keyexpr_t *z_publisher_keyexpr(const z_loaned_publisher_t *publisher);\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n/**\n * Gets the entity global Id from a publisher.\n *\n * Parameters:\n *   publisher: Pointer to a :c:type:`z_loaned_publisher_t` to get the entity global Id from.\n *\n * Return:\n *   The entity gloabl Id wrapped as a :c:type:`z_entity_global_id_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_entity_global_id_t z_publisher_id(const z_loaned_publisher_t *publisher);\n#endif\n\n#if Z_FEATURE_MATCHING == 1\n/**\n * Declares a matching listener, registering a callback for notifying subscribers matching with a given publisher.\n * The callback will be run in the background until the corresponding publisher is dropped.\n *\n * Parameters:\n *   publisher: A publisher to associate with matching listener.\n *   callback: A closure that will be called every time the matching status of the publisher changes (If last subscriber\n * disconnects or when the first subscriber connects).\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n */\nz_result_t z_publisher_declare_background_matching_listener(const z_loaned_publisher_t *publisher,\n                                                            z_moved_closure_matching_status_t *callback);\n/**\n * Constructs matching listener, registering a callback for notifying subscribers matching with a given publisher.\n *\n * Parameters:\n *   publisher: A publisher to associate with matching listener.\n *   matching_listener: An uninitialized memory location where matching listener will be constructed. The matching\n * listener's callback will be automatically dropped when the publisher is dropped. callback: A closure that will be\n * called every time the matching status of the publisher changes (If last subscriber disconnects or when the first\n * subscriber connects).\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n */\nz_result_t z_publisher_declare_matching_listener(const z_loaned_publisher_t *publisher,\n                                                 z_owned_matching_listener_t *matching_listener,\n                                                 z_moved_closure_matching_status_t *callback);\n/**\n * Gets publisher matching status - i.e. if there are any subscribers matching its key expression.\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n */\nz_result_t z_publisher_get_matching_status(const z_loaned_publisher_t *publisher, z_matching_status_t *matching_status);\n\n/**\n * Undeclares the matching listener.\n *\n * Parameters:\n *   listener: Moved :c:type:`z_owned_matching_listener_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n */\nz_result_t z_undeclare_matching_listener(z_moved_matching_listener_t *listener);\n\n#endif  // Z_FEATURE_MATCHING == 1\n\n#endif  // Z_FEATURE_PUBLICATION == 1\n\n#if Z_FEATURE_QUERY == 1\n/**\n * Builds a :c:type:`z_get_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_get_options_t`.\n */\nvoid z_get_options_default(z_get_options_t *options);\n\n/**\n * Sends a distributed query for a given keyexpr.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to send the query through.\n *   keyexpr: Pointer to a  :c:type:`z_loaned_keyexpr_t` to send the query for.\n *   parameters: Pointer to the parameters as a null-terminated string.\n *   callback: Moved :c:type:`z_owned_closure_reply_t` callback.\n *   options: Pointer to a :c:type:`z_get_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, const char *parameters,\n                 z_moved_closure_reply_t *callback, z_get_options_t *options);\n\n/**\n * Sends a distributed query for a given keyexpr.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to send the query through.\n *   keyexpr: Pointer to a  :c:type:`z_loaned_keyexpr_t` to send the query for.\n *   parameters: Pointer to the parameters string.\n *   parameters_len: Length of the parameters string.\n *   callback: Moved :c:type:`z_owned_closure_reply_t` callback.\n *   options: Pointer to a :c:type:`z_get_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_get_with_parameters_substr(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                        const char *parameters, size_t parameters_len,\n                                        z_moved_closure_reply_t *callback, z_get_options_t *options);\n\n/**\n *  Constructs the default value for :c:type:`z_querier_get_options_t`.\n */\nvoid z_querier_get_options_default(z_querier_get_options_t *options);\n\n/**\n *  Constructs the default value for :c:type:`z_querier_options_t`.\n */\nvoid z_querier_options_default(z_querier_options_t *options);\n\n/**\n * Constructs and declares a querier on the given key expression.\n *\n * The queries can be send with the help of the `z_querier_get()` function.\n *\n * Parameters:\n *   zs: The Zenoh session.\n *   querier: An uninitialized location in memory where querier will be constructed.\n *   keyexpr: The key expression to send queries on.\n *   options: Additional options for the querier.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\n\nz_result_t z_declare_querier(const z_loaned_session_t *zs, z_owned_querier_t *querier,\n                             const z_loaned_keyexpr_t *keyexpr, z_querier_options_t *options);\n\n/**\n * Frees memory and resets querier to its gravestone state.\n */\nz_result_t z_undeclare_querier(z_moved_querier_t *querier);\n\n/**\n * Query data from the matching queryables in the system.\n *\n * Replies are provided through a callback function.\n *\n * Parameters:\n *   querier: The querier to make query from.\n *   parameters: The query's parameters null-terminated string, similar to a url's query segment.\n *   callback: The callback function that will be called on reception of replies for this query. It will be\n * \t\t\t\tautomatically dropped once all replies are processed.\n *   options: Additional options for the get. All owned fields will be consumed.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_querier_get(const z_loaned_querier_t *querier, const char *parameters, z_moved_closure_reply_t *callback,\n                         z_querier_get_options_t *options);\n\n/**\n * Query data from the matching queryables in the system.\n *\n * Replies are provided through a callback function.\n *\n * Parameters:\n *   querier: The querier to make query from.\n *   parameters: The query's parameters string, similar to a url's query segment.\n *   parameters_len: Length of the parameters string\n *   callback: The callback function that will be called on reception of replies for this query. It will be\n * \t\t\t\tautomatically dropped once all replies are processed.\n *   options: Additional options for the get. All owned fields will be consumed.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_querier_get_with_parameters_substr(const z_loaned_querier_t *querier, const char *parameters,\n                                                size_t parameters_len, z_moved_closure_reply_t *callback,\n                                                z_querier_get_options_t *options);\n\n/**\n *  Returns the key expression of the querier.\n */\nconst z_loaned_keyexpr_t *z_querier_keyexpr(const z_loaned_querier_t *querier);\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n/**\n * Gets the entity global Id from a querier.\n *\n * Parameters:\n *   publisher: Pointer to a :c:type:`z_loaned_querier_t` to get the entity global Id from.\n *\n * Return:\n *   The entity gloabl Id wrapped as a :c:type:`z_entity_global_global_id_t`.\n */\nz_entity_global_id_t z_querier_id(const z_loaned_querier_t *querier);\n#endif\n\n#if Z_FEATURE_MATCHING == 1\n/**\n * Declares a matching listener, registering a callback for notifying queryables matching the given querier key\n * expression and target. The callback will be run in the background until the corresponding querier is dropped.\n *\n * Parameters:\n *   querier: A querier to associate with matching listener.\n *   callback: A closure that will be called every time the matching status of the querier changes (If last\n *             queryable disconnects or when the first queryable connects).\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_querier_declare_background_matching_listener(const z_loaned_querier_t *querier,\n                                                          z_moved_closure_matching_status_t *callback);\n/**\n * Constructs matching listener, registering a callback for notifying queryables matching with a given querier's\n * key expression and target.\n *\n * Parameters:\n *   querier: A querier to associate with matching listener.\n *   matching_listener: An uninitialized memory location where matching listener will be constructed. The matching\n *                      listener's callback will be automatically dropped when the querier is dropped.\n *   callback: A closure that will be called every time the matching status of the querier changes (If last\n *             queryable disconnects or when the first queryable connects).\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_querier_declare_matching_listener(const z_loaned_querier_t *querier,\n                                               z_owned_matching_listener_t *matching_listener,\n                                               z_moved_closure_matching_status_t *callback);\n/**\n * Gets querier matching status - i.e. if there are any queryables matching its key expression and target.\n *\n * Return:\n *   ``0`` if put operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_querier_get_matching_status(const z_loaned_querier_t *querier, z_matching_status_t *matching_status);\n\n#endif  // Z_FEATURE_MATCHING == 1\n\n/**\n * Checks if queryable answered with an OK, which allows this value to be treated as a sample.\n *\n * Parameters:\n *   reply: Pointer to a :c:type:`z_loaned_reply_t` to check.\n *\n * Return:\n *   ``true`` if queryable answered with an OK, ``false`` otherwise.\n */\nbool z_reply_is_ok(const z_loaned_reply_t *reply);\n\n/**\n * Gets the content of an OK reply.\n *\n * You should always make sure that :c:func:`z_reply_is_ok` returns ``true`` before calling this function.\n *\n * Parameters:\n *   reply: Pointer to a :c:type:`z_loaned_reply_t` to get content from.\n *\n * Return:\n *   The OK reply content wrapped as a :c:type:`z_loaned_sample_t`.\n */\nconst z_loaned_sample_t *z_reply_ok(const z_loaned_reply_t *reply);\n\n/**\n * Gets the contents of an error reply.\n *\n * You should always make sure that :c:func:`z_reply_is_ok` returns ``false`` before calling this function.\n *\n * Parameters:\n *   reply: Pointer to a :c:type:`z_loaned_reply_t` to get content from.\n *\n * Return:\n *   The error reply content wrapped as a :c:type:`z_loaned_reply_err_t`.\n */\nconst z_loaned_reply_err_t *z_reply_err(const z_loaned_reply_t *reply);\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * Gets the id of the zenoh instance that answered this Reply.\n *\n * Parameters:\n *   reply: Pointer to a :c:type:`z_loaned_reply_t` to get content from.\n *\n * Return:\n * \t `true` if id is present\n */\nbool z_reply_replier_id(const z_loaned_reply_t *reply, z_entity_global_id_t *out_id);\n#endif  // Z_FEATURE_UNSTABLE_API\n\n#endif  // Z_FEATURE_QUERY == 1\n\n#if Z_FEATURE_QUERYABLE == 1\n/**\n * Builds a :c:type:`z_queryable_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_queryable_options_t`.\n */\nvoid z_queryable_options_default(z_queryable_options_t *options);\n\n/**\n * Declares a queryable for a given keyexpr.\n * Note that dropping queryable drops its callback.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the subscriber through.\n *   queryable: Pointer to an uninitialized :c:type:`z_owned_queryable_t` to contain the queryable.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the subscriber with.\n *   callback: Pointer to a :c:type:`z_owned_closure_query_t` callback.\n *   options: Pointer to a :c:type:`z_queryable_options_t` to configure the declare.\n *\n * Return:\n *   ``0`` if declare operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_declare_queryable(const z_loaned_session_t *zs, z_owned_queryable_t *queryable,\n                               const z_loaned_keyexpr_t *keyexpr, z_moved_closure_query_t *callback,\n                               const z_queryable_options_t *options);\n\n/**\n * Undeclares the queryable.\n *\n * Parameters:\n *   pub: Moved :c:type:`z_owned_queryable_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n */\nz_result_t z_undeclare_queryable(z_moved_queryable_t *pub);\n\n/**\n * Declares a background queryable for a given keyexpr. The queryable callback will be called\n * to proccess incoming queries until the corresponding session is closed or dropped.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the subscriber through.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the subscriber with.\n *   callback: Pointer to a :c:type:`z_owned_closure_query_t` callback.\n *   options: Pointer to a :c:type:`z_queryable_options_t` to configure the declare.\n *\n * Return:\n *   ``0`` if declare operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_declare_background_queryable(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                          z_moved_closure_query_t *callback, const z_queryable_options_t *options);\n\n/**\n * Builds a :c:type:`z_query_reply_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_query_reply_options_t`.\n */\nvoid z_query_reply_options_default(z_query_reply_options_t *options);\n\n/**\n * Sends a reply to a query.\n *\n * This function must be called inside of a :c:type:`z_owned_closure_query_t` callback associated to the\n * :c:type:`z_owned_queryable_t`, passing the received query as parameters of the callback function. This function can\n * be called multiple times to send multiple replies to a query. The reply will be considered complete when the callback\n * returns.\n *\n * Parameters:\n *   query: Pointer to a :c:type:`z_loaned_query_t` to reply.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the reply with.\n *   payload: Pointer to the reply data.\n *   options: Pointer to a :c:type:`z_query_reply_options_t` to configure the reply.\n *\n * Return:\n *   ``0`` if reply operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_query_reply(const z_loaned_query_t *query, const z_loaned_keyexpr_t *keyexpr, z_moved_bytes_t *payload,\n                         const z_query_reply_options_t *options);\n\nz_result_t _z_query_reply_sample(const z_loaned_query_t *query, z_loaned_sample_t *sample,\n                                 const z_query_reply_options_t *options);\n\nz_result_t z_query_take_from_loaned(z_owned_query_t *dst, z_loaned_query_t *src);\n\n/**\n * Builds a :c:type:`z_query_reply_del_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_query_reply_del_options_t`.\n */\nvoid z_query_reply_del_options_default(z_query_reply_del_options_t *options);\n\n/**\n * Sends a reply delete to a query.\n *\n * This function must be called inside of a :c:type:`z_owned_closure_query_t` callback associated to the\n * :c:type:`z_owned_queryable_t`, passing the received query as parameters of the callback function. This function can\n * be called multiple times to send multiple replies to a query. The reply will be considered complete when the callback\n * returns.\n *\n * Parameters:\n *   query: Pointer to a :c:type:`z_loaned_query_t` to reply.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the reply with.\n *   options: Pointer to a :c:type:`z_query_reply_del_options_t` to configure the reply.\n *\n * Return:\n *   ``0`` if reply operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_query_reply_del(const z_loaned_query_t *query, const z_loaned_keyexpr_t *keyexpr,\n                             const z_query_reply_del_options_t *options);\n\n/**\n * Builds a :c:type:`z_query_reply_err_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_query_reply_err_options_t`.\n */\nvoid z_query_reply_err_options_default(z_query_reply_err_options_t *options);\n\n/**\n * Sends a reply error to a query.\n *\n * This function must be called inside of a :c:type:`z_owned_closure_query_t` callback associated to the\n * :c:type:`z_owned_queryable_t`, passing the received query as parameters of the callback function. This function can\n * be called multiple times to send multiple replies to a query. The reply will be considered complete when the callback\n * returns.\n *\n * Parameters:\n *   query: Pointer to a :c:type:`z_loaned_query_t` to reply.\n *   payload: Moved reply error data payload.\n *   options: Pointer to a :c:type:`z_query_reply_err_options_t` to configure the reply error.\n *\n * Return:\n *   ``0`` if reply operation is successful, ``negative value`` otherwise.\n */\nz_result_t z_query_reply_err(const z_loaned_query_t *query, z_moved_bytes_t *payload,\n                             const z_query_reply_err_options_t *options);\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n/**\n * Gets the entity global Id from a queryable.\n *\n * Parameters:\n *   publisher: Pointer to a :c:type:`z_loaned_queryable_t` to get the entity global Id from.\n *\n * Return:\n *   The entity gloabl Id wrapped as a :c:type:`z_loaned_queryable_t`.\n */\nz_entity_global_id_t z_queryable_id(const z_loaned_queryable_t *queryable);\n#endif\n\n/**\n * Gets the keyexpr from a queryable.\n *\n * Parameters:\n *   queryable: Pointer to a :c:type:`z_loaned_queryable_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a :c:type:`z_loaned_keyexpr_t`. Will return NULL if\n *   corresponding session is closed or dropped.\n *   The lifetime of key expression pointer is bound to those of queryable and its session.\n */\nconst z_loaned_keyexpr_t *z_queryable_keyexpr(const z_loaned_queryable_t *queryable);\n\n#endif\n\n/**\n * Builds a new keyexpr.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t` to store the keyexpr.\n *   name: Pointer to the null-terminated string of the keyexpr.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_from_str(z_owned_keyexpr_t *keyexpr, const char *name);\n\n/**\n * Builds a new keyexpr from a substring.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t` to store the keyexpr.\n *   name: Pointer to the start of the substring for keyxpr.\n *   len: Length of the substring to consider.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_from_substr(z_owned_keyexpr_t *keyexpr, const char *name, size_t len);\n\n/**\n * Builds a :c:type:`z_owned_keyexpr_t` from a null-terminated string with auto canonization.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t`.\n *   name: Pointer to string representation of the keyexpr as a null terminated string.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_from_str_autocanonize(z_owned_keyexpr_t *keyexpr, const char *name);\n\n/**\n * Builds a :c:type:`z_owned_keyexpr_t` from a substring with auto canonization.\n *\n * Parameters:\n *   keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t` to store the keyexpr.\n *   name: Pointer to the start of the substring for keyexpr.\n *   len: Length of the substring to consider. After the function return it will be equal to the canonized key\n *     expression string length.\n *\n * Return:\n *   ``0`` if creation is successful, ``negative value`` otherwise.\n */\nz_result_t z_keyexpr_from_substr_autocanonize(z_owned_keyexpr_t *keyexpr, const char *name, size_t *len);\n\n/**\n * Declares a keyexpr, so that it is mapped on a numerical id.\n *\n * This numerical id is used on the network to save bandwidth and ease the retrieval of the concerned resource\n * in the routing tables.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the keyexpr through.\n *   declared_keyexpr: Pointer to an uninitialized :c:type:`z_owned_keyexpr_t` to contain the declared keyexpr.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the keyexpr with.\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n */\nz_result_t z_declare_keyexpr(const z_loaned_session_t *zs, z_owned_keyexpr_t *declared_keyexpr,\n                             const z_loaned_keyexpr_t *keyexpr);\n\n/**\n * Undeclares a keyexpr.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to undeclare the data through.\n *   keyexpr: Moved :c:type:`z_owned_keyexpr_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n */\nz_result_t z_undeclare_keyexpr(const z_loaned_session_t *zs, z_moved_keyexpr_t *keyexpr);\n\n/**\n * Constructs a new empty string array.\n *\n * Parameters:\n *   a: Pointer to an uninitialized :c:type:`z_owned_string_array_t` to store the array of strings.\n */\nvoid z_string_array_new(z_owned_string_array_t *a);\n\n/**\n * Appends specified value to the end of the string array by alias.\n *\n * Parameters:\n *   a: Pointer to :c:type:`z_loaned_string_array_t`.\n *   value: Pointer to the string to be added.\n *\n * Return:\n *   The new length of the array.\n */\nsize_t z_string_array_push_by_alias(z_loaned_string_array_t *a, const z_loaned_string_t *value);\n\n/**\n * Appends specified value to the end of the string array by copying.\n *\n * Parameters:\n *   a: Pointer to :c:type:`z_loaned_string_array_t`.\n *   value: Pointer to the string to be added.\n *\n * Return:\n *   The new length of the array.\n */\nsize_t z_string_array_push_by_copy(z_loaned_string_array_t *a, const z_loaned_string_t *value);\n\n/**\n * Returns the value at the position of index in the string array.\n *\n * Parameters:\n *   a: Pointer to :c:type:`z_loaned_string_array_t`.\n *   k: index value.\n *\n * Return:\n *   `NULL` if the index is out of bounds.\n */\nconst z_loaned_string_t *z_string_array_get(const z_loaned_string_array_t *a, size_t k);\n\n/**\n * Returns the number of elements in the array.\n */\nsize_t z_string_array_len(const z_loaned_string_array_t *a);\n\n/**\n * Returns ``true`` if the array is empty, ``false`` otherwise.\n */\nbool z_string_array_is_empty(const z_loaned_string_array_t *a);\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n/**\n * Builds a :c:type:`z_subscriber_options_t` with default values.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`z_subscriber_options_t`.\n */\nvoid z_subscriber_options_default(z_subscriber_options_t *options);\n\n/**\n * Declares a subscriber for a given keyexpr.\n * Note that dropping subscriber drops its callback.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the subscriber through.\n *   sub: Pointer to a :c:type:`z_owned_subscriber_t` to contain the subscriber.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the subscriber with.\n *   callback: Pointer to a`z_owned_closure_sample_t` callback.\n *   options: Pointer to a :c:type:`z_subscriber_options_t` to configure the operation\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n */\nz_result_t z_declare_subscriber(const z_loaned_session_t *zs, z_owned_subscriber_t *sub,\n                                const z_loaned_keyexpr_t *keyexpr, z_moved_closure_sample_t *callback,\n                                const z_subscriber_options_t *options);\n\n/**\n * Undeclares the subscriber.\n *\n * Parameters:\n *   pub: Moved :c:type:`z_owned_subscriber_t` to undeclare.\n *\n * Return:\n *   ``0`` if undeclare is successful, ``negative value`` otherwise.\n */\nz_result_t z_undeclare_subscriber(z_moved_subscriber_t *pub);\n\n/**\n * Declares a background subscriber for a given keyexpr. Subscriber callback will be called to process the messages,\n * until the corresponding session is closed or dropped.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to declare the subscriber through.\n *   keyexpr: Pointer to a :c:type:`z_loaned_keyexpr_t` to bind the subscriber with.\n *   callback: Pointer to a`z_owned_closure_sample_t` callback.\n *   options: Pointer to a :c:type:`z_subscriber_options_t` to configure the operation\n *\n * Return:\n *   ``0`` if declare is successful, ``negative value`` otherwise.\n */\nz_result_t z_declare_background_subscriber(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                           z_moved_closure_sample_t *callback, const z_subscriber_options_t *options);\n\n/**\n * Gets the keyexpr from a subscriber.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`z_loaned_subscriber_t` to get the keyexpr from.\n *\n * Return:\n *   The keyexpr wrapped as a :c:type:`z_loaned_keyexpr_t`. Will return `NULL` if corresponding session\n *   is closed or dropped.\n *   The lifetime of key expression pointer is bound to those of subscriber and its session.\n */\nconst z_loaned_keyexpr_t *z_subscriber_keyexpr(const z_loaned_subscriber_t *subscriber);\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n/**\n * Gets the entity global Id from a subscriber.\n *\n * Parameters:\n *   subscriber: Pointer to a :c:type:`z_loaned_subscriber_t` to get the entity global Id from.\n *\n * Return:\n *   The entity gloabl Id wrapped as a :c:type:`z_entity_global_global_id_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_entity_global_id_t z_subscriber_id(const z_loaned_subscriber_t *subscriber);\n#endif\n#endif\n\n#if Z_FEATURE_BATCHING == 1\n\n/**\n * Activate the batching mechanism, any message that would have been sent on the network by a subsequent api call (e.g\n * z_put, z_get) will be instead stored until either: the batch is full, flushed with :c:func:`zp_batch_flush`, batching\n * is stopped with :c:func:`zp_batch_stop`, a message needs to be sent immediately.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` that will start batching messages.\n *\n * Return:\n *   ``0`` if batching started, ``negative value`` otherwise.\n */\nz_result_t zp_batch_start(const z_loaned_session_t *zs);\n\n/**\n * Send the currently batched messages on the network.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` that will send its batched messages.\n *\n * Return:\n *   ``0`` if batch successfully sent, ``negative value`` otherwise.\n */\nz_result_t zp_batch_flush(const z_loaned_session_t *zs);\n\n/**\n * Deactivate the batching mechanism and send the currently batched on the network.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` that will stop batching messages.\n *\n * Return:\n *   ``0`` if batching stopped and batch successfully sent, ``negative value`` otherwise.\n */\nz_result_t zp_batch_stop(const z_loaned_session_t *zs);\n#endif\n#if Z_FEATURE_MULTI_THREAD == 1 || defined(SPHINX_DOCS)\n/************* Multi Thread Tasks helpers **************/\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`zp_task_read_options_t`.\n */\nvoid zp_task_read_options_default(zp_task_read_options_t *options);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to start the task from.\n *   options: Pointer to a :c:type:`zp_task_read_options_t` to configure the task.\n *\n * Return:\n *   ``0`` if task started successfully, ``negative value`` otherwise.\n */\nz_result_t zp_start_read_task(z_loaned_session_t *zs, const zp_task_read_options_t *options);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to stop the task from.\n *\n * Return:\n *   ``0`` if task stopped successfully, ``negative value`` otherwise.\n */\nz_result_t zp_stop_read_task(z_loaned_session_t *zs);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n */\nbool zp_read_task_is_running(const z_loaned_session_t *zs);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`zp_task_lease_options_t`.\n */\nvoid zp_task_lease_options_default(zp_task_lease_options_t *options);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to start the task from.\n *   options: Pointer to a :c:type:`zp_task_lease_options_t` to configure the task.\n *\n * Return:\n *   ``0`` if task started successfully, ``negative value`` otherwise.\n */\nz_result_t zp_start_lease_task(z_loaned_session_t *zs, const zp_task_lease_options_t *options);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to stop the task from.\n *\n * Return:\n *   ``0`` if task stopped successfully, ``negative value`` otherwise.\n */\nz_result_t zp_stop_lease_task(z_loaned_session_t *zs);\n\n/**\n * Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started automatically when session is\n * created.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n */\nbool zp_lease_task_is_running(const z_loaned_session_t *zs);\n#endif\n#if Z_FEATURE_MULTI_THREAD == 0 || defined(SPHINX_DOCS)\n/************* Single Thread helpers **************/\n/**\n * Deprecated, please use :c:func:`zp_spin_once` instead, which will run a single pending zenoh task\n * (including read, lease, keep alive, accept, connect, etc...) from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`zp_read_options_t`.\n */\nvoid zp_read_options_default(zp_read_options_t *options);\n\n/**\n * Deprecated, please use :c:func:`zp_spin_once` instead, which will run a single pending zenoh task\n * (including read, lease, keep alive, accept, connect, etc...) from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to execute the read for.\n *   options: Pointer to a :c:type:`zp_read_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n */\nz_result_t zp_read(const z_loaned_session_t *zs, const zp_read_options_t *options);\n\n/**\n * Deprecated, please use :c:func:`zp_spin_once` instead, which will run a single pending zenoh task\n * (including read, lease, keep alive, accept, connect, etc...) from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`zp_send_keep_alive_options_t`.\n */\nvoid zp_send_keep_alive_options_default(zp_send_keep_alive_options_t *options);\n\n/**\n * Deprecated, please use :c:func:`zp_spin_once` instead, which will run a single pending zenoh task\n * (including read, lease, keep alive, accept, connect, etc...) from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to execute the send for.\n *   options: Pointer to a :c:type:`zp_send_keep_alive_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n */\nz_result_t zp_send_keep_alive(const z_loaned_session_t *zs, const zp_send_keep_alive_options_t *options);\n\n/**\n * Deprecated, please use :c:func:`zp_spin_once` instead, which will run a single pending zenoh task\n * (including read, lease, keep alive, accept, connect, etc...) from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   options: Pointer to an uninitialized :c:type:`zp_send_join_options_t`.\n */\nvoid zp_send_join_options_default(zp_send_join_options_t *options);\n\n/**\n * Deprecated, please use :c:func:`zp_spin_once` instead, which will run a single pending zenoh task\n * (including read, lease, keep alive, accept, connect, etc...) from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to execute the send for.\n *   options: Pointer to a :c:type:`zp_send_keep_alive_options_t` to configure the operation.\n *\n * Return:\n *   ``0`` if execution was successful, ``negative value`` otherwise.\n */\nz_result_t zp_send_join(const z_loaned_session_t *zs, const zp_send_join_options_t *options);\n\n/**\n * Spins zenoh executor once, executing a single pending task (such as read, lease, keep alive, accept, connect, etc...)\n * from the task queue.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n *\n * Parameters:\n *   zs: Pointer to a :c:type:`z_loaned_session_t` to spin executor for.\n */\nvoid zp_spin_once(const z_loaned_session_t *zs);\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * Gets the default reliability value (unstable).\n *\n * Return:\n *   The reliability wrapped as a :c:type:`z_reliability_t`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_reliability_t z_reliability_default(void);\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_QUERY == 1\n/**\n * Construct a new cancellation token. Can be used to interrupt get operations.  (unstable).\n *\n * Parameters:\n *   cancellation_token: Pointer to an uninitialized :c:type:`z_owned_cancellation_token_t`.\n *\n * Return:\n *   ``0`` if creation successful, ``negative value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t z_cancellation_token_new(z_owned_cancellation_token_t *cancellation_token);\n\n/**\n * Interrupt all currently running get calls, to which clones of the token were passed.  (unstable).\n *\n * Parameters:\n *   cancellation_token: Pointer to token to cancel.\n *\n * Return:\n *   ``0`` in case of success (in this case all pending operations are guaranteed to be cancelled or terminated),\n * ``negative error value`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nz_result_t z_cancellation_token_cancel(z_loaned_cancellation_token_t *cancellation_token);\n\n/**\n * Verify if token was cancelled  (unstable).\n *\n * Parameters:\n *   cancellation_token: Pointer to cancellation token.\n *\n * Return:\n *   ``true`` if token was cancelled (i.e if :c:func:`z_cancellation_token_cancel` was called on it or one of its\n * clones), ``false`` otherwise.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\nbool z_cancellation_token_is_cancelled(const z_loaned_cancellation_token_t *cancellation_token);\n#endif\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_API_PRIMITIVES_H */\n"
  },
  {
    "path": "include/zenoh-pico/api/serialization.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_API_SERIALIZATION_H\n#define INCLUDE_ZENOH_PICO_API_SERIALIZATION_H\n\n#include \"olv_macros.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Represents a reader for serialized data.\n */\ntypedef struct ze_deserializer_t {\n    z_bytes_reader_t _reader;\n} ze_deserializer_t;\n\ntypedef struct _ze_serializer_t {\n    _z_bytes_writer_t _writer;\n} _ze_serializer_t;\n\n/**\n * Represents a writer for serialized data.\n */\n_Z_OWNED_TYPE_VALUE_PREFIX(ze, _ze_serializer_t, serializer)\n\n/**\n * Constructs an empty serializer.\n *\n * Parameters:\n *   serializer: An uninitialized memory location where serializer is to be constructed.\n *\n * Return:\n *   ``0`` in case of success, ``negative value`` otherwise.\n */\nz_result_t ze_serializer_empty(ze_owned_serializer_t *serializer);\n\n/**\n * Finishes serialization and returns underlying bytes.\n *\n * Parameters:\n *   serializer: A data serializer.\n *   bytes: An uninitialized memory location where bytes is to be constructed.\n */\nvoid ze_serializer_finish(ze_moved_serializer_t *serializer, z_owned_bytes_t *bytes);\n\n/**\n * Returns a deserializer for :c:type:`z_loaned_bytes_t`.\n *\n * The `bytes` should outlive the reader and should not be modified, while reader is in use.\n *\n * Parameters:\n *   bytes: Data to deserialize.\n *\n * Return:\n *   The constructed :c:type:`ze_deserializer_t`.\n */\nze_deserializer_t ze_deserializer_from_bytes(const z_loaned_bytes_t *bytes);\n\n/**\n * Checks if deserializer parsed all of its data.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *\n * Return:\n *   ``True`` if there is no more data to parse, ``false`` otherwise.\n */\nbool ze_deserializer_is_done(const ze_deserializer_t *deserializer);\n\n/**\n * Writes a serialized `uint8_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `uint8_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_uint8(ze_loaned_serializer_t *serializer, uint8_t val) {\n    return z_bytes_writer_write_all(&serializer->_writer, &val, 1);\n}\n\n/**\n * Writes a serialized `uint16_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `uint16_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_uint16(ze_loaned_serializer_t *serializer, uint16_t val) {\n    _z_host_le_store16(val, (uint8_t *)&val);\n    return z_bytes_writer_write_all(&serializer->_writer, (uint8_t *)&val, sizeof(val));\n}\n\n/**\n * Writes a serialized `uint32_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `uint32_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_uint32(ze_loaned_serializer_t *serializer, uint32_t val) {\n    _z_host_le_store32(val, (uint8_t *)&val);\n    return z_bytes_writer_write_all(&serializer->_writer, (uint8_t *)&val, sizeof(val));\n}\n\n/**\n * Writes a serialized `uint64_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `uint64_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_uint64(ze_loaned_serializer_t *serializer, uint64_t val) {\n    _z_host_le_store64(val, (uint8_t *)&val);\n    return z_bytes_writer_write_all(&serializer->_writer, (uint8_t *)&val, sizeof(val));\n}\n\n/**\n * Writes a serialized `float` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `float` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_float(ze_loaned_serializer_t *serializer, float val) {\n    return z_bytes_writer_write_all(&serializer->_writer, (uint8_t *)&val, sizeof(val));\n}\n\n/**\n * Writes a serialized `double` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `double` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_double(ze_loaned_serializer_t *serializer, double val) {\n    return z_bytes_writer_write_all(&serializer->_writer, (uint8_t *)&val, sizeof(val));\n}\n\n/**\n * Writes a serialized 'bool' into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `bool` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_bool(ze_loaned_serializer_t *serializer, bool val) {\n    return ze_serializer_serialize_uint8(serializer, val ? 1 : 0);\n}\n\n/**\n * Writes a serialized `int8_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `int8_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_int8(ze_loaned_serializer_t *serializer, int8_t val) {\n    return ze_serializer_serialize_uint8(serializer, (uint8_t)val);\n}\n\n/**\n * Writes a serialized `int16_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `int16_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_int16(ze_loaned_serializer_t *serializer, int16_t val) {\n    return ze_serializer_serialize_uint16(serializer, (uint16_t)val);\n}\n\n/**\n * Writes a serialized `int32_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `int32_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_int32(ze_loaned_serializer_t *serializer, int32_t val) {\n    return ze_serializer_serialize_uint32(serializer, (uint32_t)val);\n}\n\n/**\n * Writes a serialized `int64_t` into underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: `int64_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_serializer_serialize_int64(ze_loaned_serializer_t *serializer, int64_t val) {\n    return ze_serializer_serialize_uint64(serializer, (uint64_t)val);\n}\n\n/**\n * Deserializes next portion of data into a `uint8_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `uint8_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_uint8(ze_deserializer_t *deserializer, uint8_t *val) {\n    if (z_bytes_reader_read(&deserializer->_reader, val, 1) != 1) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `uint16_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `uint16_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_uint16(ze_deserializer_t *deserializer, uint16_t *val) {\n    if (z_bytes_reader_read(&deserializer->_reader, (uint8_t *)val, sizeof(uint16_t)) != sizeof(uint16_t)) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    *val = _z_host_le_load16((const uint8_t *)val);\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `uint32_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `uint32_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_uint32(ze_deserializer_t *deserializer, uint32_t *val) {\n    if (z_bytes_reader_read(&deserializer->_reader, (uint8_t *)val, sizeof(uint32_t)) != sizeof(uint32_t)) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    *val = _z_host_le_load32((uint8_t *)val);\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `uint64_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `uint64_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_uint64(ze_deserializer_t *deserializer, uint64_t *val) {\n    if (z_bytes_reader_read(&deserializer->_reader, (uint8_t *)val, sizeof(uint64_t)) != sizeof(uint64_t)) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    *val = _z_host_le_load64((uint8_t *)val);\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `float`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `float` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_float(ze_deserializer_t *deserializer, float *val) {\n    if (z_bytes_reader_read(&deserializer->_reader, (uint8_t *)val, sizeof(float)) != sizeof(float)) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `double`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `double` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_double(ze_deserializer_t *deserializer, double *val) {\n    if (z_bytes_reader_read(&deserializer->_reader, (uint8_t *)val, sizeof(double)) != sizeof(double)) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `bool`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `bool` to contain the deserialized value.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_bool(ze_deserializer_t *deserializer, bool *val) {\n    uint8_t res;\n    _Z_RETURN_IF_ERR(ze_deserializer_deserialize_uint8(deserializer, &res));\n    if (res > 1) {\n        return Z_EDESERIALIZE;\n    }\n    *val = (res == 1);\n    return _Z_RES_OK;\n}\n\n/**\n * Deserializes next portion of data into a `int8_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `int8_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_int8(ze_deserializer_t *deserializer, int8_t *val) {\n    return ze_deserializer_deserialize_uint8(deserializer, (uint8_t *)val);\n}\n\n/**\n * Deserializes next portion of data into a `int16_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `int16_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_int16(ze_deserializer_t *deserializer, int16_t *val) {\n    return ze_deserializer_deserialize_uint16(deserializer, (uint16_t *)val);\n}\n\n/**\n * Deserializes next portion of data into a `int32_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `int32_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_int32(ze_deserializer_t *deserializer, int32_t *val) {\n    return ze_deserializer_deserialize_uint32(deserializer, (uint32_t *)val);\n}\n\n/**\n * Deserializes next portion of data into a `int64_t`.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   dst: Pointer to an uninitialized `int64_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nstatic inline z_result_t ze_deserializer_deserialize_int64(ze_deserializer_t *deserializer, int64_t *val) {\n    return ze_deserializer_deserialize_uint64(deserializer, (uint64_t *)val);\n}\n\n/**\n * Serializes array of bytes and writes it into an underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: Pointer to the data to serialize.\n *   len: Number of bytes to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serializer_serialize_buf(ze_loaned_serializer_t *serializer, const uint8_t *val, size_t len);\n\n/**\n * Serializes slice and writes it into an underlying :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: A slice to serialize.\n *   len: Number of bytes to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serializer_serialize_slice(ze_loaned_serializer_t *serializer, const z_loaned_slice_t *val);\n\n/**\n * Deserializes next portion of data and advances the reader position.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   val: Pointer to an uninitialized :c:type:`z_owned_slice_t` to contain the deserialized slice.\n *\n * Return:\n *   ``0`` if deserialization is successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserializer_deserialize_slice(ze_deserializer_t *deserializer, z_owned_slice_t *val);\n\n/**\n * Serializes a null-terminated string and writes it into an underlying :c:type:`z_owned_bytes_t`.\n * The string should be a valid UTF-8.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: Pointer to the string to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serializer_serialize_str(ze_loaned_serializer_t *serializer, const char *val);\n\n/**\n * Serializes a substring and writes it into an underlying :c:type:`z_owned_bytes_t`.\n * The substring should be a valid UTF-8.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   start: Pointer to the start of the substring to serialize.\n *   len: Length of the substring to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serializer_serialize_substr(ze_loaned_serializer_t *serializer, const char *start, size_t len);\n\n/**\n * Serializes a string and writes it into an underlying :c:type:`z_owned_bytes_t`.\n * The string should be a valid UTF-8.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   val: Pointer to the string to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serializer_serialize_string(ze_loaned_serializer_t *serializer, const z_loaned_string_t *val);\n\n/**\n * Deserializes next portion of data and advances the reader position.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   val: Pointer to an uninitialized :c:type:`z_owned_string_t` to contain the deserialized string.\n *\n * Return:\n *   ``0`` if deserialization is successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserializer_deserialize_string(ze_deserializer_t *deserializer, z_owned_string_t *val);\n\n/**\n * Initiate serialization of a sequence of multiple elements.\n *\n * Parameters:\n *   serializer: A serializer instance.\n *   len: Length of the sequence. Could be read during deserialization using\n *     :c:func:`ze_deserializer_deserialize_sequence_length`.\n *\n * Return:\n *   ``0`` if deserialization is successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_serializer_serialize_sequence_length(ze_loaned_serializer_t *serializer, size_t len);\n\n/**\n * Initiate deserialization of a sequence of multiple elements.\n *\n * Parameters:\n *   deserializer: A deserializer instance.\n *   len: A pointer where the length of the sequence (previously passed via\n *     :c:func:`ze_serializer_serialize_sequence_length`) will be written.\n *\n * Return:\n *   ``0`` if deserialization is successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserializer_deserialize_sequence_length(ze_deserializer_t *deserializer, size_t *len);\n\n/**\n * Serializes data into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized data.\n *   data: Pointer to the data to serialize.\n *   len: Number of bytes to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_buf(z_owned_bytes_t *bytes, const uint8_t *data, size_t len);\n\n/**\n * Serializes a string into a :c:type:`z_owned_bytes_t`.\n *\n * The string should be a valid UTF-8.\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized string.\n *   s: Pointer to the string to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_string(z_owned_bytes_t *bytes, const z_loaned_string_t *s);\n\n/**\n * Serializes a null-terminated string into a :c:type:`z_owned_bytes_t`.\n * The string should be a valid UTF-8.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized string.\n *   value: Pointer to the string to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_str(z_owned_bytes_t *bytes, const char *value);\n\n/**\n * Serializes a substring into a :c:type:`z_owned_bytes_t`.\n * The substring should be a valid UTF-8.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized string.\n *   start: Pointer to the the start of string to serialize.\n *   len: Length of the substring to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_substr(z_owned_bytes_t *bytes, const char *start, size_t len);\n\n/**\n * Serializes a slice into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized slice.\n *   slice: Pointer to the slice to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_slice(z_owned_bytes_t *bytes, const z_loaned_slice_t *slice);\n\n/**\n * Serializes a `int8_t` into a :c:type:`z_owned_bytes_t` .\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `int8_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_int8(z_owned_bytes_t *bytes, int8_t val);\n\n/**\n * Serializes a `int16_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `int16_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_int16(z_owned_bytes_t *bytes, int16_t val);\n\n/**\n * Serializes a `int32_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `int32_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_int32(z_owned_bytes_t *bytes, int32_t val);\n\n/**\n * Serializes a `int64_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `int64_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_int64(z_owned_bytes_t *bytes, int64_t val);\n\n/**\n * Serializes a `uint8_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `uint8_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_uint8(z_owned_bytes_t *bytes, uint8_t val);\n\n/**\n * Serializes a `uint16_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `uint16_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_uint16(z_owned_bytes_t *bytes, uint16_t val);\n\n/**\n * Serializes a `uint32_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `uint32_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_uint32(z_owned_bytes_t *bytes, uint32_t val);\n\n/**\n * Serializes a `uint64_t` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `uint64_t` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_uint64(z_owned_bytes_t *bytes, uint64_t val);\n\n/**\n * Serializes a `float` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `float` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_float(z_owned_bytes_t *bytes, float val);\n\n/**\n * Serializes a `double` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `double` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_double(z_owned_bytes_t *bytes, double val);\n\n/**\n * Serializes a `bool` into a :c:type:`z_owned_bytes_t`.\n *\n * Parameters:\n *   bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the serialized int.\n *   val: `bool` value to serialize.\n *\n * Return:\n *   ``0`` if serialization is successful, ``negative value`` otherwise.\n */\nz_result_t ze_serialize_bool(z_owned_bytes_t *bytes, bool val);\n\n/**\n * Deserializes data into a :c:type:`z_owned_slice_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   str: Pointer to an uninitialized :c:type:`z_owned_slice_t` to contain the deserialized slice.\n *\n * Return:\n *   ``0`` if deserialization is successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_slice(const z_loaned_bytes_t *bytes, z_owned_slice_t *dst);\n\n/**\n * Deserializes data into a :c:type:`z_owned_string_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   str: Pointer to an uninitialized :c:type:`z_owned_string_t` to contain the deserialized string.\n *\n * Return:\n *   ``0`` if deserialization is successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_string(const z_loaned_bytes_t *bytes, z_owned_string_t *str);\n\n/**\n * Deserializes data into a `int8_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `int8_t` to contain the deserialized.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_int8(const z_loaned_bytes_t *bytes, int8_t *dst);\n\n/**\n * Deserializes data into a `int16_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `int16_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_int16(const z_loaned_bytes_t *bytes, int16_t *dst);\n\n/**\n * Deserializes data into a `int32_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `int32_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_int32(const z_loaned_bytes_t *bytes, int32_t *dst);\n\n/**\n * Deserializes data into a `int64_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `int64_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_int64(const z_loaned_bytes_t *bytes, int64_t *dst);\n\n/**\n * Deserializes data into a `uint8_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `uint8_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_uint8(const z_loaned_bytes_t *bytes, uint8_t *dst);\n\n/**\n * Deserializes data into a `uint16_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `uint16_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_uint16(const z_loaned_bytes_t *bytes, uint16_t *dst);\n\n/**\n * Deserializes data into a `uint32_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `uint32_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_uint32(const z_loaned_bytes_t *bytes, uint32_t *dst);\n\n/**\n * Deserializes data into a `uint64_t`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `uint64_t` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_uint64(const z_loaned_bytes_t *bytes, uint64_t *dst);\n\n/**\n * Deserializes data into a `float`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `float` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_float(const z_loaned_bytes_t *bytes, float *dst);\n\n/**\n * Deserializes data into a `double`.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `double` to contain the deserialized number.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_double(const z_loaned_bytes_t *bytes, double *dst);\n\n/**\n * Deserializes data into a boolean.\n *\n * Parameters:\n *   bytes: Pointer to a :c:type:`z_loaned_bytes_t` to deserialize.\n *   dst: Pointer to an uninitialized `bool` to contain the deserialized value.\n *\n * Return:\n *   ``0`` if deserialization successful, or a ``negative value`` otherwise.\n */\nz_result_t ze_deserialize_bool(const z_loaned_bytes_t *bytes, bool *dst);\n\n_Z_OWNED_FUNCTIONS_NO_COPY_DEF_PREFIX(ze, serializer)\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/api/types.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n//\n#ifndef INCLUDE_ZENOH_PICO_API_TYPES_H\n#define INCLUDE_ZENOH_PICO_API_TYPES_H\n\n#include \"olv_macros.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/net/matching.h\"\n#include \"zenoh-pico/net/publish.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/net/reply.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/net/subscribe.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/cancellation.h\"\n#include \"zenoh-pico/session/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Represents a Zenoh ID.\n *\n * In general, valid Zenoh IDs are LSB-first 128bit unsigned and non-zero integers.\n *\n * Members:\n *   uint8_t id[16]: The array containing the 16 octets of a Zenoh ID.\n */\ntypedef _z_id_t z_id_t;\n\n/**\n *  Represents an ID globally identifying an entity in a Zenoh system.\n */\ntypedef _z_entity_global_id_t z_entity_global_id_t;\n\n/*\n * Represents timestamp value in Zenoh\n */\ntypedef _z_timestamp_t z_timestamp_t;\n\n/**\n * Represents an array of bytes.\n */\n_Z_OWNED_TYPE_VALUE(_z_slice_t, slice)\n_Z_VIEW_TYPE(_z_slice_t, slice)\n\n/**\n * Represents a container for slices.\n */\n_Z_OWNED_TYPE_VALUE(_z_bytes_t, bytes)\n\n/**\n * Represents a writer for data.\n */\n_Z_OWNED_TYPE_VALUE(_z_bytes_writer_t, bytes_writer)\n\n/**\n * A reader for data.\n */\ntypedef _z_bytes_reader_t z_bytes_reader_t;\n\n/**\n * An iterator over slices of data.\n */\ntypedef struct {\n    const _z_bytes_t *_bytes;\n    size_t _slice_idx;\n} z_bytes_slice_iterator_t;\n\n/**\n * Represents a string without null-terminator.\n */\n_Z_OWNED_TYPE_VALUE(_z_string_t, string)\n_Z_VIEW_TYPE(_z_string_t, string)\n\n/**\n * Represents a key expression in Zenoh.\n */\n_Z_OWNED_TYPE_VALUE(_z_declared_keyexpr_t, keyexpr)\n_Z_VIEW_TYPE(_z_declared_keyexpr_t, keyexpr)\n\n/**\n * Represents a Zenoh configuration, used to configure Zenoh sessions upon opening.\n */\n_Z_OWNED_TYPE_VALUE(_z_config_t, config)\n\n/**\n * Represents a Zenoh Session.\n */\n_Z_OWNED_TYPE_RC(_z_session_rc_t, session)\n\n/**\n * Represents a Zenoh Subscriber entity.\n */\n_Z_OWNED_TYPE_VALUE(_z_subscriber_t, subscriber)\n\n/**\n * Represents a Zenoh Publisher entity.\n */\n_Z_OWNED_TYPE_VALUE(_z_publisher_t, publisher)\n\n/**\n * Represents a Zenoh Querier entity.\n */\n_Z_OWNED_TYPE_VALUE(_z_querier_t, querier)\n\n/**\n * Represents a Zenoh Matching listener entity.\n */\n_Z_OWNED_TYPE_VALUE(_z_matching_listener_t, matching_listener)\n\n/**\n * Represents a Zenoh Queryable entity.\n */\n_Z_OWNED_TYPE_VALUE(_z_queryable_t, queryable)\n\n/**\n * Represents a Zenoh Query entity, received by Zenoh Queryable entities.\n */\n_Z_OWNED_TYPE_RC(_z_query_rc_t, query)\n\n/**\n * Represents the encoding of a payload, in a MIME-like format.\n */\n_Z_OWNED_TYPE_VALUE(_z_encoding_t, encoding)\n\n/**\n * Represents a Zenoh reply error.\n */\n_Z_OWNED_TYPE_VALUE(_z_value_t, reply_err)\n\n/**\n * Represents sample source information.\n */\ntypedef _z_source_info_t z_source_info_t;\n\n/**\n * A struct that indicates if there exist Subscribers matching the Publisher's key expression or Queryables matching\n * Querier's key expression and target.\n * Members:\n *   bool matching: true if there exist matching Zenoh entities, false otherwise.\n */\ntypedef _z_matching_status_t z_matching_status_t;\n\n/**\n * Represents the configuration used to configure a subscriber upon declaration :c:func:`z_declare_subscriber`.\n */\ntypedef struct {\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    z_locality_t allowed_origin;\n#else\n    uint8_t __dummy;  // keep struct non-empty when locality is disabled\n#endif\n} z_subscriber_options_t;\n\n/**\n * Represents the configuration used to configure a zenoh session upon opening :c:func:`z_open`.\n *\n * Members:\n *   bool auto_start_read_task: Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are\n * now started automatically when session is created.\n *   bool auto_start_lease_task: Deprecated, if Z_FEATURE_MULTI_THREAD is enabled background tasks are now started\n * automatically when session is created.\n *   z_task_attr_t* executor_task_attributes: the attributes to pass to zenoh session executor thread running read,\n * lease, keep alive, join, connect and other tasks in the background (only when Z_FEATURE_MULTI_THREAD is enabled).\n *   bool auto_start_admin_space: auto-start admin space after ``z_open()`` (default\n * false; only when admin space feature is enabled).\n */\ntypedef struct {\n#if Z_FEATURE_MULTI_THREAD == 1\n    bool auto_start_read_task;\n    bool auto_start_lease_task;\n    z_task_attr_t *executor_task_attributes;\n#endif\n#if (Z_FEATURE_ADMIN_SPACE == 1)\n    bool auto_start_admin_space;\n#endif\n#if Z_FEATURE_ADMIN_SPACE == 0 && (Z_FEATURE_MULTI_THREAD == 0)\n    uint8_t __dummy;  // avoid empty struct\n#endif\n} z_open_options_t;\n\n/**\n * Represents the configuration used to configure a zenoh upon closing :c:func:`z_close`.\n */\ntypedef struct {\n    uint8_t __dummy;  // Just to avoid empty structures that might cause undefined behavior\n} z_close_options_t;\n\n/**\n * Represents the reply consolidation mode to apply on replies to a :c:func:`z_get`.\n *\n * Members:\n *   z_consolidation_mode_t mode: the consolidation mode, see :c:type:`z_consolidation_mode_t`\n */\ntypedef struct {\n    z_consolidation_mode_t mode;\n} z_query_consolidation_t;\n\n/**\n * A cancellation token used to interrupt get requests (unstable).\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\n_Z_OWNED_TYPE_RC(_z_cancellation_token_rc_t, cancellation_token)\n\n/**\n * Represents the configuration used to configure a publisher upon declaration with :c:func:`z_declare_publisher`.\n *\n * Members:\n *   z_moved_encoding_t *encoding: Default encoding for messages put by this publisher.\n *   z_congestion_control_t congestion_control: The congestion control to apply when routing messages from this\n *     publisher.\n *   z_priority_t priority: The priority of messages issued by this publisher.\n *   bool is_express: If ``true``, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *   z_reliability_t reliability: The reliability that should be used to transmit the data (unstable).\n */\ntypedef struct {\n    z_moved_encoding_t *encoding;\n    z_congestion_control_t congestion_control;\n    z_priority_t priority;\n    bool is_express;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_reliability_t reliability;\n#endif\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    z_locality_t allowed_destination;\n#endif\n} z_publisher_options_t;\n\n/**\n * Options passed to the :c:func:`z_declare_querier()` function.\n *\n * Members:\n *   z_moved_encoding_t *encoding: Default encoding for values sent by this querier.\n *   z_query_target_t target: The Queryables that should be target of the querier queries.\n *   z_query_consolidation_t consolidation: The replies consolidation strategy to apply on replies to the querier\n *     queries.\n *   z_congestion_control_t congestion_control: The congestion control to apply when routing the querier queries.\n *   bool is_express: If set to ``true``, the querier queries will not be batched. This usually has a positive impact on\n *     latency but negative impact on throughput.\n *   z_priority_t priority: The priority of the querier queries.\n *   uint64_t timeout_ms: The timeout for the querier queries in milliseconds. 0 corresponds to default get request\n *     timeout.\n *   z_reply_keyexpr_t accept_replies: The accepted replies for the querier queries.\n */\ntypedef struct z_querier_options_t {\n    z_moved_encoding_t *encoding;\n    z_query_target_t target;\n    z_query_consolidation_t consolidation;\n    z_congestion_control_t congestion_control;\n    bool is_express;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    z_locality_t allowed_destination;\n#endif\n    z_priority_t priority;\n    uint64_t timeout_ms;\n    z_reply_keyexpr_t accept_replies;\n} z_querier_options_t;\n\n/**\n * Options passed to the :c:func:`z_querier_get()` function.\n *\n * Members:\n *   z_moved_bytes_t *payload: An optional payload to attach to the query.\n *   z_moved_encoding_t *encoding: An optional encoding of the query payload and or attachment.\n *   z_moved_bytes_t *attachment: An optional attachment to attach to the query.\n *   z_source_info_t* source_info: The source info for the request (unstable).\n *   z_moved_cancellation_token_t *cancellation_token: Token to allow cancelling get operation (unstable).\n */\ntypedef struct z_querier_get_options_t {\n    z_moved_bytes_t *payload;\n    z_moved_encoding_t *encoding;\n    z_moved_bytes_t *attachment;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_moved_cancellation_token_t *cancellation_token;\n    z_source_info_t *source_info;\n#endif\n} z_querier_get_options_t;\n\n/**\n * Represents the configuration used to configure a queryable upon declaration :c:func:`z_declare_queryable`.\n *\n * Members:\n *   bool complete: The completeness of the queryable.\n */\ntypedef struct {\n    bool complete;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    z_locality_t allowed_origin;\n#endif\n} z_queryable_options_t;\n\n/**\n * Represents the configuration used to configure a query reply sent via :c:func:`z_query_reply`.\n *\n * Members:\n *   z_moved_encoding_t* encoding: The encoding of the payload.\n *   z_congestion_control_t congestion_control: **Deprecated**. This field is ignored.\n *     Congestion control for replies is taken from the query.\n *   z_priority_t priority: **Deprecated**. This field is ignored.\n *     Priority for replies is taken from the query.\n *   z_timestamp_t *timestamp: The API level timestamp (e.g. of the data when it was created).\n *   bool is_express: If ``true``, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *   z_moved_bytes_t* attachment: An optional attachment to the response.\n *   z_source_info_t* source_info: The source info for the message (unstable).\n */\ntypedef struct {\n    z_moved_encoding_t *encoding;\n    z_congestion_control_t congestion_control;  // Deprecated: ignored, taken from query\n    z_priority_t priority;                      // Deprecated: ignored, taken from query\n    z_timestamp_t *timestamp;\n    bool is_express;\n    z_moved_bytes_t *attachment;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_source_info_t *source_info;\n#endif\n} z_query_reply_options_t;\n\n/**\n * Represents the configuration used to configure a query reply delete sent via :c:func:`z_query_reply_del`.\n *\n * Members:\n *   z_congestion_control_t congestion_control: **Deprecated**. This field is ignored.\n *     Congestion control for replies is taken from the query.\n *   z_priority_t priority: **Deprecated**. This field is ignored.\n *     Priority for replies is taken from the query.\n *   z_timestamp_t *timestamp: The API level timestamp (e.g. of the data when it was created).\n *   bool is_express: If ``true``, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *   z_moved_bytes_t* attachment: An optional attachment to the response.\n *   z_source_info_t* source_info: The source info for the message (unstable).\n */\ntypedef struct {\n    z_congestion_control_t congestion_control;  // Deprecated: ignored, taken from query\n    z_priority_t priority;                      // Deprecated: ignored, taken from query\n    z_timestamp_t *timestamp;\n    bool is_express;\n    z_moved_bytes_t *attachment;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_source_info_t *source_info;\n#endif\n} z_query_reply_del_options_t;\n\n/**\n * Represents the configuration used to configure a query reply error sent via :c:func:`z_query_reply_err`.\n *\n * Members:\n *   z_moved_encoding_t* encoding: The encoding of the payload.\n */\ntypedef struct {\n    z_moved_encoding_t *encoding;\n} z_query_reply_err_options_t;\n\n/**\n * Represents the configuration used to configure a put operation sent via :c:func:`z_put`.\n *\n * Members:\n *   z_moved_encoding_t* encoding: The encoding of the payload.\n *   z_congestion_control_t congestion_control: The congestion control to apply when routing this message.\n *   z_priority_t priority: The priority of this message when routed.\n *   z_timestamp_t *timestamp: The API level timestamp (e.g. of the data when it was created).\n *   bool is_express: If ``true``, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *   z_moved_bytes_t* attachment: An optional attachment to the publication.\n *   z_reliability_t reliability: The reliability that should be used to transmit the data (unstable).\n *   z_source_info_t* source_info: The source info for the message (unstable).\n */\ntypedef struct {\n    z_moved_encoding_t *encoding;\n    z_congestion_control_t congestion_control;\n    z_priority_t priority;\n    z_timestamp_t *timestamp;\n    bool is_express;\n    z_moved_bytes_t *attachment;\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    z_locality_t allowed_destination;\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_reliability_t reliability;\n    z_source_info_t *source_info;\n#endif\n} z_put_options_t;\n\n/**\n * Represents the configuration used to configure a delete operation sent via :c:func:`z_delete`.\n *\n * Members:\n *   z_congestion_control_t congestion_control: The congestion control to apply when routing this message.\n *   z_priority_t priority: The priority of this message when router.\n *   bool is_express: If ``true``, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *   z_timestamp_t *timestamp: The API level timestamp (e.g. of the data when it was created).\n *   z_reliability_t reliability: The reliability that should be used to transmit the data (unstable).\n *   z_source_info_t* source_info: The source info for the message (unstable).\n */\ntypedef struct {\n    z_congestion_control_t congestion_control;\n    z_priority_t priority;\n    bool is_express;\n    z_timestamp_t *timestamp;\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    z_locality_t allowed_destination;\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_reliability_t reliability;\n    z_source_info_t *source_info;\n#endif\n} z_delete_options_t;\n\n/**\n * Represents the configuration used to configure a put operation by a previously declared publisher,\n * sent via :c:func:`z_publisher_put`.\n *\n * Members:\n *   z_moved_encoding_t* encoding: The encoding of the payload.\n *   z_timestamp_t *timestamp: The API level timestamp (e.g. of the data when it was created).\n *   z_moved_bytes_t* attachment: An optional attachment to the publication.\n *   z_source_info_t* source_info: The source info for the message (unstable).\n */\ntypedef struct {\n    z_moved_encoding_t *encoding;\n    z_timestamp_t *timestamp;\n    z_moved_bytes_t *attachment;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_source_info_t *source_info;\n#endif\n} z_publisher_put_options_t;\n\n/**\n * Represents the configuration used to configure a delete operation by a previously declared publisher,\n * sent via :c:func:`z_publisher_delete`.\n *\n * Members:\n *   z_timestamp_t *timestamp: The API level timestamp (e.g. of the data when it was created).\n *   z_source_info_t* source_info: The source info for the message (unstable).\n */\ntypedef struct {\n    z_timestamp_t *timestamp;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_source_info_t *source_info;\n#endif\n} z_publisher_delete_options_t;\n\n/**\n * Represents the configuration used to configure a get operation sent via :c:func:`z_get`.\n *\n * Members:\n *   z_moved_bytes_t* payload: The payload to include in the query.\n *   z_moved_encoding_t* encoding: Payload encoding.\n *   z_query_consolidation_t consolidation: The replies consolidation strategy to apply on replies.\n *   z_congestion_control_t congestion_control: The congestion control to apply when routing the query.\n *   z_priority_t priority: The priority of the query.\n *   bool is_express: If ``true``, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *   z_query_target_t target: The queryables that should be targeted by this get.\n *   uint64_t timeout_ms: Query timeout in milliseconds. 0 means default timeout. 0 corresponds to default get request\n *     timeout.\n *   z_moved_bytes_t* attachment: An optional attachment to the query.\n *   z_source_info_t* source_info: The source info for the request (unstable).\n *   z_moved_cancellation_token_t *cancellation_token: Token to allow cancelling get operation (unstable).\n *   z_reply_keyexpr_t accept_replies: The type of accepted replies for the query.\n */\ntypedef struct {\n    z_moved_bytes_t *payload;\n    z_moved_encoding_t *encoding;\n    z_query_consolidation_t consolidation;\n    z_congestion_control_t congestion_control;\n    z_priority_t priority;\n    bool is_express;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    z_locality_t allowed_destination;\n#endif\n    z_query_target_t target;\n    uint64_t timeout_ms;\n    z_moved_bytes_t *attachment;\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_source_info_t *source_info;\n    z_moved_cancellation_token_t *cancellation_token;\n#endif\n    z_reply_keyexpr_t accept_replies;\n} z_get_options_t;\n\n#if Z_FEATURE_MULTI_THREAD == 1 || defined(SPHINX_DOCS)\n/**\n * Represents the configuration used to configure a read task started via :c:func:`zp_start_read_task`.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n */\ntypedef struct {\n    z_task_attr_t *task_attributes;\n} zp_task_read_options_t;\n\n/**\n * Represents the configuration used to configure a lease task started via :c:func:`zp_start_lease_task`.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is enabled.\n */\ntypedef struct {\n    z_task_attr_t *task_attributes;\n} zp_task_lease_options_t;\n#endif\n#if Z_FEATURE_MULTI_THREAD == 0 || defined(SPHINX_DOCS)\n/**\n * Represents the configuration used to configure a read operation started via :c:func:`zp_read`.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n */\ntypedef struct {\n    bool single_read;  // Read a single packet instead of the whole buffer\n} zp_read_options_t;\n\n/**\n * Represents the configuration used to configure a send keep alive operation started via :c:func:`zp_send_keep_alive`.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n */\ntypedef struct {\n    uint8_t __dummy;  // Just to avoid empty structures that might cause undefined behavior\n} zp_send_keep_alive_options_t;\n\n/**\n * Represents the configuration used to configure a send join operation started via :c:func:`zp_send_join`.\n *\n * Note: only if Z_FEATURE_MULTI_THREAD is disabled.\n */\ntypedef struct {\n    uint8_t __dummy;  // Just to avoid empty structures that might cause undefined behavior\n} zp_send_join_options_t;\n#endif\n/**\n * Represents the configuration used to configure a publisher upon declaration with :c:func:`z_declare_publisher`.\n *\n * Members:\n *   uint64_t timeout_ms: The maximum duration in ms the scouting can take.\n *   z_what_t what: Type of entities to scout for.\n */\ntypedef struct {\n    uint32_t timeout_ms;\n    z_what_t what;\n} z_scout_options_t;\n\n/**\n * Represents missed samples.\n *\n * Members:\n *   source: The source of missed samples.\n *   nb: The number of missed samples.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\ntypedef struct {\n    z_entity_global_id_t source;\n    uint32_t nb;\n} ze_miss_t;\n\n/**\n * Represents a data sample.\n */\n_Z_OWNED_TYPE_VALUE(_z_sample_t, sample)\n\n/**\n * Represents the content of a ``hello`` message returned by a zenoh entity as a reply to a `scout` message.\n */\n_Z_OWNED_TYPE_VALUE(_z_hello_t, hello)\n\n/**\n * Represents the reply to a query.\n */\n_Z_OWNED_TYPE_VALUE(_z_reply_t, reply)\n\n/**\n * Represents an array of non null-terminated string.\n */\n_Z_OWNED_TYPE_VALUE(_z_string_svec_t, string_array)\n\n#if Z_FEATURE_CONNECTIVITY == 1\n/**\n * Represents a transport connected to the current session.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct _z_info_transport_t {\n    z_id_t _zid;\n    z_whatami_t _whatami;\n    bool _is_qos;\n    bool _is_multicast;\n    bool _is_shm;\n} _z_info_transport_t;\n_Z_OWNED_TYPE_VALUE(_z_info_transport_t, transport)\n\n/**\n * Represents a link connected to the current session.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct _z_info_link_t {\n    z_id_t _zid;\n    _z_string_t _src;\n    _z_string_t _dst;\n    uint16_t _mtu;\n    bool _is_streamed;\n    bool _is_reliable;\n} _z_info_link_t;\n_Z_OWNED_TYPE_VALUE(_z_info_link_t, link)\n\n/**\n * Represents a transport connectivity event.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct _z_info_transport_event_t {\n    z_sample_kind_t kind;\n    _z_info_transport_t transport;\n} _z_info_transport_event_t;\n_Z_OWNED_TYPE_VALUE(_z_info_transport_event_t, transport_event)\n\n/**\n * Represents a link connectivity event.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct _z_info_link_event_t {\n    z_sample_kind_t kind;\n    _z_info_link_t link;\n} _z_info_link_event_t;\n_Z_OWNED_TYPE_VALUE(_z_info_link_event_t, link_event)\n\n/**\n * Represents a transport events listener entity.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct _z_transport_events_listener_t {\n    size_t _id;\n    _z_session_weak_t _session;\n    _z_sync_group_t _callback_drop_sync_group;\n} _z_transport_events_listener_t;\n_Z_OWNED_TYPE_VALUE(_z_transport_events_listener_t, transport_events_listener)\n\n/**\n * Represents a link events listener entity.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct _z_link_events_listener_t {\n    size_t _id;\n    _z_session_weak_t _session;\n    _z_sync_group_t _callback_drop_sync_group;\n} _z_link_events_listener_t;\n_Z_OWNED_TYPE_VALUE(_z_link_events_listener_t, link_events_listener)\n\n/**\n * Options passed to the :c:func:`z_declare_transport_events_listener()` function.\n *\n * Members:\n *   bool history: If set, the listener receives current transports as ``PUT`` events before future events.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct z_transport_events_listener_options_t {\n    bool history;\n} z_transport_events_listener_options_t;\n\n/**\n * Options passed to the :c:func:`z_declare_link_events_listener()` function.\n *\n * Members:\n *   bool history: If set, the listener receives current links as ``PUT`` events before future events.\n *   z_moved_transport_t *transport: Optional transport filter. If set, only events for this transport are delivered.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct z_link_events_listener_options_t {\n    bool history;\n    z_moved_transport_t *transport;\n} z_link_events_listener_options_t;\n\n/**\n * Options passed to the :c:func:`z_info_links()` function.\n *\n * Members:\n *   z_moved_transport_t *transport: Optional transport filter. If set, only links for this transport are returned.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\ntypedef struct z_info_links_options_t {\n    z_moved_transport_t *transport;\n} z_info_links_options_t;\n#endif\n\ntypedef _z_drop_handler_t z_closure_drop_callback_t;\ntypedef _z_closure_sample_callback_t z_closure_sample_callback_t;\n\ntypedef struct {\n    void *context;\n    z_closure_sample_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_sample_t;\n\n/**\n * Represents the sample closure.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_sample_t, closure_sample)\n\ntypedef _z_closure_query_callback_t z_closure_query_callback_t;\n\ntypedef struct {\n    void *context;\n    z_closure_query_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_query_t;\n\n/**\n * Represents the query callback closure.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_query_t, closure_query)\n\ntypedef _z_closure_reply_callback_t z_closure_reply_callback_t;\n\ntypedef struct {\n    void *context;\n    z_closure_reply_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_reply_t;\n\n/**\n * Represents the query reply callback closure.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_reply_t, closure_reply)\n\ntypedef void (*z_closure_hello_callback_t)(z_loaned_hello_t *hello, void *arg);\n\ntypedef struct {\n    void *context;\n    z_closure_hello_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_hello_t;\n\n/**\n * Represents the Zenoh ID callback closure.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_hello_t, closure_hello)\n\ntypedef void (*z_closure_zid_callback_t)(const z_id_t *id, void *arg);\n\ntypedef struct {\n    void *context;\n    z_closure_zid_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_zid_t;\n\n/**\n * Represents the Zenoh ID callback closure.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_zid_t, closure_zid)\n\n#if Z_FEATURE_CONNECTIVITY == 1\ntypedef void (*z_closure_transport_callback_t)(z_loaned_transport_t *transport, void *arg);\n\ntypedef struct {\n    void *context;\n    z_closure_transport_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_transport_t;\n\n/**\n * Represents the transport callback closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_transport_t, closure_transport)\n\ntypedef void (*z_closure_link_callback_t)(z_loaned_link_t *link, void *arg);\n\ntypedef struct {\n    void *context;\n    z_closure_link_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_link_t;\n\n/**\n * Represents the link callback closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_link_t, closure_link)\n\ntypedef void (*z_closure_transport_event_callback_t)(z_loaned_transport_event_t *event, void *arg);\n\ntypedef struct {\n    void *context;\n    z_closure_transport_event_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_transport_event_t;\n\n/**\n * Represents the transport event callback closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_transport_event_t, closure_transport_event)\n\ntypedef void (*z_closure_link_event_callback_t)(z_loaned_link_event_t *event, void *arg);\n\ntypedef struct {\n    void *context;\n    z_closure_link_event_callback_t call;\n    z_closure_drop_callback_t drop;\n} _z_closure_link_event_t;\n\n/**\n * Represents the link event callback closure.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future\n * release.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_link_event_t, closure_link_event)\n#endif\n\ntypedef _z_closure_matching_status_callback_t z_closure_matching_status_callback_t;\ntypedef _z_closure_matching_status_t z_closure_matching_status_t;\n/**\n * Represents the matching status callback closure.\n */\n_Z_OWNED_TYPE_VALUE(_z_closure_matching_status_t, closure_matching_status)\n\ntypedef void (*ze_closure_miss_callback_t)(const ze_miss_t *miss, void *arg);\n\ntypedef struct {\n    void *context;\n    ze_closure_miss_callback_t call;\n    z_closure_drop_callback_t drop;\n} _ze_closure_miss_t;\n\n/**\n * Represents the sample miss callback closure.\n */\n_Z_OWNED_TYPE_VALUE_PREFIX(ze, _ze_closure_miss_t, closure_miss)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_API_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/advanced_cache.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef INCLUDE_ZENOH_PICO_COLLECTIONS_ADVANCED_CACHE_H\n#define INCLUDE_ZENOH_PICO_COLLECTIONS_ADVANCED_CACHE_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/ring.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Represents the set of options that can be applied to an advaned publishers cache.\n * The cache allows advanced subscribers to recover history and/or lost samples.\n *\n * Members:\n *   bool is_enabled: Must be set to ``true``, to enable the cache.\n *   size_t max_samples: Number of samples to keep for each resource.\n *   z_congestion_control_t congestion_control: The congestion control to apply to replies.\n *   z_priority_t priority: The priority of replies.\n *   bool is_express: If set to ``true``, this cache replies will not be batched. This usually\n *     has a positive impact on latency but negative impact on throughput.\n */\ntypedef struct {\n    bool is_enabled;\n    size_t max_samples;\n    z_congestion_control_t congestion_control;\n    z_priority_t priority;\n    bool is_express;\n    bool _liveliness;  // TODO: Private as not yet exposed in Zenoh implementation.\n} ze_advanced_publisher_cache_options_t;\n\ntypedef struct {\n    _z_sample_ring_t _cache;\n    _z_sample_t *_outbox;\n    size_t _outbox_cap;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t _mutex;\n    _z_mutex_t _outbox_mutex;\n#endif\n    z_owned_queryable_t _queryable;\n    z_owned_liveliness_token_t _liveliness;\n    z_congestion_control_t _congestion_control;\n    z_priority_t _priority;\n    bool _is_express;\n} _ze_advanced_cache_t;\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n\n_ze_advanced_cache_t *_ze_advanced_cache_new(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                             const z_loaned_keyexpr_t *suffix,\n                                             const ze_advanced_publisher_cache_options_t options);\n\nz_result_t _ze_advanced_cache_add(_ze_advanced_cache_t *cache, _z_sample_t *sample);\n\nvoid _ze_advanced_cache_free(_ze_advanced_cache_t **xs);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // INCLUDE_ZENOH_PICO_COLLECTIONS_ADVANCED_CACHE_H\n"
  },
  {
    "path": "include/zenoh-pico/collections/arc_slice.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_ARC_SLICE_H\n#define ZENOH_PICO_COLLECTIONS_ARC_SLICE_H\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"refcount.h\"\n#include \"slice.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n_Z_SIMPLE_REFCOUNT_DEFINE(_z_slice, _z_slice)\n\n/*-------- ArcSlice --------*/\n/**\n * An atomically reference counted subslice.\n *\n * Members:\n *   _z_slice_simple_rc_t len: Rc counted slice.\n *   size_t start: Offset to the subslice start.\n *   size_t len: Length of the subslice.\n */\n\ntypedef struct {\n    _z_slice_simple_rc_t slice;\n    size_t start;\n    size_t len;\n} _z_arc_slice_t;\n\nstatic inline _z_arc_slice_t _z_arc_slice_empty(void) { return (_z_arc_slice_t){0}; }\nstatic inline size_t _z_arc_slice_len(const _z_arc_slice_t* s) { return s->len; }\nstatic inline bool _z_arc_slice_is_empty(const _z_arc_slice_t* s) { return _z_arc_slice_len(s) == 0; }\nstatic inline _z_arc_slice_t _z_arc_slice_wrap_slice_rc(_z_slice_simple_rc_t* slice_rc, size_t offset, size_t len) {\n    assert(offset + len <= _z_slice_simple_rc_value(slice_rc)->len);\n    _z_arc_slice_t arc_s;\n    arc_s.slice = _z_slice_simple_rc_clone(slice_rc);\n    arc_s.len = len;\n    arc_s.start = offset;\n    return arc_s;\n}\nstatic inline const uint8_t* _z_arc_slice_data(const _z_arc_slice_t* s) {\n    return _z_slice_simple_rc_value(&s->slice)->start + s->start;\n}\nstatic inline z_result_t _z_arc_slice_drop(_z_arc_slice_t* s) {\n    _z_slice_simple_rc_drop(&s->slice);\n    return _Z_RES_OK;\n}\nstatic inline size_t _z_arc_slice_size(const _z_arc_slice_t* s) {\n    (void)s;\n    return sizeof(_z_arc_slice_t);\n}\n\n_z_arc_slice_t _z_arc_slice_wrap(_z_slice_t* s, size_t offset, size_t len);\n_z_arc_slice_t _z_arc_slice_get_subslice(const _z_arc_slice_t* s, size_t offset, size_t len);\nz_result_t _z_arc_slice_copy(_z_arc_slice_t* dst, const _z_arc_slice_t* src);\nz_result_t _z_arc_slice_move(_z_arc_slice_t* dst, _z_arc_slice_t* src);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_ARC_SLICE_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/array.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_ARRAY_H\n#define ZENOH_PICO_COLLECTIONS_ARRAY_H\n\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Internal Array Macros ------------------*/\n#define _Z_ARRAY_DEFINE(name, type)                                                                 \\\n    typedef struct {                                                                                \\\n        size_t _len;                                                                                \\\n        type *_val;                                                                                 \\\n    } name##_array_t;                                                                               \\\n    static inline name##_array_t name##_array_empty(void) {                                         \\\n        name##_array_t a;                                                                           \\\n        a._val = NULL;                                                                              \\\n        a._len = 0;                                                                                 \\\n        return a;                                                                                   \\\n    }                                                                                               \\\n    static inline name##_array_t name##_array_make(size_t capacity) {                               \\\n        name##_array_t a;                                                                           \\\n        a._val = (type *)z_malloc(capacity * sizeof(type));                                         \\\n        if (a._val != NULL) {                                                                       \\\n            a._len = capacity;                                                                      \\\n        } else {                                                                                    \\\n            a._len = 0;                                                                             \\\n        }                                                                                           \\\n        return a;                                                                                   \\\n    }                                                                                               \\\n    static inline void name##_array_move(name##_array_t *dst, name##_array_t *src) {                \\\n        dst->_len = src->_len;                                                                      \\\n        dst->_val = src->_val;                                                                      \\\n        src->_len = 0;                                                                              \\\n        src->_val = NULL;                                                                           \\\n    }                                                                                               \\\n    static inline void name##_array_copy(name##_array_t *dst, name##_array_t *src) {                \\\n        dst->_len = src->_len;                                                                      \\\n        memcpy(&dst->_val, &src->_val, src->_len);                                                  \\\n    }                                                                                               \\\n    static inline type *name##_array_get(const name##_array_t *a, size_t k) { return &a->_val[k]; } \\\n    static inline size_t name##_array_len(const name##_array_t *a) { return a->_len; }              \\\n    static inline bool name##_array_is_empty(const name##_array_t *a) { return a->_len == 0; }      \\\n    static inline void name##_array_clear(name##_array_t *a) {                                      \\\n        for (size_t i = 0; i < a->_len; i++) {                                                      \\\n            name##_elem_clear(&a->_val[i]);                                                         \\\n        }                                                                                           \\\n        z_free(a->_val);                                                                            \\\n        a->_len = 0;                                                                                \\\n        a->_val = NULL;                                                                             \\\n    }                                                                                               \\\n    static inline void name##_array_free(name##_array_t **a) {                                      \\\n        name##_array_t *ptr = *a;                                                                   \\\n        if (ptr != NULL) {                                                                          \\\n            name##_array_clear(ptr);                                                                \\\n            z_free(ptr);                                                                            \\\n            *a = NULL;                                                                              \\\n        }                                                                                           \\\n    }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_ARRAY_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/atomic.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_ATOMIC_H\n#define ZENOH_PICO_COLLECTIONS_ATOMIC_H\n#include <stdbool.h>\n#include <stddef.h>\n\ntypedef struct {\n    size_t _value;\n} _z_atomic_size_t;\n\ntypedef enum {\n    _z_memory_order_relaxed,\n    _z_memory_order_acquire,\n    _z_memory_order_release,\n    _z_memory_order_acq_rel,\n    _z_memory_order_seq_cst\n} _z_memory_order_t;\n\nvoid _z_atomic_size_init(_z_atomic_size_t *var, size_t value);\nsize_t _z_atomic_size_load(_z_atomic_size_t *var, _z_memory_order_t order);\nvoid _z_atomic_size_store(_z_atomic_size_t *var, size_t val, _z_memory_order_t order);\nsize_t _z_atomic_size_fetch_add(_z_atomic_size_t *var, size_t val, _z_memory_order_t order);\nsize_t _z_atomic_size_fetch_sub(_z_atomic_size_t *var, size_t val, _z_memory_order_t order);\nbool _z_atomic_size_compare_exchange_strong(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                            _z_memory_order_t success, _z_memory_order_t failure);\nbool _z_atomic_size_compare_exchange_weak(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                          _z_memory_order_t success, _z_memory_order_t failure);\nvoid _z_atomic_thread_fence(_z_memory_order_t order);\n\ntypedef _z_atomic_size_t _z_atomic_bool_t;\nstatic inline void _z_atomic_bool_init(_z_atomic_bool_t *var, bool value) { _z_atomic_size_init(var, value ? 1 : 0); }\nstatic inline bool _z_atomic_bool_load(_z_atomic_bool_t *var, _z_memory_order_t order) {\n    return _z_atomic_size_load(var, order) != 0;\n}\nstatic inline void _z_atomic_bool_store(_z_atomic_bool_t *var, bool val, _z_memory_order_t order) {\n    _z_atomic_size_store(var, val ? 1 : 0, order);\n}\nstatic inline bool _z_atomic_bool_compare_exchange_strong(_z_atomic_bool_t *var, bool *expected, bool desired,\n                                                          _z_memory_order_t success, _z_memory_order_t failure) {\n    size_t expected_val = *expected ? 1 : 0;\n    bool result = _z_atomic_size_compare_exchange_strong(var, &expected_val, desired ? 1 : 0, success, failure);\n    *expected = expected_val != 0;\n    return result;\n}\nstatic inline bool _z_atomic_bool_compare_exchange_weak(_z_atomic_bool_t *var, bool *expected, bool desired,\n                                                        _z_memory_order_t success, _z_memory_order_t failure) {\n    size_t expected_val = *expected ? 1 : 0;\n    bool result = _z_atomic_size_compare_exchange_weak(var, &expected_val, desired ? 1 : 0, success, failure);\n    *expected = expected_val != 0;\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/collections/bytes.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_BYTES_H\n#define ZENOH_PICO_COLLECTIONS_BYTES_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"arc_slice.h\"\n#include \"vec.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n_Z_ELEM_DEFINE(_z_arc_slice, _z_arc_slice_t, _z_arc_slice_size, _z_arc_slice_drop, _z_arc_slice_copy, _z_arc_slice_move,\n               _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SVEC_DEFINE(_z_arc_slice, _z_arc_slice_t)\n\n/*-------- Bytes --------*/\n/**\n * A container for slices.\n *\n * Members:\n *   _z_slice_vec_t _slices: contents of the container.\n */\n\ntypedef struct {\n    _z_arc_slice_svec_t _slices;\n} _z_bytes_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_bytes_t _z_bytes_null(void) { return (_z_bytes_t){0}; }\nstatic inline void _z_bytes_alias_arc_slice(_z_bytes_t *dst, _z_arc_slice_t *s) {\n    dst->_slices = _z_arc_slice_svec_alias_element(s);\n}\nstatic inline _z_bytes_t _z_bytes_alias(const _z_bytes_t *src) {\n    if (src == NULL) {\n        return _z_bytes_null();\n    }\n    _z_bytes_t dst;\n    dst._slices = src->_slices;\n    return dst;\n}\nstatic inline _z_bytes_t _z_bytes_steal(_z_bytes_t *src) {\n    _z_bytes_t b = *src;\n    src->_slices._len = 0;\n    src->_slices._val = NULL;\n    return b;\n}\nstatic inline size_t _z_bytes_num_slices(const _z_bytes_t *bs) { return _z_arc_slice_svec_len(&bs->_slices); }\nstatic inline _z_arc_slice_t *_z_bytes_get_slice(const _z_bytes_t *bs, size_t i) {\n    if (i >= _z_bytes_num_slices(bs)) return NULL;\n    return _z_arc_slice_svec_get(&bs->_slices, i);\n}\nstatic inline void _z_bytes_drop(_z_bytes_t *bytes) { _z_arc_slice_svec_clear(&bytes->_slices); }\n\nbool _z_bytes_check(const _z_bytes_t *bytes);\nz_result_t _z_bytes_append_bytes(_z_bytes_t *dst, _z_bytes_t *src);\nz_result_t _z_bytes_append_slice(_z_bytes_t *dst, _z_arc_slice_t *s);\nz_result_t _z_bytes_copy(_z_bytes_t *dst, const _z_bytes_t *src);\n_z_bytes_t _z_bytes_duplicate(const _z_bytes_t *src);\nz_result_t _z_bytes_move(_z_bytes_t *dst, _z_bytes_t *src);\nvoid _z_bytes_free(_z_bytes_t **bs);\nsize_t _z_bytes_len(const _z_bytes_t *bs);\nbool _z_bytes_is_empty(const _z_bytes_t *bs);\nz_result_t _z_bytes_to_slice(const _z_bytes_t *bytes, _z_slice_t *s);\nz_result_t _z_bytes_from_slice(_z_bytes_t *b, _z_slice_t *s);\nsize_t _z_bytes_to_buf(const _z_bytes_t *bytes, uint8_t *dst, size_t len);\nz_result_t _z_bytes_from_buf(_z_bytes_t *b, const uint8_t *src, size_t len);\n_z_slice_t _z_bytes_try_get_contiguous(const _z_bytes_t *bs);\n\ntypedef struct {\n    size_t slice_idx;\n    size_t in_slice_idx;\n    size_t byte_idx;\n    const _z_bytes_t *bytes;\n} _z_bytes_reader_t;\n\n_z_bytes_reader_t _z_bytes_get_reader(const _z_bytes_t *bytes);\nz_result_t _z_bytes_reader_seek(_z_bytes_reader_t *reader, int64_t offset, int origin);\nint64_t _z_bytes_reader_tell(const _z_bytes_reader_t *reader);\nz_result_t _z_bytes_reader_read_slices(_z_bytes_reader_t *reader, size_t len, _z_bytes_t *out);\nsize_t _z_bytes_reader_read(_z_bytes_reader_t *reader, uint8_t *buf, size_t len);\n\ntypedef struct {\n    _z_arc_slice_t *cache;\n    _z_bytes_t bytes;\n} _z_bytes_writer_t;\n\nbool _z_bytes_writer_is_empty(const _z_bytes_writer_t *writer);\nbool _z_bytes_writer_check(const _z_bytes_writer_t *writer);\n_z_bytes_writer_t _z_bytes_writer_from_bytes(_z_bytes_t *bytes);\n_z_bytes_writer_t _z_bytes_writer_empty(void);\nz_result_t _z_bytes_writer_write_all(_z_bytes_writer_t *writer, const uint8_t *src, size_t len);\nz_result_t _z_bytes_writer_append_z_bytes(_z_bytes_writer_t *writer, _z_bytes_t *bytes);\nz_result_t _z_bytes_writer_append_slice(_z_bytes_writer_t *writer, _z_arc_slice_t *bytes);\n_z_bytes_t _z_bytes_writer_finish(_z_bytes_writer_t *writer);\nvoid _z_bytes_writer_clear(_z_bytes_writer_t *writer);\nz_result_t _z_bytes_writer_move(_z_bytes_writer_t *dst, _z_bytes_writer_t *src);\nsize_t _z_bytes_reader_remaining(const _z_bytes_reader_t *reader);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_BYTES_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/cat.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_CAT_H\n#define ZENOH_PICO_COLLECTIONS_CAT_H\n#define _ZP_CAT_INNER(a, b) a##_##b\n#define _ZP_CAT(a, b) _ZP_CAT_INNER(a, b)\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/collections/deque_template.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// user needs to define the following macros before including this file\n// _ZP_DEQUE_TEMPLATE_ELEM_TYPE: the type of the elements in the buffer\n// _ZP_DEQUE_TEMPLATE_NAME: the name of the buffer type to generate (without the _t suffix)\n// _ZP_DEQUE_TEMPLATE_SIZE: the maximum size of the circular buffer (optional, default is 16)\n// _ZP_DEQUE_TEMPLATE_ALLOCATOR_TYPE: the type of the allocator to use for the buffer nodes (optional, default is a\n// simple z_malloc/z_free allocator) _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME: the name of the function to destroy an\n// element (optional, default is a no-op function) _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME: the name of the function to\n// move an element (optional, default is an element-wise move function that uses the copy function and then clears the\n// source element)\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#include \"zenoh-pico/collections/cat.h\"\n\n#ifndef _ZP_DEQUE_TEMPLATE_ELEM_TYPE\n#error \"_ZP_DEQUE_TEMPLATE_ELEM_TYPE must be defined before including deque_template.h\"\n#define _ZP_DEQUE_TEMPLATE_ELEM_TYPE int\n#endif\n#ifndef _ZP_DEQUE_TEMPLATE_SIZE\n#define _ZP_DEQUE_TEMPLATE_SIZE 16\n#endif\n#ifndef _ZP_DEQUE_TEMPLATE_NAME\n#define _ZP_DEQUE_TEMPLATE_NAME _ZP_CAT(_ZP_CAT(_ZP_DEQUE_TEMPLATE_ELEM_TYPE, deque), _ZP_DEQUE_TEMPLATE_SIZE)\n#endif\n\n#ifndef _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME\n#define _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME(x) (void)(x)\n#endif\n#ifndef _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME\n#define _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME(dst, src) \\\n    *(dst) = *(src);                                   \\\n    _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME(src);\n#endif\n\n#define _ZP_DEQUE_TEMPLATE_TYPE _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, t)\ntypedef struct _ZP_DEQUE_TEMPLATE_TYPE {\n    _ZP_DEQUE_TEMPLATE_ELEM_TYPE _buffer[_ZP_DEQUE_TEMPLATE_SIZE];\n    size_t _start;\n    size_t _end;\n} _ZP_DEQUE_TEMPLATE_TYPE;\n\nstatic inline _ZP_DEQUE_TEMPLATE_TYPE _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, new)(void) {\n    _ZP_DEQUE_TEMPLATE_TYPE deque = {0};\n    return deque;\n}\nstatic inline size_t _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, size)(const _ZP_DEQUE_TEMPLATE_TYPE *deque) {\n    if (deque->_start < deque->_end) {\n        return deque->_end - deque->_start;\n    } else if (deque->_start == 0 && deque->_end == 0) {\n        return 0;\n    }\n    return _ZP_DEQUE_TEMPLATE_SIZE - deque->_start + deque->_end;\n}\nstatic inline void _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, destroy)(_ZP_DEQUE_TEMPLATE_TYPE *deque) {\n    size_t count = _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, size)(deque);\n    for (size_t i = 0; i < count; i++) {\n        size_t idx = deque->_start + i;\n        if (i >= _ZP_DEQUE_TEMPLATE_SIZE) {\n            idx -= _ZP_DEQUE_TEMPLATE_SIZE;\n        }\n        _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME(&deque->_buffer[idx]);\n    }\n    deque->_start = 0;\n    deque->_end = 0;\n}\nstatic inline bool _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, is_empty)(const _ZP_DEQUE_TEMPLATE_TYPE *deque) {\n    return _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, size)(deque) == 0;\n}\nstatic inline bool _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, push_back)(_ZP_DEQUE_TEMPLATE_TYPE *deque,\n                                                               _ZP_DEQUE_TEMPLATE_ELEM_TYPE *elem) {\n    if (_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, size)(deque) == _ZP_DEQUE_TEMPLATE_SIZE) {\n        return false;\n    }\n    if (deque->_end == _ZP_DEQUE_TEMPLATE_SIZE) {\n        deque->_end = 0;\n    }\n    _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME(&deque->_buffer[deque->_end], elem);\n    deque->_end++;\n    return true;\n}\nstatic inline bool _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, pop_back)(_ZP_DEQUE_TEMPLATE_TYPE *deque,\n                                                              _ZP_DEQUE_TEMPLATE_ELEM_TYPE *out) {\n    if (_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, is_empty)(deque)) {\n        return false;\n    }\n    if (deque->_end == 0) {\n        deque->_end = _ZP_DEQUE_TEMPLATE_SIZE;\n    }\n    deque->_end--;\n    _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME(out, &deque->_buffer[deque->_end]);\n    if (deque->_end == deque->_start) {\n        deque->_end = 0;\n        deque->_start = 0;\n    }\n    return true;\n}\nstatic inline _ZP_DEQUE_TEMPLATE_ELEM_TYPE *_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, back)(_ZP_DEQUE_TEMPLATE_TYPE *deque) {\n    if (_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, is_empty)(deque)) {\n        return NULL;\n    }\n    size_t idx = deque->_end == 0 ? _ZP_DEQUE_TEMPLATE_SIZE - 1 : deque->_end - 1;\n    return &deque->_buffer[idx];\n}\nstatic inline bool _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, push_front)(_ZP_DEQUE_TEMPLATE_TYPE *deque,\n                                                                _ZP_DEQUE_TEMPLATE_ELEM_TYPE *elem) {\n    if (_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, size)(deque) == _ZP_DEQUE_TEMPLATE_SIZE) {\n        return false;\n    }\n    if (deque->_start == 0) {\n        deque->_start = _ZP_DEQUE_TEMPLATE_SIZE;\n    }\n    deque->_start--;\n    _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME(&deque->_buffer[deque->_start], elem);\n    return true;\n}\nstatic inline bool _ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, pop_front)(_ZP_DEQUE_TEMPLATE_TYPE *deque,\n                                                               _ZP_DEQUE_TEMPLATE_ELEM_TYPE *out) {\n    if (_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, is_empty)(deque)) {\n        return false;\n    }\n    _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME(out, &deque->_buffer[deque->_start]);\n    deque->_start++;\n    if (deque->_end == deque->_start) {\n        deque->_end = 0;\n        deque->_start = 0;\n    }\n    return true;\n}\nstatic inline _ZP_DEQUE_TEMPLATE_ELEM_TYPE *_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, front)(_ZP_DEQUE_TEMPLATE_TYPE *deque) {\n    if (_ZP_CAT(_ZP_DEQUE_TEMPLATE_NAME, is_empty)(deque)) {\n        return NULL;\n    }\n    return &deque->_buffer[deque->_start];\n}\n\n#undef _ZP_DEQUE_TEMPLATE_TYPE\n#undef _ZP_DEQUE_TEMPLATE_ELEM_TYPE\n#undef _ZP_DEQUE_TEMPLATE_NAME\n#undef _ZP_DEQUE_TEMPLATE_NODE_TYPE\n#undef _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME\n#undef _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME\n#undef _ZP_DEQUE_TEMPLATE_SIZE\n"
  },
  {
    "path": "include/zenoh-pico/collections/element.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_ELEMENT_H\n#define ZENOH_PICO_COLLECTIONS_ELEMENT_H\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- element functions --------*/\ntypedef size_t (*z_element_size_f)(void *e);\ntypedef void (*z_element_clear_f)(void *e);\ntypedef void (*z_element_free_f)(void **e);\ntypedef void (*z_element_copy_f)(void *dst, const void *src);\ntypedef void (*z_element_move_f)(void *dst, void *src);\ntypedef void *(*z_element_clone_f)(const void *e);\ntypedef bool (*z_element_eq_f)(const void *left, const void *right);\ntypedef int (*z_element_cmp_f)(const void *left, const void *right);\ntypedef size_t (*z_element_hash_f)(const void *e);\n\n#define _Z_ELEM_DEFINE(name, type, elem_size_f, elem_clear_f, elem_copy_f, elem_move_f, elem_eq_f, elem_cmp_f, \\\n                       elem_hash_f)                                                                            \\\n    typedef bool (*name##_eq_f)(const type *left, const type *right);                                          \\\n    typedef int (*name##_cmp_f)(const type *left, const type *right);                                          \\\n    static inline void name##_elem_clear(void *e) { elem_clear_f((type *)e); }                                 \\\n    static inline void name##_elem_free(void **e) {                                                            \\\n        type *ptr = (type *)*e;                                                                                \\\n        if (ptr != NULL) {                                                                                     \\\n            elem_clear_f(ptr);                                                                                 \\\n            z_free(ptr);                                                                                       \\\n            *e = NULL;                                                                                         \\\n        }                                                                                                      \\\n    }                                                                                                          \\\n    static inline void name##_elem_move(void *dst, void *src) { elem_move_f((type *)dst, (type *)src); }       \\\n    static inline void name##_elem_copy(void *dst, const void *src) { elem_copy_f((type *)dst, (type *)src); } \\\n    static inline void *name##_elem_clone(const void *src) {                                                   \\\n        type *dst = (type *)z_malloc(elem_size_f((type *)src));                                                \\\n        if (dst != NULL) {                                                                                     \\\n            elem_copy_f(dst, (type *)src);                                                                     \\\n        }                                                                                                      \\\n        return dst;                                                                                            \\\n    }                                                                                                          \\\n    static inline bool name##_elem_eq(const void *left, const void *right) {                                   \\\n        return elem_eq_f((const type *)left, (const type *)right);                                             \\\n    }                                                                                                          \\\n    static inline int name##_elem_cmp(const void *left, const void *right) {                                   \\\n        return elem_cmp_f((const type *)left, (const type *)right);                                            \\\n    }                                                                                                          \\\n    static inline size_t name##_elem_hash(const void *e) { return elem_hash_f((const type *)e); }\n\n/*------------------ void ----------------*/\ntypedef void _z_noop_t;\n\nstatic inline size_t _z_noop_size(void *s) {\n    (void)(s);\n    return 0;\n}\n\nstatic inline void _z_noop_clear(void *s) { (void)(s); }\n\nstatic inline void _z_noop_free(void **s) { (void)(s); }\n\nstatic inline void _z_noop_copy(void *dst, const void *src) {\n    _ZP_UNUSED(dst);\n    _ZP_UNUSED(src);\n}\n\nstatic inline void _z_noop_move(void *dst, void *src) {\n    _ZP_UNUSED(dst);\n    _ZP_UNUSED(src);\n}\n\nstatic inline bool _z_noop_eq(const void *left, const void *right) {\n    _ZP_UNUSED(left);\n    _ZP_UNUSED(right);\n    return true;\n}\n\nstatic inline int _z_noop_cmp(const void *left, const void *right) {\n    _ZP_UNUSED(left);\n    _ZP_UNUSED(right);\n    return 0;\n}\n\nstatic inline size_t _z_noop_hash(const void *e) {\n    _ZP_UNUSED(e);\n    return 0;\n}\n\n_Z_ELEM_DEFINE(_z_noop, _z_noop_t, _z_noop_size, _z_noop_clear, _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp,\n               _z_noop_hash)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_ELEMENT_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/fifo.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef ZENOH_PICO_COLLECTIONS_FIFO_H\n#define ZENOH_PICO_COLLECTIONS_FIFO_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/ring.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Fifo Buffer --------*/\ntypedef struct {\n    _z_ring_t _ring;\n} _z_fifo_t;\n\nz_result_t _z_fifo_init(_z_fifo_t *fifo, size_t capacity);\n_z_fifo_t _z_fifo_make(size_t capacity);\n\nsize_t _z_fifo_capacity(const _z_fifo_t *r);\nsize_t _z_fifo_len(const _z_fifo_t *r);\nbool _z_fifo_is_empty(const _z_fifo_t *r);\nbool _z_fifo_is_full(const _z_fifo_t *r);\n\nvoid *_z_fifo_push(_z_fifo_t *r, void *e);\nvoid _z_fifo_push_drop(_z_fifo_t *r, void *e, z_element_free_f f);\nvoid *_z_fifo_pull(_z_fifo_t *r);\n\n_z_fifo_t *_z_fifo_clone(const _z_fifo_t *xs, z_element_clone_f d_f);\n\nvoid _z_fifo_clear(_z_fifo_t *v, z_element_free_f f);\nvoid _z_fifo_free(_z_fifo_t **xs, z_element_free_f f_f);\n\n#define _Z_FIFO_DEFINE(name, type)                                                                         \\\n    typedef _z_fifo_t name##_fifo_t;                                                                       \\\n    static inline z_result_t name##_fifo_init(name##_fifo_t *fifo, size_t capacity) {                      \\\n        return _z_fifo_init(fifo, capacity);                                                               \\\n    }                                                                                                      \\\n    static inline name##_fifo_t name##_fifo_make(size_t capacity) { return _z_fifo_make(capacity); }       \\\n    static inline size_t name##_fifo_capacity(const name##_fifo_t *r) { return _z_fifo_capacity(r); }      \\\n    static inline size_t name##_fifo_len(const name##_fifo_t *r) { return _z_fifo_len(r); }                \\\n    static inline bool name##_fifo_is_empty(const name##_fifo_t *r) { return _z_fifo_is_empty(r); }        \\\n    static inline bool name##_fifo_is_full(const name##_fifo_t *r) { return _z_fifo_is_full(r); }          \\\n    static inline type *name##_fifo_push(name##_fifo_t *r, type *e) { return _z_fifo_push(r, (void *)e); } \\\n    static inline void name##_fifo_push_drop(name##_fifo_t *r, type *e) {                                  \\\n        _z_fifo_push_drop(r, (void *)e, name##_elem_free);                                                 \\\n    }                                                                                                      \\\n    static inline type *name##_fifo_pull(name##_fifo_t *r) { return (type *)_z_fifo_pull(r); }             \\\n    static inline void name##_fifo_clear(name##_fifo_t *r) { _z_fifo_clear(r, name##_elem_free); }         \\\n    static inline void name##_fifo_free(name##_fifo_t **r) { _z_fifo_free(r, name##_elem_free); }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_FIFO_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/fifo_mt.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef ZENOH_PICO_COLLECTIONS_FIFO_MT_H\n#define ZENOH_PICO_COLLECTIONS_FIFO_MT_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/fifo.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Fifo Buffer Multithreaded --------*/\ntypedef struct {\n    _z_fifo_t _fifo;\n    bool is_closed;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t _mutex;\n    _z_condvar_t _cv_not_full;\n    _z_condvar_t _cv_not_empty;\n#endif\n} _z_fifo_mt_t;\n\nz_result_t _z_fifo_mt_init(_z_fifo_mt_t *fifo, size_t capacity);\n_z_fifo_mt_t *_z_fifo_mt_new(size_t capacity);\n\nz_result_t _z_fifo_mt_close(_z_fifo_mt_t *fifo);\nvoid _z_fifo_mt_clear(_z_fifo_mt_t *fifo, z_element_free_f free_f);\nvoid _z_fifo_mt_free(_z_fifo_mt_t *fifo, z_element_free_f free_f);\n\nz_result_t _z_fifo_mt_push(const void *src, void *context, z_element_free_f element_free);\n\nz_result_t _z_fifo_mt_pull(void *dst, void *context, z_element_move_f element_move);\nz_result_t _z_fifo_mt_try_pull(void *dst, void *context, z_element_move_f element_move);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // ZENOH_PICO_COLLECTIONS_FIFO_MT_H\n"
  },
  {
    "path": "include/zenoh-pico/collections/hashmap.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_HASHMAP_H\n#define ZENOH_PICO_COLLECTIONS_HASHMAP_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_DEFAULT_HASHMAP_CAPACITY 16\n\n/**\n * A hashmap entry with generic keys.\n *\n * Members:\n *   void *_key: the key of the entry\n *   void *_val: the value of the entry\n */\ntypedef struct {\n    void *_key;\n    void *_val;\n} _z_hashmap_entry_t;\n\n/**\n * A hashmap with generic keys.\n *\n * Members:\n *    size_t _capacity: the number of buckets available in the hashmap\n *   _z_list_t **_vals: the linked list containing the values\n *   z_element_hash_f _f_hash: the hash function used to hash keys\n *   z_element_eq_f _f_equals: the function used to compare keys for equality\n */\ntypedef struct {\n    size_t _capacity;\n    _z_list_t **_vals;\n    z_element_hash_f _f_hash;\n    z_element_eq_f _f_equals;\n} _z_hashmap_t;\n\n/**\n * Iterator for a generic key-value hashmap.\n */\ntypedef struct {\n    _z_hashmap_entry_t *_entry;\n    const _z_hashmap_t *_map;\n    size_t _idx;\n    _z_list_t *_list_ptr;\n} _z_hashmap_iterator_t;\n\nvoid _z_hashmap_init(_z_hashmap_t *map, size_t capacity, z_element_hash_f f_hash, z_element_eq_f f_equals);\n_z_hashmap_t _z_hashmap_make(size_t capacity, z_element_hash_f f_hash, z_element_eq_f f_equals);\n\nvoid *_z_hashmap_insert(_z_hashmap_t *map, void *key, void *val, z_element_free_f f, bool replace);\nvoid *_z_hashmap_get(const _z_hashmap_t *map, const void *key);\n_z_list_t *_z_hashmap_get_all(const _z_hashmap_t *map, const void *key);\nvoid _z_hashmap_remove(_z_hashmap_t *map, const void *key, z_element_free_f f);\n_z_hashmap_entry_t _z_hashmap_extract(_z_hashmap_t *map, const void *key);\n\nsize_t _z_hashmap_capacity(const _z_hashmap_t *map);\nsize_t _z_hashmap_len(const _z_hashmap_t *map);\nbool _z_hashmap_is_empty(const _z_hashmap_t *map);\n\nz_result_t _z_hashmap_copy(_z_hashmap_t *dst, const _z_hashmap_t *src, z_element_clone_f f_c);\n_z_hashmap_t _z_hashmap_clone(const _z_hashmap_t *src, z_element_clone_f f_c, z_element_free_f f_f);\n\nvoid _z_hashmap_clear(_z_hashmap_t *map, z_element_free_f f);\nvoid _z_hashmap_free(_z_hashmap_t **map, z_element_free_f f);\nstatic inline void _z_hashmap_move(_z_hashmap_t *dst, _z_hashmap_t *src) {\n    *dst = *src;\n    *src = _z_hashmap_make(src->_capacity, src->_f_hash, src->_f_equals);\n}\n\n_z_hashmap_iterator_t _z_hashmap_iterator_make(const _z_hashmap_t *map);\nbool _z_hashmap_iterator_next(_z_hashmap_iterator_t *iter);\nvoid *_z_hashmap_iterator_key(const _z_hashmap_iterator_t *iter);\nvoid *_z_hashmap_iterator_value(const _z_hashmap_iterator_t *iter);\n\n#define _Z_HASHMAP_DEFINE_INNER(map_name, key_name, val_name, key_type, val_type)                                     \\\n    typedef _z_hashmap_entry_t map_name##_hashmap_entry_t;                                                            \\\n    static inline void map_name##_hashmap_entry_elem_free(void **e) {                                                 \\\n        map_name##_hashmap_entry_t *ptr = (map_name##_hashmap_entry_t *)*e;                                           \\\n        if (ptr != NULL) {                                                                                            \\\n            key_name##_elem_free(&ptr->_key);                                                                         \\\n            val_name##_elem_free(&ptr->_val);                                                                         \\\n            z_free(ptr);                                                                                              \\\n            *e = NULL;                                                                                                \\\n        }                                                                                                             \\\n    }                                                                                                                 \\\n    static inline void *map_name##_hashmap_entry_elem_clone(const void *e) {                                          \\\n        const map_name##_hashmap_entry_t *src = (map_name##_hashmap_entry_t *)e;                                      \\\n        map_name##_hashmap_entry_t *dst = (map_name##_hashmap_entry_t *)z_malloc(sizeof(map_name##_hashmap_entry_t)); \\\n        dst->_key = key_name##_elem_clone(src->_key);                                                                 \\\n        dst->_val = val_name##_elem_clone(src->_val);                                                                 \\\n        return dst;                                                                                                   \\\n    }                                                                                                                 \\\n    static inline bool map_name##_hashmap_entry_key_eq(const void *left, const void *right) {                         \\\n        const map_name##_hashmap_entry_t *l = (const map_name##_hashmap_entry_t *)left;                               \\\n        const map_name##_hashmap_entry_t *r = (const map_name##_hashmap_entry_t *)right;                              \\\n        return key_name##_elem_eq(l->_key, r->_key);                                                                  \\\n    }                                                                                                                 \\\n    typedef _z_hashmap_t map_name##_hashmap_t;                                                                        \\\n    typedef _z_hashmap_iterator_t map_name##_hashmap_iterator_t;                                                      \\\n    static inline void map_name##_hashmap_init(map_name##_hashmap_t *m) {                                             \\\n        _z_hashmap_init(m, _Z_DEFAULT_HASHMAP_CAPACITY, key_name##_elem_hash, map_name##_hashmap_entry_key_eq);       \\\n    }                                                                                                                 \\\n    static inline map_name##_hashmap_t map_name##_hashmap_make(void) {                                                \\\n        return _z_hashmap_make(_Z_DEFAULT_HASHMAP_CAPACITY, key_name##_elem_hash, map_name##_hashmap_entry_key_eq);   \\\n    }                                                                                                                 \\\n    static inline val_type *map_name##_hashmap_insert(map_name##_hashmap_t *m, key_type *k, val_type *v) {            \\\n        return (val_type *)_z_hashmap_insert(m, k, v, map_name##_hashmap_entry_elem_free, true);                      \\\n    }                                                                                                                 \\\n    static inline val_type *map_name##_hashmap_insert_push(map_name##_hashmap_t *m, key_type *k, val_type *v) {       \\\n        return (val_type *)_z_hashmap_insert(m, k, v, map_name##_hashmap_entry_elem_free, false);                     \\\n    }                                                                                                                 \\\n    static inline val_type *map_name##_hashmap_get(const map_name##_hashmap_t *m, const key_type *k) {                \\\n        return (val_type *)_z_hashmap_get(m, k);                                                                      \\\n    }                                                                                                                 \\\n    static inline _z_list_t *map_name##_hashmap_get_all(const map_name##_hashmap_t *m, const key_type *k) {           \\\n        return _z_hashmap_get_all(m, k);                                                                              \\\n    }                                                                                                                 \\\n    static inline map_name##_hashmap_t map_name##_hashmap_clone(const map_name##_hashmap_t *m) {                      \\\n        return _z_hashmap_clone(m, map_name##_hashmap_entry_elem_clone, map_name##_hashmap_entry_elem_free);          \\\n    }                                                                                                                 \\\n    static inline void map_name##_hashmap_remove(map_name##_hashmap_t *m, const key_type *k) {                        \\\n        _z_hashmap_remove(m, k, map_name##_hashmap_entry_elem_free);                                                  \\\n    }                                                                                                                 \\\n    static inline map_name##_hashmap_entry_t map_name##_hashmap_extract(map_name##_hashmap_t *m, const key_type *k) { \\\n        map_name##_hashmap_entry_t out;                                                                               \\\n        _z_hashmap_entry_t e = _z_hashmap_extract(m, k);                                                              \\\n        out._key = e._key;                                                                                            \\\n        out._val = e._val;                                                                                            \\\n        return out;                                                                                                   \\\n    }                                                                                                                 \\\n    static inline size_t map_name##_hashmap_capacity(map_name##_hashmap_t *m) { return _z_hashmap_capacity(m); }      \\\n    static inline size_t map_name##_hashmap_len(map_name##_hashmap_t *m) { return _z_hashmap_len(m); }                \\\n    static inline bool map_name##_hashmap_is_empty(const map_name##_hashmap_t *m) { return _z_hashmap_is_empty(m); }  \\\n    static inline void map_name##_hashmap_clear(map_name##_hashmap_t *m) {                                            \\\n        _z_hashmap_clear(m, map_name##_hashmap_entry_elem_free);                                                      \\\n    }                                                                                                                 \\\n    static inline void map_name##_hashmap_free(map_name##_hashmap_t **m) {                                            \\\n        _z_hashmap_free(m, map_name##_hashmap_entry_elem_free);                                                       \\\n    }                                                                                                                 \\\n    static inline z_result_t map_name##_hashmap_move(map_name##_hashmap_t *dst, map_name##_hashmap_t *src) {          \\\n        _z_hashmap_move(dst, src);                                                                                    \\\n        return _Z_RES_OK;                                                                                             \\\n    }                                                                                                                 \\\n    static inline map_name##_hashmap_iterator_t map_name##_hashmap_iterator_make(const map_name##_hashmap_t *m) {     \\\n        return _z_hashmap_iterator_make(m);                                                                           \\\n    }                                                                                                                 \\\n    static inline bool map_name##_hashmap_iterator_next(map_name##_hashmap_iterator_t *iter) {                        \\\n        return _z_hashmap_iterator_next(iter);                                                                        \\\n    }                                                                                                                 \\\n    static inline key_type *map_name##_hashmap_iterator_key(const map_name##_hashmap_iterator_t *iter) {              \\\n        return (key_type *)_z_hashmap_iterator_key(iter);                                                             \\\n    }                                                                                                                 \\\n    static inline val_type *map_name##_hashmap_iterator_value(const map_name##_hashmap_iterator_t *iter) {            \\\n        return (val_type *)_z_hashmap_iterator_value(iter);                                                           \\\n    }\n\n#define _Z_HASHMAP_DEFINE(key_name, val_name, key_type, val_type) \\\n    _Z_HASHMAP_DEFINE_INNER(key_name##_##val_name, key_name, val_name, key_type, val_type)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_HASHMAP_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/hashmap_template.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// Hashmap with separate chaining using a fixed-size node pool.\n//\n// Each bucket is the head of an intrusive singly-linked list.  Nodes are\n// allocated from a flat pool of _ZP_HASHMAP_TEMPLATE_CAPACITY\n// elements — no heap allocation is performed.\n//\n// User must define the following macros before including this file:\n//\n// Required:\n//   _ZP_HASHMAP_TEMPLATE_KEY_TYPE\n//       type of the key\n//   _ZP_HASHMAP_TEMPLATE_VAL_TYPE\n//       type of the value\n//   _ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME(key_ptr) -> size_t\n//       hash function for the key\n//\n// Optional:\n//   _ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME(key_a_ptr, key_b_ptr) -> bool\n//       equality function for keys (default: memcmp == 0)\n//   _ZP_HASHMAP_TEMPLATE_NAME\n//       base name for all generated symbols\n//       (default: _ZP_CAT(key_type, _ZP_CAT(val_type, hmap)))\n//   _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT\n//       number of hash buckets\n//       (default: 16)\n//   _ZP_HASHMAP_TEMPLATE_CAPACITY\n//       maximum total number of entries that can be stored\n//       (default: _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT)\n//   _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(key_ptr)\n//       destroy a key (default: no-op)\n//   _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(val_ptr)\n//       destroy a value (default: no-op)\n//   _ZP_HASHMAP_TEMPLATE_KEY_MOVE_FN_NAME(dst_ptr, src_ptr)\n//       move a key (default: copy then destroy src)\n//   _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME(dst_ptr, src_ptr)\n//       move a value (default: copy then destroy src)\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/cat.h\"\n\n// ── Required macros ──────────────────────────────────────────────────────────\n\n#ifndef _ZP_HASHMAP_TEMPLATE_KEY_TYPE\n#error \"_ZP_HASHMAP_TEMPLATE_KEY_TYPE must be defined before including hashmap_template.h\"\n#define _ZP_HASHMAP_TEMPLATE_KEY_TYPE int\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_VAL_TYPE\n#error \"_ZP_HASHMAP_TEMPLATE_VAL_TYPE must be defined before including hashmap_template.h\"\n#define _ZP_HASHMAP_TEMPLATE_VAL_TYPE int\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME\n#error \"_ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME must be defined before including hashmap_template.h\"\n#endif\n\n// ── Optional macros with defaults ────────────────────────────────────────────\n#ifndef _ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME\n#define _ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME(key_a_ptr, key_b_ptr) (*(key_a_ptr) == *(key_b_ptr))\n#endif\n\n#ifndef _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT\n#define _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT 16\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_CAPACITY\n#define _ZP_HASHMAP_TEMPLATE_CAPACITY _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_NAME\n#define _ZP_HASHMAP_TEMPLATE_NAME _ZP_CAT(_ZP_HASHMAP_TEMPLATE_KEY_TYPE, _ZP_CAT(_ZP_HASHMAP_TEMPLATE_VAL_TYPE, hmap))\n#endif\n\n// ── Index type selection ──────────────────────────────────────────────────────\n//\n// Choose the smallest unsigned type whose maximum representable value is\n// strictly greater than CAPACITY (the extra value is used as the sentinel\n// \"end-of-list / empty-bucket\" marker).\n//\n//   CAPACITY ≤ 254   → uint8_t   (sentinel = 255)\n//   CAPACITY ≤ 65534 → uint16_t  (sentinel = 65535)\n//   otherwise        → uint32_t  (sentinel = UINT32_MAX)\n\n#if _ZP_HASHMAP_TEMPLATE_CAPACITY <= 254\n#define _ZP_HASHMAP_TEMPLATE_INDEX_TYPE uint8_t\n#define _ZP_HASHMAP_TEMPLATE_INDEX_NONE ((uint8_t)255)\n#elif _ZP_HASHMAP_TEMPLATE_CAPACITY <= 65534\n#define _ZP_HASHMAP_TEMPLATE_INDEX_TYPE uint16_t\n#define _ZP_HASHMAP_TEMPLATE_INDEX_NONE ((uint16_t)65535)\n#else\n#define _ZP_HASHMAP_TEMPLATE_INDEX_TYPE uint32_t\n#define _ZP_HASHMAP_TEMPLATE_INDEX_NONE ((uint32_t)0xFFFFFFFFu)\n#endif\n\n#ifndef _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME\n#define _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(x) (void)(x)\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME\n#define _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(x) (void)(x)\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_KEY_MOVE_FN_NAME\n#define _ZP_HASHMAP_TEMPLATE_KEY_MOVE_FN_NAME(dst, src) \\\n    *(dst) = *(src);                                    \\\n    _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(src);\n#endif\n#ifndef _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME\n#define _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME(dst, src) \\\n    *(dst) = *(src);                                    \\\n    _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(src);\n#endif\n\n// ── Internal name helpers ─────────────────────────────────────────────────────\n\n#define _ZP_HASHMAP_TEMPLATE_TYPE _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, t)\n#define _ZP_HASHMAP_TEMPLATE_NODE_TYPE _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, node_t)\n#define _ZP_HASHMAP_TEMPLATE_INDEX_TYPEDEF _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, index_t)\n\n// ── Node ──────────────────────────────────────────────────────────────────────\n//\n// Nodes live in a flat pool. The singly-linked-list \"next\" pointers are stored\n// in a separate parallel array (_next) rather than inside the node struct.\n// This avoids the tail-padding that the compiler would otherwise insert after\n// a small index field to satisfy the alignment requirement of the key/value\n// types.\n\ntypedef struct _ZP_HASHMAP_TEMPLATE_NODE_TYPE {\n    _ZP_HASHMAP_TEMPLATE_KEY_TYPE key;\n    _ZP_HASHMAP_TEMPLATE_VAL_TYPE val;\n} _ZP_HASHMAP_TEMPLATE_NODE_TYPE;\n\n// Public typedef for the index type so callers can store/declare indices without\n// spelling out the internal macro.\ntypedef _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _ZP_HASHMAP_TEMPLATE_INDEX_TYPEDEF;\n\n// ── Map type ──────────────────────────────────────────────────────────────────\n//\n// _next[i]     : index of the next node in the chain for pool slot i,\n//                INDEX_NONE = end-of-chain or free-list end.\n// _buckets[b]  : index of the first node in bucket b, INDEX_NONE = empty.\n// _free_head   : index of the first free pool slot (free list via _next).\n\ntypedef struct _ZP_HASHMAP_TEMPLATE_TYPE {\n    _ZP_HASHMAP_TEMPLATE_NODE_TYPE _pool[_ZP_HASHMAP_TEMPLATE_CAPACITY];\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _next[_ZP_HASHMAP_TEMPLATE_CAPACITY];\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _buckets[_ZP_HASHMAP_TEMPLATE_BUCKET_COUNT];\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _free_head;\n    size_t _size;  // number of live entries\n} _ZP_HASHMAP_TEMPLATE_TYPE;\n\n// ── new ───────────────────────────────────────────────────────────────────────\n\nstatic inline _ZP_HASHMAP_TEMPLATE_TYPE _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, new)(void) {\n    _ZP_HASHMAP_TEMPLATE_TYPE map;\n    for (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE b = 0; b < _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT; b++) {\n        map._buckets[b] = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n    }\n    for (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE i = 0; i + 1 < _ZP_HASHMAP_TEMPLATE_CAPACITY; i++) {\n        map._next[i] = (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE)(i + 1);\n    }\n    map._next[_ZP_HASHMAP_TEMPLATE_CAPACITY - 1] = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;  // end of free list\n    map._free_head = 0;\n    map._size = 0;\n    return map;\n}\n\n// ── Internal: allocate / free pool node ──────────────────────────────────────\n\nstatic inline _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME,\n                                                      pool_alloc)(_ZP_HASHMAP_TEMPLATE_TYPE *map) {\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx = map->_free_head;\n    if (idx == _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        return _ZP_HASHMAP_TEMPLATE_INDEX_NONE;  // pool full\n    }\n    map->_free_head = map->_next[idx];\n    map->_next[idx] = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n    return idx;\n}\n\nstatic inline void _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, pool_free)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                                 _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx) {\n    map->_next[idx] = map->_free_head;\n    map->_free_head = idx;\n}\n\n// ── get_idx ──────────────────────────────────────────────────────────────────\n// Returns an index of the node for key, or INDEX_NONE if not found.\n\nstatic inline _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME,\n                                                      get_idx)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                               const _ZP_HASHMAP_TEMPLATE_KEY_TYPE *key) {\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE b = (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE)(_ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME(key) %\n                                                                          _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT);\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx = map->_buckets[b];\n    while (idx != _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        _ZP_HASHMAP_TEMPLATE_NODE_TYPE *n = &map->_pool[idx];\n        if (_ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME(&n->key, key)) {\n            return idx;\n        }\n        idx = map->_next[idx];\n    }\n    return _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n}\n\n// ── get ───────────────────────────────────────────────────────────────────────\n// Returns a pointer to the value for key, or NULL if not found.\n\nstatic inline _ZP_HASHMAP_TEMPLATE_VAL_TYPE *_ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME,\n                                                     get)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                          const _ZP_HASHMAP_TEMPLATE_KEY_TYPE *key) {\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx = _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, get_idx)(map, key);\n    if (idx != _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        return &map->_pool[idx].val;\n    }\n    return NULL;\n}\n\n// ── contains ─────────────────────────────────────────────────────────────────\n\nstatic inline bool _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, contains)(const _ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                                const _ZP_HASHMAP_TEMPLATE_KEY_TYPE *key) {\n    return _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, get)((_ZP_HASHMAP_TEMPLATE_TYPE *)(uintptr_t)map, key) != NULL;\n}\n\n// ── size / is_empty ───────────────────────────────────────────────────────────\n\nstatic inline size_t _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, size)(const _ZP_HASHMAP_TEMPLATE_TYPE *map) {\n    return map->_size;\n}\n\nstatic inline bool _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, is_empty)(const _ZP_HASHMAP_TEMPLATE_TYPE *map) {\n    return map->_size == 0;\n}\n\n// ── index_valid ──────────────────────────────────────────────────────────────\n// index_valid: returns true when idx is a live node index (not the sentinel).\nstatic inline bool _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, index_valid)(_ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx) {\n    return idx != _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n}\n// ── node_at ──────────────────────────────────────────────────────────────────\n// Converts a valid index to a pointer to its node.\n// Behaviour is undefined if idx is INDEX_NONE.\nstatic inline _ZP_HASHMAP_TEMPLATE_NODE_TYPE *_ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME,\n                                                      node_at)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                               _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx) {\n    return &map->_pool[idx];\n}\n\n// ── insert ────────────────────────────────────────────────────────────────────\n// Takes ownership of *key and *val via move.\n// If key already exists: old value is destroyed, new value is moved in.\n// The new key is destroyed (existing key kept).\n// Returns the index of the inserted/updated node.\n// Returns INDEX_NONE only when the pool is exhausted and the key is not already\n// present.  Use index_valid() to check the result; use node_at() to obtain\n// a pointer to the node.\n\nstatic inline _ZP_HASHMAP_TEMPLATE_INDEX_TYPE _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME,\n                                                      insert)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                              _ZP_HASHMAP_TEMPLATE_KEY_TYPE *key,\n                                                              _ZP_HASHMAP_TEMPLATE_VAL_TYPE *val) {\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE b = (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE)(_ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME(key) %\n                                                                          _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT);\n    // Walk the chain looking for an existing entry with the same key\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx = map->_buckets[b];\n    while (idx != _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        _ZP_HASHMAP_TEMPLATE_NODE_TYPE *n = &map->_pool[idx];\n        if (_ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME(&n->key, key)) {\n            // Update: destroy incoming key, replace value in-place\n            _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(key);\n            _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(&n->val);\n            _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME(&n->val, val);\n            return idx;\n        }\n        idx = map->_next[idx];\n    }\n    // New entry — allocate a pool node\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE new_idx = _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, pool_alloc)(map);\n    if (new_idx == _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        return _ZP_HASHMAP_TEMPLATE_INDEX_NONE;  // pool exhausted\n    }\n    _ZP_HASHMAP_TEMPLATE_NODE_TYPE *n = &map->_pool[new_idx];\n    _ZP_HASHMAP_TEMPLATE_KEY_MOVE_FN_NAME(&n->key, key);\n    _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME(&n->val, val);\n    // Prepend to bucket chain (O(1))\n    map->_next[new_idx] = map->_buckets[b];\n    map->_buckets[b] = new_idx;\n    map->_size++;\n    return new_idx;\n}\n\n// ── remove_at ────────────────────────────────────────────────────────────────\n// Remove the node at the given pool index (obtained from insert or a prior\n// lookup).  Behaviour is undefined if idx is INDEX_NONE or has already been\n// freed.  If out_val != NULL the value is moved out; otherwise it is destroyed.\n\nstatic inline void _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, remove_at)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                                 _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx,\n                                                                 _ZP_HASHMAP_TEMPLATE_VAL_TYPE *out_val) {\n    _ZP_HASHMAP_TEMPLATE_NODE_TYPE *n = &map->_pool[idx];\n    // Re-derive the bucket from the node's own key so the caller does not need\n    // to supply it separately.\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE b =\n        (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE)(_ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME(&n->key) %\n                                          _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT);\n    // Walk the chain to find the predecessor and unlink idx.\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE prev = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE cur = map->_buckets[b];\n    while (cur != idx) {\n        prev = cur;\n        cur = map->_next[cur];\n    }\n    if (prev == _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        map->_buckets[b] = map->_next[idx];  // idx was the bucket head\n    } else {\n        map->_next[prev] = map->_next[idx];\n    }\n    _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(&n->key);\n    if (out_val != NULL) {\n        _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME(out_val, &n->val);\n    } else {\n        _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(&n->val);\n    }\n    _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, pool_free)(map, idx);\n    map->_size--;\n}\n\n// ── remove ────────────────────────────────────────────────────────────────────\n// If out_val != NULL the value is moved out; otherwise it is destroyed.\n// Returns true if the key was found.\n\nstatic inline bool _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, remove)(_ZP_HASHMAP_TEMPLATE_TYPE *map,\n                                                              const _ZP_HASHMAP_TEMPLATE_KEY_TYPE *key,\n                                                              _ZP_HASHMAP_TEMPLATE_VAL_TYPE *out_val) {\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE b = (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE)(_ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME(key) %\n                                                                          _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT);\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE prev = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n    _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx = map->_buckets[b];\n    while (idx != _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n        _ZP_HASHMAP_TEMPLATE_NODE_TYPE *n = &map->_pool[idx];\n        if (_ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME(&n->key, key)) {\n            // Unlink from chain\n            if (prev == _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n                map->_buckets[b] = map->_next[idx];  // was the head\n            } else {\n                map->_next[prev] = map->_next[idx];\n            }\n            _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(&n->key);\n            if (out_val != NULL) {\n                _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME(out_val, &n->val);\n            } else {\n                _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(&n->val);\n            }\n            _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, pool_free)(map, idx);\n            map->_size--;\n            return true;\n        }\n        prev = idx;\n        idx = map->_next[idx];\n    }\n    return false;\n}\n\n// ── destroy ─────────────────────────────────────────────────────────────────────\n// Destroys all entries and resets the map for reuse (does not free the map).\n\nstatic inline void _ZP_CAT(_ZP_HASHMAP_TEMPLATE_NAME, destroy)(_ZP_HASHMAP_TEMPLATE_TYPE *map) {\n    // Walk every bucket chain and destroy live entries\n    for (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE b = 0; b < _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT; b++) {\n        _ZP_HASHMAP_TEMPLATE_INDEX_TYPE idx = map->_buckets[b];\n        while (idx != _ZP_HASHMAP_TEMPLATE_INDEX_NONE) {\n            _ZP_HASHMAP_TEMPLATE_NODE_TYPE *n = &map->_pool[idx];\n            _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME(&n->key);\n            _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME(&n->val);\n            idx = map->_next[idx];\n        }\n        map->_buckets[b] = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;\n    }\n    // Rebuild the free list\n    for (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE i = 0; i + 1 < _ZP_HASHMAP_TEMPLATE_CAPACITY; i++) {\n        map->_next[i] = (_ZP_HASHMAP_TEMPLATE_INDEX_TYPE)(i + 1);\n    }\n    map->_next[_ZP_HASHMAP_TEMPLATE_CAPACITY - 1] = _ZP_HASHMAP_TEMPLATE_INDEX_NONE;  // end of free list\n    map->_free_head = 0;\n    map->_size = 0;\n}\n\n// ── Undef all macros ──────────────────────────────────────────────────────────\n\n#undef _ZP_HASHMAP_TEMPLATE_KEY_TYPE\n#undef _ZP_HASHMAP_TEMPLATE_VAL_TYPE\n#undef _ZP_HASHMAP_TEMPLATE_NAME\n#undef _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT\n#undef _ZP_HASHMAP_TEMPLATE_CAPACITY\n#undef _ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME\n#undef _ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME\n#undef _ZP_HASHMAP_TEMPLATE_KEY_DESTROY_FN_NAME\n#undef _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME\n#undef _ZP_HASHMAP_TEMPLATE_KEY_MOVE_FN_NAME\n#undef _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME\n#undef _ZP_HASHMAP_TEMPLATE_TYPE\n#undef _ZP_HASHMAP_TEMPLATE_NODE_TYPE\n#undef _ZP_HASHMAP_TEMPLATE_INDEX_TYPE\n#undef _ZP_HASHMAP_TEMPLATE_INDEX_NONE\n#undef _ZP_HASHMAP_TEMPLATE_INDEX_TYPEDEF\n"
  },
  {
    "path": "include/zenoh-pico/collections/intmap.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_INTMAP_H\n#define ZENOH_PICO_COLLECTIONS_INTMAP_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/hashmap.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_DEFAULT_INT_MAP_CAPACITY 16\n\ntypedef _z_hashmap_t _z_int_void_map_t;\ntypedef _z_hashmap_entry_t _z_int_void_map_entry_t;\ntypedef _z_hashmap_iterator_t _z_int_void_map_iterator_t;\n\nstatic inline size_t _z_int_void_map_hash(const void *key) { return *(const size_t *)key; }\n\nstatic inline bool _z_int_void_map_eq(const void *left, const void *right) {\n    const _z_int_void_map_entry_t *l = (_z_int_void_map_entry_t *)left;\n    const _z_int_void_map_entry_t *r = (_z_int_void_map_entry_t *)right;\n    return *(size_t *)l->_key == *(size_t *)r->_key;\n}\n\nstatic inline void _z_int_void_map_init(_z_int_void_map_t *map, size_t capacity) {\n    _z_hashmap_init(map, capacity, _z_int_void_map_hash, _z_int_void_map_eq);\n}\n\nstatic inline _z_int_void_map_t _z_int_void_map_make(size_t capacity) {\n    return _z_hashmap_make(capacity, _z_int_void_map_hash, _z_int_void_map_eq);\n}\n\nstatic inline void *_z_int_void_map_insert(_z_int_void_map_t *map, size_t k, void *v, z_element_free_f f,\n                                           bool replace) {\n    size_t *key = (size_t *)z_malloc(sizeof(size_t));\n    if (key == NULL) {\n        _Z_ERROR(\"Failed to allocate key for intmap.\");\n        return NULL;\n    }\n    *key = k;\n    void *ret = _z_hashmap_insert(map, key, v, f, replace);\n    if (ret == NULL) {\n        z_free(key);\n    }\n    return ret;\n}\n\nstatic inline void *_z_int_void_map_get(const _z_int_void_map_t *map, size_t k) { return _z_hashmap_get(map, &k); }\n\nstatic inline _z_list_t *_z_int_void_map_get_all(const _z_int_void_map_t *map, size_t k) {\n    return _z_hashmap_get_all(map, &k);\n}\n\nstatic inline void _z_int_void_map_remove(_z_int_void_map_t *map, size_t k, z_element_free_f f) {\n    _z_hashmap_remove(map, &k, f);\n}\n\nstatic inline size_t _z_int_void_map_capacity(const _z_int_void_map_t *map) { return _z_hashmap_capacity(map); }\n\nstatic inline size_t _z_int_void_map_len(const _z_int_void_map_t *map) { return _z_hashmap_len(map); }\n\nstatic inline bool _z_int_void_map_is_empty(const _z_int_void_map_t *map) { return _z_hashmap_is_empty(map); }\n\nstatic inline z_result_t _z_int_void_map_copy(_z_int_void_map_t *dst, const _z_int_void_map_t *src,\n                                              z_element_clone_f f_c) {\n    return _z_hashmap_copy(dst, src, f_c);\n}\n\nstatic inline _z_int_void_map_t _z_int_void_map_clone(const _z_int_void_map_t *src, z_element_clone_f f_c,\n                                                      z_element_free_f f_f) {\n    return _z_hashmap_clone(src, f_c, f_f);\n}\n\nstatic inline void _z_int_void_map_clear(_z_int_void_map_t *map, z_element_free_f f) { _z_hashmap_clear(map, f); }\n\nstatic inline void _z_int_void_map_free(_z_int_void_map_t **map, z_element_free_f f) { _z_hashmap_free(map, f); }\n\nstatic inline void _z_int_void_map_move(_z_int_void_map_t *dst, _z_int_void_map_t *src) { _z_hashmap_move(dst, src); }\n\nstatic inline _z_int_void_map_iterator_t _z_int_void_map_iterator_make(const _z_int_void_map_t *map) {\n    return _z_hashmap_iterator_make(map);\n}\n\nstatic inline bool _z_int_void_map_iterator_next(_z_int_void_map_iterator_t *iter) {\n    return _z_hashmap_iterator_next(iter);\n}\n\nstatic inline size_t _z_int_void_map_iterator_key(const _z_int_void_map_iterator_t *iter) {\n    return *((size_t *)_z_hashmap_iterator_key(iter));\n}\n\nstatic inline void *_z_int_void_map_iterator_value(const _z_int_void_map_iterator_t *iter) {\n    return _z_hashmap_iterator_value(iter);\n}\n\n#define _Z_INT_MAP_DEFINE(name, type)                                                                           \\\n    typedef _z_int_void_map_entry_t name##_intmap_entry_t;                                                      \\\n    static inline void name##_intmap_entry_elem_free(void **e) {                                                \\\n        name##_intmap_entry_t *ptr = (name##_intmap_entry_t *)*e;                                               \\\n        if (ptr != NULL) {                                                                                      \\\n            z_free(ptr->_key);                                                                                  \\\n            name##_elem_free(&ptr->_val);                                                                       \\\n            z_free(ptr);                                                                                        \\\n            *e = NULL;                                                                                          \\\n        }                                                                                                       \\\n    }                                                                                                           \\\n    static inline void *name##_intmap_entry_elem_clone(const void *e) {                                         \\\n        const name##_intmap_entry_t *src = (name##_intmap_entry_t *)e;                                          \\\n        name##_intmap_entry_t *dst = (name##_intmap_entry_t *)z_malloc(sizeof(name##_intmap_entry_t));          \\\n        if (dst == NULL) {                                                                                      \\\n            _Z_ERROR(\"Failed to allocate intmap entry clone.\");                                                 \\\n            return NULL;                                                                                        \\\n        }                                                                                                       \\\n        dst->_key = z_malloc(sizeof(size_t));                                                                   \\\n        if (dst->_key == NULL) {                                                                                \\\n            _Z_ERROR(\"Failed to allocate key for intmap entry clone.\");                                         \\\n            z_free(dst);                                                                                        \\\n            return NULL;                                                                                        \\\n        }                                                                                                       \\\n        *((size_t *)dst->_key) = *((size_t *)src->_key);                                                        \\\n        dst->_val = name##_elem_clone(src->_val);                                                               \\\n        return dst;                                                                                             \\\n    }                                                                                                           \\\n    typedef _z_int_void_map_t name##_intmap_t;                                                                  \\\n    typedef _z_int_void_map_iterator_t name##_intmap_iterator_t;                                                \\\n    static inline void name##_intmap_init(name##_intmap_t *m) {                                                 \\\n        _z_int_void_map_init(m, _Z_DEFAULT_INT_MAP_CAPACITY);                                                   \\\n    }                                                                                                           \\\n    static inline name##_intmap_t name##_intmap_make(void) {                                                    \\\n        return _z_int_void_map_make(_Z_DEFAULT_INT_MAP_CAPACITY);                                               \\\n    }                                                                                                           \\\n    static inline type *name##_intmap_insert(name##_intmap_t *m, size_t k, type *v) {                           \\\n        return (type *)_z_int_void_map_insert(m, k, v, name##_intmap_entry_elem_free, true);                    \\\n    }                                                                                                           \\\n    static inline type *name##_intmap_insert_push(name##_intmap_t *m, size_t k, type *v) {                      \\\n        return (type *)_z_int_void_map_insert(m, k, v, name##_intmap_entry_elem_free, false);                   \\\n    }                                                                                                           \\\n    static inline type *name##_intmap_get(const name##_intmap_t *m, size_t k) {                                 \\\n        return (type *)_z_int_void_map_get(m, k);                                                               \\\n    }                                                                                                           \\\n    static inline _z_list_t *name##_intmap_get_all(const name##_intmap_t *m, size_t k) {                        \\\n        return _z_int_void_map_get_all(m, k);                                                                   \\\n    }                                                                                                           \\\n    static inline name##_intmap_t name##_intmap_clone(const name##_intmap_t *m) {                               \\\n        return _z_int_void_map_clone(m, name##_intmap_entry_elem_clone, name##_intmap_entry_elem_free);         \\\n    }                                                                                                           \\\n    static inline void name##_intmap_remove(name##_intmap_t *m, size_t k) {                                     \\\n        _z_int_void_map_remove(m, k, name##_intmap_entry_elem_free);                                            \\\n    }                                                                                                           \\\n    static inline size_t name##_intmap_capacity(name##_intmap_t *m) { return _z_int_void_map_capacity(m); }     \\\n    static inline size_t name##_intmap_len(name##_intmap_t *m) { return _z_int_void_map_len(m); }               \\\n    static inline bool name##_intmap_is_empty(const name##_intmap_t *m) { return _z_int_void_map_is_empty(m); } \\\n    static inline void name##_intmap_clear(name##_intmap_t *m) {                                                \\\n        _z_int_void_map_clear(m, name##_intmap_entry_elem_free);                                                \\\n    }                                                                                                           \\\n    static inline void name##_intmap_free(name##_intmap_t **m) {                                                \\\n        _z_int_void_map_free(m, name##_intmap_entry_elem_free);                                                 \\\n    }                                                                                                           \\\n    static inline z_result_t name##_intmap_move(name##_intmap_t *dst, name##_intmap_t *src) {                   \\\n        _z_int_void_map_move(dst, src);                                                                         \\\n        return _Z_RES_OK;                                                                                       \\\n    }                                                                                                           \\\n    static inline name##_intmap_iterator_t name##_intmap_iterator_make(const name##_intmap_t *m) {              \\\n        return _z_int_void_map_iterator_make(m);                                                                \\\n    }                                                                                                           \\\n    static inline bool name##_intmap_iterator_next(name##_intmap_iterator_t *iter) {                            \\\n        return _z_int_void_map_iterator_next(iter);                                                             \\\n    }                                                                                                           \\\n    static inline size_t name##_intmap_iterator_key(const name##_intmap_iterator_t *iter) {                     \\\n        return _z_int_void_map_iterator_key(iter);                                                              \\\n    }                                                                                                           \\\n    static inline type *name##_intmap_extract(name##_intmap_t *m, size_t k) {                                   \\\n        type *out;                                                                                              \\\n        _z_int_void_map_entry_t e = _z_hashmap_extract(m, &k);                                                  \\\n        out = (type *)e._val;                                                                                   \\\n        z_free(e._key);                                                                                         \\\n        return out;                                                                                             \\\n    }                                                                                                           \\\n    static inline type *name##_intmap_iterator_value(const name##_intmap_iterator_t *iter) {                    \\\n        return (type *)_z_int_void_map_iterator_value(iter);                                                    \\\n    }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_INTMAP_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/lifo.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef ZENOH_PICO_COLLECTIONS_LIFO_H\n#define ZENOH_PICO_COLLECTIONS_LIFO_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Ring Buffer --------*/\ntypedef struct {\n    void **_val;\n    size_t _capacity;\n    size_t _len;\n} _z_lifo_t;\n\nz_result_t _z_lifo_init(_z_lifo_t *lifo, size_t capacity);\n_z_lifo_t _z_lifo_make(size_t capacity);\n\nsize_t _z_lifo_capacity(const _z_lifo_t *r);\nsize_t _z_lifo_len(const _z_lifo_t *r);\nbool _z_lifo_is_empty(const _z_lifo_t *r);\nbool _z_lifo_is_full(const _z_lifo_t *r);\n\nvoid *_z_lifo_push(_z_lifo_t *r, void *e);\nvoid _z_lifo_push_drop(_z_lifo_t *r, void *e, z_element_free_f f);\nvoid *_z_lifo_pull(_z_lifo_t *r);\n\n_z_lifo_t *_z_lifo_clone(const _z_lifo_t *xs, z_element_clone_f d_f);\n\nvoid _z_lifo_clear(_z_lifo_t *v, z_element_free_f f);\nvoid _z_lifo_free(_z_lifo_t **xs, z_element_free_f f_f);\n\n#define _Z_LIFO_DEFINE(name, type)                                                                         \\\n    typedef _z_lifo_t name##_lifo_t;                                                                       \\\n    static inline z_result_t name##_lifo_init(name##_lifo_t *lifo, size_t capacity) {                      \\\n        return _z_lifo_init(lifo, capacity);                                                               \\\n    }                                                                                                      \\\n    static inline name##_lifo_t name##_lifo_make(size_t capacity) { return _z_lifo_make(capacity); }       \\\n    static inline size_t name##_lifo_capacity(const name##_lifo_t *r) { return _z_lifo_capacity(r); }      \\\n    static inline size_t name##_lifo_len(const name##_lifo_t *r) { return _z_lifo_len(r); }                \\\n    static inline bool name##_lifo_is_empty(const name##_lifo_t *r) { return _z_lifo_is_empty(r); }        \\\n    static inline bool name##_lifo_is_full(const name##_lifo_t *r) { return _z_lifo_is_full(r); }          \\\n    static inline type *name##_lifo_push(name##_lifo_t *r, type *e) { return _z_lifo_push(r, (void *)e); } \\\n    static inline void name##_lifo_push_drop(name##_lifo_t *r, type *e) {                                  \\\n        _z_lifo_push_drop(r, (void *)e, name##_elem_free);                                                 \\\n    }                                                                                                      \\\n    static inline type *name##_lifo_pull(name##_lifo_t *r) { return (type *)_z_lifo_pull(r); }             \\\n    static inline void name##_lifo_clear(name##_lifo_t *r) { _z_lifo_clear(r, name##_elem_free); }         \\\n    static inline void name##_lifo_free(name##_lifo_t **r) { _z_lifo_free(r, name##_elem_free); }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_LIFO_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/list.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_LIST_H\n#define ZENOH_PICO_COLLECTIONS_LIST_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Single-linked List --------*/\n/**\n * A single-linked list. Elements are stored as pointers.\n *\n *  Members:\n *   void *lal: The pointer to the inner value.\n *   struct z_list *tail: A pointer to the next element in the list.\n */\ntypedef struct _z_l_t {\n    void *_val;\n    struct _z_l_t *_next;\n} _z_list_t;\n\nsize_t _z_list_len(const _z_list_t *xs);\nstatic inline bool _z_list_is_empty(const _z_list_t *xs) { return xs == NULL; }\nstatic inline void *_z_list_value(const _z_list_t *xs) { return xs->_val; }\nstatic inline _z_list_t *_z_list_next(const _z_list_t *xs) { return xs->_next; }\n\n_z_list_t *_z_list_push(_z_list_t *xs, void *x);\n_z_list_t *_z_list_push_after(_z_list_t *xs, void *x);\n_z_list_t *_z_list_push_back(_z_list_t *xs, void *x);\n_z_list_t *_z_list_push_sorted(_z_list_t *xs, z_element_cmp_f c_f, void *x);\n_z_list_t *_z_list_pop(_z_list_t *xs, z_element_free_f f_f, void **x);\n\n_z_list_t *_z_list_find(const _z_list_t *xs, z_element_eq_f f_f, const void *e);\n_z_list_t *_z_list_drop_element(_z_list_t *list, _z_list_t *prev, z_element_free_f f_f);\n_z_list_t *_z_list_drop_filter(_z_list_t *xs, z_element_free_f f_f, z_element_eq_f c_f, const void *left,\n                               bool only_first);\n_z_list_t *_z_list_extract_filter(_z_list_t *xs, z_element_eq_f c_f, const void *left, _z_list_t **extracted,\n                                  bool only_first);\n\n_z_list_t *_z_list_clone(const _z_list_t *xs, z_element_clone_f d_f);\nvoid _z_list_free(_z_list_t **xs, z_element_free_f f_f);\n\n#define _Z_LIST_DEFINE(name, type)                                                                                    \\\n    typedef _z_list_t name##_list_t;                                                                                  \\\n    static inline name##_list_t *name##_list_new(void) { return NULL; }                                               \\\n    static inline size_t name##_list_len(const name##_list_t *l) { return _z_list_len(l); }                           \\\n    static inline bool name##_list_is_empty(const name##_list_t *l) { return _z_list_is_empty(l); }                   \\\n    static inline type *name##_list_value(const name##_list_t *l) { return (type *)_z_list_value(l); }                \\\n    static inline name##_list_t *name##_list_next(const name##_list_t *l) { return _z_list_next(l); }                 \\\n    static inline name##_list_t *name##_list_push(name##_list_t *l, type *e) { return _z_list_push(l, e); }           \\\n    static inline name##_list_t *name##_list_push_after(name##_list_t *l, type *e) {                                  \\\n        return _z_list_push_after(l, e);                                                                              \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_push_back(name##_list_t *l, type *e) { return _z_list_push_back(l, e); } \\\n    static inline name##_list_t *name##_list_push_sorted(name##_list_t *l, type *e) {                                 \\\n        return _z_list_push_sorted(l, name##_elem_cmp, e);                                                            \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_pop(name##_list_t *l, type **x) {                                        \\\n        return _z_list_pop(l, name##_elem_free, (void **)x);                                                          \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_find(const name##_list_t *l, name##_eq_f c_f, const type *e) {           \\\n        return _z_list_find(l, (z_element_eq_f)c_f, e);                                                               \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_drop_element(name##_list_t *l, name##_list_t *p) {                       \\\n        return _z_list_drop_element(l, p, name##_elem_free);                                                          \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_drop_first_filter(name##_list_t *l, name##_eq_f c_f, const type *e) {    \\\n        return _z_list_drop_filter(l, name##_elem_free, (z_element_eq_f)c_f, e, true);                                \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_drop_all_filter(name##_list_t *l, name##_eq_f c_f, const type *e) {      \\\n        return _z_list_drop_filter(l, name##_elem_free, (z_element_eq_f)c_f, e, false);                               \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_extract_all_filter(name##_list_t *l, name##_list_t **extracted,          \\\n                                                                name##_eq_f c_f, const type *e) {                     \\\n        return _z_list_extract_filter(l, (z_element_eq_f)c_f, e, extracted, false);                                   \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_extract_first_filter(name##_list_t *l, name##_list_t **extracted,        \\\n                                                                  name##_eq_f c_f, const type *e) {                   \\\n        return _z_list_extract_filter(l, (z_element_eq_f)c_f, e, extracted, true);                                    \\\n    }                                                                                                                 \\\n    static inline name##_list_t *name##_list_clone(name##_list_t *l) { return _z_list_clone(l, name##_elem_clone); }  \\\n    static inline void name##_list_free(name##_list_t **l) { _z_list_free(l, name##_elem_free); }\n\n/*-------- Sized Single-linked List --------*/\n/**\n * A single-linked list. Elements are stored as value.\n *\n *  Members:\n *   _z_slist_node_t *data: Pointer to internal data\n */\n\n// Node struct: {next node_address; generic type}\ntypedef void _z_slist_t;\n\nstatic inline bool _z_slist_is_empty(const _z_slist_t *node) { return node == NULL; }\n_z_slist_t *_z_slist_push_empty(_z_slist_t *node, size_t value_size);\n_z_slist_t *_z_slist_push(_z_slist_t *node, const void *value, size_t value_size, z_element_copy_f d_f,\n                          bool use_elem_f);\n_z_slist_t *_z_slist_push_back(_z_slist_t *node, const void *value, size_t value_size, z_element_copy_f d_f,\n                               bool use_elem_f);\nvoid *_z_slist_value(const _z_slist_t *node);\n_z_slist_t *_z_slist_next(const _z_slist_t *node);\nsize_t _z_slist_len(const _z_slist_t *node);\n_z_slist_t *_z_slist_pop(_z_slist_t *node, z_element_clear_f f_f);\n_z_slist_t *_z_slist_find(const _z_slist_t *node, z_element_eq_f c_f, const void *target_val);\n_z_slist_t *_z_slist_drop_element(_z_slist_t *list, _z_slist_t *prev, z_element_clear_f f_f);\n_z_slist_t *_z_slist_drop_filter(_z_slist_t *head, z_element_clear_f f_f, z_element_eq_f c_f, const void *target_val,\n                                 bool only_first);\n_z_slist_t *_z_slist_extract_filter(_z_slist_t *head, z_element_eq_f c_f, const void *target_val,\n                                    _z_slist_t **extracted, bool only_first);\n_z_slist_t *_z_slist_clone(const _z_slist_t *node, size_t value_size, z_element_copy_f d_f, bool use_elem_f);\nvoid _z_slist_free(_z_slist_t **node, z_element_clear_f f);\n\n#define _Z_SLIST_DEFINE(name, type, use_elem_f)                                                                       \\\n    typedef _z_slist_t name##_slist_t;                                                                                \\\n    static inline name##_slist_t *name##_slist_new(void) { return NULL; }                                             \\\n    static inline size_t name##_slist_len(const name##_slist_t *l) { return _z_slist_len(l); }                        \\\n    static inline bool name##_slist_is_empty(const name##_slist_t *l) { return _z_slist_is_empty(l); }                \\\n    static inline name##_slist_t *name##_slist_next(const name##_slist_t *l) { return _z_slist_next(l); }             \\\n    static inline type *name##_slist_value(const name##_slist_t *l) { return (type *)_z_slist_value(l); }             \\\n    static inline name##_slist_t *name##_slist_push_empty(name##_slist_t *l) {                                        \\\n        return _z_slist_push_empty(l, sizeof(type));                                                                  \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_push(name##_slist_t *l, const type *e) {                               \\\n        return _z_slist_push(l, e, sizeof(type), name##_elem_copy, use_elem_f);                                       \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_push_back(name##_slist_t *l, const type *e) {                          \\\n        return _z_slist_push_back(l, e, sizeof(type), name##_elem_copy, use_elem_f);                                  \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_pop(name##_slist_t *l) { return _z_slist_pop(l, name##_elem_clear); }  \\\n    static inline name##_slist_t *name##_slist_find(const name##_slist_t *l, name##_eq_f c_f, const type *e) {        \\\n        return _z_slist_find(l, (z_element_eq_f)c_f, e);                                                              \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_drop_element(name##_slist_t *l, name##_slist_t *p) {                   \\\n        return _z_slist_drop_element(l, p, name##_elem_clear);                                                        \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_drop_all_filter(name##_slist_t *l, name##_eq_f c_f, const type *e) {   \\\n        return _z_slist_drop_filter(l, name##_elem_clear, (z_element_eq_f)c_f, e, false);                             \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_drop_first_filter(name##_slist_t *l, name##_eq_f c_f, const type *e) { \\\n        return _z_slist_drop_filter(l, name##_elem_clear, (z_element_eq_f)c_f, e, true);                              \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_extract_all_filter(name##_slist_t *l, name##_slist_t **extracted,      \\\n                                                                  name##_eq_f c_f, const type *e) {                   \\\n        return _z_slist_extract_filter(l, (z_element_eq_f)c_f, e, extracted, false);                                  \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_extract_first_filter(name##_slist_t *l, name##_slist_t **extracted,    \\\n                                                                    name##_eq_f c_f, const type *e) {                 \\\n        return _z_slist_extract_filter(l, (z_element_eq_f)c_f, e, extracted, true);                                   \\\n    }                                                                                                                 \\\n    static inline name##_slist_t *name##_slist_clone(name##_slist_t *l) {                                             \\\n        return _z_slist_clone(l, sizeof(type), name##_elem_copy, use_elem_f);                                         \\\n    }                                                                                                                 \\\n    static inline void name##_slist_free(name##_slist_t **l) { _z_slist_free(l, name##_elem_clear); }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_LIST_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/lru_cache.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_LRUCACHE_H\n#define ZENOH_PICO_COLLECTIONS_LRUCACHE_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Three way comparison function pointer\ntypedef int (*_z_lru_val_cmp_f)(const void *first, const void *second);\n\n// Node struct: {node_data; generic type}\ntypedef void _z_lru_cache_node_t;\n\n/*-------- Dynamically allocated vector --------*/\n/**\n * A least recently used cache implementation\n */\ntypedef struct _z_lru_cache_t {\n    size_t capacity;              // Max number of node\n    size_t len;                   // Number of node\n    _z_lru_cache_node_t *head;    // List head\n    _z_lru_cache_node_t *tail;    // List tail\n    _z_lru_cache_node_t **slist;  // Sorted node list\n} _z_lru_cache_t;\n\n_z_lru_cache_t _z_lru_cache_init(size_t capacity);\nvoid *_z_lru_cache_get(_z_lru_cache_t *cache, void *value, _z_lru_val_cmp_f compare);\nz_result_t _z_lru_cache_insert(_z_lru_cache_t *cache, void *value, size_t value_size, _z_lru_val_cmp_f compare);\nvoid _z_lru_cache_clear(_z_lru_cache_t *cache, z_element_clear_f clear);\nvoid _z_lru_cache_delete(_z_lru_cache_t *cache, z_element_clear_f clear);\n\n#define _Z_LRU_CACHE_DEFINE(name, type, compare_f)                                                                  \\\n    typedef _z_lru_cache_t name##_lru_cache_t;                                                                      \\\n    static inline name##_lru_cache_t name##_lru_cache_init(size_t capacity) { return _z_lru_cache_init(capacity); } \\\n    static inline type *name##_lru_cache_get(name##_lru_cache_t *cache, type *val) {                                \\\n        return (type *)_z_lru_cache_get(cache, (void *)val, compare_f);                                             \\\n    }                                                                                                               \\\n    static inline z_result_t name##_lru_cache_insert(name##_lru_cache_t *cache, type *val) {                        \\\n        return _z_lru_cache_insert(cache, (void *)val, sizeof(type), compare_f);                                    \\\n    }                                                                                                               \\\n    static inline void name##_lru_cache_clear(name##_lru_cache_t *cache) {                                          \\\n        _z_lru_cache_clear(cache, name##_elem_clear);                                                               \\\n    }                                                                                                               \\\n    static inline void name##_lru_cache_delete(name##_lru_cache_t *cache) {                                         \\\n        _z_lru_cache_delete(cache, name##_elem_clear);                                                              \\\n    }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_LRUCACHE_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/pqueue_template.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// user needs to define the following macros before including this file:\n// _ZP_PQUEUE_TEMPLATE_ELEM_TYPE: the type of the elements in the priority queue\n// _ZP_PQUEUE_TEMPLATE_NAME: the name of the priority queue type to generate (without the _t suffix)\n// _ZP_PQUEUE_TEMPLATE_SIZE: the maximum size of the priority queue (optional, default is 16)\n// _ZP_PQUEUE_TEMPLATE_ELEM_DESTROY_FN_NAME: the name of the function to destroy an element (optional, default is a\n// no-op) _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME: the name of the function to move an element (optional, default is\n// element-wise copy + destroy source) _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME: the name of the comparison function\n// (elem_a, elem_b) -> int\n//   should return <0 if a has higher priority than b, 0 if equal, >0 if b has higher priority than a\n//   (i.e. min-priority queue by default: smallest element is at the top)\n//\n// Optional context support:\n//   _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE: the type of an optional context passed to the compare function.\n//       When defined, the compare macro signature becomes (elem_a, elem_b, ctx_ptr) where ctx_ptr is of type\n//       _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE *.  The context is stored inside the queue struct and supplied to every\n//       sift_up / sift_down call automatically.  Use new_with_ctx(ctx) to initialise it; new() zero-initialises it.\n//       When not defined (the default), the compare macro keeps its original (elem_a, elem_b) signature and no\n//       context is stored.\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#include \"zenoh-pico/collections/cat.h\"\n\n#ifndef _ZP_PQUEUE_TEMPLATE_ELEM_TYPE\n#error \"_ZP_PQUEUE_TEMPLATE_ELEM_TYPE must be defined before including pqueue_template.h\"\n#define _ZP_PQUEUE_TEMPLATE_ELEM_TYPE int\n#endif\n#ifndef _ZP_PQUEUE_TEMPLATE_SIZE\n#define _ZP_PQUEUE_TEMPLATE_SIZE 16\n#endif\n#ifndef _ZP_PQUEUE_TEMPLATE_NAME\n#define _ZP_PQUEUE_TEMPLATE_NAME _ZP_CAT(_ZP_CAT(_ZP_PQUEUE_TEMPLATE_ELEM_TYPE, pqueue), _ZP_PQUEUE_TEMPLATE_SIZE)\n#endif\n#ifndef _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME\n#error \"_ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME must be defined before including pqueue_template.h\"\n#endif\n#ifndef _ZP_PQUEUE_TEMPLATE_ELEM_DESTROY_FN_NAME\n#define _ZP_PQUEUE_TEMPLATE_ELEM_DESTROY_FN_NAME(x) (void)(x)\n#endif\n#ifndef _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME\n#define _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(dst, src) \\\n    *(dst) = *(src);                                    \\\n    _ZP_PQUEUE_TEMPLATE_ELEM_DESTROY_FN_NAME(src);\n#endif\n\n// ── Context support ───────────────────────────────────────────────────────────\n// Internally the template always calls _ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL(a, b, ctx_ptr).\n// When _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE is defined the user-supplied CMP_FN receives the pointer;\n// otherwise we define the internal macro to call the 2-argument CMP_FN and ignore ctx.\n\n#ifdef _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE\n// Context-aware path: user compare macro is (elem_a, elem_b, ctx_ptr)\n#define _ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL(a, b, pqueue) \\\n    _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME((a), (b), (pqueue->_cmp_ctx))\n#else\n// Context-free path: user compare macro is (elem_a, elem_b); ctx ignored\n#define _ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL(a, b, pqueue) _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME((a), (b))\n#endif\n\n#define _ZP_PQUEUE_TEMPLATE_TYPE _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, t)\ntypedef struct _ZP_PQUEUE_TEMPLATE_TYPE {\n    _ZP_PQUEUE_TEMPLATE_ELEM_TYPE _buffer[_ZP_PQUEUE_TEMPLATE_SIZE];\n    size_t _size;\n#ifdef _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE\n    _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE *_cmp_ctx;\n#endif\n} _ZP_PQUEUE_TEMPLATE_TYPE;\n\nstatic inline _ZP_PQUEUE_TEMPLATE_TYPE _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, new)(void) {\n    _ZP_PQUEUE_TEMPLATE_TYPE pqueue = {0};\n    return pqueue;\n}\n\n#ifdef _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE\n// new_with_ctx: initialise the queue and store a context pointer for comparisons.\nstatic inline _ZP_PQUEUE_TEMPLATE_TYPE _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME,\n                                               new_with_ctx)(_ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE *ctx) {\n    _ZP_PQUEUE_TEMPLATE_TYPE pqueue = {0};\n    pqueue._cmp_ctx = ctx;\n    return pqueue;\n}\n// set_ctx: overwrite the context pointer in an existing queue.\n// This is useful if the context needs to be updated after the queue is created (for example in case of move of\n// self-referencing structs), or if new() was used to create a zero-initialised queue and the context pointer needs to\n// be set later.\nstatic inline void _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, set_ctx)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue,\n                                                              _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE *ctx) {\n    pqueue->_cmp_ctx = ctx;\n}\n#endif\n\nstatic inline void _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, destroy)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue) {\n    for (size_t i = 0; i < pqueue->_size; i++) {\n        _ZP_PQUEUE_TEMPLATE_ELEM_DESTROY_FN_NAME(&pqueue->_buffer[i]);\n    }\n    pqueue->_size = 0;\n}\nstatic inline size_t _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, size)(const _ZP_PQUEUE_TEMPLATE_TYPE *pqueue) {\n    return pqueue->_size;\n}\nstatic inline bool _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, is_empty)(const _ZP_PQUEUE_TEMPLATE_TYPE *pqueue) {\n    return pqueue->_size == 0;\n}\nstatic inline _ZP_PQUEUE_TEMPLATE_ELEM_TYPE *_ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, peek)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue) {\n    if (pqueue->_size == 0) {\n        return NULL;\n    }\n    return &pqueue->_buffer[0];\n}\nstatic inline void _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, sift_up)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue, size_t i) {\n    while (i > 0) {\n        size_t parent = (i - 1) / 2;\n        if (_ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL(&pqueue->_buffer[i], &pqueue->_buffer[parent], pqueue) < 0) {\n            _ZP_PQUEUE_TEMPLATE_ELEM_TYPE tmp;\n            _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&tmp, &pqueue->_buffer[parent]);\n            _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&pqueue->_buffer[parent], &pqueue->_buffer[i]);\n            _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&pqueue->_buffer[i], &tmp);\n            i = parent;\n        } else {\n            break;\n        }\n    }\n}\nstatic inline void _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, sift_down)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue, size_t i) {\n    while (true) {\n        size_t left = 2 * i + 1;\n        size_t right = 2 * i + 2;\n        size_t best = i;\n        if (left < pqueue->_size &&\n            _ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL(&pqueue->_buffer[left], &pqueue->_buffer[best], pqueue) < 0) {\n            best = left;\n        }\n        if (right < pqueue->_size &&\n            _ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL(&pqueue->_buffer[right], &pqueue->_buffer[best], pqueue) < 0) {\n            best = right;\n        }\n        if (best == i) {\n            break;\n        }\n        _ZP_PQUEUE_TEMPLATE_ELEM_TYPE tmp;\n        _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&tmp, &pqueue->_buffer[i]);\n        _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&pqueue->_buffer[i], &pqueue->_buffer[best]);\n        _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&pqueue->_buffer[best], &tmp);\n        i = best;\n    }\n}\nstatic inline bool _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, push)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue,\n                                                           _ZP_PQUEUE_TEMPLATE_ELEM_TYPE *elem) {\n    if (pqueue->_size == _ZP_PQUEUE_TEMPLATE_SIZE) {\n        return false;\n    }\n    _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&pqueue->_buffer[pqueue->_size], elem);\n    _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, sift_up)(pqueue, pqueue->_size);\n    pqueue->_size++;\n    return true;\n}\nstatic inline bool _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, pop)(_ZP_PQUEUE_TEMPLATE_TYPE *pqueue,\n                                                          _ZP_PQUEUE_TEMPLATE_ELEM_TYPE *out) {\n    if (pqueue->_size == 0) {\n        return false;\n    }\n    _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(out, &pqueue->_buffer[0]);\n    pqueue->_size--;\n    if (pqueue->_size > 0) {\n        _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME(&pqueue->_buffer[0], &pqueue->_buffer[pqueue->_size]);\n        _ZP_CAT(_ZP_PQUEUE_TEMPLATE_NAME, sift_down)(pqueue, 0);\n    }\n    return true;\n}\n\n#undef _ZP_PQUEUE_TEMPLATE_ELEM_TYPE\n#undef _ZP_PQUEUE_TEMPLATE_NAME\n#undef _ZP_PQUEUE_TEMPLATE_SIZE\n#undef _ZP_PQUEUE_TEMPLATE_ELEM_DESTROY_FN_NAME\n#undef _ZP_PQUEUE_TEMPLATE_ELEM_MOVE_FN_NAME\n#undef _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME\n#undef _ZP_PQUEUE_TEMPLATE_TYPE\n#ifdef _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE\n#undef _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE\n#endif\n#undef _ZP_PQUEUE_TEMPLATE_ELEM_CMP_INTERNAL\n"
  },
  {
    "path": "include/zenoh-pico/collections/refcount.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_REFCOUNT_H\n#define ZENOH_PICO_COLLECTIONS_REFCOUNT_H\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_rc_init(void **cnt);\nz_result_t _z_rc_increase_strong(void *cnt);\nz_result_t _z_rc_increase_weak(void *cnt);\nbool _z_rc_decrease_strong(void **cnt);\nbool _z_rc_decrease_weak(void **cnt);\nz_result_t _z_rc_weak_upgrade(void *cnt);\n\nsize_t _z_rc_weak_count(void *cnt);\nsize_t _z_rc_strong_count(void *cnt);\n\nvoid *_z_simple_rc_value(void *rc);\nz_result_t _z_simple_rc_init(void **rc, const void *val, size_t val_size);\nz_result_t _z_simple_rc_increase(void *rc);\nbool _z_simple_rc_decrease(void *rc);\n\nsize_t _z_simple_rc_strong_count(void *rc);\n\n#define _Z_REFCOUNT_DEFINE_STRUCTS(name, type)                                               \\\n    typedef struct name##_rc_t {                                                             \\\n        type##_t *_val;                                                                      \\\n        void *_cnt;                                                                          \\\n    } name##_rc_t;                                                                           \\\n                                                                                             \\\n    typedef struct name##_weak_t {                                                           \\\n        type##_t *_val;                                                                      \\\n        void *_cnt;                                                                          \\\n    } name##_weak_t;                                                                         \\\n    static inline void name##_weak_to_rc_inner(const name##_weak_t *weak, name##_rc_t *rc) { \\\n        rc->_val = weak->_val;                                                               \\\n        rc->_cnt = weak->_cnt;                                                               \\\n    }                                                                                        \\\n    static inline void name##_rc_to_weak_inner(const name##_rc_t *rc, name##_weak_t *weak) { \\\n        weak->_val = rc->_val;                                                               \\\n        weak->_cnt = rc->_cnt;                                                               \\\n    }                                                                                        \\\n    static inline void name##_rc_clear_inner(name##_rc_t *rc) { type##_clear(rc->_val); }\n\n#define _Z_REFCOUNT_DEFINE_NO_FROM_VAL_INNER(name, type)                                                             \\\n                                                                                                                     \\\n    static inline name##_rc_t name##_rc_null(void) { return (name##_rc_t){0}; }                                      \\\n    static inline name##_weak_t name##_weak_null(void) { return (name##_weak_t){0}; }                                \\\n    static inline name##_rc_t name##_rc_clone(const name##_rc_t *p) {                                                \\\n        return _z_rc_increase_strong(p->_cnt) == _Z_RES_OK ? *p : name##_rc_null();                                  \\\n    }                                                                                                                \\\n    static inline name##_rc_t *name##_rc_clone_as_ptr(const name##_rc_t *p) {                                        \\\n        name##_rc_t *c = (name##_rc_t *)z_malloc(sizeof(name##_rc_t));                                               \\\n        if (c != NULL) {                                                                                             \\\n            *c = name##_rc_clone(p);                                                                                 \\\n            if (c->_cnt == NULL) {                                                                                   \\\n                z_free(c);                                                                                           \\\n                c = NULL;                                                                                            \\\n            }                                                                                                        \\\n        }                                                                                                            \\\n        return c;                                                                                                    \\\n    }                                                                                                                \\\n    static inline name##_weak_t name##_rc_clone_as_weak(const name##_rc_t *p) {                                      \\\n        if (_z_rc_increase_weak(p->_cnt) == _Z_RES_OK) {                                                             \\\n            name##_weak_t ret;                                                                                       \\\n            name##_rc_to_weak_inner(p, &ret);                                                                        \\\n            return ret;                                                                                              \\\n        }                                                                                                            \\\n        return name##_weak_null();                                                                                   \\\n    }                                                                                                                \\\n    static inline name##_weak_t *name##_rc_clone_as_weak_ptr(const name##_rc_t *p) {                                 \\\n        name##_weak_t *c = (name##_weak_t *)z_malloc(sizeof(name##_weak_t));                                         \\\n        if (c != NULL) {                                                                                             \\\n            *c = name##_rc_clone_as_weak(p);                                                                         \\\n            if (c->_cnt == NULL) {                                                                                   \\\n                z_free(c);                                                                                           \\\n                c = NULL;                                                                                            \\\n            }                                                                                                        \\\n        }                                                                                                            \\\n        return c;                                                                                                    \\\n    }                                                                                                                \\\n    static inline z_result_t name##_rc_copy(name##_rc_t *dst, const name##_rc_t *p) {                                \\\n        *dst = name##_rc_clone(p);                                                                                   \\\n        if (dst->_cnt == NULL) {                                                                                     \\\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);                                                            \\\n        }                                                                                                            \\\n        return _Z_RES_OK;                                                                                            \\\n    }                                                                                                                \\\n    static inline bool name##_rc_eq(const name##_rc_t *left, const name##_rc_t *right) {                             \\\n        return (left->_val == right->_val);                                                                          \\\n    }                                                                                                                \\\n    static inline bool name##_rc_decr(name##_rc_t *p) {                                                              \\\n        if ((p == NULL) || (p->_cnt == NULL)) {                                                                      \\\n            return false;                                                                                            \\\n        }                                                                                                            \\\n        if (_z_rc_decrease_strong(&p->_cnt)) {                                                                       \\\n            return true;                                                                                             \\\n        }                                                                                                            \\\n        return false;                                                                                                \\\n    }                                                                                                                \\\n    static inline bool name##_rc_drop(name##_rc_t *p) {                                                              \\\n        if (p == NULL) {                                                                                             \\\n            return false;                                                                                            \\\n        }                                                                                                            \\\n        bool res = false;                                                                                            \\\n        if (name##_rc_decr(p) && p->_val != NULL) {                                                                  \\\n            name##_rc_clear_inner(p);                                                                                \\\n            z_free(p->_val);                                                                                         \\\n            res = true;                                                                                              \\\n        }                                                                                                            \\\n        *p = name##_rc_null();                                                                                       \\\n        return res;                                                                                                  \\\n    }                                                                                                                \\\n    static inline name##_weak_t name##_weak_clone(const name##_weak_t *p) {                                          \\\n        return _z_rc_increase_weak(p->_cnt) == _Z_RES_OK ? *p : name##_weak_null();                                  \\\n    }                                                                                                                \\\n    static inline void name##_weak_copy(name##_weak_t *dst, const name##_weak_t *p) { *dst = name##_weak_clone(p); } \\\n    static inline name##_rc_t name##_weak_upgrade(const name##_weak_t *p) {                                          \\\n        if (_z_rc_weak_upgrade(p->_cnt) == _Z_RES_OK) {                                                              \\\n            name##_rc_t ret;                                                                                         \\\n            name##_weak_to_rc_inner(p, &ret);                                                                        \\\n            return ret;                                                                                              \\\n        }                                                                                                            \\\n        return name##_rc_null();                                                                                     \\\n    }                                                                                                                \\\n    static inline bool name##_weak_eq(const name##_weak_t *left, const name##_weak_t *right) {                       \\\n        return (left->_val == right->_val);                                                                          \\\n    }                                                                                                                \\\n    static inline bool name##_weak_drop(name##_weak_t *p) {                                                          \\\n        if ((p == NULL) || (p->_cnt == NULL)) {                                                                      \\\n            return false;                                                                                            \\\n        }                                                                                                            \\\n        bool res = false;                                                                                            \\\n        if (_z_rc_decrease_weak(&p->_cnt)) {                                                                         \\\n            res = true;                                                                                              \\\n        }                                                                                                            \\\n        *p = name##_weak_null();                                                                                     \\\n        return res;                                                                                                  \\\n    }                                                                                                                \\\n    static inline size_t name##_rc_size(name##_rc_t *p) {                                                            \\\n        _ZP_UNUSED(p);                                                                                               \\\n        return sizeof(name##_rc_t);                                                                                  \\\n    }                                                                                                                \\\n    static inline size_t name##_rc_strong_count(const name##_rc_t *p) { return _z_rc_strong_count(p->_cnt); }        \\\n    static inline size_t name##_rc_weak_count(const name##_rc_t *p) { return _z_rc_weak_count(p->_cnt); }            \\\n    static inline size_t name##_weak_strong_count(const name##_weak_t *p) { return _z_rc_strong_count(p->_cnt); }    \\\n    static inline size_t name##_weak_weak_count(const name##_weak_t *p) { return _z_rc_weak_count(p->_cnt); }        \\\n    static inline name##_t *name##_weak_as_unsafe_ptr(name##_weak_t *p) { return p->_val; }\n\ntypedef void _z_void_t;\ntypedef void (*_z_void_rc_deleter)(void *);\ntypedef struct _z_void_rc_t {\n    void *_val;\n    void *_cnt;\n    _z_void_rc_deleter _deleter;\n} _z_void_rc_t;\n\ntypedef struct _z_void_weak_t {\n    void *_val;\n    void *_cnt;\n    _z_void_rc_deleter _deleter;\n} _z_void_weak_t;\n\nstatic inline void _z_void_weak_to_rc_inner(const _z_void_weak_t *weak, _z_void_rc_t *rc) {\n    rc->_val = weak->_val;\n    rc->_cnt = weak->_cnt;\n    rc->_deleter = weak->_deleter;\n}\n\nstatic inline void _z_void_rc_to_weak_inner(const _z_void_rc_t *rc, _z_void_weak_t *weak) {\n    weak->_val = rc->_val;\n    weak->_cnt = rc->_cnt;\n    weak->_deleter = rc->_deleter;\n}\n\nstatic inline void _z_void_rc_clear_inner(_z_void_rc_t *rc) {\n    if (rc->_deleter != NULL) {\n        rc->_deleter(rc->_val);\n    }\n}\n_Z_REFCOUNT_DEFINE_NO_FROM_VAL_INNER(_z_void, _z_void)\nstatic inline _z_void_rc_t _z_void_rc_rc_new(void *val, _z_void_rc_deleter deleter) {\n    _z_void_rc_t p = _z_void_rc_null();\n    if (_z_rc_init(&p._cnt) == _Z_RES_OK) {\n        p._val = val;\n        p._deleter = deleter;\n    }\n    return p;\n}\n\n#define _Z_REFCOUNT_DEFINE_NO_FROM_VAL(name, type)                                                \\\n    _Z_REFCOUNT_DEFINE_STRUCTS(name, type)                                                        \\\n    _Z_REFCOUNT_DEFINE_NO_FROM_VAL_INNER(name, type)                                              \\\n    static inline name##_rc_t name##_rc_new(type##_t *val) {                                      \\\n        name##_rc_t p = name##_rc_null();                                                         \\\n        if (_z_rc_init(&p._cnt) == _Z_RES_OK) {                                                   \\\n            p._val = val;                                                                         \\\n        }                                                                                         \\\n        return p;                                                                                 \\\n    }                                                                                             \\\n    static inline void __##name##_z_void_rc_deleter(void *val) { type##_clear((type##_t *)val); } \\\n    static inline _z_void_rc_t name##_rc_to_void(type##_rc_t *rc) {                               \\\n        _z_void_rc_t p = _z_void_rc_null();                                                       \\\n        p._val = (void *)rc->_val;                                                                \\\n        p._cnt = rc->_cnt;                                                                        \\\n        p._deleter = __##name##_z_void_rc_deleter;                                                \\\n        *rc = name##_rc_null();                                                                   \\\n        return p;                                                                                 \\\n    }\n\n#define _Z_REFCOUNT_DEFINE(name, type)                                      \\\n    _Z_REFCOUNT_DEFINE_NO_FROM_VAL(name, type)                              \\\n    static inline name##_rc_t name##_rc_new_from_val(const type##_t *val) { \\\n        type##_t *v = (type##_t *)z_malloc(sizeof(type##_t));               \\\n        if (v == NULL) {                                                    \\\n            return name##_rc_null();                                        \\\n        }                                                                   \\\n        *v = *val;                                                          \\\n        name##_rc_t p = name##_rc_new(v);                                   \\\n        if (p._cnt == NULL) {                                               \\\n            z_free(v);                                                      \\\n            return name##_rc_null();                                        \\\n        }                                                                   \\\n        return p;                                                           \\\n    }                                                                       \\\n    static inline name##_rc_t name##_rc_new_undefined(void) {               \\\n        type##_t *v = (type##_t *)z_malloc(sizeof(type##_t));               \\\n        if (v == NULL) {                                                    \\\n            return name##_rc_null();                                        \\\n        }                                                                   \\\n        name##_rc_t p = name##_rc_new(v);                                   \\\n        if (p._cnt == NULL) {                                               \\\n            z_free(v);                                                      \\\n            return name##_rc_null();                                        \\\n        }                                                                   \\\n        return p;                                                           \\\n    }\n\n#define _Z_SIMPLE_REFCOUNT_DEFINE(name, type)                                                                 \\\n    typedef struct name##_simple_rc_t {                                                                       \\\n        void *_val;                                                                                           \\\n    } name##_simple_rc_t;                                                                                     \\\n                                                                                                              \\\n    static inline name##_simple_rc_t name##_simple_rc_null(void) { return (name##_simple_rc_t){0}; }          \\\n                                                                                                              \\\n    static inline name##_simple_rc_t name##_simple_rc_new_from_val(const type##_t *val) {                     \\\n        name##_simple_rc_t p = name##_simple_rc_null();                                                       \\\n        _z_simple_rc_init(&p._val, val, sizeof(type##_t));                                                    \\\n        return p;                                                                                             \\\n    }                                                                                                         \\\n    static inline name##_simple_rc_t name##_simple_rc_clone(const name##_simple_rc_t *p) {                    \\\n        return _z_simple_rc_increase(p->_val) == _Z_RES_OK ? *p : name##_simple_rc_null();                    \\\n    }                                                                                                         \\\n    static inline name##_simple_rc_t *name##_simple_rc_clone_as_ptr(const name##_simple_rc_t *p) {            \\\n        name##_simple_rc_t *c = (name##_simple_rc_t *)z_malloc(sizeof(name##_simple_rc_t));                   \\\n        if (c != NULL) {                                                                                      \\\n            *c = name##_simple_rc_clone(p);                                                                   \\\n            if (c->_val == NULL) {                                                                            \\\n                z_free(c);                                                                                    \\\n                c = NULL;                                                                                     \\\n            }                                                                                                 \\\n        }                                                                                                     \\\n        return c;                                                                                             \\\n    }                                                                                                         \\\n    static inline void name##_simple_rc_copy(name##_simple_rc_t *dst, const name##_simple_rc_t *p) {          \\\n        *dst = name##_simple_rc_clone(p);                                                                     \\\n    }                                                                                                         \\\n    static inline bool name##_simple_rc_eq(const name##_simple_rc_t *left, const name##_simple_rc_t *right) { \\\n        return (left->_val == right->_val);                                                                   \\\n    }                                                                                                         \\\n    static inline bool name##_simple_rc_decr(name##_simple_rc_t *p) {                                         \\\n        if (_z_simple_rc_decrease(p->_val)) {                                                                 \\\n            return true;                                                                                      \\\n        }                                                                                                     \\\n        return false;                                                                                         \\\n    }                                                                                                         \\\n    static inline bool name##_simple_rc_drop(name##_simple_rc_t *p) {                                         \\\n        bool res;                                                                                             \\\n        if ((p->_val != NULL) && name##_simple_rc_decr(p)) {                                                  \\\n            type##_clear((type##_t *)_z_simple_rc_value(p->_val));                                            \\\n            z_free(p->_val);                                                                                  \\\n            res = true;                                                                                       \\\n        } else {                                                                                              \\\n            res = false;                                                                                      \\\n        }                                                                                                     \\\n        p->_val = NULL;                                                                                       \\\n        return res;                                                                                           \\\n    }                                                                                                         \\\n    static inline size_t name##_simple_rc_count(const name##_simple_rc_t *p) {                                \\\n        return _z_simple_rc_strong_count(p->_val);                                                            \\\n    }                                                                                                         \\\n    static inline size_t name##_simple_rc_size(name##_simple_rc_t *p) {                                       \\\n        _ZP_UNUSED(p);                                                                                        \\\n        return sizeof(name##_simple_rc_t);                                                                    \\\n    }                                                                                                         \\\n    static inline type##_t *name##_simple_rc_value(const name##_simple_rc_t *p) {                             \\\n        return (type##_t *)_z_simple_rc_value(p->_val);                                                       \\\n    }                                                                                                         \\\n    static inline bool name##_simple_rc_is_null(const name##_simple_rc_t *p) { return p->_val == NULL; }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_REFCOUNT_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/ring.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef ZENOH_PICO_COLLECTIONS_RING_H\n#define ZENOH_PICO_COLLECTIONS_RING_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Ring Buffer --------*/\ntypedef struct {\n    void **_val;\n    size_t _capacity;\n    size_t _len;\n    size_t _r_idx;\n    size_t _w_idx;\n} _z_ring_t;\n\n/**\n * Forward iterator of a ring buffer.\n */\ntypedef struct {\n    void *_val;\n\n    const _z_ring_t *_ring;\n    size_t _r_idx;\n    size_t _w_idx;\n} _z_ring_iterator_t;\n\n/**\n * Reverse iterator of a ring buffer.\n */\ntypedef struct {\n    void *_val;\n\n    const _z_ring_t *_ring;\n    size_t _r_idx;\n    size_t _w_idx;\n} _z_ring_reverse_iterator_t;\n\nz_result_t _z_ring_init(_z_ring_t *ring, size_t capacity);\n_z_ring_t _z_ring_make(size_t capacity);\n\nsize_t _z_ring_capacity(const _z_ring_t *r);\nsize_t _z_ring_len(const _z_ring_t *r);\nbool _z_ring_is_empty(const _z_ring_t *r);\nbool _z_ring_is_full(const _z_ring_t *r);\n\nvoid *_z_ring_push(_z_ring_t *r, void *e);\nvoid *_z_ring_push_force(_z_ring_t *r, void *e);\nvoid _z_ring_push_force_drop(_z_ring_t *r, void *e, z_element_free_f f);\nvoid *_z_ring_pull(_z_ring_t *r);\n\n_z_ring_t *_z_ring_clone(const _z_ring_t *xs, z_element_clone_f d_f);\n\nvoid _z_ring_clear(_z_ring_t *v, z_element_free_f f);\nvoid _z_ring_free(_z_ring_t **xs, z_element_free_f f_f);\n\n_z_ring_iterator_t _z_ring_iterator_make(const _z_ring_t *ring);\nbool _z_ring_iterator_next(_z_ring_iterator_t *iter);\nvoid *_z_ring_iterator_value(const _z_ring_iterator_t *iter);\n\n_z_ring_reverse_iterator_t _z_ring_reverse_iterator_make(const _z_ring_t *ring);\nbool _z_ring_reverse_iterator_next(_z_ring_reverse_iterator_t *iter);\nvoid *_z_ring_reverse_iterator_value(const _z_ring_reverse_iterator_t *iter);\n\n#define _Z_RING_DEFINE(name, type)                                                                                     \\\n    typedef _z_ring_t name##_ring_t;                                                                                   \\\n    typedef _z_ring_iterator_t name##_ring_iterator_t;                                                                 \\\n    typedef _z_ring_reverse_iterator_t name##_ring_reverse_iterator_t;                                                 \\\n    static inline z_result_t name##_ring_init(name##_ring_t *ring, size_t capacity) {                                  \\\n        return _z_ring_init(ring, capacity);                                                                           \\\n    }                                                                                                                  \\\n    static inline name##_ring_t name##_ring_make(size_t capacity) { return _z_ring_make(capacity); }                   \\\n    static inline size_t name##_ring_capacity(const name##_ring_t *r) { return _z_ring_capacity(r); }                  \\\n    static inline size_t name##_ring_len(const name##_ring_t *r) { return _z_ring_len(r); }                            \\\n    static inline bool name##_ring_is_empty(const name##_ring_t *r) { return _z_ring_is_empty(r); }                    \\\n    static inline bool name##_ring_is_full(const name##_ring_t *r) { return _z_ring_is_full(r); }                      \\\n    static inline type *name##_ring_push(name##_ring_t *r, type *e) { return (type *)_z_ring_push(r, (void *)e); }     \\\n    static inline type *name##_ring_push_force(name##_ring_t *r, type *e) {                                            \\\n        return (type *)_z_ring_push_force(r, (void *)e);                                                               \\\n    }                                                                                                                  \\\n    static inline void name##_ring_push_force_drop(name##_ring_t *r, type *e) {                                        \\\n        _z_ring_push_force_drop(r, (void *)e, name##_elem_free);                                                       \\\n    }                                                                                                                  \\\n    static inline type *name##_ring_pull(name##_ring_t *r) { return (type *)_z_ring_pull(r); }                         \\\n    static inline void name##_ring_clear(name##_ring_t *r) { _z_ring_clear(r, name##_elem_free); }                     \\\n    static inline void name##_ring_free(name##_ring_t **r) { _z_ring_free(r, name##_elem_free); }                      \\\n    static inline name##_ring_iterator_t name##_ring_iterator_make(const name##_ring_t *ring) {                        \\\n        return _z_ring_iterator_make(ring);                                                                            \\\n    }                                                                                                                  \\\n    static inline bool name##_ring_iterator_next(name##_ring_iterator_t *iter) { return _z_ring_iterator_next(iter); } \\\n    static inline type *name##_ring_iterator_value(const name##_ring_iterator_t *iter) {                               \\\n        return (type *)_z_ring_iterator_value(iter);                                                                   \\\n    }                                                                                                                  \\\n    static inline name##_ring_reverse_iterator_t name##_ring_reverse_iterator_make(const name##_ring_t *ring) {        \\\n        return _z_ring_reverse_iterator_make(ring);                                                                    \\\n    }                                                                                                                  \\\n    static inline bool name##_ring_reverse_iterator_next(name##_ring_reverse_iterator_t *iter) {                       \\\n        return _z_ring_reverse_iterator_next(iter);                                                                    \\\n    }                                                                                                                  \\\n    static inline type *name##_ring_reverse_iterator_value(const name##_ring_reverse_iterator_t *iter) {               \\\n        return (type *)_z_ring_reverse_iterator_value(iter);                                                           \\\n    }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_RING_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/ring_mt.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#ifndef ZENOH_PICO_COLLECTIONS_RING_MT_H\n#define ZENOH_PICO_COLLECTIONS_RING_MT_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/fifo.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Ring Buffer Multithreaded --------*/\ntypedef struct {\n    _z_ring_t _ring;\n    bool is_closed;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t _mutex;\n    _z_condvar_t _cv_not_empty;\n#endif\n} _z_ring_mt_t;\n\nz_result_t _z_ring_mt_init(_z_ring_mt_t *ring, size_t capacity);\n_z_ring_mt_t *_z_ring_mt_new(size_t capacity);\nz_result_t _z_ring_mt_close(_z_ring_mt_t *ring);\n\nvoid _z_ring_mt_clear(_z_ring_mt_t *ring, z_element_free_f free_f);\nvoid _z_ring_mt_free(_z_ring_mt_t *ring, z_element_free_f free_f);\n\nz_result_t _z_ring_mt_push(const void *src, void *context, z_element_free_f element_free);\n\nz_result_t _z_ring_mt_pull(void *dst, void *context, z_element_move_f element_move);\nz_result_t _z_ring_mt_try_pull(void *dst, void *context, z_element_move_f element_move);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // ZENOH_PICO_COLLECTIONS_RING_MT_H\n"
  },
  {
    "path": "include/zenoh-pico/collections/seqnumber.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_SEQNUMBER_H\n#define ZENOH_PICO_COLLECTIONS_SEQNUMBER_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n * Compute the next sequence number after `last` in 32-bit serial number space.\n * Wraps from UINT32_MAX back to 0.\n */\nstatic inline uint32_t _z_seqnumber_next(uint32_t last) { return (last == UINT32_MAX) ? 0u : (last + 1u); }\n\n/*\n * Test whether `current` is the immediate successor of `last` in\n * 32-bit serial number space (wrap-safe).\n */\nstatic inline bool _z_seqnumber_is_next(uint32_t last, uint32_t current) {\n    return (current == _z_seqnumber_next(last));\n}\n\n/*\n * Compute the previous sequence number before `current` in 32-bit serial number space.\n * Wraps from 0 back to UINT32_MAX.\n */\nstatic inline uint32_t _z_seqnumber_prev(uint32_t current) { return (current == 0u) ? UINT32_MAX : (current - 1u); }\n\n/*\n * Test whether `current` is the immediate predecessor of `last` in\n * 32-bit serial number space (wrap-safe).\n */\nstatic inline bool _z_seqnumber_is_prev(uint32_t last, uint32_t current) {\n    return (current == _z_seqnumber_prev(last));\n}\n\n/*\n * Compute signed wrap-safe difference between two 32-bit sequence numbers.\n * Positive if 'a' is newer than 'b', negative if older, zero if equal.\n * Follows RFC 1982 serial number arithmetic.\n *\n * Range: [-2^31+1, 2^31-1]\n */\nstatic inline int64_t _z_seqnumber_diff(uint32_t a, uint32_t b) { return (int64_t)((int32_t)(a - b)); }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_SEQNUMBER_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/slice.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_SLICE_H\n#define ZENOH_PICO_COLLECTIONS_SLICE_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    void (*deleter)(void *data, void *context);\n    void *context;\n} _z_delete_context_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_delete_context_t _z_delete_context_null(void) { return (_z_delete_context_t){0}; }\n\nstatic inline _z_delete_context_t _z_delete_context_create(void (*deleter)(void *context, void *data), void *context) {\n    _z_delete_context_t ret;\n    ret.deleter = deleter;\n    ret.context = context;\n    return ret;\n}\nstatic inline bool _z_delete_context_is_null(const _z_delete_context_t *c) { return c->deleter == NULL; }\nstatic inline void _z_delete_context_delete(_z_delete_context_t *c, void *data) {\n    if (!_z_delete_context_is_null(c)) {\n        c->deleter(data, c->context);\n    }\n}\n_z_delete_context_t _z_delete_context_default(void);\n_z_delete_context_t _z_delete_context_static(void);\n\n/*-------- Slice --------*/\n/**\n * An array of bytes.\n *\n * Members:\n *   size_t len: The length of the bytes array.\n *   uint8_t *start: A pointer to the bytes array.\n *   _z_delete_context_t delete_context - context used to delete the data.\n */\ntypedef struct {\n    size_t len;\n    const uint8_t *start;\n    _z_delete_context_t _delete_context;\n} _z_slice_t;\n\nstatic inline _z_slice_t _z_slice_null(void) { return (_z_slice_t){0}; }\nstatic inline void _z_slice_reset(_z_slice_t *bs) { *bs = _z_slice_null(); }\nstatic inline bool _z_slice_is_empty(const _z_slice_t *bs) { return bs->len == 0; }\nstatic inline bool _z_slice_check(const _z_slice_t *slice) { return slice->start != NULL; }\nstatic inline _z_slice_t _z_slice_alias(const _z_slice_t bs) {\n    _z_slice_t ret;\n    ret.len = bs.len;\n    ret.start = bs.start;\n    ret._delete_context = _z_delete_context_null();\n    return ret;\n}\nstatic inline _z_slice_t _z_slice_from_buf_custom_deleter(const uint8_t *p, size_t len, _z_delete_context_t dc) {\n    _z_slice_t bs;\n    bs.start = p;\n    bs.len = len;\n    bs._delete_context = dc;\n    return bs;\n}\nstatic inline _z_slice_t _z_slice_alias_buf(const uint8_t *p, size_t len) {\n    return _z_slice_from_buf_custom_deleter(p, len, _z_delete_context_null());\n}\nstatic inline void _z_slice_clear(_z_slice_t *bs) {\n    if (bs->start != NULL) {\n        _z_delete_context_delete(&bs->_delete_context, (void *)bs->start);\n        bs->len = 0;\n        bs->start = NULL;\n    }\n}\n\nz_result_t _z_slice_init(_z_slice_t *bs, size_t capacity);\n_z_slice_t _z_slice_make(size_t capacity);\n_z_slice_t _z_slice_copy_from_buf(const uint8_t *bs, size_t len);\n_z_slice_t _z_slice_steal(_z_slice_t *b);\nz_result_t _z_slice_copy(_z_slice_t *dst, const _z_slice_t *src);\nz_result_t _z_slice_n_copy(_z_slice_t *dst, const _z_slice_t *src, size_t offset, size_t len);\n_z_slice_t _z_slice_duplicate(const _z_slice_t *src);\nz_result_t _z_slice_move(_z_slice_t *dst, _z_slice_t *src);\nbool _z_slice_eq(const _z_slice_t *left, const _z_slice_t *right);\nvoid _z_slice_free(_z_slice_t **bs);\nbool _z_slice_is_alloced(const _z_slice_t *s);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_SLICE_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/sortedmap.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_SORTEDMAP_H\n#define ZENOH_PICO_COLLECTIONS_SORTEDMAP_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * A map entry.\n *\n * Members:\n *   void *_key: the key of the entry\n *   void *_val: the value of the entry\n */\ntypedef struct {\n    void *_key;\n    void *_val;\n} _z_sortedmap_entry_t;\n\n/**\n * A sorted map.\n *\n * Members:\n *   _z_list_t *_vals: a linked list containing the values\n *   z_element_cmp_f _f_cmp: the function used to compare keys\n */\ntypedef struct {\n    _z_list_t *_vals;\n    z_element_cmp_f _f_cmp;\n} _z_sortedmap_t;\n\n/**\n * Iterator for a generic key-value hashmap.\n */\ntypedef struct {\n    _z_sortedmap_entry_t *_entry;\n    const _z_sortedmap_t *_map;\n    _z_list_t *_list_ptr;\n    bool _initialized;\n} _z_sortedmap_iterator_t;\n\nvoid _z_sortedmap_init(_z_sortedmap_t *map, z_element_cmp_f f_cmp);\n_z_sortedmap_t _z_sortedmap_make(z_element_cmp_f f_cmp);\n\nvoid *_z_sortedmap_insert(_z_sortedmap_t *map, void *key, void *val, z_element_free_f f, bool replace);\nvoid *_z_sortedmap_get(const _z_sortedmap_t *map, const void *key);\n_z_sortedmap_entry_t *_z_sortedmap_pop_first(_z_sortedmap_t *map);\nvoid _z_sortedmap_remove(_z_sortedmap_t *map, const void *key, z_element_free_f f);\n\nsize_t _z_sortedmap_len(const _z_sortedmap_t *map);\nbool _z_sortedmap_is_empty(const _z_sortedmap_t *map);\n\nz_result_t _z_sortedmap_copy(_z_sortedmap_t *dst, const _z_sortedmap_t *src, z_element_clone_f f_c);\n_z_sortedmap_t _z_sortedmap_clone(const _z_sortedmap_t *src, z_element_clone_f f_c, z_element_free_f f_f);\n\nvoid _z_sortedmap_clear(_z_sortedmap_t *map, z_element_free_f f);\nvoid _z_sortedmap_free(_z_sortedmap_t **map, z_element_free_f f);\nstatic inline void _z_sortedmap_move(_z_sortedmap_t *dst, _z_sortedmap_t *src) {\n    *dst = *src;\n    *src = _z_sortedmap_make(src->_f_cmp);\n}\n\n_z_sortedmap_iterator_t _z_sortedmap_iterator_make(const _z_sortedmap_t *map);\nbool _z_sortedmap_iterator_next(_z_sortedmap_iterator_t *iter);\nvoid *_z_sortedmap_iterator_key(const _z_sortedmap_iterator_t *iter);\nvoid *_z_sortedmap_iterator_value(const _z_sortedmap_iterator_t *iter);\n\n#define _Z_SORTEDMAP_DEFINE_INNER(map_name, key_name, val_name, key_type, val_type)                                \\\n    typedef _z_sortedmap_entry_t map_name##_sortedmap_entry_t;                                                     \\\n    static inline key_type *map_name##_sortedmap_entry_key(const map_name##_sortedmap_entry_t *entry) {            \\\n        return (key_type *)entry->_key;                                                                            \\\n    }                                                                                                              \\\n    static inline val_type *map_name##_sortedmap_entry_val(const map_name##_sortedmap_entry_t *entry) {            \\\n        return (val_type *)entry->_val;                                                                            \\\n    }                                                                                                              \\\n    static inline void map_name##_sortedmap_entry_free(map_name##_sortedmap_entry_t **entry) {                     \\\n        map_name##_sortedmap_entry_t *ptr = *entry;                                                                \\\n        if (ptr != NULL) {                                                                                         \\\n            key_name##_elem_free(&ptr->_key);                                                                      \\\n            val_name##_elem_free(&ptr->_val);                                                                      \\\n            z_free(ptr);                                                                                           \\\n            *entry = NULL;                                                                                         \\\n        }                                                                                                          \\\n    }                                                                                                              \\\n    static inline void map_name##_sortedmap_entry_elem_free(void **e) {                                            \\\n        map_name##_sortedmap_entry_free((map_name##_sortedmap_entry_t **)e);                                       \\\n    }                                                                                                              \\\n    static inline void *map_name##_sortedmap_entry_elem_clone(const void *e) {                                     \\\n        const map_name##_sortedmap_entry_t *src = (map_name##_sortedmap_entry_t *)e;                               \\\n        map_name##_sortedmap_entry_t *dst =                                                                        \\\n            (map_name##_sortedmap_entry_t *)z_malloc(sizeof(map_name##_sortedmap_entry_t));                        \\\n        dst->_key = key_name##_elem_clone(src->_key);                                                              \\\n        dst->_val = val_name##_elem_clone(src->_val);                                                              \\\n        return dst;                                                                                                \\\n    }                                                                                                              \\\n    typedef _z_sortedmap_t map_name##_sortedmap_t;                                                                 \\\n    typedef _z_sortedmap_iterator_t map_name##_sortedmap_iterator_t;                                               \\\n    static inline void map_name##_sortedmap_init(map_name##_sortedmap_t *m) {                                      \\\n        _z_sortedmap_init(m, key_name##_elem_cmp);                                                                 \\\n    }                                                                                                              \\\n    static inline map_name##_sortedmap_t map_name##_sortedmap_make(void) {                                         \\\n        return _z_sortedmap_make(key_name##_elem_cmp);                                                             \\\n    }                                                                                                              \\\n    static inline val_type *map_name##_sortedmap_insert(map_name##_sortedmap_t *m, key_type *k, val_type *v) {     \\\n        return (val_type *)_z_sortedmap_insert(m, k, v, map_name##_sortedmap_entry_elem_free, true);               \\\n    }                                                                                                              \\\n    static inline val_type *map_name##_sortedmap_get(const map_name##_sortedmap_t *m, const key_type *k) {         \\\n        return (val_type *)_z_sortedmap_get(m, k);                                                                 \\\n    }                                                                                                              \\\n    static inline map_name##_sortedmap_entry_t *map_name##_sortedmap_pop_first(map_name##_sortedmap_t *m) {        \\\n        return (map_name##_sortedmap_entry_t *)_z_sortedmap_pop_first(m);                                          \\\n    }                                                                                                              \\\n    static inline z_result_t map_name##_sortedmap_copy(map_name##_sortedmap_t *dst,                                \\\n                                                       const map_name##_sortedmap_t *src) {                        \\\n        return _z_sortedmap_copy(dst, src, map_name##_sortedmap_entry_elem_clone);                                 \\\n    }                                                                                                              \\\n    static inline map_name##_sortedmap_t map_name##_sortedmap_clone(const map_name##_sortedmap_t *m) {             \\\n        return _z_sortedmap_clone(m, map_name##_sortedmap_entry_elem_clone, map_name##_sortedmap_entry_elem_free); \\\n    }                                                                                                              \\\n    static inline void map_name##_sortedmap_remove(map_name##_sortedmap_t *m, const key_type *k) {                 \\\n        _z_sortedmap_remove(m, k, map_name##_sortedmap_entry_elem_free);                                           \\\n    }                                                                                                              \\\n    static inline size_t map_name##_sortedmap_len(map_name##_sortedmap_t *m) { return _z_sortedmap_len(m); }       \\\n    static inline bool map_name##_sortedmap_is_empty(const map_name##_sortedmap_t *m) {                            \\\n        return _z_sortedmap_is_empty(m);                                                                           \\\n    }                                                                                                              \\\n    static inline void map_name##_sortedmap_clear(map_name##_sortedmap_t *m) {                                     \\\n        _z_sortedmap_clear(m, map_name##_sortedmap_entry_elem_free);                                               \\\n    }                                                                                                              \\\n    static inline void map_name##_sortedmap_free(map_name##_sortedmap_t **m) {                                     \\\n        _z_sortedmap_free(m, map_name##_sortedmap_entry_elem_free);                                                \\\n    }                                                                                                              \\\n    static inline z_result_t map_name##_sortedmap_move(map_name##_sortedmap_t *dst, map_name##_sortedmap_t *src) { \\\n        _z_sortedmap_move(dst, src);                                                                               \\\n        return _Z_RES_OK;                                                                                          \\\n    }                                                                                                              \\\n    static inline map_name##_sortedmap_iterator_t map_name##_sortedmap_iterator_make(                              \\\n        const map_name##_sortedmap_t *m) {                                                                         \\\n        return _z_sortedmap_iterator_make(m);                                                                      \\\n    }                                                                                                              \\\n    static inline bool map_name##_sortedmap_iterator_next(map_name##_sortedmap_iterator_t *iter) {                 \\\n        return _z_sortedmap_iterator_next(iter);                                                                   \\\n    }                                                                                                              \\\n    static inline key_type *map_name##_sortedmap_iterator_key(const map_name##_sortedmap_iterator_t *iter) {       \\\n        return (key_type *)_z_sortedmap_iterator_key(iter);                                                        \\\n    }                                                                                                              \\\n    static inline val_type *map_name##_sortedmap_iterator_value(const map_name##_sortedmap_iterator_t *iter) {     \\\n        return (val_type *)_z_sortedmap_iterator_value(iter);                                                      \\\n    }\n\n#define _Z_SORTEDMAP_DEFINE(key_name, val_name, key_type, val_type) \\\n    _Z_SORTEDMAP_DEFINE_INNER(key_name##_##val_name, key_name, val_name, key_type, val_type)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_SORTEDMAP_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/string.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_COLLECTIONS_STRING_H\n#define ZENOH_PICO_COLLECTIONS_STRING_H\n\n#include \"zenoh-pico/collections/array.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/vec.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- str --------*/\ntypedef char *_z_str_t;\n\nchar *_z_str_clone(const char *src);\nchar *_z_str_n_clone(const char *src, size_t len);\nvoid _z_str_clear(char *src);\nvoid _z_str_free(char **src);\nbool _z_str_eq(const char *left, const char *right);\nint _z_str_cmp(const char *left, const char *right);\n\nsize_t _z_str_size(const char *src);\nvoid _z_str_copy(char *dst, const char *src);\nvoid _z_str_n_copy(char *dst, const char *src, size_t size);\n_Z_ELEM_DEFINE(_z_str, char, _z_str_size, _z_noop_clear, _z_str_copy, _z_noop_move, _z_str_eq, _z_str_cmp, _z_noop_hash)\n\n_Z_VEC_DEFINE(_z_str, char)\n_Z_LIST_DEFINE(_z_str, char)\n_Z_INT_MAP_DEFINE(_z_str, char)\n\n#define INT_STR_MAP_KEYVALUE_SEPARATOR '='\n#define INT_STR_MAP_LIST_SEPARATOR ';'\n\ntypedef struct {\n    char *_str;\n    uint8_t _key;\n} _z_str_intmapping_t;\n\nsize_t _z_str_intmap_strlen(const _z_str_intmap_t *s, uint8_t argc, _z_str_intmapping_t argv[]);\n\nvoid _z_str_intmap_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s, uint8_t argc,\n                            _z_str_intmapping_t argv[]);\nchar *_z_str_intmap_to_str(const _z_str_intmap_t *s, uint8_t argc, _z_str_intmapping_t argv[]);\n\nz_result_t _z_str_intmap_from_str(_z_str_intmap_t *strint, const char *s, uint8_t argc, _z_str_intmapping_t argv[]);\nz_result_t _z_str_intmap_from_strn(_z_str_intmap_t *strint, const char *s, uint8_t argc, _z_str_intmapping_t argv[],\n                                   size_t n);\n\n/*-------- string --------*/\n/**\n * A string with no terminator.\n *\n */\ntypedef struct {\n    _z_slice_t _slice;\n} _z_string_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_string_t _z_string_null(void) { return (_z_string_t){0}; }\nstatic inline bool _z_string_check(const _z_string_t *value) { return !_z_slice_is_empty(&value->_slice); }\nstatic inline _z_string_t _z_string_alias(const _z_string_t str) {\n    _z_string_t ret;\n    ret._slice = _z_slice_alias(str._slice);\n    return ret;\n}\nstatic inline size_t _z_string_len(const _z_string_t *s) { return s->_slice.len; }\nstatic inline const char *_z_string_data(const _z_string_t *s) { return (const char *)s->_slice.start; }\nstatic inline bool _z_string_is_empty(const _z_string_t *s) { return s->_slice.len == 0; }\nstatic inline _z_string_t _z_string_alias_slice(const _z_slice_t *slice) {\n    _z_string_t s;\n    s._slice = _z_slice_alias(*slice);\n    return s;\n}\nstatic inline _z_string_t _z_string_alias_str(const char *value) {\n    _z_string_t s;\n    s._slice = _z_slice_alias_buf((const uint8_t *)(value), strlen(value));\n    return s;\n}\nstatic inline _z_string_t _z_string_alias_substr(const char *value, size_t len) {\n    _z_string_t s;\n    s._slice = _z_slice_alias_buf((const uint8_t *)(value), len);\n    return s;\n}\nstatic inline _z_string_t _z_string_from_str_custom_deleter(char *value, _z_delete_context_t c) {\n    _z_string_t s;\n    s._slice = _z_slice_from_buf_custom_deleter((const uint8_t *)(value), strlen(value), c);\n    return s;\n}\nstatic inline void _z_string_reset(_z_string_t *str) { _z_slice_reset(&str->_slice); }\nstatic inline void _z_string_clear(_z_string_t *str) { _z_slice_clear(&str->_slice); }\n\n_z_string_t _z_string_copy_from_str(const char *value);\n_z_string_t _z_string_copy_from_substr(const char *value, size_t len);\n_z_string_t *_z_string_copy_from_str_as_ptr(const char *value);\nconst char *_z_string_rchr(_z_string_t *str, char filter);\nchar *_z_string_pbrk(_z_string_t *str, const char *filter);\n\nz_result_t _z_string_copy(_z_string_t *dst, const _z_string_t *src);\nz_result_t _z_string_copy_substring(_z_string_t *dst, const _z_string_t *src, size_t offset, size_t len);\nz_result_t _z_string_move(_z_string_t *dst, _z_string_t *src);\n_z_string_t _z_string_steal(_z_string_t *str);\nvoid _z_string_move_str(_z_string_t *dst, char *src);\nvoid _z_string_free(_z_string_t **s);\nint _z_string_compare(const _z_string_t *left, const _z_string_t *right);\nint _z_substring_compare(const _z_string_t *left, size_t left_start, size_t left_len, const _z_string_t *right,\n                         size_t right_start, size_t right_len);\nbool _z_string_equals(const _z_string_t *left, const _z_string_t *right);\n_z_string_t _z_string_convert_bytes_le(const _z_slice_t *bs);\n_z_string_t _z_string_preallocate(const size_t len);\nz_result_t _z_string_concat_substr(_z_string_t *s, const _z_string_t *left, const char *right, size_t len,\n                                   const char *separator, size_t separator_len);\nstatic inline z_result_t _z_string_concat(_z_string_t *s, const _z_string_t *left, const _z_string_t *right,\n                                          const char *separator, size_t separator_len) {\n    return _z_string_concat_substr(s, left, _z_string_data(right), _z_string_len(right), separator, separator_len);\n}\n\nchar *_z_str_from_string_clone(const _z_string_t *str);\n\n_Z_ELEM_DEFINE(_z_string, _z_string_t, _z_string_len, _z_string_clear, _z_string_copy, _z_string_move, _z_string_equals,\n               _z_string_compare, _z_noop_hash)\n_Z_SVEC_DEFINE(_z_string, _z_string_t)\n_Z_LIST_DEFINE(_z_string, _z_string_t)\n_Z_INT_MAP_DEFINE(_z_string, _z_string_t)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_STRING_H */\n"
  },
  {
    "path": "include/zenoh-pico/collections/sync_group.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_COLLECTIONS_SYNC_GROUP_H\n#define ZENOH_PICO_COLLECTIONS_SYNC_GROUP_H\n\n#include \"refcount.h\"\n#include \"stdint.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/result.h\"\n\ntypedef struct {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t counter_mutex;\n    _z_condvar_t counter_condvar;\n#endif\n    bool is_closed;\n} _z_sync_group_state_t;\n\nz_result_t _z_sync_group_state_create(_z_sync_group_state_t* sync_group);\nvoid _z_sync_group_state_clear(_z_sync_group_state_t* sync_group_state);\n\n_Z_REFCOUNT_DEFINE_NO_FROM_VAL(_z_sync_group_state, _z_sync_group_state)\n\ntypedef struct {\n    _z_sync_group_state_rc_t _state;\n} _z_sync_group_t;\n\ntypedef struct {\n    _z_sync_group_state_weak_t _state;\n} _z_sync_group_notifier_t;\n\nstatic inline _z_sync_group_t _z_sync_group_null(void) {\n    _z_sync_group_t sg = {0};\n    return sg;\n}\n\nstatic inline _z_sync_group_notifier_t _z_sync_group_notifier_null(void) {\n    _z_sync_group_notifier_t n = {0};\n    return n;\n}\n\nstatic inline _z_sync_group_notifier_t _z_sync_group_notifier_steal(_z_sync_group_notifier_t* notifier) {\n    _z_sync_group_notifier_t n = *notifier;\n    *notifier = _z_sync_group_notifier_null();\n    return n;\n}\n\nz_result_t _z_sync_group_create(_z_sync_group_t* sync_group);\nz_result_t _z_sync_group_wait(_z_sync_group_t* sync_group);\nvoid _z_sync_group_close(_z_sync_group_t* sync_group);\nz_result_t _z_sync_group_wait_deadline(_z_sync_group_t* sync_group, const z_clock_t* deadline);\nstatic inline bool _z_sync_group_check(const _z_sync_group_t* sync_group) {\n    return !_Z_RC_IS_NULL(&sync_group->_state);\n}\nbool _z_sync_group_is_closed(const _z_sync_group_t* sync_group);\nvoid _z_sync_group_drop(_z_sync_group_t* sync_group);\nz_result_t _z_sync_group_create_notifier(const _z_sync_group_t* sync_group, _z_sync_group_notifier_t* notifier);\nvoid _z_sync_group_notifier_drop(_z_sync_group_notifier_t* notifier);\nstatic inline bool _z_sync_group_notifier_check(const _z_sync_group_notifier_t* notifier) {\n    return !_Z_RC_IS_NULL(&notifier->_state);\n}\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/collections/vec.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_VECTOR_H\n#define ZENOH_PICO_COLLECTIONS_VECTOR_H\n\n#include <assert.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*-------- Dynamically allocated vector --------*/\n/**\n * A dynamically allocated vector. Elements are stored as pointers.\n */\ntypedef struct {\n    size_t _capacity;\n    size_t _len;\n    void **_val;\n} _z_vec_t;\n\nstatic inline _z_vec_t _z_vec_null(void) { return (_z_vec_t){0}; }\nstatic inline _z_vec_t _z_vec_alias(const _z_vec_t *src) { return *src; }\nstatic inline void *_z_vec_get(const _z_vec_t *v, size_t pos) {\n    assert(pos < v->_len);\n    return v->_val[pos];\n}\nstatic inline size_t _z_vec_len(const _z_vec_t *v) { return v->_len; }\nstatic inline bool _z_vec_is_empty(const _z_vec_t *v) { return v->_len == 0; }\n\n_z_vec_t _z_vec_make(size_t capacity);\nvoid _z_vec_copy(_z_vec_t *dst, const _z_vec_t *src, z_element_clone_f f);\nvoid _z_vec_move(_z_vec_t *dst, _z_vec_t *src);\n\nvoid _z_vec_append(_z_vec_t *v, void *e);\nvoid _z_vec_set(_z_vec_t *sv, size_t pos, void *e, z_element_free_f f);\nvoid _z_vec_remove(_z_vec_t *sv, size_t pos, z_element_free_f f);\n\nvoid _z_vec_reset(_z_vec_t *v, z_element_free_f f);\nvoid _z_vec_clear(_z_vec_t *v, z_element_free_f f);\nvoid _z_vec_free(_z_vec_t **v, z_element_free_f f);\nvoid _z_vec_release(_z_vec_t *v);\n\n#define _Z_VEC_DEFINE(name, type)                                                                                  \\\n    typedef _z_vec_t name##_vec_t;                                                                                 \\\n    static inline name##_vec_t name##_vec_make(size_t capacity) { return _z_vec_make(capacity); }                  \\\n    static inline size_t name##_vec_len(const name##_vec_t *v) { return _z_vec_len(v); }                           \\\n    static inline bool name##_vec_is_empty(const name##_vec_t *v) { return _z_vec_is_empty(v); }                   \\\n    static inline void name##_vec_append(name##_vec_t *v, type *e) { _z_vec_append(v, e); }                        \\\n    static inline type *name##_vec_get(const name##_vec_t *v, size_t pos) { return (type *)_z_vec_get(v, pos); }   \\\n    static inline void name##_vec_set(name##_vec_t *v, size_t pos, type *e) {                                      \\\n        _z_vec_set(v, pos, e, name##_elem_free);                                                                   \\\n    }                                                                                                              \\\n    static inline void name##_vec_remove(name##_vec_t *v, size_t pos) { _z_vec_remove(v, pos, name##_elem_free); } \\\n    static inline void name##_vec_copy(name##_vec_t *dst, const name##_vec_t *src) {                               \\\n        _z_vec_copy(dst, src, name##_elem_clone);                                                                  \\\n    }                                                                                                              \\\n    static inline name##_vec_t name##_vec_alias(const name##_vec_t *v) { return _z_vec_alias(v); }                 \\\n    static inline void name##_vec_move(name##_vec_t *dst, name##_vec_t *src) { _z_vec_move(dst, src); }            \\\n    static inline void name##_vec_reset(name##_vec_t *v) { _z_vec_reset(v, name##_elem_free); }                    \\\n    static inline void name##_vec_clear(name##_vec_t *v) { _z_vec_clear(v, name##_elem_free); }                    \\\n    static inline void name##_vec_free(name##_vec_t **v) { _z_vec_free(v, name##_elem_free); }                     \\\n    static inline void name##_vec_release(name##_vec_t *v) { _z_vec_release(v); }\n\n/*-------- Dynamically allocated sized vector --------*/\n/**\n * A dynamically allocated vector. Elements are stored by value.\n */\ntypedef struct {\n    size_t _capacity;\n    size_t _len;\n    void *_val;\n    bool _aliased;\n} _z_svec_t;\n\nstatic inline _z_svec_t _z_svec_null(void) { return (_z_svec_t){0}; }\nstatic inline _z_svec_t _z_svec_alias(const _z_svec_t *src, bool ownership) {\n    _z_svec_t ret;\n    ret._capacity = src->_capacity;\n    ret._len = src->_len;\n    ret._val = src->_val;\n    ret._aliased = !ownership;\n    return ret;\n}\nstatic inline _z_svec_t _z_svec_alias_element(void *element) {\n    _z_svec_t ret;\n    ret._capacity = 1;\n    ret._len = 1;\n    ret._val = element;\n    ret._aliased = true;\n    return ret;\n}\nstatic inline size_t _z_svec_len(const _z_svec_t *v) { return v->_len; }\nstatic inline bool _z_svec_is_empty(const _z_svec_t *v) { return v->_len == 0; }\nstatic inline void *_z_svec_get(const _z_svec_t *v, size_t i, size_t element_size) {\n    assert(i < v->_len);\n    return (uint8_t *)v->_val + i * element_size;\n}\nstatic inline void *_z_svec_get_mut(_z_svec_t *v, size_t i, size_t element_size) {\n    return (uint8_t *)v->_val + i * element_size;\n}\n\nvoid _z_svec_init(_z_svec_t *v, size_t offset, size_t element_size);\n_z_svec_t _z_svec_make(size_t capacity, size_t element_size);\nz_result_t _z_svec_copy(_z_svec_t *dst, const _z_svec_t *src, z_element_copy_f copy, size_t element_size,\n                        bool use_elem_f);\nvoid _z_svec_move(_z_svec_t *dst, _z_svec_t *src);\n\nz_result_t _z_svec_expand(_z_svec_t *v, z_element_move_f move, size_t element_size, bool use_elem_f);\nz_result_t _z_svec_append(_z_svec_t *v, const void *e, z_element_move_f m, size_t element_size, bool use_elem_f);\n\nvoid _z_svec_set(_z_svec_t *sv, size_t pos, void *e, z_element_clear_f f, size_t element_size);\nvoid _z_svec_remove(_z_svec_t *sv, size_t pos, z_element_clear_f f, z_element_move_f m, size_t element_size,\n                    bool use_elem_f);\n\nvoid _z_svec_reset(_z_svec_t *v, z_element_clear_f f, size_t element_size);\nvoid _z_svec_clear(_z_svec_t *v, z_element_clear_f f, size_t element_size);\nvoid _z_svec_free(_z_svec_t **v, z_element_clear_f f, size_t element_size);\nvoid _z_svec_release(_z_svec_t *v);\n\n#define _Z_SVEC_DEFINE_NO_COPY(name, type)                                                                          \\\n    typedef _z_svec_t name##_svec_t;                                                                                \\\n    static inline name##_svec_t name##_svec_null(void) { return _z_svec_null(); }                                   \\\n    static inline name##_svec_t name##_svec_make(size_t capacity) { return _z_svec_make(capacity, sizeof(type)); }  \\\n    static inline void name##_svec_init(name##_svec_t *v, size_t offset) { _z_svec_init(v, offset, sizeof(type)); } \\\n    static inline size_t name##_svec_len(const name##_svec_t *v) { return _z_svec_len(v); }                         \\\n    static inline bool name##_svec_is_empty(const name##_svec_t *v) { return _z_svec_is_empty(v); }                 \\\n    static inline z_result_t name##_svec_expand(name##_svec_t *v, bool use_elem_f) {                                \\\n        return _z_svec_expand(v, name##_elem_move, sizeof(type), use_elem_f);                                       \\\n    }                                                                                                               \\\n    static inline z_result_t name##_svec_append(name##_svec_t *v, const type *e, bool use_elem_f) {                 \\\n        return _z_svec_append(v, e, name##_elem_move, sizeof(type), use_elem_f);                                    \\\n    }                                                                                                               \\\n    static inline type *name##_svec_get(const name##_svec_t *v, size_t pos) {                                       \\\n        return (type *)_z_svec_get(v, pos, sizeof(type));                                                           \\\n    }                                                                                                               \\\n    static inline type *name##_svec_get_mut(name##_svec_t *v, size_t pos) {                                         \\\n        return (type *)_z_svec_get_mut(v, pos, sizeof(type));                                                       \\\n    }                                                                                                               \\\n    static inline void name##_svec_set(name##_svec_t *v, size_t pos, type *e) {                                     \\\n        _z_svec_set(v, pos, e, name##_elem_clear, sizeof(type));                                                    \\\n    }                                                                                                               \\\n    static inline void name##_svec_remove(name##_svec_t *v, size_t pos, bool use_elem_f) {                          \\\n        _z_svec_remove(v, pos, name##_elem_clear, name##_elem_move, sizeof(type), use_elem_f);                      \\\n    }                                                                                                               \\\n    static inline name##_svec_t name##_svec_alias(const name##_svec_t *v) { return _z_svec_alias(v, false); }       \\\n    static inline name##_svec_t name##_svec_transfer(name##_svec_t *v) {                                            \\\n        name##_svec_t ret = _z_svec_alias(v, true);                                                                 \\\n        v->_aliased = true;                                                                                         \\\n        return ret;                                                                                                 \\\n    }                                                                                                               \\\n    static inline name##_svec_t name##_svec_alias_element(type *e) { return _z_svec_alias_element((void *)e); }     \\\n    static inline z_result_t name##_svec_move(name##_svec_t *dst, name##_svec_t *src) {                             \\\n        _z_svec_move(dst, src);                                                                                     \\\n        return _Z_RES_OK;                                                                                           \\\n    }                                                                                                               \\\n    static inline void name##_svec_reset(name##_svec_t *v) { _z_svec_reset(v, name##_elem_clear, sizeof(type)); }   \\\n    static inline void name##_svec_clear(name##_svec_t *v) { _z_svec_clear(v, name##_elem_clear, sizeof(type)); }   \\\n    static inline void name##_svec_release(name##_svec_t *v) { _z_svec_release(v); }                                \\\n    static inline void name##_svec_free(name##_svec_t **v) { _z_svec_free(v, name##_elem_clear, sizeof(type)); }\n\n#define _Z_SVEC_DEFINE(name, type)                                                                             \\\n    _Z_SVEC_DEFINE_NO_COPY(name, type)                                                                         \\\n    static inline z_result_t name##_svec_copy(name##_svec_t *dst, const name##_svec_t *src, bool use_elem_f) { \\\n        return _z_svec_copy(dst, src, name##_elem_copy, sizeof(type), use_elem_f);                             \\\n    }\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COLLECTIONS_VECTOR_H */\n"
  },
  {
    "path": "include/zenoh-pico/config.h.in",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_CONFIG_H\n#define INCLUDE_ZENOH_PICO_CONFIG_H\n\n#cmakedefine ZP_SYSTEM_PLATFORM_HEADER \"@ZP_SYSTEM_PLATFORM_HEADER@\"\n\n#ifdef ZENOH_GENERIC\n#include <zenoh_generic_config.h>\n#else\n\n/*--- CMake generated config; pass values to CMake to change the following tokens ---*/\n#define Z_FRAG_MAX_SIZE @FRAG_MAX_SIZE@\n#define Z_BATCH_UNICAST_SIZE @BATCH_UNICAST_SIZE@\n#define Z_BATCH_MULTICAST_SIZE @BATCH_MULTICAST_SIZE@\n#define Z_CONFIG_SOCKET_TIMEOUT @Z_CONFIG_SOCKET_TIMEOUT@\n#define Z_TRANSPORT_LEASE @Z_TRANSPORT_LEASE@\n#define Z_TRANSPORT_LEASE_EXPIRE_FACTOR @Z_TRANSPORT_LEASE_EXPIRE_FACTOR@\n#define Z_RUNTIME_MAX_TASKS @Z_RUNTIME_MAX_TASKS@\n#define Z_TRANSPORT_ACCEPT_TIMEOUT @Z_TRANSPORT_ACCEPT_TIMEOUT@\n#define Z_TRANSPORT_CONNECT_TIMEOUT @Z_TRANSPORT_CONNECT_TIMEOUT@\n\n#cmakedefine Z_FEATURE_UNSTABLE_API\n#define Z_FEATURE_CONNECTIVITY @Z_FEATURE_CONNECTIVITY@\n#define Z_FEATURE_MULTI_THREAD @Z_FEATURE_MULTI_THREAD@\n#define Z_FEATURE_PUBLICATION @Z_FEATURE_PUBLICATION@\n#define Z_FEATURE_ADVANCED_PUBLICATION @Z_FEATURE_ADVANCED_PUBLICATION@\n#define Z_FEATURE_SUBSCRIPTION @Z_FEATURE_SUBSCRIPTION@\n#define Z_FEATURE_ADVANCED_SUBSCRIPTION @Z_FEATURE_ADVANCED_SUBSCRIPTION@\n#define Z_FEATURE_QUERY @Z_FEATURE_QUERY@\n#define Z_FEATURE_QUERYABLE @Z_FEATURE_QUERYABLE@\n#define Z_FEATURE_LIVELINESS @Z_FEATURE_LIVELINESS@\n#define Z_FEATURE_RAWETH_TRANSPORT @Z_FEATURE_RAWETH_TRANSPORT@\n#define Z_FEATURE_INTEREST @Z_FEATURE_INTEREST@\n#define Z_FEATURE_LINK_TCP @Z_FEATURE_LINK_TCP@\n#define Z_FEATURE_LINK_BLUETOOTH @Z_FEATURE_LINK_BLUETOOTH@\n#define Z_FEATURE_LINK_WS @Z_FEATURE_LINK_WS@\n#define Z_FEATURE_LINK_SERIAL @Z_FEATURE_LINK_SERIAL@\n#define Z_FEATURE_LINK_SERIAL_USB @Z_FEATURE_LINK_SERIAL_USB@\n#define Z_FEATURE_LINK_TLS @Z_FEATURE_LINK_TLS@\n#define Z_FEATURE_SCOUTING @Z_FEATURE_SCOUTING@\n#define Z_FEATURE_LINK_UDP_MULTICAST @Z_FEATURE_LINK_UDP_MULTICAST@\n#define Z_FEATURE_LINK_UDP_UNICAST @Z_FEATURE_LINK_UDP_UNICAST@\n#define Z_FEATURE_MULTICAST_TRANSPORT @Z_FEATURE_MULTICAST_TRANSPORT@\n#define Z_FEATURE_UNICAST_TRANSPORT @Z_FEATURE_UNICAST_TRANSPORT@\n#define Z_FEATURE_FRAGMENTATION @Z_FEATURE_FRAGMENTATION@\n#define Z_FEATURE_ENCODING_VALUES @Z_FEATURE_ENCODING_VALUES@\n#define Z_FEATURE_TCP_NODELAY @Z_FEATURE_TCP_NODELAY@\n#define Z_FEATURE_LOCAL_SUBSCRIBER @Z_FEATURE_LOCAL_SUBSCRIBER@\n#define Z_FEATURE_LOCAL_QUERYABLE @Z_FEATURE_LOCAL_QUERYABLE@\n#define Z_FEATURE_SESSION_CHECK @Z_FEATURE_SESSION_CHECK@\n#define Z_FEATURE_BATCHING @Z_FEATURE_BATCHING@\n#define Z_FEATURE_BATCH_TX_MUTEX @Z_FEATURE_BATCH_TX_MUTEX@\n#define Z_FEATURE_BATCH_PEER_MUTEX @Z_FEATURE_BATCH_PEER_MUTEX@\n#define Z_FEATURE_MATCHING @Z_FEATURE_MATCHING@\n#define Z_FEATURE_RX_CACHE @Z_FEATURE_RX_CACHE@\n#define Z_FEATURE_UNICAST_PEER @Z_FEATURE_UNICAST_PEER@\n#define Z_FEATURE_AUTO_RECONNECT @Z_FEATURE_AUTO_RECONNECT@\n#define Z_FEATURE_MULTICAST_DECLARATIONS @Z_FEATURE_MULTICAST_DECLARATIONS@\n#define Z_FEATURE_ADMIN_SPACE @Z_FEATURE_ADMIN_SPACE@\n\n// End of CMake generation\n\n#endif /* ZENOH_GENERIC */\n\n/*------------------ Runtime configuration properties ------------------*/\n/**\n * The library mode.\n * Accepted values : `\"client\"`, `\"peer\"`.\n * Default value : `\"client\"`.\n */\n#define Z_CONFIG_MODE_KEY 0x40\n#define Z_CONFIG_MODE_CLIENT \"client\"\n#define Z_CONFIG_MODE_PEER \"peer\"\n#define Z_CONFIG_MODE_DEFAULT Z_CONFIG_MODE_CLIENT\n\n/**\n * The locator of a peer to connect to.\n * Accepted values : `<locator>` (ex: `\"tcp/10.10.10.10:7447\"`).\n * Default value : None.\n * Multiple values are accepted in peer to peer unicast mode.\n */\n#define Z_CONFIG_CONNECT_KEY 0x41\n\n/**\n * A locator to listen on.\n * Accepted values : `<locator>` (ex: `\"tcp/10.10.10.10:7447\"`).\n * Default value : None.\n * Multiple values are not accepted in zenoh-pico.\n */\n#define Z_CONFIG_LISTEN_KEY 0x42\n\n/**\n * The user name to use for authentication.\n * Accepted values : `<string>`.\n * Default value : None.\n */\n#define Z_CONFIG_USER_KEY 0x43\n\n/**\n * The password to use for authentication.\n * Accepted values : `<string>`.\n * Default value : None.\n */\n#define Z_CONFIG_PASSWORD_KEY 0x44\n\n/**\n * Activates/Deactivates multicast scouting.\n * Accepted values : `false`, `true`.\n * Default value : `true`.\n */\n#define Z_CONFIG_MULTICAST_SCOUTING_KEY 0x45\n#define Z_CONFIG_MULTICAST_SCOUTING_DEFAULT \"true\"\n\n/**\n * The multicast address and ports to use for multicast scouting.\n * Accepted values : `<ip address>:<port>`.\n * Default value : `\"224.0.0.224:7446\"`.\n */\n#define Z_CONFIG_MULTICAST_LOCATOR_KEY 0x46\n#define Z_CONFIG_MULTICAST_LOCATOR_DEFAULT \"udp/224.0.0.224:7446\"\n\n/**\n * In client mode, the period dedicated to scouting a router before failing.\n * Accepted values : `<int in milliseconds>`.\n * Default value : `\"1000\"`.\n */\n#define Z_CONFIG_SCOUTING_TIMEOUT_KEY 0x47\n#define Z_CONFIG_SCOUTING_TIMEOUT_DEFAULT \"1000\"\n\n/**\n * The entities to find in the multicast scouting, defined as a bitwise value.\n * Accepted values : [0-7]. Bitwise value are defined in :c:enum:`z_whatami_t`.\n * Default value : `3`.\n */\n#define Z_CONFIG_SCOUTING_WHAT_KEY 0x48\n#define Z_CONFIG_SCOUTING_WHAT_DEFAULT \"3\"\n\n/**\n * A configurable and static Zenoh ID to be used on Zenoh Sessions.\n * Accepted values : `<UUDI 128-bit>`.\n */\n#define Z_CONFIG_SESSION_ZID_KEY 0x49\n\n/**\n * Indicates if data messages should be timestamped.\n * Accepted values : `false`, `true`.\n * Default value : `false`.\n */\n#define Z_CONFIG_ADD_TIMESTAMP_KEY 0x4A\n#define Z_CONFIG_ADD_TIMESTAMP_DEFAULT \"false\"\n\n/*------------------ TLS configuration properties ------------------*/\n#define Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY 0x4B\n#define Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY 0x4C\n#define Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_KEY 0x4D\n#define Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_BASE64_KEY 0x4E\n#define Z_CONFIG_TLS_LISTEN_CERTIFICATE_KEY 0x4F\n#define Z_CONFIG_TLS_LISTEN_CERTIFICATE_BASE64_KEY 0x50\n#define Z_CONFIG_TLS_ENABLE_MTLS_KEY 0x51\n#define Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_KEY 0x52\n#define Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_BASE64_KEY 0x53\n#define Z_CONFIG_TLS_CONNECT_CERTIFICATE_KEY 0x54\n#define Z_CONFIG_TLS_CONNECT_CERTIFICATE_BASE64_KEY 0x55\n#define Z_CONFIG_TLS_VERIFY_NAME_ON_CONNECT_KEY 0x56\n\n/*------------------ Connect behaviour properties ------------------*/\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * The timeout dedicated to establishing connections to configured\n * connect locators.\n *\n * Accepted values : `<int in milliseconds>`.\n * - `0`  : no retry, try each locator once\n * - `>0` : retry retryable locators until timeout expires\n * - `-1` : retry indefinitely until a connection is established\n *\n * In client mode, this applies to the initial connection attempt and\n * requires at least one locator to succeed.\n *\n * In peer mode, this applies to the initial connection phase for\n * configured locators.\n *\n * Default value : `\"0\"`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\n#define Z_CONFIG_CONNECT_TIMEOUT_KEY 0x57\n#endif\n#define Z_CONFIG_CONNECT_TIMEOUT_DEFAULT \"0\"\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * Indicates whether the application should fail if connection attempts\n * to configured connect locators do not succeed.\n *\n * Accepted values : `false`, `true`.\n * - `true`  : fail if the connection phase does not establish the required connectivity\n * - `false` : allow the session to continue even if some connections fail\n *\n * In client mode, this requires at least one locator to be successfully connected.\n *\n * In peer mode, this controls whether failures while connecting configured\n * peer locators are tolerated. If set to `true`, non-retryable connect errors\n * fail immediately. Retryable connect errors are retried according to\n * `Z_CONFIG_CONNECT_TIMEOUT_KEY`; if the timeout expires before the required\n * connectivity is established, `z_open` fails.\n *\n * Default value : `\"true\"` in client mode, `\"false\"` in peer mode.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\n#define Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY 0x58\n#endif\n#define Z_CONFIG_CONNECT_EXIT_ON_FAILURE_CLIENT_DEFAULT \"true\"\n#define Z_CONFIG_CONNECT_EXIT_ON_FAILURE_PEER_DEFAULT \"false\"\n\n/*------------------ Listen behaviour properties ------------------*/\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * The timeout dedicated to opening configured listen locators.\n *\n * Accepted values : `<int in milliseconds>`.\n * - `0`  : no retry, try each locator once\n * - `>0` : retry retryable locators until timeout expires\n * - `-1` : retry indefinitely until a listener is established\n *\n * In peer mode, this applies to the initial listen phase for\n * configured locators.\n *\n * Default value : `\"0\"`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\n#define Z_CONFIG_LISTEN_TIMEOUT_KEY 0x59\n#endif\n#define Z_CONFIG_LISTEN_TIMEOUT_DEFAULT \"0\"\n\n#ifdef Z_FEATURE_UNSTABLE_API\n/**\n * Indicates whether the application should fail if configured listen\n * locators cannot be opened.\n *\n * Accepted values : `false`, `true`.\n * - `true`  : fail if the listen phase does not establish the required listeners\n * - `false` : allow the session to continue even if listen attempts fail\n *\n * In peer mode, this applies to the initial listen phase for\n * configured locators.\n * If set to `true`, non-retryable listen errors fail immediately.\n * Retryable listen errors are retried according to\n * `Z_CONFIG_LISTEN_TIMEOUT_KEY`; if the timeout expires before the\n * listen locator is opened, `z_open` fails.\n *\n * Default value : `\"true\"`.\n *\n * .. warning:: This API has been marked as unstable: it works as advertised, but it may be changed in a future release.\n */\n#define Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY 0x5A\n#endif\n#define Z_CONFIG_LISTEN_EXIT_ON_FAILURE_DEFAULT \"true\"\n\n/*------------------ Compile-time configuration properties ------------------*/\n/**\n * Default length for Zenoh ID. Maximum size is 16 bytes.\n * This configuration will only be applied to Zenoh IDs generated by Zenoh-Pico.\n */\n#define Z_ZID_LENGTH 16\n\n/**\n * Protocol version identifier.\n * Do not change this value.\n */\n#define Z_PROTO_VERSION 0x09\n\n/**\n * Default multicast session join interval in milliseconds.\n */\n#define Z_JOIN_INTERVAL 2500\n\n#define Z_SN_RESOLUTION 0x02\n#define Z_REQ_RESOLUTION 0x02\n\n/**\n * Default size for the rx cache size (if activated).\n */\n#define Z_RX_CACHE_SIZE 10\n\n/**\n * Default get timeout in milliseconds.\n */\n#define Z_GET_TIMEOUT_DEFAULT 10000\n\n/**\n * Maximum number of connections for unicast listen sockets.\n */\n#define Z_LISTEN_MAX_CONNECTION_NB 10\n\n/**\n * Default \"nop\" instruction\n */\n#define ZP_ASM_NOP __asm__(\"nop\")\n\n#endif /* INCLUDE_ZENOH_PICO_CONFIG_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/bt.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_LINK_CONFIG_BT_H\n#define ZENOH_PICO_LINK_CONFIG_BT_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n\n#define BT_CONFIG_ARGC 3\n\n#define BT_CONFIG_MODE_KEY 0x01\n#define BT_CONFIG_MODE_STR \"mode\"\n\n#define BT_CONFIG_PROFILE_KEY 0x02\n#define BT_CONFIG_PROFILE_STR \"profile\"\n\n#define BT_CONFIG_TOUT_KEY 0x03\n#define BT_CONFIG_TOUT_STR \"tout\"\n\n#define BT_CONFIG_MAPPING_BUILD                   \\\n    _z_str_intmapping_t args[BT_CONFIG_ARGC];     \\\n    args[0]._key = BT_CONFIG_MODE_KEY;            \\\n    args[0]._str = (char *)BT_CONFIG_MODE_STR;    \\\n    args[1]._key = BT_CONFIG_PROFILE_KEY;         \\\n    args[1]._str = (char *)BT_CONFIG_PROFILE_STR; \\\n    args[2]._key = BT_CONFIG_TOUT_KEY;            \\\n    args[2]._str = (char *)BT_CONFIG_TOUT_STR;\n\nsize_t _z_bt_config_strlen(const _z_str_intmap_t *s);\n\nvoid _z_bt_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s);\nchar *_z_bt_config_to_str(const _z_str_intmap_t *s);\n\nz_result_t _z_bt_config_from_str(_z_str_intmap_t *strint, const char *s);\nz_result_t _z_bt_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_BT_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/raweth.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_CONFIG_RAWETH_H\n#define ZENOH_PICO_LINK_CONFIG_RAWETH_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/link.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define RAWETH_SCHEMA \"reth\"\n\nz_result_t _z_endpoint_raweth_valid(_z_endpoint_t *endpoint);\nz_result_t _z_new_link_raweth(_z_link_t *zl, _z_endpoint_t endpoint);\nsize_t _z_raweth_config_strlen(const _z_str_intmap_t *s);\nchar *_z_raweth_config_to_str(const _z_str_intmap_t *s);\nz_result_t _z_raweth_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\nz_result_t _z_raweth_config_from_str(_z_str_intmap_t *strint, const char *s);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_RAWETH_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/serial.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_CONFIG_SERIAL_H\n#define ZENOH_PICO_LINK_CONFIG_SERIAL_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n\n#define SERIAL_CONFIG_ARGC 1\n\n#define SERIAL_CONFIG_BAUDRATE_KEY 0x01\n#define SERIAL_CONFIG_BAUDRATE_STR \"baudrate\"\n\n// #define SERIAL_CONFIG_DATABITS_KEY     0x02\n// #define SERIAL_CONFIG_DATABITS_STR     \"data_bits\"\n\n// #define SERIAL_CONFIG_FLOWCONTROL_KEY  0x03\n// #define SERIAL_CONFIG_FLOWCONTROL_STR  \"flow_control\"\n\n// #define SERIAL_CONFIG_PARITY_KEY       0x04\n// #define SERIAL_CONFIG_PARITY_STR       \"parity\"\n\n// #define SERIAL_CONFIG_STOPBITS_KEY     0x05\n// #define SERIAL_CONFIG_STOPBITS_STR     \"stop_bits\"\n\n// #define SERIAL_CONFIG_TOUT_KEY         0x06\n// #define SERIAL_CONFIG_TOUT_STR         \"tout\"\n\n#define SERIAL_CONFIG_MAPPING_BUILD               \\\n    _z_str_intmapping_t args[SERIAL_CONFIG_ARGC]; \\\n    args[0]._key = SERIAL_CONFIG_BAUDRATE_KEY;    \\\n    args[0]._str = (char *)SERIAL_CONFIG_BAUDRATE_STR;\n// args[1]._key = SERIAL_CONFIG_DATABITS_KEY;\n// args[1]._str = SERIAL_CONFIG_DATABITS_STR;\n// args[2]._key = SERIAL_CONFIG_FLOWCONTROL_KEY;\n// args[2]._str = SERIAL_CONFIG_FLOWCONTROL_STR;\n// args[3]._key = SERIAL_CONFIG_PARITY_KEY;\n// args[3]._str = SERIAL_CONFIG_PARITY_STR;\n// args[4]._key = SERIAL_CONFIG_STOPBITS_KEY;\n// args[4]._str = SERIAL_CONFIG_STOPBITS_STR;\n// args[5]._key = SERIAL_CONFIG_TOUT_KEY;\n// args[5]._str = SERIAL_CONFIG_TOUT_STR;\n\nsize_t _z_serial_config_strlen(const _z_str_intmap_t *s);\n\nvoid _z_serial_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s);\nchar *_z_serial_config_to_str(const _z_str_intmap_t *s);\n\nz_result_t _z_serial_config_from_str(_z_str_intmap_t *strint, const char *s);\nz_result_t _z_serial_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_SERIAL_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/tcp.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_CONFIG_TCP_H\n#define ZENOH_PICO_LINK_CONFIG_TCP_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_TCP == 1\n\n#define TCP_CONFIG_ARGC 1\n\n#define TCP_CONFIG_TOUT_KEY 0x01\n#define TCP_CONFIG_TOUT_STR \"tout\"\n\n#define TCP_CONFIG_MAPPING_BUILD               \\\n    _z_str_intmapping_t args[TCP_CONFIG_ARGC]; \\\n    args[0]._key = TCP_CONFIG_TOUT_KEY;        \\\n    args[0]._str = (char *)TCP_CONFIG_TOUT_STR;\n\nsize_t _z_tcp_config_strlen(const _z_str_intmap_t *s);\n\nvoid _z_tcp_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s);\nchar *_z_tcp_config_to_str(const _z_str_intmap_t *s);\n\nz_result_t _z_tcp_config_from_str(_z_str_intmap_t *strint, const char *s);\nz_result_t _z_tcp_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_TCP_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/tls.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_LINK_CONFIG_TLS_H\n#define ZENOH_PICO_LINK_CONFIG_TLS_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_TLS == 1\n\n#define TLS_CONFIG_ARGC 12\n\n#define TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY 0x01\n#define TLS_CONFIG_ROOT_CA_CERTIFICATE_STR \"root_ca_certificate\"\n\n#define TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_KEY 0x02\n#define TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_STR \"root_ca_certificate_base64\"\n\n#define TLS_CONFIG_LISTEN_PRIVATE_KEY_KEY 0x03\n#define TLS_CONFIG_LISTEN_PRIVATE_KEY_STR \"listen_private_key\"\n\n#define TLS_CONFIG_LISTEN_PRIVATE_KEY_BASE64_KEY 0x04\n#define TLS_CONFIG_LISTEN_PRIVATE_KEY_BASE64_STR \"listen_private_key_base64\"\n\n#define TLS_CONFIG_LISTEN_CERTIFICATE_KEY 0x05\n#define TLS_CONFIG_LISTEN_CERTIFICATE_STR \"listen_certificate\"\n\n#define TLS_CONFIG_LISTEN_CERTIFICATE_BASE64_KEY 0x06\n#define TLS_CONFIG_LISTEN_CERTIFICATE_BASE64_STR \"listen_certificate_base64\"\n\n#define TLS_CONFIG_ENABLE_MTLS_KEY 0x07\n#define TLS_CONFIG_ENABLE_MTLS_STR \"enable_mtls\"\n\n#define TLS_CONFIG_CONNECT_PRIVATE_KEY_KEY 0x08\n#define TLS_CONFIG_CONNECT_PRIVATE_KEY_STR \"connect_private_key\"\n\n#define TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_KEY 0x09\n#define TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_STR \"connect_private_key_base64\"\n\n#define TLS_CONFIG_CONNECT_CERTIFICATE_KEY 0x0A\n#define TLS_CONFIG_CONNECT_CERTIFICATE_STR \"connect_certificate\"\n\n#define TLS_CONFIG_CONNECT_CERTIFICATE_BASE64_KEY 0x0B\n#define TLS_CONFIG_CONNECT_CERTIFICATE_BASE64_STR \"connect_certificate_base64\"\n\n#define TLS_CONFIG_VERIFY_NAME_ON_CONNECT_KEY 0x0C\n#define TLS_CONFIG_VERIFY_NAME_ON_CONNECT_STR \"verify_name_on_connect\"\n\n#define TLS_CONFIG_MAPPING_BUILD                                       \\\n    _z_str_intmapping_t args[TLS_CONFIG_ARGC];                         \\\n    args[0]._key = TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY;                 \\\n    args[0]._str = (char *)TLS_CONFIG_ROOT_CA_CERTIFICATE_STR;         \\\n    args[1]._key = TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_KEY;          \\\n    args[1]._str = (char *)TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_STR;  \\\n    args[2]._key = TLS_CONFIG_LISTEN_PRIVATE_KEY_KEY;                  \\\n    args[2]._str = (char *)TLS_CONFIG_LISTEN_PRIVATE_KEY_STR;          \\\n    args[3]._key = TLS_CONFIG_LISTEN_PRIVATE_KEY_BASE64_KEY;           \\\n    args[3]._str = (char *)TLS_CONFIG_LISTEN_PRIVATE_KEY_BASE64_STR;   \\\n    args[4]._key = TLS_CONFIG_LISTEN_CERTIFICATE_KEY;                  \\\n    args[4]._str = (char *)TLS_CONFIG_LISTEN_CERTIFICATE_STR;          \\\n    args[5]._key = TLS_CONFIG_LISTEN_CERTIFICATE_BASE64_KEY;           \\\n    args[5]._str = (char *)TLS_CONFIG_LISTEN_CERTIFICATE_BASE64_STR;   \\\n    args[6]._key = TLS_CONFIG_ENABLE_MTLS_KEY;                         \\\n    args[6]._str = (char *)TLS_CONFIG_ENABLE_MTLS_STR;                 \\\n    args[7]._key = TLS_CONFIG_CONNECT_PRIVATE_KEY_KEY;                 \\\n    args[7]._str = (char *)TLS_CONFIG_CONNECT_PRIVATE_KEY_STR;         \\\n    args[8]._key = TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_KEY;          \\\n    args[8]._str = (char *)TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_STR;  \\\n    args[9]._key = TLS_CONFIG_CONNECT_CERTIFICATE_KEY;                 \\\n    args[9]._str = (char *)TLS_CONFIG_CONNECT_CERTIFICATE_STR;         \\\n    args[10]._key = TLS_CONFIG_CONNECT_CERTIFICATE_BASE64_KEY;         \\\n    args[10]._str = (char *)TLS_CONFIG_CONNECT_CERTIFICATE_BASE64_STR; \\\n    args[11]._key = TLS_CONFIG_VERIFY_NAME_ON_CONNECT_KEY;             \\\n    args[11]._str = (char *)TLS_CONFIG_VERIFY_NAME_ON_CONNECT_STR;\n\nsize_t _z_tls_config_strlen(const _z_str_intmap_t *s);\n\nvoid _z_tls_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s);\nchar *_z_tls_config_to_str(const _z_str_intmap_t *s);\n\nz_result_t _z_tls_config_from_str(_z_str_intmap_t *strint, const char *s);\nz_result_t _z_tls_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_TLS_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/udp.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_CONFIG_UDP_H\n#define ZENOH_PICO_LINK_CONFIG_UDP_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define UDP_CONFIG_ARGC 3\n\n#define UDP_CONFIG_IFACE_KEY 0x01\n#define UDP_CONFIG_IFACE_STR \"iface\"\n\n#define UDP_CONFIG_TOUT_KEY 0x02\n#define UDP_CONFIG_TOUT_STR \"tout\"\n\n#define UDP_CONFIG_JOIN_KEY 0x03\n#define UDP_CONFIG_JOIN_STR \"join\"\n\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n#define UDP_CONFIG_MAPPING_BUILD                 \\\n    _z_str_intmapping_t args[UDP_CONFIG_ARGC];   \\\n    args[0]._key = UDP_CONFIG_IFACE_KEY;         \\\n    args[0]._str = (char *)UDP_CONFIG_IFACE_STR; \\\n    args[1]._key = UDP_CONFIG_TOUT_KEY;          \\\n    args[1]._str = (char *)UDP_CONFIG_TOUT_STR;  \\\n    args[2]._key = UDP_CONFIG_JOIN_KEY;          \\\n    args[2]._str = (char *)UDP_CONFIG_JOIN_STR;\n\nsize_t _z_udp_config_strlen(const _z_str_intmap_t *s);\n\nvoid _z_udp_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s);\nchar *_z_udp_config_to_str(const _z_str_intmap_t *s);\n\nz_result_t _z_udp_config_from_str(_z_str_intmap_t *strint, const char *s);\nz_result_t _z_udp_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_UDP_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/config/ws.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_CONFIG_WS_H\n#define ZENOH_PICO_LINK_CONFIG_WS_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_WS == 1\n\n#define WS_CONFIG_TOUT_KEY 0x01\n#define WS_CONFIG_TOUT_STR \"tout\"\n\n#define WS_CONFIG_MAPPING_BUILD        \\\n    uint8_t argc = 1;                  \\\n    _z_str_intmapping_t args[argc];    \\\n    args[0]._key = WS_CONFIG_TOUT_KEY; \\\n    args[0]._str = WS_CONFIG_TOUT_STR;\n\nsize_t _z_ws_config_strlen(const _z_str_intmap_t *s);\n\nvoid _z_ws_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s);\nchar *_z_ws_config_to_str(const _z_str_intmap_t *s);\n\nz_result_t _z_ws_config_from_str(_z_str_intmap_t *strint, const char *s);\nz_result_t _z_ws_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_CONFIG_WS_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/endpoint.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_ENDPOINT_H\n#define ZENOH_PICO_LINK_ENDPOINT_H\n\n#include \"zenoh-pico/collections/array.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Locator ------------------*/\n#if Z_FEATURE_LINK_TCP == 1\n#define TCP_SCHEMA \"tcp\"\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n#define UDP_SCHEMA \"udp\"\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#define BT_SCHEMA \"bt\"\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n#define SERIAL_SCHEMA \"serial\"\n#endif\n#if Z_FEATURE_LINK_WS == 1\n#define WS_SCHEMA \"ws\"\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n#define TLS_SCHEMA \"tls\"\n#endif\n\n#define LOCATOR_PROTOCOL_SEPARATOR '/'\n#define LOCATOR_METADATA_SEPARATOR '?'\ntypedef struct {\n    _z_str_intmap_t _metadata;\n    _z_string_t _protocol;\n    _z_string_t _address;\n} _z_locator_t;\n\nbool _z_locator_eq(const _z_locator_t *left, const _z_locator_t *right);\n\nvoid _z_locator_init(_z_locator_t *locator);\n_z_string_t _z_locator_to_string(const _z_locator_t *loc);\nz_result_t _z_locator_from_string(_z_locator_t *lc, const _z_string_t *s);\n\nsize_t _z_locator_size(_z_locator_t *lc);\nvoid _z_locator_clear(_z_locator_t *lc);\n_Z_ELEM_DEFINE(_z_locator, _z_locator_t, _z_locator_size, _z_locator_clear, _z_noop_copy, _z_noop_move, _z_locator_eq,\n               _z_noop_cmp, _z_noop_hash)\n\n/*------------------ Locator array ------------------*/\n_Z_ARRAY_DEFINE(_z_locator, _z_locator_t)\n\n/*------------------ Endpoint ------------------*/\n#define ENDPOINT_CONFIG_SEPARATOR '#'\n\ntypedef struct {\n    _z_locator_t _locator;\n    _z_str_intmap_t _config;\n} _z_endpoint_t;\n\n_z_string_t _z_endpoint_to_string(const _z_endpoint_t *e);\nz_result_t _z_endpoint_from_string(_z_endpoint_t *ep, const _z_string_t *s);\nvoid _z_endpoint_clear(_z_endpoint_t *ep);\nvoid _z_endpoint_free(_z_endpoint_t **ep);\n\nchar *_z_endpoint_parse_host(const _z_string_t *addr);\nchar *_z_endpoint_parse_port(const _z_string_t *addr);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_ENDPOINT_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/link.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_H\n#define ZENOH_PICO_LINK_H\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/link/transport/bt.h\"\n#include \"zenoh-pico/link/transport/raweth.h\"\n#include \"zenoh-pico/link/transport/tcp.h\"\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n#include \"zenoh-pico/link/transport/ws.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#include \"zenoh-pico/link/transport/serial_protocol.h\"\n#endif\n\n#if Z_FEATURE_LINK_TLS == 1\n#include \"zenoh-pico/link/transport/tls_stream.h\"\n#endif\n\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Link transport capability enum.\n *\n * Enumerators:\n *     Z_LINK_CAP_TRANSPORT_UNICAST: Link has unicast capabilities.\n *     Z_LINK_CAP_TRANSPORT_MULTICAST: Link has multicast capabilities.\n */\ntypedef enum {\n    Z_LINK_CAP_TRANSPORT_UNICAST = 0,\n    Z_LINK_CAP_TRANSPORT_MULTICAST = 1,\n    Z_LINK_CAP_TRANSPORT_RAWETH = 2,\n} _z_link_cap_transport_t;\n\n/**\n * Link flow capability enum.\n *\n * Enumerators:\n *     Z_LINK_CAP_FLOW_DATAGRAM: Link uses datagrams.\n *     Z_LINK_CAP_FLOW_STREAM: Link uses a byte stream.\n */\ntypedef enum {\n    Z_LINK_CAP_FLOW_DATAGRAM = 0,\n    Z_LINK_CAP_FLOW_STREAM = 1,\n} _z_link_cap_flow_t;\n\n/**\n * Link capabilities, stored as a register-like object.\n *\n * Fields:\n *     transport: 2 bits, see _z_link_cap_transport_t enum.\n *     flow: 1 bit, see _z_link_cap_flow_t enum.\n *     reliable: 1 bit, 1 if the link is reliable (network definition)\n *     reserved: 4 bits, reserved for future use\n */\ntypedef struct _z_link_capabilities_t {\n    uint8_t _transport : 2;\n    uint8_t _flow : 1;\n    uint8_t _is_reliable : 1;\n    uint8_t _reserved : 4;\n} _z_link_capabilities_t;\n\nstruct _z_link_t;  // Forward declaration to be used in _z_f_link_*\n\ntypedef z_result_t (*_z_f_link_open)(struct _z_link_t *self);\ntypedef z_result_t (*_z_f_link_listen)(struct _z_link_t *self);\ntypedef void (*_z_f_link_close)(struct _z_link_t *self);\ntypedef size_t (*_z_f_link_write)(const struct _z_link_t *self, const uint8_t *ptr, size_t len,\n                                  _z_sys_net_socket_t *socket);\ntypedef size_t (*_z_f_link_write_all)(const struct _z_link_t *self, const uint8_t *ptr, size_t len);\ntypedef size_t (*_z_f_link_read)(const struct _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr);\ntypedef size_t (*_z_f_link_read_exact)(const struct _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                       _z_sys_net_socket_t *socket);\ntypedef size_t (*_z_f_link_read_socket)(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len);\ntypedef void (*_z_f_link_free)(struct _z_link_t *self);\n\nstatic inline size_t _z_noop_link_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    _ZP_UNUSED(socket);\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(len);\n    _Z_ERROR(\"Function not implemented\");\n    return 0;\n}\n\nenum _z_link_type_e {\n    _Z_LINK_TYPE_TCP,\n    _Z_LINK_TYPE_UDP,\n    _Z_LINK_TYPE_BT,\n    _Z_LINK_TYPE_SERIAL,\n    _Z_LINK_TYPE_WS,\n    _Z_LINK_TYPE_TLS,\n    _Z_LINK_TYPE_RAWETH,\n};\n\ntypedef struct _z_link_t {\n    _z_endpoint_t _endpoint;\n    int _type;\n    union {\n#if Z_FEATURE_LINK_TCP == 1\n        _z_tcp_socket_t _tcp;\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n        _z_udp_socket_t _udp;\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n        _z_bt_socket_t _bt;\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        _z_serial_socket_t _serial;\n#endif\n#if Z_FEATURE_LINK_WS == 1\n        _z_ws_socket_t _ws;\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n        _z_tls_socket_t _tls;\n#endif\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n        _z_raweth_socket_t _raweth;\n#endif\n    } _socket;\n\n    _z_f_link_open _open_f;\n    _z_f_link_listen _listen_f;\n    _z_f_link_close _close_f;\n    _z_f_link_write _write_f;\n    _z_f_link_write_all _write_all_f;\n    _z_f_link_read _read_f;\n    _z_f_link_read_exact _read_exact_f;\n    _z_f_link_read_socket _read_socket_f;\n    _z_f_link_free _free_f;\n\n    uint16_t _mtu;\n    _z_link_capabilities_t _cap;\n} _z_link_t;\n\nvoid _z_link_clear(_z_link_t *zl);\nvoid _z_link_free(_z_link_t **zl);\nz_result_t _z_open_socket(const _z_string_t *locator, const _z_config_t *session_cfg, _z_sys_net_socket_t *socket);\nz_result_t _z_open_link(_z_link_t *zl, const _z_string_t *locator, const _z_config_t *session_cfg);\nz_result_t _z_listen_link(_z_link_t *zl, const _z_string_t *locator, const _z_config_t *session_cfg);\n\nz_result_t _z_link_send_wbuf(const _z_link_t *zl, const _z_wbuf_t *wbf, _z_sys_net_socket_t *socket);\nsize_t _z_link_recv_zbuf(const _z_link_t *zl, _z_zbuf_t *zbf, _z_slice_t *addr);\nsize_t _z_link_recv_exact_zbuf(const _z_link_t *zl, _z_zbuf_t *zbf, size_t len, _z_slice_t *addr,\n                               _z_sys_net_socket_t *socket);\nsize_t _z_link_socket_recv_zbuf(const _z_link_t *link, _z_zbuf_t *zbf, const _z_sys_net_socket_t socket);\nconst _z_sys_net_socket_t *_z_link_get_socket(const _z_link_t *link);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/manager.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_MANAGER_H\n#define ZENOH_PICO_LINK_MANAGER_H\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/utils/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_endpoint_tcp_valid(_z_endpoint_t *ep);\nz_result_t _z_new_peer_tcp(_z_endpoint_t *endpoint, _z_sys_net_socket_t *socket);\nz_result_t _z_new_link_tcp(_z_link_t *zl, _z_endpoint_t *ep);\n\n#if Z_FEATURE_LINK_UDP_UNICAST == 1\nz_result_t _z_endpoint_udp_unicast_valid(_z_endpoint_t *ep);\nz_result_t _z_new_link_udp_unicast(_z_link_t *zl, _z_endpoint_t ep);\n#endif\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1\nz_result_t _z_endpoint_udp_multicast_valid(_z_endpoint_t *ep);\nz_result_t _z_new_link_udp_multicast(_z_link_t *zl, _z_endpoint_t ep);\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\nz_result_t _z_endpoint_bt_valid(_z_endpoint_t *ep);\nz_result_t _z_new_link_bt(_z_link_t *zl, _z_endpoint_t ep);\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\nz_result_t _z_endpoint_serial_valid(_z_endpoint_t *ep);\nz_result_t _z_new_link_serial(_z_link_t *zl, _z_endpoint_t ep);\n#endif\n#if Z_FEATURE_LINK_WS == 1\nz_result_t _z_endpoint_ws_valid(_z_endpoint_t *ep);\nz_result_t _z_new_link_ws(_z_link_t *zl, _z_endpoint_t *ep);\n#endif\n#if Z_FEATURE_LINK_TLS == 1\nz_result_t _z_endpoint_tls_valid(_z_endpoint_t *ep);\nz_result_t _z_new_peer_tls(_z_endpoint_t *endpoint, _z_sys_net_socket_t *socket, const _z_config_t *session_cfg);\nz_result_t _z_new_link_tls(_z_link_t *zl, _z_endpoint_t *ep, const _z_config_t *session_cfg);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_MANAGER_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/bt.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_BT_H\n#define ZENOH_PICO_LINK_TRANSPORT_BT_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_BT_MODE_MASTER 0\n#define _Z_BT_MODE_SLAVE 1\n\n#define _Z_BT_PROFILE_UNSUPPORTED 255\n#define _Z_BT_PROFILE_SPP 0\n\ntypedef struct {\n    _z_sys_net_socket_t _sock;\n    char *_gname;\n} _z_bt_socket_t;\n\nz_result_t _z_open_bt(_z_sys_net_socket_t *sock, const char *gname, uint8_t mode, uint8_t profile, uint32_t tout);\nz_result_t _z_listen_bt(_z_sys_net_socket_t *sock, const char *gname, uint8_t mode, uint8_t profile, uint32_t tout);\nvoid _z_close_bt(_z_sys_net_socket_t *sock);\nsize_t _z_read_exact_bt(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_read_bt(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_send_bt(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_BT_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/lwip_socket.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_LWIP_SOCKET_H\n#define ZENOH_PICO_LINK_TRANSPORT_LWIP_SOCKET_H\n\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP) && defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED) && \\\n    !defined(ZP_LWIP_SOCKET_HELPERS_DEFINED)\n#error \"LWIP socket helpers must be provided by the selected platform header\"\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_LWIP_SOCKET_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/raweth.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_RAWETH_H\n#define ZENOH_PICO_LINK_TRANSPORT_RAWETH_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n\n// Ethernet types (big endian)\n#define _ZP_ETH_TYPE_VLAN 0x0081\n\n// Address Sizes\n#define _ZP_MAC_ADDR_LENGTH 6\n\n// Max frame size\n#define _ZP_MAX_ETH_FRAME_SIZE 1514\n\n// Endpoint config types\ntypedef struct {\n    _z_string_t _keyexpr;\n    uint16_t _vlan;  // vlan tag (pcp + dei + id), big endian\n    uint8_t _dmac[_ZP_MAC_ADDR_LENGTH];\n    bool _has_vlan;\n} _zp_raweth_mapping_entry_t;\n\nvoid _z_raweth_clear_mapping_entry(_zp_raweth_mapping_entry_t *entry);\n\n_Z_ELEM_DEFINE(_zp_raweth_mapping, _zp_raweth_mapping_entry_t, _z_noop_size, _z_raweth_clear_mapping_entry,\n               _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_ARRAY_DEFINE(_zp_raweth_mapping, _zp_raweth_mapping_entry_t)\n\ntypedef struct {\n    uint8_t _mac[_ZP_MAC_ADDR_LENGTH];\n} _zp_raweth_whitelist_entry_t;\n\n_Z_ELEM_DEFINE(_zp_raweth_whitelist, _zp_raweth_whitelist_entry_t, _z_noop_size, _z_noop_clear, _z_noop_copy,\n               _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_ARRAY_DEFINE(_zp_raweth_whitelist, _zp_raweth_whitelist_entry_t)\n\n// Ethernet header structure type\ntypedef struct {\n    uint8_t dmac[_ZP_MAC_ADDR_LENGTH];  // Destination mac address\n    uint8_t smac[_ZP_MAC_ADDR_LENGTH];  // Source mac address\n    uint16_t ethtype;                   // Ethertype of frame\n    uint16_t data_length;               // Payload length\n} _zp_eth_header_t;\n\ntypedef struct {\n    uint8_t dmac[_ZP_MAC_ADDR_LENGTH];  // Destination mac address\n    uint8_t smac[_ZP_MAC_ADDR_LENGTH];  // Source mac address\n    uint16_t vlan_type;                 // Vlan ethtype\n    uint16_t tag;                       // Vlan tag\n    uint16_t ethtype;                   // Ethertype of frame\n    uint16_t data_length;               // Payload length\n} _zp_eth_vlan_header_t;\n\ntypedef struct {\n    const char *_interface;\n    _z_sys_net_socket_t _sock;\n    _zp_raweth_mapping_array_t _mapping;\n    _zp_raweth_whitelist_array_t _whitelist;\n    uint16_t _vlan;\n    uint16_t _ethtype;\n    uint8_t _dmac[_ZP_MAC_ADDR_LENGTH];\n    uint8_t _smac[_ZP_MAC_ADDR_LENGTH];\n    bool _has_vlan;\n} _z_raweth_socket_t;\n\nz_result_t _z_open_raweth(_z_sys_net_socket_t *sock, const char *interface);\nsize_t _z_send_raweth(const _z_sys_net_socket_t *sock, const void *buff, size_t buff_len);\nsize_t _z_receive_raweth(const _z_sys_net_socket_t *sock, void *buff, size_t buff_len, _z_slice_t *addr,\n                         const _zp_raweth_whitelist_array_t *whitelist);\nz_result_t _z_close_raweth(_z_sys_net_socket_t *sock);\nuint16_t _z_raweth_ntohs(uint16_t val);\nuint16_t _z_raweth_htons(uint16_t val);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_RAWETH_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/serial.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_SERIAL_H\n#define ZENOH_PICO_LINK_TRANSPORT_SERIAL_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate);\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate);\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate);\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate);\nvoid _z_serial_close(_z_sys_net_socket_t *sock);\n// flawfinder: ignore\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_SERIAL_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/serial_protocol.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_SERIAL_PROTOCOL_H\n#define ZENOH_PICO_LINK_TRANSPORT_SERIAL_PROTOCOL_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n\n#define _Z_SERIAL_MTU_SIZE 1500\n#define _Z_SERIAL_MFS_SIZE _Z_SERIAL_MTU_SIZE + 1 + 2 + 4  // MTU + Header + Serial Len + Serial CRC32\n#define _Z_SERIAL_MAX_COBS_BUF_SIZE \\\n    1516  // Max On-the-wire length for an MFS/MTU of 1510/1500 (MFS + Overhead Byte (OHB) + End of packet (EOP))\n\ntypedef struct {\n    _z_sys_net_socket_t _sock;\n} _z_serial_socket_t;\n\nz_result_t _z_serial_endpoint_valid(const _z_endpoint_t *endpoint);\nz_result_t _z_serial_protocol_open(_z_serial_socket_t *sock, const _z_endpoint_t *endpoint);\nz_result_t _z_serial_protocol_listen(_z_serial_socket_t *sock, const _z_endpoint_t *endpoint);\nvoid _z_serial_protocol_close(_z_serial_socket_t *sock);\nz_result_t _z_connect_serial(const _z_sys_net_socket_t sock);\nsize_t _z_read_serial(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_send_serial(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len);\nsize_t _z_read_exact_serial(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_SERIAL_PROTOCOL_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/socket.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_SOCKET_H\n#define ZENOH_PICO_LINK_TRANSPORT_SOCKET_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _z_socket_wait_iter_t _z_socket_wait_iter_t;\ntypedef void (*_z_socket_wait_iter_reset_f)(_z_socket_wait_iter_t *iter);\ntypedef bool (*_z_socket_wait_iter_next_f)(_z_socket_wait_iter_t *iter);\ntypedef const _z_sys_net_socket_t *(*_z_socket_wait_iter_get_socket_f)(const _z_socket_wait_iter_t *iter);\ntypedef void (*_z_socket_wait_iter_set_ready_f)(_z_socket_wait_iter_t *iter, bool ready);\n\nstruct _z_socket_wait_iter_t {\n    void *_ctx;\n    void *_current_entry;\n    _z_socket_wait_iter_reset_f _reset;\n    _z_socket_wait_iter_next_f _next;\n    _z_socket_wait_iter_get_socket_f _get_socket;\n    _z_socket_wait_iter_set_ready_f _set_ready;\n};\n\nstatic inline void _z_socket_wait_iter_reset(_z_socket_wait_iter_t *iter) { iter->_reset(iter); }\nstatic inline bool _z_socket_wait_iter_next(_z_socket_wait_iter_t *iter) { return iter->_next(iter); }\nstatic inline const _z_sys_net_socket_t *_z_socket_wait_iter_get_socket(const _z_socket_wait_iter_t *iter) {\n    return iter->_get_socket(iter);\n}\nstatic inline void _z_socket_wait_iter_set_ready(_z_socket_wait_iter_t *iter, bool ready) {\n    iter->_set_ready(iter, ready);\n}\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms);\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking);\nz_result_t _z_ip_port_to_endpoint(const uint8_t *address, size_t address_len, uint16_t port, char *dst, size_t dst_len);\nz_result_t _z_socket_get_endpoints(const _z_sys_net_socket_t *sock, char *local, size_t local_len, char *remote,\n                                   size_t remote_len);\nvoid _z_socket_close(_z_sys_net_socket_t *sock);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_SOCKET_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/tcp.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_TCP_H\n#define ZENOH_PICO_LINK_TRANSPORT_TCP_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    _z_sys_net_socket_t _sock;\n    _z_sys_net_endpoint_t _rep;\n} _z_tcp_socket_t;\n\nchar *_z_tcp_address_parse_host(const _z_string_t *address);\nz_result_t _z_tcp_address_valid(const _z_string_t *address);\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port);\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep);\nz_result_t _z_tcp_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address);\n\n// flawfinder: ignore\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout);\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint);\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out);\nvoid _z_tcp_close(_z_sys_net_socket_t *sock);\n\n// flawfinder: ignore\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_TCP_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/tls_stream.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_TLS_STREAM_H\n#define ZENOH_PICO_LINK_TRANSPORT_TLS_STREAM_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_TLS == 1\n\n#include \"mbedtls/entropy.h\"\n#include \"mbedtls/error.h\"\n#include \"mbedtls/hmac_drbg.h\"\n#include \"mbedtls/net_sockets.h\"\n#include \"mbedtls/pk.h\"\n#include \"mbedtls/ssl.h\"\n#include \"mbedtls/x509_crt.h\"\n\ntypedef struct {\n    mbedtls_ssl_context _ssl;\n    mbedtls_ssl_config _ssl_config;\n    mbedtls_entropy_context _entropy;\n    mbedtls_hmac_drbg_context _hmac_drbg;\n    mbedtls_x509_crt _ca_cert;\n    mbedtls_pk_context _listen_key;\n    mbedtls_x509_crt _listen_cert;\n    mbedtls_pk_context _client_key;\n    mbedtls_x509_crt _client_cert;\n    bool _enable_mtls;\n} _z_tls_context_t;\n\ntypedef struct {\n    _z_sys_net_socket_t _sock;\n    _z_tls_context_t *_tls_ctx;\n    bool _is_peer_socket;  // a peer socket allocated in heap, needs to be freed in _z_close_tls\n} _z_tls_socket_t;\n\nz_result_t _z_open_tls(_z_tls_socket_t *sock, const _z_sys_net_endpoint_t *rep, const char *hostname,\n                       const _z_str_intmap_t *config, bool peer_socket);\nz_result_t _z_listen_tls(_z_tls_socket_t *sock, const _z_sys_net_endpoint_t *rep, const _z_str_intmap_t *config);\nz_result_t _z_tls_accept(_z_sys_net_socket_t *socket, const _z_sys_net_socket_t *listen_sock);\nvoid _z_close_tls_socket(_z_sys_net_socket_t *socket);\nvoid _z_close_tls(_z_tls_socket_t *sock);\nsize_t _z_read_tls(const _z_tls_socket_t *sock, uint8_t *ptr, size_t len);\nsize_t _z_write_tls(const _z_tls_socket_t *sock, const uint8_t *ptr, size_t len);\nsize_t _z_write_all_tls(const _z_tls_socket_t *sock, const uint8_t *ptr, size_t len);\n\n#endif  // Z_FEATURE_LINK_TLS == 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_TLS_STREAM_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/udp_multicast.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_UDP_MULTICAST_H\n#define ZENOH_PICO_LINK_TRANSPORT_UDP_MULTICAST_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1\n\nstatic inline z_result_t _z_udp_multicast_default_endpoint_init_from_address(_z_sys_net_endpoint_t *ep,\n                                                                             const _z_string_t *address) {\n    return _z_udp_unicast_endpoint_init_from_address(ep, address);\n}\n\nstatic inline void _z_udp_multicast_default_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    _z_udp_unicast_endpoint_clear(ep);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address);\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep);\n\n// flawfinder: ignore\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface);\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join);\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep);\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep);\n// flawfinder: ignore\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep);\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_UDP_MULTICAST_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/udp_unicast.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_UDP_UNICAST_H\n#define ZENOH_PICO_LINK_TRANSPORT_UDP_UNICAST_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    _z_sys_net_socket_t _sock;\n    _z_sys_net_socket_t _msock;\n    _z_sys_net_endpoint_t _rep;\n    _z_sys_net_endpoint_t _lep;\n} _z_udp_socket_t;\n\nz_result_t _z_udp_unicast_address_valid(const _z_string_t *address);\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port);\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep);\nz_result_t _z_udp_unicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address);\n\n// flawfinder: ignore\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout);\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout);\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock);\n\n// flawfinder: ignore\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len);\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_UDP_UNICAST_H */\n"
  },
  {
    "path": "include/zenoh-pico/link/transport/ws.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_WS_H\n#define ZENOH_PICO_LINK_TRANSPORT_WS_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LINK_WS == 1\n\ntypedef struct {\n    _z_sys_net_socket_t _sock;\n    _z_sys_net_endpoint_t _rep;\n} _z_ws_socket_t;\n\nz_result_t _z_ws_endpoint_init(_z_sys_net_endpoint_t *ep, const _z_string_t *address);\nvoid _z_ws_endpoint_clear(_z_sys_net_endpoint_t *ep);\nz_result_t _z_ws_transport_open(_z_ws_socket_t *sock, uint32_t tout);\nz_result_t _z_ws_transport_listen(_z_ws_socket_t *sock);\nvoid _z_ws_transport_close(_z_ws_socket_t *sock);\nsize_t _z_ws_transport_read(const _z_ws_socket_t *sock, uint8_t *ptr, size_t len);\nsize_t _z_ws_transport_read_exact(const _z_ws_socket_t *sock, uint8_t *ptr, size_t len);\nsize_t _z_ws_transport_write(const _z_ws_socket_t *sock, const uint8_t *ptr, size_t len);\nsize_t _z_ws_transport_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_WS_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/config.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_CONFIG_NETAPI_H\n#define ZENOH_PICO_CONFIG_NETAPI_H\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Create an empty set of properties for zenoh-net session configuration.\n *\n * Returns:\n *     A :c:type:`_z_config_t` containing an empty configuration.\n */\n_z_config_t _z_config_empty(void);\n\n/**\n * Create a default set of properties for zenoh-net session configuration.\n *\n * Parameters:\n *   config:  A :c:type:`_z_config_t` where a default configuration for client mode will be constructed.\n *\n * Returns:\n *   `0`` in case of success, or a ``negative value`` otherwise.\n */\nz_result_t _z_config_default(_z_config_t *config);\n\n/**\n * Create a default set of properties for client mode zenoh-net session configuration.\n * If peer is not null, it is added to the configuration as remote peer.\n *\n * Parameters:\n *   config:  A :c:type:`_z_config_t` where a default configuration for client mode will be constructed.\n *   locator: An optional peer locator. The caller keeps its ownership.\n *\n * Returns:\n *     `0`` in case of success, or a ``negative value`` otherwise.\n */\nz_result_t _z_config_client(_z_config_t *config, const char *locator);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_CONFIG_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/encoding.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_ENCODING_NETAPI_H\n#define ZENOH_PICO_ENCODING_NETAPI_H\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/string.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_ENCODING_ID_DEFAULT 0\n\n/**\n * A zenoh encoding.\n */\ntypedef struct _z_encoding_t {\n    _z_string_t schema;\n    uint16_t id;\n} _z_encoding_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_encoding_t _z_encoding_null(void) { return (_z_encoding_t){0}; }\nstatic inline bool _z_encoding_check(const _z_encoding_t *encoding) {\n    return ((encoding->id != _Z_ENCODING_ID_DEFAULT) || _z_string_check(&encoding->schema));\n}\nstatic inline void _z_encoding_clear(_z_encoding_t *encoding) { _z_string_clear(&encoding->schema); }\n_z_encoding_t _z_encoding_wrap(uint16_t id, const char *schema);\nz_result_t _z_encoding_make(_z_encoding_t *encoding, uint16_t id, const char *schema, size_t len);\nz_result_t _z_encoding_copy(_z_encoding_t *dst, const _z_encoding_t *src);\nz_result_t _z_encoding_move(_z_encoding_t *dst, _z_encoding_t *src);\nstatic inline _z_encoding_t _z_encoding_alias(const _z_encoding_t *src) {\n    _z_encoding_t dst;\n    dst.id = src->id;\n    if (_z_string_check(&src->schema)) {\n        dst.schema = _z_string_alias(src->schema);\n    } else {\n        dst.schema = _z_string_null();\n    }\n    return dst;\n}\nstatic inline _z_encoding_t _z_encoding_steal(_z_encoding_t *val) {\n    _z_encoding_t ret = *val;\n    val->schema._slice.len = 0;\n    val->schema._slice.start = NULL;\n    return ret;\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_ENCODING_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/filtering.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_FILTERING_NETAPI_H\n#define ZENOH_PICO_FILTERING_NETAPI_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/utils/locality.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    uintptr_t peer;\n    uint32_t decl_id;\n} _z_filter_target_t;\n\ntypedef z_element_eq_f _z_filter_target_eq_f;\ntypedef z_element_eq_f _z_filter_target_predicate_f;\n#define _z_filter_target_elem_copy _z_noop_copy\n#define _z_filter_target_elem_clear _z_noop_clear\n_Z_SLIST_DEFINE(_z_filter_target, _z_filter_target_t, false)\n\ntypedef enum {\n    WRITE_FILTER_ACTIVE = 0,\n    WRITE_FILTER_OFF = 1,\n} _z_write_filter_state_t;\n\nstruct _z_write_filter_registration_t;\n\ntypedef enum {\n    _Z_WRITE_FILTER_SUBSCRIBER = 0,\n    _Z_WRITE_FILTER_QUERYABLE = 1,\n} _z_write_filter_target_type_t;\n\ntypedef struct {\n    _z_session_weak_t zn;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t mutex;\n#endif\n    _z_filter_target_slist_t *targets;\n#if Z_FEATURE_MATCHING == 1\n    _z_closure_matching_status_intmap_t callbacks;\n#endif\n    _z_keyexpr_t key;\n    uint8_t state;\n    bool is_complete;\n    bool is_aggregate;\n    bool allow_local;\n    bool allow_remote;\n    _z_write_filter_target_type_t target_type;\n    size_t local_targets;\n    struct _z_write_filter_registration_t *registration;\n} _z_write_filter_ctx_t;\n\nz_result_t _z_write_filter_ctx_clear(_z_write_filter_ctx_t *filter);\n\n_Z_REFCOUNT_DEFINE_NO_FROM_VAL(_z_write_filter_ctx, _z_write_filter_ctx)\n\n/**\n * Return type when declaring a queryable.\n */\ntypedef struct _z_write_filter_t {\n    uint32_t _interest_id;\n    _z_write_filter_ctx_rc_t ctx;\n} _z_write_filter_t;\n\nz_result_t _z_write_filter_create(const _z_session_rc_t *zn, _z_write_filter_t *filter,\n                                  const _z_declared_keyexpr_t *keyexpr, uint8_t interest_flag, bool complete,\n                                  z_locality_t locality);\nz_result_t _z_write_filter_clear(_z_write_filter_t *filter);\nvoid _z_write_filter_notify_subscriber(struct _z_session_t *session, const _z_keyexpr_t *key,\n                                       z_locality_t allowed_origin, bool add);\nvoid _z_write_filter_notify_queryable(struct _z_session_t *session, const _z_keyexpr_t *key,\n                                      z_locality_t allowed_origin, bool is_complete, bool add);\n\n#if Z_FEATURE_MATCHING\nz_result_t _z_write_filter_ctx_add_callback(_z_write_filter_ctx_t *filter, size_t id, _z_closure_matching_status_t *v);\nvoid _z_write_filter_ctx_remove_callback(_z_write_filter_ctx_t *filter, size_t id);\nvoid _z_write_filter_ctx_remove_callbacks(_z_write_filter_ctx_t *ctx);\n#endif\n\n#if Z_FEATURE_INTEREST == 1\nstatic inline bool _z_write_filter_ctx_active(const _z_write_filter_ctx_t *ctx) {\n    return ctx->state == WRITE_FILTER_ACTIVE;\n}\nstatic inline bool _z_write_filter_active(const _z_write_filter_t *filter) {\n    return _z_write_filter_ctx_active(_Z_RC_IN_VAL(&filter->ctx));\n}\n#else\nstatic inline bool _z_write_filter_active(const _z_write_filter_t *filter) {\n    _ZP_UNUSED(filter);\n    return false;\n}\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_FILTERING_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/liveliness.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef INCLUDE_ZENOH_PICO_NET_LIVELINESS_H\n#define INCLUDE_ZENOH_PICO_NET_LIVELINESS_H\n\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/net/subscribe.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_LIVELINESS == 1\n\nz_result_t _z_declare_liveliness_token(const _z_session_rc_t *zn, _z_liveliness_token_t *ret_token,\n                                       const _z_declared_keyexpr_t *keyexpr);\nz_result_t _z_undeclare_liveliness_token(_z_liveliness_token_t *token);\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n/**\n * Declare a :c:type:`_z_subscriber_t` for the given liveliness key.\n *\n * Parameters:\n *     subscriber: The subscriber to initialize.\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr: The resource key to subscribe.\n *     callback: The callback function that will be called each time a matching liveliness token changed.\n *     history: Enable current interest to return history tokens.\n *     arg: A pointer that will be passed to the **callback** on each call.\n *\n * Returns:\n *     0 in case of success, negative error code otherwise.\n */\nz_result_t _z_declare_liveliness_subscriber(_z_subscriber_t *subscriber, const _z_session_rc_t *zn,\n                                            const _z_declared_keyexpr_t *keyexpr, _z_closure_sample_callback_t callback,\n                                            _z_drop_handler_t dropper, bool history, void *arg);\n\nz_result_t _z_register_liveliness_subscriber(uint32_t *out_sub_id, const _z_session_rc_t *zn,\n                                             const _z_declared_keyexpr_t *keyexpr,\n                                             _z_closure_sample_callback_t callback, _z_drop_handler_t dropper,\n                                             bool history, void *arg,\n                                             const _z_sync_group_t *opt_callback_drop_sync_group);\n\n/**\n * Undeclare a liveliness :c:type:`_z_subscriber_t`.\n *\n * Parameters:\n *     sub: The :c:type:`_z_subscriber_t` to undeclare. The callee releases the\n *          subscriber upon successful return.\n * Returns:\n *     0 if success, or a negative value identifying the error.\n */\nz_result_t _z_undeclare_liveliness_subscriber(_z_subscriber_t *sub);\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n#if Z_FEATURE_QUERY == 1\n/**\n * Query liveliness token state.\n *\n * Parameters:\n *     session: The zenoh-net session.\n *     keyexpr: The resource key to liveliness token.\n *     callback: The callback function that will be called on reception of replies for this query.\n *     dropper: The callback function that will be called on upon completion of the callback.\n *     arg: A pointer that will be passed to the **callback** on each call.\n *     timeout_ms: The timeout value of this query.\n *     opt_cancellation_token: Optional cancellation token, can be NULL.\n */\nz_result_t _z_liveliness_query(const _z_session_rc_t *session, const _z_declared_keyexpr_t *keyexpr,\n                               _z_closure_reply_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                               uint64_t timeout_ms, _z_cancellation_token_rc_t *opt_cancellation_token);\n#endif  // Z_FEATURE_QUERY == 1\n\n#endif  // Z_FEATURE_LIVELINESS == 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_NET_LIVELINESS_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/logger.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LOGGER_NETAPI_H\n#define ZENOH_PICO_LOGGER_NETAPI_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Initialise the zenoh runtime logger\n */\nvoid _z_init_logger(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LOGGER_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/matching.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_NET_MATCHING_H\n#define INCLUDE_ZENOH_PICO_NET_MATCHING_H\n\n#include \"zenoh-pico/net/filtering.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _z_matching_listener_t {\n    uint32_t _id;\n    _z_write_filter_ctx_weak_t _write_filter_ctx;\n} _z_matching_listener_t;\n\n#if Z_FEATURE_MATCHING == 1\nz_result_t _z_matching_listener_declare(_z_matching_listener_t *listener, _z_session_t *s,\n                                        const _z_write_filter_ctx_rc_t *ctx, _z_closure_matching_status_t *callback);\nz_result_t _z_matching_listener_register(uint32_t *listener_id, _z_session_t *s, const _z_write_filter_ctx_rc_t *ctx,\n                                         _z_closure_matching_status_t *callback);\nz_result_t _z_matching_listener_undeclare(_z_matching_listener_t *listener);\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_matching_listener_t _z_matching_listener_null(void) { return (_z_matching_listener_t){0}; }\nstatic inline bool _z_matching_listener_check(const _z_matching_listener_t *matching_listener) {\n    return !_Z_RC_IS_NULL(&matching_listener->_write_filter_ctx);\n}\nvoid _z_matching_listener_clear(_z_matching_listener_t *listener);\nvoid _z_matching_listener_free(_z_matching_listener_t **listener);\n#endif  // Z_FEATURE_MATCHING == 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_NET_MATCHING_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/primitives.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef INCLUDE_ZENOH_PICO_NET_PRIMITIVES_H\n#define INCLUDE_ZENOH_PICO_NET_PRIMITIVES_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/net/publish.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/net/subscribe.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------- Declaration Helpers --------------*/\nz_result_t _z_send_declare(_z_session_t *zn, const _z_network_message_t *n_msg);\nz_result_t _z_send_undeclare(_z_session_t *zn, const _z_network_message_t *n_msg);\n\n/*------------------ Discovery ------------------*/\n#if Z_FEATURE_SCOUTING == 1\n/**\n * Scout for routers and/or peers.\n *\n * Parameters:\n *     what: A what bitmask of zenoh entities kind to scout for.\n *     zid: The ZenohID of the scouting origin.\n *     locator: The locator where to scout.\n *     timeout: The time that should be spent scouting before returning the results.\n */\nvoid _z_scout(const z_what_t what, const _z_id_t zid, _z_string_t *locator, const uint32_t timeout,\n              _z_closure_hello_callback_t callback, void *arg_call, _z_drop_handler_t dropper, void *arg_drop);\n#endif\n/*------------------ Declarations ------------------*/\n\n/**\n * Associate a numerical id with the given resource key.\n *\n * This numerical id will be used on the network to save bandwidth and\n * ease the retrieval of the concerned resource in the routing tables.\n *\n * Parameters:\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     key: The resource key to map to a numerical id. The callee gets\n *             the ownership of any allocated value.\n *     out_id: The memory location where to store the numerical id of the declared resource.\n *\n * Returns:\n *     0 in case of success, or a negative value identifying the error.\n */\nz_result_t _z_declare_resource(_z_session_t *zn, const _z_string_t *key, uint16_t *out_id);\n\n/**\n * Associate a numerical id with the given resource key.\n *\n * This numerical id will be used on the network to save bandwidth and\n * ease the retrieval of the concerned resource in the routing tables.\n *\n * Parameters:\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     rid: The numerical id of the resource to undeclare.\n * Returns:\n *    0 if success, or a negative value identifying the error.\n */\nz_result_t _z_undeclare_resource(_z_session_t *zn, uint16_t rid);\n\n/**\n * Declare keyexpr if it is necessary and allowed.\n * Returns updated keyexpr.\n *\n * Parameters:\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr: The resource key to declare.\n * Returns:\n *     Updated keyexpr.\n */\n_z_keyexpr_t _z_update_keyexpr_to_declared(_z_session_t *zs, _z_keyexpr_t keyexpr);\n\n#if Z_FEATURE_PUBLICATION == 1\n/**\n * Declare a :c:type:`_z_publisher_t` for the given resource key.\n *\n * Written resources that match the given key will only be sent on the network\n * if matching subscribers exist in the system.\n *\n * Parameters:\n *     publisher: The publisher to initialize.\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr:  The resource key to publish.\n *     encoding: The optional default encoding to use during put. The callee gets the ownership.\n *     reliability: The reliability of the publisher messages\n *\n * Returns:\n *    0 in case of success, negative error code otherwise.\n */\nz_result_t _z_declare_publisher(_z_publisher_t *publisher, const _z_session_rc_t *zn,\n                                const _z_declared_keyexpr_t *keyexpr, _z_encoding_t *encoding,\n                                z_congestion_control_t congestion_control, z_priority_t priority, bool is_express,\n                                z_reliability_t reliability, z_locality_t allowed_destination);\n\n/**\n * Undeclare a :c:type:`_z_publisher_t`.\n *\n * Parameters:\n *     pub: The :c:type:`_z_publisher_t` to undeclare. The callee releases the\n *          publisher upon successful return.\n * Returns:\n *    0 if success, or a negative value identifying the error.\n */\nz_result_t _z_undeclare_publisher(_z_publisher_t *pub);\n\n/**\n * Write data corresponding to a given resource key, allowing the definition of\n * additional properties.\n *\n * Parameters:\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr: The resource key to write. The caller keeps its ownership.\n *     payload: The data to write.\n *     encoding: The encoding of the payload. The callee gets the ownership of\n *               any allocated value.\n *     kind: The kind of the value.\n *     cong_ctrl: The congestion control of this write. Possible values defined\n *                in :c:type:`_z_congestion_control_t`.\n *     is_express: If true, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *     timestamp: The timestamp of this write. The API level timestamp (e.g. of the data when it was created).\n *     attachment: An optional attachment to this write.\n *     reliability: The message reliability.\n *     source_info: The message source info.\n *     allowed_destination: The allowed destination locality.\n * Returns:\n *     ``0`` in case of success, ``-1`` in case of failure.\n */\nz_result_t _z_write(_z_session_t *zn, const _z_declared_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                    _z_encoding_t *encoding, const z_sample_kind_t kind, const z_congestion_control_t cong_ctrl,\n                    z_priority_t priority, bool is_express, const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                    z_reliability_t reliability, const _z_source_info_t *source_info, z_locality_t allowed_destination);\n#endif\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n/**\n * Declare a :c:type:`_z_subscriber_t` for the given resource key.\n *\n * Parameters:\n *     subscriber: The subscriber to initialize.\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr: The resource key to subscribe.\n *     callback: The callback function that will be called each time a data matching the subscribed resource is\n * received.\n *     dropper: A function that will be called once subscriber is undeclared.\n *     arg: A pointer that will be passed to the **callback** on each call.\n *\n * Returns:\n *    0 in case of success, negative error code otherwise.\n */\nz_result_t _z_declare_subscriber(_z_subscriber_t *subscriber, const _z_session_rc_t *zn,\n                                 const _z_declared_keyexpr_t *keyexpr, _z_closure_sample_callback_t callback,\n                                 _z_drop_handler_t dropper, void *arg, z_locality_t allowed_origin);\n\nz_result_t _z_register_subscriber(uint32_t *out_sub_id, const _z_session_rc_t *zn, const _z_declared_keyexpr_t *keyexpr,\n                                  _z_closure_sample_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                                  z_locality_t allowed_origin, const _z_sync_group_t *opt_callback_drop_sync_group);\n\n/**\n * Undeclare a :c:type:`_z_subscriber_t`.\n *\n * Parameters:\n *     sub: The :c:type:`_z_subscriber_t` to undeclare. The callee releases the\n *          subscriber upon successful return.\n * Returns:\n *    0 if success, or a negative value identifying the error.\n */\nz_result_t _z_undeclare_subscriber(_z_subscriber_t *sub);\n#endif\n\n#if Z_FEATURE_QUERYABLE == 1\n/**\n * Declare a :c:type:`_z_queryable_t` for the given resource key.\n *\n * Parameters:\n *     queryable: The queryable to initialize.\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr: The resource key the :c:type:`_z_queryable_t` will reply to.\n *     complete: The complete of :c:type:`_z_queryable_t`.\n *     callback: The callback function that will be called each time a matching query is received.\n *     arg: A pointer that will be passed to the **callback** on each call.\n *\n * Returns:\n *    0 in case of success, negative error code otherwise.\n */\nz_result_t _z_declare_queryable(_z_queryable_t *queryable, const _z_session_rc_t *zn,\n                                const _z_declared_keyexpr_t *keyexpr, bool complete,\n                                _z_closure_query_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                                z_locality_t allowed_origin);\n\nz_result_t _z_register_queryable(uint32_t *queryable_id, const _z_session_rc_t *zn,\n                                 const _z_declared_keyexpr_t *keyexpr, bool complete,\n                                 _z_closure_query_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                                 z_locality_t allowed_origin, const _z_sync_group_t *sync_group);\n\n/**\n * Undeclare a :c:type:`_z_queryable_t`.\n *\n * Parameters:\n *     qle: The :c:type:`_z_queryable_t` to undeclare. The callee releases the\n *          queryable upon successful return.\n * Returns:\n *    0 if success, or a negative value identifying the error.\n */\nz_result_t _z_undeclare_queryable(_z_queryable_t *qle);\n\n/**\n * Send a reply to a query.\n *\n * This function must be called inside of a Queryable callback passing the\n * query received as parameters of the callback function. This function can\n * be called multiple times to send multiple replies to a query. The reply\n * will be considered complete when the Queryable callback returns.\n *\n * Parameters:\n *     query: The query to reply to. The caller keeps its ownership.\n *     key: The resource key of this reply. The caller keeps the ownership.\n *     payload: The value of this reply, the caller keeps ownership.\n *     kind: The type of operation.\n *     attachment: An optional attachment to the reply.\n *     is_express: If true, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *     timestamp: The timestamp of this reply. The API level timestamp (e.g. of the data when it was created).\n *     source_info: The message source info.\n */\nz_result_t _z_send_reply(const _z_query_t *query, const _z_session_rc_t *zsrc, const _z_declared_keyexpr_t *keyexpr,\n                         _z_bytes_t *payload, _z_encoding_t *encoding, const z_sample_kind_t kind, bool is_express,\n                         const _z_timestamp_t *timestamp, _z_bytes_t *attachment, _z_source_info_t *source_info);\n/**\n * Send a reply error to a query.\n *\n * This function must be called inside of a Queryable callback passing the\n * query received as parameters of the callback function. This function can\n * be called multiple times to send multiple replies to a query. The reply\n * will be considered complete when the Queryable callback returns.\n *\n * Parameters:\n *     query: The query to reply to. The caller keeps its ownership.\n *     key: The resource key of this reply. The caller keeps the ownership.\n *     payload: The value of this reply, the caller keeps ownership.\n */\nz_result_t _z_send_reply_err(const _z_query_t *query, const _z_session_rc_t *zsrc, _z_bytes_t *payload,\n                             _z_encoding_t *encoding);\n#endif\n\n#if Z_FEATURE_QUERY == 1\n/**\n * Declare a :c:type:`_z_querier_t` for the given resource key.\n *\n * Parameters:\n *     querier: The querie to initialize.\n *     zn: The zenoh-net session. The caller keeps its ownership.\n *     keyexpr: The resource key to query.\n *     consolidation_mode: The kind of consolidation that should be applied on replies.\n *     congestion_control: The congestion control to apply when routing the querier queries.\n *     target: The kind of queryables that should be target of this query.\n *     priority: The priority of the query.\n *     is_express: If true, Zenoh will not wait to batch this operation with others to reduce the bandwidth.\n *     timeout_ms: The timeout value of this query.\n *     encoding: The optional default encoding to use during query. The callee gets the ownership.\n *     reliability: The reliability of the querier messages.\n *     allowed_destination: Locality restrictions for delivery.\n *     accept_replies: The accepted replies for this querier.\n * Returns:\n *    0 in case of success, negative error code otherwise.\n */\nz_result_t _z_declare_querier(_z_querier_t *querier, const _z_session_rc_t *zn, const _z_declared_keyexpr_t *keyexpr,\n                              z_consolidation_mode_t consolidation_mode, z_congestion_control_t congestion_control,\n                              z_query_target_t target, z_priority_t priority, bool is_express, uint64_t timeout_ms,\n                              _z_encoding_t *encoding, z_reliability_t reliability, z_locality_t allowed_destination,\n                              z_reply_keyexpr_t accept_replies);\n\n/**\n * Undeclare a :c:type:`_z_querier_t`.\n *\n * Parameters:\n *     querier: The :c:type:`_z_querier_t` to undeclare. The callee releases the\n *          querier upon successful return.\n * Returns:\n *    0 if success, or a negative value identifying the error.\n */\nz_result_t _z_undeclare_querier(_z_querier_t *querier);\n\n/**\n * Query data from the matching queryables in the system.\n *\n * Parameters:\n *     session: The zenoh-net session.\n *     querier_id: Optional id of querier.\n *     keyexpr: The resource key to query.\n *     parameters: An indication to matching queryables about the queried data.\n *     parameters_len: Length of the parameters string.\n *     target: The kind of queryables that should be target of this query.\n *     consolidation: The kind of consolidation that should be applied on replies.\n *     value: The payload of the query.\n *     callback: The callback function that will be called on reception of replies for this query.\n *     dropper: The callback function that will be called on upon completion of the callback.\n *     arg: A pointer that will be passed to the **callback** on each call.\n *     timeout_ms: The timeout value of this query.\n *     attachment: An optional attachment to this query.\n *     qos: QoS to apply when routing this query.\n *     source_info: Querier source info.\n *     accept_replies: The accepted replies for this query.\n *     allowed_destination: Locality restrictions for delivery.\n *     opt_cancellation_token: Optional cancellation token to cancel the query, can be null.\n *\n */\nz_result_t _z_query(const _z_session_rc_t *session, _z_optional_id_t querier_id, const _z_declared_keyexpr_t *keyexpr,\n                    const char *parameters, size_t parameters_len, z_query_target_t target,\n                    z_consolidation_mode_t consolidation, _z_bytes_t *payload, _z_encoding_t *encoding,\n                    _z_closure_reply_callback_t callback, _z_drop_handler_t dropper, void *arg, uint64_t timeout_ms,\n                    _z_bytes_t *attachment, _z_n_qos_t qos, _z_source_info_t *source_info,\n                    z_reply_keyexpr_t accept_replies, z_locality_t allowed_destination,\n                    _z_cancellation_token_rc_t *opt_cancellation_token);\n#endif\n\n#if Z_FEATURE_INTEREST == 1\nuint32_t _z_add_interest(_z_session_t *zn, const _z_declared_keyexpr_t *keyexpr, _z_interest_handler_t callback,\n                         uint8_t flags, _z_void_rc_t *arg);\nz_result_t _z_remove_interest(_z_session_t *zn, uint32_t interest_id);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_NET_PRIMITIVES_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/publish.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_NET_PUBLISH_H\n#define INCLUDE_ZENOH_PICO_NET_PUBLISH_H\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Return type when declaring a publisher.\n */\ntypedef struct _z_publisher_t {\n    _z_declared_keyexpr_t _key;\n    _z_zint_t _id;\n    _z_session_weak_t _zn;\n    _z_encoding_t _encoding;\n    z_congestion_control_t _congestion_control;\n    z_priority_t _priority;\n    z_reliability_t reliability;\n    bool _is_express;\n    z_locality_t _allowed_destination;\n    _z_write_filter_t _filter;\n} _z_publisher_t;\n\n#if Z_FEATURE_PUBLICATION == 1\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_publisher_t _z_publisher_null(void) { return (_z_publisher_t){0}; }\nstatic inline bool _z_publisher_check(const _z_publisher_t *publisher) { return !_Z_RC_IS_NULL(&publisher->_zn); }\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_NET_PUBLISH_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/query.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_QUERY_NETAPI_H\n#define ZENOH_PICO_QUERY_NETAPI_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * The query to be answered by a queryable.\n */\ntypedef struct _z_query_t {\n    _z_declared_keyexpr_t _key;\n    _z_value_t _value;\n    uint32_t _request_id;\n    _z_session_weak_t _zn;\n    _z_bytes_t _attachment;\n    _z_string_t _parameters;\n    _z_source_info_t _source_info;\n    _z_n_qos_t _qos;\n    bool _anyke;\n    bool _is_local;\n} _z_query_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_query_t _z_query_null(void) { return (_z_query_t){0}; }\nstatic inline bool _z_query_check(const _z_query_t *query) {\n    return _z_declared_keyexpr_check(&query->_key) || _z_value_check(&query->_value) ||\n           _z_bytes_check(&query->_attachment) || _z_string_check(&query->_parameters);\n}\nz_result_t _z_query_send_reply_final(_z_query_t *q);\nz_result_t _z_session_send_reply_final(_z_session_t *session, uint32_t query_id, bool is_local);\nvoid _z_query_clear(_z_query_t *q);\nvoid _z_query_free(_z_query_t **query);\n\n_Z_REFCOUNT_DEFINE(_z_query, _z_query)\n\n/**\n * Return type when declaring a querier.\n */\ntypedef struct _z_querier_t {\n    _z_declared_keyexpr_t _key;\n    uint32_t _id;\n    _z_session_weak_t _zn;\n    _z_encoding_t _encoding;\n    z_consolidation_mode_t _consolidation_mode;\n    z_query_target_t _target;\n    z_congestion_control_t _congestion_control;\n    z_priority_t _priority;\n    z_reliability_t reliability;\n    bool _is_express;\n    z_reply_keyexpr_t _accept_replies;\n    uint64_t _timeout_ms;\n    z_locality_t _allowed_destination;\n    _z_write_filter_t _filter;\n} _z_querier_t;\n\n#if Z_FEATURE_QUERY == 1\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_querier_t _z_querier_null(void) { return (_z_querier_t){0}; }\nstatic inline bool _z_querier_check(const _z_querier_t *querier) { return !_Z_RC_IS_NULL(&querier->_zn); }\n#endif\n\n/**\n * Return type when declaring a queryable.\n */\ntypedef struct {\n    uint32_t _entity_id;\n    _z_session_weak_t _zn;\n    _z_sync_group_t _callback_drop_sync_group;\n} _z_queryable_t;\n\n#if Z_FEATURE_QUERYABLE == 1\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_queryable_t _z_queryable_null(void) { return (_z_queryable_t){0}; }\nstatic inline bool _z_queryable_check(const _z_queryable_t *queryable) { return !_Z_RC_IS_NULL(&queryable->_zn); }\nstatic inline z_result_t _z_query_move_data(_z_query_t *dst, _z_value_t *value, _z_keyexpr_t *key,\n                                            _z_slice_t *parameters, const _z_session_weak_t *zn, uint32_t request_id,\n                                            _z_bytes_t *attachment, bool implicit_anyke,\n                                            const _z_source_info_t *source_info) {\n    *dst = _z_query_null();\n    dst->_anyke = implicit_anyke || _z_parameters_has_anyke((const char *)parameters->start, parameters->len);\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_move(&dst->_key._inner, key), _z_query_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_value_move(&dst->_value, value), _z_query_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_move(&dst->_attachment, attachment), _z_query_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_slice_move(&dst->_parameters._slice, parameters), _z_query_clear(dst));\n    dst->_request_id = request_id;\n    dst->_zn = _z_session_weak_clone(zn);\n    dst->_source_info = *source_info;\n    return _Z_RES_OK;\n}\nvoid _z_queryable_clear(_z_queryable_t *qbl);\nvoid _z_queryable_free(_z_queryable_t **qbl);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_QUERY_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/reply.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_REPLY_NETAPI_H\n#define ZENOH_PICO_REPLY_NETAPI_H\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Reply tag values.\n *\n * Enumerators:\n *     _Z_REPLY_TAG_DATA: Tag identifying that the reply contains some data.\n *     _Z_REPLY_TAG_FINAL: Tag identifying that the reply does not contain any data and that there will be no more\n *         replies for this query.\n *     _Z_REPLY_TAG_ERROR: Tag identifying that the reply contains error.\n *     _Z_REPLY_TAG_NONE: Tag identifying empty reply.\n */\ntypedef enum {\n    _Z_REPLY_TAG_DATA = 0,\n    _Z_REPLY_TAG_FINAL = 1,\n    _Z_REPLY_TAG_ERROR = 2,\n    _Z_REPLY_TAG_NONE = 3\n} _z_reply_tag_t;\n\n/**\n * An reply to a :c:func:`z_query`.\n *\n * Members:\n *   _z_sample_t data: a :c:type:`_z_sample_t` containing the key and value of the reply.\n *   _z_slice_t replier_id: The id of the entity that sent this reply.\n *\n */\ntypedef struct _z_reply_data_t {\n    union {\n        _z_value_t error;\n        _z_sample_t sample;\n    } _result;\n    _z_entity_global_id_t replier_id;\n    _z_reply_tag_t _tag;\n} _z_reply_data_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_reply_data_t _z_reply_data_null(void) { return (_z_reply_data_t){0}; }\nvoid _z_reply_data_clear(_z_reply_data_t *rd);\nz_result_t _z_reply_data_copy(_z_reply_data_t *dst, const _z_reply_data_t *src);\n\n/**\n * An reply to a :c:func:`z_query`.\n *\n * Members:\n *   _z_reply_t_Tag tag: Indicates if the reply contains data or if it's a FINAL reply.\n *   _z_reply_data_t data: The reply data if :c:member:`_z_reply_t.tag` equals\n * :c:member:`_z_reply_t_Tag._Z_REPLY_TAG_DATA`.\n *\n */\ntypedef struct _z_reply_t {\n    _z_reply_data_t data;\n} _z_reply_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_reply_t _z_reply_null(void) { return (_z_reply_t){0}; }\nvoid _z_reply_steal_data(_z_reply_t *dst, _z_keyexpr_t *keyexpr, _z_entity_global_id_t replier_id, _z_bytes_t *payload,\n                         const _z_timestamp_t *timestamp, _z_encoding_t *encoding, z_sample_kind_t kind,\n                         _z_bytes_t *attachment, _z_source_info_t *source_info);\nvoid _z_reply_err_steal_data(_z_reply_t *dst, _z_bytes_t *payload, _z_encoding_t *encoding,\n                             _z_entity_global_id_t replier_id);\nz_result_t _z_reply_move(_z_reply_t *dst, _z_reply_t *src);\nvoid _z_reply_clear(_z_reply_t *src);\nvoid _z_reply_free(_z_reply_t **hello);\nz_result_t _z_reply_copy(_z_reply_t *dst, const _z_reply_t *src);\n\ntypedef struct _z_pending_reply_t {\n    _z_reply_t _reply;\n    _z_timestamp_t _tstamp;\n} _z_pending_reply_t;\n\nbool _z_pending_reply_eq(const _z_pending_reply_t *one, const _z_pending_reply_t *two);\nvoid _z_pending_reply_clear(_z_pending_reply_t *res);\n\n_Z_ELEM_DEFINE(_z_pending_reply, _z_pending_reply_t, _z_noop_size, _z_pending_reply_clear, _z_noop_copy, _z_noop_move,\n               _z_pending_reply_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_pending_reply, _z_pending_reply_t, false)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_REPLY_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/sample.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_SAMPLE_NETAPI_H\n#define ZENOH_PICO_SAMPLE_NETAPI_H\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/ring.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * A zenoh-net data sample.\n *\n * A sample is the value associated to a given resource at a given point in time.\n *\n * Members:\n *   _z_keyexpr_t key: The resource key of this data sample.\n *   _z_slice_t value: The value of this data sample.\n *   _z_encoding_t encoding: The encoding for the value of this data sample.\n *   _z_source_info_t source_info: The source info for this data sample (unstable).\n */\ntypedef struct _z_sample_t {\n    _z_declared_keyexpr_t keyexpr;\n    _z_bytes_t payload;\n    _z_timestamp_t timestamp;\n    _z_encoding_t encoding;\n    z_sample_kind_t kind;\n    _z_qos_t qos;\n    _z_bytes_t attachment;\n    z_reliability_t reliability;\n    _z_source_info_t source_info;\n} _z_sample_t;\nvoid _z_sample_clear(_z_sample_t *sample);\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_sample_t _z_sample_null(void) { return (_z_sample_t){0}; }\nstatic inline bool _z_sample_check(const _z_sample_t *sample) {\n    return _z_declared_keyexpr_check(&sample->keyexpr) || _z_encoding_check(&sample->encoding) ||\n           _z_bytes_check(&sample->payload) || _z_bytes_check(&sample->attachment);\n}\nstatic inline size_t _z_sample_size(const _z_sample_t *s) {\n    (void)(s);\n    return sizeof(_z_sample_t);\n}\n\nvoid _z_sample_steal_data(_z_sample_t *dst, _z_keyexpr_t *key, _z_bytes_t *payload, const _z_timestamp_t *timestamp,\n                          _z_encoding_t *encoding, z_sample_kind_t kind, _z_qos_t qos, _z_bytes_t *attachment,\n                          z_reliability_t reliability, _z_source_info_t *source_info);\nz_result_t _z_sample_copy_data(_z_sample_t *dst, const _z_declared_keyexpr_t *key, const _z_bytes_t *payload,\n                               const _z_timestamp_t *timestamp, const _z_encoding_t *encoding, z_sample_kind_t kind,\n                               _z_qos_t qos, const _z_bytes_t *attachment, z_reliability_t reliability,\n                               const _z_source_info_t *source_info);\nz_result_t _z_sample_move(_z_sample_t *dst, _z_sample_t *src);\n\n/**\n * Free a :c:type:`_z_sample_t`, including its internal fields.\n *\n * Parameters:\n *     sample: The :c:type:`_z_sample_t` to free.\n */\nvoid _z_sample_free(_z_sample_t **sample);\n\nz_result_t _z_sample_copy(_z_sample_t *dst, const _z_sample_t *src);\n_z_sample_t _z_sample_duplicate(const _z_sample_t *src);\n\n_Z_ELEM_DEFINE(_z_sample, _z_sample_t, _z_sample_size, _z_sample_clear, _z_sample_copy, _z_sample_move, _z_noop_eq,\n               _z_noop_cmp, _z_noop_hash)\n_Z_RING_DEFINE(_z_sample, _z_sample_t)\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* ZENOH_PICO_SAMPLE_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/session.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#ifndef INCLUDE_ZENOH_PICO_NET_SESSION_H\n#define INCLUDE_ZENOH_PICO_NET_SESSION_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/atomic.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/matching.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/utils/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * A zenoh-net session.\n */\nstruct _z_write_filter_registration_t;\n\n#if Z_FEATURE_CONNECTIVITY == 1\ntypedef struct {\n    _z_void_rc_t _callback;\n} _z_connectivity_transport_listener_t;\n\nstatic inline size_t _z_connectivity_transport_listener_size(const _z_connectivity_transport_listener_t *listener) {\n    _ZP_UNUSED(listener);\n    return sizeof(_z_connectivity_transport_listener_t);\n}\n\nstatic inline void _z_connectivity_transport_listener_clear(_z_connectivity_transport_listener_t *listener) {\n    _z_void_rc_drop(&listener->_callback);\n    listener->_callback = _z_void_rc_null();\n}\n\nstatic inline void _z_connectivity_transport_listener_copy(_z_connectivity_transport_listener_t *dst,\n                                                           const _z_connectivity_transport_listener_t *src) {\n    dst->_callback = _z_void_rc_clone(&src->_callback);\n}\n\nstatic inline void _z_connectivity_transport_listener_move(_z_connectivity_transport_listener_t *dst,\n                                                           _z_connectivity_transport_listener_t *src) {\n    dst->_callback = src->_callback;\n    src->_callback = _z_void_rc_null();\n}\n\n_Z_ELEM_DEFINE(_z_connectivity_transport_listener, _z_connectivity_transport_listener_t,\n               _z_connectivity_transport_listener_size, _z_connectivity_transport_listener_clear,\n               _z_connectivity_transport_listener_copy, _z_connectivity_transport_listener_move, _z_noop_eq,\n               _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_connectivity_transport_listener, _z_connectivity_transport_listener_t)\n\ntypedef struct {\n    _z_void_rc_t _callback;\n    bool _has_transport_filter;\n    _z_id_t _transport_zid;\n    bool _transport_is_multicast;\n} _z_connectivity_link_listener_t;\n\nstatic inline size_t _z_connectivity_link_listener_size(const _z_connectivity_link_listener_t *listener) {\n    _ZP_UNUSED(listener);\n    return sizeof(_z_connectivity_link_listener_t);\n}\n\nstatic inline void _z_connectivity_link_listener_clear(_z_connectivity_link_listener_t *listener) {\n    _z_void_rc_drop(&listener->_callback);\n    listener->_callback = _z_void_rc_null();\n    listener->_has_transport_filter = false;\n    listener->_transport_zid = (_z_id_t){0};\n    listener->_transport_is_multicast = false;\n}\n\nstatic inline void _z_connectivity_link_listener_copy(_z_connectivity_link_listener_t *dst,\n                                                      const _z_connectivity_link_listener_t *src) {\n    dst->_callback = _z_void_rc_clone(&src->_callback);\n    dst->_has_transport_filter = src->_has_transport_filter;\n    dst->_transport_zid = src->_transport_zid;\n    dst->_transport_is_multicast = src->_transport_is_multicast;\n}\n\nstatic inline void _z_connectivity_link_listener_move(_z_connectivity_link_listener_t *dst,\n                                                      _z_connectivity_link_listener_t *src) {\n    dst->_callback = src->_callback;\n    dst->_has_transport_filter = src->_has_transport_filter;\n    dst->_transport_zid = src->_transport_zid;\n    dst->_transport_is_multicast = src->_transport_is_multicast;\n    src->_callback = _z_void_rc_null();\n    src->_has_transport_filter = false;\n    src->_transport_zid = (_z_id_t){0};\n    src->_transport_is_multicast = false;\n}\n\n_Z_ELEM_DEFINE(_z_connectivity_link_listener, _z_connectivity_link_listener_t, _z_connectivity_link_listener_size,\n               _z_connectivity_link_listener_clear, _z_connectivity_link_listener_copy,\n               _z_connectivity_link_listener_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_connectivity_link_listener, _z_connectivity_link_listener_t)\n#endif\n\ntypedef struct _z_session_t {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t _mutex_inner;\n    _z_mutex_rec_t _mutex_transport;\n#if Z_FEATURE_ADMIN_SPACE == 1\n    _z_mutex_t _mutex_admin_space;\n#endif\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    // Zenoh-pico is considering a single transport per session.\n    z_whatami_t _mode;\n    _z_transport_t _tp;\n\n    // Zenoh PID\n    _z_id_t _local_zid;\n\n    // Session counters\n    uint16_t _resource_id;\n    uint32_t _entity_id;\n    _z_zint_t _query_id;\n    _z_zint_t _interest_id;\n\n    // Session declarations\n    _z_resource_slist_t *_local_resources;\n\n    // Information for session restoring and asynchronous peer connection\n    _z_config_t _config;\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    _z_network_message_slist_t *_declaration_cache;\n#endif\n\n    // Session subscriptions\n#if Z_FEATURE_SUBSCRIPTION == 1\n    _z_subscription_rc_slist_t *_subscriptions;\n    _z_subscription_rc_slist_t *_liveliness_subscriptions;\n#if Z_FEATURE_RX_CACHE == 1\n    _z_subscription_lru_cache_t _subscription_cache;\n#endif\n#endif\n\n#if Z_FEATURE_LIVELINESS == 1\n    _z_declared_keyexpr_intmap_t _local_tokens;\n    _z_keyexpr_intmap_t _remote_tokens;\n#if Z_FEATURE_QUERY == 1\n    uint32_t _liveliness_query_id;\n    _z_liveliness_pending_query_intmap_t _liveliness_pending_queries;\n#endif\n#endif\n\n    // Session queryables\n#if Z_FEATURE_QUERYABLE == 1\n    _z_session_queryable_rc_slist_t *_local_queryable;\n#if Z_FEATURE_RX_CACHE == 1\n    _z_queryable_lru_cache_t _queryable_cache;\n#endif\n#endif\n#if Z_FEATURE_QUERY == 1\n    _z_pending_query_slist_t *_pending_queries;\n#endif\n\n    // Session interests\n#if Z_FEATURE_INTEREST == 1\n    _z_session_interest_rc_slist_t *_local_interests;\n    _z_declare_data_slist_t *_remote_declares;\n    struct _z_write_filter_registration_t *_write_filters;\n#endif\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n    // entity Id for admin space queryable (0 if not started)\n    uint32_t _admin_space_queryable_id;\n#if Z_FEATURE_CONNECTIVITY == 1\n    // entity Id for session connectivity queryable (0 if not started)\n    uint32_t _admin_space_session_queryable_id;\n#if Z_FEATURE_PUBLICATION == 1\n    // listener ids for admin-space connectivity event bridge (0 if not started)\n    size_t _admin_space_transport_listener_id;\n    size_t _admin_space_link_listener_id;\n#endif\n#endif\n#endif\n#if Z_FEATURE_CONNECTIVITY == 1\n    size_t _connectivity_next_listener_id;\n    _z_connectivity_transport_listener_intmap_t _connectivity_transport_event_listeners;\n    _z_connectivity_link_listener_intmap_t _connectivity_link_event_listeners;\n#endif\n    _z_sync_group_t _callback_drop_sync_group;\n    _z_atomic_bool_t _is_closed;\n    _z_runtime_t _runtime;\n} _z_session_t;\n\n/**\n * Open a zenoh-net session\n *\n * Parameters:\n *     zn: A pointer of A :c:type:`_z_session_t` used as a return value.\n *     config: A set of properties. The caller keeps its ownership.\n *     zid: A pointer to Zenoh ID.\n *\n * Returns:\n *     ``0`` in case of success, or a ``negative value`` in case of failure.\n */\nz_result_t _z_open(_z_session_rc_t *zn, _z_config_t *config, const _z_id_t *zid);\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\nvoid _z_client_reopen_task_drop(void *ztc_arg);\n_z_fut_fn_result_t _z_client_reopen_task_fn(void *ztc_arg, _z_executor_t *executor);\n#endif\n\n/**\n * Store declaration network message to cache for resend it after session restore\n *\n * Parameters:\n *     zs: A zenoh-net session.\n *     z_msg: Network message with declaration\n */\nvoid _z_cache_declaration(_z_session_t *zs, const _z_network_message_t *n_msg);\n\n/**\n * Remove corresponding declaration from the cache\n *\n * Parameters:\n *     zs: A zenoh-net session.\n *     z_msg: Network message with undeclaration\n */\nvoid _z_prune_declaration(_z_session_t *zs, const _z_network_message_t *n_msg);\n\n/**\n * Return true is session and all associated transports were closed.\n */\nbool _z_session_is_closed(const _z_session_t *session);\n\n/**\n * Return true if session is connected to at least one router peer.\n */\nbool _z_session_has_router_peer(const _z_session_t *session);\n\n/**\n * Upgrade a weak session reference to a strong one if the session is open, otherwise return null.\n */\n_z_session_rc_t _z_session_weak_upgrade_if_open(const _z_session_weak_t *weak);\n/**\n * Get informations about an zenoh-net session.\n *\n * Parameters:\n *     session: A zenoh-net session. The caller keeps its ownership.\n *\n * Returns:\n *     A :c:type:`_z_config_t` map containing informations on the given zenoh-net session.\n */\n_z_config_t *_z_info(const _z_session_t *session);\n\n/*------------------ Zenoh-Pico Session Management Auxiliary ------------------*/\n/**\n * Read from the network. This function should be called manually called when\n * the read loop has not been started, e.g., when running in a single thread.\n *\n * Parameters:\n *     session: The zenoh-net session. The caller keeps its ownership.\n *     single_read: Read a single packet from the buffer instead of the whole buffer\n * Returns:\n *     ``0`` in case of success, ``-1`` in case of failure.\n */\nz_result_t _zp_read(_z_session_t *z, bool single_read);\n\n/**\n * Send a KeepAlive message.\n *\n * Parameters:\n *     session: The zenoh-net session. The caller keeps its ownership.\n * Returns:\n *     ``0`` in case of success, ``-1`` in case of failure.\n */\nz_result_t _zp_send_keep_alive(_z_session_t *z);\n\n/**\n * Send a Join message.\n *\n * Parameters:\n *     session: The zenoh-net session. The caller keeps its ownership.\n * Returns:\n *     ``0`` in case of success, ``-1`` in case of failure.\n */\nz_result_t _zp_send_join(_z_session_t *z);\n\nz_result_t _zp_start_transport_tasks(_z_session_t *z);\n#if Z_FEATURE_CONNECTIVITY == 1\nvoid _z_connectivity_peer_connected(_z_session_t *session, const _z_connectivity_peer_event_data_t *peer,\n                                    bool is_multicast, uint16_t mtu, bool is_streamed, bool is_reliable);\nvoid _z_connectivity_peer_disconnected(_z_session_t *session, const _z_connectivity_peer_event_data_t *peer,\n                                       bool is_multicast, uint16_t mtu, bool is_streamed, bool is_reliable);\nvoid _z_connectivity_peer_disconnected_from_transport(_z_session_t *session, const _z_transport_common_t *transport,\n                                                      const _z_connectivity_peer_event_data_t *peer, bool is_multicast);\n#endif\n\nstatic inline _z_session_t *_z_transport_common_get_session(_z_transport_common_t *transport) {\n    // the session should always outlive the transport, so it should be safe\n    // to access pointer directly without upgrade\n    return _z_session_weak_as_unsafe_ptr(&transport->_session);\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_NET_SESSION_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/subscribe.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SUBSCRIBE_NETAPI_H\n#define ZENOH_PICO_SUBSCRIBE_NETAPI_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Return type when declaring a subscriber.\n */\ntypedef struct {\n    uint32_t _entity_id;\n    _z_session_weak_t _zn;\n    _z_sync_group_t _callback_drop_sync_group;\n} _z_subscriber_t;\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_subscriber_t _z_subscriber_null(void) { return (_z_subscriber_t){0}; }\nstatic inline bool _z_subscriber_check(const _z_subscriber_t *subscriber) { return !_Z_RC_IS_NULL(&subscriber->_zn); }\nvoid _z_subscriber_clear(_z_subscriber_t *sub);\nvoid _z_subscriber_free(_z_subscriber_t **sub);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SUBSCRIBE_NETAPI_H */\n"
  },
  {
    "path": "include/zenoh-pico/net/zenoh-pico.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef ZENOH_PICO_NET_H\n#define ZENOH_PICO_NET_H\n\n#include \"zenoh-pico/net/config.h\"\n#include \"zenoh-pico/net/logger.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/net/publish.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/net/subscribe.h\"\n\n#if defined(ZENOH_ZEPHYR)\n#include <kernel.h>\n#endif\n\n#endif /* ZENOH_PICO_NET_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/core.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_CORE_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_CORE_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef z_result_t (*__z_single_byte_reader_t)(uint8_t *, void *context);\n/*------------------ Internal Zenoh-net Macros ------------------*/\nz_result_t _z_consolidation_mode_encode(_z_wbuf_t *wbf, z_consolidation_mode_t en);\nz_result_t _z_consolidation_mode_decode(z_consolidation_mode_t *en, _z_zbuf_t *zbf);\nz_result_t _z_query_target_encode(_z_wbuf_t *wbf, z_query_target_t en);\nz_result_t _z_query_target_decode(z_query_target_t *en, _z_zbuf_t *zbf);\nz_result_t _z_whatami_encode(_z_wbuf_t *wbf, z_whatami_t en);\nz_result_t _z_whatami_decode(z_whatami_t *en, _z_zbuf_t *zbf);\n\nuint8_t _z_whatami_to_uint8(z_whatami_t whatami);\nz_whatami_t _z_whatami_from_uint8(uint8_t b);\n\nz_result_t _z_uint8_encode(_z_wbuf_t *buf, uint8_t v);\nz_result_t _z_uint8_decode(uint8_t *u8, _z_zbuf_t *buf);\nz_result_t _z_uint8_decode_as_ref(uint8_t **u8, _z_zbuf_t *zbf);\n\nz_result_t _z_uint16_encode(_z_wbuf_t *buf, uint16_t v);\nz_result_t _z_uint16_decode(uint16_t *u16, _z_zbuf_t *buf);\n\nuint8_t _z_zint_len(uint64_t v);\nuint8_t _z_zint64_encode_buf(uint8_t *buf, uint64_t v);\nstatic inline uint8_t _z_zsize_encode_buf(uint8_t *buf, _z_zint_t v) { return _z_zint64_encode_buf(buf, (uint64_t)v); }\n\nz_result_t _z_zint64_encode(_z_wbuf_t *buf, uint64_t v);\nstatic inline z_result_t _z_zint16_encode(_z_wbuf_t *wbf, uint16_t v) { return _z_zint64_encode(wbf, (uint64_t)v); }\nstatic inline z_result_t _z_zint32_encode(_z_wbuf_t *wbf, uint32_t v) { return _z_zint64_encode(wbf, (uint64_t)v); }\nstatic inline z_result_t _z_zsize_encode(_z_wbuf_t *wbf, _z_zint_t v) { return _z_zint64_encode(wbf, (uint64_t)v); }\n\nz_result_t _z_zint16_decode(uint16_t *zint, _z_zbuf_t *buf);\nz_result_t _z_zint32_decode(uint32_t *zint, _z_zbuf_t *buf);\nz_result_t _z_zint64_decode(uint64_t *zint, _z_zbuf_t *buf);\nz_result_t _z_zint64_decode_with_reader(uint64_t *zint, __z_single_byte_reader_t reader, void *context);\nz_result_t _z_zsize_decode_with_reader(_z_zint_t *zint, __z_single_byte_reader_t reader, void *context);\nz_result_t _z_zsize_decode(_z_zint_t *zint, _z_zbuf_t *buf);\n\nz_result_t _z_buf_encode(_z_wbuf_t *wbf, const uint8_t *buf, size_t len);\nstatic inline z_result_t _z_slice_val_encode(_z_wbuf_t *wbf, const _z_slice_t *bs) {\n    return _z_buf_encode(wbf, bs->start, bs->len);\n}\nstatic inline z_result_t _z_slice_val_decode_na(_z_slice_t *bs, _z_zbuf_t *zbf) {\n    // Check if we have enough bytes to read\n    if (_z_zbuf_len(zbf) < bs->len) {\n        _Z_WARN(\"Not enough bytes to read\");\n        bs->len = 0;\n        bs->start = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *bs = _z_slice_alias_buf(_z_zbuf_get_rptr(zbf), bs->len);  // Decode without allocating\n    _z_zbuf_set_rpos(zbf, _z_zbuf_get_rpos(zbf) + bs->len);    // Move the read position\n    return _Z_RES_OK;\n}\nstatic inline z_result_t _z_slice_decode_na(_z_slice_t *bs, _z_zbuf_t *zbf) {\n    _Z_RETURN_IF_ERR(_z_zsize_decode(&bs->len, zbf));\n    return _z_slice_val_decode_na(bs, zbf);\n}\nstatic inline z_result_t _z_slice_val_decode(_z_slice_t *bs, _z_zbuf_t *zbf) { return _z_slice_val_decode_na(bs, zbf); }\nstatic inline z_result_t _z_slice_decode(_z_slice_t *bs, _z_zbuf_t *zbf) { return _z_slice_decode_na(bs, zbf); }\nz_result_t _z_slice_encode(_z_wbuf_t *buf, const _z_slice_t *bs);\nz_result_t _z_slices_encode(_z_wbuf_t *wbf, const _z_slice_t *bs, size_t num_slices);\n\nz_result_t _z_bytes_decode(_z_bytes_t *bs, _z_zbuf_t *zbf, _z_arc_slice_t *arcs);\nz_result_t _z_bytes_encode(_z_wbuf_t *wbf, const _z_bytes_t *bs);\nz_result_t _z_zbuf_read_exact(_z_zbuf_t *zbf, uint8_t *dest, size_t length);\n\nz_result_t _z_str_encode(_z_wbuf_t *buf, const char *s);\nz_result_t _z_str_decode(char **str, _z_zbuf_t *buf);\nz_result_t _z_string_encode(_z_wbuf_t *wbf, const _z_string_t *s);\nz_result_t _z_string_decode(_z_string_t *str, _z_zbuf_t *zbf);\n\nsize_t _z_encoding_len(const _z_encoding_t *en);\nz_result_t _z_encoding_encode(_z_wbuf_t *wbf, const _z_encoding_t *en);\nz_result_t _z_encoding_decode(_z_encoding_t *en, _z_zbuf_t *zbf);\n\nz_result_t _z_value_encode(_z_wbuf_t *wbf, const _z_value_t *en);\nz_result_t _z_value_decode(_z_value_t *en, _z_zbuf_t *zbf);\n\nz_result_t _z_wireexpr_encode(_z_wbuf_t *buf, bool has_suffix, const _z_wireexpr_t *ke);\nz_result_t _z_wireexpr_decode(_z_wireexpr_t *ke, _z_zbuf_t *buf, bool has_suffix, bool remote_mapping,\n                              uintptr_t mapping);\n\nz_result_t _z_timestamp_encode(_z_wbuf_t *buf, const _z_timestamp_t *ts);\nz_result_t _z_timestamp_encode_ext(_z_wbuf_t *buf, const _z_timestamp_t *ts);\nz_result_t _z_timestamp_decode(_z_timestamp_t *ts, _z_zbuf_t *buf);\n\nz_result_t _z_source_info_encode(_z_wbuf_t *wbf, const _z_source_info_t *info);\nz_result_t _z_source_info_encode_ext(_z_wbuf_t *wbf, const _z_source_info_t *info);\nz_result_t _z_source_info_decode(_z_source_info_t *info, _z_zbuf_t *zbf);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_CORE_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/declarations.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_DECLARATIONS_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_DECLARATIONS_H\n\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_DECL_KEXPR_MID 0\n#define _Z_DECL_KEXPR_FLAG_N 0x20\n#define _Z_UNDECL_KEXPR_MID 1\n#define _Z_DECL_SUBSCRIBER_MID 2\n#define _Z_DECL_SUBSCRIBER_FLAG_N 0x20\n#define _Z_DECL_SUBSCRIBER_FLAG_M 0x40\n#define _Z_UNDECL_SUBSCRIBER_MID 3\n#define _Z_DECL_QUERYABLE_MID 4\n#define _Z_UNDECL_QUERYABLE_MID 5\n#define _Z_DECL_TOKEN_MID 6\n#define _Z_UNDECL_TOKEN_MID 7\n#define _Z_DECL_FINAL_MID 0x1a\n\nz_result_t _z_decl_kexpr_encode(_z_wbuf_t *wbf, const _z_decl_kexpr_t *decl);\nz_result_t _z_decl_kexpr_decode(_z_decl_kexpr_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_undecl_kexpr_encode(_z_wbuf_t *wbf, const _z_undecl_kexpr_t *decl);\nz_result_t _z_undecl_kexpr_decode(_z_undecl_kexpr_t *decl, _z_zbuf_t *zbf, uint8_t header);\nz_result_t _z_decl_subscriber_encode(_z_wbuf_t *wbf, const _z_decl_subscriber_t *decl);\nz_result_t _z_decl_subscriber_decode(_z_decl_subscriber_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_undecl_subscriber_encode(_z_wbuf_t *wbf, const _z_undecl_subscriber_t *decl);\nz_result_t _z_undecl_subscriber_decode(_z_undecl_subscriber_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_decl_queryable_encode(_z_wbuf_t *wbf, const _z_decl_queryable_t *decl);\nz_result_t _z_decl_queryable_decode(_z_decl_queryable_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_undecl_queryable_encode(_z_wbuf_t *wbf, const _z_undecl_queryable_t *decl);\nz_result_t _z_undecl_queryable_decode(_z_undecl_queryable_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_decl_token_encode(_z_wbuf_t *wbf, const _z_decl_token_t *decl);\nz_result_t _z_decl_token_decode(_z_decl_token_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_undecl_token_encode(_z_wbuf_t *wbf, const _z_undecl_token_t *decl);\nz_result_t _z_undecl_token_decode(_z_undecl_token_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\n\nz_result_t _z_declaration_encode(_z_wbuf_t *wbf, const _z_declaration_t *decl);\nz_result_t _z_declaration_decode(_z_declaration_t *decl, _z_zbuf_t *zbf, uintptr_t mapping);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_DECLARATIONS_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/ext.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_EXTCODEC_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_EXTCODEC_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Message Extension ------------------*/\nz_result_t _z_msg_ext_encode(_z_wbuf_t *wbf, const _z_msg_ext_t *ext, bool has_next);\nz_result_t _z_msg_ext_decode(_z_msg_ext_t *ext, _z_zbuf_t *zbf, bool *has_next);\nz_result_t _z_msg_ext_decode_na(_z_msg_ext_t *ext, _z_zbuf_t *zbf, bool *has_next);\nz_result_t _z_msg_ext_vec_encode(_z_wbuf_t *wbf, const _z_msg_ext_vec_t *extensions);\nz_result_t _z_msg_ext_vec_decode(_z_msg_ext_vec_t *extensions, _z_zbuf_t *zbf);\n/**\n * Iterates through the extensions in `zbf`, assuming at least one is present at its beginning\n * (calling this function otherwise is UB). Short-circuits if `callback` returns a non-zero value.\n *\n * `callback` will receive `context` as its second argument, and may \"steal\" its first argument by\n * copying its value and setting it to `_z_msg_ext_make_unit(0)`.\n */\nz_result_t _z_msg_ext_decode_iter(_z_zbuf_t *zbf, z_result_t (*callback)(_z_msg_ext_t *, void *), void *context);\n/**\n * Iterates through the extensions in `zbf`, assuming at least one is present at its beginning.\n * Returns `_Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN` if a mandatory extension is found,\n * `_Z_RES_OK` otherwise.\n */\nz_result_t _z_msg_ext_skip_non_mandatories(_z_zbuf_t *zbf, uint8_t trace_id);\n/**\n * Logs an error to debug the unknown extension, returning `_Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN`.\n *\n * `trace_id` may be any arbitrary value, but is advised to be unique to its call-site,\n * to help debugging should it be necessary.\n */\nz_result_t _z_msg_ext_unknown_error(_z_msg_ext_t *extension, uint8_t trace_id);\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_EXTCODEC_H */\n\n// NOTE: the following headers are for unit testing only\n#ifdef ZENOH_PICO_TEST_H\n// ------------------ Message Fields ------------------\nz_result_t _z_msg_ext_encode_unit(_z_wbuf_t *wbf, const _z_msg_ext_unit_t *pld);\nz_result_t _z_msg_ext_decode_unit(_z_msg_ext_unit_t *pld, _z_zbuf_t *zbf);\nz_result_t _z_msg_ext_decode_unit_na(_z_msg_ext_unit_t *pld, _z_zbuf_t *zbf);\n\nz_result_t _z_msg_ext_encode_zint(_z_wbuf_t *wbf, const _z_msg_ext_zint_t *pld);\nz_result_t _z_msg_ext_decode_zint(_z_msg_ext_zint_t *pld, _z_zbuf_t *zbf);\nz_result_t _z_msg_ext_decode_zint_na(_z_msg_ext_zint_t *pld, _z_zbuf_t *zbf);\n\nz_result_t _z_msg_ext_encode_zbuf(_z_wbuf_t *wbf, const _z_msg_ext_zbuf_t *pld);\nz_result_t _z_msg_ext_decode_zbuf(_z_msg_ext_zbuf_t *pld, _z_zbuf_t *zbf);\nz_result_t _z_msg_ext_decode_zbuf_na(_z_msg_ext_zbuf_t *pld, _z_zbuf_t *zbf);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TEST_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/interest.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_INTEREST_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_INTEREST_H\n\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_interest_encode(_z_wbuf_t *wbf, const _z_interest_t *interest, bool is_final);\nz_result_t _z_interest_decode(_z_interest_t *decl, _z_zbuf_t *zbf, bool is_final, bool has_ext, uintptr_t mapping);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_DECLARATIONS_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/message.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_MESSAGE_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_MESSAGE_H\n\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_push_body_encode(_z_wbuf_t *wbf, const _z_push_body_t *pshb);\nz_result_t _z_push_body_decode(_z_push_body_t *body, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs);\n\nz_result_t _z_query_encode(_z_wbuf_t *wbf, const _z_msg_query_t *query);\nz_result_t _z_query_decode(_z_msg_query_t *query, _z_zbuf_t *zbf, uint8_t header);\nz_result_t _z_reply_encode(_z_wbuf_t *wbf, const _z_msg_reply_t *reply);\nz_result_t _z_reply_decode(_z_msg_reply_t *reply, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs);\n\nz_result_t _z_err_encode(_z_wbuf_t *wbf, const _z_msg_err_t *err);\nz_result_t _z_err_decode(_z_msg_err_t *err, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs);\n\nz_result_t _z_put_encode(_z_wbuf_t *wbf, const _z_msg_put_t *put);\nz_result_t _z_put_decode(_z_msg_put_t *put, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs);\n\nz_result_t _z_del_encode(_z_wbuf_t *wbf, const _z_msg_del_t *del);\nz_result_t _z_del_decode(_z_msg_del_t *del, _z_zbuf_t *zbf, uint8_t header);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_MESSAGE_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/network.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_NETWORK_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_NETWORK_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_push_encode(_z_wbuf_t *wbf, const _z_n_msg_push_t *msg);\nz_result_t _z_push_decode(_z_n_msg_push_t *msg, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs,\n                          uintptr_t mapping);\nz_result_t _z_request_encode(_z_wbuf_t *wbf, const _z_n_msg_request_t *msg);\nz_result_t _z_request_decode(_z_n_msg_request_t *msg, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs,\n                             uintptr_t mapping);\nz_result_t _z_response_encode(_z_wbuf_t *wbf, const _z_n_msg_response_t *msg);\nz_result_t _z_response_decode(_z_n_msg_response_t *msg, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs,\n                              uintptr_t mapping);\nz_result_t _z_response_final_encode(_z_wbuf_t *wbf, const _z_n_msg_response_final_t *msg);\nz_result_t _z_response_final_decode(_z_n_msg_response_final_t *msg, _z_zbuf_t *zbf, uint8_t header);\nz_result_t _z_declare_encode(_z_wbuf_t *wbf, const _z_n_msg_declare_t *decl);\nz_result_t _z_declare_decode(_z_n_msg_declare_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_n_interest_encode(_z_wbuf_t *wbf, const _z_n_msg_interest_t *interest);\nz_result_t _z_n_interest_decode(_z_n_msg_interest_t *interest, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping);\nz_result_t _z_oam_encode(_z_wbuf_t *wbf, const _z_n_msg_oam_t *oam);\nz_result_t _z_oam_decode(_z_n_msg_oam_t *oam, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_network_message_encode(_z_wbuf_t *wbf, const _z_network_message_t *msg);\nz_result_t _z_network_message_decode(_z_network_message_t *msg, _z_zbuf_t *zbf, _z_arc_slice_t *arcs,\n                                     uintptr_t mapping);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_NETWORK_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/serial.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_SERIAL_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_SERIAL_H\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nsize_t _z_serial_msg_serialize(uint8_t *dest, size_t dest_len, const uint8_t *src, size_t src_len, uint8_t header,\n                               uint8_t *tmp_buf, size_t tmp_buf_len);\nsize_t _z_serial_msg_deserialize(const uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len, uint8_t *header,\n                                 uint8_t *tmp_buf, size_t tmp_buf_len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_SERIAL_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec/transport.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_TRANSPORT_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_TRANSPORT_H\n\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_scouting_message_encode(_z_wbuf_t *buf, const _z_scouting_message_t *msg);\nz_result_t _z_scouting_message_decode(_z_scouting_message_t *msg, _z_zbuf_t *buf);\n\nz_result_t _z_transport_message_encode(_z_wbuf_t *buf, const _z_transport_message_t *msg);\nz_result_t _z_transport_message_decode(_z_transport_message_t *msg, _z_zbuf_t *buf);\n\nz_result_t _z_join_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_join_t *msg);\nz_result_t _z_join_decode(_z_t_msg_join_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_init_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_init_t *msg);\nz_result_t _z_init_decode(_z_t_msg_init_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_open_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_open_t *msg);\nz_result_t _z_open_decode(_z_t_msg_open_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_close_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_close_t *msg);\nz_result_t _z_close_decode(_z_t_msg_close_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_keep_alive_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_keep_alive_t *msg);\nz_result_t _z_keep_alive_decode(_z_t_msg_keep_alive_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_frame_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_frame_t *msg);\nz_result_t _z_frame_decode(_z_t_msg_frame_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\nz_result_t _z_fragment_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_fragment_t *msg);\nz_result_t _z_fragment_decode(_z_t_msg_fragment_t *msg, _z_zbuf_t *zbf, uint8_t header);\n\n#if defined(Z_TEST_HOOKS)\ntypedef z_result_t (*_z_transport_message_encode_override_fn)(_z_wbuf_t *wbf, const _z_transport_message_t *msg,\n                                                              bool *handled);\nvoid _z_transport_set_message_encode_override(_z_transport_message_encode_override_fn fn);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_TRANSPORT_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/codec.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_H\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/message.h\"\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CODEC_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/core.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_CORE_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_CORE_H\n\n#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_OPTIONAL\n#define _Z_MOVE(x) x *\n\n/**\n * The reserved resource ID indicating a string-only resource key.\n */\n#define Z_RESOURCE_ID_NONE 0\n\n/**\n * Priority values.\n */\n#define Z_PRIORITIES_NUM 8\n\n/**\n * A variable-length encoding unsigned integer.\n */\ntypedef size_t _z_zint_t;\n\n/**\n * A zenoh ID.\n */\n\n#define ZENOH_ID_SIZE 16\ntypedef struct {\n    uint8_t id[ZENOH_ID_SIZE];\n} _z_id_t;\nextern const _z_id_t empty_id;\nuint8_t _z_id_len(_z_id_t id);\nstatic inline bool _z_id_check(_z_id_t id) { return memcmp(&id, &empty_id, sizeof(id)) != 0; }\nstatic inline size_t _z_id_size(_z_id_t *id) {\n    _ZP_UNUSED(id);\n    return sizeof(_z_id_t);\n}\nstatic inline void _z_id_copy(_z_id_t *dst, const _z_id_t *src) {\n    size_t offset = 0;\n    (void)_z_memcpy_checked(dst, sizeof(_z_id_t), &offset, src, sizeof(_z_id_t));\n}\nstatic inline bool _z_id_eq(const _z_id_t *left, const _z_id_t *right) {\n    return memcmp(left->id, right->id, ZENOH_ID_SIZE) == 0;\n}\nint _z_id_cmp(const _z_id_t *left, const _z_id_t *right);\nsize_t _z_id_hash(const _z_id_t *id);\nstatic inline _z_id_t _z_id_empty(void) { return (_z_id_t){0}; }\n\n_Z_ELEM_DEFINE(_z_id, _z_id_t, _z_id_size, _z_noop_clear, _z_id_copy, _z_noop_move, _z_id_eq, _z_id_cmp, _z_id_hash)\n\ntypedef struct {\n    _z_id_t zid;\n    uint32_t eid;\n} _z_entity_global_id_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_entity_global_id_t _z_entity_global_id_null(void) { return (_z_entity_global_id_t){0}; }\nstatic inline bool _z_entity_global_id_check(const _z_entity_global_id_t *info) {\n    return _z_id_check(info->zid) || info->eid != 0;\n}\nstatic inline size_t _z_entity_global_id_size(_z_entity_global_id_t *id) {\n    _ZP_UNUSED(id);\n    return sizeof(_z_entity_global_id_t);\n}\nstatic inline void _z_entity_global_id_copy(_z_entity_global_id_t *dst, const _z_entity_global_id_t *src) {\n    *dst = *src;\n}\nstatic inline bool _z_entity_global_id_eq(const _z_entity_global_id_t *left, const _z_entity_global_id_t *right) {\n    return memcmp(left, right, sizeof(_z_entity_global_id_t)) == 0;\n}\nsize_t _z_entity_global_id_hash(const _z_entity_global_id_t *id);\n\n_Z_ELEM_DEFINE(_z_entity_global_id, _z_entity_global_id_t, _z_entity_global_id_size, _z_noop_clear,\n               _z_entity_global_id_copy, _z_noop_move, _z_entity_global_id_eq, _z_noop_cmp, _z_entity_global_id_hash)\n\n/**\n * NTP64 time.\n */\ntypedef uint64_t _z_ntp64_t;\n\n/**\n * A zenoh timestamp.\n */\ntypedef struct {\n    bool valid;\n    _z_id_t id;\n    _z_ntp64_t time;\n} _z_timestamp_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_timestamp_t _z_timestamp_null(void) { return (_z_timestamp_t){0}; }\nstatic inline void _z_timestamp_invalid(_z_timestamp_t *tstamp) { tstamp->valid = false; }\nstatic inline bool _z_timestamp_check(const _z_timestamp_t *tstamp) { return tstamp->valid; }\nvoid _z_timestamp_copy(_z_timestamp_t *dst, const _z_timestamp_t *src);\n_z_timestamp_t _z_timestamp_duplicate(const _z_timestamp_t *tstamp);\nvoid _z_timestamp_clear(_z_timestamp_t *tstamp);\nvoid _z_timestamp_move(_z_timestamp_t *dst, _z_timestamp_t *src);\nstatic inline size_t _z_timestamp_size(const _z_timestamp_t *ts) {\n    (void)(ts);\n    return sizeof(_z_timestamp_t);\n}\nint _z_timestamp_cmp(const _z_timestamp_t *left, const _z_timestamp_t *right);\n_z_ntp64_t _z_timestamp_ntp64_from_time(uint32_t seconds, uint32_t nanos);\n\n_Z_ELEM_DEFINE(_z_timestamp, _z_timestamp_t, _z_timestamp_size, _z_timestamp_clear, _z_timestamp_copy, _z_noop_move,\n               _z_noop_eq, _z_timestamp_cmp, _z_noop_hash)\n\n/**\n * A zenoh key-expression.\n *\n * Members:\n *  uint16_t _id: The resource ID of the ke.\n *  uintptr_t _mapping: Address of the peer as id, if ke is remotely declared.\n *  _z_string_t _suffix: The string value of the ke.\n */\n// Note on the _mapping field: there are collisions on _id value between peers/local, this field is used only to\n// distinguish which peer/local id space we are in and should not be dereferenced, just compared. NULL/0 value is used\n// for local declared keyexpr and the address of empty_id as a placeholder.\n#define _Z_KEYEXPR_MAPPING_LOCAL (uintptr_t)0\n\ntypedef struct {\n    uint16_t _id;\n    uintptr_t _mapping;\n    _z_string_t _suffix;\n} _z_wireexpr_t;\n\nstatic inline void _z_wireexpr_clear(_z_wireexpr_t *expr) { _z_string_clear(&expr->_suffix); }\nstatic inline z_result_t _z_wireexpr_copy(_z_wireexpr_t *dst, const _z_wireexpr_t *src) {\n    _Z_RETURN_IF_ERR(_z_string_copy(&dst->_suffix, &src->_suffix));\n    dst->_id = src->_id;\n    dst->_mapping = src->_mapping;\n    return _Z_RES_OK;\n}\nstatic inline _z_wireexpr_t _z_wireexpr_alias(const _z_wireexpr_t *src) {\n    _z_wireexpr_t dst;\n    dst._suffix = _z_string_alias(src->_suffix);\n    dst._id = src->_id;\n    dst._mapping = src->_mapping;\n    return dst;\n}\nstatic inline _z_wireexpr_t _z_wireexpr_null(void) {\n    _z_wireexpr_t expr = {0};\n    return expr;\n}\nstatic inline _z_wireexpr_t _z_wireexpr_steal(_z_wireexpr_t *expr) {\n    _z_wireexpr_t expr2 = *expr;\n    *expr = _z_wireexpr_null();\n    return expr2;\n}\nstatic inline bool _z_wireexpr_is_local(const _z_wireexpr_t *expr) {\n    return expr->_mapping == _Z_KEYEXPR_MAPPING_LOCAL;\n}\nstatic inline bool _z_wireexpr_has_suffix(const _z_wireexpr_t *expr) { return _z_string_check(&expr->_suffix); }\nstatic inline bool _z_wireexpr_check(const _z_wireexpr_t *expr) {\n    return _z_string_check(&expr->_suffix) || expr->_id != Z_RESOURCE_ID_NONE;\n}\n\n/**\n * QoS settings of zenoh message.\n */\ntypedef struct {\n    uint8_t _val;\n} _z_qos_t;\n\n/**\n * Represents a Zenoh value.\n *\n * Members:\n *   _z_bytes_t payload: The payload of this zenoh value.\n *   _z_encoding_t encoding: The encoding of the `payload`.\n */\ntypedef struct {\n    _z_bytes_t payload;\n    _z_encoding_t encoding;\n} _z_value_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_value_t _z_value_null(void) { return (_z_value_t){0}; }\nstatic inline bool _z_value_check(const _z_value_t *value) {\n    return _z_bytes_check(&value->payload) || _z_encoding_check(&value->encoding);\n}\nstatic inline _z_value_t _z_value_alias(_z_value_t *src) {\n    _z_value_t dst;\n    dst.payload = _z_bytes_alias(&src->payload);\n    dst.encoding = _z_encoding_alias(&src->encoding);\n    return dst;\n}\n_z_value_t _z_value_steal(_z_value_t *value);\nz_result_t _z_value_copy(_z_value_t *dst, const _z_value_t *src);\nz_result_t _z_value_move(_z_value_t *dst, _z_value_t *src);\nvoid _z_value_clear(_z_value_t *src);\nvoid _z_value_free(_z_value_t **hello);\n\n/**\n * A hello message returned by a zenoh entity to a scout message sent with :c:func:`_z_scout`.\n *\n * Members:\n *   _z_slice_t zid: The Zenoh ID of the scouted entity (empty if absent).\n *   _z_string_vec_t locators: The locators of the scouted entity.\n *   z_whatami_t whatami: The kind of zenoh entity.\n */\ntypedef struct {\n    _z_id_t _zid;\n    _z_string_svec_t _locators;\n    z_whatami_t _whatami;\n    uint8_t _version;\n} _z_hello_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_hello_t _z_hello_null(void) { return (_z_hello_t){0}; }\nvoid _z_hello_clear(_z_hello_t *src);\nvoid _z_hello_free(_z_hello_t **hello);\nz_result_t _z_hello_copy(_z_hello_t *dst, const _z_hello_t *src);\nz_result_t _z_hello_move(_z_hello_t *dst, _z_hello_t *src);\nbool _z_hello_check(const _z_hello_t *hello);\n\n_Z_ELEM_DEFINE(_z_hello, _z_hello_t, _z_noop_size, _z_hello_clear, _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp,\n               _z_noop_hash)\n_Z_SLIST_DEFINE(_z_hello, _z_hello_t, false)\n\ntypedef struct {\n    _z_zint_t n;\n} _z_target_complete_body_t;\n\ntypedef struct {\n    _z_entity_global_id_t _source_id;\n    uint32_t _source_sn;\n} _z_source_info_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_source_info_t _z_source_info_null(void) { return (_z_source_info_t){0}; }\nstatic inline bool _z_source_info_check(const _z_source_info_t *info) {\n    return _z_entity_global_id_check(&info->_source_id);\n}\ntypedef struct {\n    uint32_t _request_id;\n    uint32_t _entity_id;\n} _z_reply_context_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_CORE_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/core.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_CORE_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_CORE_H\n\n#include \"zenoh-pico/protocol/core.h\"\n\n#define _Z_DEFAULT_UNICAST_BATCH_SIZE 65535\n#define _Z_DEFAULT_MULTICAST_BATCH_SIZE 8192\n#define _Z_DEFAULT_RESOLUTION_SIZE 2\n\n#define _Z_DECLARE_CLEAR(layer, name) void _z_##layer##_msg_clear_##name(_z_##name##_t *m, uint8_t header)\n#define _Z_DECLARE_CLEAR_NOH(layer, name) void _z_##layer##_msg_clear_##name(_z_##name##_t *m)\n\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n#define _Z_MSG_LEN_ENC_SIZE 2\n\n/*=============================*/\n/*       Message header        */\n/*=============================*/\n#define _Z_MID_MASK 0x1f\n#define _Z_FLAGS_MASK 0xe0\n\n/*=============================*/\n/*       Message helpers       */\n/*=============================*/\n#define _Z_MID(h) (_Z_MID_MASK & (h))\n#define _Z_FLAGS(h) (_Z_FLAGS_MASK & (h))\n#define _Z_HAS_FLAG(h, f) (((h) & (f)) != 0)\n#define _Z_SET_FLAG(h, f) (h |= f)\n#define _Z_CLEAR_FLAG(h, f) (h &= (uint8_t)(~(f)))\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_CORE_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/declarations.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_DECLARATIONS_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_DECLARATIONS_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    uint16_t _id;\n    _z_wireexpr_t _keyexpr;\n} _z_decl_kexpr_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_decl_kexpr_t _z_decl_kexpr_null(void) { return (_z_decl_kexpr_t){0}; }\ntypedef struct {\n    uint16_t _id;\n} _z_undecl_kexpr_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_undecl_kexpr_t _z_undecl_kexpr_null(void) { return (_z_undecl_kexpr_t){0}; }\n\ntypedef struct {\n    _z_wireexpr_t _keyexpr;\n    uint32_t _id;\n} _z_decl_subscriber_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_decl_subscriber_t _z_decl_subscriber_null(void) { return (_z_decl_subscriber_t){0}; }\ntypedef struct {\n    uint32_t _id;\n    _z_wireexpr_t _ext_keyexpr;\n} _z_undecl_subscriber_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_undecl_subscriber_t _z_undecl_subscriber_null(void) { return (_z_undecl_subscriber_t){0}; }\n\ntypedef struct {\n    _z_wireexpr_t _keyexpr;\n    uint32_t _id;\n    struct {\n        bool _complete;\n        uint16_t _distance;\n    } _ext_queryable_info;\n} _z_decl_queryable_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_decl_queryable_t _z_decl_queryable_null(void) { return (_z_decl_queryable_t){0}; }\ntypedef struct {\n    uint32_t _id;\n    _z_wireexpr_t _ext_keyexpr;\n} _z_undecl_queryable_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_undecl_queryable_t _z_undecl_queryable_null(void) { return (_z_undecl_queryable_t){0}; }\n\ntypedef struct {\n    _z_wireexpr_t _keyexpr;\n    uint32_t _id;\n} _z_decl_token_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_decl_token_t _z_decl_token_null(void) { return (_z_decl_token_t){0}; }\ntypedef struct {\n    uint32_t _id;\n    _z_wireexpr_t _ext_keyexpr;\n} _z_undecl_token_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_undecl_token_t _z_undecl_token_null(void) { return (_z_undecl_token_t){0}; }\n\ntypedef struct {\n    bool _placeholder;  // In case we add extensions\n} _z_decl_final_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_decl_final_t _z_decl_final_null(void) { return (_z_decl_final_t){0}; }\n\ntypedef struct {\n    enum {\n        _Z_DECL_KEXPR,\n        _Z_UNDECL_KEXPR,\n        _Z_DECL_SUBSCRIBER,\n        _Z_UNDECL_SUBSCRIBER,\n        _Z_DECL_QUERYABLE,\n        _Z_UNDECL_QUERYABLE,\n        _Z_DECL_TOKEN,\n        _Z_UNDECL_TOKEN,\n        _Z_DECL_FINAL,\n    } _tag;\n    union {\n        _z_decl_kexpr_t _decl_kexpr;\n        _z_undecl_kexpr_t _undecl_kexpr;\n        _z_decl_subscriber_t _decl_subscriber;\n        _z_undecl_subscriber_t _undecl_subscriber;\n        _z_decl_queryable_t _decl_queryable;\n        _z_undecl_queryable_t _undecl_queryable;\n        _z_decl_token_t _decl_token;\n        _z_undecl_token_t _undecl_token;\n        _z_decl_final_t _decl_final;\n    } _body;\n} _z_declaration_t;\nvoid _z_declaration_clear(_z_declaration_t* decl);\n\n_z_declaration_t _z_make_decl_keyexpr(uint16_t id, _Z_MOVE(_z_wireexpr_t) key);\n_z_declaration_t _z_make_undecl_keyexpr(uint16_t id);\n\n_z_declaration_t _z_make_decl_subscriber(_Z_MOVE(_z_wireexpr_t) key, uint32_t id);\n_z_declaration_t _z_make_undecl_subscriber(uint32_t id, _Z_OPTIONAL _Z_MOVE(_z_wireexpr_t) key);\n\n_z_declaration_t _z_make_decl_queryable(_Z_MOVE(_z_wireexpr_t) key, uint32_t id, bool complete, uint16_t distance);\n_z_declaration_t _z_make_undecl_queryable(uint32_t id, _Z_OPTIONAL _Z_MOVE(_z_wireexpr_t) key);\n\n_z_declaration_t _z_make_decl_token(_Z_MOVE(_z_wireexpr_t) key, uint32_t id);\n_z_declaration_t _z_make_undecl_token(uint32_t id, _Z_OPTIONAL _Z_MOVE(_z_wireexpr_t) key);\n\n_z_declaration_t _z_make_decl_final(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_DECLARATIONS_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/interest.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_INTEREST_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_INTEREST_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_INTEREST_FLAG_KEYEXPRS (1)\n#define _Z_INTEREST_FLAG_SUBSCRIBERS (1 << 1)\n#define _Z_INTEREST_FLAG_QUERYABLES (1 << 2)\n#define _Z_INTEREST_FLAG_TOKENS (1 << 3)\n#define _Z_INTEREST_FLAG_RESTRICTED (1 << 4)\n#define _Z_INTEREST_FLAG_CURRENT (1 << 5)\n#define _Z_INTEREST_FLAG_FUTURE (1 << 6)\n#define _Z_INTEREST_FLAG_AGGREGATE (1 << 7)\n\n#define _Z_INTEREST_NOT_FINAL_MASK (_Z_INTEREST_FLAG_CURRENT | _Z_INTEREST_FLAG_FUTURE)\n\ntypedef struct {\n    _z_wireexpr_t _keyexpr;\n    uint32_t _id;\n    uint8_t flags;\n    bool complete;\n} _z_interest_t;\n\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_interest_t _z_interest_null(void) { return (_z_interest_t){0}; }\nvoid _z_interest_clear(_z_interest_t* decl);\n_z_interest_t _z_make_interest(_Z_MOVE(_z_wireexpr_t) key, uint32_t id, uint8_t flags);\n_z_interest_t _z_make_interest_final(uint32_t id);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_INTEREST_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/message.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_MESSAGE_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_MESSAGE_H\n\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Zenoh Messages */\n#define _Z_MID_Z_OAM 0x00\n#define _Z_MID_Z_PUT 0x01\n#define _Z_MID_Z_DEL 0x02\n#define _Z_MID_Z_QUERY 0x03\n#define _Z_MID_Z_REPLY 0x04\n#define _Z_MID_Z_ERR 0x05\n\n/* Zenoh message flags */\n#define _Z_FLAG_Z_Z 0x80\n#define _Z_FLAG_Z_D 0x20  // 1 << 5 | Dropping          if D==1 then the message can be dropped\n#define _Z_FLAG_Z_K 0x80  // 1 << 7 | ResourceKey       if K==1 then keyexpr is string\n#define _Z_FLAG_Z_R \\\n    0x20  // 1 << 5 | Reliable          if R==1 then it concerns the reliable channel, best-effort otherwise\n#define _Z_FLAG_Z_X 0x00  // Unused flags are set to zero\n\n#define _Z_FRAG_BUFF_BASE_SIZE 128  // Arbitrary base size of the buffer to encode a fragment message header\n\n// Flags:\n// - X: Reserved\n// - E: Encoding       If E==1 then the encoding is present\n// - Z: Extension      If Z==1 then at least one extension is present\n//\n//   7 6 5 4 3 2 1 0\n//  +-+-+-+-+-+-+-+-+\n//  |Z|E|X|   ERR   |\n//  +-+-+-+---------+\n//  %   encoding    %\n//  +---------------+\n//  ~  [err_exts]   ~  if Z==1\n//  +---------------+\n///  ~ pl: <u8;z32>  ~ Payload\n///  +---------------+\n#define _Z_FLAG_Z_E_E 0x40\ntypedef struct {\n    _z_encoding_t _encoding;\n    _z_source_info_t _ext_source_info;\n    _z_bytes_t _payload;\n} _z_msg_err_t;\nvoid _z_msg_err_clear(_z_msg_err_t *err);\n\ntypedef struct {\n    _z_timestamp_t _timestamp;\n    _z_source_info_t _source_info;\n} _z_m_push_commons_t;\n\ntypedef struct {\n    _z_m_push_commons_t _commons;\n    _z_bytes_t _attachment;\n} _z_msg_del_t;\nstatic inline void _z_msg_del_clear(_z_msg_del_t *del) { (void)del; }\n#define _Z_M_DEL_ID 0x02\n#define _Z_FLAG_Z_D_T 0x20\n\ntypedef struct {\n    _z_m_push_commons_t _commons;\n    _z_bytes_t _payload;\n    _z_encoding_t _encoding;\n    _z_bytes_t _attachment;\n} _z_msg_put_t;\nvoid _z_msg_put_clear(_z_msg_put_t *);\n#define _Z_M_PUT_ID 0x01\n#define _Z_FLAG_Z_P_E 0x40\n#define _Z_FLAG_Z_P_T 0x20\n\n/*------------------ Query Message ------------------*/\n//   7 6 5 4 3 2 1 0\n//  +-+-+-+-+-+-+-+-+\n//  |Z|P|C|  QUERY  |\n//  +-+-+-+---------+\n//  ~ consolidation ~  if C==1 -- u8\n//  +---------------+\n//  ~ params        ~  if P==1 -- <utf8;z16>\n//  +---------------+\n//  ~ [qry_exts]    ~  if Z==1\n//  +---------------+\n#define _Z_FLAG_Z_Q_C 0x20  // 1 << 5 | Consolidation if C==1 then consolidation is present\n#define _Z_FLAG_Z_Q_P 0x40  // 1 << 6 | Params        if P==1 then parameters are present\ntypedef struct {\n    _z_slice_t _parameters;\n    _z_source_info_t _ext_info;\n    _z_value_t _ext_value;\n    z_consolidation_mode_t _consolidation;\n    _z_bytes_t _ext_attachment;\n    bool _implicit_anyke;  // implicit _anyke parameter (i.e it is not listed in _parameters, but is still present)\n} _z_msg_query_t;\ntypedef struct {\n    bool info;\n    bool body;\n    bool attachment;\n} _z_msg_query_reqexts_t;\n_z_msg_query_reqexts_t _z_msg_query_required_extensions(const _z_msg_query_t *msg);\nvoid _z_msg_query_clear(_z_msg_query_t *msg);\n\ntypedef struct {\n    bool _is_put;\n    union {\n        _z_msg_del_t _del;\n        _z_msg_put_t _put;\n    } _body;\n} _z_reply_body_t;\n// Flags:\n// - C: Consolidation  If C==1 then consolidation is present\n// - X: Reserved\n// - Z: Extension      If Z==1 then at least one extension is present\n//\n//   7 6 5 4 3 2 1 0\n//  +-+-+-+-+-+-+-+-+\n//  |Z|X|C|  REPLY  |\n//  +-+-+-+---------+\n//  ~ consolidation ~  if C==1\n//  +---------------+\n//  ~  [repl_exts]  ~  if Z==1\n//  +---------------+\n//  ~  ReplyBody    ~  -- Payload\n//  +---------------+\ntypedef struct {\n    z_consolidation_mode_t _consolidation;\n    _z_reply_body_t _body;\n} _z_msg_reply_t;\nvoid _z_msg_reply_clear(_z_msg_reply_t *msg);\n#define _Z_FLAG_Z_R_C 0x20\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_MESSAGE_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/network.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_NETWORK_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_NETWORK_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Network Messages */\n#define _Z_MID_N_OAM 0x1f\n#define _Z_MID_N_DECLARE 0x1e\n#define _Z_MID_N_PUSH 0x1d\n#define _Z_MID_N_REQUEST 0x1c\n#define _Z_MID_N_RESPONSE 0x1b\n#define _Z_MID_N_RESPONSE_FINAL 0x1a\n#define _Z_MID_N_INTEREST 0x19\n\n/*=============================*/\n/*        Network flags        */\n/*=============================*/\n#define _Z_FLAG_N_Z 0x80  // 1 << 7\n\n// DECLARE message flags:\n// - I: Interest       If I==1 then the declare is in a response to an Interest with future==false\n// - X: Reserved\n// - Z: Extension      If Z==1 then Zenoh extensions are present\n#define _Z_FLAG_N_DECLARE_I 0x20  // 1 << 5\n\n// INTEREST message flags:\n// - C: Current       If C==1 then interest concerns current declarations\n// - F: Future        If F==1 then interest concerns future declarations\n// - Z: Extension     If Z==1 then Zenoh extensions are present\n#define _Z_FLAG_N_INTEREST_CURRENT 0x20  // 1 << 5\n#define _Z_FLAG_N_INTEREST_FUTURE 0x40   // 1 << 6\n\n// PUSH message flags:\n//      N Named            if N==1 then the key expr has name/suffix\n//      M Mapping          if M==1 then keyexpr mapping is the one declared by the sender, otherwise by the receiver\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_N_PUSH_N 0x20  // 1 << 5\n#define _Z_FLAG_N_PUSH_M 0x40  // 1 << 6\n\n// REQUEST message flags:\n//      N Named            if N==1 then the key expr has name/suffix\n//      M Mapping          if M==1 then keyexpr mapping is the one declared by the sender, otherwise by the receiver\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_N_REQUEST_N 0x20  // 1 << 5\n#define _Z_FLAG_N_REQUEST_M 0x40  // 1 << 6\n\n// RESPONSE message flags:\n//      N Named            if N==1 then the key expr has name/suffix\n//      M Mapping          if M==1 then keyexpr mapping is the one declared by the sender, otherwise by the receiver\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_N_RESPONSE_N 0x20  // 1 << 5\n#define _Z_FLAG_N_RESPONSE_M 0x40  // 1 << 6\n\ntypedef _z_qos_t _z_n_qos_t;\n\n#define _Z_N_QOS_IS_EXPRESS_FLAG (1 << 4)\n\nstatic inline _z_qos_t _z_n_qos_create(bool express, z_congestion_control_t congestion_control, z_priority_t priority) {\n    _z_n_qos_t ret;\n    bool nodrop = congestion_control == Z_CONGESTION_CONTROL_DROP ? 0 : 1;\n    ret._val = (uint8_t)((express << 4) | (nodrop << 3) | (uint8_t)priority);\n    return ret;\n}\nstatic inline z_priority_t _z_n_qos_get_priority(_z_n_qos_t n_qos) {\n    z_priority_t ret = (z_priority_t)(n_qos._val & 0x07);  // 0b0111\n    return ret;\n}\nstatic inline z_congestion_control_t _z_n_qos_get_congestion_control(_z_n_qos_t n_qos) {\n    z_congestion_control_t ret =\n        (n_qos._val & 0x08) ? Z_CONGESTION_CONTROL_BLOCK : Z_CONGESTION_CONTROL_DROP;  // 0b1000\n    return ret;\n}\nstatic inline bool _z_n_qos_get_express(_z_n_qos_t n_qos) {\n    bool ret = (n_qos._val & 0x10) != 0;  // 0b10000\n    return ret;\n}\n#define _z_n_qos_make(express, nodrop, priority)                                                    \\\n    _z_n_qos_create((bool)express, nodrop ? Z_CONGESTION_CONTROL_BLOCK : Z_CONGESTION_CONTROL_DROP, \\\n                    (z_priority_t)priority)\n\nextern const _z_qos_t _Z_N_QOS_DEFAULT;\n\n// RESPONSE FINAL message flags:\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n// #define _Z_FLAG_N_RESPONSE_X 0x20  // 1 << 5\n// #define _Z_FLAG_N_RESPONSE_X 0x40  // 1 << 6\n\n// Flags:\n// - N: Named          if N==1 then the keyexpr has name/suffix\n// - M: Mapping        if M==1 then keyexpr mapping is the one declared by the sender, otherwise by the receiver\n// - Z: Extension      if Z==1 then at least one extension is present\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|M|N| REQUEST |\n// +-+-+-+---------+\n// ~ request_id:z32~\n// +---------------+\n// ~ key_scope:z16 ~\n// +---------------+\n// ~  key_suffix   ~  if N==1 -- <u8;z16>\n// +---------------+\n// ~   [req_exts]  ~  if Z==1\n// +---------------+\n// ~ ZenohMessage  ~\n// +---------------+\n//\ntypedef struct {\n    _z_zint_t _rid;\n    _z_wireexpr_t _key;\n    _z_timestamp_t _ext_timestamp;\n    _z_n_qos_t _ext_qos;\n    z_query_target_t _ext_target;\n    uint32_t _ext_budget;\n    uint64_t _ext_timeout_ms;\n    enum {\n        _Z_REQUEST_QUERY,\n        _Z_REQUEST_PUT,\n        _Z_REQUEST_DEL,\n    } _tag;\n    union {\n        _z_msg_query_t _query;\n        _z_msg_put_t _put;\n        _z_msg_del_t _del;\n    } _body;\n} _z_n_msg_request_t;\ntypedef struct {\n    bool ext_qos;\n    bool ext_tstamp;\n    bool ext_target;\n    bool ext_budget;\n    bool ext_timeout_ms;\n    uint8_t n;\n} _z_n_msg_request_exts_t;\n_z_n_msg_request_exts_t _z_n_msg_request_needed_exts(const _z_n_msg_request_t *msg);\nvoid _z_n_msg_request_clear(_z_n_msg_request_t *msg);\n\ntypedef _z_reply_body_t _z_push_body_t;\n// Warning: None of the sub-types require a non-0 initialization. Add a init function if it changes.\nstatic inline _z_push_body_t _z_push_body_null(void) { return (_z_push_body_t){0}; }\n\n_z_push_body_t _z_push_body_steal(_z_push_body_t *msg);\nvoid _z_push_body_clear(_z_push_body_t *msg);\n\n/*------------------ Response Final Message ------------------*/\n// Flags:\n// - Z: Extension      if Z==1 then at least one extension is present\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|M|N| ResFinal|\n// +-+-+-+---------+\n// ~ request_id:z32~\n// +---------------+\n// ~  [reply_exts] ~  if Z==1\n// +---------------+\n//\ntypedef struct {\n    _z_zint_t _request_id;\n} _z_n_msg_response_final_t;\nvoid _z_n_msg_response_final_clear(_z_n_msg_response_final_t *msg);\n\n// Flags:\n// - N: Named          if N==1 then the keyexpr has name/suffix\n// - M: Mapping        if M==1 then keyexpr mapping is the one declared by the sender, otherwise by the receiver\n// - Z: Extension      if Z==1 then at least one extension is present\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|M|N|  PUSH   |\n// +-+-+-+---------+\n// ~ key_scope:z?  ~\n// +---------------+\n// ~  key_suffix   ~  if N==1 -- <u8;z16>\n// +---------------+\n// ~  [push_exts]  ~  if Z==1\n// +---------------+\n// ~ ZenohMessage  ~\n// +---------------+\n//\ntypedef struct {\n    _z_wireexpr_t _key;\n    _z_timestamp_t _timestamp;\n    _z_n_qos_t _qos;\n    _z_push_body_t _body;\n} _z_n_msg_push_t;\nvoid _z_n_msg_push_clear(_z_n_msg_push_t *msg);\n\n/*------------------ Response Message ------------------*/\ntypedef struct {\n    _z_timestamp_t _ext_timestamp;\n    _z_zint_t _request_id;\n    _z_wireexpr_t _key;\n    _z_n_qos_t _ext_qos;\n    struct {\n        _z_id_t _zid;\n        uint32_t _eid;\n    } _ext_responder;\n    enum {\n        _Z_RESPONSE_BODY_REPLY,\n        _Z_RESPONSE_BODY_ERR,\n    } _tag;\n    union {\n        _z_msg_reply_t _reply;\n        _z_msg_err_t _err;\n    } _body;\n} _z_n_msg_response_t;\nvoid _z_n_msg_response_clear(_z_n_msg_response_t *msg);\n\n/*------------------ Declare Message ------------------*/\ntypedef struct {\n    uint32_t value;\n    bool has_value;\n} _z_optional_id_t;\nstatic inline _z_optional_id_t _z_optional_id_make_some(uint32_t value) {\n    _z_optional_id_t id;\n    id.value = value;\n    id.has_value = true;\n    return id;\n}\nstatic inline _z_optional_id_t _z_optional_id_make_none(void) {\n    _z_optional_id_t id = {0};\n    return id;\n}\n\ntypedef struct {\n    _z_declaration_t _decl;\n    _z_timestamp_t _ext_timestamp;\n    _z_n_qos_t _ext_qos;\n    _z_optional_id_t _interest_id;\n} _z_n_msg_declare_t;\nstatic inline void _z_n_msg_declare_clear(_z_n_msg_declare_t *msg) { _z_declaration_clear(&msg->_decl); }\n\n/*------------------ Interest Message ------------------*/\n\n/// Flags:\n/// - C: Current       If C==1 then interest concerns current declarations\n/// - F: Future        If F==1 then interest concerns future declarations\n/// - Z: Extension     If Z==1 then Zenoh extensions are present\n/// If C==0 and F==0, then interest is final\n///\n/// 7 6 5 4 3 2 1 0\n/// +-+-+-+-+-+-+-+-+\n/// |Z|F|C|INTEREST |\n/// +-+-+-+---------+\n/// ~    id:z32     ~\n/// +---------------+\n/// |A|M|N|R|T|Q|S|K|  (*) if interest is not final\n/// +---------------+\n/// ~ key_scope:z16 ~  if interest is not final && R==1\n/// +---------------+\n/// ~  key_suffix   ~  if interest is not final && R==1 && N==1 -- <u8;z16>\n/// +---------------+\n/// ~  [int_exts]   ~  if Z==1\n/// +---------------+\n///\n/// (*) - if K==1 then the interest refers to key expressions\n///     - if S==1 then the interest refers to subscribers\n///     - if Q==1 then the interest refers to queryables\n///     - if T==1 then the interest refers to tokens\n///     - if R==1 then the interest is restricted to the matching key expression, else it is for all key expressions.\n///     - if N==1 then the key expr has name/suffix. If R==0 then N should be set to 0.\n///     - if M==1 then key expr mapping is the one declared by the sender, else it is the one declared by the receiver.\n///               If R==0 then M should be set to 0.\n///     - if A==1 then the replies SHOULD be aggregated\n/// ```\n\ntypedef struct {\n    _z_interest_t _interest;\n} _z_n_msg_interest_t;\nstatic inline void _z_n_msg_interest_clear(_z_n_msg_interest_t *msg) { _z_interest_clear(&msg->_interest); }\n\n/*------------------ OAM Message ------------------*/\n\n/// Flags:\n/// - E |: Encoding     The encoding of the extension\n/// - E/\n/// - Z: Extension      If Z==1 then at least one extension is present\n///\n///  7 6 5 4 3 2 1 0\n/// +-+-+-+-+-+-+-+-+\n/// |Z|ENC|  OAM    |\n/// +-+-+-+---------+\n/// ~    id:z16     ~\n/// +---------------+\n/// ~  [oam_exts]   ~  if Z==1\n/// +---------------+\n/// %    length     %  If ENC == Z64 || ENC == ZBuf (z32)\n/// +---------------+\n/// ~     [u8]      ~  If ENC == ZBuf\n/// +---------------+\n///\n/// Encoding:\n/// - 0b00: Unit\n/// - 0b01: Z64\n/// - 0b10: ZBuf\n/// - 0b11: Reserved\ntypedef struct {\n    uint16_t _id;\n    _z_timestamp_t _ext_timestamp;\n    _z_n_qos_t _ext_qos;\n    enum { _Z_OAM_BODY_UNIT, _Z_OAM_BODY_ZINT, _Z_OAM_BODY_ZBUF } _enc;\n    _z_msg_ext_body_t _body;\n} _z_n_msg_oam_t;\nvoid _z_n_msg_oam_clear(_z_n_msg_oam_t *msg);\n\n/*------------------ Zenoh Message ------------------*/\ntypedef union {\n    _z_n_msg_declare_t _declare;\n    _z_n_msg_push_t _push;\n    _z_n_msg_request_t _request;\n    _z_n_msg_response_t _response;\n    _z_n_msg_response_final_t _response_final;\n    _z_n_msg_interest_t _interest;\n    _z_n_msg_oam_t _oam;\n} _z_network_body_t;\ntypedef struct {\n    enum { _Z_N_DECLARE, _Z_N_PUSH, _Z_N_REQUEST, _Z_N_RESPONSE, _Z_N_RESPONSE_FINAL, _Z_N_INTEREST, _Z_N_OAM } _tag;\n    _z_network_body_t _body;\n    z_reliability_t _reliability;\n} _z_network_message_t;\ntypedef _z_network_message_t _z_zenoh_message_t;\nvoid _z_n_msg_clear(_z_network_message_t *m);\nvoid _z_n_msg_free(_z_network_message_t **m);\ninline static void _z_msg_clear(_z_zenoh_message_t *msg) { _z_n_msg_clear(msg); }\ninline static void _z_msg_free(_z_zenoh_message_t **msg) { _z_n_msg_free(msg); }\nz_result_t _z_n_msg_copy(_z_network_message_t *dst, const _z_network_message_t *src);\n_z_network_message_t *_z_n_msg_clone(const _z_network_message_t *src);\n\n_Z_ELEM_DEFINE(_z_network_message, _z_network_message_t, _z_noop_size, _z_n_msg_clear, _z_n_msg_copy, _z_noop_move,\n               _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SVEC_DEFINE(_z_network_message, _z_network_message_t)\n_Z_SLIST_DEFINE(_z_network_message, _z_network_message_t, true)\n\nvoid _z_n_msg_make_response_final(_z_network_message_t *msg, _z_zint_t rid);\nvoid _z_n_msg_make_declare(_z_network_message_t *msg, _z_declaration_t declaration, _z_optional_id_t interest_id);\nvoid _z_n_msg_make_query(_z_zenoh_message_t *msg, const _z_wireexpr_t *key, const _z_slice_t *parameters, _z_zint_t qid,\n                         z_reliability_t reliability, z_consolidation_mode_t consolidation, const _z_bytes_t *payload,\n                         const _z_encoding_t *encoding, uint64_t timeout_ms, const _z_bytes_t *attachment,\n                         _z_n_qos_t qos, const _z_source_info_t *source_info, bool implicit_anyke);\nvoid _z_n_msg_make_push_put(_z_network_message_t *dst, const _z_wireexpr_t *key, const _z_bytes_t *payload,\n                            const _z_encoding_t *encoding, _z_n_qos_t qos, const _z_timestamp_t *timestamp,\n                            const _z_bytes_t *attachment, z_reliability_t reliability,\n                            const _z_source_info_t *source_info);\nvoid _z_n_msg_make_push_del(_z_network_message_t *dst, const _z_wireexpr_t *key, _z_n_qos_t qos,\n                            const _z_timestamp_t *timestamp, z_reliability_t reliability,\n                            const _z_source_info_t *source_info);\nvoid _z_n_msg_make_reply_ok_put(_z_network_message_t *dst, const _z_id_t *zid, _z_zint_t rid, const _z_wireexpr_t *key,\n                                z_reliability_t reliability, z_consolidation_mode_t consolidation, _z_n_qos_t qos,\n                                const _z_timestamp_t *timestamp, const _z_source_info_t *source_info,\n                                const _z_bytes_t *payload, const _z_encoding_t *encoding, const _z_bytes_t *attachment);\nvoid _z_n_msg_make_reply_ok_del(_z_network_message_t *dst, const _z_id_t *zid, _z_zint_t rid, const _z_wireexpr_t *key,\n                                z_reliability_t reliability, z_consolidation_mode_t consolidation, _z_n_qos_t qos,\n                                const _z_timestamp_t *timestamp, const _z_source_info_t *source_info,\n                                const _z_bytes_t *attachment);\nvoid _z_n_msg_make_reply_err(_z_network_message_t *dst, const _z_id_t *zid, _z_zint_t rid, z_reliability_t reliability,\n                             _z_n_qos_t qos, const _z_bytes_t *payload, const _z_encoding_t *encoding,\n                             const _z_source_info_t *source_info);\nvoid _z_n_msg_make_interest(_z_network_message_t *msg, _z_interest_t interest);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_NETWORK_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/serial.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_SERIAL_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_SERIAL_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/// ZSerial Frame Format\n///\n/// Using COBS\n///\n/// +-+-+----+------------+--------+-+\n/// |O|H|XXXX|ZZZZ....ZZZZ|CCCCCCCC|0|\n/// +-+----+------------+--------+-+\n/// |O| |Len |   Data     |  CRC32 |C|\n/// +-+-+-2--+----N-------+---4----+-+\n///\n/// Header: 1byte\n/// +---------------+\n/// |7|6|5|4|3|2|1|0|\n/// +---------------+\n/// |x|x|x|x|x|R|A|I|\n/// +---------------+\n///\n/// Flags:\n/// I - Init\n/// A - Ack\n/// R - Reset\n///\n/// Max Frame Size: 1510\n/// Max MTU: 1500\n/// Max On-the-wire length: 1516 (MFS + Overhead Byte (OHB) + Kind Byte + End of packet (EOP))\n\n#define _Z_FLAG_SERIAL_INIT 0x01\n#define _Z_FLAG_SERIAL_ACK 0x02\n#define _Z_FLAG_SERIAL_RESET 0x04\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_SERIAL_H*/\n"
  },
  {
    "path": "include/zenoh-pico/protocol/definitions/transport.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_TRANSPORT_H\n#define INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_TRANSPORT_H\n\n/* Scouting Messages */\n#include <stdint.h>\n\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_MID_SCOUT 0x01\n#define _Z_MID_HELLO 0x02\n\n/* Transport Messages */\n#define _Z_MID_T_OAM 0x00\n#define _Z_MID_T_INIT 0x01\n#define _Z_MID_T_OPEN 0x02\n#define _Z_MID_T_CLOSE 0x03\n#define _Z_MID_T_KEEP_ALIVE 0x04\n#define _Z_MID_T_FRAME 0x05\n#define _Z_MID_T_FRAGMENT 0x06\n#define _Z_MID_T_JOIN 0x07\n\n/*=============================*/\n/*        Message flags        */\n/*=============================*/\n#define _Z_FLAG_T_Z 0x80  // 1 << 7\n\n// Scout message flags:\n//      I ZenohID          if I==1 then the ZenohID is present\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_SCOUT_I 0x08  // 1 << 3\n\n// Hello message flags:\n//      L Locators         if L==1 then Locators are present\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_HELLO_L 0x20  // 1 << 5\n\n// Join message flags:\n//      T Lease period     if T==1 then the lease period is in seconds else in milliseconds\n//      S Size params      if S==1 then size parameters are exchanged\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_JOIN_T 0x20  // 1 << 5\n#define _Z_FLAG_T_JOIN_S 0x40  // 1 << 6\n\n// Init message flags:\n//      A Ack              if A==1 then the message is an acknowledgment (aka InitAck), otherwise InitSyn\n//      S Size params      if S==1 then size parameters are exchanged\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_INIT_A 0x20  // 1 << 5\n#define _Z_FLAG_T_INIT_S 0x40  // 1 << 6\n\n// Open message flags:\n//      A Ack              if A==1 then the message is an acknowledgment (aka OpenAck), otherwise OpenSyn\n//      T Lease period     if T==1 then the lease period is in seconds else in milliseconds\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_OPEN_A 0x20  // 1 << 5\n#define _Z_FLAG_T_OPEN_T 0x40  // 1 << 6\n\n// Frame message flags:\n//      R Reliable         if R==1 it concerns the reliable channel, else the best-effort channel\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_FRAME_R 0x20  // 1 << 5\n\n// Frame message flags:\n//      R Reliable         if R==1 it concerns the reliable channel, else the best-effort channel\n//      M More             if M==1 then other fragments will follow\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_FRAGMENT_R 0x20  // 1 << 5\n#define _Z_FLAG_T_FRAGMENT_M 0x40  // 1 << 6\n\n// Close message flags:\n//      S Session Close    if S==1 Session close or S==0 Link close\n//      Z Extensions       if Z==1 then Zenoh extensions are present\n#define _Z_FLAG_T_CLOSE_S 0x20  // 1 << 5\n\n/*=============================*/\n/*            Patch            */\n/*=============================*/\n/// Used to negotiate the patch version of the protocol\n/// if not present (or 0), then protocol as released with 1.0.0\n/// if >= 1, then fragmentation start/stop marker\n#define _Z_NO_PATCH 0x00\n#define _Z_CURRENT_PATCH 0x01\n#define _Z_PATCH_HAS_FRAGMENT_MARKERS(patch) (patch >= 1)\n\n/*=============================*/\n/*     Transport Messages      */\n/*=============================*/\n/*------------------ Scout Message ------------------*/\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The SCOUT message can be sent at any point in time to solicit HELLO messages from matching parties.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|X|X|  SCOUT  |\n// +-+-+-+---------+\n// |    version    |\n// +---------------+\n// |zid_len|I| what| (#)(*)\n// +-+-+-+-+-+-+-+-+\n// ~      [u8]     ~ if Flag(I)==1 -- ZenohID\n// +---------------+\n//\n// (#) ZID length. If Flag(I)==1 it indicates how many bytes are used for the ZenohID bytes.\n//     A ZenohID is minimum 1 byte and maximum 16 bytes. Therefore, the actual length is computed as:\n//         real_zid_len := 1 + zid_len\n//\n// (*) What. It indicates a bitmap of WhatAmI interests.\n//    The valid bitflags are:\n//    - 0b001: Router\n//    - 0b010: Peer\n//    - 0b100: Client\n//\ntypedef struct {\n    _z_id_t _zid;\n    z_what_t _what;\n    uint8_t _version;\n} _z_s_msg_scout_t;\nvoid _z_s_msg_scout_clear(_z_s_msg_scout_t *msg);\n\n/*------------------ Hello Message ------------------*/\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The HELLO message is sent in any of the following three cases:\n//     1) in response to a SCOUT message;\n//     2) to (periodically) advertise (e.g., on multicast) the Peer and the locators it is reachable at;\n//     3) in a already established session to update the corresponding peer on the new capabilities\n//        (i.e., whatami) and/or new set of locators (i.e., added or deleted).\n// Locators are expressed as:\n// <code>\n//  udp/192.168.0.2:1234\n//  tcp/192.168.0.2:1234\n//  udp/239.255.255.123:5555\n// <code>\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|X|L|  HELLO  |\n// +-+-+-+---------+\n// |    version    |\n// +---------------+\n// |zid_len|X|X|wai| (*)\n// +-+-+-+-+-+-+-+-+\n// ~     [u8]      ~ -- ZenohID\n// +---------------+\n// ~   <utf8;z8>   ~ if Flag(L)==1 -- List of locators\n// +---------------+\n//\n// (*) WhatAmI. It indicates the role of the zenoh node sending the HELLO message.\n//    The valid WhatAmI values are:\n//    - 0b00: Router\n//    - 0b01: Peer\n//    - 0b10: Client\n//    - 0b11: Reserved\n//\ntypedef struct {\n    _z_id_t _zid;\n    _z_locator_array_t _locators;\n    z_whatami_t _whatami;\n    uint8_t _version;\n} _z_s_msg_hello_t;\nvoid _z_s_msg_hello_clear(_z_s_msg_hello_t *msg);\n\n/*------------------ Join Message ------------------*/\n// # Join message\n//\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The JOIN message is sent on a multicast Locator to advertise the transport parameters.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |O|S|T|   JOIN  |\n// +-+-+-+-+-------+\n// ~             |Q~ if O==1\n// +---------------+\n// | v_maj | v_min | -- Protocol Version VMaj.VMin\n// +-------+-------+\n// ~    whatami    ~ -- Router, Peer or a combination of them\n// +---------------+\n// ~   zenoh_id    ~ -- PID of the sender of the JOIN message\n// +---------------+\n// ~     lease     ~ -- Lease period of the sender of the JOIN message(*)\n// +---------------+\n// ~ seq_num_res ~ if S==1(*) -- Otherwise 2^28 is assumed(**)\n// +---------------+\n// ~   [next_sn]   ~ (***)\n// +---------------+\n//\n// - if Q==1 then the sender supports QoS.\n//\n// (*)   if T==1 then the lease period is expressed in seconds, otherwise in milliseconds\n// (**)  if S==0 then 2^28 is assumed.\n// (***) if Q==1 then 8 sequence numbers are present: one for each priority.\n//       if Q==0 then only one sequence number is present.\n//\ntypedef struct {\n    _z_zint_t _reliable;\n    _z_zint_t _best_effort;\n} _z_coundit_sn_t;\ntypedef struct {\n    union {\n        _z_coundit_sn_t _plain;\n        _z_coundit_sn_t _qos[Z_PRIORITIES_NUM];\n    } _val;\n    bool _is_qos;\n} _z_conduit_sn_list_t;\ntypedef struct {\n    _z_id_t _zid;\n    _z_zint_t _lease;\n    _z_conduit_sn_list_t _next_sn;\n    uint16_t _batch_size;\n    z_whatami_t _whatami;\n    uint8_t _req_id_res;\n    uint8_t _seq_num_res;\n    uint8_t _version;\n#if Z_FEATURE_FRAGMENTATION == 1\n    uint8_t _patch;\n#endif\n} _z_t_msg_join_t;\nvoid _z_t_msg_join_clear(_z_t_msg_join_t *msg);\n\n/*------------------ Init Message ------------------*/\n// # Init message\n//\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The INIT message is sent on a specific Locator to initiate a session with the peer associated\n// with that Locator. The initiator MUST send an INIT message with the A flag set to 0.  If the\n// corresponding peer deems appropriate to initialize a session with the initiator, the corresponding\n// peer MUST reply with an INIT message with the A flag set to 1.\n//\n// Flags:\n// - A: Ack          if A==0 then the message is an InitSyn else it is an InitAck\n// - S: Size params  if S==1 then size parameters are exchanged\n// - Z: Extensions   if Z==1 then zenoh extensions will follow.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|S|A|   INIT  |\n// +-+-+-+---------+\n// |    version    |\n// +---------------+\n// |zid_len|x|x|wai| (#)(*)\n// +-------+-+-+---+\n// ~      [u8]     ~ -- ZenohID of the sender of the INIT message\n// +---------------+\n// |x|x|kid|rid|fsn| \\                -- SN/ID resolution (+)\n// +---------------+  | if Flag(S)==1\n// |      u16      |  |               -- Batch Size ($)\n// |               | /\n// +---------------+\n// ~    <u8;z16>   ~ -- if Flag(A)==1 -- Cookie\n// +---------------+\n// ~   [InitExts]  ~ -- if Flag(Z)==1\n// +---------------+\n//\n// If A==1 and S==0 then size parameters are (ie. S flag) are accepted.\n//\n// (*) WhatAmI. It indicates the role of the zenoh node sending the INIT\n// message.\n//    The valid WhatAmI values are:\n//    - 0b00: Router\n//    - 0b01: Peer\n//    - 0b10: Client\n//    - 0b11: Reserved\n//\n// (#) ZID length. It indicates how many bytes are used for the ZenohID bytes.\n//     A ZenohID is minimum 1 byte and maximum 16 bytes. Therefore, the actual\n//     length is computed as:\n//         real_zid_len := 1 + zid_len\n//\n// (+) Sequence Number/ID resolution. It indicates the resolution and\n// consequently the wire overhead\n//     of various SN and ID in Zenoh.\n//     - fsn: frame/fragment sequence number resolution. Used in Frame/Fragment\n//     messages.\n//     - rid: request ID resolution. Used in Request/Response messages.\n//     - kid: key expression ID resolution. Used in Push/Request/Response\n//     messages. The valid SN/ID resolution values are:\n//     - 0b00: 8 bits\n//     - 0b01: 16 bits\n//     - 0b10: 32 bits\n//     - 0b11: 64 bits\n//\n// ($) Batch Size. It indicates the maximum size of a batch the sender of the\n//\ntypedef struct {\n    _z_id_t _zid;\n    _z_slice_t _cookie;\n    uint16_t _batch_size;\n    z_whatami_t _whatami;\n    uint8_t _req_id_res;\n    uint8_t _seq_num_res;\n    uint8_t _version;\n#if Z_FEATURE_FRAGMENTATION == 1\n    uint8_t _patch;\n#endif\n} _z_t_msg_init_t;\nvoid _z_t_msg_init_clear(_z_t_msg_init_t *msg);\n\n/*------------------ Open Message ------------------*/\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The OPEN message is sent on a link to finally open an initialized session with the peer.\n//\n// Flags:\n// - A Ack           if A==1 then the message is an acknowledgment (aka OpenAck), otherwise OpenSyn\n// - T Lease period  if T==1 then the lease period is in seconds else in milliseconds\n// - Z Extensions    if Z==1 then Zenoh extensions are present\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|T|A|   OPEN  |\n// +-+-+-+---------+\n// %     lease     % -- Lease period of the sender of the OPEN message\n// +---------------+\n// %  initial_sn   % -- Initial SN proposed by the sender of the OPEN(*)\n// +---------------+\n// ~    <u8;z16>   ~ if Flag(A)==0 (**) -- Cookie\n// +---------------+\n// ~   [OpenExts]  ~ if Flag(Z)==1\n// +---------------+\n//\n// (*)     The initial sequence number MUST be compatible with the sequence number resolution agreed in the\n//         [`super::InitSyn`]-[`super::InitAck`] message exchange\n// (**)    The cookie MUST be the same received in the [`super::InitAck`]from the corresponding zenoh node\n//\ntypedef struct {\n    _z_zint_t _lease;\n    _z_zint_t _initial_sn;\n    _z_slice_t _cookie;\n} _z_t_msg_open_t;\nvoid _z_t_msg_open_clear(_z_t_msg_open_t *msg);\n\n/*------------------ Close Message ------------------*/\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The CLOSE message is sent in any of the following two cases:\n//     1) in response to an OPEN message which is not accepted;\n//     2) at any time to arbitrarily close the session with the corresponding peer.\n//\n// Flags:\n// - S: Session Close  if S==1 Session close or S==0 Link close\n// - X: Reserved\n// - Z: Extensions     if Z==1 then zenoh extensions will follow.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|X|S|  CLOSE  |\n// +-+-+-+---------+\n// |    Reason     |\n// +---------------+\n// ~  [CloseExts]  ~ if Flag(Z)==1\n// +---------------+\n//\ntypedef struct {\n    uint8_t _reason;\n} _z_t_msg_close_t;\nvoid _z_t_msg_close_clear(_z_t_msg_close_t *msg);\n/*=============================*/\n/*        Close reasons        */\n/*=============================*/\n#define _Z_CLOSE_GENERIC 0x00\n#define _Z_CLOSE_UNSUPPORTED 0x01\n#define _Z_CLOSE_INVALID 0x02\n#define _Z_CLOSE_MAX_TRANSPORTS 0x03\n#define _Z_CLOSE_MAX_LINKS 0x04\n#define _Z_CLOSE_EXPIRED 0x05\n\n/*------------------ Keep Alive Message ------------------*/\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// The KEEP_ALIVE message can be sent periodically to avoid the expiration of the session lease\n// period in case there are no messages to be sent.\n//\n// Flags:\n// - X: Reserved\n// - X: Reserved\n// - Z: Extensions     If Z==1 then Zenoh extensions will follow.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|X|X| KALIVE  |\n// +-+-+-+---------+\n// ~  [KAliveExts] ~ if Flag(Z)==1\n// +---------------+\n//\ntypedef struct {\n    uint8_t __dummy;  // Just to avoid empty structures that might cause undefined behavior\n} _z_t_msg_keep_alive_t;\nvoid _z_t_msg_keep_alive_clear(_z_t_msg_keep_alive_t *msg);\n\n/*------------------ Frame Message ------------------*/\n// NOTE: 16 bits (2 bytes) may be prepended to the serialized message indicating the total length\n//       in bytes of the message, resulting in the maximum length of a message being 65_535 bytes.\n//       This is necessary in those stream-oriented transports (e.g., TCP) that do not preserve\n//       the boundary of the serialized messages. The length is encoded as little-endian.\n//       In any case, the length of a message must not exceed 65_535 bytes.\n//\n// Flags:\n// - R: Reliable       If R==1 it concerns the reliable channel, else the best-effort channel\n// - X: Reserved\n// - Z: Extensions     If Z==1 then zenoh extensions will follow.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|X|R|  FRAME  |\n// +-+-+-+---------+\n// %    seq num    %\n// +---------------+\n// ~  [FrameExts]  ~ if Flag(Z)==1\n// +---------------+\n// ~  [NetworkMsg] ~\n// +---------------+\n//\n// - if R==1 then the FRAME is sent on the reliable channel, best-effort otherwise.\n//\ntypedef struct {\n    _z_zbuf_t *_payload;\n    _z_zint_t _sn;\n} _z_t_msg_frame_t;\nvoid _z_t_msg_frame_clear(_z_t_msg_frame_t *msg);\n\n/*------------------ Fragment Message ------------------*/\n// The Fragment message is used to transmit on the wire large Zenoh Message that require fragmentation\n// because they are larger than the maximum batch size (i.e. 2^16-1) and/or the link MTU.\n//\n// The [`Fragment`] message flow is the following:\n//\n// Flags:\n// - R: Reliable       if R==1 it concerns the reliable channel, else the best-effort channel\n// - M: More           if M==1 then other fragments will follow\n// - Z: Extensions     if Z==1 then zenoh extensions will follow.\n//\n//  7 6 5 4 3 2 1 0\n// +-+-+-+-+-+-+-+-+\n// |Z|M|R| FRAGMENT|\n// +-+-+-+---------+\n// %    seq num    %\n// +---------------+\n// ~   [FragExts]  ~ if Flag(Z)==1\n// +---------------+\n// ~      [u8]     ~\n// +---------------+\n//\ntypedef struct {\n    _z_slice_t _payload;\n    _z_zint_t _sn;\n    bool first;\n    bool drop;\n} _z_t_msg_fragment_t;\nvoid _z_t_msg_fragment_clear(_z_t_msg_fragment_t *msg);\n\n/*------------------ Transport Message ------------------*/\ntypedef union {\n    _z_t_msg_join_t _join;\n    _z_t_msg_init_t _init;\n    _z_t_msg_open_t _open;\n    _z_t_msg_close_t _close;\n    _z_t_msg_keep_alive_t _keep_alive;\n    _z_t_msg_frame_t _frame;\n    _z_t_msg_fragment_t _fragment;\n} _z_transport_body_t;\n\ntypedef struct {\n    _z_transport_body_t _body;\n    uint8_t _header;\n} _z_transport_message_t;\nvoid _z_t_msg_clear(_z_transport_message_t *msg);\n\nz_reliability_t _z_t_msg_get_reliability(_z_transport_message_t *msg);\n\n/*------------------ Builders ------------------*/\n_z_transport_message_t _z_t_msg_make_join(z_whatami_t whatami, _z_zint_t lease, _z_id_t zid,\n                                          _z_conduit_sn_list_t next_sn);\n_z_transport_message_t _z_t_msg_make_init_syn(z_whatami_t whatami, _z_id_t zid);\n_z_transport_message_t _z_t_msg_make_init_ack(z_whatami_t whatami, _z_id_t zid, _z_slice_t cookie);\n_z_transport_message_t _z_t_msg_make_open_syn(_z_zint_t lease, _z_zint_t initial_sn, _z_slice_t cookie);\n_z_transport_message_t _z_t_msg_make_open_ack(_z_zint_t lease, _z_zint_t initial_sn);\n_z_transport_message_t _z_t_msg_make_close(uint8_t reason, bool link_only);\n_z_transport_message_t _z_t_msg_make_keep_alive(void);\n_z_transport_message_t _z_t_msg_make_frame(_z_zint_t sn, _z_zbuf_t *payload, z_reliability_t reliability);\n_z_transport_message_t _z_t_msg_make_frame_header(_z_zint_t sn, z_reliability_t reliability);\n_z_transport_message_t _z_t_msg_make_fragment_header(_z_zint_t sn, z_reliability_t reliability, bool is_last,\n                                                     bool first, bool drop);\n_z_transport_message_t _z_t_msg_make_fragment(_z_zint_t sn, _z_slice_t messages, z_reliability_t reliability,\n                                              bool is_last, bool first, bool drop);\n\n/*------------------ Copy ------------------*/\nvoid _z_t_msg_copy(_z_transport_message_t *clone, _z_transport_message_t *msg);\nvoid _z_t_msg_copy_join(_z_t_msg_join_t *clone, _z_t_msg_join_t *msg);\nvoid _z_t_msg_copy_init(_z_t_msg_init_t *clone, _z_t_msg_init_t *msg);\nvoid _z_t_msg_copy_open(_z_t_msg_open_t *clone, _z_t_msg_open_t *msg);\nvoid _z_t_msg_copy_close(_z_t_msg_close_t *clone, _z_t_msg_close_t *msg);\nvoid _z_t_msg_copy_keep_alive(_z_t_msg_keep_alive_t *clone, _z_t_msg_keep_alive_t *msg);\nvoid _z_t_msg_copy_frame(_z_t_msg_frame_t *clone, _z_t_msg_frame_t *msg);\n\ntypedef union {\n    _z_s_msg_scout_t _scout;\n    _z_s_msg_hello_t _hello;\n} _z_scouting_body_t;\n\ntypedef struct {\n    _z_scouting_body_t _body;\n    uint8_t _header;\n} _z_scouting_message_t;\nvoid _z_s_msg_clear(_z_scouting_message_t *msg);\n\n_z_scouting_message_t _z_s_msg_make_scout(z_what_t what, _z_id_t zid);\n_z_scouting_message_t _z_s_msg_make_hello(z_whatami_t whatami, _z_id_t zid, _z_locator_array_t locators);\n\nvoid _z_s_msg_copy(_z_scouting_message_t *clone, _z_scouting_message_t *msg);\nvoid _z_s_msg_copy_scout(_z_s_msg_scout_t *clone, _z_s_msg_scout_t *msg);\nvoid _z_s_msg_copy_hello(_z_s_msg_hello_t *clone, _z_s_msg_hello_t *msg);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_PROTOCOL_DEFINITIONS_TRANSPORT_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/ext.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_PROTOCOL_EXTENSION_H\n#define ZENOH_PICO_PROTOCOL_EXTENSION_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*=============================*/\n/*       Message header        */\n/*=============================*/\n#define _Z_EXT_FULL_ID_MASK 0x7F\n#define _Z_EXT_ID_MASK 0x0F\n#define _Z_EXT_ENC_MASK 0x60\n\n/*=============================*/\n/*       Message helpers       */\n/*=============================*/\n#define _Z_EXT_FULL_ID(h) (_Z_EXT_FULL_ID_MASK & h)\n#define _Z_EXT_ID(h) (_Z_EXT_ID_MASK & h)\n#define _Z_EXT_ENC(h) (_Z_EXT_ENC_MASK & h)\n#define _Z_EXT_HAS_FLAG(h, f) ((h & f) != 0)\n#define _Z_EXT_SET_FLAG(h, f) (h |= f)\n\n/*=============================*/\n/*        Extension IDs        */\n/*=============================*/\n#define _Z_MSG_EXT_ID_JOIN_QOS (0x01 | _Z_MSG_EXT_FLAG_M | _Z_MSG_EXT_ENC_ZBUF)\n#define _Z_MSG_EXT_ID_JOIN_PATCH (0x07 | _Z_MSG_EXT_ENC_ZINT)\n#define _Z_MSG_EXT_ID_INIT_PATCH (0x07 | _Z_MSG_EXT_ENC_ZINT)\n#define _Z_MSG_EXT_ID_FRAGMENT_FIRST (0x02 | _Z_MSG_EXT_ENC_UNIT)\n#define _Z_MSG_EXT_ID_FRAGMENT_DROP (0x03 | _Z_MSG_EXT_ENC_UNIT)\n\n/*=============================*/\n/*     Extension Encodings     */\n/*=============================*/\n#define _Z_MSG_EXT_ENC_UNIT 0x00  // 0x00 << 5\n#define _Z_MSG_EXT_ENC_ZINT 0x20  // 0x01 << 5\n#define _Z_MSG_EXT_ENC_ZBUF 0x40  // 0x10 << 5\n\n/*=============================*/\n/*       Extension flags       */\n/*=============================*/\n#define _Z_MSG_EXT_FLAG_M 0x10\n#define _Z_MSG_EXT_IS_MANDATORY(h) ((h & _Z_MSG_EXT_FLAG_M) != 0)\n#define _Z_MSG_EXT_FLAG_Z 0x80\n#define _Z_MSG_EXT_MORE(more) (more ? _Z_MSG_EXT_FLAG_Z : 0)\n\ntypedef struct {\n    uint8_t __dummy;  // Just to avoid empty structures that might cause undefined behavior\n} _z_msg_ext_unit_t;\nvoid _z_msg_ext_clear_unit(_z_msg_ext_unit_t *ext);\n\n/*------------------ ZID Extension ------------------*/\ntypedef struct {\n    uint64_t _val;\n} _z_msg_ext_zint_t;\nvoid _z_msg_ext_clear_zint(_z_msg_ext_zint_t *ext);\n\n/*------------------ Unknown Extension ------------------*/\ntypedef struct {\n    _z_slice_t _val;\n} _z_msg_ext_zbuf_t;\nvoid _z_msg_ext_clear_zbuf(_z_msg_ext_zbuf_t *ext);\n\n/*------------------ Message Extensions ------------------*/\ntypedef union {\n    _z_msg_ext_unit_t _unit;\n    _z_msg_ext_zint_t _zint;\n    _z_msg_ext_zbuf_t _zbuf;\n} _z_msg_ext_body_t;\n\ntypedef struct {\n    _z_msg_ext_body_t _body;\n    uint8_t _header;\n} _z_msg_ext_t;\nvoid _z_msg_ext_clear(_z_msg_ext_t *ext);\n\n/*------------------ Builders ------------------*/\n_z_msg_ext_t _z_msg_ext_make_unit(uint8_t id);\n_z_msg_ext_t _z_msg_ext_make_zint(uint8_t id, _z_zint_t zid);\n_z_msg_ext_t _z_msg_ext_make_zbuf(uint8_t id, _z_slice_t zbuf);\n\n/*------------------ Copy ------------------*/\nvoid _z_msg_ext_copy(_z_msg_ext_t *clone, const _z_msg_ext_t *ext);\nvoid _z_msg_ext_copy_unit(_z_msg_ext_unit_t *clone, const _z_msg_ext_unit_t *ext);\nvoid _z_msg_ext_copy_zint(_z_msg_ext_zint_t *clone, const _z_msg_ext_zint_t *ext);\nvoid _z_msg_ext_copy_zbuf(_z_msg_ext_zbuf_t *clone, const _z_msg_ext_zbuf_t *ext);\n\n_Z_ELEM_DEFINE(_z_msg_ext, _z_msg_ext_t, _z_noop_size, _z_msg_ext_clear, _z_msg_ext_copy, _z_noop_move, _z_noop_eq,\n               _z_noop_cmp, _z_noop_hash)\n_Z_VEC_DEFINE(_z_msg_ext, _z_msg_ext_t)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_PROTOCOL_EXTENSION_H */\n"
  },
  {
    "path": "include/zenoh-pico/protocol/iobuf.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_PROTOCOL_IOBUF_H\n#define ZENOH_PICO_PROTOCOL_IOBUF_H\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/arc_slice.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/vec.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ IOSli ------------------*/\n\ntypedef struct {\n    size_t _r_pos;\n    size_t _w_pos;\n    size_t _capacity;\n    uint8_t *_buf;\n    bool _is_alloc;\n} _z_iosli_t;\n\nstatic inline _z_iosli_t _z_iosli_null(void) { return (_z_iosli_t){0}; }\nstatic inline size_t _z_iosli_writable(const _z_iosli_t *ios) { return ios->_capacity - ios->_w_pos; }\nstatic inline size_t _z_iosli_readable(const _z_iosli_t *ios) { return ios->_w_pos - ios->_r_pos; }\nstatic inline bool _z_iosli_can_write(const _z_iosli_t *ios) { return ios->_capacity > ios->_w_pos; }\nstatic inline bool _z_iosli_can_read(const _z_iosli_t *ios) { return ios->_w_pos > ios->_r_pos; }\nstatic inline uint8_t _z_iosli_read(_z_iosli_t *ios) {\n    assert(ios->_r_pos < ios->_w_pos);\n    return ios->_buf[ios->_r_pos++];\n}\nstatic inline uint8_t *_z_iosli_read_as_ref(_z_iosli_t *ios) {\n    assert(ios->_r_pos < ios->_w_pos);\n    return &ios->_buf[ios->_r_pos++];\n}\nstatic inline void _z_iosli_write(_z_iosli_t *ios, uint8_t b) {\n    assert(ios->_capacity > ios->_w_pos);\n    ios->_buf[ios->_w_pos++] = b;\n}\nstatic inline uint8_t _z_iosli_get(const _z_iosli_t *ios, size_t pos) {\n    assert(pos < ios->_capacity);\n    return ios->_buf[pos];\n}\nstatic inline void _z_iosli_put(_z_iosli_t *ios, uint8_t b, size_t pos) {\n    assert(pos < ios->_capacity);\n    ios->_buf[pos] = b;\n}\nstatic inline void _z_iosli_reset(_z_iosli_t *ios) {\n    ios->_r_pos = 0;\n    ios->_w_pos = 0;\n}\nstatic inline size_t _z_iosli_size(const _z_iosli_t *ios) {\n    (void)(ios);\n    return sizeof(_z_iosli_t);\n}\nstatic inline void _z_iosli_read_bytes(_z_iosli_t *ios, uint8_t *dst, size_t offset, size_t length) {\n    assert(_z_iosli_readable(ios) >= length);\n    uint8_t *w_pos = _z_ptr_u8_offset(dst, (ptrdiff_t)offset);\n    (void)memcpy(w_pos, ios->_buf + ios->_r_pos, length);\n    ios->_r_pos = ios->_r_pos + length;\n}\nstatic inline void _z_iosli_copy_bytes(_z_iosli_t *dst, const _z_iosli_t *src) {\n    size_t length = _z_iosli_readable(src);\n    assert(dst->_capacity >= length);\n    (void)memcpy(dst->_buf + dst->_w_pos, src->_buf + src->_r_pos, length);\n    dst->_w_pos += length;\n}\nstatic inline void _z_iosli_write_bytes(_z_iosli_t *ios, const uint8_t *bs, size_t offset, size_t length) {\n    assert(_z_iosli_writable(ios) >= length);\n    uint8_t *w_pos = _z_ptr_u8_offset(ios->_buf, (ptrdiff_t)ios->_w_pos);\n    (void)memcpy(w_pos, _z_cptr_u8_offset(bs, (ptrdiff_t)offset), length);\n    ios->_w_pos += length;\n}\n\n_z_iosli_t _z_iosli_make(size_t capacity);\n_z_iosli_t *_z_iosli_new(size_t capacity);\n_z_iosli_t _z_iosli_wrap(const uint8_t *buf, size_t length, size_t r_pos, size_t w_pos);\n_z_iosli_t _z_iosli_steal(_z_iosli_t *ios);\n_z_slice_t _z_iosli_to_bytes(const _z_iosli_t *ios);\nsize_t _z_iosli_size(const _z_iosli_t *ios);\nvoid _z_iosli_clear(_z_iosli_t *ios);\nvoid _z_iosli_free(_z_iosli_t **ios);\nvoid _z_iosli_copy(_z_iosli_t *dst, const _z_iosli_t *src);\n_z_iosli_t *_z_iosli_clone(const _z_iosli_t *src);\n\n_Z_ELEM_DEFINE(_z_iosli, _z_iosli_t, _z_iosli_size, _z_iosli_clear, _z_iosli_copy, _z_noop_move, _z_noop_eq,\n               _z_noop_cmp, _z_noop_hash)\n_Z_SVEC_DEFINE(_z_iosli, _z_iosli_t)\n\n/*------------------ ZBuf ------------------*/\ntypedef struct {\n    _z_iosli_t _ios;\n    _z_slice_simple_rc_t _slice;\n} _z_zbuf_t;\n\nstatic inline size_t _z_zbuf_get_ref_count(const _z_zbuf_t *zbf) { return _z_slice_simple_rc_count(&zbf->_slice); }\nstatic inline _z_zbuf_t _z_zbuf_null(void) { return (_z_zbuf_t){0}; }\nstatic inline void _z_zbuf_reset(_z_zbuf_t *zbf) { _z_iosli_reset(&zbf->_ios); }\n\nstatic inline uint8_t const *_z_zbuf_start(const _z_zbuf_t *zbf) {\n    return _z_ptr_u8_offset(zbf->_ios._buf, (ptrdiff_t)zbf->_ios._r_pos);\n}\nstatic inline size_t _z_zbuf_capacity(const _z_zbuf_t *zbf) { return zbf->_ios._capacity; }\nstatic inline size_t _z_zbuf_space_left(const _z_zbuf_t *zbf) { return _z_iosli_writable(&zbf->_ios); }\n\nstatic inline size_t _z_zbuf_len(const _z_zbuf_t *zbf) { return _z_iosli_readable(&zbf->_ios); }\nstatic inline bool _z_zbuf_can_read(const _z_zbuf_t *zbf) { return _z_iosli_can_read(&zbf->_ios); }\nstatic inline uint8_t _z_zbuf_read(_z_zbuf_t *zbf) { return _z_iosli_read(&zbf->_ios); }\nstatic inline uint8_t *_z_zbuf_read_as_ref(_z_zbuf_t *zbf) { return _z_iosli_read_as_ref(&zbf->_ios); }\nstatic inline uint8_t _z_zbuf_get(const _z_zbuf_t *zbf, size_t pos) { return _z_iosli_get(&zbf->_ios, pos); }\n\nstatic inline size_t _z_zbuf_get_rpos(const _z_zbuf_t *zbf) { return zbf->_ios._r_pos; }\nstatic inline size_t _z_zbuf_get_wpos(const _z_zbuf_t *zbf) { return zbf->_ios._w_pos; }\nstatic inline void _z_zbuf_set_rpos(_z_zbuf_t *zbf, size_t r_pos) {\n    assert(r_pos <= zbf->_ios._w_pos);\n    zbf->_ios._r_pos = r_pos;\n}\nstatic inline void _z_zbuf_set_wpos(_z_zbuf_t *zbf, size_t w_pos) {\n    assert(w_pos <= zbf->_ios._capacity);\n    zbf->_ios._w_pos = w_pos;\n}\nstatic inline uint8_t *_z_zbuf_get_rptr(const _z_zbuf_t *zbf) { return zbf->_ios._buf + zbf->_ios._r_pos; }\nstatic inline uint8_t *_z_zbuf_get_wptr(const _z_zbuf_t *zbf) { return zbf->_ios._buf + zbf->_ios._w_pos; }\n\n// Constructs a _borrowing_ reader on `slice`\n_z_zbuf_t _z_zbuf_make(size_t capacity);\n_z_zbuf_t _z_zbuf_view(_z_zbuf_t *zbf, size_t length);\n_z_zbuf_t _z_slice_as_zbuf(_z_slice_t slice);\n\nvoid _z_zbuf_copy_bytes(_z_zbuf_t *dst, const _z_zbuf_t *src);\nvoid _z_zbuf_copy(_z_zbuf_t *dst, const _z_zbuf_t *src);\nvoid _z_zbuf_read_bytes(_z_zbuf_t *zbf, uint8_t *dest, size_t offset, size_t length);\nvoid _z_zbuf_compact(_z_zbuf_t *zbf);\nvoid _z_zbuf_clear(_z_zbuf_t *zbf);\nvoid _z_zbuf_free(_z_zbuf_t **zbf);\n\n/*------------------ WBuf ------------------*/\ntypedef struct {\n    _z_iosli_svec_t _ioss;\n    size_t _r_idx;\n    size_t _w_idx;\n    size_t _expansion_step;\n} _z_wbuf_t;\n\nstatic inline _z_wbuf_t _z_wbuf_null(void) { return (_z_wbuf_t){0}; }\nstatic inline _z_iosli_t *_z_wbuf_get_iosli(const _z_wbuf_t *wbf, size_t idx) {\n    return _z_iosli_svec_get(&wbf->_ioss, idx);\n}\n_z_wbuf_t _z_wbuf_make(size_t capacity, bool is_expandable);\n\nsize_t _z_wbuf_capacity(const _z_wbuf_t *wbf);\nsize_t _z_wbuf_len(const _z_wbuf_t *wbf);\nsize_t _z_wbuf_space_left(const _z_wbuf_t *wbf);\n\nz_result_t _z_wbuf_write(_z_wbuf_t *wbf, uint8_t b);\nz_result_t _z_wbuf_write_bytes(_z_wbuf_t *wbf, const uint8_t *bs, size_t offset, size_t length);\nz_result_t _z_wbuf_wrap_bytes(_z_wbuf_t *wbf, const uint8_t *bs, size_t offset, size_t length);\nvoid _z_wbuf_put(_z_wbuf_t *wbf, uint8_t b, size_t pos);\n\nsize_t _z_wbuf_get_rpos(const _z_wbuf_t *wbf);\nsize_t _z_wbuf_get_wpos(const _z_wbuf_t *wbf);\nvoid _z_wbuf_set_rpos(_z_wbuf_t *wbf, size_t r_pos);\nvoid _z_wbuf_set_wpos(_z_wbuf_t *wbf, size_t w_pos);\n\nsize_t _z_wbuf_len_iosli(const _z_wbuf_t *wbf);\n\n_z_zbuf_t _z_wbuf_to_zbuf(const _z_wbuf_t *wbf);\n_z_zbuf_t _z_wbuf_moved_as_zbuf(_z_wbuf_t *wbf);\nz_result_t _z_wbuf_siphon(_z_wbuf_t *dst, _z_wbuf_t *src, size_t length);\n\nvoid _z_wbuf_copy(_z_wbuf_t *dst, const _z_wbuf_t *src);\nvoid _z_wbuf_reset(_z_wbuf_t *wbf);\nvoid _z_wbuf_clear(_z_wbuf_t *wbf);\nvoid _z_wbuf_free(_z_wbuf_t **wbf);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_PROTOCOL_IOBUF_H */\n"
  },
  {
    "path": "include/zenoh-pico/runtime/background_executor.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COLLECTIONS_BACKGROUND_EXECUTOR_H\n#define ZENOH_PICO_COLLECTIONS_BACKGROUND_EXECUTOR_H\n\n#include \"zenoh-pico/config.h\"\n#if Z_FEATURE_MULTI_THREAD == 1\n#include <stddef.h>\n\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/runtime/executor.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _z_background_executor_inner_t _z_background_executor_inner_t;\nvoid _z_background_executor_inner_clear(_z_background_executor_inner_t *be);\n\n_Z_REFCOUNT_DEFINE_NO_FROM_VAL(_z_background_executor_inner, _z_background_executor_inner)\n\ntypedef struct _z_background_executor_t {\n    _z_background_executor_inner_rc_t _inner;\n} _z_background_executor_t;\n\nz_result_t _z_background_executor_init(_z_background_executor_t *be, z_task_attr_t *task_attr);\n// Initializes the executor without spawning a background thread.\n// Tasks can be added via _z_background_executor_spawn but won't be executed until\n// _z_background_executor_start is called.\nz_result_t _z_background_executor_init_deferred(_z_background_executor_t *be);\n// Spawns a background thread to run an executor that was previously created with _z_background_executor_init_deferred.\n// Returns _Z_RES_OK in case of success or if the executor is already running, non-zero value otherwise.\nz_result_t _z_background_executor_start(_z_background_executor_t *be, z_task_attr_t *task_attr);\n// Stops the background executor thread without destroying the executor.\n// Pending tasks are preserved and can be executed after restarting with _z_background_executor_start.\n// Returns _Z_RES_OK in case of success or if the executor was already stopped, non-zero value otherwise.\nz_result_t _z_background_executor_stop(_z_background_executor_t *be);\nstatic inline void _z_background_executor_null(_z_background_executor_t *be) {\n    be->_inner = _z_background_executor_inner_rc_null();\n}\n// Spawns a future to be executed in the background.\n// The caller can optionally receive a handle to the future, which can be used to check the future's status or cancel\n// it. If the caller does not care about the future's status, they can pass NULL as opt_handle_out.\nz_result_t _z_background_executor_spawn(_z_background_executor_t *be, _z_fut_t *fut, _z_fut_handle_t *opt_handle_out);\nz_result_t _z_background_executor_suspend(_z_background_executor_t *be);\nz_result_t _z_background_executor_resume(_z_background_executor_t *be);\nvoid _z_background_executor_destroy(_z_background_executor_t *be);\nz_result_t _z_background_executor_get_fut_status(_z_background_executor_t *be, const _z_fut_handle_t *handle,\n                                                 _z_fut_status_t *status_out);\nz_result_t _z_background_executor_cancel_fut(_z_background_executor_t *be, const _z_fut_handle_t *handle);\nz_result_t _z_background_executor_clone(_z_background_executor_t *dst, const _z_background_executor_t *src);\nbool _z_background_executor_is_running(const _z_background_executor_t *be);\n#ifdef __cplusplus\n}\n#endif\n#endif /* Z_FEATURE_MULTI_THREAD */\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/runtime/executor.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_RUNTIME_EXECUTOR_H\n#define ZENOH_PICO_RUNTIME_EXECUTOR_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/atomic.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef enum _z_fut_status_t {\n    _Z_FUT_STATUS_RUNNING = 0,\n    _Z_FUT_STATUS_READY = 1,\n    _Z_FUT_STATUS_SLEEPING = 2,\n    _Z_FUT_STATUS_SUSPENDED = 3,\n} _z_fut_status_t;\n\ntypedef struct _z_fut_handle_t {\n    size_t _id;\n} _z_fut_handle_t;\n\nstatic inline _z_fut_handle_t _z_fut_handle_null(void) {\n    _z_fut_handle_t handle;\n    handle._id = 0;\n    return handle;\n}\n\nstatic inline bool _z_fut_handle_is_null(_z_fut_handle_t handle) { return handle._id == 0; }\n\ntypedef struct _z_fut_fn_result_t {\n    _z_fut_status_t _status;\n    z_clock_t _wake_up_time;\n} _z_fut_fn_result_t;\n\nstatic inline _z_fut_fn_result_t _z_fut_fn_result_ready(void) {\n    _z_fut_fn_result_t result;\n    result._status = _Z_FUT_STATUS_READY;\n    return result;\n}\n\nstatic inline _z_fut_fn_result_t _z_fut_fn_result_continue(void) {\n    _z_fut_fn_result_t result;\n    result._status = _Z_FUT_STATUS_RUNNING;\n    return result;\n}\n\nstatic inline _z_fut_fn_result_t _z_fut_fn_result_suspend(void) {\n    _z_fut_fn_result_t result;\n    result._status = _Z_FUT_STATUS_SUSPENDED;\n    return result;\n}\n\nstatic inline _z_fut_fn_result_t _z_fut_fn_result_wake_up_after(unsigned long wake_up_time_ms) {\n    _z_fut_fn_result_t result;\n    result._status = _Z_FUT_STATUS_SLEEPING;\n    result._wake_up_time = z_clock_now();\n    z_clock_advance_ms(&result._wake_up_time, wake_up_time_ms);\n    return result;\n}\n\ntypedef struct _z_executor_t _z_executor_t;\ntypedef _z_fut_fn_result_t (*_z_fut_fn_t)(void *arg, _z_executor_t *executor);\ntypedef void (*_z_fut_destroy_fn_t)(void *arg);\n\ntypedef struct _z_fut_t {\n    void *_fut_arg;\n    _z_fut_fn_t _fut_fn;\n    _z_fut_destroy_fn_t _destroy_fn;\n} _z_fut_t;\n\nstatic inline void _z_fut_destroy(_z_fut_t *fut) {\n    if (fut->_destroy_fn != NULL) {\n        fut->_destroy_fn(fut->_fut_arg);\n    }\n    fut->_fut_arg = NULL;\n    fut->_fut_fn = NULL;\n    fut->_destroy_fn = NULL;\n}\n\nstatic inline void _z_fut_move(_z_fut_t *dst, _z_fut_t *src) {\n    dst->_fut_arg = src->_fut_arg;\n    dst->_fut_fn = src->_fut_fn;\n    dst->_destroy_fn = src->_destroy_fn;\n\n    // Clear source\n    src->_fut_arg = NULL;\n    src->_fut_fn = NULL;\n    src->_destroy_fn = NULL;\n}\n\nstatic inline _z_fut_t _z_fut_new(void *arg, _z_fut_fn_t fut_fn, _z_fut_destroy_fn_t destroy_fn) {\n    _z_fut_t fut;\n    fut._fut_arg = arg;\n    fut._fut_fn = fut_fn;\n    fut._destroy_fn = destroy_fn;\n    return fut;\n}\n\nstatic inline _z_fut_t _z_fut_null(void) { return _z_fut_new(NULL, NULL, NULL); }\n\nstatic inline bool _z_fut_is_null(const _z_fut_t *fut) { return fut->_fut_fn == NULL; }\n\n// _z_fut_schedule_t packs status (bits [7:0]) and wake-up time in ms (bits [63:8]) into a single uint64_t.\n// The wake-up time is only meaningful when status == _Z_FUT_STATUS_SLEEPING.\n// This gives a maximum schedulable wake-up offset of 2^56 ms (~2.28 billion years) from the executor epoch.\ntypedef uint64_t _z_fut_schedule_t;\n\n#define _Z_FUT_SCHEDULE_STATUS_MASK ((uint64_t)0xFFu)\n#define _Z_FUT_SCHEDULE_TIME_SHIFT 8u\n\nstatic inline _z_fut_status_t _z_fut_schedule_get_status(const _z_fut_schedule_t s) {\n    return (_z_fut_status_t)(s & _Z_FUT_SCHEDULE_STATUS_MASK);\n}\nstatic inline uint64_t _z_fut_schedule_get_wake_up_time_ms(const _z_fut_schedule_t s) {\n    return s >> _Z_FUT_SCHEDULE_TIME_SHIFT;\n}\n\nstatic inline _z_fut_schedule_t _z_fut_schedule_running(void) { return (uint64_t)_Z_FUT_STATUS_RUNNING; }\nstatic inline _z_fut_schedule_t _z_fut_schedule_ready(void) { return (uint64_t)_Z_FUT_STATUS_READY; }\nstatic inline _z_fut_schedule_t _z_fut_schedule_sleeping(uint64_t wake_up_time_ms) {\n    return (uint64_t)_Z_FUT_STATUS_SLEEPING | (wake_up_time_ms << _Z_FUT_SCHEDULE_TIME_SHIFT);\n}\nstatic inline _z_fut_schedule_t _z_fut_schedule_suspended(void) { return (uint64_t)_Z_FUT_STATUS_SUSPENDED; }\n\ntypedef struct _z_fut_data_t {\n    _z_fut_t _fut;\n    _z_fut_schedule_t _schedule;\n} _z_fut_data_t;\n\nstatic inline void _z_fut_data_destroy(_z_fut_data_t *data) {\n    _z_fut_destroy(&data->_fut);\n    data->_schedule = _z_fut_schedule_ready();  // Reset status to ready after destroy\n}\n\nstatic inline void _z_fut_data_move(_z_fut_data_t *dst, _z_fut_data_t *src) {\n    _z_fut_move(&dst->_fut, &src->_fut);\n    dst->_schedule = src->_schedule;\n    src->_schedule = _z_fut_schedule_ready();\n}\n\nstatic inline size_t _z_size_fut_data_hmap_hash(const size_t *key) { return *key; }\n\n#ifndef _ZP_EXECUTOR_MAX_NUM_FUTURES\n#define _ZP_EXECUTOR_MAX_NUM_FUTURES 64\n#endif\n\n#define _ZP_EXECUTOR_MAX_FUT_BUCKET_COUNT (_ZP_EXECUTOR_MAX_NUM_FUTURES * 3 / 2)  // 0.66 load factor\n\n#define _ZP_HASHMAP_TEMPLATE_KEY_TYPE size_t\n#define _ZP_HASHMAP_TEMPLATE_VAL_TYPE _z_fut_data_t\n#define _ZP_HASHMAP_TEMPLATE_NAME _z_fut_data_hmap\n#define _ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME _z_size_fut_data_hmap_hash\n#define _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT _ZP_EXECUTOR_MAX_FUT_BUCKET_COUNT\n#define _ZP_HASHMAP_TEMPLATE_CAPACITY _ZP_EXECUTOR_MAX_NUM_FUTURES\n#define _ZP_HASHMAP_TEMPLATE_VAL_DESTROY_FN_NAME _z_fut_data_destroy\n#define _ZP_HASHMAP_TEMPLATE_VAL_MOVE_FN_NAME _z_fut_data_move\n#include \"zenoh-pico/collections/hashmap_template.h\"\n\n#define _ZP_DEQUE_TEMPLATE_ELEM_TYPE _z_fut_data_hmap_index_t\n#define _ZP_DEQUE_TEMPLATE_NAME _z_fut_data_hmap_index_deque\n#define _ZP_DEQUE_TEMPLATE_SIZE _ZP_EXECUTOR_MAX_NUM_FUTURES\n#include \"zenoh-pico/collections/deque_template.h\"\n\n// Compare two sleeping-task indices by their wake-up time stored in the hashmap.\n// The context is a pointer to the task hashmap, which provides the wake-up times.\nstatic inline int _z_sleeping_fut_idx_cmp(const _z_fut_data_hmap_index_t *a, const _z_fut_data_hmap_index_t *b,\n                                          const _z_fut_data_hmap_t *tasks) {\n    uint64_t ta =\n        _z_fut_schedule_get_wake_up_time_ms(_z_fut_data_hmap_node_at((_z_fut_data_hmap_t *)tasks, *a)->val._schedule);\n    uint64_t tb =\n        _z_fut_schedule_get_wake_up_time_ms(_z_fut_data_hmap_node_at((_z_fut_data_hmap_t *)tasks, *b)->val._schedule);\n    if (ta < tb) return -1;\n    if (ta > tb) return 1;\n    return 0;\n}\n\n#define _ZP_PQUEUE_TEMPLATE_ELEM_TYPE _z_fut_data_hmap_index_t\n#define _ZP_PQUEUE_TEMPLATE_NAME _z_sleeping_fut_pqueue\n#define _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE _z_fut_data_hmap_t\n#define _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME _z_sleeping_fut_idx_cmp\n#define _ZP_PQUEUE_TEMPLATE_SIZE _ZP_EXECUTOR_MAX_NUM_FUTURES\n#include \"zenoh-pico/collections/pqueue_template.h\"\n\ntypedef struct _z_executor_t {\n    _z_fut_data_hmap_index_deque_t _ready_tasks;\n    _z_sleeping_fut_pqueue_t _sleeping_tasks;\n    _z_fut_data_hmap_t _tasks;\n    z_clock_t _epoch;\n    size_t _next_fut_id;\n} _z_executor_t;\n\nstatic inline void _z_executor_null(_z_executor_t *executor) {\n    executor->_ready_tasks = _z_fut_data_hmap_index_deque_new();\n    executor->_sleeping_tasks = _z_sleeping_fut_pqueue_new();\n    executor->_tasks = _z_fut_data_hmap_new();\n    executor->_next_fut_id = 0;\n    // Set context after _tasks is initialised so the pointer is valid.\n    _z_sleeping_fut_pqueue_set_ctx(&executor->_sleeping_tasks, &executor->_tasks);\n}\n\nstatic inline void _z_executor_init(_z_executor_t *executor) {\n    _z_executor_null(executor);\n    executor->_epoch = z_clock_now();\n}\n\nstatic inline _z_executor_t _z_executor_new(void) {\n    _z_executor_t executor;\n    _z_executor_init(&executor);\n    return executor;\n}\n\nstatic inline void _z_executor_destroy(_z_executor_t *executor) {\n    _z_fut_data_hmap_index_deque_destroy(&executor->_ready_tasks);\n    _z_sleeping_fut_pqueue_destroy(&executor->_sleeping_tasks);\n    _z_fut_data_hmap_destroy(&executor->_tasks);\n}\n\n// Spawn a new future to be executed.\n// The executor takes the ownership of the future, and will destroy the future (by calling the destroy_fn) when the\n// future is finished or cancelled. The caller can use the future handle to cancel the future or check its status.\n_z_fut_handle_t _z_executor_spawn(_z_executor_t *executor, _z_fut_t *fut);\n\ntypedef enum _z_executor_spin_result_status_t {\n    _Z_EXECUTOR_SPIN_RESULT_NO_TASKS,\n    _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK,\n    _Z_EXECUTOR_SPIN_RESULT_SHOULD_WAIT,\n    _Z_EXECUTOR_SPIN_RESULT_FAILED,\n} _z_executor_spin_result_status_t;\ntypedef struct _z_executor_spin_result_t {\n    _z_executor_spin_result_status_t status;\n    z_clock_t next_wake_up_time;\n} _z_executor_spin_result_t;\n\n_z_executor_spin_result_t _z_executor_spin(_z_executor_t *executor);\n\n_z_fut_status_t _z_executor_get_fut_status(const _z_executor_t *executor, const _z_fut_handle_t *handle);\nbool _z_executor_cancel_fut(_z_executor_t *executor, const _z_fut_handle_t *handle);\nbool _z_executor_resume_suspended_fut(_z_executor_t *executor, const _z_fut_handle_t *handle);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/runtime/runtime.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_RUNTIME_RUNTIME_H\n#define ZENOH_PICO_RUNTIME_RUNTIME_H\n\n#include \"zenoh-pico/config.h\"\n\n#define _ZP_EXECUTOR_MAX_NUM_FUTURES Z_RUNTIME_MAX_TASKS\n#if Z_FEATURE_MULTI_THREAD == 1\n#include \"zenoh-pico/runtime/background_executor.h\"\n#else\n#include \"zenoh-pico/runtime/executor.h\"\n#endif\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef _z_background_executor_t _z_runtime_t;\nstatic inline _z_fut_handle_t _z_runtime_spawn(_z_runtime_t *runtime, _z_fut_t *fut) {\n    _z_fut_handle_t handle;\n    _z_background_executor_spawn(runtime, fut, &handle);\n    return handle;\n}\nstatic inline z_result_t _z_runtime_cancel_fut(_z_runtime_t *runtime, _z_fut_handle_t *handle) {\n    return _z_background_executor_cancel_fut(runtime, handle);\n}\nstatic inline z_result_t _z_runtime_init(_z_runtime_t *runtime) {\n    return _z_background_executor_init_deferred(runtime);\n}\nstatic inline void _z_runtime_clear(_z_runtime_t *runtime) { _z_background_executor_destroy(runtime); }\nstatic inline void _z_runtime_null(_z_runtime_t *runtime) { _z_background_executor_null(runtime); }\nstatic inline z_result_t _z_runtime_start(_z_runtime_t *runtime, z_task_attr_t *task_attr) {\n    return _z_background_executor_start(runtime, task_attr);\n}\n\nstatic inline z_result_t _z_runtime_stop(_z_runtime_t *runtime) { return _z_background_executor_stop(runtime); }\n#else\ntypedef _z_executor_t _z_runtime_t;\nstatic inline _z_fut_handle_t _z_runtime_spawn(_z_runtime_t *runtime, _z_fut_t *fut) {\n    return _z_executor_spawn(runtime, fut);\n}\nstatic inline z_result_t _z_runtime_init(_z_runtime_t *runtime) {\n    _z_executor_init(runtime);\n    return _Z_RES_OK;\n}\nstatic inline void _z_runtime_clear(_z_runtime_t *runtime) { _z_executor_destroy(runtime); }\nstatic inline void _z_runtime_null(_z_runtime_t *runtime) { _z_executor_null(runtime); }\nstatic inline z_result_t _z_runtime_cancel_fut(_z_runtime_t *runtime, _z_fut_handle_t *handle) {\n    _z_executor_cancel_fut(runtime, handle);\n    return _Z_RES_OK;\n}\nstatic inline void _z_runtime_spin_once(_z_runtime_t *runtime) { _z_executor_spin(runtime); }\n\nstatic inline z_result_t _z_runtime_stop(_z_runtime_t *runtime) {\n    _ZP_UNUSED(runtime);\n    return _Z_RES_OK;\n}\n#endif\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/session/cancellation.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SESSION_CANCELLATION_H\n#define ZENOH_PICO_SESSION_CANCELLATION_H\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/sync_group.h\"\n#include \"zenoh-pico/system/platform.h\"\n\ntypedef z_result_t (*_z_cancellation_token_on_cancel_handler_callback)(void* arg);\ntypedef void (*_z_cancellation_token_on_cancel_handler_dropper)(void* arg);\n\ntypedef struct {\n    _z_cancellation_token_on_cancel_handler_callback _on_cancel;\n    _z_cancellation_token_on_cancel_handler_dropper _on_drop;\n    void* _arg;\n} _z_cancellation_token_on_cancel_handler_t;\n\nz_result_t _z_cancellation_token_on_cancel_handler_call(_z_cancellation_token_on_cancel_handler_t* handler);\n\nstatic inline _z_cancellation_token_on_cancel_handler_t _z_cancellation_token_on_cancel_handler_null(void) {\n    _z_cancellation_token_on_cancel_handler_t h = {0};\n    return h;\n}\n\nstatic inline void _z_cancellation_token_on_cancel_handler_drop(_z_cancellation_token_on_cancel_handler_t* h) {\n    if (h->_on_drop != NULL) {\n        h->_on_drop(h->_arg);\n    }\n    h->_on_cancel = NULL;\n    h->_arg = NULL;\n    h->_on_drop = NULL;\n}\n\nstatic inline void _z_cancellation_token_on_cancel_handler_move(_z_cancellation_token_on_cancel_handler_t* dst,\n                                                                _z_cancellation_token_on_cancel_handler_t* src) {\n    *dst = *src;\n    *src = _z_cancellation_token_on_cancel_handler_null();\n}\n\n_Z_ELEM_DEFINE(_z_cancellation_token_on_cancel_handler, _z_cancellation_token_on_cancel_handler_t, _z_noop_size,\n               _z_cancellation_token_on_cancel_handler_drop, _z_noop_copy, _z_cancellation_token_on_cancel_handler_move,\n               _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_cancellation_token_on_cancel_handler, _z_cancellation_token_on_cancel_handler_t)\n\ntypedef struct {\n    _z_cancellation_token_on_cancel_handler_intmap_t _handlers;\n    size_t _next_handler_id;\n    _z_sync_group_notifier_t _cancel_sync_notifier;\n} _z_cancellation_handlers_storage_t;\n\ntypedef struct {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t _mutex;\n#endif\n    _z_cancellation_handlers_storage_t _handlers;\n    _z_sync_group_t _sync_group;\n    z_result_t _cancel_result;\n} _z_cancellation_token_t;\n\nz_result_t _z_cancellation_token_create(_z_cancellation_token_t* ct);\nbool _z_cancellation_token_is_cancelled(const _z_cancellation_token_t* ct);\nz_result_t _z_cancellation_token_cancel(_z_cancellation_token_t* ct);\nz_result_t _z_cancellation_token_cancel_with_timeout(_z_cancellation_token_t* ct, uint32_t timeout_ms);\nvoid _z_cancellation_token_clear(_z_cancellation_token_t* ct);\n\n// if return value is not _Z_RES_OK, handler is not consumed\nz_result_t _z_cancellation_token_add_on_cancel_handler(_z_cancellation_token_t* ct,\n                                                       _z_cancellation_token_on_cancel_handler_t* handler,\n                                                       size_t* handler_id);\n\nz_result_t _z_cancellation_token_remove_on_cancel_handler(_z_cancellation_token_t* ct, size_t handler_id);\nz_result_t _z_cancellation_token_get_notifier(_z_cancellation_token_t* ct, _z_sync_group_notifier_t* notifier);\n\n_Z_REFCOUNT_DEFINE(_z_cancellation_token, _z_cancellation_token)\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/session/interest.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SESSION_INTEREST_H\n#define ZENOH_PICO_SESSION_INTEREST_H\n\n#include <stdbool.h>\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_INTEREST == 1\n_z_session_interest_rc_t *_z_get_interest_by_id(_z_session_t *zn, const _z_zint_t id);\n_z_session_interest_rc_t *_z_register_interest(_z_session_t *zn, _z_session_interest_t *intr);\nvoid _z_unregister_interest(_z_session_t *zn, _z_session_interest_rc_t *intr);\n#endif  // Z_FEATURE_INTEREST == 1\n\nvoid _z_interest_init(_z_session_t *zn);\nvoid _z_flush_interest(_z_session_t *zn);\nz_result_t _z_interest_process_declares(_z_session_t *zn, const _z_n_msg_declare_t *decl,\n                                        _z_transport_peer_common_t *peer);\nz_result_t _z_interest_process_undeclares(_z_session_t *zn, const _z_declaration_t *decl,\n                                          _z_transport_peer_common_t *peer);\nz_result_t _z_interest_process_declare_final(_z_session_t *zn, uint32_t id, _z_transport_peer_common_t *peer);\nz_result_t _z_interest_process_interest_final(_z_session_t *zn, uint32_t id);\nz_result_t _z_interest_process_interest(_z_session_t *zn, const _z_wireexpr_t *wireexpr, uint32_t id, uint8_t flags,\n                                        _z_transport_peer_common_t *peer);\nz_result_t _z_interest_push_declarations_to_peer(_z_session_t *zn, _z_transport_peer_common_t *peer);\nz_result_t _z_interest_pull_resource_from_peers(_z_session_t *zn);\nvoid _z_interest_peer_disconnected(_z_session_t *zn, _z_transport_peer_common_t *peer);\nvoid _z_interest_replay_declare(_z_session_t *zn, _z_session_interest_t *interest);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SESSION_INTEREST_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/keyexpr.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_KEYEXPR_H\n#define INCLUDE_ZENOH_PICO_SESSION_KEYEXPR_H\n\n#include <stdbool.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/weak_session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    uint16_t _id;\n    uint16_t _prefix_len;\n    _z_session_weak_t _session;\n} _z_keyexpr_wire_declaration_t;\n\nstatic inline _z_keyexpr_wire_declaration_t _z_keyexpr_wire_declaration_null(void) {\n    _z_keyexpr_wire_declaration_t d = {0};\n    return d;\n}\n\nstatic inline bool _z_keyexpr_wire_declaration_equals(const _z_keyexpr_wire_declaration_t *left,\n                                                      const _z_keyexpr_wire_declaration_t *right) {\n    return left->_id == right->_id && left->_session._val == right->_session._val;\n}\n\nz_result_t _z_keyexpr_wire_declaration_new(_z_keyexpr_wire_declaration_t *declaration, const _z_string_t *keyexpr,\n                                           const _z_session_rc_t *session);\n\nz_result_t _z_keyexpr_wire_declaration_undeclare(_z_keyexpr_wire_declaration_t *declaration);\nvoid _z_keyexpr_wire_declaration_clear(_z_keyexpr_wire_declaration_t *declaration);\nstatic inline bool _z_keyexpr_wire_declaration_is_declared_on_session(const _z_keyexpr_wire_declaration_t *declaration,\n                                                                      const _z_session_t *s) {\n    return !_Z_RC_IS_NULL(&declaration->_session) && declaration->_session._val == s;\n}\n\n_Z_REFCOUNT_DEFINE(_z_keyexpr_wire_declaration, _z_keyexpr_wire_declaration)\n\ntypedef struct {\n    _z_string_t _keyexpr;\n} _z_keyexpr_t;\n\nstatic inline _z_keyexpr_t _z_keyexpr_null(void) {\n    _z_keyexpr_t ke = {0};\n    return ke;\n}\n\nbool _z_keyexpr_includes(const _z_keyexpr_t *left, const _z_keyexpr_t *right);\nbool _z_keyexpr_intersects(const _z_keyexpr_t *left, const _z_keyexpr_t *right);\n\nzp_keyexpr_canon_status_t _z_keyexpr_is_canon(const char *start, size_t len);\nzp_keyexpr_canon_status_t _z_keyexpr_canonize(char *start, size_t *len);\nz_result_t _z_keyexpr_concat(_z_keyexpr_t *key, const _z_keyexpr_t *left, const char *right, size_t len);\nz_result_t _z_keyexpr_join(_z_keyexpr_t *key, const _z_keyexpr_t *left, const _z_keyexpr_t *right);\nstatic inline _z_keyexpr_t _z_keyexpr_alias(const _z_keyexpr_t *src) {\n    _z_keyexpr_t ret;\n    ret._keyexpr = _z_string_alias(src->_keyexpr);\n    return ret;\n}\n\n_z_keyexpr_t _z_keyexpr_alias_from_string(const _z_string_t *str);\n_z_keyexpr_t _z_keyexpr_alias_from_substr(const char *str, size_t len);\nstatic inline _z_keyexpr_t _z_keyexpr_alias_from_str(const char *str) {\n    // SAFETY: By convention in pico code-base passing const char* without len implies that it is null-terminated.\n    // Flawfinder: ignore [CWE-126]\n    return _z_keyexpr_alias_from_substr(str, strlen(str));\n}\n\nz_result_t _z_keyexpr_from_string(_z_keyexpr_t *dst, const _z_string_t *str);\nz_result_t _z_keyexpr_from_substr(_z_keyexpr_t *dst, const char *str, size_t len);\n\nstatic inline void _z_keyexpr_clear(_z_keyexpr_t *key) { _z_string_clear(&key->_keyexpr); }\n\nstatic inline bool _z_keyexpr_check(const _z_keyexpr_t *key) { return _z_string_check(&key->_keyexpr); }\nstatic inline z_result_t _z_keyexpr_copy(_z_keyexpr_t *dst, const _z_keyexpr_t *src) {\n    *dst = _z_keyexpr_null();\n    return _z_string_copy(&dst->_keyexpr, &src->_keyexpr);\n}\n\nstatic inline z_result_t _z_keyexpr_move(_z_keyexpr_t *dst, _z_keyexpr_t *src) {\n    *dst = _z_keyexpr_null();\n    _Z_CLEAN_RETURN_IF_ERR(_z_string_move(&dst->_keyexpr, &src->_keyexpr), _z_keyexpr_clear(src));\n    return _Z_RES_OK;\n}\n\nstatic inline _z_keyexpr_t _z_keyexpr_steal(_Z_MOVE(_z_keyexpr_t) src) {\n    _z_keyexpr_t stolen = *src;\n    *src = _z_keyexpr_null();\n    return stolen;\n}\n\nsize_t _z_keyexpr_non_wild_prefix_len(const _z_keyexpr_t *key);\n\nstatic inline int _z_keyexpr_compare(const _z_keyexpr_t *first, const _z_keyexpr_t *second) {\n    return _z_string_compare(&first->_keyexpr, &second->_keyexpr);\n}\nstatic inline bool _z_keyexpr_equals(const _z_keyexpr_t *first, const _z_keyexpr_t *second) {\n    return _z_keyexpr_compare(first, second) == 0;\n}\nstatic inline size_t _z_keyexpr_size(_z_keyexpr_t *p) {\n    _ZP_UNUSED(p);\n    return sizeof(_z_keyexpr_t);\n}\n\n_z_wireexpr_t _z_keyexpr_alias_to_wire(const _z_keyexpr_t *key);\n\ntypedef struct {\n    _z_keyexpr_wire_declaration_rc_t _declaration;\n    _z_keyexpr_t _inner;\n} _z_declared_keyexpr_t;\n\nstatic inline bool _z_declared_keyexpr_includes(const _z_declared_keyexpr_t *left, const _z_declared_keyexpr_t *right) {\n    return _z_keyexpr_includes(&left->_inner, &right->_inner);\n}\nstatic inline bool _z_declared_keyexpr_intersects(const _z_declared_keyexpr_t *left,\n                                                  const _z_declared_keyexpr_t *right) {\n    return _z_keyexpr_intersects(&left->_inner, &right->_inner);\n}\n\nz_result_t _z_declared_keyexpr_concat(_z_declared_keyexpr_t *key, const _z_declared_keyexpr_t *left, const char *right,\n                                      size_t len);\nz_result_t _z_declared_keyexpr_join(_z_declared_keyexpr_t *key, const _z_declared_keyexpr_t *left,\n                                    const _z_declared_keyexpr_t *right);\n\nstatic inline _z_declared_keyexpr_t _z_declared_keyexpr_null(void) {\n    _z_declared_keyexpr_t ke = {0};\n    return ke;\n}\n\n_z_declared_keyexpr_t _z_declared_keyexpr_alias_from_string(const _z_string_t *str);\n_z_declared_keyexpr_t _z_declared_keyexpr_alias_from_substr(const char *str, size_t len);\nstatic inline _z_declared_keyexpr_t _z_declared_keyexpr_alias_from_str(const char *str) {\n    // SAFETY: By convention in pico code-base passing const char* without len implies that it is null-terminated.\n    // Flawfinder: ignore [CWE-126]\n    return _z_declared_keyexpr_alias_from_substr(str, strlen(str));\n}\nstatic inline z_result_t _z_declared_keyexpr_from_string(_z_declared_keyexpr_t *dst, const _z_string_t *str) {\n    *dst = _z_declared_keyexpr_null();\n    return _z_keyexpr_from_string(&dst->_inner, str);\n}\n\nstatic inline z_result_t _z_declared_keyexpr_from_substr(_z_declared_keyexpr_t *dst, const char *str, size_t len) {\n    *dst = _z_declared_keyexpr_null();\n    return _z_keyexpr_from_substr(&dst->_inner, str, len);\n}\n\nz_result_t _z_declared_keyexpr_copy(_z_declared_keyexpr_t *dst, const _z_declared_keyexpr_t *src);\n\nstatic inline _z_declared_keyexpr_t _z_declared_keyexpr_steal(_Z_MOVE(_z_declared_keyexpr_t) src) {\n    _z_declared_keyexpr_t stolen = *src;\n    *src = _z_declared_keyexpr_null();\n    return stolen;\n}\n\nstatic inline void _z_declared_keyexpr_clear(_z_declared_keyexpr_t *key) {\n    _z_keyexpr_wire_declaration_rc_drop(&key->_declaration);\n    _z_keyexpr_clear(&key->_inner);\n}\n\nstatic inline bool _z_declared_keyexpr_check(const _z_declared_keyexpr_t *key) {\n    return _z_keyexpr_check(&key->_inner);\n}\n\nstatic inline bool _z_declared_keyexpr_is_fully_optimized(const _z_declared_keyexpr_t *key,\n                                                          const _z_session_t *session) {\n    return !_Z_RC_IS_NULL(&key->_declaration) &&\n           _z_keyexpr_wire_declaration_is_declared_on_session(_Z_RC_IN_VAL(&key->_declaration), session) &&\n           _Z_RC_IN_VAL(&key->_declaration)->_prefix_len == _z_string_len(&key->_inner._keyexpr);\n}\n\nstatic inline bool _z_declared_keyexpr_is_non_wild_prefix_optimized(const _z_declared_keyexpr_t *key,\n                                                                    const _z_session_t *session) {\n    return !_Z_RC_IS_NULL(&key->_declaration) &&\n           _z_keyexpr_wire_declaration_is_declared_on_session(_Z_RC_IN_VAL(&key->_declaration), session) &&\n           _Z_RC_IN_VAL(&key->_declaration)->_prefix_len == _z_keyexpr_non_wild_prefix_len(&key->_inner);\n}\n\nstatic inline bool _z_declared_keyexpr_equals(const _z_declared_keyexpr_t *left, const _z_declared_keyexpr_t *right) {\n    return _z_keyexpr_equals(&left->_inner, &right->_inner);\n}\nz_result_t _z_declared_keyexpr_move(_z_declared_keyexpr_t *dst, _z_declared_keyexpr_t *src);\n\n_z_wireexpr_t _z_declared_keyexpr_alias_to_wire(const _z_declared_keyexpr_t *key, const _z_session_t *session);\nz_result_t _z_declared_keyexpr_declare(const _z_session_rc_t *zs, _z_declared_keyexpr_t *out,\n                                       const _z_declared_keyexpr_t *keyexpr);\nz_result_t _z_declared_keyexpr_declare_non_wild_prefix(const _z_session_rc_t *zs, _z_declared_keyexpr_t *out,\n                                                       const _z_declared_keyexpr_t *keyexpr);\n\nstatic inline size_t _z_declared_keyexpr_size(_z_declared_keyexpr_t *p) {\n    _ZP_UNUSED(p);\n    return sizeof(_z_declared_keyexpr_t);\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_KEYEXPR_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/keyexpr_match_template.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n//\n\n#ifndef ZENOH_PICO_SESSION_KEYEXPR_MATCH_TEMPLATE_H\n#define ZENOH_PICO_SESSION_KEYEXPR_MATCH_TEMPLATE_H\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/cat.h\"\n\nconst char _Z_VERBATIM = '@';\nconst char _Z_DELIMITER = '/';\nconst char _Z_STAR = '*';\nconst char _Z_DSL0 = '$';\nconst char _Z_DSL1 = '*';\nconst size_t _Z_DELIMITER_LEN = 1;\nconst size_t _Z_DSL_LEN = 2;\nconst size_t _Z_DOUBLE_STAR_LEN = 2;\n\ntypedef enum _z_chunk_match_result_t {\n    _Z_CHUNK_MATCH_RESULT_NO,\n    _Z_CHUNK_MATCH_RESULT_YES,\n    _Z_CHUNK_MATCH_RESULT_LEFT_SUPERWILD,\n    _Z_CHUNK_MATCH_RESULT_RIGHT_SUPERWILD,\n} _z_chunk_match_result_t;\n\ntypedef struct _z_chunk_forward_match_data_t {\n    _z_chunk_match_result_t result;\n    const char *lend;  // only valid if result is _Z_CHUNK_MATCH_RESULT_YES\n    const char *rend;  // only valid if result is _Z_CHUNK_MATCH_RESULT_YES\n} _z_chunk_forward_match_data_t;\n\ntypedef struct _z_chunk_backward_match_data_t {\n    _z_chunk_match_result_t result;\n    const char *lbegin;  // only valid if result is _Z_CHUNK_MATCH_RESULT_YES\n    const char *rbegin;  // only valid if result is _Z_CHUNK_MATCH_RESULT_YES\n} _z_chunk_backward_match_data_t;\n\nstatic inline const char *_z_chunk_end(const char *begin, const char *end) {\n    const char *sep = (const char *)memchr(begin, _Z_DELIMITER, (size_t)(end - begin));\n    return sep ? sep : end;\n}\n\nstatic inline const char *_z_chunk_begin(const char *begin, const char *end) {\n    const char *last = end - 1;\n    while (begin <= last && *last != _Z_DELIMITER) {\n        last--;\n    }\n    return last + 1;\n}\n\nstatic inline bool _z_keyexpr_is_double_star(const char *begin, const char *end) {\n    size_t len = (size_t)(end - begin);\n    return len == 2 && begin[0] == _Z_STAR && begin[1] == _Z_STAR;\n}\n\nstatic inline bool _z_chunk_contains_stardsl(const char *begin, const char *end) {\n    return memchr(begin, _Z_DSL0, (size_t)(end - begin)) != NULL;\n}\n\nstatic bool _z_chunk_right_contains_all_stardsl_subchunks_of_left(const char *lbegin, const char *lend,\n                                                                  const char *rbegin, const char *rend) {\n    // Check if right chunk contains all stardsl subchunks of left chunk\n    const char *next_dsl = NULL;\n    bool matched = false;\n    do {\n        size_t llen = (size_t)(lend - lbegin);\n        next_dsl = memchr(lbegin, _Z_DSL0, llen);\n        size_t clen = next_dsl ? (size_t)(next_dsl - lbegin) : llen;\n        // TODO: Should we consider a more optimial substring search algorithm, like Boyer-Moore ? The simple version\n        // below looks good enough if the chunks are short.\n        matched = false;\n        while (rbegin + clen <= rend) {\n            if (memcmp(rbegin, lbegin, clen) == 0) {\n                rbegin += clen;\n                matched = true;\n                break;\n            }\n            rbegin++;\n        }\n        lbegin += clen + _Z_DSL_LEN;  // skip the matched part and the following stardsl\n    } while (matched && next_dsl != NULL);\n    return matched;\n}\n\nstatic inline bool _z_chunk_is_stardsl(const char *begin, const char *kend) {\n    return *begin == _Z_DSL0 && (begin + _Z_DSL_LEN == kend || *(begin + 2) == _Z_DELIMITER);\n}\n\nstatic inline bool _z_chunk_is_stardsl_backward(const char *kbegin, const char *last) {\n    // does not test for **\n    return *last == _Z_DSL1 && (last == kbegin + 1 || (last > kbegin + 1 && *(last - 2) == _Z_DELIMITER));\n}\n\nstatic inline const char *_z_keyexpr_get_next_double_star_chunk(const char *begin, const char *end) {\n    while (begin + 1 < end) {\n        const char *c = (const char *)memchr(begin, _Z_STAR, (size_t)(end - begin - 1));\n        if (c == NULL) {\n            return NULL;\n        }\n        if (*(c + 1) == _Z_STAR) {\n            return c;\n        }\n        begin = c + _Z_DOUBLE_STAR_LEN;\n    }\n    return NULL;\n}\n\nstatic inline const char *_z_keyexpr_get_next_verbatim_chunk(const char *begin, const char *end) {\n    return (const char *)memchr(begin, _Z_VERBATIM, (size_t)(end - begin));\n}\n\n#endif\n\n#ifndef _ZP_KE_MATCH_TEMPLATE_INTERSECTS\n#error \"_ZP_KE_MATCH_TEMPLATE_INTERSECTS must be defined before including keyexpr_match_template.h\"\n#endif\n\n#if _ZP_KE_MATCH_TEMPLATE_INTERSECTS == 1\n#define _ZP_KE_MATCH_OP intersects\n#define _ZP_KE_MATCH_TYPE_INTERSECTS true\n#define _ZP_KE_MATCH_TYPE_INCLUDES false\n#else\n#define _ZP_KE_MATCH_OP includes\n#define _ZP_KE_MATCH_TYPE_INTERSECTS false\n#define _ZP_KE_MATCH_TYPE_INCLUDES true\n#endif\n\nbool _ZP_CAT(_z_chunk_special, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lend, const char *rbegin,\n                                                const char *rend) {\n    // left is a non-empty part of a chunk following a stardsl and preceeding a stardsl i.e. $*lllll$*,\n    // right is chunk that does not start, nor end with a stardsl(s), but can contain stardsl in the middle,\n    // original left chunk has the following form $*L1$*L2$*...$*LN$*\n    // so there are only 2 cases where it can intersect with right:\n    // 1. right contains a stardsl in the middle, in this case bound stardsls in left can match parts before and after\n    // stardsl in the right, while right's stardsl can match the middle part of left.\n    //\n    // 2. every subchunk of left (L1, L2, ..., LN) is present in right in the\n    // correct order (and they do not overlap).\n    //\n    // For includes relation, only case 2 is valid.\n\n    return (_ZP_KE_MATCH_TYPE_INTERSECTS && _z_chunk_contains_stardsl(rbegin, rend)) ||\n           _z_chunk_right_contains_all_stardsl_subchunks_of_left(lbegin, lend, rbegin, rend);\n}\n\n_z_chunk_forward_match_data_t _ZP_CAT(_z_chunk_forward_backward, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lkend,\n                                                                                  const char *rbegin,\n                                                                                  const char *rkend) {\n    // left is a part of a chunk following a stardsl. i.e $*llllll\n    _z_chunk_forward_match_data_t result = {0};\n    result.lend = _z_chunk_end(lbegin, lkend);\n    result.rend = _z_chunk_end(rbegin, rkend);\n\n    const char *lend = result.lend;\n    const char *rend = result.rend;\n\n    while (lend > lbegin && rend > rbegin) {\n        lend--;\n        rend--;\n        if (_ZP_KE_MATCH_TYPE_INTERSECTS && *rend == _Z_DSL1) {\n            result.result = _Z_CHUNK_MATCH_RESULT_YES;\n            return result;\n        } else if (*lend == _Z_DSL1) {\n            result.result = _ZP_CAT(_z_chunk_special, _ZP_KE_MATCH_OP)(lbegin, lend + 1 - _Z_DSL_LEN, rbegin, rend + 1)\n                                ? _Z_CHUNK_MATCH_RESULT_YES\n                                : _Z_CHUNK_MATCH_RESULT_NO;\n            return result;\n        } else if (*lend != *rend) {\n            result.result = _Z_CHUNK_MATCH_RESULT_NO;\n            return result;\n        }\n    }\n    if (lbegin == lend) {  // remainder of left is entirely matched, leading stardsl can match the rest of right\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n    }\n    // if rbegin == rend remainder of right is entirely matched, but there are still chars in left (which are not\n    // strardsl due to canonicalization), so no match\n    return result;\n}\n\n_z_chunk_forward_match_data_t _ZP_CAT(_z_chunk_forward, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lkend,\n                                                                         const char *rbegin, const char *rkend) {\n    // left and right are guaranteed to be non-empty canonized chunks\n    _z_chunk_forward_match_data_t result = {0};\n    // assume canonized chunks\n    bool left_is_wild = *lbegin == _Z_STAR;\n    bool right_is_wild = *rbegin == _Z_STAR;\n\n    bool left_is_superwild = left_is_wild && (lbegin + 2 <= lkend) && *(lbegin + 1) == _Z_STAR;\n    bool right_is_superwild = right_is_wild && (rbegin + 2 <= rkend) && *(rbegin + 1) == _Z_STAR;\n\n    if (left_is_superwild) {\n        result.result = _Z_CHUNK_MATCH_RESULT_LEFT_SUPERWILD;\n        return result;\n    } else if (right_is_superwild) {\n        if (_ZP_KE_MATCH_TYPE_INCLUDES) {\n            return result;\n        }\n        result.result = _Z_CHUNK_MATCH_RESULT_RIGHT_SUPERWILD;\n        return result;\n    }\n    bool left_is_verbatim = *lbegin == _Z_VERBATIM;\n    bool right_is_verbatim = *rbegin == _Z_VERBATIM;\n\n    if (left_is_verbatim != right_is_verbatim) {\n        return result;\n    } else if (left_is_wild) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lend = lbegin + 1;\n        result.rend = _z_chunk_end(rbegin, rkend);\n        return result;\n    } else if (right_is_wild) {\n        if (_ZP_KE_MATCH_TYPE_INCLUDES) {\n            return result;\n        }\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lend = _z_chunk_end(lbegin, lkend);\n        result.rend = rbegin + 1;\n        return result;\n    }\n    // at this stage we should only care about stardsl, as the presence of verbatim or wild is already checked.\n    while (lbegin < lkend && rbegin < rkend && *lbegin != _Z_DELIMITER && *rbegin != _Z_DELIMITER) {\n        if (*lbegin == _Z_DSL0) {\n            return _ZP_CAT(_z_chunk_forward_backward, _ZP_KE_MATCH_OP)(lbegin + _Z_DSL_LEN, lkend, rbegin, rkend);\n        } else if (_ZP_KE_MATCH_TYPE_INTERSECTS && *rbegin == _Z_DSL0) {\n            _z_chunk_forward_match_data_t res =\n                _ZP_CAT(_z_chunk_forward_backward, _ZP_KE_MATCH_OP)(rbegin + _Z_DSL_LEN, rkend, lbegin, lkend);\n            result.lend = res.rend;\n            result.rend = res.lend;\n            result.result = res.result;\n            return result;\n        } else if (*lbegin != *rbegin) {\n            return result;\n        }\n        lbegin++;\n        rbegin++;\n    }\n    bool left_exhausted = lbegin == lkend || *lbegin == _Z_DELIMITER;\n    bool right_exhausted = rbegin == rkend || *rbegin == _Z_DELIMITER;\n    if (left_exhausted && right_exhausted) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lend = lbegin;\n        result.rend = rbegin;\n    } else if (_ZP_KE_MATCH_TYPE_INTERSECTS && left_exhausted && _z_chunk_is_stardsl(rbegin, rkend)) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lend = lbegin;\n        result.rend = rbegin + _Z_DSL_LEN;\n    } else if (right_exhausted && _z_chunk_is_stardsl(lbegin, lkend)) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lend = lbegin + _Z_DSL_LEN;\n        result.rend = rbegin;\n    }\n    return result;\n}\n\n_z_chunk_backward_match_data_t _ZP_CAT(_z_chunk_backward_forward,\n                                       _ZP_KE_MATCH_OP)(const char *lkbegin, const char *lend, const char *rkbegin,\n                                                        const char *rend) {\n    // left is a part of a chunk preceeding a stardsl i.e lllll$*\n    _z_chunk_backward_match_data_t result = {0};\n    const char *lbegin = _z_chunk_begin(lkbegin, lend);\n    const char *rbegin = _z_chunk_begin(rkbegin, rend);\n    if ((*lbegin == _Z_VERBATIM) != (*rbegin == _Z_VERBATIM)) {  // one is verbatim, the other is not, so no match\n        return result;\n    }\n    result.lbegin = lbegin;\n    result.rbegin = rbegin;\n\n    // chunks can not be star, nor doublestar\n    while (lbegin < lend && rbegin < rend) {\n        if (_ZP_KE_MATCH_TYPE_INTERSECTS && *rbegin == _Z_DSL0) {\n            result.result = _Z_CHUNK_MATCH_RESULT_YES;\n            return result;\n        } else if (*lbegin == _Z_DSL0) {\n            result.result = _ZP_CAT(_z_chunk_special, _ZP_KE_MATCH_OP)(lbegin + 2, lend, rbegin, rend)\n                                ? _Z_CHUNK_MATCH_RESULT_YES\n                                : _Z_CHUNK_MATCH_RESULT_NO;\n            return result;\n        } else if (*lbegin != *rbegin) {\n            return result;\n        }\n        lbegin++;\n        rbegin++;\n    }\n\n    if (lbegin == lend) {  // remainder of left is entirely matched, suffix stardsl can match the rest of right\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n    }\n    return result;\n}\n\n_z_chunk_backward_match_data_t _ZP_CAT(_z_chunk_backward, _ZP_KE_MATCH_OP)(const char *lkbegin, const char *lend,\n                                                                           const char *rkbegin, const char *rend) {\n    _z_chunk_backward_match_data_t result = {0};\n    const char *llast = lend - 1;\n    const char *rlast = rend - 1;\n    // assume canonized chunks\n    bool left_is_wild = *llast == _Z_STAR;\n    bool right_is_wild = *rlast == _Z_STAR;\n\n    bool left_is_superwild = left_is_wild && (lkbegin + 2 <= lend) && *(llast - 1) == _Z_STAR;\n    bool right_is_superwild = right_is_wild && (rkbegin + 2 <= rend) && *(rlast - 1) == _Z_STAR;\n\n    if (left_is_superwild) {\n        result.result = _Z_CHUNK_MATCH_RESULT_LEFT_SUPERWILD;\n        return result;\n    } else if (right_is_superwild) {\n        if (_ZP_KE_MATCH_TYPE_INCLUDES) {\n            return result;\n        }\n        result.result = _Z_CHUNK_MATCH_RESULT_RIGHT_SUPERWILD;\n        return result;\n    }\n    left_is_wild = left_is_wild && (lkbegin == llast || *(llast - 1) == _Z_DELIMITER);\n    right_is_wild = right_is_wild && (rkbegin == rlast || *(rlast - 1) == _Z_DELIMITER);\n    if (left_is_wild) {\n        result.lbegin = llast;\n        result.rbegin = _z_chunk_begin(rkbegin, rend);\n        result.result = *result.rbegin == _Z_VERBATIM ? _Z_CHUNK_MATCH_RESULT_NO : _Z_CHUNK_MATCH_RESULT_YES;\n        return result;\n    } else if (right_is_wild) {\n        if (_ZP_KE_MATCH_TYPE_INCLUDES) {\n            return result;\n        }\n        result.lbegin = _z_chunk_begin(lkbegin, lend);\n        result.rbegin = rlast;\n        result.result = *result.lbegin == _Z_VERBATIM ? _Z_CHUNK_MATCH_RESULT_NO : _Z_CHUNK_MATCH_RESULT_YES;\n        return result;\n    }\n\n    while (llast >= lkbegin && rlast >= rkbegin && *llast != _Z_DELIMITER && *rlast != _Z_DELIMITER) {\n        if (*llast == _Z_DSL1) {\n            return _ZP_CAT(_z_chunk_backward_forward, _ZP_KE_MATCH_OP)(lkbegin, llast + 1 - _Z_DSL_LEN, rkbegin,\n                                                                       rlast + 1);\n        } else if (_ZP_KE_MATCH_TYPE_INTERSECTS && *rlast == _Z_DSL1) {\n            _z_chunk_backward_match_data_t res = _ZP_CAT(_z_chunk_backward_forward, _ZP_KE_MATCH_OP)(\n                rkbegin, rlast + 1 - _Z_DSL_LEN, lkbegin, llast + 1);\n            result.lbegin = res.rbegin;\n            result.rbegin = res.lbegin;\n            result.result = res.result;\n            return result;\n        } else if (*llast != *rlast) {\n            return result;\n        }\n        llast--;\n        rlast--;\n    }\n    bool left_exhausted = lkbegin == llast + 1 || *llast == _Z_DELIMITER;\n    bool right_exhausted = rkbegin == rlast + 1 || *rlast == _Z_DELIMITER;\n    if (left_exhausted && right_exhausted) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lbegin = llast + 1;\n        result.rbegin = rlast + 1;\n    } else if (_ZP_KE_MATCH_TYPE_INTERSECTS && left_exhausted && _z_chunk_is_stardsl_backward(rkbegin, rlast)) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lbegin = llast + 1;\n        result.rbegin = rlast + 1 - _Z_DSL_LEN;\n    } else if (right_exhausted && _z_chunk_is_stardsl_backward(lkbegin, llast)) {\n        result.result = _Z_CHUNK_MATCH_RESULT_YES;\n        result.lbegin = llast + 1 - _Z_DSL_LEN;\n        result.rbegin = rlast + 1;\n    }\n    return result;\n}\n\nbool _ZP_CAT(_z_keyexpr_special, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lend, const char *rbegin,\n                                                  const char *rend) {\n    // left is a non-empty part of a ke sorrounded by doublestar i.e. **/l/l/l/l**\n    // right is ke that does not start, nor end with a doublestar(s), but can contain doublestar in the middle\n    // none of the kes contain any verbatim chunks\n    // so there are only 2 cases where left can intersect with right:\n    // 1. right contains a doublestar in the middle, in this case bound doublestars in left can match parts before and\n    // after doublestar in right, while right's doublestar can match the middle part of left.\n    //\n    // 2. every chunk of left **/L1/**/L2/**/../LN/** is matched in right\n    // in the correct order and without overlap.\n\n    // For includes relation, only case 2 is valid.\n    if (_ZP_KE_MATCH_TYPE_INTERSECTS && _z_keyexpr_get_next_double_star_chunk(rbegin, rend) != NULL) {\n        return true;\n    }\n\n    // right is guaranteed not to have doublestars for intersects, while for includes we do not care\n    while (lbegin < lend) {\n        const char *lcbegin = lbegin;\n        const char *lcend = _z_keyexpr_get_next_double_star_chunk(lbegin, lend);\n        lcend = lcend != NULL ? lcend - _Z_DELIMITER_LEN : lend;\n        const char *rcbegin = rbegin;\n\n        while (lcbegin < lcend) {\n            if (rcbegin >= rend) {\n                return false;\n            }\n            _z_chunk_forward_match_data_t res =\n                _ZP_CAT(_z_chunk_forward, _ZP_KE_MATCH_OP)(lcbegin, lcend, rcbegin, rend);\n            if (res.result == _Z_CHUNK_MATCH_RESULT_YES) {\n                lcbegin = res.lend + _Z_DELIMITER_LEN;\n                rcbegin = res.rend + _Z_DELIMITER_LEN;\n            } else {  // the only other possible case is res.result == _Z_CHUNK_MATCH_RESULT_NO\n                // reset subke matching and try to match current left subke with the next right chunk\n                lcbegin = lbegin;\n                rbegin = _z_chunk_end(rbegin, rend) + _Z_DELIMITER_LEN;\n                rcbegin = rbegin;\n            }\n        }\n        lbegin = lcbegin;\n        rbegin = rcbegin;\n    }\n    return true;\n}\n\nbool _ZP_CAT(_z_keyexpr_parts, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lend, const char *rbegin,\n                                                const char *rend);\n\nbool _ZP_CAT(_z_keyexpr_backward, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lend, const char *rbegin,\n                                                   const char *rend, bool can_have_verbatim) {\n    // left is a suffix following a doublestar i.e. **/l/l/l/l\n    while (lbegin < lend && rbegin < rend) {\n        _z_chunk_backward_match_data_t res = _ZP_CAT(_z_chunk_backward, _ZP_KE_MATCH_OP)(lbegin, lend, rbegin, rend);\n        if (res.result == _Z_CHUNK_MATCH_RESULT_NO ||\n            (_ZP_KE_MATCH_TYPE_INCLUDES && res.result == _Z_CHUNK_MATCH_RESULT_RIGHT_SUPERWILD)) {\n            return false;\n        } else if (res.result == _Z_CHUNK_MATCH_RESULT_YES) {\n            bool left_exhausted = lbegin == res.lbegin;\n            bool right_exhausted = rbegin == res.rbegin;\n            if (left_exhausted && right_exhausted) {\n                return true;  // leading doublestar in left matches an empty string\n            } else if (left_exhausted) {\n                // left is exhausted, right is matched if it does not contain any verbatim chunks\n                return !can_have_verbatim ||\n                       _z_keyexpr_get_next_verbatim_chunk(rbegin, res.rbegin - _Z_DELIMITER_LEN) == NULL;\n            } else if (right_exhausted) {\n                return false;  // right is exhausted, left is not (and thus contains at least one non doublestar chunk),\n                               // match is impossible\n            }\n            lend = res.lbegin - _Z_DELIMITER_LEN;\n            rend = res.rbegin - _Z_DELIMITER_LEN;\n        } else if (can_have_verbatim) {\n            // Now this becomes more complicated.\n            // In the absence of verbatim chunks, we could apply the same logic as for matching stardsl chunks, but not\n            // here. Given that we would anyway need to scan both kes for verbatim chunks and compare them, we rather\n            // fallback to splitting kes across verbatim chunks boundary and run matching on each subke.\n            return _ZP_CAT(_z_keyexpr_parts, _ZP_KE_MATCH_OP)(lbegin - _Z_DOUBLE_STAR_LEN - _Z_DELIMITER_LEN, lend,\n                                                              rbegin, rend);\n        } else if (res.result == _Z_CHUNK_MATCH_RESULT_LEFT_SUPERWILD) {\n            return _ZP_CAT(_z_keyexpr_special, _ZP_KE_MATCH_OP)(lbegin, lend - _Z_DOUBLE_STAR_LEN - _Z_DELIMITER_LEN,\n                                                                rbegin, rend);\n        } else if (res.result == _Z_CHUNK_MATCH_RESULT_RIGHT_SUPERWILD) {\n            return true;\n        }\n    }\n    bool left_exhausted = lbegin >= lend;\n    bool right_exhausted = rbegin >= rend;\n    return (left_exhausted || _z_keyexpr_is_double_star(lbegin, lend)) &&\n           (right_exhausted || (_ZP_KE_MATCH_TYPE_INTERSECTS && _z_keyexpr_is_double_star(rbegin, rend)));\n}\n\nbool _ZP_CAT(_z_keyexpr_forward, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lend, const char *rbegin,\n                                                  const char *rend, bool can_have_verbatim) {\n    while (lbegin < lend && rbegin < rend) {\n        _z_chunk_forward_match_data_t res = _ZP_CAT(_z_chunk_forward, _ZP_KE_MATCH_OP)(lbegin, lend, rbegin, rend);\n        if (res.result == _Z_CHUNK_MATCH_RESULT_YES) {\n            lbegin = res.lend + _Z_DELIMITER_LEN;\n            rbegin = res.rend + _Z_DELIMITER_LEN;\n        } else if (res.result == _Z_CHUNK_MATCH_RESULT_LEFT_SUPERWILD) {\n            if (lbegin + _Z_DOUBLE_STAR_LEN == lend) {  // left is exhausted\n                return _z_keyexpr_get_next_verbatim_chunk(rbegin, rend) == NULL;\n            }\n            return _ZP_CAT(_z_keyexpr_backward, _ZP_KE_MATCH_OP)(lbegin + _Z_DOUBLE_STAR_LEN + _Z_DELIMITER_LEN, lend,\n                                                                 rbegin, rend, can_have_verbatim);\n        } else if (_ZP_KE_MATCH_TYPE_INTERSECTS && res.result == _Z_CHUNK_MATCH_RESULT_RIGHT_SUPERWILD) {\n            if (rbegin + _Z_DOUBLE_STAR_LEN == rend) {  // right is exhausted\n                return _z_keyexpr_get_next_verbatim_chunk(lbegin, lend) == NULL;\n            }\n            return _ZP_CAT(_z_keyexpr_backward, _ZP_KE_MATCH_OP)(rbegin + _Z_DOUBLE_STAR_LEN + _Z_DELIMITER_LEN, rend,\n                                                                 lbegin, lend, can_have_verbatim);\n        } else {\n            return false;\n        }\n    }\n\n    bool left_exhausted = lbegin >= lend;\n    bool right_exhausted = rbegin >= rend;\n    return (left_exhausted || _z_keyexpr_is_double_star(lbegin, lend)) &&\n           (right_exhausted || (_ZP_KE_MATCH_TYPE_INTERSECTS && _z_keyexpr_is_double_star(rbegin, rend)));\n}\n\nbool _ZP_CAT(_z_keyexpr_parts, _ZP_KE_MATCH_OP)(const char *lbegin, const char *lend, const char *rbegin,\n                                                const char *rend) {\n    while (lbegin < lend && rbegin < rend) {\n        const char *lverbatim = _z_keyexpr_get_next_verbatim_chunk(lbegin, lend);\n        const char *rverbatim = _z_keyexpr_get_next_verbatim_chunk(rbegin, rend);\n        if (lverbatim == NULL && rverbatim == NULL) {\n            return _ZP_CAT(_z_keyexpr_forward, _ZP_KE_MATCH_OP)(lbegin, lend, rbegin, rend, false);\n        } else if (lverbatim == NULL || rverbatim == NULL) {  // different number of verbatim chunks, kes can not match\n            return false;\n        }\n\n        const char *lskend = lverbatim == lbegin ? lbegin : lverbatim - _Z_DELIMITER_LEN;\n        const char *rskend = rverbatim == rbegin ? rbegin : rverbatim - _Z_DELIMITER_LEN;\n        if (!_ZP_CAT(_z_keyexpr_forward, _ZP_KE_MATCH_OP)(lbegin, lskend, rbegin, rskend, false)) {\n            return false;  // prefixes before verbatim chunks do not match, so kes can not match\n        }\n\n        _z_chunk_forward_match_data_t res =\n            _ZP_CAT(_z_chunk_forward, _ZP_KE_MATCH_OP)(lverbatim, lend, rverbatim, rend);\n        if (res.result != _Z_CHUNK_MATCH_RESULT_YES) {\n            return false;  // verbatim chunks do not match, so kes can not match\n        }\n        lbegin = res.lend + _Z_DELIMITER_LEN;\n        rbegin = res.rend + _Z_DELIMITER_LEN;\n    }\n    bool left_exhausted = lbegin >= lend;\n    bool right_exhausted = rbegin >= rend;\n    return (left_exhausted || _z_keyexpr_is_double_star(lbegin, lend)) &&\n           (right_exhausted || (_ZP_KE_MATCH_TYPE_INTERSECTS && _z_keyexpr_is_double_star(rbegin, rend)));\n}\n\n#undef _ZP_KE_MATCH_OP\n#undef _ZP_KE_MATCH_TYPE_INTERSECTS\n#undef _ZP_KE_MATCH_TYPE_INCLUDES\n#undef _ZP_KE_MATCH_TEMPLATE_INTERSECTS\n"
  },
  {
    "path": "include/zenoh-pico/session/liveliness.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SESSION_LIVELINESS_H\n#define ZENOH_PICO_SESSION_LIVELINESS_H\n\n#include \"zenoh-pico/session/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Forward declaration to avoid cyclical include\ntypedef struct _z_session_t _z_session_t;\n\n#if Z_FEATURE_LIVELINESS == 1\n\ntypedef struct {\n    _z_keyexpr_t _key;\n    uint32_t _id;\n    _z_closure_reply_callback_t _callback;\n    _z_drop_handler_t _dropper;\n    void *_arg;\n#ifdef Z_FEATURE_UNSTABLE_API\n    _z_pending_query_cancellation_data_t _cancellation_data;\n#endif\n} _z_liveliness_pending_query_t;\n\nstatic inline _z_liveliness_pending_query_t _z_liveliness_pending_query_null(void) {\n    _z_liveliness_pending_query_t pq = {0};\n    return pq;\n}\n\nvoid _z_liveliness_pending_query_clear(_z_liveliness_pending_query_t *res);\n\n_Z_ELEM_DEFINE(_z_liveliness_pending_query, _z_liveliness_pending_query_t, _z_noop_size,\n               _z_liveliness_pending_query_clear, _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_liveliness_pending_query, _z_liveliness_pending_query_t)\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nz_result_t _z_liveliness_process_remote_token_declare(_z_session_t *zn, uint32_t id, const _z_wireexpr_t *keyexpr,\n                                                      const _z_timestamp_t *timestamp,\n                                                      _z_transport_peer_common_t *peer);\nz_result_t _z_liveliness_process_remote_token_undeclare(_z_session_t *zn, uint32_t id, const _z_timestamp_t *timestamp);\nz_result_t _z_liveliness_subscription_undeclare_all(_z_session_t *zn);\n#endif\n\n#if Z_FEATURE_QUERY == 1\n_z_liveliness_pending_query_t *_z_unsafe_liveliness_register_pending_query(_z_session_t *zn);\nz_result_t _z_liveliness_unregister_pending_query(_z_session_t *zn, uint32_t id);\n#endif\n\nvoid _z_liveliness_init(_z_session_t *zn);\nvoid _z_liveliness_clear(_z_session_t *zn);\n#endif  // Z_FEATURE_LIVELINESS == 1\n\nz_result_t _z_liveliness_process_token_declare(_z_session_t *zn, const _z_n_msg_declare_t *decl,\n                                               _z_transport_peer_common_t *peer);\nz_result_t _z_liveliness_process_token_undeclare(_z_session_t *zn, const _z_n_msg_declare_t *decl);\nz_result_t _z_liveliness_process_declare_final(_z_session_t *zn, const _z_n_msg_declare_t *decl);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SESSION_LIVELINESS_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/loopback.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SESSION_LOOPBACK_H\n#define ZENOH_PICO_SESSION_LOOPBACK_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_session_deliver_push_locally(_z_session_t *zn, const _z_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                                           _z_encoding_t *encoding, z_sample_kind_t kind, _z_n_qos_t qos,\n                                           const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                                           z_reliability_t reliability, const _z_source_info_t *source_info);\n\nz_result_t _z_session_deliver_query_locally(_z_session_t *zn, const _z_keyexpr_t *keyexpr, const _z_slice_t *parameters,\n                                            z_consolidation_mode_t consolidation, _z_bytes_t *payload,\n                                            _z_encoding_t *encoding, _z_bytes_t *attachment,\n                                            const _z_source_info_t *source_info, _z_zint_t qid, uint64_t timeout_ms,\n                                            _z_n_qos_t qos, bool implicit_anyke);\n\nz_result_t _z_session_deliver_reply_locally(const _z_query_t *query, const _z_session_rc_t *zn,\n                                            const _z_declared_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                                            _z_encoding_t *encoding, z_sample_kind_t kind, _z_n_qos_t qos,\n                                            const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                                            const _z_source_info_t *source_info);\n\nz_result_t _z_session_deliver_reply_err_locally(const _z_query_t *query, const _z_session_rc_t *zn, _z_bytes_t *payload,\n                                                _z_encoding_t *encoding, _z_n_qos_t qos);\n\nz_result_t _z_session_deliver_reply_final_locally(_z_session_t *zn, _z_zint_t rid);\n\n#if defined(Z_TEST_HOOKS)\ntypedef _z_transport_common_t *(*_z_session_transport_override_fn)(_z_session_t *);\nvoid _z_session_set_transport_common_override(_z_session_transport_override_fn fn);\n\ntypedef z_result_t (*_z_session_send_override_fn)(_z_session_t *zn, const _z_network_message_t *n_msg,\n                                                  z_reliability_t reliability, z_congestion_control_t cong_ctrl,\n                                                  void *peer, bool *handled);\nvoid _z_transport_set_send_n_msg_override(_z_session_send_override_fn fn);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SESSION_LOOPBACK_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/matching.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_MATCHING_H\n#define INCLUDE_ZENOH_PICO_SESSION_MATCHING_H\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/session/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    bool matching;  // true if there exist matching Zenoh entities, false otherwise.\n} _z_matching_status_t;\n\ntypedef void (*_z_closure_matching_status_callback_t)(const _z_matching_status_t *status, void *arg);\n\ntypedef struct {\n    void *context;\n    _z_closure_matching_status_callback_t call;\n    _z_drop_handler_t drop;\n} _z_closure_matching_status_t;\n\n#if Z_FEATURE_MATCHING == 1\n\nstatic inline void _z_closure_matching_status_clear(_z_closure_matching_status_t *closure) {\n    if (closure->drop != NULL) {\n        closure->drop(closure->context);\n    }\n}\n\n_Z_ELEM_DEFINE(_z_closure_matching_status, _z_closure_matching_status_t, _z_noop_size, _z_closure_matching_status_clear,\n               _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_closure_matching_status, _z_closure_matching_status_t)\n#endif  // Z_FEATURE_MATCHING == 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_MATCHING_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/push.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdint.h>\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n\n#ifndef ZENOH_PICO_SESSION_PUSH_H\n#define ZENOH_PICO_SESSION_PUSH_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_trigger_push(_z_session_t *zn, _z_n_msg_push_t *push, z_reliability_t reliability,\n                           _z_transport_peer_common_t *peer);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SESSION_PUSH_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/query.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SESSION_QUERY_H\n#define ZENOH_PICO_SESSION_QUERY_H\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid _z_pending_query_process_timeout(_z_session_t *zn);\n_z_fut_fn_result_t _z_pending_query_process_timeout_task_fn(void *session_arg, _z_executor_t *executor);\n\n#if Z_FEATURE_QUERY == 1\n/*------------------ Query ------------------*/\n_z_pending_query_t *_z_unsafe_register_pending_query(_z_session_t *zn);\nz_result_t _z_trigger_query_reply_partial(_z_session_t *zn, _z_zint_t reply_context, _z_wireexpr_t *wireexpr,\n                                          _z_msg_put_t *msg, z_sample_kind_t kind, _z_entity_global_id_t *replier_id,\n                                          _z_transport_peer_common_t *peer);\nz_result_t _z_trigger_query_reply_err(_z_session_t *zn, _z_zint_t id, _z_msg_err_t *msg,\n                                      _z_entity_global_id_t *replier_id);\nz_result_t _z_trigger_query_reply_final(_z_session_t *zn, _z_zint_t id);\nvoid _z_unregister_pending_query(_z_session_t *zn, _z_zint_t query_id);\nvoid _z_unregister_pending_queries_from_querier(_z_session_t *zn, uint32_t querier_id);\nvoid _z_flush_pending_queries(_z_session_t *zn);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SESSION_QUERY_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/queryable.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SESSION_QUERYABLE_H\n#define ZENOH_PICO_SESSION_QUERYABLE_H\n\n#include <stdbool.h>\n#include <zenoh-pico/session/session.h>\n\n#include \"zenoh-pico/collections/lru_cache.h\"\n\n// Forward declaration to avoid cyclical include\ntypedef struct _z_session_t _z_session_t;\ntypedef struct _z_session_rc_t _z_session_rc_t;\n\n// Queryable infos\n_Z_SVEC_DEFINE(_z_session_queryable_rc, _z_session_queryable_rc_t)\n_Z_REFCOUNT_DEFINE(_z_session_queryable_rc_svec, _z_session_queryable_rc_svec)\n\ntypedef struct {\n    _z_keyexpr_t ke;\n    _z_session_queryable_rc_svec_rc_t infos;\n    bool is_remote;\n} _z_queryable_cache_data_t;\n\nvoid _z_unsafe_queryable_cache_invalidate(_z_session_t *zn);\nint _z_queryable_cache_data_compare(const void *first, const void *second);\nvoid _z_queryable_cache_data_clear(_z_queryable_cache_data_t *val);\n\n#if Z_FEATURE_QUERYABLE == 1\n#define _Z_QUERYABLE_COMPLETE_DEFAULT false\n#define _Z_QUERYABLE_DISTANCE_DEFAULT 0\n\n#if Z_FEATURE_RX_CACHE == 1\n_Z_ELEM_DEFINE(_z_queryable, _z_queryable_cache_data_t, _z_noop_size, _z_queryable_cache_data_clear, _z_noop_copy,\n               _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_LRU_CACHE_DEFINE(_z_queryable, _z_queryable_cache_data_t, _z_queryable_cache_data_compare)\n#endif\n\n/*------------------ Queryable ------------------*/\n_z_session_queryable_rc_t _z_get_session_queryable_by_id(_z_session_t *zn, const _z_zint_t id);\n_z_session_queryable_rc_t _z_register_session_queryable(_z_session_t *zn, _z_session_queryable_t *q);\nz_result_t _z_trigger_queryables(_z_transport_common_t *transport, _z_msg_query_t *query, _z_wireexpr_t *q_key,\n                                 uint32_t qid, _z_n_qos_t qos, _z_transport_peer_common_t *peer);\nvoid _z_unregister_session_queryable(_z_session_t *zn, _z_session_queryable_rc_t *q);\nvoid _z_flush_session_queryable(_z_session_t *zn);\n#endif\n\n#endif /* ZENOH_PICO_SESSION_QUERYABLE_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/reply.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdint.h>\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef ZENOH_PICO_SESSION_REPLY_H\n#define ZENOH_PICO_SESSION_REPLY_H\n\nz_result_t _z_trigger_reply_partial(_z_session_t *zn, _z_zint_t id, _z_wireexpr_t *wireexpr, _z_msg_reply_t *reply,\n                                    _z_entity_global_id_t *replier_id, _z_transport_peer_common_t *peer);\n\nz_result_t _z_trigger_reply_err(_z_session_t *zn, _z_zint_t id, _z_msg_err_t *error, _z_entity_global_id_t *replier_id);\n\nz_result_t _z_trigger_reply_final(_z_session_t *zn, _z_n_msg_response_final_t *final);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SESSION_REPLY_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/resource.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_RESOURCE_H\n#define INCLUDE_ZENOH_PICO_SESSION_RESOURCE_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/net/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Entity ------------------*/\nuint32_t _z_get_entity_id(_z_session_t *zn);\n\n/*------------------ Resource ------------------*/\nuint16_t _z_get_resource_id(_z_session_t *zn);\nz_result_t _z_get_keyexpr_from_wireexpr(_z_session_t *zn, _z_keyexpr_t *out, const _z_wireexpr_t *expr,\n                                        _z_transport_peer_common_t *peer, bool alias_wireexpr_if_possible);\nz_result_t _z_register_resource(_z_session_t *zn, const _z_wireexpr_t *key, uint16_t id,\n                                _z_transport_peer_common_t *peer, uint16_t *out_id);\nz_result_t _z_unregister_resource(_z_session_t *zn, uint16_t id, _z_transport_peer_common_t *peer);\nvoid _z_flush_local_resources(_z_session_t *zn);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_RESOURCE_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/session.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_SESSION_H\n#define INCLUDE_ZENOH_PICO_SESSION_SESSION_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/list.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/cancellation.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/transport/manager.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * The callback signature of the cleanup functions.\n */\ntypedef void (*_z_drop_handler_t)(void *arg);\n\nstatic inline void _z_drop_handler_execute(_z_drop_handler_t dropper, void *arg) {\n    if (dropper != NULL) {\n        dropper(arg);\n    }\n}\n\ntypedef enum {\n    _Z_SUBSCRIBER_KIND_SUBSCRIBER = 0,\n    _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER = 1,\n} _z_subscriber_kind_t;\n\ntypedef struct {\n    _z_keyexpr_t _key;\n    uint16_t _id;\n    uint16_t _refcount;\n} _z_resource_t;\n\nbool _z_resource_eq(const _z_resource_t *one, const _z_resource_t *two);\nvoid _z_resource_clear(_z_resource_t *res);\nvoid _z_resource_copy(_z_resource_t *dst, const _z_resource_t *src);\nvoid _z_resource_free(_z_resource_t **res);\nsize_t _z_resource_size(_z_resource_t *p);\n\n_Z_ELEM_DEFINE(_z_resource, _z_resource_t, _z_resource_size, _z_resource_clear, _z_resource_copy, _z_noop_move,\n               _z_resource_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_resource, _z_resource_t, true)\n\n_Z_ELEM_DEFINE(_z_keyexpr, _z_keyexpr_t, _z_keyexpr_size, _z_keyexpr_clear, _z_keyexpr_copy, _z_keyexpr_move,\n               _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_keyexpr, _z_keyexpr_t)\n_Z_SLIST_DEFINE(_z_keyexpr, _z_keyexpr_t, true)\n_Z_ELEM_DEFINE(_z_declared_keyexpr, _z_declared_keyexpr_t, _z_declared_keyexpr_size, _z_declared_keyexpr_clear,\n               _z_declared_keyexpr_copy, _z_declared_keyexpr_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_INT_MAP_DEFINE(_z_declared_keyexpr, _z_declared_keyexpr_t)\n\n// Forward declaration to avoid cyclical include\ntypedef struct _z_sample_t _z_sample_t;\n\n/**\n * The callback signature of the functions handling data messages.\n */\ntypedef void (*_z_closure_sample_callback_t)(_z_sample_t *sample, void *arg);\n\ntypedef struct {\n    _z_declared_keyexpr_t _key;\n    uint32_t _id;\n    z_locality_t _allowed_origin;\n    _z_closure_sample_callback_t _callback;\n    _z_drop_handler_t _dropper;\n    void *_arg;\n    _z_sync_group_notifier_t _session_callback_drop_notifier;\n    _z_sync_group_notifier_t _subscriber_callback_drop_notifier;\n} _z_subscription_t;\n\nbool _z_subscription_eq(const _z_subscription_t *one, const _z_subscription_t *two);\nvoid _z_subscription_clear(_z_subscription_t *sub);\n\nstatic inline _z_subscription_t _z_subscription_null(void) {\n    _z_subscription_t s = {0};\n    return s;\n}\n\n_Z_REFCOUNT_DEFINE(_z_subscription, _z_subscription)\n_Z_ELEM_DEFINE(_z_subscriber, _z_subscription_t, _z_noop_size, _z_subscription_clear, _z_noop_copy, _z_noop_move,\n               _z_subscription_eq, _z_noop_cmp, _z_noop_hash)\n_Z_ELEM_DEFINE(_z_subscription_rc, _z_subscription_rc_t, _z_subscription_rc_size, _z_subscription_rc_drop,\n               _z_subscription_rc_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_subscription_rc, _z_subscription_rc_t, true)\n\ntypedef struct {\n    _z_keyexpr_t _key;\n    uint32_t _id;\n} _z_publication_t;\n\n// Forward type declaration to avoid cyclical include\ntypedef struct _z_query_rc_t _z_query_rc_t;\n\n/**\n * The callback signature of the functions handling query messages.\n */\ntypedef void (*_z_closure_query_callback_t)(_z_query_rc_t *query, void *arg);\n\ntypedef struct {\n    _z_declared_keyexpr_t _key;\n    uint32_t _id;\n    _z_closure_query_callback_t _callback;\n    _z_drop_handler_t _dropper;\n    void *_arg;\n    bool _complete;\n    z_locality_t _allowed_origin;\n    _z_sync_group_notifier_t _session_callback_drop_notifier;\n    _z_sync_group_notifier_t _queryable_callback_drop_notifier;\n} _z_session_queryable_t;\n\nstatic inline _z_session_queryable_t _z_session_queryable_null(void) {\n    _z_session_queryable_t qle = {0};\n    return qle;\n}\n\nbool _z_session_queryable_eq(const _z_session_queryable_t *one, const _z_session_queryable_t *two);\nvoid _z_session_queryable_clear(_z_session_queryable_t *res);\n\n_Z_REFCOUNT_DEFINE(_z_session_queryable, _z_session_queryable)\n_Z_ELEM_DEFINE(_z_session_queryable, _z_session_queryable_t, _z_noop_size, _z_session_queryable_clear, _z_noop_copy,\n               _z_noop_move, _z_session_queryable_eq, _z_noop_cmp, _z_noop_hash)\n_Z_ELEM_DEFINE(_z_session_queryable_rc, _z_session_queryable_rc_t, _z_session_queryable_rc_size,\n               _z_session_queryable_rc_drop, _z_session_queryable_rc_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp,\n               _z_noop_hash)\n_Z_SLIST_DEFINE(_z_session_queryable_rc, _z_session_queryable_rc_t, true)\n\n// Forward declaration to avoid cyclical includes\ntypedef struct _z_reply_t _z_reply_t;\ntypedef _z_slist_t _z_pending_reply_slist_t;\ntypedef struct _z_reply_t _z_reply_t;\n\n/**\n * The callback signature of the functions handling query replies.\n */\ntypedef void (*_z_closure_reply_callback_t)(_z_reply_t *reply, void *arg);\n\ntypedef struct _z_pending_query_t _z_pending_query_t;\n#ifdef Z_FEATURE_UNSTABLE_API\ntypedef struct {\n    _z_cancellation_token_rc_t _cancellation_token;\n    size_t _handler_id;\n    _z_sync_group_notifier_t _notifier;\n} _z_pending_query_cancellation_data_t;\n\nstatic inline _z_pending_query_cancellation_data_t _z_pending_query_cancellation_data_null(void) {\n    _z_pending_query_cancellation_data_t d = {0};\n    return d;\n}\nstatic inline void _z_pending_query_cancellation_data_clear(_z_pending_query_cancellation_data_t *data) {\n    if (!_Z_RC_IS_NULL(&data->_cancellation_token)) {\n        _z_cancellation_token_remove_on_cancel_handler(_Z_RC_IN_VAL(&data->_cancellation_token), data->_handler_id);\n        _z_cancellation_token_rc_drop(&data->_cancellation_token);\n        _z_sync_group_notifier_drop(&data->_notifier);\n    }\n}\n\nz_result_t _z_pending_query_register_cancellation(_z_pending_query_t *pq,\n                                                  const _z_cancellation_token_rc_t *opt_cancellation_token,\n                                                  const _z_session_rc_t *session);\n\nvoid _z_pending_query_cancellation_data_clear(_z_pending_query_cancellation_data_t *data);\n#endif\nstruct _z_pending_query_t {\n    _z_keyexpr_t _key;\n    _z_optional_id_t _querier_id;\n    _z_zint_t _id;\n    _z_closure_reply_callback_t _callback;\n    _z_drop_handler_t _dropper;\n    z_locality_t _allowed_destination;\n    z_clock_t _start_time;\n    uint64_t _timeout;\n    void *_arg;\n    uint32_t _remaining_finals;\n    _z_pending_reply_slist_t *_pending_replies;\n    z_query_target_t _target;\n    z_consolidation_mode_t _consolidation;\n    bool _anyke;\n#ifdef Z_FEATURE_UNSTABLE_API\n    _z_pending_query_cancellation_data_t _cancellation_data;\n#endif\n};\n\nbool _z_pending_query_eq(const _z_pending_query_t *one, const _z_pending_query_t *two);\nvoid _z_pending_query_clear(_z_pending_query_t *res);\n\n_Z_ELEM_DEFINE(_z_pending_query, _z_pending_query_t, _z_noop_size, _z_pending_query_clear, _z_noop_copy, _z_noop_move,\n               _z_pending_query_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_pending_query, _z_pending_query_t, false)\n\nstruct __z_hello_handler_wrapper_t;  // Forward declaration to be used in _z_closure_hello_callback_t\n/**\n * The callback signature of the functions handling hello messages.\n */\ntypedef void (*_z_closure_hello_callback_t)(_z_hello_t *hello, struct __z_hello_handler_wrapper_t *arg);\n\nz_result_t _z_session_generate_zid(_z_id_t *bs, uint8_t size);\n\ntypedef enum {\n    _Z_INTEREST_MSG_TYPE_FINAL = 0,\n    _Z_INTEREST_MSG_TYPE_DECL_SUBSCRIBER = 1,\n    _Z_INTEREST_MSG_TYPE_DECL_QUERYABLE = 2,\n    _Z_INTEREST_MSG_TYPE_DECL_TOKEN = 3,\n    _Z_INTEREST_MSG_TYPE_UNDECL_SUBSCRIBER = 4,\n    _Z_INTEREST_MSG_TYPE_UNDECL_QUERYABLE = 5,\n    _Z_INTEREST_MSG_TYPE_UNDECL_TOKEN = 6,\n    _Z_INTEREST_MSG_TYPE_CONNECTION_DROPPED = 7,\n} _z_interest_msg_type_t;\n\ntypedef struct _z_interest_msg_t {\n    uint32_t id;\n    uint8_t type;\n    const _z_keyexpr_t *key;\n    bool is_complete;\n} _z_interest_msg_t;\n\n/**\n * The callback signature of the functions handling interest messages.\n */\ntypedef void (*_z_interest_handler_t)(const _z_interest_msg_t *msg, _z_transport_peer_common_t *peer, void *arg);\n\ntypedef struct {\n    _z_keyexpr_t _key;\n    uint32_t _id;\n    _z_interest_handler_t _callback;\n    _z_void_rc_t _arg;\n    uint8_t _flags;\n} _z_session_interest_t;\n\nbool _z_session_interest_eq(const _z_session_interest_t *one, const _z_session_interest_t *two);\nvoid _z_session_interest_clear(_z_session_interest_t *res);\n\nstatic inline bool _z_session_interest_is_aggregate(const _z_session_interest_t *intr) {\n    return (intr->_flags & _Z_INTEREST_FLAG_AGGREGATE) != 0;\n}\n\n_Z_REFCOUNT_DEFINE(_z_session_interest, _z_session_interest)\n_Z_ELEM_DEFINE(_z_session_interest, _z_session_interest_t, _z_noop_size, _z_session_interest_clear, _z_noop_copy,\n               _z_noop_move, _z_session_interest_eq, _z_noop_cmp, _z_noop_hash)\n_Z_ELEM_DEFINE(_z_session_interest_rc, _z_session_interest_rc_t, _z_session_interest_rc_size,\n               _z_session_interest_rc_drop, _z_session_interest_rc_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp,\n               _z_noop_hash)\n_Z_SLIST_DEFINE(_z_session_interest_rc, _z_session_interest_rc_t, true)\n\ntypedef enum {\n    _Z_DECLARE_TYPE_SUBSCRIBER = 0,\n    _Z_DECLARE_TYPE_QUERYABLE = 1,\n    _Z_DECLARE_TYPE_TOKEN = 2,\n} _z_declare_type_t;\n\ntypedef struct {\n    _z_keyexpr_t _key;\n    _z_transport_peer_common_t *_peer;\n    uint32_t _id;\n    uint8_t _type;\n    bool _complete;\n} _z_declare_data_t;\n\nvoid _z_declare_data_clear(_z_declare_data_t *data);\nsize_t _z_declare_data_size(_z_declare_data_t *data);\nvoid _z_declare_data_copy(_z_declare_data_t *dst, const _z_declare_data_t *src);\n_Z_ELEM_DEFINE(_z_declare_data, _z_declare_data_t, _z_declare_data_size, _z_declare_data_clear, _z_declare_data_copy,\n               _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_declare_data, _z_declare_data_t, true)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_SESSION_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/subscription.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_SUBSCRIPTION_H\n#define INCLUDE_ZENOH_PICO_SESSION_SUBSCRIPTION_H\n\n#include \"zenoh-pico/collections/lru_cache.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Forward declaration to avoid cyclical include\ntypedef struct _z_session_t _z_session_t;\n\n_Z_SVEC_DEFINE(_z_subscription_rc, _z_subscription_rc_t)\n_Z_REFCOUNT_DEFINE(_z_subscription_rc_svec, _z_subscription_rc_svec)\n\ntypedef struct {\n    _z_keyexpr_t ke;\n    _z_subscription_rc_svec_rc_t infos;\n    bool is_remote;\n} _z_subscription_cache_data_t;\n\nstatic inline _z_subscription_cache_data_t _z_subscription_cache_data_null(void) {\n    _z_subscription_cache_data_t ret = {0};\n    return ret;\n}\n\nvoid _z_unsafe_subscription_cache_invalidate(_z_session_t *zn);\nint _z_subscription_cache_data_compare(const void *first, const void *second);\nvoid _z_subscription_cache_data_clear(_z_subscription_cache_data_t *val);\n\n/*------------------ Subscription ------------------*/\nz_result_t _z_trigger_liveliness_subscriptions_declare(_z_session_t *zn, const _z_wireexpr_t *wireexpr,\n                                                       const _z_timestamp_t *timestamp,\n                                                       _z_transport_peer_common_t *peer);\n\nz_result_t _z_trigger_liveliness_subscriptions_undeclare(_z_session_t *zn, const _z_keyexpr_t *keyexpr,\n                                                         const _z_timestamp_t *timestamp);\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\n#if Z_FEATURE_RX_CACHE == 1\n_Z_ELEM_DEFINE(_z_subscription, _z_subscription_cache_data_t, _z_noop_size, _z_subscription_cache_data_clear,\n               _z_noop_copy, _z_noop_move, _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_LRU_CACHE_DEFINE(_z_subscription, _z_subscription_cache_data_t, _z_subscription_cache_data_compare)\n#endif\n\n_z_subscription_rc_t _z_get_subscription_by_id(_z_session_t *zn, _z_subscriber_kind_t kind, const _z_zint_t id);\n_z_subscription_rc_t _z_register_subscription(_z_session_t *zn, _z_subscriber_kind_t kind, _z_subscription_t *sub);\nz_result_t _z_trigger_subscriptions_impl(_z_session_t *zn, _z_subscriber_kind_t sub_kind, _z_wireexpr_t *wireexpr,\n                                         _z_bytes_t *payload, _z_encoding_t *encoding, const _z_zint_t sample_kind,\n                                         const _z_timestamp_t *timestamp, const _z_n_qos_t qos, _z_bytes_t *attachment,\n                                         z_reliability_t reliability, _z_source_info_t *source_info,\n                                         _z_transport_peer_common_t *peer);\nvoid _z_unregister_subscription(_z_session_t *zn, _z_subscriber_kind_t kind, _z_subscription_rc_t *sub);\nvoid _z_flush_subscriptions(_z_session_t *zn);\n\nstatic inline z_result_t _z_trigger_subscriptions_put(_z_session_t *zn, _z_wireexpr_t *wireexpr, _z_bytes_t *payload,\n                                                      _z_encoding_t *encoding, const _z_timestamp_t *timestamp,\n                                                      const _z_n_qos_t qos, _z_bytes_t *attachment,\n                                                      z_reliability_t reliability, _z_source_info_t *source_info,\n                                                      _z_transport_peer_common_t *peer) {\n    return _z_trigger_subscriptions_impl(zn, _Z_SUBSCRIBER_KIND_SUBSCRIBER, wireexpr, payload, encoding,\n                                         Z_SAMPLE_KIND_PUT, timestamp, qos, attachment, reliability, source_info, peer);\n}\nstatic inline z_result_t _z_trigger_subscriptions_del(_z_session_t *zn, _z_wireexpr_t *wireexpr,\n                                                      const _z_timestamp_t *timestamp, const _z_n_qos_t qos,\n                                                      _z_bytes_t *attachment, z_reliability_t reliability,\n                                                      _z_source_info_t *source_info, _z_transport_peer_common_t *peer) {\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_bytes_t payload = _z_bytes_null();\n    return _z_trigger_subscriptions_impl(zn, _Z_SUBSCRIBER_KIND_SUBSCRIBER, wireexpr, &payload, &encoding,\n                                         Z_SAMPLE_KIND_DELETE, timestamp, qos, attachment, reliability, source_info,\n                                         peer);\n}\n#else   // Z_FEATURE_SUBSCRIPTION == 0\nstatic inline z_result_t _z_trigger_subscriptions_put(_z_session_t *zn, _z_wireexpr_t *wireexpr, _z_bytes_t *payload,\n                                                      _z_encoding_t *encoding, const _z_timestamp_t *timestamp,\n                                                      const _z_n_qos_t qos, _z_bytes_t *attachment,\n                                                      z_reliability_t reliability, _z_source_info_t *source_info,\n                                                      _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(wireexpr);\n    _ZP_UNUSED(payload);\n    _ZP_UNUSED(encoding);\n    _ZP_UNUSED(qos);\n    _ZP_UNUSED(timestamp);\n    _ZP_UNUSED(attachment);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(source_info);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nstatic inline z_result_t _z_trigger_subscriptions_del(_z_session_t *zn, _z_wireexpr_t *wireexpr,\n                                                      const _z_timestamp_t *timestamp, const _z_n_qos_t qos,\n                                                      _z_bytes_t *attachment, z_reliability_t reliability,\n                                                      _z_source_info_t *source_info, _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(wireexpr);\n    _ZP_UNUSED(qos);\n    _ZP_UNUSED(timestamp);\n    _ZP_UNUSED(attachment);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(source_info);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_SUBSCRIPTION_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/utils.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_UTILS_H\n#define INCLUDE_ZENOH_PICO_SESSION_UTILS_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Session ------------------*/\n_z_hello_slist_t *_z_scout_inner(const z_what_t what, _z_id_t id, _z_string_t *locator, const uint32_t timeout,\n                                 const bool exit_on_first);\n\nz_result_t _z_session_init(_z_session_t *zn, const _z_id_t *zid);\nvoid _z_session_clear(_z_session_t *zn);\nz_result_t _z_session_close(_z_session_t *zn);\n\nz_result_t _z_handle_network_message(_z_transport_common_t *transport, _z_zenoh_message_t *z_msg,\n                                     _z_transport_peer_common_t *peer);\n\n#if Z_FEATURE_MULTI_THREAD == 1\nstatic inline z_result_t _z_session_mutex_lock(_z_session_t *zn) { return _z_mutex_lock(&zn->_mutex_inner); }\nstatic inline z_result_t _z_session_mutex_lock_if_open(_z_session_t *zn) {\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&zn->_mutex_inner));\n    if (_z_session_is_closed(zn)) {\n        _z_mutex_unlock(&zn->_mutex_inner);\n        return _Z_ERR_SESSION_CLOSED;\n    }\n    return _Z_RES_OK;\n}\nstatic inline void _z_session_mutex_unlock(_z_session_t *zn) { (void)_z_mutex_unlock(&zn->_mutex_inner); }\nstatic inline void _z_session_transport_mutex_lock(_z_session_t *zn) { (void)_z_mutex_rec_lock(&zn->_mutex_transport); }\nstatic inline void _z_session_transport_mutex_unlock(_z_session_t *zn) {\n    (void)_z_mutex_rec_unlock(&zn->_mutex_transport);\n}\n#if Z_FEATURE_ADMIN_SPACE == 1\nstatic inline void _z_session_admin_space_mutex_lock(_z_session_t *zn) { (void)_z_mutex_lock(&zn->_mutex_admin_space); }\nstatic inline void _z_session_admin_space_mutex_unlock(_z_session_t *zn) {\n    (void)_z_mutex_unlock(&zn->_mutex_admin_space);\n}\n#else\nstatic inline void _z_session_admin_space_mutex_lock(_z_session_t *zn) { _ZP_UNUSED(zn); }\nstatic inline void _z_session_admin_space_mutex_unlock(_z_session_t *zn) { _ZP_UNUSED(zn); }\n#endif\n#else\nstatic inline z_result_t _z_session_mutex_lock(_z_session_t *zn) {\n    _ZP_UNUSED(zn);\n    return _Z_RES_OK;\n}\nstatic inline z_result_t _z_session_mutex_lock_if_open(_z_session_t *zn) {\n    return _z_session_is_closed(zn) ? _Z_ERR_SESSION_CLOSED : _Z_RES_OK;\n}\nstatic inline void _z_session_mutex_unlock(_z_session_t *zn) { _ZP_UNUSED(zn); }\nstatic inline void _z_session_transport_mutex_lock(_z_session_t *zn) { _ZP_UNUSED(zn); }\nstatic inline void _z_session_transport_mutex_unlock(_z_session_t *zn) { _ZP_UNUSED(zn); }\nstatic inline void _z_session_admin_space_mutex_lock(_z_session_t *zn) { _ZP_UNUSED(zn); }\nstatic inline void _z_session_admin_space_mutex_unlock(_z_session_t *zn) { _ZP_UNUSED(zn); }\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_UTILS_H */\n"
  },
  {
    "path": "include/zenoh-pico/session/weak_session.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_SESSION_WEAK_SESSION_H\n#define INCLUDE_ZENOH_PICO_SESSION_WEAK_SESSION_H\n\n#include \"zenoh-pico/collections/refcount.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Forward declaration to avoid cyclical include\ntypedef struct _z_session_t _z_session_t;\nextern void _z_session_clear(_z_session_t *zn);\n_Z_REFCOUNT_DEFINE_NO_FROM_VAL(_z_session, _z_session)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_SESSION_WEAK_SESSION_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/common/platform.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#ifndef ZENOH_PICO_SYSTEM_PLATFORM_COMMON_H\n#define ZENOH_PICO_SYSTEM_PLATFORM_COMMON_H\n\n#ifndef SPHINX_DOCS\n// For some reason sphinx/clang doesn't handle bool types correctly if stdbool.h is included\n#include <stdbool.h>\n#endif\n#include <stdint.h>\n\n#include \"zenoh-pico/api/olv_macros.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/* Centralized built-in socket markers for TCP/UDP/WS/TLS transports that use\n * the platform socket layer. */\n#if !defined(ZP_PLATFORM_SOCKET_POSIX) && (defined(ZENOH_LINUX) || defined(ZENOH_MACOS) || defined(ZENOH_BSD))\n#define ZP_PLATFORM_SOCKET_POSIX 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_WINDOWS) && defined(ZENOH_WINDOWS)\n#define ZP_PLATFORM_SOCKET_WINDOWS 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_ZEPHYR) && defined(ZENOH_ZEPHYR)\n#define ZP_PLATFORM_SOCKET_ZEPHYR 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_FREERTOS_PLUS_TCP) && defined(ZENOH_FREERTOS_PLUS_TCP)\n#define ZP_PLATFORM_SOCKET_FREERTOS_PLUS_TCP 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_LWIP) && (defined(ZENOH_FREERTOS_LWIP) || defined(ZENOH_RPI_PICO))\n#define ZP_PLATFORM_SOCKET_LWIP 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_ESP32) && (defined(ZENOH_ESPIDF) || defined(ZENOH_ARDUINO_ESP32))\n#define ZP_PLATFORM_SOCKET_ESP32 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_MBED) && defined(ZENOH_MBED)\n#define ZP_PLATFORM_SOCKET_MBED 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_OPENCR) && defined(ZENOH_ARDUINO_OPENCR)\n#define ZP_PLATFORM_SOCKET_OPENCR 1\n#endif\n\n#if !defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED) &&                                    \\\n    (Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_TLS == 1 || Z_FEATURE_LINK_WS == 1 || \\\n     Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1)\n#define ZP_PLATFORM_SOCKET_LINKS_ENABLED 1\n#endif\n\n#ifdef ZP_SYSTEM_PLATFORM_HEADER\n#include ZP_SYSTEM_PLATFORM_HEADER\n#elif defined(ZENOH_LINUX) || defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n#include \"zenoh-pico/system/platform/unix.h\"\n#elif defined(ZENOH_WINDOWS)\n#define NOMINMAX\n#include \"zenoh-pico/system/platform/windows.h\"\n#elif defined(ZENOH_ESPIDF)\n#include \"zenoh-pico/system/platform/espidf.h\"\n#elif defined(ZENOH_MBED)\n#include \"zenoh-pico/system/platform/mbed.h\"\n#elif defined(ZENOH_ZEPHYR)\n#include \"zenoh-pico/system/platform/zephyr.h\"\n#elif defined(ZENOH_ARDUINO_ESP32)\n#include \"zenoh-pico/system/platform/arduino/esp32.h\"\n#elif defined(ZENOH_ARDUINO_OPENCR)\n#include \"zenoh-pico/system/platform/arduino/opencr.h\"\n#elif defined(ZENOH_EMSCRIPTEN)\n#include \"zenoh-pico/system/platform/emscripten.h\"\n#elif defined(ZENOH_FLIPPER)\n#include \"zenoh-pico/system/platform/flipper.h\"\n#elif defined(ZENOH_FREERTOS_PLUS_TCP)\n#include \"zenoh-pico/system/platform/freertos/freertos_plus_tcp.h\"\n#elif defined(ZENOH_FREERTOS_LWIP)\n#include \"zenoh-pico/system/platform/freertos/lwip.h\"\n#elif defined(ZENOH_RPI_PICO)\n#include \"zenoh-pico/system/platform/rpi_pico.h\"\n#elif defined(ZENOH_GENERIC)\n#include \"zenoh_generic_platform.h\"\n#elif defined(ZENOH_THREADX_STM32)\n#include \"zenoh-pico/system/platform/threadx/stm32.h\"\n#else\n#include \"zenoh-pico/system/platform/void.h\"\n#error \"Unknown platform\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Random ------------------*/\n/**\n * Generates a random unsigned 8-bit integer.\n */\nuint8_t z_random_u8(void);\n\n/**\n * Generates a random unsigned 16-bit integer.\n */\nuint16_t z_random_u16(void);\n\n/**\n * Generates a random unsigned 32-bit integer.\n */\nuint32_t z_random_u32(void);\n\n/**\n * Generates a random unsigned 64-bit integer.\n */\nuint64_t z_random_u64(void);\n\n/**\n * Fills buffer with random data.\n *\n * Parameters:\n *   buf: Pointer to the buffer that will be filled with random data.\n *   len: Number of bytes to fill in the buffer.\n */\nvoid z_random_fill(void *buf, size_t len);\n\n/*------------------ Memory ------------------*/\n\n/**\n * Allocates memory of the specified size.\n *\n * Parameters:\n *   size: The number of bytes to allocate.\n *\n * Returns:\n *   A pointer to the allocated memory, or NULL if the allocation fails.\n */\nvoid *z_malloc(size_t size);\n\n/**\n * Reallocates the given memory block to a new size.\n *\n * Parameters:\n *   ptr: Pointer to the previously allocated memory. Can be NULL, in which case it behaves like z_malloc().\n *   size: The new size for the memory block in bytes.\n *\n * Returns:\n *   A pointer to the reallocated memory, or NULL if the reallocation fails.\n */\nvoid *z_realloc(void *ptr, size_t size);\n\n/**\n * Frees the memory previously allocated by z_malloc or z_realloc.\n *\n * Parameters:\n *   ptr: Pointer to the memory to be freed. If NULL, no action is taken.\n */\nvoid z_free(void *ptr);\n\n#if Z_FEATURE_MULTI_THREAD == 0\n// dummy types for correct macros work\ntypedef void *_z_task_t;\ntypedef void *_z_mutex_t;\ntypedef void *_z_mutex_rec_t;\ntypedef void *_z_condvar_t;\ntypedef void *z_task_attr_t;\ntypedef void *_z_task_id_t;\n#endif\n\n/*------------------ Thread ------------------*/\n_Z_OWNED_TYPE_VALUE(_z_task_t, task)\n_Z_OWNED_FUNCTIONS_SYSTEM_DEF(task)\n\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg);\nz_result_t _z_task_join(_z_task_t *task);\nz_result_t _z_task_detach(_z_task_t *task);\nz_result_t _z_task_cancel(_z_task_t *task);\nvoid _z_task_exit(void);\nvoid _z_task_free(_z_task_t **task);\n_z_task_id_t _z_task_get_id(const _z_task_t *task);\n_z_task_id_t _z_task_current_id(void);\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r);\n\n/**\n * Constructs a new task.\n *\n * Parameters:\n *   task: An uninitialized memory location where task will be constructed.\n *   attr: Attributes of the task.\n *   fun: Function to be executed by the task.\n *   arg: Argument that will be passed to the function `fun`.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_task_init(z_owned_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg);\n\n/**\n * Joins the task and releases all allocated resources.\n *\n * Parameters:\n *   task: Pointer to a :c:type:`z_moved_task_t` representing the task to be joined.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_task_join(z_moved_task_t *task);\n\n/**\n * Detaches the task and releases all allocated resources.\n *\n * Parameters:\n *   task: Pointer to a :c:type:`z_moved_task_t` representing the task to be detached.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_task_detach(z_moved_task_t *task);\n\n/**\n * Drops the task. Same as :c:func:`z_task_detach`. Use :c:func:`z_task_join` to wait for the task completion.\n *\n * Parameters:\n *   task: Pointer to a :c:type:`z_moved_task_t` representing the task to be dropped.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_task_drop(z_moved_task_t *task);\n\n/*------------------ Mutex ------------------*/\n_Z_OWNED_TYPE_VALUE(_z_mutex_t, mutex)\n_Z_OWNED_FUNCTIONS_SYSTEM_DEF(mutex)\n\nz_result_t _z_mutex_init(_z_mutex_t *m);\nz_result_t _z_mutex_drop(_z_mutex_t *m);\n\nz_result_t _z_mutex_lock(_z_mutex_t *m);\nz_result_t _z_mutex_try_lock(_z_mutex_t *m);\nz_result_t _z_mutex_unlock(_z_mutex_t *m);\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m);\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m);\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m);\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m);\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m);\n\n/**\n * Constructs a mutex.\n *\n * Parameters:\n *   m: Pointer to an uninitialized :c:type:`z_owned_mutex_t` that will be constructed.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_mutex_init(z_owned_mutex_t *m);\n\n/**\n * Drops a mutex and resets it to its gravestone state.\n *\n * Parameters:\n *   m: Pointer to a :c:type:`z_moved_mutex_t` that will be dropped.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_mutex_drop(z_moved_mutex_t *m);\n\n/**\n * Locks a mutex. If the mutex is already locked, blocks the thread until it acquires the lock.\n *\n * Parameters:\n *   m: Pointer to a :c:type:`z_loaned_mutex_t` that will be locked.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_mutex_lock(z_loaned_mutex_t *m);\n\n/**\n * Tries to lock a mutex. If the mutex is already locked, the function returns immediately.\n *\n * Parameters:\n *   m: Pointer to a :c:type:`z_loaned_mutex_t` that will be locked if not already locked.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_mutex_try_lock(z_loaned_mutex_t *m);\n\n/**\n * Unlocks a previously locked mutex. If the mutex was not locked by the current thread, the behavior is undefined.\n *\n * Parameters:\n *   m: Pointer to a :c:type:`z_loaned_mutex_t` that will be unlocked.\n *\n * Returns:\n *   ``0`` in case of success, negative error code otherwise.\n */\nz_result_t z_mutex_unlock(z_loaned_mutex_t *m);\n\n/*------------------ CondVar ------------------*/\n_Z_OWNED_TYPE_VALUE(_z_condvar_t, condvar)\n_Z_OWNED_FUNCTIONS_SYSTEM_DEF(condvar)\n\nz_result_t _z_condvar_init(_z_condvar_t *cv);\nz_result_t _z_condvar_drop(_z_condvar_t *cv);\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv);\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv);\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m);\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime);\n\n/**\n * Initializes a condition variable.\n *\n * Parameters:\n *   cv: Pointer to an uninitialized :c:type:`z_owned_condvar_t` that will be initialized.\n *\n * Returns:\n *   ``0`` if the initialization is successful, a negative value otherwise.\n */\nz_result_t z_condvar_init(z_owned_condvar_t *cv);\n\n/**\n * Destroys a condition variable and releases its resources.\n *\n * Parameters:\n *   cv: Pointer to a :c:type:`z_moved_condvar_t` that will be destroyed.\n *\n * Returns:\n *   ``0`` if the destruction is successful, a negative value otherwise.\n */\nz_result_t z_condvar_drop(z_moved_condvar_t *cv);\n\n/**\n * Signals (wakes up) one thread waiting on the condition variable.\n *\n * Parameters:\n *   cv: Pointer to a :c:type:`z_loaned_condvar_t` that will be signaled.\n *\n * Returns:\n *   ``0`` if the signal is successful, a negative value otherwise.\n */\nz_result_t z_condvar_signal(z_loaned_condvar_t *cv);\n\n/**\n * Waits for a signal on the condition variable while holding a mutex.\n *\n * The calling thread is blocked until the condition variable is signaled.\n * The associated mutex must be locked by the calling thread, and it will be automatically unlocked while waiting.\n *\n * Parameters:\n *   cv: Pointer to a :c:type:`z_loaned_condvar_t` on which to wait.\n *   m: Pointer to a :c:type:`z_loaned_mutex_t` that will be unlocked during the wait.\n *\n * Returns:\n *   ``0`` if the wait is successful, a negative value otherwise.\n */\nz_result_t z_condvar_wait(z_loaned_condvar_t *cv, z_loaned_mutex_t *m);\n\n/**\n * Waits for a signal on the condition variable while holding a mutex until a specified time.\n *\n * The calling thread is blocked until the condition variable is signaled or the timeout occurs.\n * The associated mutex must be locked by the calling thread, and it will be automatically unlocked while waiting.\n *\n * Parameters:\n *   cv: Pointer to a :c:type:`z_loaned_condvar_t` on which to wait.\n *   m: Pointer to a :c:type:`z_loaned_mutex_t` that will be unlocked during the wait.\n *   abstime: Absolute end time.\n *\n * Returns:\n *   ``0`` if the wait is successful, ``Z_ETIMEDOUT`` if a timeout occurred, other negative value otherwise.\n */\nz_result_t z_condvar_wait_until(z_loaned_condvar_t *cv, z_loaned_mutex_t *m, const z_clock_t *abstime);\n\n/*------------------ Sleep ------------------*/\n/**\n * Suspends execution for a specified amount of time in microseconds.\n *\n * Parameters:\n *   time: The amount of time to sleep, in microseconds.\n *\n * Returns:\n *   ``0`` if the sleep is successful, a negative value otherwise.\n */\nz_result_t z_sleep_us(size_t time);\n\n/**\n * Suspends execution for a specified amount of time in milliseconds.\n *\n * Parameters:\n *   time: The amount of time to sleep, in milliseconds.\n *\n * Returns:\n *   ``0`` if the sleep is successful, a negative value otherwise.\n */\nz_result_t z_sleep_ms(size_t time);\n\n/**\n * Suspends execution for a specified amount of time in seconds.\n *\n * Parameters:\n *   time: The amount of time to sleep, in seconds.\n *\n * Returns:\n *   ``0`` if the sleep is successful, a negative value otherwise.\n */\nz_result_t z_sleep_s(size_t time);\n\n/*------------------ Clock ------------------*/\n/**\n * Returns monotonic clock time point corresponding to the current time instant.\n */\nz_clock_t z_clock_now(void);\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch);\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch);\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch);\n\n/**\n * Returns the elapsed time in microseconds since a given clock time.\n *\n * Parameters:\n *   time: Pointer to a `z_clock_t` representing the starting time.\n *\n * Returns:\n *   The elapsed time in microseconds.\n */\nunsigned long z_clock_elapsed_us(z_clock_t *time);\n\n/**\n * Returns the elapsed time in milliseconds since a given clock time.\n *\n * Parameters:\n *   time: Pointer to a `z_clock_t` representing the starting time.\n *\n * Returns:\n *   The elapsed time in milliseconds.\n */\nunsigned long z_clock_elapsed_ms(z_clock_t *time);\n\n/**\n * Returns the elapsed time in seconds since a given clock time.\n *\n * Parameters:\n *   time: Pointer to a `z_clock_t` representing the starting time.\n *\n * Returns:\n *   The elapsed time in seconds.\n */\nunsigned long z_clock_elapsed_s(z_clock_t *time);\n\n/**\n * Offsets the clock by a specified duration in microseconds.\n *\n * Parameters:\n *   clock: Pointer to a `z_clock_t` to offset.\n *   duration: The duration in microseconds.\n */\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration);\n\n/**\n * Offsets the clock by a specified duration in milliseconds.\n *\n * Parameters:\n *   clock: Pointer to a `z_clock_t` to offset.\n *   duration: The duration in milliseconds.\n */\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration);\n\n/**\n * Offsets the clock by a specified duration in seconds.\n *\n * Parameters:\n *   clock: Pointer to a `z_clock_t` to offset.\n *   duration: The duration in seconds.\n */\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration);\n\n/*------------------ Time ------------------*/\n\n/**\n * Returns system clock time point corresponding to the current time instant.\n */\nz_time_t z_time_now(void);\n\n/**\n * Gets the current time as a string.\n *\n * Parameters:\n *   buf: Pointer to a buffer where the time string will be written.\n *   buflen: The length of the buffer.\n *\n * Returns:\n *   A pointer to the buffer containing the time string.\n */\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen);\n\n/**\n * Returns the elapsed time in microseconds since a given time.\n *\n * Parameters:\n *   time: Pointer to a `z_time_t` representing the starting time.\n *\n * Returns:\n *   The elapsed time in microseconds.\n */\nunsigned long z_time_elapsed_us(z_time_t *time);\n\n/**\n * Returns the elapsed time in milliseconds since a given time.\n *\n * Parameters:\n *   time: Pointer to a `z_time_t` representing the starting time.\n *\n * Returns:\n *   The elapsed time in milliseconds.\n */\nunsigned long z_time_elapsed_ms(z_time_t *time);\n\n/**\n * Returns the elapsed time in seconds since a given time.\n *\n * Parameters:\n *   time: Pointer to a `z_time_t` representing the starting time.\n *\n * Returns:\n *   The elapsed time in seconds.\n */\nunsigned long z_time_elapsed_s(z_time_t *time);\n\ntypedef struct {\n    uint32_t secs;\n    uint32_t nanos;\n} _z_time_since_epoch;\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t);\n\n/*------------------ P2p unicast internal functions ------------------*/\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking);\nz_result_t _z_ip_port_to_endpoint(const uint8_t *address, size_t address_len, uint16_t port, char *dst, size_t dst_len);\nz_result_t _z_socket_get_endpoints(const _z_sys_net_socket_t *sock, char *local, size_t local_len, char *remote,\n                                   size_t remote_len);\nvoid _z_socket_close(_z_sys_net_socket_t *sock);\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_PLATFORM_COMMON_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/common/system_error.h",
    "content": "#ifndef ZENOH_PICO_SYSTEM_COMMON_SYSTEM_ERROR_H\n#define ZENOH_PICO_SYSTEM_COMMON_SYSTEM_ERROR_H\n\n#include \"zenoh-pico/utils/logging.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic inline void _z_report_system_error(int errcode) { _Z_ERROR(\"System error: %i\", errcode); }\n\n#define _Z_CHECK_SYS_ERR(expr)                      \\\n    do {                                            \\\n        int __res = expr;                           \\\n        if (__res != 0) {                           \\\n            _z_report_system_error(__res);          \\\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_GENERIC); \\\n        }                                           \\\n        return _Z_RES_OK;                           \\\n    } while (false)\n\n#define _Z_RETURN_IF_SYS_ERR(expr)                  \\\n    do {                                            \\\n        int __res = expr;                           \\\n        if (__res != 0) {                           \\\n            _z_report_system_error(__res);          \\\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_GENERIC); \\\n        }                                           \\\n    } while (false)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_COMMON_SYSTEM_ERROR_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/arduino/esp32.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_ESP32_TYPES_H\n#define ZENOH_PICO_SYSTEM_ESP32_TYPES_H\n\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#include <pthread.h>\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct {\n    const char *name;\n    UBaseType_t priority;\n    size_t stack_depth;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    bool static_allocation;\n    StackType_t *stack_buffer;\n    StaticTask_t *task_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} z_task_attr_t;\ntypedef struct {\n    TaskHandle_t handle;\n    EventGroupHandle_t join_event;\n} _z_task_t;\ntypedef pthread_mutex_t _z_mutex_t;\ntypedef pthread_mutex_t _z_mutex_rec_t;\ntypedef pthread_cond_t _z_condvar_t;\ntypedef TaskHandle_t _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct BluetoothSerial BluetoothSerial;  // Forward declaration to be used in _z_sys_net_socket_t\ntypedef struct HardwareSerial HardwareSerial;    // Forward declaration to be used in _z_sys_net_socket_t\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        int _fd;\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n        BluetoothSerial *_bts;  // As pointer to cross the boundary between C and C++\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        HardwareSerial *_serial;  // As pointer to cross the boundary between C and C++\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on ESP32 port of Zenoh-Pico\"\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_ESP32_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/arduino/opencr.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_ARDUINO_OPENCR_TYPES_H\n#define ZENOH_PICO_SYSTEM_ARDUINO_OPENCR_TYPES_H\n\n#include <stddef.h>\n#include <sys/time.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef void *_z_task_t;\ntypedef void *z_task_attr_t;\ntypedef void *_z_mutex_t;\ntypedef void *_z_condvar_t;\ntypedef void *_z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct IPAddress IPAddress;    // Forward declaration to be used in __z_net_iptcp_addr_t\ntypedef struct WiFiClient WiFiClient;  // Forward declaration to be used in _z_sys_net_socket_t\ntypedef struct WiFiUDP WiFiUDP;        // Forward declaration to be used in _z_sys_net_socket_t\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_TCP == 1\n        WiFiClient *_tcp;  // As pointer to cross the boundary between C and C++\n#endif\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1\n        WiFiUDP *_udp;  // As pointer to cross the boundary between C and C++\n#endif\n        bool _err;\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    IPAddress *_addr;  // As pointer to cross the boundary between C and C++\n    uint16_t _port;\n} __z_net_iptcp_addr_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        __z_net_iptcp_addr_t _iptcp;\n#endif\n    };\n    bool _err;\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_ARDUINO_OPENCR_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/emscripten.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_WASM_TYPES_H\n#define ZENOH_PICO_SYSTEM_WASM_TYPES_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#include <pthread.h>\n\ntypedef pthread_t _z_task_t;\ntypedef pthread_attr_t z_task_attr_t;\ntypedef pthread_mutex_t _z_mutex_t;\ntypedef pthread_mutex_t _z_mutex_rec_t;\ntypedef pthread_cond_t _z_condvar_t;\ntypedef pthread_t _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef double z_clock_t;\ntypedef double z_time_t;\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_WS == 1\n        struct {\n            int _fd;\n            uint32_t _tout;\n        } _ws;\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_WS == 1\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_WASM_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/espidf.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_ESPIDF_TYPES_H\n#define ZENOH_PICO_SYSTEM_ESPIDF_TYPES_H\n\n#include <driver/uart.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/event_groups.h>\n#include <freertos/task.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#include <pthread.h>\n\ntypedef struct {\n    const char *name;\n    UBaseType_t priority;\n    size_t stack_depth;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    bool static_allocation;\n    StackType_t *stack_buffer;\n    StaticTask_t *task_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} z_task_attr_t;\ntypedef struct {\n    TaskHandle_t handle;\n    EventGroupHandle_t join_event;\n} _z_task_t;\ntypedef pthread_mutex_t _z_mutex_t;\ntypedef pthread_mutex_t _z_mutex_rec_t;\ntypedef pthread_cond_t _z_condvar_t;\ntypedef TaskHandle_t _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        int _fd;\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        uart_port_t _serial;\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on ESP-IDF port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on ESP-IDF port of Zenoh-Pico\"\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_ESPIDF_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/flipper.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_FLIPPER_TYPES_H\n#define ZENOH_PICO_SYSTEM_FLIPPER_TYPES_H\n\n#include <furi.h>\n#include <furi_hal.h>\n#include <sys/time.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define FLIPPER_DEFAULT_THREAD_STACK_SIZE 2048\n#define FLIPPER_SERIAL_STREAM_BUFFER_SIZE 512\n#define FLIPPER_SERIAL_STREAM_TRIGGERED_LEVEL 10\n#define FLIPPER_SERIAL_TIMEOUT_MS 200\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef FuriThread* _z_task_t;\ntypedef uint32_t z_task_attr_t;\ntypedef FuriMutex* _z_mutex_t;\ntypedef void* _z_mutex_t;\ntypedef void* _z_condvar_t;\ntypedef FuriThreadId _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n#if Z_FEATURE_LINK_SERIAL == 1\n    FuriStreamBuffer* _rx_stream;\n    FuriHalSerialHandle* _serial;\n#endif\n} _z_sys_net_socket_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_FLIPPER_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/freertos/freertos_plus_tcp.h",
    "content": "//\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#ifndef ZENOH_PICO_SYSTEM_FREERTOS_PLUS_TCP_TYPES_H\n#define ZENOH_PICO_SYSTEM_FREERTOS_PLUS_TCP_TYPES_H\n\n#include <time.h>\n\n#include \"FreeRTOS.h\"\n#include \"FreeRTOS_IP.h\"\n#include \"semphr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct {\n    const char *name;\n    UBaseType_t priority;\n    size_t stack_depth;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    bool static_allocation;\n    StackType_t *stack_buffer;\n    StaticTask_t *task_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} z_task_attr_t;\n\ntypedef struct {\n    TaskHandle_t handle;\n    EventGroupHandle_t join_event;\n    void *(*fun)(void *);\n    void *arg;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    StaticEventGroup_t join_event_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} _z_task_t;\n\ntypedef struct {\n    SemaphoreHandle_t handle;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    StaticSemaphore_t buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} _z_mutex_t;\n\ntypedef _z_mutex_t _z_mutex_rec_t;\n\ntypedef struct {\n    SemaphoreHandle_t mutex;\n    SemaphoreHandle_t sem;\n    int waiters;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    StaticSemaphore_t mutex_buffer;\n    StaticSemaphore_t sem_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} _z_condvar_t;\n\ntypedef TaskHandle_t _z_task_id_t;\n#endif  // Z_MULTI_THREAD == 1\n\ntypedef TickType_t z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        Socket_t _socket;\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct freertos_addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/freertos/lwip.h",
    "content": "//\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   João Mário Lago, <joaolago@bluerobotics.com>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_FREERTOS_PLUS_LWIP_TYPES_H\n#define ZENOH_PICO_SYSTEM_FREERTOS_PLUS_LWIP_TYPES_H\n\n#include <time.h>\n\n#include \"FreeRTOS.h\"\n#include \"lwip/sockets.h\"\n#include \"semphr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#include \"event_groups.h\"\n\ntypedef struct {\n    const char *name;\n    UBaseType_t priority;\n    size_t stack_depth;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    bool static_allocation;\n    StackType_t *stack_buffer;\n    StaticTask_t *task_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} z_task_attr_t;\n\ntypedef struct {\n    TaskHandle_t handle;\n    EventGroupHandle_t join_event;\n    void *(*fun)(void *);\n    void *arg;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    StaticEventGroup_t join_event_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} _z_task_t;\n\ntypedef struct {\n    SemaphoreHandle_t handle;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    StaticSemaphore_t buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} _z_mutex_t;\n\ntypedef _z_mutex_t _z_mutex_rec_t;\n\ntypedef struct {\n    SemaphoreHandle_t mutex;\n    SemaphoreHandle_t sem;\n    int waiters;\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    StaticSemaphore_t mutex_buffer;\n    StaticSemaphore_t sem_buffer;\n#endif /* SUPPORT_STATIC_ALLOCATION */\n} _z_condvar_t;\n\ntypedef TaskHandle_t _z_task_id_t;\n#endif  // Z_MULTI_THREAD == 1\n\ntypedef TickType_t z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        int _socket;\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP) && defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n#define ZP_LWIP_SOCKET_HELPERS_DEFINED 1\nstatic inline int _z_lwip_socket_get(_z_sys_net_socket_t sock) { return sock._socket; }\nstatic inline void _z_lwip_socket_set(_z_sys_net_socket_t *sock, int fd) { sock->_socket = fd; }\n#endif\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on FreeRTOS + LWIP port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#error \"Serial not supported yet on FreeRTOS + LWIP port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on FreeRTOS + LWIP port of Zenoh-Pico\"\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/mbed.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_MBED_TYPES_H\n#define ZENOH_PICO_SYSTEM_MBED_TYPES_H\n\n#include <stdint.h>\n#include <sys/time.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef int _z_socket_t;\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef void *_z_task_t;       // Workaround as MBED is a C++ library\ntypedef void *z_task_attr_t;   // Workaround as MBED is a C++ library\ntypedef void *_z_mutex_t;      // Workaround as MBED is a C++ library\ntypedef void *_z_mutex_rec_t;  // Workaround as MBED is a C++ library\ntypedef void *_z_condvar_t;    // Workaround as MBED is a C++ library\ntypedef void *_z_task_id_t;    // osThreadId_t is defined as void* in MBED\n#endif                         // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct BufferedSerial BufferedSerial;  // Forward declaration to be used in _z_sys_net_socket_t\ntypedef struct UDPSocket UDPSocket;            // Forward declaration to be used in _z_sys_net_socket_t\ntypedef struct TCPSocket TCPSocket;            // Forward declaration to be used in _z_sys_net_socket_t\ntypedef struct SocketAddress SocketAddress;    // Forward declaration to be used in _z_sys_net_endpoint_t\n\ntypedef struct {\n    bool _err;\n    union {\n#if Z_FEATURE_LINK_TCP == 1\n        TCPSocket *_tcp;  // As pointer to cross the boundary between C and C++\n#endif\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1\n        UDPSocket *_udp;  // As pointer to cross the boundary between C and C++\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        BufferedSerial *_serial;  // As pointer to cross the boundary between C and C++\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    bool _err;\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        SocketAddress *_iptcp;  // As pointer to cross the boundary between C and C++\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_MBED_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/rpi_pico.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_RPI_PICO_TYPES_H\n#define ZENOH_PICO_SYSTEM_RPI_PICO_TYPES_H\n\n#include <time.h>\n\n#include \"FreeRTOS.h\"\n#include \"event_groups.h\"\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1\n#include \"lwip/ip4_addr.h\"\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n#include \"hardware/gpio.h\"\n#include \"hardware/uart.h\"\n#endif\n#include \"semphr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct {\n    const char *name;\n    UBaseType_t priority;\n    size_t stack_depth;\n} z_task_attr_t;\n\ntypedef struct {\n    TaskHandle_t handle;\n    EventGroupHandle_t join_event;\n} _z_task_t;\n\ntypedef SemaphoreHandle_t _z_mutex_t;\ntypedef SemaphoreHandle_t _z_mutex_rec_t;\ntypedef struct {\n    SemaphoreHandle_t mutex;\n    SemaphoreHandle_t sem;\n    int waiters;\n} _z_condvar_t;\ntypedef TaskHandle_t _z_task_id_t;\n#endif  // Z_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        int _fd;\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        uart_inst_t *_serial;\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP) && defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n#define ZP_LWIP_SOCKET_HELPERS_DEFINED 1\nstatic inline int _z_lwip_socket_get(_z_sys_net_socket_t sock) { return sock._fd; }\nstatic inline void _z_lwip_socket_set(_z_sys_net_socket_t *sock, int fd) { sock->_fd = fd; }\n#endif\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on Raspberry Pi Pico W port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on Raspberry Pi Pico W port of Zenoh-Pico\"\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#if Z_FEATURE_LINK_SERIAL_USB == 1\nvoid _z_usb_uart_init();\nvoid _z_usb_uart_deinit();\nvoid _z_usb_uart_write(const uint8_t *buf, int length);\nuint8_t _z_usb_uart_getc();\n#endif\n\n#endif  // ZENOH_PICO_SYSTEM_RPI_PICO_TYPES_H\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/threadx/stm32.h",
    "content": "#ifndef ZENOH_PICO_SYSTEM_THREADX_TYPES_H\n#define ZENOH_PICO_SYSTEM_THREADX_TYPES_H\n\n#include <sys/_timespec.h>\n\n#include \"zenoh-pico/config.h\"\n/*\n * hal.h needs to be provided by application layer. It should include\n * the necessary stm32 HAL headers for your target (ex. stm32f4xx_hal.h).\n */\n#include \"hal.h\"\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#include \"tx_api.h\"\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\n\n#ifndef Z_TASK_STACK_SIZE\n#define Z_TASK_STACK_SIZE 4096\n#endif\n\n#ifndef Z_TASK_PRIORITY\n#define Z_TASK_PRIORITY 14\n#endif\n\n#ifndef Z_TASK_PREEMPT_THRESHOLD\n#define Z_TASK_PREEMPT_THRESHOLD 14\n#endif\n\n#ifndef Z_TASK_TIME_SLICE\n#define Z_TASK_TIME_SLICE 1\n#endif\n\n/*\n * Use this define if you want to use functions HAL_UARTEx_RxEventCallback and\n * HAL_UART_ErrorCallback in your application with multiple other uart ports.\n * Application is then responisble for calling zptxstm32_rx_event_cb and zptxstm32_error_event_cb functions\n * inside these two HAL interrupts.\n */\n#ifndef ZENOH_THREADX_STM32_GEN_IRQ\n#define ZENOH_THREADX_STM32_GEN_IRQ 1\n#endif\n\ntypedef struct {\n    TX_THREAD threadx_thread;\n    uint8_t threadx_stack[Z_TASK_STACK_SIZE];\n} _z_task_t;\n\ntypedef void *z_task_attr_t;  // Not used\n\ntypedef TX_MUTEX _z_mutex_rec_t;\ntypedef TX_MUTEX _z_mutex_t;\ntypedef struct {\n    TX_MUTEX mutex;\n    TX_SEMAPHORE sem;\n    UINT waiters;\n} _z_condvar_t;\n\ntypedef TX_THREAD *_z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef ULONG z_time_t;\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#ifndef ZENOH_HUART\n#error Please define ZENOH_HUART: STM32CubeMX - Connectivity – USARTx – User constants, click “Add IP Handle Label” and enter\n#error ZENOH_HUART for a serial port which will be used with zenoh-pico\n#error Alternatively, define ZENOH_HUART by hand, set to huart1, huart2, etc.\n#endif\n#endif\n\ntypedef struct {\n    union {\n        void *_socket;\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {};\n} _z_sys_net_endpoint_t;\n\n#if ZENOH_THREADX_STM32_GEN_IRQ == 0\nvoid zptxstm32_rx_event_cb(UART_HandleTypeDef *huart, uint16_t offset);\nvoid zptxstm32_error_event_cb(UART_HandleTypeDef *huart);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_THREADX_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/unix.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_UNIX_TYPES_H\n#define ZENOH_PICO_SYSTEM_UNIX_TYPES_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <sys/time.h>\n#if Z_FEATURE_MULTI_THREAD == 1\n#include <pthread.h>\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef pthread_t _z_task_t;\ntypedef pthread_attr_t z_task_attr_t;\ntypedef pthread_mutex_t _z_mutex_t;\ntypedef pthread_mutex_t _z_mutex_rec_t;\ntypedef pthread_cond_t _z_condvar_t;\ntypedef pthread_t _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1 || \\\n    Z_FEATURE_RAWETH_TRANSPORT == 1 || Z_FEATURE_LINK_SERIAL == 1\n        int _fd;\n#endif\n    };\n#if Z_FEATURE_LINK_TLS == 1\n    void *_tls_sock;  // Pointer to _z_tls_socket_t\n#endif\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1\n        struct addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_UNIX_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/void.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_VOID_H\n#define ZENOH_PICO_SYSTEM_VOID_H\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef void *_z_task_t;\ntypedef void *z_task_attr_t;\ntypedef void *_z_mutex_t;\ntypedef void *_z_mutex_rec_t;\ntypedef void *_z_condvar_t;\ntypedef void *_z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef void *z_clock_t;\ntypedef void *z_time_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_VOID_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/windows.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_WINDOWS_H\n#define ZENOH_PICO_SYSTEM_WINDOWS_H\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n\n#include <sys/timeb.h>\n#include <windows.h>\n#include <winsock2.h>\n#include <ws2tcpip.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef HANDLE *_z_task_t;\ntypedef void *z_task_attr_t;  // Not used in Windows\ntypedef SRWLOCK _z_mutex_t;\ntypedef CRITICAL_SECTION _z_mutex_rec_t;\ntypedef CONDITION_VARIABLE _z_condvar_t;\ntypedef DWORD _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef LARGE_INTEGER z_clock_t;\ntypedef struct timeb z_time_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        SOCKET _fd;\n#endif\n    } _sock;\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct addrinfo *_iptcp;\n#endif\n    } _ep;\n} _z_sys_net_endpoint_t;\n\ninline void __asm__(char *instruction) { (void)(instruction); }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_VOID_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform/zephyr.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_SYSTEM_ZEPHYR_TYPES_H\n#define ZENOH_PICO_SYSTEM_ZEPHYR_TYPES_H\n\n#include <version.h>\n\n#if KERNEL_VERSION_MAJOR == 2\n#include <kernel.h>\n#elif KERNEL_VERSION_MAJOR == 3 || KERNEL_VERSION_MAJOR == 4\n#include <zephyr/kernel.h>\n#else\n#pragma GCC warning \"This Zephyr version might not be supported.\"\n#include <zephyr/kernel.h>\n#endif\n\n#include <pthread.h>\n\n#include \"zenoh-pico/config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef pthread_t _z_task_t;\ntypedef pthread_attr_t z_task_attr_t;\ntypedef pthread_mutex_t _z_mutex_t;\ntypedef pthread_mutex_t _z_mutex_rec_t;\ntypedef pthread_cond_t _z_condvar_t;\ntypedef pthread_t _z_task_id_t;\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct timespec z_clock_t;\ntypedef struct timeval z_time_t;\n\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\nstruct zsock_addrinfo;\n#endif\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        int _fd;\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        const struct device *_serial;\n#endif\n    };\n} _z_sys_net_socket_t;\n\ntypedef struct {\n    union {\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n        struct zsock_addrinfo *_iptcp;\n#endif\n    };\n} _z_sys_net_endpoint_t;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_SYSTEM_ZEPHYR_TYPES_H */\n"
  },
  {
    "path": "include/zenoh-pico/system/platform.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#ifndef ZENOH_PICO_SYSTEM_PLATFORM_H\n#define ZENOH_PICO_SYSTEM_PLATFORM_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n\n#endif /* ZENOH_PICO_SYSTEM_PLATFORM_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/common/lease.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_TRANSPORT_LEASE_H\n#define ZENOH_PICO_TRANSPORT_LEASE_H\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_send_join(_z_transport_t *zt);\nz_result_t _z_send_keep_alive(_z_transport_t *zt);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_LEASE_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/common/read.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_TRANSPORT_READ_H\n#define ZENOH_PICO_TRANSPORT_READ_H\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_read(_z_transport_t *zt, bool single_read);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_READ_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/common/rx.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_TRANSPORT_RX_H\n#define ZENOH_PICO_TRANSPORT_RX_H\n\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ Transmission and Reception helpers ------------------*/\nsize_t _z_read_stream_size(_z_zbuf_t *zbuf);\n// Socket is assumed to be in blocking mode with a finite timeout.\nz_result_t _z_link_recv_t_msg(_z_transport_message_t *t_msg, const _z_link_t *zl, _z_sys_net_socket_t *socket,\n                              z_clock_t recv_deadline);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_RX_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/common/transport.h",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_COMMON_TRANSPORT_H\n#define ZENOH_PICO_COMMON_TRANSPORT_H\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid _z_transport_common_clear(_z_transport_common_t *ztc);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_COMMON_TRANSPORT_H*/\n"
  },
  {
    "path": "include/zenoh-pico/transport/common/tx.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_TRANSPORT_TX_H\n#define ZENOH_PICO_TRANSPORT_TX_H\n\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid __unsafe_z_prepare_wbuf(_z_wbuf_t *buf, uint8_t link_flow_capability);\nvoid __unsafe_z_finalize_wbuf(_z_wbuf_t *buf, uint8_t link_flow_capability);\n/*This function is unsafe because it operates in potentially concurrent\n        data.*Make sure that the following mutexes are locked before calling this function : *-ztu->mutex_tx */\nz_result_t __unsafe_z_serialize_zenoh_fragment(_z_wbuf_t *dst, _z_wbuf_t *src, z_reliability_t reliability, size_t sn,\n                                               bool first);\n\n/*------------------ Transmission and Reception helpers ------------------*/\nz_result_t _z_transport_tx_send_t_msg(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg,\n                                      _z_transport_peer_unicast_slist_t *peers);\nz_result_t _z_transport_tx_send_t_msg_wrapper(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg);\nz_result_t _z_send_t_msg(_z_transport_t *zt, const _z_transport_message_t *t_msg);\nz_result_t _z_link_send_t_msg(const _z_link_t *zl, const _z_transport_message_t *t_msg, _z_sys_net_socket_t *socket);\nz_result_t _z_send_n_msg(_z_session_t *zn, const _z_network_message_t *n_msg, z_reliability_t reliability,\n                         z_congestion_control_t cong_ctrl, void *peer);\nz_result_t _z_send_n_batch(_z_session_t *zn, z_congestion_control_t cong_ctrl);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_TX_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/manager.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_TRANSPORT_MANAGER_H\n#define INCLUDE_ZENOH_PICO_TRANSPORT_MANAGER_H\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum _z_peer_op_e {\n    _Z_PEER_OP_OPEN = 0,\n    _Z_PEER_OP_LISTEN = 1,\n};\n\nz_result_t _z_new_transport(_z_transport_t *zt, const _z_id_t *bs, const _z_string_t *locator, z_whatami_t mode,\n                            int peer_op, const _z_config_t *session_cfg, _z_runtime_t *runtime);\nz_result_t _z_new_peer(_z_transport_t *zt, const _z_id_t *session_id, const _z_string_t *locator,\n                       const _z_config_t *session_cfg);\nbool _z_transport_open_error_is_retryable(z_result_t ret);\nvoid _z_free_transport(_z_transport_t **zt);\n\n#if Z_FEATURE_UNICAST_PEER == 1\nz_result_t _z_add_peers(_z_transport_t *zt, const _z_id_t *session_id, _z_pending_peers_t *pending_peers,\n                        const _z_config_t *session_cfg, bool exit_on_failure);\n_z_fut_fn_result_t _zp_add_peers_task_fn(void *ztu_arg, _z_executor_t *executor);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* INCLUDE_ZENOH_PICO_TRANSPORT_MANAGER_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/multicast/lease.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_MULTICAST_LEASE_H\n#define ZENOH_PICO_MULTICAST_LEASE_H\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\nz_result_t _zp_multicast_send_join(_z_transport_multicast_t *ztm);\nz_result_t _zp_multicast_send_keep_alive(_z_transport_multicast_t *ztm);\n_z_fut_fn_result_t _zp_multicast_keep_alive_task_fn(void *ztm_arg, _z_executor_t *executor);\n_z_fut_fn_result_t _zp_multicast_lease_task_fn(void *ztm_arg, _z_executor_t *executor);\n_z_fut_fn_result_t _zp_multicast_send_join_task_fn(void *ztm_arg, _z_executor_t *executor);\n_z_fut_fn_result_t _zp_multicast_failed_result(_z_transport_multicast_t *ztm, _z_executor_t *executor);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_MULTICAST_LEASE_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/multicast/read.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_MULTICAST_READ_H\n#define ZENOH_PICO_MULTICAST_READ_H\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _zp_multicast_read(_z_transport_multicast_t *ztm, bool single_read);\n_z_fut_fn_result_t _zp_multicast_read_task_fn(void *ztm_arg, _z_executor_t *executor);\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_MULTICAST_READ_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/multicast/rx.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_MULTICAST_RX_H\n#define ZENOH_PICO_MULTICAST_RX_H\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_multicast_recv_zbuf(_z_transport_multicast_t *ztm, size_t *to_read);\nz_result_t _z_multicast_recv_t_msg(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg);\nz_result_t _z_multicast_handle_transport_message(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg,\n                                                 _z_slice_t *addr);\nz_result_t _z_multicast_update_rx_buffer(_z_transport_multicast_t *ztm);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_LINK_RX_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/multicast/transport.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_MULTICAST_TRANSPORT_H\n#define ZENOH_PICO_MULTICAST_TRANSPORT_H\n\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_multicast_transport_create(_z_transport_t *zt, _z_link_t *zl,\n                                         _z_transport_multicast_establish_param_t *param);\nz_result_t _z_multicast_open_peer(_z_transport_multicast_establish_param_t *param, const _z_link_t *zl,\n                                  const _z_id_t *local_zid);\nz_result_t _z_multicast_open_client(_z_transport_multicast_establish_param_t *param, const _z_link_t *zl,\n                                    const _z_id_t *local_zid);\nz_result_t _z_multicast_send_close(_z_transport_multicast_t *ztm, uint8_t reason, bool link_only);\nz_result_t _z_multicast_transport_close(_z_transport_multicast_t *ztm, uint8_t reason);\nvoid _z_multicast_transport_clear(_z_transport_multicast_t *ztm);\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* ZENOH_PICO_MULTICAST_TRANSPORT_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/multicast.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_MULTICAST_H\n#define ZENOH_PICO_MULTICAST_H\n\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid _zp_multicast_fetch_zid(const _z_transport_t *zt, _z_closure_zid_t *callback);\nvoid _zp_multicast_info_session(const _z_transport_t *zt, _z_config_t *ps);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_MULTICAST_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/raweth/read.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_RAWETH_READ_H\n#define ZENOH_PICO_RAWETH_READ_H\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\nz_result_t _zp_raweth_read(_z_transport_multicast_t *ztm, bool single_read);\n_z_fut_fn_result_t _zp_raweth_read_task_fn(void *ztm_arg, _z_executor_t *executor);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_RAWETH_READ_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/raweth/rx.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_RAWETH_RX_H\n#define ZENOH_PICO_RAWETH_RX_H\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_raweth_recv_t_msg(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg, _z_slice_t *addr);\nz_result_t _z_raweth_recv_t_msg_na(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg, _z_slice_t *addr);\nz_result_t _z_raweth_update_rx_buff(_z_transport_multicast_t *ztm);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_RAWETH_RX_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/raweth/tx.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_RAWETH_TX_H\n#define ZENOH_PICO_RAWETH_TX_H\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_raweth_link_send_t_msg(const _z_link_t *zl, const _z_transport_message_t *t_msg);\nz_result_t _z_raweth_send_n_msg(_z_session_t *zn, const _z_network_message_t *z_msg, z_reliability_t reliability,\n                                z_congestion_control_t cong_ctrl);\nz_result_t _z_raweth_send_t_msg(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_RAWETH_TX_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/transport.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_TRANSPORT_TRANSPORT_H\n#define INCLUDE_ZENOH_PICO_TRANSPORT_TRANSPORT_H\n\n#include <assert.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/element.h\"\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/weak_session.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum _z_dbuf_state_e {\n    _Z_DBUF_STATE_NULL = 0,\n    _Z_DBUF_STATE_INIT = 1,\n    _Z_DBUF_STATE_OVERFLOW = 2,\n};\n\nenum _z_batching_state_e {\n    _Z_BATCHING_IDLE = 0,\n    _Z_BATCHING_ACTIVE = 1,\n};\n\n// Forward declaration to avoid cyclical include\ntypedef _z_slist_t _z_resource_slist_t;\n\ntypedef struct {\n    _z_id_t _remote_zid;\n    z_whatami_t _remote_whatami;\n    volatile bool _received;\n    _z_resource_slist_t *_remote_resources;\n#if Z_FEATURE_CONNECTIVITY == 1\n    _z_string_t _link_src;\n    _z_string_t _link_dst;\n#endif\n#if Z_FEATURE_FRAGMENTATION == 1\n    // Defragmentation buffers\n    uint8_t _state_reliable;\n    uint8_t _state_best_effort;\n    _z_wbuf_t _dbuf_reliable;\n    _z_wbuf_t _dbuf_best_effort;\n    // Patch\n    uint8_t _patch;\n#endif\n} _z_transport_peer_common_t;\n\n#if Z_FEATURE_CONNECTIVITY == 1\ntypedef struct {\n    _z_id_t _remote_zid;\n    z_whatami_t _remote_whatami;\n    _z_string_t _link_src;\n    _z_string_t _link_dst;\n    bool _owns_endpoints;\n} _z_connectivity_peer_event_data_t;\n#endif\n\nvoid _z_transport_peer_common_clear(_z_transport_peer_common_t *src);\nvoid _z_transport_peer_common_copy(_z_transport_peer_common_t *dst, const _z_transport_peer_common_t *src);\nbool _z_transport_peer_common_eq(const _z_transport_peer_common_t *left, const _z_transport_peer_common_t *right);\n#if Z_FEATURE_CONNECTIVITY == 1\nvoid _z_connectivity_peer_event_data_clear(_z_connectivity_peer_event_data_t *event_data);\nvoid _z_connectivity_peer_event_data_copy_from_common(_z_connectivity_peer_event_data_t *dst,\n                                                      const _z_transport_peer_common_t *src);\nvoid _z_connectivity_peer_event_data_alias_from_common(_z_connectivity_peer_event_data_t *dst,\n                                                       const _z_transport_peer_common_t *src);\n#endif\n\ntypedef struct {\n    _z_transport_peer_common_t common;\n    _z_slice_t _remote_addr;\n    _z_conduit_sn_list_t _sn_rx_sns;\n    // SN numbers\n    _z_zint_t _sn_res;\n    volatile _z_zint_t _lease;\n} _z_transport_peer_multicast_t;\n\nsize_t _z_transport_peer_multicast_size(const _z_transport_peer_multicast_t *src);\nvoid _z_transport_peer_multicast_clear(_z_transport_peer_multicast_t *src);\nvoid _z_transport_peer_multicast_copy(_z_transport_peer_multicast_t *dst, const _z_transport_peer_multicast_t *src);\nbool _z_transport_peer_multicast_eq(const _z_transport_peer_multicast_t *left,\n                                    const _z_transport_peer_multicast_t *right);\n_Z_ELEM_DEFINE(_z_transport_peer_multicast, _z_transport_peer_multicast_t, _z_transport_peer_multicast_size,\n               _z_transport_peer_multicast_clear, _z_transport_peer_multicast_copy, _z_noop_move,\n               _z_transport_peer_multicast_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_transport_peer_multicast, _z_transport_peer_multicast_t, true)\n\ntypedef enum _z_unicast_peer_flow_state_e {\n    _Z_FLOW_STATE_INACTIVE = 0,\n    _Z_FLOW_STATE_PENDING_SIZE = 1,\n    _Z_FLOW_STATE_PENDING_DATA = 2,\n    _Z_FLOW_STATE_READY = 3,\n} _z_unicast_peer_flow_state_e;\n\ntypedef struct {\n    _z_transport_peer_common_t common;\n    _z_sys_net_socket_t _socket;\n    // FIXME: Temporary ownership flag to avoid double-closing sockets\n    // when link and peer structs alias the same underlying fd/TLS.\n    // This should be replaced by proper, explicit ownership semantics\n    // (e.g. a ref-counted socket/TLS handle or single authoritative owner).\n    bool _owns_socket;\n    // SN numbers\n    _z_zint_t _sn_rx_reliable;\n    _z_zint_t _sn_rx_best_effort;\n    bool _pending;\n    uint8_t flow_state;\n    uint16_t flow_curr_size;\n    _z_zbuf_t flow_buff;\n} _z_transport_peer_unicast_t;\n\nvoid _z_transport_peer_unicast_clear(_z_transport_peer_unicast_t *src);\nvoid _z_transport_peer_unicast_copy(_z_transport_peer_unicast_t *dst, const _z_transport_peer_unicast_t *src);\nsize_t _z_transport_peer_unicast_size(const _z_transport_peer_unicast_t *src);\nbool _z_transport_peer_unicast_eq(const _z_transport_peer_unicast_t *left, const _z_transport_peer_unicast_t *right);\n_Z_ELEM_DEFINE(_z_transport_peer_unicast, _z_transport_peer_unicast_t, _z_transport_peer_unicast_size,\n               _z_transport_peer_unicast_clear, _z_transport_peer_unicast_copy, _z_noop_move,\n               _z_transport_peer_unicast_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SLIST_DEFINE(_z_transport_peer_unicast, _z_transport_peer_unicast_t, true)\n\n#define _Z_RES_POOL_INIT_SIZE 8  // Arbitrary small value\n\ntypedef enum _z_transport_state_t {\n    _Z_TRANSPORT_STATE_CLOSED = 0,\n    _Z_TRANSPORT_STATE_RECONNECTING = 1,\n    _Z_TRANSPORT_STATE_OPEN = 2,\n} _z_transport_state_t;\n\n// Handles to the transport tasks, stored at predefined positions.\n// Used by the reconnect task to resume them after a successful reconnection.\n// Index via _Z_TRANSPORT_TASK_* constants defined below.\n#define _Z_TRANSPORT_TASK_KEEP_ALIVE 0\n#define _Z_TRANSPORT_TASK_LEASE 1\n#define _Z_TRANSPORT_TASK_READ 2\n#define _Z_TRANSPORT_TASK_SEND_JOIN 3  // multicast / raweth only\n#define _Z_TRANSPORT_TASK_ADD_PEERS 4  // unicast only\n#define _Z_TRANSPORT_TASK_COUNT 5\n#if Z_FEATURE_AUTO_RECONNECT == 1\ntypedef struct _z_transport_tasks_t {\n    _z_fut_handle_t _task_handles[_Z_TRANSPORT_TASK_COUNT];\n} _z_transport_tasks_t;\n#endif\n\ntypedef struct {\n    _z_session_weak_t _session;\n    _z_link_t *_link;\n    // TX and RX buffers\n    _z_wbuf_t _wbuf;\n    _z_zbuf_t _zbuf;\n    // SN numbers\n    _z_zint_t _sn_res;\n    _z_zint_t _sn_tx_reliable;\n    _z_zint_t _sn_tx_best_effort;\n    volatile _z_zint_t _lease;\n    volatile bool _transmitted;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_t _mutex_tx;\n    _z_mutex_rec_t _mutex_peer;\n#endif\n// Transport batching\n#if Z_FEATURE_BATCHING == 1\n    uint8_t _batch_state;\n    size_t _batch_count;\n#endif\n    // Here we assume the value is set only by the session _z_open\n    // and after it only read by the transport tasks, so we don't need to make it atomic or protect it with mutexes.\n    _z_transport_state_t _state;\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    _z_transport_tasks_t _tasks;\n#endif\n} _z_transport_common_t;\n\n// Send function prototype\ntypedef z_result_t (*_zp_f_send_tmsg)(_z_transport_common_t *self, const _z_transport_message_t *t_msg);\n\ntypedef enum {\n    _Z_PENDING_PEER_STATE_PENDING = 0,\n    _Z_PENDING_PEER_STATE_DONE = 1,\n    _Z_PENDING_PEER_STATE_FAILED = 2,\n} _z_pending_peer_state_t;\n\ntypedef struct {\n    _z_string_t _locator;\n    _z_pending_peer_state_t _state;\n} _z_pending_peer_t;\n\nstatic inline void _z_pending_peer_clear(_z_pending_peer_t *peer) { _z_string_clear(&peer->_locator); }\n_Z_ELEM_DEFINE(_z_pending_peer, _z_pending_peer_t, _z_noop_size, _z_pending_peer_clear, _z_noop_copy, _z_noop_move,\n               _z_noop_eq, _z_noop_cmp, _z_noop_hash)\n_Z_SVEC_DEFINE_NO_COPY(_z_pending_peer, _z_pending_peer_t)\n\ntypedef struct {\n    _z_pending_peer_svec_t _peers;\n    int32_t _timeout_ms;\n    z_clock_t _start;\n    uint32_t _sleep_ms;\n} _z_pending_peers_t;\n\n_z_pending_peers_t _z_pending_peers_null(void);\nz_result_t _z_pending_peers_copy_from_locators(_z_pending_peers_t *pending_peers, const _z_string_svec_t *locators);\nbool _z_pending_peers_has_pending(const _z_pending_peers_t *pending_peers);\nvoid _z_pending_peers_clear(_z_pending_peers_t *pending_peers);\nvoid _z_pending_peers_move(_z_pending_peers_t *dst, _z_pending_peers_t *src);\n\ntypedef struct {\n    _z_transport_common_t _common;\n    // Known valid peers\n    _z_transport_peer_unicast_slist_t *_peers;\n    _z_pending_peers_t _pending_peers;\n} _z_transport_unicast_t;\n\n#define _Z_MULTICAST_ADDR_BUFF_SIZE 32  // Arbitrary size that must be able to contain any link address.\n\ntypedef struct _z_transport_multicast_t {\n    _z_transport_common_t _common;\n    // Persistent source address associated with the current contents of _zbuf.\n    // Required because datagram data may remain buffered across reads.\n    uint8_t _zbuf_addr_buf[_Z_MULTICAST_ADDR_BUFF_SIZE];\n    _z_slice_t _zbuf_addr;\n    // Known valid peers\n    _z_transport_peer_multicast_slist_t *_peers;\n    // T message send function\n    _zp_f_send_tmsg _send_f;\n} _z_transport_multicast_t;\n\ntypedef enum {\n    _Z_TRANSPORT_UNICAST_TYPE,\n    _Z_TRANSPORT_MULTICAST_TYPE,\n    _Z_TRANSPORT_RAWETH_TYPE,\n    _Z_TRANSPORT_NONE\n} _z_transport_type_t;\n\ntypedef struct {\n    union {\n        _z_transport_unicast_t _unicast;\n        _z_transport_multicast_t _multicast;\n        _z_transport_multicast_t _raweth;\n    } _transport;\n\n    _z_transport_type_t _type;\n} _z_transport_t;\n\ntypedef struct {\n    _z_id_t _remote_zid;\n    uint16_t _batch_size;\n    _z_zint_t _initial_sn_rx;\n    _z_zint_t _initial_sn_tx;\n    _z_zint_t _lease;\n    z_whatami_t _remote_whatami;\n    uint8_t _key_id_res;\n    uint8_t _req_id_res;\n    uint8_t _seq_num_res;\n    bool _is_qos;\n#if Z_FEATURE_FRAGMENTATION == 1\n    uint8_t _patch;\n#endif\n} _z_transport_unicast_establish_param_t;\n\ntypedef struct {\n    _z_conduit_sn_list_t _initial_sn_tx;\n    uint8_t _seq_num_res;\n} _z_transport_multicast_establish_param_t;\n\nz_result_t _z_transport_peer_unicast_add(_z_transport_unicast_t *ztu, _z_transport_unicast_establish_param_t *param,\n                                         _z_sys_net_socket_t socket, bool owns_socket,\n                                         _z_transport_peer_unicast_t **output_peer);\n_z_transport_common_t *_z_transport_get_common(_z_transport_t *zt);\nsize_t _z_transport_get_peers_count(_z_transport_t *zt);\nz_result_t _z_transport_close(_z_transport_t *zt, uint8_t reason);\nvoid _z_transport_clear(_z_transport_t *zt);\nvoid _z_transport_free(_z_transport_t **zt);\n\nstatic inline void _z_transport_get_link_properties(const _z_transport_common_t *transport, uint16_t *mtu,\n                                                    bool *is_streamed, bool *is_reliable) {\n    *mtu = 0;\n    *is_streamed = false;\n    *is_reliable = false;\n    if (transport != NULL && transport->_link != NULL) {\n        *mtu = transport->_link->_mtu;\n        *is_streamed = transport->_link->_cap._flow == Z_LINK_CAP_FLOW_STREAM;\n        *is_reliable = transport->_link->_cap._is_reliable;\n    }\n}\n\n#if Z_FEATURE_BATCHING == 1\nz_result_t _z_transport_start_batching(_z_transport_t *zt);\nz_result_t _z_transport_stop_batching(_z_transport_t *zt);\n\nstatic inline bool _z_transport_batch_hold_tx_mutex(void) {\n#if Z_FEATURE_BATCH_TX_MUTEX == 1\n    return true;\n#else\n    return false;\n#endif\n}\n\nstatic inline bool _z_transport_batch_hold_peer_mutex(void) {\n#if Z_FEATURE_BATCH_PEER_MUTEX == 1\n    return true;\n#else\n    return false;\n#endif\n}\n#endif  // Z_FEATURE_BATCHING == 1\n\n#if Z_FEATURE_MULTI_THREAD == 1\nstatic inline z_result_t _z_transport_tx_mutex_lock(_z_transport_common_t *ztc, bool block) {\n    if (block) {\n        _z_mutex_lock(&ztc->_mutex_tx);\n        return _Z_RES_OK;\n    } else {\n        return _z_mutex_try_lock(&ztc->_mutex_tx);\n    }\n}\nstatic inline void _z_transport_tx_mutex_unlock(_z_transport_common_t *ztc) { _z_mutex_unlock(&ztc->_mutex_tx); }\nstatic inline void _z_transport_peer_mutex_lock(_z_transport_common_t *ztc) {\n    (void)_z_mutex_rec_lock(&ztc->_mutex_peer);\n}\nstatic inline void _z_transport_peer_mutex_unlock(_z_transport_common_t *ztc) {\n    (void)_z_mutex_rec_unlock(&ztc->_mutex_peer);\n}\n#else\nstatic inline z_result_t _z_transport_tx_mutex_lock(_z_transport_common_t *ztc, bool block) {\n    _ZP_UNUSED(ztc);\n    _ZP_UNUSED(block);\n    return _Z_RES_OK;\n}\nstatic inline void _z_transport_tx_mutex_unlock(_z_transport_common_t *ztc) { _ZP_UNUSED(ztc); }\nstatic inline void _z_transport_peer_mutex_lock(_z_transport_common_t *ztc) { _ZP_UNUSED(ztc); }\nstatic inline void _z_transport_peer_mutex_unlock(_z_transport_common_t *ztc) { _ZP_UNUSED(ztc); }\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* INCLUDE_ZENOH_PICO_TRANSPORT_TRANSPORT_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/unicast/accept.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UNICAST_ACCEPT_H\n#define ZENOH_PICO_UNICAST_ACCEPT_H\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1 && Z_FEATURE_UNICAST_PEER == 1 && \\\n    (Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_TLS == 1)\n_z_fut_fn_result_t _zp_unicast_accept_task_fn(void *ztu_arg, _z_executor_t *executor);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UNICAST_ACCEPT_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/unicast/lease.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UNICAST_LEASE_H\n#define ZENOH_PICO_UNICAST_LEASE_H\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\nz_result_t _zp_unicast_send_keep_alive(_z_transport_unicast_t *ztu);\n_z_fut_fn_result_t _zp_unicast_lease_task_fn(void *ztu_arg, _z_executor_t *executor);\n_z_fut_fn_result_t _zp_unicast_keep_alive_task_fn(void *ztu_arg, _z_executor_t *executor);\n_z_fut_fn_result_t _zp_unicast_failed_result(_z_transport_unicast_t *ztu, _z_executor_t *executor);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_LINK_TASK_LEASE_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/unicast/read.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UNICAST_READ_H\n#define ZENOH_PICO_UNICAST_READ_H\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\nz_result_t _zp_unicast_read(_z_transport_unicast_t *ztu, bool single_read);\n_z_fut_fn_result_t _zp_unicast_read_task_fn(void *ztu_arg, _z_executor_t *executor);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UNICAST_READ_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/unicast/rx.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UNICAST_RX_H\n#define ZENOH_PICO_UNICAST_RX_H\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_unicast_recv_t_msg(_z_transport_unicast_t *ztu, _z_transport_message_t *t_msg);\nz_result_t _z_unicast_handle_transport_message(_z_transport_unicast_t *ztu, _z_transport_message_t *t_msg,\n                                               _z_transport_peer_unicast_t *peer);\nz_result_t _z_unicast_update_rx_buffer(_z_transport_unicast_t *ztu);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UNICAST_RX_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/unicast/transport.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UNICAST_TRANSPORT_H\n#define ZENOH_PICO_UNICAST_TRANSPORT_H\n\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nz_result_t _z_unicast_transport_create(_z_transport_t *zt, _z_link_t *zl,\n                                       _z_transport_unicast_establish_param_t *param);\nz_result_t _z_unicast_handshake_listen(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                       const _z_id_t *local_zid, z_whatami_t mode, _z_sys_net_socket_t *socket);\nz_result_t _z_unicast_open_client(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                  const _z_id_t *local_zid);\nz_result_t _z_unicast_open_peer(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                const _z_id_t *local_zid, int peer_op, _z_sys_net_socket_t *socket);\nz_result_t _z_unicast_send_close(_z_transport_unicast_t *ztu, uint8_t reason, bool link_only);\nz_result_t _z_unicast_transport_close(_z_transport_unicast_t *ztu, uint8_t reason);\nvoid _z_unicast_transport_clear(_z_transport_unicast_t *ztu);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UNICAST_TRANSPORT_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/unicast.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UNICAST_H\n#define ZENOH_PICO_UNICAST_H\n\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid _zp_unicast_fetch_zid(const _z_transport_t *zt, _z_closure_zid_t *callback);\nvoid _zp_unicast_info_session(const _z_transport_t *zt, _z_config_t *ps, int mode);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UNICAST_H */\n"
  },
  {
    "path": "include/zenoh-pico/transport/utils.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_TRANSPORT_UTILS_H\n#define ZENOH_PICO_TRANSPORT_UTILS_H\n\n#include <stdbool.h>\n\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*------------------ SN helpers ------------------*/\n_z_zint_t _z_sn_max(uint8_t bits);\n_z_zint_t _z_sn_half(_z_zint_t sn);\n_z_zint_t _z_sn_modulo_mask(uint8_t bits);\nbool _z_sn_precedes(const _z_zint_t sn_resolution, const _z_zint_t sn_left, const _z_zint_t sn_right);\nbool _z_sn_consecutive(const _z_zint_t sn_resolution, const _z_zint_t sn_left, const _z_zint_t sn_right);\n_z_zint_t _z_sn_increment(const _z_zint_t sn_resolution, const _z_zint_t sn);\n_z_zint_t _z_sn_decrement(const _z_zint_t sn_resolution, const _z_zint_t sn);\n\nvoid _z_conduit_sn_list_copy(_z_conduit_sn_list_t *dst, const _z_conduit_sn_list_t *src);\nvoid _z_conduit_sn_list_decrement(const _z_zint_t sn_resolution, _z_conduit_sn_list_t *sns);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_TRANSPORT_UTILS_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/checksum.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_CHECKSUM_H\n#define ZENOH_PICO_UTILS_CHECKSUM_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nuint32_t _z_crc32(const uint8_t *message, size_t len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_CHECKSUM_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/config.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_PROPERTY_H\n#define ZENOH_PICO_UTILS_PROPERTY_H\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/intmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Properties returned by _z_info()\n#define Z_INFO_PID_KEY 0x00\n#define Z_INFO_PEER_PID_KEY 0x01\n#define Z_INFO_ROUTER_PID_KEY 0x02\n\n/**\n * Zenoh-net properties are represented as int-string map.\n */\ntypedef _z_str_intmap_t _z_config_t;\n\n/**\n * Initialize a new empty map of properties.\n */\nz_result_t _z_config_init(_z_config_t *ps);\n\n/**\n * Insert a property with a given key to a properties map.\n * If a property with the same key already exists in the properties map, it is replaced.\n *\n * Parameters:\n *   ps: A pointer to the properties map.\n *   key: The key of the property to add.\n *   value: The value of the property to add.\n */\nz_result_t _zp_config_insert(_z_config_t *ps, uint8_t key, const char *value);\nz_result_t _zp_config_insert_string(_z_config_t *ps, uint8_t key, const _z_string_t *value);\n\n/**\n * Get the property with the given key from a properties map.\n *\n * Parameters:\n *     ps: A pointer to properties map.\n *     key: The key of the property.\n *\n * Returns:\n *     The value of the property with key ``key`` in properties map ``ps``.\n */\nchar *_z_config_get(const _z_config_t *ps, uint8_t key);\nz_result_t _z_config_get_all(const _z_config_t *ps, _z_string_svec_t *locators, uint8_t key);\n\n/**\n * Retrieve a signed 32-bit integer property from the configuration.\n * If the property is not present, the provided default value is used.\n *\n * The value is parsed as a base-10 integer and validated to ensure it\n * fits within the range of int32_t.\n *\n * Parameters:\n *   config: A pointer to the configuration object.\n *   key: The key of the property to retrieve.\n *   default_val: The default value to use if the property is not present.\n *   out: A pointer to store the parsed result.\n */\nz_result_t _z_config_get_i32_default(_z_config_t *config, uint8_t key, const char *default_val, int32_t *out);\n\n/**\n * Retrieve a boolean property from the configuration.\n * If the property is not present, the provided default value is used.\n *\n * Accepted values are \"true\" and \"false\".\n *\n * Parameters:\n *   config: A pointer to the configuration object.\n *   key: The key of the property to retrieve.\n *   default_val: The default value to use if the property is not present.\n *   out: A pointer to store the parsed result.\n */\nz_result_t _z_config_get_bool_default(_z_config_t *config, uint8_t key, const char *default_val, bool *out);\n\n/**\n * Get the length of the given properties map.\n *\n * Parameters:\n *     ps: A pointer to the properties map.\n *\n * Returns:\n *     The length of the given properties map.\n */\n#define _z_config_len _z_str_intmap_len\n\n/**\n * Clone a config.\n *\n * Parameters:\n *     m: A pointer to the config to clone.\n *\n * Returns:\n *     The clone of the config.\n */\n#define _z_config_clone _z_str_intmap_clone\n\n/**\n * Get the length of the given properties map.\n *\n * Parameters:\n *     ps: A pointer to the properties map.\n *\n * Returns:\n *     A boolean to indicate if properties are present.\n */\n#define _z_config_is_empty _z_str_intmap_is_empty\n\n/**\n * Clear a set of properties.\n *\n * Parameters:\n *   ps: A pointer to the properties map.\n */\n#define _z_config_clear _z_str_intmap_clear\n\n/**\n * Free a set of properties.\n *\n * Parameters:\n *   ps: A pointer to a pointer of properties.\n *\n */\n#define _z_config_free _z_str_intmap_free\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_PROPERTY_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/encoding.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_ENCODING_H\n#define ZENOH_PICO_UTILS_ENCODING_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nsize_t _z_cobs_encode(const uint8_t *input, size_t input_len, uint8_t *output);\nsize_t _z_cobs_decode(const uint8_t *input, size_t input_len, uint8_t *output);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_ENCODING_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/endianness.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_ENDIANNESS_H\n#define ZENOH_PICO_UTILS_ENDIANNESS_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !defined(ZENOH_ENDIANNNESS_BIG) && !defined(ZENOH_ENDIANNNESS_LITTLE)\n// Gcc/clang test\n#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n#define ZENOH_ENDIANNNESS_BIG\n#else\n#define ZENOH_ENDIANNNESS_LITTLE\n#endif\n#endif\n\n// Load int from memory with specified endianness\n\n// *** Little endian ***\n#define _Z_LE_LOAD_IMPL(SIZE)                                           \\\n    static inline uint##SIZE##_t _z_le_load##SIZE(const uint8_t *src) { \\\n        uint##SIZE##_t val = 0;                                         \\\n        for (size_t i = sizeof(val); i != 0; --i) {                     \\\n            val = val << 8;                                             \\\n            val = (uint##SIZE##_t)(val | src[i - 1]);                   \\\n        }                                                               \\\n        return val;                                                     \\\n    }\n\n#define _Z_LE_STORE_IMPL(SIZE)                                               \\\n    static inline void _z_le_store##SIZE(uint##SIZE##_t val, uint8_t *dst) { \\\n        for (size_t i = 0; i < sizeof(val); ++i) {                           \\\n            dst[i] = (uint8_t)val;                                           \\\n            val = val >> 8;                                                  \\\n        }                                                                    \\\n    }\n\n_Z_LE_LOAD_IMPL(16)\n_Z_LE_LOAD_IMPL(32)\n_Z_LE_LOAD_IMPL(64)\n\n_Z_LE_STORE_IMPL(16)\n_Z_LE_STORE_IMPL(32)\n_Z_LE_STORE_IMPL(64)\n\n#undef _Z_LE_LOAD_IMPL\n#undef _Z_LE_STORE_IMPL\n\n// *** Big endian ***\n#define _Z_BE_LOAD_IMPL(SIZE)                                           \\\n    static inline uint##SIZE##_t _z_be_load##SIZE(const uint8_t *src) { \\\n        uint##SIZE##_t val = 0;                                         \\\n        for (size_t i = 0; i < sizeof(val); ++i) {                      \\\n            val = val << 8;                                             \\\n            val = (uint##SIZE##_t)(val | src[i]);                       \\\n        }                                                               \\\n        return val;                                                     \\\n    }\n\n#define _Z_BE_STORE_IMPL(SIZE)                                               \\\n    static inline void _z_be_store##SIZE(uint##SIZE##_t val, uint8_t *dst) { \\\n        for (size_t i = sizeof(val); i != 0; --i) {                          \\\n            dst[i - 1] = (uint8_t)val;                                       \\\n            val = val >> 8;                                                  \\\n        }                                                                    \\\n    }\n\n_Z_BE_LOAD_IMPL(16)\n_Z_BE_LOAD_IMPL(32)\n_Z_BE_LOAD_IMPL(64)\n\n_Z_BE_STORE_IMPL(16)\n_Z_BE_STORE_IMPL(32)\n_Z_BE_STORE_IMPL(64)\n\n#undef _Z_BE_LOAD_IMPL\n#undef _Z_BE_STORE_IMPL\n\n// *** Host ***\nstatic inline uint16_t _z_host_le_load8(const uint8_t *src) { return src[0]; }\n\nstatic inline uint16_t _z_host_le_load16(const uint8_t *src) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    return _z_be_load16(src);\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    return _z_le_load16(src);\n#endif\n}\n\nstatic inline uint32_t _z_host_le_load32(const uint8_t *src) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    return _z_be_load32(src);\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    return _z_le_load32(src);\n#endif\n}\n\nstatic inline uint64_t _z_host_le_load64(const uint8_t *src) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    return _z_be_load64(src);\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    return _z_le_load64(src);\n#endif\n}\n\nstatic inline void _z_host_le_store8(const uint8_t val, uint8_t *dst) { dst[0] = val; }\n\nstatic inline void _z_host_le_store16(const uint16_t val, uint8_t *dst) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    _z_be_store16(val, dst);\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    _z_le_store16(val, dst);\n#endif\n}\n\nstatic inline void _z_host_le_store32(const uint32_t val, uint8_t *dst) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    _z_be_store32(val, dst);\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    _z_le_store32(val, dst);\n#endif\n}\n\nstatic inline void _z_host_le_store64(const uint64_t val, uint8_t *dst) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    _z_be_store64(val, dst);\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    _z_le_store64(val, dst);\n#endif\n}\n\nstatic inline void _z_host_u16_from_le_u16(uint16_t *val) {\n#if defined(ZENOH_ENDIANNNESS_BIG)\n    uint16_t tmp = (uint16_t)((*val & 0x00FF) << 8) + (uint16_t)((*val & 0xFF00) >> 8);\n    *val = tmp;\n#elif defined(ZENOH_ENDIANNNESS_LITTLE)\n    _ZP_UNUSED(val);\n    return;\n#endif\n}\n\n// Return u16 individual bytes\nstatic inline uint8_t _z_get_u16_lsb(uint_fast16_t val) { return (uint8_t)(val >> 0); }\nstatic inline uint8_t _z_get_u16_msb(uint_fast16_t val) { return (uint8_t)(val >> 8); }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_ENDIANNESS_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/hash.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_HASH_H\n#define ZENOH_PICO_UTILS_HASH_H\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Define FNV1a parameters for 32 and 64-bit platforms\n#if SIZE_MAX == UINT64_MAX\n#define _Z_FNV_OFFSET_BASIS 14695981039346656037ULL\n#define _Z_FNV_PRIME 1099511628211ULL\n#elif SIZE_MAX == UINT32_MAX\n#define _Z_FNV_OFFSET_BASIS 2166136261U\n#define _Z_FNV_PRIME 16777619U\n#else\n#error \"Unsupported size_t size\"\n#endif\n\nstatic inline size_t _z_hash_combine(size_t h1, size_t h2) {\n    h1 ^= h2;\n    h1 *= _Z_FNV_PRIME;\n    return h1;\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_HASH_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/json_encoder.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_JSON_ENCODER_H\n#define ZENOH_PICO_UTILS_JSON_ENCODER_H\n\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_ADMIN_SPACE == 1\n\ntypedef enum {\n    _Z_JSON_CTX_OBJ = 1,\n    _Z_JSON_CTX_ARR = 2,\n} _z_json_ctx_kind_t;\n\ntypedef struct {\n    _z_json_ctx_kind_t kind;\n    bool expect_value;\n    bool first;\n} _z_json_frame_t;\n\n// Maximum nesting depth supported by the JSON encoder\n#ifndef Z_JSON_MAX_DEPTH\n#define Z_JSON_MAX_DEPTH 16\n#endif\n\ntypedef struct {\n    z_owned_bytes_writer_t _bw;\n\n    uint8_t _depth;\n    _z_json_frame_t _stk[Z_JSON_MAX_DEPTH];\n    bool _done;\n} _z_json_encoder_t;\n\nz_result_t _z_json_encoder_empty(_z_json_encoder_t *je);\n\nz_result_t _z_json_encoder_start_object(_z_json_encoder_t *je);\nz_result_t _z_json_encoder_end_object(_z_json_encoder_t *je);\nz_result_t _z_json_encoder_start_array(_z_json_encoder_t *je);\nz_result_t _z_json_encoder_end_array(_z_json_encoder_t *je);\n\nz_result_t _z_json_encoder_write_key(_z_json_encoder_t *je, const char *key);\nz_result_t _z_json_encoder_write_string(_z_json_encoder_t *je, const char *value);\nz_result_t _z_json_encoder_write_z_string(_z_json_encoder_t *je, const _z_string_t *value);\nz_result_t _z_json_encoder_write_z_slice(_z_json_encoder_t *je, const _z_slice_t *value);\nz_result_t _z_json_encoder_write_double(_z_json_encoder_t *je, double value);\nz_result_t _z_json_encoder_write_i64(_z_json_encoder_t *je, int64_t value);\nz_result_t _z_json_encoder_write_u64(_z_json_encoder_t *je, uint64_t value);\nz_result_t _z_json_encoder_write_boolean(_z_json_encoder_t *je, bool value);\nz_result_t _z_json_encoder_write_null(_z_json_encoder_t *je);\n\nz_result_t _z_json_encoder_finish(_z_json_encoder_t *je, z_owned_bytes_t *bytes);\nvoid _z_json_encoder_clear(_z_json_encoder_t *je);\n\n#endif  // Z_FEATURE_ADMIN_SPACE == 1\n#endif  // Z_FEATURE_UNSTABLE_API\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_JSON_ENCODER_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/locality.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_LOCALITY_H\n#define ZENOH_PICO_UTILS_LOCALITY_H\n\n#include \"zenoh-pico/api/constants.h\"\n\nstatic inline bool _z_locality_allows_local(z_locality_t locality) {\n    switch (locality) {\n        case Z_LOCALITY_REMOTE:\n            return false;\n        case Z_LOCALITY_ANY:\n        case Z_LOCALITY_SESSION_LOCAL:\n        default:\n            return true;\n    }\n}\n\nstatic inline bool _z_locality_allows_remote(z_locality_t locality) {\n    switch (locality) {\n        case Z_LOCALITY_SESSION_LOCAL:\n            return false;\n        case Z_LOCALITY_ANY:\n        case Z_LOCALITY_REMOTE:\n        default:\n            return true;\n    }\n}\n\n#endif  // ZENOH_PICO_UTILS_LOCALITY_H\n"
  },
  {
    "path": "include/zenoh-pico/utils/logging.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_LOGGING_H\n#define ZENOH_PICO_UTILS_LOGGING_H\n\n#include <stdio.h>\n\n#include \"zenoh-pico/system/common/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Allows replacement of printf on targets that don't support it\n#ifndef ZENOH_LOG_PRINT\n#define ZENOH_LOG_PRINT printf\n#endif\n\n// Compatibility with legacy logging system where\n// 1 -> ERROR\n// 2 -> INFO\n// 3 -> DEBUG\n#ifdef ZENOH_DEBUG\n#undef ZENOH_LOG_ERROR\n#undef ZENOH_LOG_WARN\n#undef ZENOH_LOG_INFO\n#undef ZENOH_LOG_DEBUG\n#undef ZENOH_LOG_TRACE\n#if ZENOH_DEBUG == 1\n#define ZENOH_LOG_ERROR\n#elif ZENOH_DEBUG == 2\n#define ZENOH_LOG_INFO\n#elif ZENOH_DEBUG == 3\n#define ZENOH_LOG_DEBUG\n#endif\n#endif\n\n// Logging macros\n#define _Z_LOG(level, ...)                                               \\\n    do {                                                                 \\\n        char __timestamp[64];                                            \\\n        z_time_now_as_str(__timestamp, sizeof(__timestamp));             \\\n        ZENOH_LOG_PRINT(\"[%s \" #level \" ::%s] \", __timestamp, __func__); \\\n        ZENOH_LOG_PRINT(__VA_ARGS__);                                    \\\n        ZENOH_LOG_PRINT(\"\\r\\n\");                                         \\\n    } while (false)\n\n#define _Z_LOG_NONL(level, ...)                                          \\\n    do {                                                                 \\\n        char __timestamp[64];                                            \\\n        z_time_now_as_str(__timestamp, sizeof(__timestamp));             \\\n        ZENOH_LOG_PRINT(\"[%s \" #level \" ::%s] \", __timestamp, __func__); \\\n        ZENOH_LOG_PRINT(__VA_ARGS__);                                    \\\n    } while (false)\n// In debug build, if a level is not enabled, the following macro is used instead\n// in order to check that the arguments are valid and compile fine.\n#define _Z_CHECK_LOG(...)                        \\\n    do {                                         \\\n        if (false) ZENOH_LOG_PRINT(__VA_ARGS__); \\\n    } while (false)\n\n#ifdef ZENOH_LOG_TRACE\n#define ZENOH_LOG_DEBUG\n#define _Z_TRACE(...) _Z_LOG(TRACE, __VA_ARGS__)\n#elif defined(Z_BUILD_LOG)\n#define _Z_TRACE _Z_CHECK_LOG\n#else\n#define _Z_TRACE(...) (void)(0)\n#endif\n\n#ifdef ZENOH_LOG_DEBUG\n#define ZENOH_LOG_INFO\n#define _Z_DEBUG(...) _Z_LOG(DEBUG, __VA_ARGS__)\n#define _Z_DEBUG_NONL(...) _Z_LOG_NONL(DEBUG, __VA_ARGS__)\n#elif defined(Z_BUILD_LOG)\n#define _Z_DEBUG _Z_CHECK_LOG\n#define _Z_DEBUG_NONL _Z_CHECK_LOG\n#else\n#define _Z_DEBUG(...) (void)(0)\n#define _Z_DEBUG_NONL(...) (void)(0)\n#endif\n\n#ifdef ZENOH_LOG_INFO\n#define ZENOH_LOG_WARN\n#define _Z_INFO(...) _Z_LOG(INFO, __VA_ARGS__)\n#elif defined(Z_BUILD_LOG)\n#define _Z_INFO _Z_CHECK_LOG\n#else\n#define _Z_INFO(...) (void)(0)\n#endif\n\n#ifdef ZENOH_LOG_WARN\n#define ZENOH_LOG_ERROR\n#define _Z_WARN(...) _Z_LOG(WARN, __VA_ARGS__)\n#elif defined(Z_BUILD_LOG)\n#define _Z_WARN _Z_CHECK_LOG\n#else\n#define _Z_WARN(...) (void)(0)\n#endif\n\n#ifdef ZENOH_LOG_ERROR\n#define _Z_ERROR(...) _Z_LOG(ERROR, __VA_ARGS__)\n#elif defined(Z_BUILD_LOG)\n#define _Z_ERROR _Z_CHECK_LOG\n#else\n#define _Z_ERROR(...) (void)(0)\n#endif\n\n// Error logging macros\n// Potentially add a function call to a logger if needs arise\n#define _Z_ERROR_RETURN(err_code)                                                \\\n    do {                                                                         \\\n        _Z_TRACE(\"Error generated: %d, at %s:%d\", err_code, __FILE__, __LINE__); \\\n        return err_code;                                                         \\\n    } while (false)\n\n#define _Z_ERROR_LOG(err_code)                                                   \\\n    do {                                                                         \\\n        _Z_TRACE(\"Error generated: %d, at %s:%d\", err_code, __FILE__, __LINE__); \\\n    } while (false)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // ZENOH_PICO_UTILS_LOGGING_H\n"
  },
  {
    "path": "include/zenoh-pico/utils/mutex.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_MUTEX_H\n#define ZENOH_PICO_UTILS_MUTEX_H\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\nstatic inline z_result_t _z_mutex_rec_mt_lock(_z_mutex_rec_t *m) { return _z_mutex_rec_lock(m); }\nstatic inline z_result_t _z_mutex_rec_mt_unlock(_z_mutex_rec_t *m) { return _z_mutex_rec_unlock(m); }\n#else\nstatic inline z_result_t _z_mutex_rec_mt_lock(_z_mutex_rec_t *m) {\n    _ZP_UNUSED(m);\n    return _Z_RES_OK;\n}\nstatic inline z_result_t _z_mutex_rec_mt_unlock(_z_mutex_rec_t *m) {\n    _ZP_UNUSED(m);\n    return _Z_RES_OK;\n}\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/zenoh-pico/utils/pointers.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_POINTERS_H\n#define ZENOH_PICO_UTILS_POINTERS_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Computes the distance between two ``uint8_t`` pointers as an absolute value.\n * Note that ``l_ptr`` must be higher than ``r_ptr``.\n *\n * Parameters:\n *   l_ptr: The first pointer.\n *   r_ptr: The second pointer.\n *\n * Returns:\n *   Returns the distance between the pointers as an absolute value.\n */\nstatic inline size_t _z_ptr_u8_diff(const uint8_t *l_ptr, const uint8_t *r_ptr) { return (size_t)(l_ptr - r_ptr); }\n\n/**\n * Offsets a ``uint8_t`` pointer by a given distance. Offsets can be both positive and negative values.\n *\n * Parameters:\n *   ptr: The pointer to offset.\n *   off: The offset distance to be applied.\n *\n * Returns:\n *   Returns a ``const uint8_t`` pointer, pointing to the offset position.\n */\nconst uint8_t *_z_cptr_u8_offset(const uint8_t *ptr, ptrdiff_t off);\n\n/**\n * Offsets a ``uint8_t`` pointer by a given distance. Offsets can be both positive and negative values.\n *\n * Parameters:\n *   ptr: The pointer to offset.\n *   off: The offset distance to be applied.\n *\n * Returns:\n *   Returns a ``uint8_t`` pointer, pointing to the offset position.\n */\nstatic inline uint8_t *_z_ptr_u8_offset(uint8_t *ptr, const ptrdiff_t off) { return ptr + off; }\n\n/**\n * Computes the distance between two ``char`` pointers as an absolute value.\n * Note that ``l_ptr`` must be higher than ``r_ptr``.\n *\n * Parameters:\n *   l_ptr: The first pointer.\n *   r_ptr: The second pointer.\n *\n * Returns:\n *   Returns the distance between the pointers as an absolute value.\n */\nstatic inline size_t _z_ptr_char_diff(const char *l_ptr, const char *r_ptr) { return (size_t)(l_ptr - r_ptr); }\n\n/**\n * Offsets a ``char`` pointer by a given distance. Offsets can be both positive and negative values.\n *\n * Parameters:\n *   ptr: The pointer to offset.\n *   off: The offset distance to be applied.\n *\n * Returns:\n *   Returns a ``const char`` pointer, pointing to the offset position.\n */\nconst char *_z_cptr_char_offset(const char *ptr, ptrdiff_t off);\n\n/**\n * Offsets a ``char`` pointer by a given distance. Offsets can be both positive and negative values.\n *\n * Parameters:\n *   ptr: The pointer to offset.\n *   off: The offset distance to be applied.\n *\n * Returns:\n *   Returns a ``char`` pointer, pointing to the offset position.\n */\nstatic inline char *_z_ptr_char_offset(char *ptr, const ptrdiff_t off) { return ptr + off; }\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_POINTERS_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/query_params.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_QUERY_PARAMS_H\n#define ZENOH_PICO_UTILS_QUERY_PARAMS_H\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _Z_QUERY_PARAMS_KEY_TIME \"_time\"\n#define _Z_QUERY_PARAMS_KEY_TIME_LEN (sizeof(_Z_QUERY_PARAMS_KEY_TIME) - 1)\n#define _Z_QUERY_PARAMS_KEY_RANGE \"_sn\"\n#define _Z_QUERY_PARAMS_KEY_RANGE_LEN (sizeof(_Z_QUERY_PARAMS_KEY_RANGE) - 1)\n#define _Z_QUERY_PARAMS_KEY_MAX \"_max\"\n#define _Z_QUERY_PARAMS_KEY_MAX_LEN (sizeof(_Z_QUERY_PARAMS_KEY_MAX) - 1)\n#define _Z_QUERY_PARAMS_KEY_ANYKE \"_anyke\"\n#define _Z_QUERY_PARAMS_KEY_ANYKE_LEN (sizeof(_Z_QUERY_PARAMS_KEY_ANYKE) - 1)\n\n#define _Z_QUERY_PARAMS_LIST_SEPARATOR \";\"\n#define _Z_QUERY_PARAMS_LIST_SEPARATOR_LEN (sizeof(_Z_QUERY_PARAMS_LIST_SEPARATOR) - 1)\n#define _Z_QUERY_PARAMS_FIELD_SEPARATOR \"=\"\n#define _Z_QUERY_PARAMS_FIELD_SEPARATOR_LEN (sizeof(_Z_QUERY_PARAMS_FIELD_SEPARATOR) - 1)\n\ntypedef struct {\n    _z_str_se_t key;\n    _z_str_se_t value;\n} _z_query_param_t;\n\ntypedef struct {\n    bool _has_start;\n    uint32_t _start;\n    bool _has_end;\n    uint32_t _end;\n} _z_query_param_range_t;\n\n/**\n * Extracts the next query parameter from a `_z_str_se_t` string.\n *\n * Returns a `_z_query_param_t` with positions of the next key/value in the string if present.\n * After invocation `str` will point to the remainder of the string.\n */\n_z_query_param_t _z_query_params_next(_z_str_se_t *str);\n\nbool _z_parameters_has_anyke(const char *parameters, size_t parameters_len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_QUERY_PARAMS_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/result.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_RESULT_H\n#define ZENOH_PICO_UTILS_RESULT_H\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define _ZP_UNUSED(x) (void)(x)\n#define _ZP_ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))\n\n#define _Z_ERR_MESSAGE_MASK 0x88\n#define _Z_ERR_ENTITY_MASK 0x90\n#define _Z_ERR_TRANSPORT_MASK 0x98\n#define _Z_ERR_CONFIG_MASK 0xa0\n#define _Z_ERR_SCOUT_MASK 0xa8\n#define _Z_ERR_SYSTEM_MASK 0xb0\n#define _Z_ERR_GENERIC_MASK 0xb8\n\ntypedef int8_t z_result_t;\n/*------------------ Result Enums ------------------*/\ntypedef enum {\n    _Z_RES_OK = 0,\n    Z_OK = 0,\n    _Z_RES_CHANNEL_CLOSED = 1,\n    Z_CHANNEL_DISCONNECTED = 1,\n    _Z_RES_CHANNEL_NODATA = 2,\n    Z_CHANNEL_NODATA = 2,\n    _Z_NO_DATA_PROCESSED = 3,\n    Z_NO_DATA_PROCESSED = 3,\n    _Z_RESOURCE_POSITIVE_REF_COUNT = 4,\n    Z_SYNC_GROUP_CLOSED = 6,\n\n    _Z_ERR_FAILED_TO_SPAWN_TASK = -121,\n    _Z_ERR_TRANSPORT_RX_DURATION_EXPIRED = -120,\n    _Z_ERR_MESSAGE_DESERIALIZATION_FAILED = -119,\n    _Z_ERR_MESSAGE_SERIALIZATION_FAILED = -118,\n    _Z_ERR_MESSAGE_UNEXPECTED = -117,\n    _Z_ERR_MESSAGE_FLAG_UNEXPECTED = -116,\n    _Z_ERR_MESSAGE_ZENOH_DECLARATION_UNKNOWN = -115,\n    _Z_ERR_MESSAGE_ZENOH_UNKNOWN = -114,\n    _Z_ERR_MESSAGE_TRANSPORT_UNKNOWN = -113,\n    _Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN = -112,\n\n    _Z_ERR_ENTITY_DECLARATION_FAILED = -111,\n    _Z_ERR_ENTITY_UNKNOWN = -110,\n    _Z_ERR_KEYEXPR_UNKNOWN = -109,\n    _Z_ERR_KEYEXPR_NOT_MATCH = -108,\n    _Z_ERR_QUERY_NOT_MATCH = -107,\n\n    _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY = -104,\n    _Z_ERR_TRANSPORT_NOT_AVAILABLE = -103,\n    _Z_ERR_TRANSPORT_OPEN_FAILED = -102,\n    _Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION = -101,\n    _Z_ERR_TRANSPORT_TX_FAILED = -100,\n    _Z_ERR_TRANSPORT_RX_FAILED = -99,\n    _Z_ERR_TRANSPORT_NO_SPACE = -98,\n    _Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES = -97,\n\n    _Z_ERR_CONFIG_FAILED_INSERT = -95,\n    _Z_ERR_CONFIG_UNSUPPORTED_CLIENT_MULTICAST = -94,\n    _Z_ERR_CONFIG_UNSUPPORTED_PEER_UNICAST = -93,\n    _Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN = -92,\n    _Z_ERR_CONFIG_LOCATOR_INVALID = -91,\n    _Z_ERR_CONFIG_INVALID_MODE = -90,\n    _Z_ERR_CONFIG_INVALID_VALUE = -89,\n\n    _Z_ERR_SCOUT_NO_RESULTS = -87,\n\n    _Z_ERR_UNDERFLOW = -81,\n    _Z_ERR_SYSTEM_GENERIC = -80,\n    _Z_ERR_SYSTEM_TASK_FAILED = -79,\n    _Z_ERR_SYSTEM_OUT_OF_MEMORY = -78,\n\n    _Z_ERR_CONNECTION_CLOSED = -77,\n\n    _Z_ERR_DID_NOT_READ = -76,\n    _Z_ERR_INVALID = -75,\n    Z_EINVAL = -75,\n    _Z_ERR_OVERFLOW = -74,\n    _Z_ERR_SESSION_CLOSED = -73,\n    Z_EDESERIALIZE = -72,\n    Z_ETIMEDOUT = -71,\n    _Z_ERR_KEYEXPR_DECLARED_ON_ANOTHER_SESSION = -70,\n    Z_ERR_CANCELLED = -69,\n\n    _Z_ERR_NULL = -127,\n    _Z_ERR_GENERIC = -128\n} _z_res_t;\n\n#define _Z_SET_IF_OK(expr, value) \\\n    {                             \\\n        if (expr == _Z_RES_OK) {  \\\n            expr = value;         \\\n        }                         \\\n    }\n\n#define _Z_RETURN_IF_ERR(expr)    \\\n    {                             \\\n        z_result_t __res = expr;  \\\n        if (__res != _Z_RES_OK) { \\\n            return __res;         \\\n        }                         \\\n    }\n\n#define _Z_CLEAN_RETURN_IF_ERR(base_expr, clean_expr) \\\n    {                                                 \\\n        z_result_t __res = base_expr;                 \\\n        if (__res != _Z_RES_OK) {                     \\\n            clean_expr;                               \\\n            return __res;                             \\\n        }                                             \\\n    }\n\n#define _Z_RETURN_ERR_OOM_IF_TRUE(expr)         \\\n    {                                           \\\n        if (expr) {                             \\\n            return _Z_ERR_SYSTEM_OUT_OF_MEMORY; \\\n        }                                       \\\n    }\n\n#define _Z_CLEAN_RETURN_ERR_OOM_IF_TRUE(expr, clean_expr) \\\n    {                                                     \\\n        if (expr) {                                       \\\n            clean_expr;                                   \\\n            return _Z_ERR_SYSTEM_OUT_OF_MEMORY;           \\\n        }                                                 \\\n    }\n\n#define _Z_IS_OK(expr) (expr == _Z_RES_OK)\n#define _Z_IS_ERR(expr) (expr != _Z_RES_OK)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_RESULT_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/sleep.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef INCLUDE_ZENOH_PICO_UTILS_SLEEP_H\n#define INCLUDE_ZENOH_PICO_UTILS_SLEEP_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/system/platform.h\"\n\n#define _Z_SLEEP_BACKOFF_MIN_MS 100\n#define _Z_SLEEP_BACKOFF_MAX_MS 1000\n\nstatic inline void _z_backoff_advance(uint32_t *sleep_ms) {\n    if (*sleep_ms < _Z_SLEEP_BACKOFF_MAX_MS) {\n        *sleep_ms <<= 1;\n        if (*sleep_ms > _Z_SLEEP_BACKOFF_MAX_MS) {\n            *sleep_ms = _Z_SLEEP_BACKOFF_MAX_MS;\n        }\n    }\n}\n\nstatic inline bool _z_backoff_sleep(z_clock_t *start, int32_t timeout_ms, uint32_t *sleep_ms) {\n    uint32_t current_sleep_ms = *sleep_ms;\n\n    if (timeout_ms == 0) {\n        return false;\n    }\n\n    if (timeout_ms > 0) {\n        unsigned long elapsed = z_clock_elapsed_ms(start);\n        if (elapsed >= (unsigned long)timeout_ms) {\n            return false;\n        }\n\n        uint32_t remaining_ms = (uint32_t)timeout_ms - (uint32_t)elapsed;\n        if (current_sleep_ms > remaining_ms) {\n            current_sleep_ms = remaining_ms;\n        }\n    }\n\n    z_sleep_ms(current_sleep_ms);\n    _z_backoff_advance(sleep_ms);\n    return true;\n}\n#endif /* INCLUDE_ZENOH_PICO_UTILS_SLEEP_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/string.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_STRING_H\n#define ZENOH_PICO_UTILS_STRING_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    char const *start;\n    char const *end;\n} _z_str_se_t;\n\ntypedef struct {\n    _z_str_se_t s;\n    char const *delimiter;\n} _z_splitstr_t;\n\n/**\n * Creates a `_z_str_se_t` from a null-terminated C string.\n */\n_z_str_se_t _z_bstrnew(const char *start);\n\n/**\n * The reverse equivalent of libc's `strstr`.\n *\n * Returns NULL if the needle is not found.\n * If found, the return pointer will point to the end of the last occurring\n * needle within the haystack.\n */\nchar const *_z_rstrstr(const char *haystack_start, const char *haystack_end, const char *needle);\n\n/**\n * A non-null-terminated haystack equivalent of libc's `strstr`.\n *\n * Returns NULL if the needle is not found.\n * If found, the return pointer will point to the start of the first occurrence\n * of the needle within the haystack.\n */\nchar const *_z_strstr(char const *haystack_start, char const *haystack_end, const char *needle_start);\n\nchar const *_z_strstr_skipneedle(char const *haystack_start, char const *haystack_end, const char *needle_start);\nchar const *_z_bstrstr_skipneedle(_z_str_se_t haystack, _z_str_se_t needle);\n\nbool _z_splitstr_is_empty(const _z_splitstr_t *src);\n_z_str_se_t _z_splitstr_next(_z_splitstr_t *str);\n_z_str_se_t _z_splitstr_split_once(_z_splitstr_t src, _z_str_se_t *next);\n_z_str_se_t _z_splitstr_nextback(_z_splitstr_t *str);\n\nsize_t _z_strcnt(char const *haystack_start, const char *harstack_end, const char *needle_start);\n\nsize_t _z_str_startswith(const char *s, const char *needle);\n\n// Must be used on a null terminated string with str[strlen(str) + 1] being valid memory.\nstatic inline void _z_str_append(char *str, const char c) {\n    size_t len = strlen(str);\n    str[len] = c;\n    str[len + 1] = '\\0';\n}\n\n/*\n * Convert a non null terminated `_z_str_se_t` to a uint32_t.\n */\nbool _z_str_se_atoui(const _z_str_se_t *str, uint32_t *result);\n\n/*\n * Parse a null-terminated base-10 string as a signed 32-bit integer.\n */\nbool _z_str_parse_i32(const char *s, int32_t *out);\n\n/*\n * Parse a null-terminated boolean string.\n *\n * Accepted values are \"true\" and \"false\".\n */\nbool _z_str_parse_bool(const char *s, bool *out);\n\nvoid *_z_memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len);\n\n/*\n * Safely copies a block of memory into a destination buffer at a given offset, if bounds allow.\n *\n * Parameters:\n *   dest       - Pointer to the destination buffer.\n *   dest_len   - Total size of the destination buffer.\n *   offset     - Pointer to the current write offset; may be NULL to use offset 0 without updating, otherwise will be\n * updated if the copy succeeds.\n *   src        - Pointer to the source data.\n *   len        - Number of bytes to copy.\n *\n * Returns:\n *   true  - If the copy succeeds (bounds are respected and pointers are valid).\n *   false - If the copy would overflow the buffer, or any pointer is NULL.\n */\nstatic inline bool _z_memcpy_checked(void *dest, size_t dest_len, size_t *offset, const void *src, size_t len) {\n    if (dest == NULL || src == NULL) {\n        return false;\n    }\n\n    size_t local_offset = (offset != NULL) ? *offset : 0;\n    if (len > dest_len - local_offset) {\n        return false;\n    }\n\n    char *d_start = (char *)dest + local_offset;\n    char *d_end = d_start + len;\n    const char *s_start = (const char *)src;\n    const char *s_end = s_start + len;\n\n    // Check for overlap: if src and dest ranges intersect\n    if ((s_start < d_end && s_end > d_start)) {\n        return false;  // Overlap detected\n    }\n\n    // SAFETY: Copy is bounds-checked above.\n    // Flawfinder: ignore [CWE-120]\n    memcpy(d_start, src, len);\n    if (offset != NULL) {\n        *offset += len;\n    }\n    return true;\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_STRING_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/time_range.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_UTILS_TIME_RANGE_H\n#define ZENOH_PICO_UTILS_TIME_RANGE_H\n\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic const double _Z_TIME_RANGE_U_TO_SECS = 0.000001;\nstatic const double _Z_TIME_RANGE_MS_TO_SECS = 0.001;\nstatic const double _Z_TIME_RANGE_M_TO_SECS = 60.0;\nstatic const double _Z_TIME_RANGE_H_TO_SECS = 3600.0;\nstatic const double _Z_TIME_RANGE_D_TO_SECS = 86400.0;\nstatic const double _Z_TIME_RANGE_W_TO_SECS = 604800.0;\n\ntypedef struct {\n    enum { _Z_TIME_BOUND_INCLUSIVE, _Z_TIME_BOUND_EXCLUSIVE, _Z_TIME_BOUND_UNBOUNDED } bound;\n    double now_offset;\n} _z_time_bound_t;\n\ntypedef struct {\n    _z_time_bound_t start;\n    _z_time_bound_t end;\n} _z_time_range_t;\n\n/**\n * Parse a time range from a string.\n *\n * Returns true if the string contained a valid time range, false otherwise.\n * If valid range will contain the result.\n */\nbool _z_time_range_from_str(const char *str, size_t len, _z_time_range_t *range);\n\n/**\n * Converts a time bound into a string.\n *\n * Returns true if the time bound was successfully converted, false otherwise.\n * If valid buf will contain the result.\n */\nbool _z_time_bound_to_str(const _z_time_bound_t *bound, char *buf, size_t buf_len);\n\n/**\n * Converts a time range into a string.\n *\n * Returns true if the time range was successfully converted, false otherwise.\n * If valid buf will contain the result.\n */\nbool _z_time_range_to_str(const _z_time_range_t *range, char *buf, size_t buf_len);\n\n/**\n * Resolves an offset to a base time.\n *\n * Returns the offset time.\n */\n_z_ntp64_t _z_time_range_resolve_offset(_z_ntp64_t base, double offset);\n\n/**\n * Checks if a timestamp is contained within a time range at the specified time.\n *\n * Returns true if the timestamp is containend in the time range, false otherwise.\n */\nbool _z_time_range_contains_at_time(const _z_time_range_t *range, const _z_ntp64_t timestamp, const _z_ntp64_t time);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_TIME_RANGE_H */\n"
  },
  {
    "path": "include/zenoh-pico/utils/uuid.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\n#ifndef ZENOH_PICO_UTILS_UUID_H\n#define ZENOH_PICO_UTILS_UUID_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Converts an UUID in string format to a byte array.\n *\n * Parameters:\n *   bytes: Pointer to an already allocated byte array of size (at least) 16 bytes.\n *   uuid_str: A valid UUID string.\n */\nvoid _z_uuid_to_bytes(uint8_t *bytes, const char *uuid_str);\n\n/**\n * Converts an Zenoh ID to string.\n *\n * Parameters:\n *   id: Zenoh ID.\n *\n * Returns:\n *   ID string representation\n */\n_z_string_t _z_id_to_string(const _z_id_t *id);\n\n/**\n * Parses a string to a Zenoh ID.\n *\n * Parameters:\n *   str - Pointer to the string to parse.\n *\n * Returns:\n *   The parsed Zenoh ID if successful, or an empty ID on failure.\n */\n_z_id_t _z_id_from_string(const _z_string_t *str);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_UTILS_UUID_H */\n"
  },
  {
    "path": "include/zenoh-pico.h",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// ⚠️ This file is auto-generated from include/zenoh-pico.h.in\n\n#ifndef ZENOH_PICO_H\n#define ZENOH_PICO_H\n\n#define ZENOH_PICO \"1.9.0\"\n#define ZENOH_PICO_MAJOR 1\n#define ZENOH_PICO_MINOR 9\n#define ZENOH_PICO_PATCH 0\n#define ZENOH_PICO_TWEAK 0\n\n#include \"zenoh-pico/api/admin_space.h\"\n#include \"zenoh-pico/api/advanced_publisher.h\"\n#include \"zenoh-pico/api/advanced_subscriber.h\"\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/encoding.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/macros.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n\n#endif /* ZENOH_PICO_H */\n"
  },
  {
    "path": "include/zenoh-pico.h.in",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// ⚠️ This file is auto-generated from include/zenoh-pico.h.in\n\n#ifndef ZENOH_PICO_H\n#define ZENOH_PICO_H\n\n#define ZENOH_PICO \"@ZENOH_PICO@\"\n#define ZENOH_PICO_MAJOR @ZENOH_PICO_MAJOR@\n#define ZENOH_PICO_MINOR @ZENOH_PICO_MINOR@\n#define ZENOH_PICO_PATCH @ZENOH_PICO_PATCH@\n#define ZENOH_PICO_TWEAK @ZENOH_PICO_TWEAK@\n\n#include \"zenoh-pico/api/admin_space.h\"\n#include \"zenoh-pico/api/advanced_publisher.h\"\n#include \"zenoh-pico/api/advanced_subscriber.h\"\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/encoding.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/macros.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n\n#endif /* ZENOH_PICO_H */\n"
  },
  {
    "path": "library.json",
    "content": "{\n    \"name\": \"zenoh-pico\",\n    \"version\": \"1.9.0\",\n    \"description\": \"The Eclipse Zenoh: Zero Overhead Pub/sub, Store/Query and Compute. It unifies data in motion, data in-use, data at rest and computations. It carefully blends traditional pub/sub with geo-distributed storages, queries and computations, while retaining a level of time and space efficiency that is well beyond any of the mainstream stacks. Zenoh-Pico is the implementation able to scale down to extremely constrainded devices and networks.\",\n    \"keywords\": [\n        \"pubsub\",\n        \"publish\",\n        \"subscribe\",\n        \"query\",\n        \"distributed data distribution\"\n    ],\n    \"homepage\": \"https://zenoh.io/\",\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"https://github.com/eclipse-zenoh/zenoh-pico\"\n    },\n    \"authors\": {\n        \"name\": \"ZettaScale Technology Zenoh Team\",\n        \"email\": \"zenoh@zettascale.tech\",\n        \"url\": \"https://www.zettascale.tech/\",\n        \"maintainer\": true\n    },\n    \"license\": \"Apache-2.0 OR EPL-2.0\",\n    \"frameworks\": [\n        \"arduino\",\n        \"espidf\",\n        \"mbed\",\n        \"zephyr\"\n    ],\n    \"headers\": [\n        \"zenoh-pico.h\"\n    ],\n    \"examples\": [\n        \"examples\"\n    ],\n    \"dependencies\": {\n        \"BluetoothSerial\": \"0.16.1\",\n        \"FreeRTOS\": \"1.0.0\"\n    },\n    \"build\": {\n        \"extraScript\": \"extra_script.py\"\n    }\n}\n"
  },
  {
    "path": "src/api/admin_space.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/api/admin_space.h\"\n\n#include \"zenoh-pico/api/encoding.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/json_encoder.h\"\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n\n#define _ZE_ADMIN_SPACE_KE_BUF_LEN 256\n\ntypedef struct {\n    const char *data;\n    size_t len;\n} _ze_admin_space_ke_segment_t;\n\ntypedef z_result_t (*_ze_admin_space_encode_fn_t)(_z_json_encoder_t *je, void *ctx);\ntypedef z_result_t (*_ze_admin_space_ke_builder_t)(z_owned_keyexpr_t *ke, const z_id_t *zid);\n\ntypedef struct {\n    const char *name;\n    _ze_admin_space_ke_builder_t build_ke;\n    _ze_admin_space_encode_fn_t encode;\n} _ze_admin_space_endpoint_t;\n\nstatic z_result_t _ze_admin_space_build_ke(z_owned_keyexpr_t *ke, const z_id_t *zid,\n                                           const _ze_admin_space_ke_segment_t *segments, size_t segment_count) {\n    z_internal_keyexpr_null(ke);\n\n    z_owned_string_t zid_str;\n    _Z_RETURN_IF_ERR(z_id_to_string(zid, &zid_str));\n\n    const z_loaned_string_t *zid_loan = z_string_loan(&zid_str);\n    const char *zid_data = z_string_data(zid_loan);\n    size_t zid_len = z_string_len(zid_loan);\n\n    char buf[_ZE_ADMIN_SPACE_KE_BUF_LEN];\n    size_t off = 0;\n\n    int n =\n        snprintf(buf + off, sizeof(buf) - off, \"%s%s%.*s\", _Z_KEYEXPR_AT, _Z_KEYEXPR_SEPARATOR, (int)zid_len, zid_data);\n    z_string_drop(z_string_move(&zid_str));\n    if (n < 0 || (size_t)n >= sizeof(buf) - off) {\n        return _Z_ERR_INVALID;\n    }\n    off += (size_t)n;\n\n    for (size_t i = 0; i < segment_count; i++) {\n        n = snprintf(buf + off, sizeof(buf) - off, \"%s%.*s\", _Z_KEYEXPR_SEPARATOR, (int)segments[i].len,\n                     segments[i].data);\n        if (n < 0 || (size_t)n >= sizeof(buf) - off) {\n            return _Z_ERR_INVALID;\n        }\n        off += (size_t)n;\n    }\n\n    return z_keyexpr_from_substr(ke, buf, off);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO / Z_KEYEXPR_STARSTAR\nstatic z_result_t _ze_admin_space_pico_queryable_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n        {_Z_KEYEXPR_STARSTAR, _Z_KEYEXPR_STARSTAR_LEN},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 2);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO\nstatic z_result_t _ze_admin_space_pico_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 1);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO / _Z_KEYEXPR_SESSION\nstatic z_result_t _ze_admin_space_pico_session_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 2);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO / _Z_KEYEXPR_SESSION / _Z_KEYEXPR_TRANSPORTS\nstatic z_result_t _ze_admin_space_pico_transports_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_TRANSPORTS, _Z_KEYEXPR_TRANSPORTS_LEN},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 3);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO / _Z_KEYEXPR_SESSION / _Z_KEYEXPR_TRANSPORTS / 0\nstatic z_result_t _ze_admin_space_pico_transports_0_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_TRANSPORTS, _Z_KEYEXPR_TRANSPORTS_LEN},\n        {\"0\", 1},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 4);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO / _Z_KEYEXPR_SESSION / _Z_KEYEXPR_TRANSPORTS / 0 / _Z_KEYEXPR_PEERS\nstatic z_result_t _ze_admin_space_pico_transports_0_peers_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_TRANSPORTS, _Z_KEYEXPR_TRANSPORTS_LEN},\n        {\"0\", 1},\n        {_Z_KEYEXPR_PEERS, _Z_KEYEXPR_PEERS_LEN},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 5);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_PICO / _Z_KEYEXPR_SESSION / _Z_KEYEXPR_TRANSPORTS / 0 / _Z_KEYEXPR_PEERS /\n// REMOTE_ZID\nstatic z_result_t _ze_admin_space_pico_transports_0_peers_peer_ke(z_owned_keyexpr_t *ke, const z_id_t *zid,\n                                                                  const z_id_t *remote_zid) {\n    z_owned_string_t remote_zid_str;\n    _Z_RETURN_IF_ERR(z_id_to_string(remote_zid, &remote_zid_str));\n\n    const z_loaned_string_t *remote_zid_loan = z_string_loan(&remote_zid_str);\n    const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_PICO, _Z_KEYEXPR_PICO_LEN},\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_TRANSPORTS, _Z_KEYEXPR_TRANSPORTS_LEN},\n        {\"0\", 1},\n        {_Z_KEYEXPR_PEERS, _Z_KEYEXPR_PEERS_LEN},\n        {z_string_data(remote_zid_loan), z_string_len(remote_zid_loan)},\n    };\n\n    z_result_t ret = _ze_admin_space_build_ke(ke, zid, segments, 6);\n    z_string_drop(z_string_move(&remote_zid_str));\n    return ret;\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_SESSION / Z_KEYEXPR_STARSTAR\nstatic z_result_t _ze_admin_space_session_queryable_ke(z_owned_keyexpr_t *ke, const z_id_t *zid) {\n    static const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_STARSTAR, _Z_KEYEXPR_STARSTAR_LEN},\n    };\n    return _ze_admin_space_build_ke(ke, zid, segments, 2);\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_SESSION / _Z_KEYEXPR_TRANSPORT_UNICAST / PEER_ZID\nstatic z_result_t _ze_admin_space_session_transport_ke(z_owned_keyexpr_t *ke, const z_id_t *zid,\n                                                       const z_id_t *peer_zid) {\n    z_owned_string_t peer_zid_str;\n    _Z_RETURN_IF_ERR(z_id_to_string(peer_zid, &peer_zid_str));\n\n    const z_loaned_string_t *peer_zid_loan = z_string_loan(&peer_zid_str);\n    const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_TRANSPORT_UNICAST, _Z_KEYEXPR_TRANSPORT_UNICAST_LEN},\n        {z_string_data(peer_zid_loan), z_string_len(peer_zid_loan)},\n    };\n\n    z_result_t ret = _ze_admin_space_build_ke(ke, zid, segments, 3);\n    z_string_drop(z_string_move(&peer_zid_str));\n    return ret;\n}\n\n// ke = _Z_KEYEXPR_AT / ZID / _Z_KEYEXPR_SESSION / _Z_KEYEXPR_TRANSPORT_UNICAST / PEER_ZID / _Z_KEYEXPR_LINK /\n// LINK_ID\nstatic z_result_t _ze_admin_space_session_link_ke(z_owned_keyexpr_t *ke, const z_id_t *zid, const z_id_t *peer_zid,\n                                                  const z_id_t *link_id) {\n    z_owned_string_t peer_zid_str;\n    _Z_RETURN_IF_ERR(z_id_to_string(peer_zid, &peer_zid_str));\n    z_owned_string_t link_id_str;\n    _Z_CLEAN_RETURN_IF_ERR(z_id_to_string(link_id, &link_id_str), z_string_drop(z_string_move(&peer_zid_str)));\n\n    const z_loaned_string_t *peer_zid_loan = z_string_loan(&peer_zid_str);\n    const z_loaned_string_t *link_id_loan = z_string_loan(&link_id_str);\n    const _ze_admin_space_ke_segment_t segments[] = {\n        {_Z_KEYEXPR_SESSION, _Z_KEYEXPR_SESSION_LEN},\n        {_Z_KEYEXPR_TRANSPORT_UNICAST, _Z_KEYEXPR_TRANSPORT_UNICAST_LEN},\n        {z_string_data(peer_zid_loan), z_string_len(peer_zid_loan)},\n        {_Z_KEYEXPR_LINK, _Z_KEYEXPR_LINK_LEN},\n        {z_string_data(link_id_loan), z_string_len(link_id_loan)},\n    };\n\n    z_result_t ret = _ze_admin_space_build_ke(ke, zid, segments, 5);\n    z_string_drop(z_string_move(&peer_zid_str));\n    z_string_drop(z_string_move(&link_id_str));\n    return ret;\n}\n#endif  // Z_FEATURE_CONNECTIVITY == 1\n\nstatic z_result_t _ze_admin_space_encode_whatami(_z_json_encoder_t *je, z_whatami_t mode) {\n    switch (mode) {\n        case Z_WHATAMI_ROUTER:\n            return _z_json_encoder_write_string(je, \"router\");\n        case Z_WHATAMI_PEER:\n            return _z_json_encoder_write_string(je, \"peer\");\n        case Z_WHATAMI_CLIENT:\n            return _z_json_encoder_write_string(je, \"client\");\n        default:\n            return _Z_ERR_INVALID;\n    }\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic z_result_t _ze_admin_space_encode_connectivity_transport_payload(z_owned_bytes_t *payload, const z_id_t *zid,\n                                                                        z_whatami_t whatami, bool is_qos, bool is_shm) {\n    z_internal_bytes_null(payload);\n\n    _z_json_encoder_t je;\n    _Z_RETURN_IF_ERR(_z_json_encoder_empty(&je));\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_start_object(&je), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"zid\"), _z_json_encoder_clear(&je));\n    z_owned_string_t zid_str;\n    _Z_CLEAN_RETURN_IF_ERR(z_id_to_string(zid, &zid_str), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_z_string(&je, z_string_loan(&zid_str)),\n                           z_string_drop(z_string_move(&zid_str));\n                           _z_json_encoder_clear(&je));\n    z_string_drop(z_string_move(&zid_str));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"whatami\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_ze_admin_space_encode_whatami(&je, whatami), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"is_qos\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_boolean(&je, is_qos), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"is_shm\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_boolean(&je, is_shm), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_end_object(&je), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_finish(&je, payload), _z_json_encoder_clear(&je));\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _ze_admin_space_encode_connectivity_link_payload(z_owned_bytes_t *payload, const _z_string_t *src,\n                                                                   const _z_string_t *dst, uint16_t mtu,\n                                                                   bool is_streamed, bool is_reliable) {\n    z_internal_bytes_null(payload);\n\n    _z_json_encoder_t je;\n    _Z_RETURN_IF_ERR(_z_json_encoder_empty(&je));\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_start_object(&je), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"src\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_z_string(&je, src), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"dst\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_z_string(&je, dst), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"group\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_null(&je), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"mtu\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_u64(&je, (uint64_t)mtu), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"is_reliable\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_boolean(&je, is_reliable), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(&je, \"is_streamed\"), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_boolean(&je, is_streamed), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_end_object(&je), _z_json_encoder_clear(&je));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_finish(&je, payload), _z_json_encoder_clear(&je));\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_CONNECTIVITY == 1\n\nstatic z_result_t _ze_admin_space_encode_transport_type(_z_json_encoder_t *je, int type) {\n    switch (type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            return _z_json_encoder_write_string(je, \"unicast\");\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            return _z_json_encoder_write_string(je, \"multicast\");\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            return _z_json_encoder_write_string(je, \"raweth\");\n        default:\n            return _Z_ERR_INVALID;\n    }\n}\n\nstatic z_result_t _ze_admin_space_encode_str_intmap(_z_json_encoder_t *je, const _z_str_intmap_t *map) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n\n    _z_str_intmap_iterator_t it = _z_str_intmap_iterator_make(map);\n    while (_z_str_intmap_iterator_next(&it)) {\n        size_t key = _z_str_intmap_iterator_key(&it);\n        char key_buf[21];  // enough for 64-bit size_t\n        int n = snprintf(key_buf, sizeof(key_buf), \"%zu\", key);\n        if (n <= 0 || (size_t)n >= sizeof(key_buf)) {\n            return _Z_ERR_INVALID;\n        }\n        _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, key_buf));\n\n        char *value = _z_str_intmap_iterator_value(&it);\n        _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, value));\n    }\n    return _z_json_encoder_end_object(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_link(_z_json_encoder_t *je, const _z_link_t *link) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"link\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"type\"));\n    switch (link->_type) {\n        case _Z_LINK_TYPE_TCP:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"tcp\"));\n            break;\n        case _Z_LINK_TYPE_UDP:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"udp\"));\n            break;\n        case _Z_LINK_TYPE_BT:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"bt\"));\n            break;\n        case _Z_LINK_TYPE_SERIAL:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"serial\"));\n            break;\n        case _Z_LINK_TYPE_WS:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"ws\"));\n            break;\n        case _Z_LINK_TYPE_TLS:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"tls\"));\n            break;\n        case _Z_LINK_TYPE_RAWETH:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"raweth\"));\n            break;\n        default:\n            return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"endpoint\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"locator\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"metadata\"));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_str_intmap(je, &link->_endpoint._locator._metadata));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"protocol\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_z_string(je, &link->_endpoint._locator._protocol));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"address\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_z_string(je, &link->_endpoint._locator._address));\n    _Z_RETURN_IF_ERR(_z_json_encoder_end_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"config\"));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_str_intmap(je, &link->_endpoint._config));\n    _Z_RETURN_IF_ERR(_z_json_encoder_end_object(je));\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"capabilities\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"transport\"));\n    switch (link->_cap._transport) {\n        case Z_LINK_CAP_TRANSPORT_UNICAST:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"unicast\"));\n            break;\n        case Z_LINK_CAP_TRANSPORT_MULTICAST:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"multicast\"));\n            break;\n        case Z_LINK_CAP_TRANSPORT_RAWETH:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"raweth\"));\n            break;\n        default:\n            return _Z_ERR_INVALID;\n    }\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"flow\"));\n    switch (link->_cap._flow) {\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"datagram\"));\n            break;\n        case Z_LINK_CAP_FLOW_STREAM:\n            _Z_RETURN_IF_ERR(_z_json_encoder_write_string(je, \"stream\"));\n            break;\n        default:\n            return _Z_ERR_INVALID;\n    }\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"is_reliable\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_boolean(je, link->_cap._is_reliable != 0));\n    _Z_RETURN_IF_ERR(_z_json_encoder_end_object(je));\n    return _z_json_encoder_end_object(je);\n}\n\nstatic void _ze_admin_space_reply_null(_ze_admin_space_reply_t *reply) {\n    z_internal_keyexpr_null(&reply->ke);\n    z_internal_bytes_null(&reply->payload);\n}\n\nvoid _ze_admin_space_reply_clear(_ze_admin_space_reply_t *reply) {\n    z_keyexpr_drop(z_keyexpr_move(&reply->ke));\n    z_bytes_drop(z_bytes_move(&reply->payload));\n    _ze_admin_space_reply_null(reply);\n}\n\nstatic z_result_t _ze_admin_space_add_reply_bytes(const z_loaned_keyexpr_t *ke, z_moved_bytes_t *payload,\n                                                  _ze_admin_space_reply_list_t **replies) {\n    _ze_admin_space_reply_t *reply = z_malloc(sizeof(_ze_admin_space_reply_t));\n    if (reply == NULL) {\n        z_bytes_drop(payload);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    _ze_admin_space_reply_null(reply);\n\n    _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_clone(&reply->ke, ke), z_bytes_drop(payload); z_free(reply));\n    z_bytes_take(&reply->payload, payload);\n\n    _ze_admin_space_reply_list_t *old = *replies;\n    _ze_admin_space_reply_list_t *tmp = _ze_admin_space_reply_list_push(*replies, reply);\n    if (tmp == old) {\n        _ze_admin_space_reply_clear(reply);\n        z_free(reply);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    *replies = tmp;\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _ze_admin_space_add_reply(_z_json_encoder_t *je, const z_loaned_keyexpr_t *ke,\n                                            _ze_admin_space_reply_list_t **replies) {\n    z_owned_bytes_t payload;\n    z_internal_bytes_null(&payload);\n    _Z_RETURN_IF_ERR(_z_json_encoder_finish(je, &payload));\n    return _ze_admin_space_add_reply_bytes(ke, z_bytes_move(&payload), replies);\n}\n\nstatic z_result_t _ze_admin_space_encode_transport_common(_z_json_encoder_t *je, const _z_transport_common_t *common) {\n    return _ze_admin_space_encode_link(je, common->_link);\n}\n\nstatic z_result_t _ze_admin_space_encode_peer_common(_z_json_encoder_t *je, const _z_transport_peer_common_t *peer) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"zid\"));\n    z_owned_string_t id_string;\n    _Z_RETURN_IF_ERR(z_id_to_string(&peer->_remote_zid, &id_string));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_z_string(je, z_string_loan(&id_string)),\n                           z_string_drop(z_string_move(&id_string)));\n    z_string_drop(z_string_move(&id_string));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"whatami\"));\n    return _ze_admin_space_encode_whatami(je, peer->_remote_whatami);\n}\n\nstatic z_result_t _ze_admin_space_encode_unicast_peer(_z_json_encoder_t *je, const _z_transport_peer_unicast_t *peer) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_peer_common(je, &peer->common));\n    return _z_json_encoder_end_object(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_multicast_peer(_z_json_encoder_t *je,\n                                                        const _z_transport_peer_multicast_t *peer) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_peer_common(je, &peer->common));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"remote_addr\"));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_z_slice(je, &peer->_remote_addr));\n    return _z_json_encoder_end_object(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_unicast_peers(_z_json_encoder_t *je,\n                                                       const _z_transport_peer_unicast_slist_t *peers) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_array(je));\n\n    for (; peers != NULL; peers = _z_transport_peer_unicast_slist_next(peers)) {\n        const _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(peers);\n        _Z_RETURN_IF_ERR(_ze_admin_space_encode_unicast_peer(je, peer));\n    }\n\n    return _z_json_encoder_end_array(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_multicast_peers(_z_json_encoder_t *je,\n                                                         const _z_transport_peer_multicast_slist_t *peers) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_array(je));\n\n    for (; peers != NULL; peers = _z_transport_peer_multicast_slist_next(peers)) {\n        const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(peers);\n        _Z_RETURN_IF_ERR(_ze_admin_space_encode_multicast_peer(je, peer));\n    }\n\n    return _z_json_encoder_end_array(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_transport_unicast(_z_json_encoder_t *je, _z_transport_unicast_t *tp) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_transport_peer_mutex_lock(&tp->_common);\n\n    ret = _ze_admin_space_encode_transport_common(je, &tp->_common);\n    if (ret == _Z_RES_OK) {\n        ret = _z_json_encoder_write_key(je, \"peers\");\n    }\n    if (ret == _Z_RES_OK) {\n        ret = _ze_admin_space_encode_unicast_peers(je, tp->_peers);\n    }\n\n    _z_transport_peer_mutex_unlock(&tp->_common);\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_encode_transport_multicast(_z_json_encoder_t *je, _z_transport_multicast_t *tp) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_transport_peer_mutex_lock(&tp->_common);\n\n    ret = _ze_admin_space_encode_transport_common(je, &tp->_common);\n    if (ret == _Z_RES_OK) {\n        ret = _z_json_encoder_write_key(je, \"peers\");\n    }\n    if (ret == _Z_RES_OK) {\n        ret = _ze_admin_space_encode_multicast_peers(je, tp->_peers);\n    }\n\n    _z_transport_peer_mutex_unlock(&tp->_common);\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_encode_transport(_z_json_encoder_t *je, _z_transport_t *tp) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"type\"));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_transport_type(je, tp->_type));\n\n    switch (tp->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            _Z_RETURN_IF_ERR(_ze_admin_space_encode_transport_unicast(je, &tp->_transport._unicast));\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            _Z_RETURN_IF_ERR(_ze_admin_space_encode_transport_multicast(je, &tp->_transport._multicast));\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            _Z_RETURN_IF_ERR(_ze_admin_space_encode_transport_multicast(je, &tp->_transport._raweth));\n            break;\n        default:\n            break;\n    }\n\n    return _z_json_encoder_end_object(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_transport_peers(_z_json_encoder_t *je, _z_transport_t *tp) {\n    z_result_t ret = _Z_RES_OK;\n\n    switch (tp->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_unicast_t *utp = &tp->_transport._unicast;\n            _z_transport_peer_mutex_lock(&utp->_common);\n            ret = _ze_admin_space_encode_unicast_peers(je, utp->_peers);\n            _z_transport_peer_mutex_unlock(&utp->_common);\n            break;\n        }\n        case _Z_TRANSPORT_MULTICAST_TYPE: {\n            _z_transport_multicast_t *mtp = &tp->_transport._multicast;\n            _z_transport_peer_mutex_lock(&mtp->_common);\n            ret = _ze_admin_space_encode_multicast_peers(je, mtp->_peers);\n            _z_transport_peer_mutex_unlock(&mtp->_common);\n            break;\n        }\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            _z_transport_multicast_t *rtp = &tp->_transport._raweth;\n            _z_transport_peer_mutex_lock(&rtp->_common);\n            ret = _ze_admin_space_encode_multicast_peers(je, rtp->_peers);\n            _z_transport_peer_mutex_unlock(&rtp->_common);\n            break;\n        }\n        default:\n            break;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_encode_transports(_z_json_encoder_t *je, _z_transport_t *tp) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_array(je));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_transport(je, tp));\n    return _z_json_encoder_end_array(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_session(_z_json_encoder_t *je, _z_session_t *session) {\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(session));\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_start_object(je), _z_session_mutex_unlock(session));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"zid\"), _z_session_mutex_unlock(session));\n    z_owned_string_t zid_str;\n    _Z_CLEAN_RETURN_IF_ERR(z_id_to_string(&session->_local_zid, &zid_str), _z_session_mutex_unlock(session));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_z_string(je, z_string_loan(&zid_str)),\n                           z_string_drop(z_string_move(&zid_str));\n                           _z_session_mutex_unlock(session));\n    z_string_drop(z_string_move(&zid_str));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"whatami\"), _z_session_mutex_unlock(session));\n    _Z_CLEAN_RETURN_IF_ERR(_ze_admin_space_encode_whatami(je, session->_mode), _z_session_mutex_unlock(session));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"transports\"), _z_session_mutex_unlock(session));\n    _Z_CLEAN_RETURN_IF_ERR(_ze_admin_space_encode_transports(je, &session->_tp), _z_session_mutex_unlock(session));\n    _Z_CLEAN_RETURN_IF_ERR(_z_json_encoder_end_object(je), _z_session_mutex_unlock(session));\n\n    _z_session_mutex_unlock(session);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _ze_admin_space_encode_pico(_z_json_encoder_t *je, void *ctx) {\n    _z_session_t *session = (_z_session_t *)ctx;\n    _Z_RETURN_IF_ERR(_z_json_encoder_start_object(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_key(je, \"session\"));\n    _Z_RETURN_IF_ERR(_ze_admin_space_encode_session(je, session));\n    return _z_json_encoder_end_object(je);\n}\n\nstatic z_result_t _ze_admin_space_encode_pico_session(_z_json_encoder_t *je, void *ctx) {\n    _z_session_t *session = (_z_session_t *)ctx;\n    return _ze_admin_space_encode_session(je, session);\n}\n\nstatic z_result_t _ze_admin_space_encode_pico_transports(_z_json_encoder_t *je, void *ctx) {\n    _z_session_t *session = (_z_session_t *)ctx;\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(session));\n    z_result_t ret = _ze_admin_space_encode_transports(je, &session->_tp);\n    _z_session_mutex_unlock(session);\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_encode_pico_transport_0(_z_json_encoder_t *je, void *ctx) {\n    _z_session_t *session = (_z_session_t *)ctx;\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(session));\n    z_result_t ret = _ze_admin_space_encode_transport(je, &session->_tp);\n    _z_session_mutex_unlock(session);\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_encode_pico_transport_0_peers(_z_json_encoder_t *je, void *ctx) {\n    _z_session_t *session = (_z_session_t *)ctx;\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(session));\n    z_result_t ret = _ze_admin_space_encode_transport_peers(je, &session->_tp);\n    _z_session_mutex_unlock(session);\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_reply_if_intersects(const z_loaned_query_t *query, const z_loaned_keyexpr_t *ke,\n                                                      void *ctx, _ze_admin_space_reply_list_t **replies,\n                                                      _ze_admin_space_encode_fn_t encode) {\n    if (z_keyexpr_intersects(z_query_keyexpr(query), ke)) {\n        _z_json_encoder_t je;\n        _Z_RETURN_IF_ERR(_z_json_encoder_empty(&je));\n        _Z_CLEAN_RETURN_IF_ERR(encode(&je, ctx), _z_json_encoder_clear(&je));\n        _Z_CLEAN_RETURN_IF_ERR(_ze_admin_space_add_reply(&je, ke, replies), _z_json_encoder_clear(&je));\n    }\n    return _Z_RES_OK;\n}\n\ntypedef struct {\n    const _z_transport_peer_unicast_t *peer;\n} _ze_admin_space_unicast_peer_ctx_t;\n\ntypedef struct {\n    const _z_transport_peer_multicast_t *peer;\n} _ze_admin_space_multicast_peer_ctx_t;\n\nstatic z_result_t _ze_admin_space_encode_pico_transport_0_unicast_peer(_z_json_encoder_t *je, void *ctx) {\n    const _ze_admin_space_unicast_peer_ctx_t *pctx = (const _ze_admin_space_unicast_peer_ctx_t *)ctx;\n    return _ze_admin_space_encode_unicast_peer(je, pctx->peer);\n}\n\nstatic z_result_t _ze_admin_space_encode_pico_transport_0_multicast_peer(_z_json_encoder_t *je, void *ctx) {\n    const _ze_admin_space_multicast_peer_ctx_t *pctx = (const _ze_admin_space_multicast_peer_ctx_t *)ctx;\n    return _ze_admin_space_encode_multicast_peer(je, pctx->peer);\n}\n\nstatic void _ze_admin_space_query_handle_pico_transport_0_unicast_peers(const z_loaned_query_t *query,\n                                                                        const z_id_t *local_zid,\n                                                                        _z_transport_unicast_t *tp,\n                                                                        _ze_admin_space_reply_list_t **replies) {\n    _z_transport_peer_mutex_lock(&tp->_common);\n\n    for (_z_transport_peer_unicast_slist_t *peers = tp->_peers; peers != NULL;\n         peers = _z_transport_peer_unicast_slist_next(peers)) {\n        const _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(peers);\n\n        z_owned_keyexpr_t ke;\n        z_result_t ret;\n\n        ret = _ze_admin_space_pico_transports_0_peers_peer_ke(&ke, local_zid, &peer->common._remote_zid);\n        if (ret != _Z_RES_OK) {\n            _Z_WARN(\"Failed to build key expression for pico/session/transports/0/peers peer query: %d\", ret);\n            continue;\n        }\n\n        _ze_admin_space_unicast_peer_ctx_t ctx = {\n            .peer = peer,\n        };\n\n        ret = _ze_admin_space_reply_if_intersects(query, z_keyexpr_loan(&ke), &ctx, replies,\n                                                  _ze_admin_space_encode_pico_transport_0_unicast_peer);\n        if (ret != _Z_RES_OK) {\n            _Z_WARN(\"Failed to handle admin space query for pico/session/transports/0/peers peer endpoint: %d\", ret);\n        }\n\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n    }\n\n    _z_transport_peer_mutex_unlock(&tp->_common);\n}\n\nstatic void _ze_admin_space_query_handle_pico_transport_0_multicast_peers(const z_loaned_query_t *query,\n                                                                          const z_id_t *local_zid,\n                                                                          _z_transport_multicast_t *tp,\n                                                                          _ze_admin_space_reply_list_t **replies) {\n    _z_transport_peer_mutex_lock(&tp->_common);\n\n    for (_z_transport_peer_multicast_slist_t *peers = tp->_peers; peers != NULL;\n         peers = _z_transport_peer_multicast_slist_next(peers)) {\n        const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(peers);\n\n        z_owned_keyexpr_t ke;\n        z_result_t ret;\n\n        ret = _ze_admin_space_pico_transports_0_peers_peer_ke(&ke, local_zid, &peer->common._remote_zid);\n        if (ret != _Z_RES_OK) {\n            _Z_WARN(\"Failed to build key expression for pico/session/transports/0/peers peer query: %d\", ret);\n            continue;\n        }\n\n        _ze_admin_space_multicast_peer_ctx_t ctx = {\n            .peer = peer,\n        };\n\n        ret = _ze_admin_space_reply_if_intersects(query, z_keyexpr_loan(&ke), &ctx, replies,\n                                                  _ze_admin_space_encode_pico_transport_0_multicast_peer);\n        if (ret != _Z_RES_OK) {\n            _Z_WARN(\"Failed to handle admin space query for pico/session/transports/0/peers peer endpoint: %d\", ret);\n        }\n\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n    }\n\n    _z_transport_peer_mutex_unlock(&tp->_common);\n}\n\nstatic void _ze_admin_space_query_handle_pico_transport_0_peers(const z_loaned_query_t *query, _z_session_t *session,\n                                                                _ze_admin_space_reply_list_t **replies) {\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            _ze_admin_space_query_handle_pico_transport_0_unicast_peers(query, &session->_local_zid,\n                                                                        &session->_tp._transport._unicast, replies);\n            break;\n\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            _ze_admin_space_query_handle_pico_transport_0_multicast_peers(query, &session->_local_zid,\n                                                                          &session->_tp._transport._multicast, replies);\n            break;\n\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            _ze_admin_space_query_handle_pico_transport_0_multicast_peers(query, &session->_local_zid,\n                                                                          &session->_tp._transport._raweth, replies);\n            break;\n\n        default:\n            break;\n    }\n}\n\nstatic void _ze_admin_space_try_reply(const z_loaned_query_t *query, _z_session_t *session,\n                                      _ze_admin_space_reply_list_t **replies, const _ze_admin_space_endpoint_t *ep) {\n    z_owned_keyexpr_t ke;\n    z_result_t ret = ep->build_ke(&ke, &session->_local_zid);\n    if (ret != _Z_RES_OK) {\n        _Z_WARN(\"Failed to build key expression for %s query: %d\", ep->name, ret);\n        return;\n    }\n\n    ret = _ze_admin_space_reply_if_intersects(query, z_keyexpr_loan(&ke), session, replies, ep->encode);\n    if (ret != _Z_RES_OK) {\n        _Z_WARN(\"Failed to handle admin space query for %s endpoint: %d\", ep->name, ret);\n    }\n\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n}\n\nstatic void _ze_admin_space_query_handle_endpoints(const z_loaned_query_t *query, _z_session_t *session,\n                                                   const _ze_admin_space_endpoint_t *endpoints, size_t endpoint_count,\n                                                   _ze_admin_space_reply_list_t **replies) {\n    for (size_t i = 0; i < endpoint_count; i++) {\n        _ze_admin_space_try_reply(query, session, replies, &endpoints[i]);\n    }\n}\n\nstatic const _ze_admin_space_endpoint_t _ze_admin_space_pico_endpoints[] = {\n    {\"pico\", _ze_admin_space_pico_ke, _ze_admin_space_encode_pico},\n    {\"pico/session\", _ze_admin_space_pico_session_ke, _ze_admin_space_encode_pico_session},\n    {\"pico/session/transports\", _ze_admin_space_pico_transports_ke, _ze_admin_space_encode_pico_transports},\n    {\"pico/session/transports/0\", _ze_admin_space_pico_transports_0_ke, _ze_admin_space_encode_pico_transport_0},\n    {\"pico/session/transports/0/peers\", _ze_admin_space_pico_transports_0_peers_ke,\n     _ze_admin_space_encode_pico_transport_0_peers},\n};\n\nstatic void _ze_admin_space_query_handle_pico(const z_loaned_query_t *query, _z_session_t *session,\n                                              _ze_admin_space_reply_list_t **replies) {\n    _ze_admin_space_query_handle_endpoints(query, session, _ze_admin_space_pico_endpoints,\n                                           _ZP_ARRAY_SIZE(_ze_admin_space_pico_endpoints), replies);\n\n    _ze_admin_space_query_handle_pico_transport_0_peers(query, session, replies);\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic void _ze_admin_space_query_handle_connectivity_session(const z_loaned_query_t *query, _z_session_t *session,\n                                                              _ze_admin_space_reply_list_t **replies) {\n    _z_session_transport_mutex_lock(session);\n    if (session->_tp._type != _Z_TRANSPORT_UNICAST_TYPE) {\n        _z_session_transport_mutex_unlock(session);\n        return;\n    }\n    _z_transport_peer_mutex_lock(&session->_tp._transport._unicast._common);\n\n    const _z_transport_common_t *transport_common = &session->_tp._transport._unicast._common;\n    const _z_transport_peer_unicast_slist_t *peers = session->_tp._transport._unicast._peers;\n    while (peers != NULL) {\n        const _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(peers);\n\n        z_owned_keyexpr_t transport_ke;\n        z_result_t ret =\n            _ze_admin_space_session_transport_ke(&transport_ke, &session->_local_zid, &peer->common._remote_zid);\n        if (ret == _Z_RES_OK) {\n            if (z_keyexpr_intersects(z_query_keyexpr(query), z_keyexpr_loan(&transport_ke))) {\n                z_owned_bytes_t payload;\n                ret = _ze_admin_space_encode_connectivity_transport_payload(&payload, &peer->common._remote_zid,\n                                                                            peer->common._remote_whatami, false, false);\n                if (ret == _Z_RES_OK) {\n                    ret =\n                        _ze_admin_space_add_reply_bytes(z_keyexpr_loan(&transport_ke), z_bytes_move(&payload), replies);\n                }\n                if (ret != _Z_RES_OK) {\n                    _Z_WARN(\"Failed to add connectivity transport status reply: %d\", ret);\n                }\n            }\n            z_keyexpr_drop(z_keyexpr_move(&transport_ke));\n        } else {\n            _Z_WARN(\"Failed to build key expression for connectivity transport status: %d\", ret);\n        }\n\n        z_owned_keyexpr_t link_ke;\n        ret = _ze_admin_space_session_link_ke(&link_ke, &session->_local_zid, &peer->common._remote_zid,\n                                              &peer->common._remote_zid);\n        if (ret == _Z_RES_OK) {\n            if (z_keyexpr_intersects(z_query_keyexpr(query), z_keyexpr_loan(&link_ke))) {\n                uint16_t mtu;\n                bool is_streamed;\n                bool is_reliable;\n                _z_transport_link_properties_from_transport(transport_common, &mtu, &is_streamed, &is_reliable);\n\n                z_owned_bytes_t payload;\n                z_internal_bytes_null(&payload);\n                ret = _ze_admin_space_encode_connectivity_link_payload(\n                    &payload, &peer->common._link_src, &peer->common._link_dst, mtu, is_streamed, is_reliable);\n                if (ret == _Z_RES_OK) {\n                    ret = _ze_admin_space_add_reply_bytes(z_keyexpr_loan(&link_ke), z_bytes_move(&payload), replies);\n                }\n                if (ret != _Z_RES_OK) {\n                    _Z_WARN(\"Failed to add connectivity link status reply: %d\", ret);\n                }\n            }\n            z_keyexpr_drop(z_keyexpr_move(&link_ke));\n        } else {\n            _Z_WARN(\"Failed to build key expression for connectivity link status: %d\", ret);\n        }\n\n        peers = _z_transport_peer_unicast_slist_next(peers);\n    }\n\n    _z_transport_peer_mutex_unlock(&session->_tp._transport._unicast._common);\n    _z_session_transport_mutex_unlock(session);\n}\n#endif  // Z_FEATURE_CONNECTIVITY == 1\n\nstatic void _ze_admin_space_query_reply_all(z_loaned_query_t *query, _ze_admin_space_reply_list_t **replies) {\n    _ze_admin_space_reply_list_t *next = *replies;\n    while (next != NULL) {\n        _ze_admin_space_reply_t *reply = _ze_admin_space_reply_list_value(next);\n        z_query_reply_options_t opt;\n        z_query_reply_options_default(&opt);\n        z_owned_encoding_t encoding;\n        if (z_encoding_clone(&encoding, z_encoding_application_json()) == _Z_RES_OK) {\n            opt.encoding = z_encoding_move(&encoding);\n            z_result_t res = z_query_reply(query, z_keyexpr_loan(&reply->ke), z_bytes_move(&reply->payload), &opt);\n            if (res != _Z_RES_OK) {\n                z_view_string_t keystr;\n                if (z_keyexpr_as_view_string(z_keyexpr_loan(&reply->ke), &keystr) == _Z_RES_OK) {\n                    _Z_ERROR(\"Failed to reply to admin space query on key expression: %.*s\",\n                             (int)z_string_len(z_view_string_loan(&keystr)),\n                             z_string_data(z_view_string_loan(&keystr)));\n                } else {\n                    _Z_ERROR(\"Failed to reply to admin space query\");\n                }\n            }\n        } else {\n            _Z_ERROR(\"Failed to clone JSON encoding for admin space query reply\");\n            break;\n        }\n        next = _ze_admin_space_reply_list_next(next);\n    }\n}\n\nstatic void _ze_admin_space_query_handler_impl(z_loaned_query_t *query, void *ctx, bool include_pico,\n                                               bool include_connectivity_session) {\n    _z_session_weak_t *session_weak = (_z_session_weak_t *)ctx;\n\n    _z_session_rc_t session_rc = _z_session_weak_upgrade_if_open(session_weak);\n    if (_Z_RC_IS_NULL(&session_rc)) {\n        _Z_ERROR(\"Dropped admin space query - session closed\");\n        return;\n    }\n\n    _z_session_t *session = _Z_RC_IN_VAL(&session_rc);\n    _ze_admin_space_reply_list_t *replies = _ze_admin_space_reply_list_new();\n\n    if (include_pico) {\n        _ze_admin_space_query_handle_pico(query, session, &replies);\n    }\n#if Z_FEATURE_CONNECTIVITY == 1\n    if (include_connectivity_session) {\n        _ze_admin_space_query_handle_connectivity_session(query, session, &replies);\n    }\n#else\n    _ZP_UNUSED(include_connectivity_session);\n#endif\n\n    _ze_admin_space_query_reply_all(query, &replies);\n    _ze_admin_space_reply_list_free(&replies);\n    _z_session_rc_drop(&session_rc);\n}\n\nstatic void _ze_admin_space_pico_query_handler(z_loaned_query_t *query, void *ctx) {\n    _ze_admin_space_query_handler_impl(query, ctx, true, false);\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic void _ze_admin_space_session_query_handler(z_loaned_query_t *query, void *ctx) {\n    _ze_admin_space_query_handler_impl(query, ctx, false, true);\n}\n#endif\n\nstatic void _ze_admin_space_query_dropper(void *ctx) {\n    _z_session_weak_t *session_weak = (_z_session_weak_t *)ctx;\n    _z_session_weak_drop(session_weak);\n    z_free(session_weak);\n}\n\nstatic z_result_t _ze_admin_space_undeclare_queryable(const z_loaned_session_t *zs, uint32_t queryable_id) {\n    if (queryable_id == 0) {\n        return _Z_RES_OK;\n    }\n\n    _z_queryable_t queryable = {\n        ._entity_id = queryable_id,\n        ._zn = _z_session_rc_clone_as_weak(zs),\n    };\n    if (_Z_RC_IS_NULL(&queryable._zn)) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    z_result_t ret = _z_undeclare_queryable(&queryable);\n    _z_queryable_clear(&queryable);\n    return ret;\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic z_result_t _ze_admin_space_declare_session_queryable(const z_loaned_session_t *zs, uint32_t *out_queryable_id,\n                                                            const z_loaned_keyexpr_t *ke, void *ctx) {\n    z_owned_closure_query_t callback;\n    z_result_t ret =\n        z_closure_query(&callback, _ze_admin_space_session_query_handler, _ze_admin_space_query_dropper, ctx);\n    if (ret != _Z_RES_OK) {\n        _ze_admin_space_query_dropper(ctx);\n        return ret;\n    }\n\n    _z_closure_query_t closure = callback._val;\n    z_internal_closure_query_null(&callback);\n\n    return _z_register_queryable(out_queryable_id, zs, ke, _Z_QUERYABLE_COMPLETE_DEFAULT, closure.call, closure.drop,\n                                 closure.context, Z_LOCALITY_SESSION_LOCAL, NULL);\n}\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_PUBLICATION == 1\ntypedef struct {\n    _z_session_weak_t _session;\n} _ze_admin_space_connectivity_listener_ctx_t;\n\nstatic void _ze_admin_space_connectivity_listener_ctx_drop(void *ctx) {\n    _ze_admin_space_connectivity_listener_ctx_t *listener_ctx = (_ze_admin_space_connectivity_listener_ctx_t *)ctx;\n    if (listener_ctx != NULL) {\n        _z_session_weak_drop(&listener_ctx->_session);\n        z_free(listener_ctx);\n    }\n}\n\nstatic _ze_admin_space_connectivity_listener_ctx_t *_ze_admin_space_connectivity_listener_ctx_new(\n    const z_loaned_session_t *zs) {\n    _ze_admin_space_connectivity_listener_ctx_t *ctx =\n        (_ze_admin_space_connectivity_listener_ctx_t *)z_malloc(sizeof(_ze_admin_space_connectivity_listener_ctx_t));\n    if (ctx == NULL) {\n        return NULL;\n    }\n\n    ctx->_session = _z_session_rc_clone_as_weak(zs);\n    if (_Z_RC_IS_NULL(&ctx->_session)) {\n        z_free(ctx);\n        return NULL;\n    }\n    return ctx;\n}\n\nstatic z_result_t _ze_admin_space_undeclare_transport_listener(z_loaned_session_t *zs, size_t listener_id) {\n    if (listener_id == 0) {\n        return _Z_RES_OK;\n    }\n\n    z_owned_transport_events_listener_t listener;\n    listener._val = (_z_transport_events_listener_t){0};\n    listener._val._id = listener_id;\n    listener._val._session = _z_session_rc_clone_as_weak(zs);\n    if (_Z_RC_IS_NULL(&listener._val._session)) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    return z_undeclare_transport_events_listener(z_transport_events_listener_move(&listener));\n}\n\nstatic z_result_t _ze_admin_space_undeclare_link_listener(z_loaned_session_t *zs, size_t listener_id) {\n    if (listener_id == 0) {\n        return _Z_RES_OK;\n    }\n\n    z_owned_link_events_listener_t listener;\n    listener._val = (_z_link_events_listener_t){0};\n    listener._val._id = listener_id;\n    listener._val._session = _z_session_rc_clone_as_weak(zs);\n    if (_Z_RC_IS_NULL(&listener._val._session)) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    return z_undeclare_link_events_listener(z_link_events_listener_move(&listener));\n}\n\nstatic inline void _ze_admin_space_transport_listener_handle_clear(z_owned_transport_events_listener_t *listener) {\n    _z_session_weak_drop(&listener->_val._session);\n    _z_sync_group_drop(&listener->_val._callback_drop_sync_group);\n    listener->_val = (_z_transport_events_listener_t){0};\n}\n\nstatic inline void _ze_admin_space_link_listener_handle_clear(z_owned_link_events_listener_t *listener) {\n    _z_session_weak_drop(&listener->_val._session);\n    _z_sync_group_drop(&listener->_val._callback_drop_sync_group);\n    listener->_val = (_z_link_events_listener_t){0};\n}\n\nstatic z_result_t _ze_admin_space_put_session_local_json(_z_session_t *session, const z_loaned_keyexpr_t *ke,\n                                                         z_owned_bytes_t *payload) {\n    z_owned_encoding_t encoding;\n    z_result_t ret = z_encoding_clone(&encoding, z_encoding_application_json());\n    if (ret != _Z_RES_OK) {\n        z_bytes_drop(z_bytes_move(payload));\n        return ret;\n    }\n\n    ret = _z_write(session, ke, &payload->_val, &encoding._val, Z_SAMPLE_KIND_PUT,\n                   z_internal_congestion_control_default_push(), Z_PRIORITY_DEFAULT, false, NULL, NULL,\n                   Z_RELIABILITY_DEFAULT, NULL, Z_LOCALITY_SESSION_LOCAL);\n\n    z_encoding_drop(z_encoding_move(&encoding));\n    z_bytes_drop(z_bytes_move(payload));\n    return ret;\n}\n\nstatic z_result_t _ze_admin_space_delete_session_local(_z_session_t *session, const z_loaned_keyexpr_t *ke) {\n    return _z_write(session, ke, NULL, NULL, Z_SAMPLE_KIND_DELETE, z_internal_congestion_control_default_push(),\n                    Z_PRIORITY_DEFAULT, false, NULL, NULL, Z_RELIABILITY_DEFAULT, NULL, Z_LOCALITY_SESSION_LOCAL);\n}\n\nstatic void _ze_admin_space_publish_transport_event(z_loaned_transport_event_t *event, void *ctx) {\n    _ze_admin_space_connectivity_listener_ctx_t *listener_ctx = (_ze_admin_space_connectivity_listener_ctx_t *)ctx;\n    if (event == NULL || listener_ctx == NULL) {\n        return;\n    }\n\n    _z_session_rc_t session_rc = _z_session_weak_upgrade_if_open(&listener_ctx->_session);\n    if (_Z_RC_IS_NULL(&session_rc)) {\n        return;\n    }\n\n    const z_loaned_transport_t *transport = z_transport_event_transport(event);\n    if (transport == NULL || z_transport_is_multicast(transport)) {\n        _z_session_rc_drop(&session_rc);\n        return;\n    }\n\n    _z_session_t *session = _Z_RC_IN_VAL(&session_rc);\n    z_id_t peer_zid = z_transport_zid(transport);\n\n    z_owned_keyexpr_t ke;\n    z_result_t ret = _ze_admin_space_session_transport_ke(&ke, &session->_local_zid, &peer_zid);\n    if (ret != _Z_RES_OK) {\n        _z_session_rc_drop(&session_rc);\n        return;\n    }\n\n    if (z_transport_event_kind(event) == Z_SAMPLE_KIND_PUT) {\n        z_owned_bytes_t payload;\n        ret = _ze_admin_space_encode_connectivity_transport_payload(&payload, &peer_zid, z_transport_whatami(transport),\n                                                                    z_transport_is_qos(transport),\n                                                                    z_transport_is_shm(transport));\n        if (ret == _Z_RES_OK) {\n            ret = _ze_admin_space_put_session_local_json(session, z_keyexpr_loan(&ke), &payload);\n        }\n    } else if (z_transport_event_kind(event) == Z_SAMPLE_KIND_DELETE) {\n        ret = _ze_admin_space_delete_session_local(session, z_keyexpr_loan(&ke));\n    } else {\n        ret = _Z_RES_OK;\n    }\n\n    if (ret != _Z_RES_OK) {\n        _Z_WARN(\"Failed to publish RFC connectivity transport event: %d\", ret);\n    }\n\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n    _z_session_rc_drop(&session_rc);\n}\n\nstatic void _ze_admin_space_publish_link_event(z_loaned_link_event_t *event, void *ctx) {\n    _ze_admin_space_connectivity_listener_ctx_t *listener_ctx = (_ze_admin_space_connectivity_listener_ctx_t *)ctx;\n    if (event == NULL || listener_ctx == NULL) {\n        return;\n    }\n\n    _z_session_rc_t session_rc = _z_session_weak_upgrade_if_open(&listener_ctx->_session);\n    if (_Z_RC_IS_NULL(&session_rc)) {\n        return;\n    }\n    _z_session_t *session = _Z_RC_IN_VAL(&session_rc);\n\n    _z_session_transport_mutex_lock(session);\n    bool is_unicast_transport = session->_tp._type == _Z_TRANSPORT_UNICAST_TYPE;\n    _z_session_transport_mutex_unlock(session);\n    if (!is_unicast_transport) {\n        _z_session_rc_drop(&session_rc);\n        return;\n    }\n\n    const z_loaned_link_t *link = z_link_event_link(event);\n    if (link == NULL) {\n        _z_session_rc_drop(&session_rc);\n        return;\n    }\n    z_id_t peer_zid = z_link_zid(link);\n\n    z_owned_keyexpr_t ke;\n    z_result_t ret = _ze_admin_space_session_link_ke(&ke, &session->_local_zid, &peer_zid, &peer_zid);\n    if (ret != _Z_RES_OK) {\n        _z_session_rc_drop(&session_rc);\n        return;\n    }\n\n    if (z_link_event_kind(event) == Z_SAMPLE_KIND_PUT) {\n        z_owned_string_t src;\n        z_owned_string_t dst;\n        z_internal_string_null(&src);\n        z_internal_string_null(&dst);\n\n        ret = z_link_src(link, &src);\n        if (ret == _Z_RES_OK) {\n            ret = z_link_dst(link, &dst);\n        }\n        if (ret == _Z_RES_OK) {\n            z_owned_bytes_t payload;\n            ret = _ze_admin_space_encode_connectivity_link_payload(&payload, z_string_loan(&src), z_string_loan(&dst),\n                                                                   z_link_mtu(link), z_link_is_streamed(link),\n                                                                   z_link_is_reliable(link));\n            if (ret == _Z_RES_OK) {\n                ret = _ze_admin_space_put_session_local_json(session, z_keyexpr_loan(&ke), &payload);\n            }\n        }\n\n        z_string_drop(z_string_move(&src));\n        z_string_drop(z_string_move(&dst));\n    } else if (z_link_event_kind(event) == Z_SAMPLE_KIND_DELETE) {\n        ret = _ze_admin_space_delete_session_local(session, z_keyexpr_loan(&ke));\n    } else {\n        ret = _Z_RES_OK;\n    }\n\n    if (ret != _Z_RES_OK) {\n        _Z_WARN(\"Failed to publish RFC connectivity link event: %d\", ret);\n    }\n\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n    _z_session_rc_drop(&session_rc);\n}\n#endif  // Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_PUBLICATION == 1\n\nz_result_t zp_start_admin_space(z_loaned_session_t *zs) {\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    z_id_t zid = z_info_zid(zs);\n    z_result_t ret = _Z_RES_OK;\n    _z_session_admin_space_mutex_lock(session);\n    if (session->_admin_space_queryable_id != 0) {\n        goto out;\n    }\n\n    _z_session_weak_t *pico_session_weak = _z_session_rc_clone_as_weak_ptr(zs);\n    if (_Z_RC_IS_NULL(pico_session_weak)) {\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto out;\n    }\n\n    z_owned_keyexpr_t ke;\n    ret = _ze_admin_space_pico_queryable_ke(&ke, &zid);\n    if (ret != _Z_RES_OK) {\n        _z_session_weak_drop(pico_session_weak);\n        z_free(pico_session_weak);\n        goto out;\n    }\n\n    z_owned_closure_query_t callback;\n    ret = z_closure_query(&callback, _ze_admin_space_pico_query_handler, _ze_admin_space_query_dropper,\n                          pico_session_weak);\n    if (ret != _Z_RES_OK) {\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n        _z_session_weak_drop(pico_session_weak);\n        z_free(pico_session_weak);\n        goto out;\n    }\n\n    z_owned_queryable_t admin_space_queryable;\n    ret = z_declare_queryable(zs, &admin_space_queryable, z_keyexpr_loan(&ke), z_closure_query_move(&callback), NULL);\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n    if (ret != _Z_RES_OK) {\n        goto out;\n    }\n\n    session->_admin_space_queryable_id = admin_space_queryable._val._entity_id;\n    _z_queryable_clear(&admin_space_queryable._val);\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    _z_session_weak_t *session_session_weak = _z_session_rc_clone_as_weak_ptr(zs);\n    if (_Z_RC_IS_NULL(session_session_weak)) {\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto err_queryable;\n    }\n\n    ret = _ze_admin_space_session_queryable_ke(&ke, &zid);\n    if (ret != _Z_RES_OK) {\n        _z_session_weak_drop(session_session_weak);\n        z_free(session_session_weak);\n        goto err_queryable;\n    }\n\n    ret = _ze_admin_space_declare_session_queryable(zs, &session->_admin_space_session_queryable_id,\n                                                    z_keyexpr_loan(&ke), session_session_weak);\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n    if (ret != _Z_RES_OK) {\n        goto err_queryable;\n    }\n\n#if Z_FEATURE_PUBLICATION == 1\n    session->_admin_space_transport_listener_id = 0;\n    session->_admin_space_link_listener_id = 0;\n\n    _ze_admin_space_connectivity_listener_ctx_t *transport_ctx = _ze_admin_space_connectivity_listener_ctx_new(zs);\n    if (transport_ctx == NULL) {\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto err_session_queryable;\n    }\n\n    z_owned_closure_transport_event_t transport_callback;\n    ret = z_closure_transport_event(&transport_callback, _ze_admin_space_publish_transport_event,\n                                    _ze_admin_space_connectivity_listener_ctx_drop, transport_ctx);\n    if (ret != _Z_RES_OK) {\n        _ze_admin_space_connectivity_listener_ctx_drop(transport_ctx);\n        goto err_session_queryable;\n    }\n\n    z_owned_transport_events_listener_t transport_listener;\n    z_transport_events_listener_options_t transport_opts;\n    z_transport_events_listener_options_default(&transport_opts);\n    ret = z_declare_transport_events_listener(zs, &transport_listener,\n                                              z_closure_transport_event_move(&transport_callback), &transport_opts);\n    if (ret != _Z_RES_OK) {\n        goto err_session_queryable;\n    }\n    session->_admin_space_transport_listener_id = transport_listener._val._id;\n    _ze_admin_space_transport_listener_handle_clear(&transport_listener);\n\n    _ze_admin_space_connectivity_listener_ctx_t *link_ctx = _ze_admin_space_connectivity_listener_ctx_new(zs);\n    if (link_ctx == NULL) {\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto err_transport_listener;\n    }\n\n    z_owned_closure_link_event_t link_callback;\n    ret = z_closure_link_event(&link_callback, _ze_admin_space_publish_link_event,\n                               _ze_admin_space_connectivity_listener_ctx_drop, link_ctx);\n    if (ret != _Z_RES_OK) {\n        _ze_admin_space_connectivity_listener_ctx_drop(link_ctx);\n        goto err_transport_listener;\n    }\n\n    z_owned_link_events_listener_t link_listener;\n    z_link_events_listener_options_t link_opts;\n    z_link_events_listener_options_default(&link_opts);\n    ret = z_declare_link_events_listener(zs, &link_listener, z_closure_link_event_move(&link_callback), &link_opts);\n    if (ret != _Z_RES_OK) {\n        goto err_transport_listener;\n    }\n    session->_admin_space_link_listener_id = link_listener._val._id;\n    _ze_admin_space_link_listener_handle_clear(&link_listener);\n#endif\n#endif\n\n    ret = _Z_RES_OK;\n    goto out;\n\n#if Z_FEATURE_CONNECTIVITY == 1\n#if Z_FEATURE_PUBLICATION == 1\nerr_transport_listener: {\n    z_result_t undeclare_transport_listener_ret =\n        _ze_admin_space_undeclare_transport_listener(zs, session->_admin_space_transport_listener_id);\n    if (undeclare_transport_listener_ret == _Z_RES_OK) {\n        session->_admin_space_transport_listener_id = 0;\n    } else if (ret == _Z_RES_OK) {\n        ret = undeclare_transport_listener_ret;\n    }\n}\n#endif\n\nerr_session_queryable: {\n    z_result_t undeclare_queryable_ret =\n        _ze_admin_space_undeclare_queryable(zs, session->_admin_space_session_queryable_id);\n    if (undeclare_queryable_ret == _Z_RES_OK) {\n        session->_admin_space_session_queryable_id = 0;\n    } else if (ret == _Z_RES_OK) {\n        ret = undeclare_queryable_ret;\n    }\n}\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\nerr_queryable: {\n    z_result_t undeclare_queryable_ret = _ze_admin_space_undeclare_queryable(zs, session->_admin_space_queryable_id);\n    if (undeclare_queryable_ret == _Z_RES_OK) {\n        session->_admin_space_queryable_id = 0;\n    } else if (ret == _Z_RES_OK) {\n        ret = undeclare_queryable_ret;\n    }\n}\n#endif\nout:\n    _z_session_admin_space_mutex_unlock(session);\n    return ret;\n}\n\nz_result_t zp_stop_admin_space(z_loaned_session_t *zs) {\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    z_result_t ret = _Z_RES_OK;\n\n    _z_session_admin_space_mutex_lock(session);\n    uint32_t admin_space_queryable_id = session->_admin_space_queryable_id;\n#if Z_FEATURE_CONNECTIVITY == 1\n    uint32_t admin_space_session_queryable_id = session->_admin_space_session_queryable_id;\n#if Z_FEATURE_PUBLICATION == 1\n    size_t admin_space_transport_listener_id = session->_admin_space_transport_listener_id;\n    size_t admin_space_link_listener_id = session->_admin_space_link_listener_id;\n\n    if (admin_space_queryable_id == 0 && admin_space_session_queryable_id == 0 &&\n        admin_space_transport_listener_id == 0 && admin_space_link_listener_id == 0) {\n        goto out;\n    }\n#else\n    if (admin_space_queryable_id == 0 && admin_space_session_queryable_id == 0) {\n        goto out;\n    }\n#endif\n#else\n    if (admin_space_queryable_id == 0) {\n        goto out;\n    }\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_PUBLICATION == 1\n    if (admin_space_transport_listener_id != 0) {\n        z_result_t listener_ret = _ze_admin_space_undeclare_transport_listener(zs, admin_space_transport_listener_id);\n        if (listener_ret == _Z_RES_OK) {\n            session->_admin_space_transport_listener_id = 0;\n        } else if (ret == _Z_RES_OK) {\n            ret = listener_ret;\n        }\n    }\n\n    if (admin_space_link_listener_id != 0) {\n        z_result_t listener_ret = _ze_admin_space_undeclare_link_listener(zs, admin_space_link_listener_id);\n        if (listener_ret == _Z_RES_OK) {\n            session->_admin_space_link_listener_id = 0;\n        } else if (ret == _Z_RES_OK) {\n            ret = listener_ret;\n        }\n    }\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    if (admin_space_session_queryable_id != 0) {\n        z_result_t queryable_ret = _ze_admin_space_undeclare_queryable(zs, admin_space_session_queryable_id);\n        if (queryable_ret == _Z_RES_OK) {\n            session->_admin_space_session_queryable_id = 0;\n        } else if (ret == _Z_RES_OK) {\n            ret = queryable_ret;\n        }\n    }\n#endif\n\n    if (admin_space_queryable_id != 0) {\n        z_result_t queryable_ret = _ze_admin_space_undeclare_queryable(zs, admin_space_queryable_id);\n        if (queryable_ret == _Z_RES_OK) {\n            session->_admin_space_queryable_id = 0;\n        } else if (ret == _Z_RES_OK) {\n            ret = queryable_ret;\n        }\n    }\n\nout:\n    _z_session_admin_space_mutex_unlock(session);\n    return ret;\n}\n\n#endif  // Z_FEATURE_ADMIN_SPACE == 1\n"
  },
  {
    "path": "src/api/advanced_publisher.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/api/advanced_publisher.h\"\n\n#include <stdio.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/serialization.h\"\n#include \"zenoh-pico/collections/atomic.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n\n// Space for 10 digits + NULL\n#define ZE_ADVANCED_PUBLISHER_UINT32_STR_BUF_LEN 11\n\nstatic void _ze_advanced_publisher_state_init(_ze_advanced_publisher_state_t *state) {\n    state->_heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE;\n    state->_last_published_sn = 0;\n    z_internal_publisher_null(&state->_publisher);\n    state->_state_publisher_task_handle = _z_fut_handle_null();\n    state->_zn = _z_session_weak_null();\n    _z_atomic_size_init(&state->_seqnumber, 0);\n}\n\nstatic bool _ze_advanced_publisher_state_check(const _ze_advanced_publisher_state_t *state) {\n    return state->_heartbeat_mode == ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE ||\n           z_internal_publisher_check(&state->_publisher);\n}\n\nvoid _ze_advanced_publisher_state_clear(_ze_advanced_publisher_state_t *state) {\n    if (state->_heartbeat_mode != ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE &&\n        !_z_fut_handle_is_null(state->_state_publisher_task_handle)) {\n        _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&state->_zn);\n        if (!_Z_RC_IS_NULL(&sess_rc)) {\n            _z_runtime_cancel_fut(&_Z_RC_IN_VAL(&sess_rc)->_runtime, &state->_state_publisher_task_handle);\n            _z_session_rc_drop(&sess_rc);\n        }\n        state->_state_publisher_task_handle = _z_fut_handle_null();\n        z_undeclare_publisher(z_publisher_move(&state->_publisher));\n    }\n    _z_session_weak_drop(&state->_zn);\n    state->_heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE;\n    state->_last_published_sn = 0;\n}\n\nbool _ze_advanced_publisher_check(const _ze_advanced_publisher_t *pub) {\n    return z_internal_publisher_check(&pub->_publisher) &&\n           (!pub->_has_liveliness || z_internal_liveliness_token_check(&pub->_liveliness)) &&\n           (_Z_RC_IS_NULL(&pub->_state) || _ze_advanced_publisher_state_check(_Z_RC_IN_VAL(&pub->_state)));\n}\n\n_ze_advanced_publisher_t _ze_advanced_publisher_null(void) {\n    _ze_advanced_publisher_t publisher = {0};\n    z_internal_publisher_null(&publisher._publisher);\n    z_internal_liveliness_token_null(&publisher._liveliness);\n    publisher._state = _ze_advanced_publisher_state_rc_null();\n    return publisher;\n}\n\nz_result_t _ze_undeclare_advanced_publisher_clear(_ze_advanced_publisher_t *pub) {\n    if (pub == NULL || !_ze_advanced_publisher_check(pub)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n\n    z_result_t ret = z_undeclare_publisher(z_publisher_move(&pub->_publisher));\n\n    if (pub->_has_liveliness) {\n        z_liveliness_token_drop(z_liveliness_token_move(&pub->_liveliness));\n        pub->_has_liveliness = false;\n    }\n\n    if (!_Z_RC_IS_NULL(&pub->_state)) {\n        _ze_advanced_publisher_state_rc_drop(&pub->_state);\n    }\n\n    if (pub->_cache != NULL) {\n        _ze_advanced_cache_free(&pub->_cache);\n    }\n    *pub = _ze_advanced_publisher_null();\n    return ret;\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX(ze, _ze_advanced_publisher_t, advanced_publisher,\n                                                     _ze_advanced_publisher_check, _ze_advanced_publisher_null,\n                                                     _ze_undeclare_advanced_publisher_clear)\n\nvoid ze_advanced_publisher_cache_options_default(ze_advanced_publisher_cache_options_t *options) {\n    options->is_enabled = true;\n    options->max_samples = 1;\n    options->congestion_control = z_internal_congestion_control_default_push();\n    options->priority = z_priority_default();\n    options->is_express = false;\n    options->_liveliness = false;\n}\n\nvoid ze_advanced_publisher_sample_miss_detection_options_default(\n    ze_advanced_publisher_sample_miss_detection_options_t *options) {\n    options->is_enabled = true;\n    options->heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_DEFAULT;\n    options->heartbeat_period_ms = 0;\n}\n\nvoid ze_advanced_publisher_options_default(ze_advanced_publisher_options_t *options) {\n    z_publisher_options_default(&options->publisher_options);\n    ze_advanced_publisher_cache_options_default(&options->cache);\n    options->cache.is_enabled = false;\n    ze_advanced_publisher_sample_miss_detection_options_default(&options->sample_miss_detection);\n    options->sample_miss_detection.is_enabled = false;\n    options->publisher_detection = false;\n    options->publisher_detection_metadata = NULL;\n}\n\nvoid ze_advanced_publisher_put_options_default(ze_advanced_publisher_put_options_t *options) {\n    z_publisher_put_options_default(&options->put_options);\n}\n\nvoid ze_advanced_publisher_delete_options_default(ze_advanced_publisher_delete_options_t *options) {\n    z_publisher_delete_options_default(&options->delete_options);\n}\n\n// suffix = KE_ADV_PREFIX / KE_PUB / ZID / [ EID | KE_UHLC ] / [ meta | KE_EMPTY]\nstatic z_result_t _ze_advanced_publisher_ke_suffix(z_owned_keyexpr_t *suffix, const z_entity_global_id_t *id,\n                                                   const _ze_advanced_publisher_sequencing_t sequencing,\n                                                   const z_loaned_keyexpr_t *metadata) {\n    z_internal_keyexpr_null(suffix);\n    _Z_RETURN_IF_ERR(_Z_KEYEXPR_APPEND_STR_ARRAY(suffix, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_PUB));\n\n    z_id_t zid = z_entity_global_id_zid(id);\n    z_owned_string_t zid_str;\n    _Z_CLEAN_RETURN_IF_ERR(z_id_to_string(&zid, &zid_str), z_keyexpr_drop(z_keyexpr_move(suffix)));\n\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_keyexpr_append_substr(suffix, z_string_data(z_string_loan(&zid_str)), z_string_len(z_string_loan(&zid_str))),\n        z_string_drop(z_string_move(&zid_str));\n        z_keyexpr_drop(z_keyexpr_move(suffix)));\n    z_string_drop(z_string_move(&zid_str));\n\n    if (sequencing == _ZE_ADVANCED_PUBLISHER_SEQUENCING_SEQUENCE_NUMBER) {\n        char buffer[ZE_ADVANCED_PUBLISHER_UINT32_STR_BUF_LEN];\n        uint32_t eid = z_entity_global_id_eid(id);\n        snprintf(buffer, sizeof(buffer), \"%u\", eid);\n        _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(suffix, buffer), z_keyexpr_drop(z_keyexpr_move(suffix)));\n    } else {\n        _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(suffix, _Z_KEYEXPR_UHLC), z_keyexpr_drop(z_keyexpr_move(suffix)));\n    }\n\n    if (metadata != NULL) {\n        _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_suffix(suffix, metadata), z_keyexpr_drop(z_keyexpr_move(suffix)));\n    } else {\n        _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(suffix, _Z_KEYEXPR_EMPTY), z_keyexpr_drop(z_keyexpr_move(suffix)));\n    }\n    return _Z_RES_OK;\n}\n\nstatic _z_fut_fn_result_t _ze_advanced_publisher_heartbeat_handler(void *ctx, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n    _ze_advanced_publisher_state_weak_t *state_weak_rc = (_ze_advanced_publisher_state_weak_t *)ctx;\n    _ze_advanced_publisher_state_rc_t state_rc = _ze_advanced_publisher_state_weak_upgrade(state_weak_rc);\n\n    if (_Z_RC_IS_NULL(&state_rc)) {\n        // State has been dropped, nothing to do\n        return _z_fut_fn_result_ready();\n    }\n    unsigned long heartbeat_period_ms = state_rc._val->_heartbeat_period_ms;\n    _ze_advanced_publisher_state_t *state = _Z_RC_IN_VAL(&state_rc);\n\n    bool publish = false;\n    uint32_t next_seq = (uint32_t)_z_atomic_size_load(&state->_seqnumber, _z_memory_order_relaxed);\n\n    switch (state->_heartbeat_mode) {\n        case ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_PERIODIC:\n            publish = true;\n            break;\n        case ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_SPORADIC:\n            // TODO: This doesn't account for sn wraparound\n            publish = (next_seq > state->_last_published_sn) ? true : false;\n            break;\n        default:\n            _Z_WARN(\"Failed to publish heartbeat, invalid mode: %d\", state->_heartbeat_mode);\n            return _z_fut_fn_result_ready();\n    };\n\n    if (publish) {\n        z_owned_bytes_t payload;\n        z_bytes_empty(&payload);\n        ze_owned_serializer_t serializer;\n        ze_serializer_empty(&serializer);\n        ze_serializer_serialize_uint32(ze_serializer_loan_mut(&serializer), _z_seqnumber_prev(next_seq));\n        ze_serializer_finish(ze_serializer_move(&serializer), &payload);\n        z_result_t res = z_publisher_put(z_publisher_loan(&state->_publisher), z_bytes_move(&payload), NULL);\n        if (res != _Z_RES_OK) {\n            _Z_WARN(\"Failed to publish heartbeat: %d\", res);\n        }\n        state->_last_published_sn = next_seq;\n    }\n\n    _ze_advanced_publisher_state_rc_drop(&state_rc);\n    return _z_fut_fn_result_wake_up_after(heartbeat_period_ms);\n}\n\nstatic void _ze_advanced_publisher_heartbeat_dropper(void *ctx) {\n    _ze_advanced_publisher_state_weak_t *state_rc = (_ze_advanced_publisher_state_weak_t *)ctx;\n    _ze_advanced_publisher_state_weak_drop(state_rc);\n    z_free(state_rc);\n}\n\nz_result_t ze_declare_advanced_publisher(const z_loaned_session_t *zs, ze_owned_advanced_publisher_t *pub,\n                                         const z_loaned_keyexpr_t *keyexpr,\n                                         const ze_advanced_publisher_options_t *options) {\n    pub->_val = _ze_advanced_publisher_null();\n\n    // Set options\n    ze_advanced_publisher_options_t opt;\n    ze_advanced_publisher_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    // Validate options early\n    if (opt.sample_miss_detection.is_enabled &&\n        opt.sample_miss_detection.heartbeat_mode != ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE) {\n        if (opt.sample_miss_detection.heartbeat_period_ms == 0) {\n            _Z_ERROR(\"Failed to create advanced publisher: heatbeat_period_ms must be > 0\");\n            return _Z_ERR_INVALID;\n        }\n    }\n\n    _Z_RETURN_IF_ERR(z_declare_publisher(zs, &pub->_val._publisher, keyexpr, &opt.publisher_options));\n\n    z_entity_global_id_t id = z_publisher_id(z_publisher_loan(&pub->_val._publisher));\n\n    if (opt.sample_miss_detection.is_enabled) {\n        pub->_val._sequencing = _ZE_ADVANCED_PUBLISHER_SEQUENCING_SEQUENCE_NUMBER;\n\n        _ze_advanced_publisher_state_t *state = z_malloc(sizeof(_ze_advanced_publisher_state_t));\n        if (state == NULL) {\n            z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        _ze_advanced_publisher_state_init(state);\n\n        pub->_val._state = _ze_advanced_publisher_state_rc_new(state);\n        if (_Z_RC_IS_NULL(&pub->_val._state)) {\n            _ze_advanced_publisher_state_clear(state);\n            z_free(state);\n            z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n    } else if (opt.cache.is_enabled) {\n        pub->_val._sequencing = _ZE_ADVANCED_PUBLISHER_SEQUENCING_TIMESTAMP;\n    } else {\n        pub->_val._sequencing = _ZE_ADVANCED_PUBLISHER_SEQUENCING_NONE;\n    }\n\n    z_owned_keyexpr_t suffix;\n    _Z_CLEAN_RETURN_IF_ERR(\n        _ze_advanced_publisher_ke_suffix(&suffix, &id, pub->_val._sequencing, opt.publisher_detection_metadata),\n        _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n        z_publisher_drop(z_publisher_move(&pub->_val._publisher)));\n\n    if (opt.cache.is_enabled) {\n        _ze_advanced_cache_t *cache = _ze_advanced_cache_new(zs, keyexpr, z_keyexpr_loan(&suffix), opt.cache);\n\n        if (cache == NULL) {\n            _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n            z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n            z_keyexpr_drop(z_keyexpr_move(&suffix));\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n        pub->_val._cache = cache;\n    }\n\n    // Create joined key expression only if needed for liveliness token or state publisher\n    if (opt.publisher_detection ||\n        (opt.sample_miss_detection.is_enabled &&\n         opt.sample_miss_detection.heartbeat_mode != ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE)) {\n        z_owned_keyexpr_t ke;\n        _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_join(&ke, keyexpr, z_keyexpr_loan(&suffix)),\n                               _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n                               z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n                               z_keyexpr_drop(z_keyexpr_move(&suffix)); _ze_advanced_cache_free(&pub->_val._cache));\n\n        // Declare liveliness token on keyexpr/suffix\n        if (opt.publisher_detection) {\n            _Z_CLEAN_RETURN_IF_ERR(z_liveliness_declare_token(zs, &pub->_val._liveliness, z_keyexpr_loan(&ke), NULL),\n                                   z_keyexpr_drop(z_keyexpr_move(&ke));\n                                   _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n                                   z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n                                   z_keyexpr_drop(z_keyexpr_move(&suffix)); _ze_advanced_cache_free(&pub->_val._cache));\n            pub->_val._has_liveliness = true;\n        }\n\n        // Declare state publisher on keyexpr/suffix\n        if (opt.sample_miss_detection.is_enabled &&\n            opt.sample_miss_detection.heartbeat_mode != ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE) {\n            _ze_advanced_publisher_state_t *state = _Z_RC_IN_VAL(&pub->_val._state);\n            state->_heartbeat_period_ms = opt.sample_miss_detection.heartbeat_period_ms;\n            state->_heartbeat_mode = opt.sample_miss_detection.heartbeat_mode;\n            state->_zn = _z_session_rc_clone_as_weak(zs);\n            state->_last_published_sn = (uint32_t)_z_atomic_size_load(&state->_seqnumber, _z_memory_order_relaxed);\n\n            z_publisher_options_t heatbeat_opts;\n            z_publisher_options_default(&heatbeat_opts);\n            if (opt.sample_miss_detection.heartbeat_mode == ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_SPORADIC) {\n                heatbeat_opts.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n            }\n            _Z_CLEAN_RETURN_IF_ERR(z_declare_publisher(zs, &state->_publisher, z_keyexpr_loan(&ke), &heatbeat_opts),\n                                   z_keyexpr_drop(z_keyexpr_move(&ke));\n                                   _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n                                   z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n                                   z_liveliness_token_drop(z_liveliness_token_move(&pub->_val._liveliness));\n                                   z_keyexpr_drop(z_keyexpr_move(&suffix)); _ze_advanced_cache_free(&pub->_val._cache));\n\n            _ze_advanced_publisher_state_weak_t *ctx =\n                _ze_advanced_publisher_state_rc_clone_as_weak_ptr(&pub->_val._state);\n            if (_Z_RC_IS_NULL(ctx)) {\n                z_keyexpr_drop(z_keyexpr_move(&ke));\n                _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n                z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n                z_liveliness_token_drop(z_liveliness_token_move(&pub->_val._liveliness));\n                z_keyexpr_drop(z_keyexpr_move(&suffix));\n                _ze_advanced_cache_free(&pub->_val._cache);\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n            _z_fut_t f = _z_fut_null();\n            f._destroy_fn = _ze_advanced_publisher_heartbeat_dropper;\n            f._fut_fn = _ze_advanced_publisher_heartbeat_handler;\n            f._fut_arg = ctx;\n\n            state->_state_publisher_task_handle = _z_runtime_spawn(&_Z_RC_IN_VAL(zs)->_runtime, &f);\n            if (_z_fut_handle_is_null(state->_state_publisher_task_handle)) {\n                z_keyexpr_drop(z_keyexpr_move(&ke));\n                _ze_advanced_publisher_state_rc_drop(&pub->_val._state);\n                z_publisher_drop(z_publisher_move(&pub->_val._publisher));\n                z_liveliness_token_drop(z_liveliness_token_move(&pub->_val._liveliness));\n                z_keyexpr_drop(z_keyexpr_move(&suffix));\n                _ze_advanced_cache_free(&pub->_val._cache);\n                return _Z_ERR_FAILED_TO_SPAWN_TASK;\n            }\n        }\n\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n    }\n\n    z_keyexpr_drop(z_keyexpr_move(&suffix));\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _ze_advanced_publisher_sequencing_options(const ze_loaned_advanced_publisher_t *pub,\n                                                            z_source_info_t *source_info, z_timestamp_t *timestamp) {\n    if (source_info == NULL || timestamp == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    const z_loaned_publisher_t *publisher = z_publisher_loan(&pub->_publisher);\n\n    // Set sequence number if required\n    if (pub->_sequencing == _ZE_ADVANCED_PUBLISHER_SEQUENCING_SEQUENCE_NUMBER) {\n        z_entity_global_id_t publisher_id = z_publisher_id(publisher);\n        uint32_t seqnumber =\n            (uint32_t)_z_atomic_size_fetch_add(&_Z_RC_IN_VAL(&pub->_state)->_seqnumber, 1, _z_memory_order_relaxed);\n        *source_info = z_source_info_new(&publisher_id, seqnumber);\n    }\n\n    // Set timestamp\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&publisher->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        _Z_CLEAN_RETURN_IF_ERR(z_timestamp_new(timestamp, &sess_rc), _z_session_rc_drop(&sess_rc));\n        _z_session_rc_drop(&sess_rc);\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t ze_undeclare_advanced_publisher(ze_moved_advanced_publisher_t *pub) {\n    return _ze_undeclare_advanced_publisher_clear(&pub->_this._val);\n}\n\nz_result_t ze_advanced_publisher_put(const ze_loaned_advanced_publisher_t *pub, z_moved_bytes_t *payload,\n                                     const ze_advanced_publisher_put_options_t *options) {\n    ze_advanced_publisher_put_options_t opt;\n    ze_advanced_publisher_put_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    z_timestamp_t timestamp = _z_timestamp_null();\n    z_source_info_t si = _z_source_info_null();\n    _Z_RETURN_IF_ERR(_ze_advanced_publisher_sequencing_options(pub, &si, &timestamp));\n    opt.put_options.timestamp = &timestamp;\n    opt.put_options.source_info = &si;\n    return _z_publisher_put_impl(z_publisher_loan(&pub->_publisher), payload, &opt.put_options, pub->_cache);\n}\n\nz_result_t ze_advanced_publisher_delete(const ze_loaned_advanced_publisher_t *pub,\n                                        const ze_advanced_publisher_delete_options_t *options) {\n    ze_advanced_publisher_delete_options_t opt;\n    ze_advanced_publisher_delete_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    z_timestamp_t timestamp = _z_timestamp_null();\n    z_source_info_t si = _z_source_info_null();\n    _Z_RETURN_IF_ERR(_ze_advanced_publisher_sequencing_options(pub, &si, &timestamp));\n    opt.delete_options.timestamp = &timestamp;\n    opt.delete_options.source_info = &si;\n    return _z_publisher_delete_impl(z_publisher_loan(&pub->_publisher), &opt.delete_options, pub->_cache);\n}\n\nconst z_loaned_keyexpr_t *ze_advanced_publisher_keyexpr(const ze_loaned_advanced_publisher_t *pub) {\n    return z_publisher_keyexpr(z_publisher_loan(&pub->_publisher));\n}\n\nz_entity_global_id_t ze_advanced_publisher_id(const ze_loaned_advanced_publisher_t *pub) {\n    return z_publisher_id(z_publisher_loan(&pub->_publisher));\n}\n\nz_result_t ze_advanced_publisher_get_matching_status(const ze_loaned_advanced_publisher_t *pub,\n                                                     z_matching_status_t *matching_status) {\n    return z_publisher_get_matching_status(z_publisher_loan(&pub->_publisher), matching_status);\n}\n\nz_result_t ze_advanced_publisher_declare_matching_listener(const ze_loaned_advanced_publisher_t *publisher,\n                                                           z_owned_matching_listener_t *matching_listener,\n                                                           z_moved_closure_matching_status_t *callback) {\n    return z_publisher_declare_matching_listener(z_publisher_loan(&publisher->_publisher), matching_listener, callback);\n}\n\nz_result_t ze_advanced_publisher_declare_background_matching_listener(const ze_loaned_advanced_publisher_t *publisher,\n                                                                      z_moved_closure_matching_status_t *callback) {\n    return z_publisher_declare_background_matching_listener(z_publisher_loan(&publisher->_publisher), callback);\n}\n\n#endif\n"
  },
  {
    "path": "src/api/advanced_subscriber.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/api/advanced_subscriber.h\"\n\n#include <ctype.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/serialization.h\"\n#include \"zenoh-pico/collections/seqnumber.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n#include \"zenoh-pico/utils/string.h\"\n#include \"zenoh-pico/utils/time_range.h\"\n#include \"zenoh-pico/utils/uuid.h\"\n\n#if Z_FEATURE_ADVANCED_SUBSCRIPTION == 1\n\n#define ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE 256\n\n// Space for 10 digits + NULL\n#define ZE_ADVANCED_SUBSCRIBER_UINT32_STR_BUF_LEN 11\n\nz_result_t _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(_ze_advanced_subscriber_state_t *state) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(z_mutex_lock(z_mutex_loan_mut(&state->_mutex)));\n#endif\n    if (state->_is_undeclaring) {\n#if Z_FEATURE_MULTI_THREAD == 1\n        z_mutex_unlock(z_mutex_loan_mut(&state->_mutex));\n#endif\n        return Z_ERR_CANCELLED;\n    }\n    return _Z_RES_OK;\n}\n\nvoid _ze_advanced_subscriber_state_unlock_mutex(_ze_advanced_subscriber_state_t *state) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_mutex_unlock(z_mutex_loan_mut(&state->_mutex));\n#endif\n}\n\nvoid _ze_sample_miss_listener_clear(_ze_sample_miss_listener_t *listener) {\n    _ze_advanced_subscriber_state_weak_drop(&listener->_statesref);\n    *listener = _ze_sample_miss_listener_null();\n}\n\nz_result_t _ze_sample_miss_listener_drop(_ze_sample_miss_listener_t *listener) {\n    if (listener == NULL) {\n        return _Z_ERR_INVALID;\n    }\n\n    _ze_advanced_subscriber_state_rc_t state_rc = _ze_advanced_subscriber_state_weak_upgrade(&listener->_statesref);\n    if (_Z_RC_IS_NULL(&state_rc)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _ze_advanced_subscriber_state_t *state = _Z_RC_IN_VAL(&state_rc);\n    z_result_t ret = _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(state);\n    if (ret != _Z_RES_OK) {\n        _ze_advanced_subscriber_state_rc_drop(&state_rc);\n        _ze_sample_miss_listener_clear(listener);\n        return ret == Z_ERR_CANCELLED ? _Z_RES_OK : ret;\n    }\n    _ze_closure_miss_intmap_remove(&state->_miss_handlers, listener->_id);\n    _ze_advanced_subscriber_state_unlock_mutex(state);\n    _ze_advanced_subscriber_state_rc_drop(&state_rc);\n    _ze_sample_miss_listener_clear(listener);\n    return _Z_RES_OK;\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX(ze, _ze_sample_miss_listener_t, sample_miss_listener,\n                                                     _ze_sample_miss_listener_check, _ze_sample_miss_listener_null,\n                                                     _ze_sample_miss_listener_drop)\n\nstatic z_result_t _ze_advanced_subscriber_sequenced_state_init(_ze_advanced_subscriber_sequenced_state_t *state,\n                                                               const _z_session_weak_t *zn,\n                                                               const z_loaned_keyexpr_t *keyexpr,\n                                                               const _z_entity_global_id_t *id) {\n    (void)(id);\n    state->_zn = _z_session_weak_clone(zn);\n    state->_has_last_delivered = false;\n    state->_last_delivered = 0;\n    state->_pending_queries = 0;\n    state->_periodic_query_handle = _z_fut_handle_null();\n    _z_uint32__z_sample_sortedmap_init(&state->_pending_samples);\n\n    z_id_t zid = z_entity_global_id_zid(id);\n    z_owned_string_t zid_str;\n    _Z_RETURN_IF_ERR(z_id_to_string(&zid, &zid_str));\n\n    char buffer[ZE_ADVANCED_SUBSCRIBER_UINT32_STR_BUF_LEN];\n    uint32_t eid = z_entity_global_id_eid(id);\n    snprintf(buffer, sizeof(buffer), \"%u\", eid);\n\n    // Initialize query_keyexpr to: keyexpr / _Z_KEYEXPR_ADV_PREFIX / _Z_KEYEXPR_STAR / ZID / EID / _Z_KEYEXPR_STARSTAR\n    z_internal_keyexpr_null(&state->_query_keyexpr);\n    _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_clone(&state->_query_keyexpr, keyexpr), z_string_drop(z_string_move(&zid_str)));\n    _Z_CLEAN_RETURN_IF_ERR(_Z_KEYEXPR_APPEND_STR_ARRAY(&state->_query_keyexpr, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_STAR),\n                           z_string_drop(z_string_move(&zid_str));\n                           z_keyexpr_drop(z_keyexpr_move(&state->_query_keyexpr)));\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_substr(&state->_query_keyexpr, z_string_data(z_string_loan(&zid_str)),\n                                                    z_string_len(z_string_loan(&zid_str))),\n                           z_string_drop(z_string_move(&zid_str));\n                           z_keyexpr_drop(z_keyexpr_move(&state->_query_keyexpr)));\n    z_string_drop(z_string_move(&zid_str));\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(&state->_query_keyexpr, buffer),\n                           z_keyexpr_drop(z_keyexpr_move(&state->_query_keyexpr)));\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(&state->_query_keyexpr, _Z_KEYEXPR_STARSTAR),\n                           z_keyexpr_drop(z_keyexpr_move(&state->_query_keyexpr)));\n\n    return _Z_RES_OK;\n}\n\nvoid _ze_advanced_subscriber_sequenced_state_clear(_ze_advanced_subscriber_sequenced_state_t *state) {\n    state->_has_last_delivered = false;\n    state->_last_delivered = 0;\n    state->_pending_queries = 0;\n\n    if (!_z_fut_handle_is_null(state->_periodic_query_handle)) {\n        _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&state->_zn);\n        if (!_Z_RC_IS_NULL(&sess_rc)) {\n            z_result_t res = _z_runtime_cancel_fut(&_Z_RC_IN_VAL(&sess_rc)->_runtime, &state->_periodic_query_handle);\n            if (res != _Z_RES_OK) {\n                _Z_WARN(\"Failed to remove periodic task, res: %d\", res);\n            }\n            state->_periodic_query_handle = _z_fut_handle_null();\n            _z_session_rc_drop(&sess_rc);\n        }\n    }\n    _z_session_weak_drop(&state->_zn);\n    state->_zn = _z_session_weak_null();\n    _z_uint32__z_sample_sortedmap_clear(&state->_pending_samples);\n    z_keyexpr_drop(z_keyexpr_move(&state->_query_keyexpr));\n}\n\nstatic void _ze_advanced_subscriber_timestamped_state_init(_ze_advanced_subscriber_timestamped_state_t *state) {\n    state->_has_last_delivered = false;\n    state->_last_delivered = _z_timestamp_null();\n    state->_pending_queries = 0;\n    _z_timestamp__z_sample_sortedmap_init(&state->_pending_samples);\n}\n\nvoid _ze_advanced_subscriber_timestamped_state_clear(_ze_advanced_subscriber_timestamped_state_t *state) {\n    state->_has_last_delivered = false;\n    _z_timestamp_clear(&state->_last_delivered);\n    state->_pending_queries = 0;\n    _z_timestamp__z_sample_sortedmap_clear(&state->_pending_samples);\n}\n\n_ze_advanced_subscriber_state_t _ze_advanced_subscriber_state_null(void) {\n    _ze_advanced_subscriber_state_t state = {0};\n    state._zn = _z_session_weak_null();\n    z_internal_keyexpr_null(&state._keyexpr);\n    z_internal_liveliness_token_null(&state._token);\n    z_internal_cancellation_token_null(&state._cancellation_token);\n    return state;\n}\n\nstatic z_result_t _ze_advanced_subscriber_state_init(_ze_advanced_subscriber_state_t *state, const _z_session_rc_t *zn,\n                                                     z_moved_closure_sample_t *callback,\n                                                     const z_loaned_keyexpr_t *keyexpr,\n                                                     const ze_advanced_subscriber_options_t *options) {\n    *state = _ze_advanced_subscriber_state_null();\n    state->_next_id = 0;\n    state->_global_pending_queries = options->history.is_enabled ? 1 : 0;\n    _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_init(&state->_sequenced_states);\n    _z_id__ze_advanced_subscriber_timestamped_state_hashmap_init(&state->_timestamped_states);\n    state->_zn = _z_session_rc_clone_as_weak(zn);\n    state->_retransmission = options->recovery.is_enabled;\n    state->_has_period = options->recovery.last_sample_miss_detection.periodic_queries_period_ms != 0;\n    state->_period_ms = options->recovery.last_sample_miss_detection.periodic_queries_period_ms;\n    state->_history_depth = options->history.is_enabled ? options->history.max_samples : 0;\n    state->_history_age = options->history.is_enabled ? options->history.max_age_ms : 0;\n    state->_query_target = Z_QUERY_TARGET_DEFAULT;\n    // Use default query timeout if not specified in options\n    state->_query_timeout = (options->query_timeout_ms > 0) ? options->query_timeout_ms : Z_GET_TIMEOUT_DEFAULT;\n    state->_callback = callback->_this._val.call;\n    state->_dropper = callback->_this._val.drop;\n    state->_ctx = callback->_this._val.context;\n    z_internal_closure_sample_null(&callback->_this);\n    _ze_closure_miss_intmap_init(&state->_miss_handlers);\n    state->_has_token = false;\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_result_t ret = z_mutex_init(&state->_mutex);\n    if (ret != _Z_RES_OK) {\n        if (state->_dropper != NULL) {\n            state->_dropper(state->_ctx);\n        }\n        return ret;\n    }\n#endif\n    _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_clone(&state->_keyexpr, keyexpr), _ze_advanced_subscriber_state_clear(state));\n    _Z_CLEAN_RETURN_IF_ERR(z_cancellation_token_new(&state->_cancellation_token),\n                           _ze_advanced_subscriber_state_clear(state));\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _ze_advanced_subscriber_state_new(_ze_advanced_subscriber_state_rc_t *rc_state,\n                                                    const _z_session_rc_t *zn, z_moved_closure_sample_t *callback,\n                                                    const z_loaned_keyexpr_t *keyexpr,\n                                                    const ze_advanced_subscriber_options_t *options) {\n    _ze_advanced_subscriber_state_t state;\n    _Z_RETURN_IF_ERR(_ze_advanced_subscriber_state_init(&state, zn, callback, keyexpr, options));\n\n    *rc_state = _ze_advanced_subscriber_state_rc_new_from_val(&state);\n    if (_Z_RC_IS_NULL(rc_state)) {\n        _ze_advanced_subscriber_state_clear(&state);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    return _Z_RES_OK;\n}\n\nvoid _ze_advanced_subscriber_state_clear(_ze_advanced_subscriber_state_t *state) {\n    _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_clear(&state->_sequenced_states);\n    _z_id__ze_advanced_subscriber_timestamped_state_hashmap_clear(&state->_timestamped_states);\n    _ze_closure_miss_intmap_clear(&state->_miss_handlers);\n    z_keyexpr_drop(z_keyexpr_move(&state->_keyexpr));\n    z_cancellation_token_drop(z_cancellation_token_move(&state->_cancellation_token));\n    if (state->_has_token) {\n        z_liveliness_token_drop(z_liveliness_token_move(&state->_token));\n    }\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_mutex_drop(z_mutex_move(&state->_mutex));\n#endif\n    _z_session_weak_drop(&state->_zn);\n\n    *state = _ze_advanced_subscriber_state_null();\n}\n\nstatic bool _ze_advanced_subscriber_state_check(const _ze_advanced_subscriber_state_t *state) {\n    return (!_Z_RC_IS_NULL(&state->_zn) && z_internal_keyexpr_check(&state->_keyexpr) &&\n            (!state->_has_token || z_internal_liveliness_token_check(&state->_token)));\n}\n\nbool _ze_advanced_subscriber_check(const _ze_advanced_subscriber_t *sub) {\n    return (z_internal_subscriber_check(&sub->_subscriber) &&\n            (!sub->_has_liveliness_subscriber || z_internal_subscriber_check(&sub->_liveliness_subscriber)) &&\n            (!sub->_has_heartbeat_subscriber || z_internal_subscriber_check(&sub->_heartbeat_subscriber)) &&\n            !_Z_RC_IS_NULL(&sub->_state) && _ze_advanced_subscriber_state_check(_Z_RC_IN_VAL(&sub->_state)));\n}\n\n_ze_advanced_subscriber_t _ze_advanced_subscriber_null(void) {\n    _ze_advanced_subscriber_t subscriber = {0};\n    z_internal_subscriber_null(&subscriber._subscriber);\n    z_internal_subscriber_null(&subscriber._liveliness_subscriber);\n    z_internal_subscriber_null(&subscriber._heartbeat_subscriber);\n    subscriber._state = _ze_advanced_subscriber_state_rc_null();\n\n    return subscriber;\n}\n\nz_result_t _ze_advanced_subscriber_undeclare(_ze_advanced_subscriber_t *sub) {\n    if (sub == NULL || !_ze_advanced_subscriber_check(sub)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n    z_result_t ret = z_undeclare_subscriber(z_subscriber_move(&sub->_subscriber));\n    if (sub->_has_liveliness_subscriber) {\n        z_result_t ret2 = z_undeclare_subscriber(z_subscriber_move(&sub->_liveliness_subscriber));\n        _Z_SET_IF_OK(ret, ret2)\n    }\n    if (sub->_has_heartbeat_subscriber) {\n        z_result_t ret2 = z_undeclare_subscriber(z_subscriber_move(&sub->_heartbeat_subscriber));\n        _Z_SET_IF_OK(ret, ret2);\n    }\n    _ze_advanced_subscriber_state_rc_drop(&sub->_state);\n\n    *sub = _ze_advanced_subscriber_null();\n    return ret;\n}\n\nvoid _ze_advanced_subscriber_clear(_ze_advanced_subscriber_t *sub) {\n    if (sub == NULL || !_ze_advanced_subscriber_check(sub)) {\n        return;\n    }\n    _z_subscriber_clear(&sub->_subscriber._val);\n    if (sub->_has_liveliness_subscriber) {\n        _z_subscriber_clear(&sub->_liveliness_subscriber._val);\n    }\n    if (sub->_has_heartbeat_subscriber) {\n        _z_subscriber_clear(&sub->_heartbeat_subscriber._val);\n    }\n    _ze_advanced_subscriber_state_rc_drop(&sub->_state);\n\n    *sub = _ze_advanced_subscriber_null();\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL_PREFIX(ze, _ze_advanced_subscriber_t, advanced_subscriber,\n                                                     _ze_advanced_subscriber_check, _ze_advanced_subscriber_null,\n                                                     _ze_advanced_subscriber_undeclare)\n\nstatic bool _ze_advanced_subscriber_populate_query_params(char *buf, size_t buf_len, size_t max_samples,\n                                                          uint64_t max_age_ms,\n                                                          const _z_query_param_range_t *seq_range) {\n    if (buf == NULL || buf_len == 0) {\n        return false;\n    }\n\n    size_t pos = 0;\n    // Allow responses for any key expression\n    if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_KEY_ANYKE, _Z_QUERY_PARAMS_KEY_ANYKE_LEN)) {\n        return false;  // Not enough space\n    }\n\n    if (max_samples > 0) {\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_LIST_SEPARATOR,\n                               _Z_QUERY_PARAMS_LIST_SEPARATOR_LEN)) {\n            return false;  // Not enough space\n        }\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_KEY_MAX, _Z_QUERY_PARAMS_KEY_MAX_LEN)) {\n            return false;  // Not enough space\n        }\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_FIELD_SEPARATOR,\n                               _Z_QUERY_PARAMS_FIELD_SEPARATOR_LEN)) {\n            return false;  // Not enough space\n        }\n\n        int written = snprintf(&buf[pos], buf_len - pos, \"%zu\", max_samples);\n        if (written < 0 || (size_t)written >= buf_len - pos) {\n            return false;  // Overflow or encoding error\n        }\n        pos += (size_t)written;\n    }\n    if (max_age_ms > 0) {\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_LIST_SEPARATOR,\n                               _Z_QUERY_PARAMS_LIST_SEPARATOR_LEN)) {\n            return false;  // Not enough space\n        }\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_KEY_TIME, _Z_QUERY_PARAMS_KEY_TIME_LEN)) {\n            return false;  // Not enough space\n        }\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_FIELD_SEPARATOR,\n                               _Z_QUERY_PARAMS_FIELD_SEPARATOR_LEN)) {\n            return false;  // Not enough space\n        }\n\n        double max_age_s = (double)max_age_ms * _Z_TIME_RANGE_MS_TO_SECS;\n        _z_time_range_t range = {.start = {.bound = _Z_TIME_BOUND_INCLUSIVE, .now_offset = -max_age_s},\n                                 .end = {.bound = _Z_TIME_BOUND_UNBOUNDED}};\n        if (!_z_time_range_to_str(&range, &buf[pos], buf_len - pos)) {\n            return false;  // Not enough space or invalid range\n        }\n        size_t used = strnlen(&buf[pos], buf_len - pos);\n        if (used == buf_len - pos) {\n            // Null terminator not found in remaining space\n            return false;\n        }\n        pos += used;\n    }\n    if (seq_range != NULL) {\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_LIST_SEPARATOR,\n                               _Z_QUERY_PARAMS_LIST_SEPARATOR_LEN)) {\n            return false;  // Not enough space\n        }\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_KEY_RANGE, _Z_QUERY_PARAMS_KEY_RANGE_LEN)) {\n            return false;  // Not enough space\n        }\n        if (!_z_memcpy_checked(buf, buf_len, &pos, _Z_QUERY_PARAMS_FIELD_SEPARATOR,\n                               _Z_QUERY_PARAMS_FIELD_SEPARATOR_LEN)) {\n            return false;  // Not enough space\n        }\n\n        if (seq_range->_has_start) {\n            int written = snprintf(&buf[pos], buf_len - pos, \"%u\", seq_range->_start);\n            if (written < 0 || (size_t)written >= buf_len - pos) {\n                return false;  // Overflow or encoding error\n            }\n            pos += (size_t)written;\n        }\n\n        if (buf_len - pos < 2) {\n            return false;  // Not enough room for \"..\"\n        }\n        buf[pos++] = '.';\n        buf[pos++] = '.';\n\n        if (seq_range->_has_end) {\n            int written = snprintf(&buf[pos], buf_len - pos, \"%u\", seq_range->_end);\n            if (written < 0 || (size_t)written >= buf_len - pos) {\n                return false;  // Overflow or encoding error\n            }\n            pos += (size_t)written;\n        }\n    }\n\n    if (pos >= buf_len) {\n        return false;  // Not enough space for '\\0'\n    }\n    buf[pos] = '\\0';\n    return true;\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nstatic inline void __unsafe_ze_advanced_subscriber_trigger_miss_handler_callbacks(\n    const _ze_closure_miss_intmap_t *miss_handlers, const z_entity_global_id_t *source_id, uint32_t nb) {\n    _ze_closure_miss_intmap_iterator_t it = _ze_closure_miss_intmap_iterator_make(miss_handlers);\n\n    ze_miss_t miss = {.source = *source_id, .nb = nb};\n\n    while (_ze_closure_miss_intmap_iterator_next(&it)) {\n        _ze_closure_miss_t *closure = _ze_closure_miss_intmap_iterator_value(&it);\n        if (closure != NULL && closure->call != NULL) {\n            (closure->call)(&miss, closure->context);\n        }\n    }\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nstatic inline void __unsafe_ze_advanced_subscriber_deliver_and_flush(_z_sample_t *sample, uint32_t source_sn,\n                                                                     _z_closure_sample_callback_t callback, void *ctx,\n                                                                     _ze_advanced_subscriber_sequenced_state_t *state) {\n    if (callback != NULL) {\n        callback(sample, ctx);\n    }\n    state->_last_delivered = source_sn;\n    state->_has_last_delivered = true;\n\n    uint32_t next_sn = _z_seqnumber_next(source_sn);\n    _z_sample_t *next_sample = _z_uint32__z_sample_sortedmap_get(&state->_pending_samples, &next_sn);\n    while (next_sample != NULL) {\n        if (callback != NULL) {\n            callback(next_sample, ctx);\n        }\n        _z_uint32__z_sample_sortedmap_remove(&state->_pending_samples, &next_sn);\n        state->_last_delivered = next_sn;\n        next_sn = _z_seqnumber_next(next_sn);\n        next_sample = _z_uint32__z_sample_sortedmap_get(&state->_pending_samples, &next_sn);\n    }\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\n// TODO: Handle sn wraparound\nstatic inline void __unsafe_ze_advanced_subscriber_flush_sequenced_source(\n    _ze_advanced_subscriber_sequenced_state_t *state, _z_closure_sample_callback_t callback, void *ctx,\n    const _z_entity_global_id_t *source_id, _ze_closure_miss_intmap_t *miss_handlers) {\n    if (state->_pending_queries != 0 || _z_uint32__z_sample_sortedmap_is_empty(&state->_pending_samples)) {\n        return;  // Pending queries or no samples to deliver\n    }\n\n    _z_uint32__z_sample_sortedmap_iterator_t it = _z_uint32__z_sample_sortedmap_iterator_make(&state->_pending_samples);\n    while (_z_uint32__z_sample_sortedmap_iterator_next(&it)) {\n        const uint32_t *source_sn = _z_uint32__z_sample_sortedmap_iterator_key(&it);\n        _z_sample_t *sample = _z_uint32__z_sample_sortedmap_iterator_value(&it);\n\n        if (!state->_has_last_delivered) {\n            state->_last_delivered = *source_sn;\n            state->_has_last_delivered = true;\n            if (callback != NULL) {\n                callback(sample, ctx);\n            }\n        } else {\n            uint32_t next_sn = _z_seqnumber_next(state->_last_delivered);\n            int64_t diff = _z_seqnumber_diff(*source_sn, next_sn);\n            if (diff >= 0) {\n                if (diff > 0) {\n                    __unsafe_ze_advanced_subscriber_trigger_miss_handler_callbacks(miss_handlers, source_id,\n                                                                                   (uint32_t)diff);\n                }\n                state->_last_delivered = *source_sn;\n                if (callback != NULL) {\n                    callback(sample, ctx);\n                }\n            }  // else older or duplicate sample\n        }\n    }\n    _z_uint32__z_sample_sortedmap_clear(&state->_pending_samples);\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nstatic inline void __unsafe_ze_advanced_subscriber_flush_timestamped_source(\n    _ze_advanced_subscriber_timestamped_state_t *state, _z_closure_sample_callback_t callback, void *ctx) {\n    if (state->_pending_queries == 0 && !_z_timestamp__z_sample_sortedmap_is_empty(&state->_pending_samples)) {\n        _z_timestamp__z_sample_sortedmap_iterator_t it =\n            _z_timestamp__z_sample_sortedmap_iterator_make(&state->_pending_samples);\n\n        while (_z_timestamp__z_sample_sortedmap_iterator_next(&it)) {\n            _z_timestamp_t *timestamp = _z_timestamp__z_sample_sortedmap_iterator_key(&it);\n            _z_sample_t *sample = _z_timestamp__z_sample_sortedmap_iterator_value(&it);\n\n            if (!state->_has_last_delivered || _z_timestamp_cmp(timestamp, &state->_last_delivered) > 0) {\n                _z_timestamp_copy(&state->_last_delivered, timestamp);\n                state->_has_last_delivered = true;\n                if (callback != NULL) {\n                    callback(sample, ctx);\n                }\n            }\n        }\n        _z_timestamp__z_sample_sortedmap_clear(&state->_pending_samples);\n    }\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\n// Sets new_sequenced_source to true for new sequenced sources, false otherwise\nstatic z_result_t __unsafe_ze_advanced_subscriber_handle_sample(_ze_advanced_subscriber_state_t *states,\n                                                                z_loaned_sample_t *sample, bool *new_sequenced_source) {\n    if (states == NULL || sample == NULL || new_sequenced_source == NULL) {\n        _Z_ERROR(\"Invalid arguments to __unsafe_ze_advanced_subscriber_handle_sample\");\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    *new_sequenced_source = false;\n\n    const z_source_info_t *source_info = z_sample_source_info(sample);\n    const z_timestamp_t *timestamp = z_sample_timestamp(sample);\n\n    if (source_info != NULL) {\n        z_entity_global_id_t id = z_source_info_id(source_info);\n        uint32_t source_sn = z_source_info_sn(source_info);\n        _ze_advanced_subscriber_sequenced_state_t *state =\n            _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states, &id);\n        if (state == NULL) {\n            *new_sequenced_source = true;\n\n            z_entity_global_id_t *new_id = z_malloc(sizeof(z_entity_global_id_t));\n            if (new_id == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new sequenced state ID\");\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n            *new_id = id;\n\n            _ze_advanced_subscriber_sequenced_state_t *new_state =\n                z_malloc(sizeof(_ze_advanced_subscriber_sequenced_state_t));\n            if (new_state == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new sequenced state\");\n                z_free(new_id);\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n            _Z_CLEAN_RETURN_IF_ERR(_ze_advanced_subscriber_sequenced_state_init(new_state, &states->_zn,\n                                                                                z_keyexpr_loan(&states->_keyexpr), &id),\n                                   z_free(new_id);\n                                   z_free(new_state));\n            state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_insert(\n                &states->_sequenced_states, new_id, new_state);\n            if (state == NULL) {\n                _Z_ERROR(\"Failed to insert new sequenced state into hashmap\");\n                z_free(new_id);\n                z_free(new_state);\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n        }\n        if (!state->_has_last_delivered && states->_global_pending_queries != 0) {\n            // Avoid going through the map if history_depth == 1\n            if (states->_history_depth == 1) {\n                state->_last_delivered = source_sn;\n                state->_has_last_delivered = true;\n                if (states->_callback != NULL) {\n                    states->_callback(sample, states->_ctx);\n                }\n            } else {\n                uint32_t *new_source_sn = z_malloc(sizeof(uint32_t));\n                if (new_source_sn == NULL) {\n                    _Z_ERROR(\"Failed to allocate memory for new source_sn\");\n                    _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                }\n                *new_source_sn = source_sn;\n\n                _z_sample_t *new_sample = z_malloc(sizeof(_z_sample_t));\n                if (new_sample == NULL) {\n                    _Z_ERROR(\"Failed to allocate memory for new sample\");\n                    z_free(new_source_sn);\n                    _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                }\n                _Z_CLEAN_RETURN_IF_ERR(_z_sample_copy(new_sample, sample), z_free(new_source_sn); z_free(new_sample));\n\n                _z_sample_t *entry =\n                    _z_uint32__z_sample_sortedmap_insert(&state->_pending_samples, new_source_sn, new_sample);\n                if (entry == NULL) {\n                    _Z_ERROR(\"Failed to insert sample into sequenced state\");\n                    z_free(new_source_sn);\n                    z_free(new_sample);\n                    _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                }\n\n                // _history_depth = 0 = wait for all global queries to complete\n                if (states->_history_depth > 0 &&\n                    _z_uint32__z_sample_sortedmap_len(&state->_pending_samples) >= states->_history_depth) {\n                    _z_uint32__z_sample_sortedmap_entry_t *first_entry =\n                        _z_uint32__z_sample_sortedmap_pop_first(&state->_pending_samples);\n                    if (first_entry != NULL) {\n                        uint32_t *first_source_sn = _z_uint32__z_sample_sortedmap_entry_key(first_entry);\n                        _z_sample_t *first_sample = _z_uint32__z_sample_sortedmap_entry_val(first_entry);\n                        __unsafe_ze_advanced_subscriber_deliver_and_flush(first_sample, *first_source_sn,\n                                                                          states->_callback, states->_ctx, state);\n                        _z_uint32__z_sample_sortedmap_entry_free(&first_entry);\n                    }\n                }\n            }\n        } else if (state->_has_last_delivered) {\n            uint32_t next_sn = _z_seqnumber_next(state->_last_delivered);\n            if (source_sn == next_sn) {\n                __unsafe_ze_advanced_subscriber_deliver_and_flush(sample, source_sn, states->_callback, states->_ctx,\n                                                                  state);\n            } else if (_z_seqnumber_diff(source_sn, next_sn) > 0) {\n                if (states->_retransmission) {\n                    uint32_t *new_source_sn = z_malloc(sizeof(uint32_t));\n                    if (new_source_sn == NULL) {\n                        _Z_ERROR(\"Failed to allocate memory for new source_sn\");\n                        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                    }\n                    *new_source_sn = source_sn;\n\n                    _z_sample_t *new_sample = z_malloc(sizeof(_z_sample_t));\n                    if (new_sample == NULL) {\n                        _Z_ERROR(\"Failed to allocate memory for new sample\");\n                        z_free(new_source_sn);\n                        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                    }\n                    _Z_CLEAN_RETURN_IF_ERR(_z_sample_copy(new_sample, sample), z_free(new_source_sn);\n                                           z_free(new_sample));\n\n                    _z_sample_t *entry =\n                        _z_uint32__z_sample_sortedmap_insert(&state->_pending_samples, new_source_sn, new_sample);\n                    if (entry == NULL) {\n                        _Z_ERROR(\"Failed to insert sample into sequenced state\");\n                        z_free(new_source_sn);\n                        z_free(new_sample);\n                        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                    }\n                } else {\n                    uint32_t nb = (uint32_t)_z_seqnumber_diff(source_sn, next_sn);\n                    if (nb > 0) {\n                        __unsafe_ze_advanced_subscriber_trigger_miss_handler_callbacks(&states->_miss_handlers, &id,\n                                                                                       nb);\n                    }\n                    state->_last_delivered = source_sn;\n                    if (states->_callback != NULL) {\n                        states->_callback(sample, states->_ctx);\n                    }\n                }\n            }\n        } else {\n            __unsafe_ze_advanced_subscriber_deliver_and_flush(sample, source_sn, states->_callback, states->_ctx,\n                                                              state);\n        }\n    } else if (timestamp != NULL) {\n        z_id_t id = z_timestamp_id(timestamp);\n        _ze_advanced_subscriber_timestamped_state_t *state =\n            _z_id__ze_advanced_subscriber_timestamped_state_hashmap_get(&states->_timestamped_states, &id);\n        if (state == NULL) {\n            z_id_t *new_id = z_malloc(sizeof(z_id_t));\n            if (new_id == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new timestamped state ID\");\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n            *new_id = id;\n            _ze_advanced_subscriber_timestamped_state_t *new_state =\n                z_malloc(sizeof(_ze_advanced_subscriber_timestamped_state_t));\n            if (new_state == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new timestamped state\");\n                z_free(new_id);\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n            _ze_advanced_subscriber_timestamped_state_init(new_state);\n            state = _z_id__ze_advanced_subscriber_timestamped_state_hashmap_insert(&states->_timestamped_states, new_id,\n                                                                                   new_state);\n            if (state == NULL) {\n                _Z_ERROR(\"Failed to insert new timestamped state into hashmap\");\n                z_free(new_id);\n                z_free(new_state);\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n        }\n        if (!state->_has_last_delivered || _z_timestamp_cmp(&state->_last_delivered, timestamp) < 0) {\n            if ((states->_global_pending_queries == 0 && state->_pending_queries == 0) || states->_history_depth == 1) {\n                state->_last_delivered = *timestamp;\n                state->_has_last_delivered = true;\n                if (states->_callback != NULL) {\n                    states->_callback(sample, states->_ctx);\n                }\n            } else {\n                _z_sample_t *entry = _z_timestamp__z_sample_sortedmap_get(&state->_pending_samples, timestamp);\n                if (entry == NULL) {\n                    z_timestamp_t *new_timestamp = z_malloc(sizeof(z_timestamp_t));\n                    if (new_timestamp == NULL) {\n                        _Z_ERROR(\"Failed to allocate memory for new timestamp\");\n                        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                    }\n                    _z_timestamp_copy(new_timestamp, timestamp);\n\n                    _z_sample_t *new_sample = z_malloc(sizeof(_z_sample_t));\n                    if (new_sample == NULL) {\n                        _Z_ERROR(\"Failed to allocate memory for new sample\");\n                        z_free(new_timestamp);\n                        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                    }\n                    _Z_CLEAN_RETURN_IF_ERR(_z_sample_copy(new_sample, sample), z_free(new_timestamp);\n                                           z_free(new_sample));\n\n                    entry =\n                        _z_timestamp__z_sample_sortedmap_insert(&state->_pending_samples, new_timestamp, new_sample);\n                    if (entry == NULL) {\n                        _Z_ERROR(\"Failed to insert sample into timestamped state\");\n                        z_free(new_timestamp);\n                        z_free(new_sample);\n                        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                    }\n                }\n                // _history_depth = 0 = query all history\n                if (states->_history_depth > 0 &&\n                    _z_timestamp__z_sample_sortedmap_len(&state->_pending_samples) >= states->_history_depth) {\n                    __unsafe_ze_advanced_subscriber_flush_timestamped_source(state, states->_callback, states->_ctx);\n                }\n            }\n        }\n    } else {\n        if (states->_callback != NULL) {\n            states->_callback(sample, states->_ctx);\n        }\n    }\n    return _Z_RES_OK;\n}\n\ntypedef enum {\n    _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_INITIAL,\n    _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_SEQUENCED,\n    _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_TIMESTAMPED\n} _ze_advanced_subscriber_query_ctx_kind_t;\n\ntypedef struct {\n    _ze_advanced_subscriber_state_rc_t _statesref;\n    _ze_advanced_subscriber_query_ctx_kind_t _kind;\n\n    union {\n        z_entity_global_id_t _source_id;\n        z_id_t _id;\n    };\n} _ze_advanced_subscriber_query_ctx_t;\n\nstatic inline _ze_advanced_subscriber_query_ctx_t _ze_advanced_subscriber_query_ctx_null(void) {\n    _ze_advanced_subscriber_query_ctx_t ctx = {0};\n    ctx._statesref = _ze_advanced_subscriber_state_rc_null();\n    return ctx;\n}\n\nvoid _ze_advanced_subscriber_query_reply_handler(z_loaned_reply_t *reply, void *ctx) {\n    if (!z_reply_is_ok(reply)) {\n        const z_loaned_reply_err_t *err = z_reply_err(reply);\n        z_owned_string_t errstr;\n        z_bytes_to_string(z_reply_err_payload(err), &errstr);\n        _Z_ERROR(\"Failed to query samples: %.*s\", (int)z_string_len(z_string_loan(&errstr)),\n                 z_string_data(z_string_loan(&errstr)));\n        z_string_drop(z_string_move(&errstr));\n        return;\n    }\n\n    _ze_advanced_subscriber_query_ctx_t *query_ctx = (_ze_advanced_subscriber_query_ctx_t *)ctx;\n\n    if (!_Z_RC_IS_NULL(&query_ctx->_statesref)) {\n        _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(&query_ctx->_statesref);\n\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        const z_loaned_keyexpr_t *keyexpr = z_sample_keyexpr(sample);\n\n        if (z_keyexpr_intersects(z_keyexpr_loan(&states->_keyexpr), keyexpr)) {\n            if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states) != _Z_RES_OK) {\n                _Z_WARN(\"Failed to lock mutex for query reply handling\");\n                return;\n            }\n            z_owned_sample_t sample_copy;\n            if (z_sample_clone(&sample_copy, sample) == _Z_RES_OK) {\n                bool new_source = false;\n                z_result_t ret =\n                    __unsafe_ze_advanced_subscriber_handle_sample(states, z_sample_loan_mut(&sample_copy), &new_source);\n                if (ret != _Z_RES_OK) {\n                    _Z_ERROR(\"Failed to handle sample: %i\", ret);\n                }\n                z_sample_drop(z_sample_move(&sample_copy));\n            } else {\n                _Z_ERROR(\"Failed to clone sample for query reply handling\");\n            }\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n        }\n    }\n}\n\n// Forward declaration\nstatic z_result_t __unsafe_ze_advanced_subscriber_spawn_periodic_query(_ze_advanced_subscriber_sequenced_state_t *state,\n                                                                       _ze_advanced_subscriber_state_rc_t *states_rc,\n                                                                       const z_entity_global_id_t *source_id);\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nvoid __unsafe_ze_advanced_subscriber_initial_query_drop_handler(_ze_advanced_subscriber_state_t *states,\n                                                                _ze_advanced_subscriber_state_rc_t *rc_states) {\n    states->_global_pending_queries = (states->_global_pending_queries > 0) ? (states->_global_pending_queries - 1) : 0;\n    if (states->_global_pending_queries == 0) {\n        for (_z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_iterator_t it =\n                 _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_iterator_make(\n                     &states->_sequenced_states);\n             _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_iterator_next(&it);) {\n            _z_entity_global_id_t *source_id =\n                _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_iterator_key(&it);\n            _ze_advanced_subscriber_sequenced_state_t *sequenced_state =\n                _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_iterator_value(&it);\n\n            __unsafe_ze_advanced_subscriber_flush_sequenced_source(sequenced_state, states->_callback, states->_ctx,\n                                                                   source_id, &states->_miss_handlers);\n\n            if (_z_fut_handle_is_null(sequenced_state->_periodic_query_handle)) {\n                __unsafe_ze_advanced_subscriber_spawn_periodic_query(sequenced_state, rc_states, source_id);\n            }\n        }\n        for (_z_id__ze_advanced_subscriber_timestamped_state_hashmap_iterator_t it =\n                 _z_id__ze_advanced_subscriber_timestamped_state_hashmap_iterator_make(&states->_timestamped_states);\n             _z_id__ze_advanced_subscriber_timestamped_state_hashmap_iterator_next(&it);) {\n            _ze_advanced_subscriber_timestamped_state_t *timestamped_state =\n                _z_id__ze_advanced_subscriber_timestamped_state_hashmap_iterator_value(&it);\n\n            __unsafe_ze_advanced_subscriber_flush_timestamped_source(timestamped_state, states->_callback,\n                                                                     states->_ctx);\n        }\n    }\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nvoid __unsafe_ze_advanced_subscriber_sequenced_query_drop_handler(_ze_advanced_subscriber_state_t *states,\n                                                                  const z_entity_global_id_t *source_id) {\n    _ze_advanced_subscriber_sequenced_state_t *state =\n        _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states, source_id);\n    if (state != NULL) {\n        state->_pending_queries = (state->_pending_queries > 0) ? (state->_pending_queries - 1) : 0;\n        if (states->_global_pending_queries == 0) {\n            __unsafe_ze_advanced_subscriber_flush_sequenced_source(state, states->_callback, states->_ctx, source_id,\n                                                                   &states->_miss_handlers);\n        }\n    }\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nvoid __unsafe_ze_advanced_subscriber_timestamped_query_drop_handler(_ze_advanced_subscriber_state_t *states,\n                                                                    const z_id_t *id) {\n    _ze_advanced_subscriber_timestamped_state_t *state =\n        _z_id__ze_advanced_subscriber_timestamped_state_hashmap_get(&states->_timestamped_states, id);\n    if (state != NULL) {\n        state->_pending_queries = (state->_pending_queries > 0) ? (state->_pending_queries - 1) : 0;\n        if (states->_global_pending_queries == 0) {\n            __unsafe_ze_advanced_subscriber_flush_timestamped_source(state, states->_callback, states->_ctx);\n        }\n    }\n}\n\nvoid _ze_advanced_subscriber_query_drop_handler(void *ctx) {\n    _ze_advanced_subscriber_query_ctx_t *query_ctx = (_ze_advanced_subscriber_query_ctx_t *)ctx;\n\n    if (!_Z_RC_IS_NULL(&query_ctx->_statesref)) {\n        _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(&query_ctx->_statesref);\n#if Z_FEATURE_MULTI_THREAD == 1\n        if (z_mutex_lock(z_mutex_loan_mut(&states->_mutex)) == _Z_RES_OK) {\n#endif\n            switch (query_ctx->_kind) {\n                case _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_INITIAL:\n                    __unsafe_ze_advanced_subscriber_initial_query_drop_handler(states, &query_ctx->_statesref);\n                    break;\n                case _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_SEQUENCED:\n                    __unsafe_ze_advanced_subscriber_sequenced_query_drop_handler(states, &query_ctx->_source_id);\n                    break;\n                case _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_TIMESTAMPED:\n                    __unsafe_ze_advanced_subscriber_timestamped_query_drop_handler(states, &query_ctx->_id);\n                    break;\n                default:\n                    _Z_ERROR(\"Drop handler called for unknown query kind.\");\n            };\n#if Z_FEATURE_MULTI_THREAD == 1\n            z_mutex_unlock(z_mutex_loan_mut(&states->_mutex));\n        }\n#endif\n        _ze_advanced_subscriber_state_rc_drop(&query_ctx->_statesref);\n    }\n    z_free(ctx);\n}\n\nstatic void _ze_advanced_subscriber_query_ctx_free(_ze_advanced_subscriber_query_ctx_t *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n    if (!_Z_RC_IS_NULL(&ctx->_statesref)) {\n        _ze_advanced_subscriber_state_rc_drop(&ctx->_statesref);\n    }\n    z_free(ctx);\n}\n\nstatic z_result_t _ze_advanced_subscriber_run_query(_ze_advanced_subscriber_query_ctx_t *ctx,\n                                                    _ze_advanced_subscriber_state_rc_t *rc_state,\n                                                    const z_loaned_keyexpr_t *keyexpr, const char *params) {\n    if (_Z_RC_IS_NULL(rc_state)) {\n        _Z_ERROR(\"Failed to run query - state is NULL\");\n        // Query context is still locally owned until the reply closure is handed to z_get().\n        _ze_advanced_subscriber_query_ctx_free(ctx);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _ze_advanced_subscriber_state_t *state = _Z_RC_IN_VAL(rc_state);\n    _Z_CLEAN_RETURN_IF_ERR(_ze_advanced_subscriber_state_rc_copy(&ctx->_statesref, rc_state),\n                           _ze_advanced_subscriber_query_ctx_free(ctx));\n\n    z_owned_closure_reply_t callback;\n    z_closure_reply(&callback, _ze_advanced_subscriber_query_reply_handler, _ze_advanced_subscriber_query_drop_handler,\n                    ctx);\n\n    z_get_options_t get_opts;\n    z_get_options_default(&get_opts);\n    get_opts.consolidation.mode = Z_CONSOLIDATION_MODE_NONE;\n    get_opts.target = Z_QUERY_TARGET_ALL;\n    get_opts.timeout_ms = state->_query_timeout;\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&state->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _ze_advanced_subscriber_query_ctx_free(ctx);\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n\n    z_owned_cancellation_token_t ct;\n    _Z_CLEAN_RETURN_IF_ERR(z_cancellation_token_clone(&ct, z_cancellation_token_loan(&state->_cancellation_token)),\n                           _z_session_rc_drop(&sess_rc);\n                           _ze_advanced_subscriber_query_ctx_free(ctx));\n    get_opts.cancellation_token = z_cancellation_token_move(&ct);\n    // From this point on, the reply closure owns ctx and the drop handler must free it.\n    z_result_t ret = z_get(&sess_rc, keyexpr, params, z_closure_reply_move(&callback), &get_opts);\n    _z_session_rc_drop(&sess_rc);\n    return ret;\n}\n\nstatic inline z_result_t _ze_advanced_subscriber_initial_query(_ze_advanced_subscriber_state_rc_t *state,\n                                                               const z_loaned_keyexpr_t *keyexpr, const char *params) {\n    _ze_advanced_subscriber_query_ctx_t *ctx = z_malloc(sizeof(_ze_advanced_subscriber_query_ctx_t));\n    if (ctx == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *ctx = _ze_advanced_subscriber_query_ctx_null();\n    ctx->_kind = _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_INITIAL;\n    return _ze_advanced_subscriber_run_query(ctx, state, keyexpr, params);\n}\n\nstatic inline z_result_t _ze_advanced_subscriber_sequenced_query(_ze_advanced_subscriber_state_rc_t *state,\n                                                                 const z_loaned_keyexpr_t *keyexpr, const char *params,\n                                                                 const z_entity_global_id_t *source_id) {\n    _ze_advanced_subscriber_query_ctx_t *ctx = z_malloc(sizeof(_ze_advanced_subscriber_query_ctx_t));\n    if (ctx == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *ctx = _ze_advanced_subscriber_query_ctx_null();\n    ctx->_kind = _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_SEQUENCED;\n    ctx->_source_id = *source_id;\n    return _ze_advanced_subscriber_run_query(ctx, state, keyexpr, params);\n}\n\nstatic inline z_result_t _ze_advanced_subscriber_timestamped_query(_ze_advanced_subscriber_state_rc_t *state,\n                                                                   const z_loaned_keyexpr_t *keyexpr,\n                                                                   const char *params, const z_id_t *id) {\n    _ze_advanced_subscriber_query_ctx_t *ctx = z_malloc(sizeof(_ze_advanced_subscriber_query_ctx_t));\n    if (ctx == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *ctx = _ze_advanced_subscriber_query_ctx_null();\n    ctx->_kind = _ZE_ADVANCED_SUBSCRIBER_QUERY_CTX_TIMESTAMPED;\n    ctx->_id = *id;\n    return _ze_advanced_subscriber_run_query(ctx, state, keyexpr, params);\n}\n\ntypedef struct {\n    z_entity_global_id_t source_id;\n    _ze_advanced_subscriber_state_rc_t _statesref;\n    _z_sync_group_notifier_t _task_finished_notifier;\n} _ze_advanced_subscriber_periodic_query_ctx_t;\n\n_ze_advanced_subscriber_periodic_query_ctx_t _ze_advanced_subscriber_periodic_query_ctx_null(void) {\n    _ze_advanced_subscriber_periodic_query_ctx_t ctx = {0};\n    return ctx;\n}\n\nvoid _ze_advanced_subscriber_periodic_query_ctx_drop(_ze_advanced_subscriber_periodic_query_ctx_t *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n    _ze_advanced_subscriber_state_rc_drop(&ctx->_statesref);\n    _z_sync_group_notifier_drop(&ctx->_task_finished_notifier);\n}\n\nvoid _ze_advanced_subscriber_periodic_query_ctx_free(_ze_advanced_subscriber_periodic_query_ctx_t **ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n    _ze_advanced_subscriber_periodic_query_ctx_drop(*ctx);\n    z_free(*ctx);\n    *ctx = NULL;\n}\n\nstatic _z_fut_fn_result_t _ze_advanced_subscriber_periodic_query_handler(void *ctx, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n    _ze_advanced_subscriber_periodic_query_ctx_t *query_ctx = (_ze_advanced_subscriber_periodic_query_ctx_t *)ctx;\n    if (_Z_RC_IS_NULL(&query_ctx->_statesref)) {\n        return _z_fut_fn_result_ready();\n    }\n    _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(&query_ctx->_statesref);\n\n    z_result_t res = _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states);\n    if (res != _Z_RES_OK) {\n        _Z_WARN(\"Failed to lock mutex when running periodic query: %d\", res);\n        return _z_fut_fn_result_ready();\n    }\n\n    // Global history still running? Don’t schedule a per-source query yet.\n    if (states->_global_pending_queries != 0) {\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        return _z_fut_fn_result_wake_up_after(states->_period_ms);\n    }\n\n    _ze_advanced_subscriber_sequenced_state_t *state =\n        _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states,\n                                                                                &query_ctx->source_id);\n    if (state == NULL) {\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        return _z_fut_fn_result_wake_up_after(states->_period_ms);\n    }\n\n    // Don’t pile up queries; wait until the previous one finishes.\n    if (state->_pending_queries != 0) {\n        // Nothing to do this tick.\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        return _z_fut_fn_result_wake_up_after(states->_period_ms);\n    }\n\n    char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];\n    _z_query_param_range_t range = {\n        ._has_start = state->_has_last_delivered,\n        ._start = state->_has_last_delivered ? _z_seqnumber_next(state->_last_delivered) : 0u,\n        ._has_end = false,\n        ._end = 0};\n\n    if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), 0, 0, &range)) {\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        _Z_WARN(\"Failed to prepare periodic query\");\n        return _z_fut_fn_result_ready();\n    }\n\n    state->_pending_queries++;\n\n    _ze_advanced_subscriber_state_unlock_mutex(states);\n    res = _ze_advanced_subscriber_sequenced_query(&query_ctx->_statesref, z_keyexpr_loan(&state->_query_keyexpr),\n                                                  params, &query_ctx->source_id);\n    if (res != _Z_RES_OK) {\n        _Z_WARN(\"Failed to run periodic query\");\n        res = _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states);\n        if (res != _Z_RES_OK) {\n            _Z_WARN(\"Failed to lock mutex for periodic query failure (%d)\", res);\n            return _z_fut_fn_result_ready();\n        }\n        state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states,\n                                                                                        &query_ctx->source_id);\n        if (state != NULL) {\n            state->_pending_queries--;\n        }\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n    }\n    return _z_fut_fn_result_wake_up_after(states->_period_ms);\n}\n\nstatic void _ze_advanced_subscriber_periodic_query_dropper(void *ctx) {\n    _ze_advanced_subscriber_periodic_query_ctx_t *query_ctx = (_ze_advanced_subscriber_periodic_query_ctx_t *)ctx;\n    _ze_advanced_subscriber_periodic_query_ctx_free(&query_ctx);\n}\n\n// SAFETY: Must be called with _ze_advanced_subscriber_state_t mutex locked\nstatic z_result_t __unsafe_ze_advanced_subscriber_spawn_periodic_query(_ze_advanced_subscriber_sequenced_state_t *state,\n                                                                       _ze_advanced_subscriber_state_rc_t *rc_states,\n                                                                       const z_entity_global_id_t *source_id) {\n    if (_Z_RC_IS_NULL(rc_states)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(rc_states);\n\n    // Don’t schedule while already running or while a global history query is pending.\n    if (!_z_fut_handle_is_null(state->_periodic_query_handle) || states->_global_pending_queries != 0) {\n        return _Z_RES_OK;\n    }\n\n    // Don't post periodic query if period is not set\n    if (!states->_has_period) {\n        return _Z_RES_OK;\n    }\n    _z_sync_group_notifier_t notifier;\n    _Z_RETURN_IF_ERR(_z_cancellation_token_get_notifier(\n        z_cancellation_token_loan_mut(&states->_cancellation_token)->_val, &notifier));\n\n    _ze_advanced_subscriber_periodic_query_ctx_t *ctx = z_malloc(sizeof(_ze_advanced_subscriber_periodic_query_ctx_t));\n    if (ctx == NULL) {\n        _z_sync_group_notifier_drop(&notifier);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *ctx = _ze_advanced_subscriber_periodic_query_ctx_null();\n    ctx->source_id = *source_id;\n    ctx->_statesref = _ze_advanced_subscriber_state_rc_clone(rc_states);\n    ctx->_task_finished_notifier = notifier;\n    if (_Z_RC_IS_NULL(&ctx->_statesref)) {\n        _ze_advanced_subscriber_periodic_query_ctx_free(&ctx);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&states->_zn);\n#else\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&states->_zn);\n#endif\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _ze_advanced_subscriber_periodic_query_ctx_free(&ctx);\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n\n    _z_fut_t fut = _z_fut_null();\n    fut._fut_arg = ctx;\n    fut._fut_fn = _ze_advanced_subscriber_periodic_query_handler;\n    fut._destroy_fn = _ze_advanced_subscriber_periodic_query_dropper;\n    state->_periodic_query_handle = _z_runtime_spawn(&_Z_RC_IN_VAL(&sess_rc)->_runtime, &fut);\n    _z_session_rc_drop(&sess_rc);\n    if (_z_fut_handle_is_null(state->_periodic_query_handle)) {\n        _Z_ERROR_RETURN(_Z_ERR_FAILED_TO_SPAWN_TASK);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _ze_advanced_subscriber_subscriber_callback(z_loaned_sample_t *sample, void *ctx) {\n    _ze_advanced_subscriber_state_rc_t *rc_states = (_ze_advanced_subscriber_state_rc_t *)ctx;\n    if (_Z_RC_IS_NULL(rc_states)) {\n        return;\n    }\n\n    _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(rc_states);\n    if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to lock subscriber callback mutex\");\n        return;\n    }\n\n    bool new_source = false;\n    z_result_t ret = __unsafe_ze_advanced_subscriber_handle_sample(states, sample, &new_source);\n    if (ret != _Z_RES_OK) {\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        _Z_ERROR(\"Failed to handle sample in subscriber callback: %i\", ret);\n        return;\n    }\n\n    const z_source_info_t *source_info = z_sample_source_info(sample);\n    if (source_info == NULL) {\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        return;\n    }\n    z_entity_global_id_t source_id = z_source_info_id(source_info);\n\n    _ze_advanced_subscriber_sequenced_state_t *state =\n        _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states, &source_id);\n    if (state != NULL && new_source) {\n        __unsafe_ze_advanced_subscriber_spawn_periodic_query(state, rc_states, &source_id);\n    }\n    if (state != NULL && states->_retransmission && state->_pending_queries == 0 &&\n        !_z_uint32__z_sample_sortedmap_is_empty(&state->_pending_samples)) {\n        char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];\n        _z_query_param_range_t range = {\n            ._has_start = state->_has_last_delivered,\n            ._start = state->_has_last_delivered ? _z_seqnumber_next(state->_last_delivered) : 0u,\n            ._has_end = false,\n            ._end = 0};\n\n        if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), 0, 0, &range)) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to prepare query for missing samples\");\n            return;\n        }\n\n        state->_pending_queries++;\n\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n\n        z_result_t res = _ze_advanced_subscriber_sequenced_query(rc_states, z_keyexpr_loan(&state->_query_keyexpr),\n                                                                 params, &source_id);\n        if (res != _Z_RES_OK) {\n            _Z_ERROR(\"Failed to query for missing samples\");\n            if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states) != _Z_RES_OK) {\n                _Z_WARN(\"Failed to lock mutex missing sample query failure (%d)\", res);\n                return;\n            }\n\n            state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states,\n                                                                                            &source_id);\n            if (state != NULL) {\n                state->_pending_queries--;\n            }\n\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n        }\n        return;\n    }\n    _ze_advanced_subscriber_state_unlock_mutex(states);\n}\n\nvoid _ze_advanced_subscriber_subscriber_drop_handler(void *ctx) {\n    _ze_advanced_subscriber_state_rc_t *rc_state = (_ze_advanced_subscriber_state_rc_t *)ctx;\n    if (!_Z_RC_IS_NULL(rc_state)) {\n        _ze_advanced_subscriber_state_t *state = _Z_RC_IN_VAL(rc_state);\n        if (state->_dropper != NULL) {\n            state->_dropper(state->_ctx);\n        }\n        if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(state) != _Z_RES_OK) {\n            _Z_WARN(\"Failed to lock mutex for subscriber drop handler\");\n            return;\n        }\n        // signal undeclaring state to prevent new queries or miss handlers from being added\n        state->_is_undeclaring = true;\n        // Eagerly clear child state before dropping our last direct rc reference so all advanced\n        // subscriber resources are released by the time z_close()/undeclare returns: sequenced\n        // states cancel their periodic query tasks here, and miss handlers release user callback\n        // resources here.\n        // clear miss handlers to release user callbacks\n        _ze_closure_miss_intmap_clear(&state->_miss_handlers);\n        // clear sequenced state to remove any periodic query tasks\n        _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_clear(&state->_sequenced_states);\n        _z_id__ze_advanced_subscriber_timestamped_state_hashmap_clear(&state->_timestamped_states);\n        _ze_advanced_subscriber_state_unlock_mutex(state);\n        if (z_internal_cancellation_token_check(&state->_cancellation_token)) {\n            z_cancellation_token_cancel(z_cancellation_token_loan_mut(&state->_cancellation_token));\n        }\n\n        _ze_advanced_subscriber_state_rc_drop(rc_state);\n        z_free(ctx);\n    }\n}\n\nstatic bool _ze_advanced_subscriber_parse_liveliness_keyexpr_u32(const char *start, size_t len, uint32_t *out) {\n    if (start == NULL || len == 0 || len >= 11 || out == NULL) {\n        return false;  // 10 digits max + '\\0'\n    }\n\n    char buf[ZE_ADVANCED_SUBSCRIBER_UINT32_STR_BUF_LEN];\n    if (!_z_memcpy_checked(buf, sizeof(buf) - 1, NULL, start, len)) {\n        return false;\n    }\n    buf[len] = '\\0';\n\n    char *endptr = NULL;\n    unsigned long val = strtoul(buf, &endptr, 10);\n\n    // Reject if not fully parsed or value is out of uint32_t range\n    if (endptr == buf || *endptr != '\\0' || val > UINT32_MAX) {\n        return false;\n    }\n\n    *out = (uint32_t)val;\n    return true;\n}\n\n#define _ZE_ADVANCED_SUBSCRIBER_UHLC_EID 0\n\n// suffix = _Z_KEYEXPR_ADV_PREFIX / Entity Type / ZID / [ EID | _Z_KEYEXPR_UHLC ] / [ meta | _Z_KEYEXPR_EMPTY ]\n// On successful return id will be populated with the publishers ZID and either the EID or 0 for _Z_KEYEXPR_UHLC\nstatic bool _ze_advanced_subscriber_parse_liveliness_keyexpr(const z_loaned_keyexpr_t *ke, _z_entity_global_id_t *id) {\n    z_view_string_t view;\n    if (z_keyexpr_as_view_string(ke, &view) != _Z_RES_OK) {\n        return false;\n    }\n\n    _z_str_se_t str;\n    str.start = z_string_data(z_view_string_loan(&view));\n    str.end = str.start + z_string_len(z_view_string_loan(&view));\n\n    _z_splitstr_t segments = {.s = str, .delimiter = \"/\"};\n    int segment_cnt = 0;\n    while (segments.s.end != NULL && segment_cnt < 5) {\n        _z_str_se_t segment = _z_splitstr_nextback(&segments);\n\n        if (segment.start != NULL) {\n            segment_cnt++;\n            size_t segment_len = (size_t)(segment.end - segment.start);\n            switch (segment_cnt) {\n                case 2: {\n                    // EID | _Z_KEYEXPR_UHLC\n                    if ((segment_len == _Z_KEYEXPR_UHLC_LEN &&\n                         strncmp(segment.start, _Z_KEYEXPR_UHLC, _Z_KEYEXPR_UHLC_LEN) == 0)) {\n                        id->eid = _ZE_ADVANCED_SUBSCRIBER_UHLC_EID;\n                    } else if (!_ze_advanced_subscriber_parse_liveliness_keyexpr_u32(segment.start, segment_len,\n                                                                                     &id->eid) ||\n                               id->eid == 0) {\n                        // Invalid EID\n                        *id = _z_entity_global_id_null();\n                        _Z_TRACE(\"Received liveliness key expression with invalid EID\");\n                        return false;\n                    }\n                    break;\n                }\n                case 3: {\n                    // ZID\n                    _z_string_t zid_str = _z_string_alias_substr(segment.start, segment_len);\n                    id->zid = _z_id_from_string(&zid_str);\n                    if (!_z_id_check(id->zid)) {\n                        // Invalid Zenoh ID\n                        *id = _z_entity_global_id_null();\n                        _Z_TRACE(\"Received liveliness key expression with invalid ZID\");\n                        return false;\n                    }\n                    break;\n                }\n                case 5: {\n                    // _Z_KEYEXPR_ADV_PREFIX\n                    if (segment_len != _Z_KEYEXPR_ADV_PREFIX_LEN ||\n                        strncmp(segment.start, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_ADV_PREFIX_LEN) != 0) {\n                        *id = _z_entity_global_id_null();\n                        _Z_TRACE(\"Received liveliness key expression with invalid segment\");\n                        return false;\n                    }\n                    break;\n                }\n            }\n        }\n    }\n    // Validate segment count\n    if (segment_cnt < 5) {\n        *id = _z_entity_global_id_null();\n        return false;\n    }\n    return true;\n}\n\nvoid _ze_advanced_subscriber_liveliness_callback(z_loaned_sample_t *sample, void *ctx) {\n    if (z_sample_kind(sample) != Z_SAMPLE_KIND_PUT) {\n        return;\n    }\n\n    _ze_advanced_subscriber_state_rc_t *rc_states = (_ze_advanced_subscriber_state_rc_t *)ctx;\n    if (_Z_RC_IS_NULL(rc_states)) {\n        _Z_ERROR(\"Liveliness subscriber callback called with NULL state reference\");\n        return;\n    }\n    _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(rc_states);\n\n    const z_loaned_keyexpr_t *ke = z_sample_keyexpr(sample);\n    z_entity_global_id_t id = _z_entity_global_id_null();\n    // Parse key expression to extract ZID and EID\n    if (!_ze_advanced_subscriber_parse_liveliness_keyexpr(ke, &id)) {\n        z_view_string_t kestr;\n        z_keyexpr_as_view_string(ke, &kestr);\n        _Z_WARN(\"Received malformed liveliness token key expression: '%.*s'\\n\",\n                (int)z_string_len(z_view_string_loan(&kestr)), z_string_data(z_view_string_loan(&kestr)));\n        return;\n    }\n\n    if (id.eid == _ZE_ADVANCED_SUBSCRIBER_UHLC_EID) {\n        if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states) != _Z_RES_OK) {\n            _Z_WARN(\"Failed to lock liveliness subscriber callback mutex\");\n            return;\n        }\n\n        _ze_advanced_subscriber_timestamped_state_t *state =\n            _z_id__ze_advanced_subscriber_timestamped_state_hashmap_get(&states->_timestamped_states, &id.zid);\n        if (state == NULL) {\n            z_id_t *new_zid = z_malloc(sizeof(z_id_t));\n            if (new_zid == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new timestamped state ID\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                return;\n            }\n            *new_zid = id.zid;\n            _ze_advanced_subscriber_timestamped_state_t *new_state =\n                z_malloc(sizeof(_ze_advanced_subscriber_timestamped_state_t));\n            if (new_state == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new timestamped state\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                z_free(new_zid);\n                return;\n            }\n            _ze_advanced_subscriber_timestamped_state_init(new_state);\n            state = _z_id__ze_advanced_subscriber_timestamped_state_hashmap_insert(&states->_timestamped_states,\n                                                                                   new_zid, new_state);\n            if (state == NULL) {\n                _Z_ERROR(\"Failed to insert new timestamped state into hashmap\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                z_free(new_zid);\n                z_free(new_state);\n                return;\n            }\n        }\n\n        char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];\n        if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), states->_history_depth,\n                                                           states->_history_age, NULL)) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to prepare query for timestamped samples\");\n            return;\n        }\n\n        state->_pending_queries++;\n\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        if (_ze_advanced_subscriber_timestamped_query(rc_states, ke, params, &id.zid) != _Z_RES_OK) {\n            _Z_ERROR(\"Failed to query for timestamped samples\");\n            z_result_t res = _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states);\n            if (res != _Z_RES_OK) {\n                _Z_WARN(\"Failed to lock mutex to relock mutex after timestamped sample query failure (%d)\", res);\n                return;\n            }\n\n            state = _z_id__ze_advanced_subscriber_timestamped_state_hashmap_get(&states->_timestamped_states, &id.zid);\n            if (state != NULL) {\n                state->_pending_queries--;\n            }\n\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n        }\n        return;\n    } else {\n        if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states) != _Z_RES_OK) {\n            _Z_WARN(\"Failed to lock mutex when processing liveliness subscriber callback\");\n            return;\n        }\n\n        _ze_advanced_subscriber_sequenced_state_t *state =\n            _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states, &id);\n        bool new_source = false;\n        if (state == NULL) {\n            new_source = true;\n\n            z_entity_global_id_t *new_id = z_malloc(sizeof(z_entity_global_id_t));\n            if (new_id == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new sequenced state ID\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                return;\n            }\n            *new_id = id;\n\n            _ze_advanced_subscriber_sequenced_state_t *new_state =\n                z_malloc(sizeof(_ze_advanced_subscriber_sequenced_state_t));\n            if (new_state == NULL) {\n                _Z_ERROR(\"Failed to allocate memory for new sequenced state\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                z_free(new_id);\n                return;\n            }\n            if (_ze_advanced_subscriber_sequenced_state_init(new_state, &states->_zn, z_keyexpr_loan(&states->_keyexpr),\n                                                             &id) != _Z_RES_OK) {\n                _Z_ERROR(\"Failed to initialize new sequenced state\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                z_free(new_id);\n                z_free(new_state);\n                return;\n            }\n            state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_insert(\n                &states->_sequenced_states, new_id, new_state);\n            if (state == NULL) {\n                _Z_ERROR(\"Failed to insert new sequenced state into hashmap\");\n                _ze_advanced_subscriber_state_unlock_mutex(states);\n                z_free(new_id);\n                z_free(new_state);\n                return;\n            }\n        }\n\n        char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];\n        if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), states->_history_depth,\n                                                           states->_history_age, NULL)) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to prepare query for sequenced samples\");\n            return;\n        }\n\n        if (state != NULL && new_source) {\n            __unsafe_ze_advanced_subscriber_spawn_periodic_query(state, rc_states, &id);\n        }\n\n        state->_pending_queries++;\n\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        z_result_t res =\n            _ze_advanced_subscriber_sequenced_query(rc_states, z_keyexpr_loan(&state->_query_keyexpr), params, &id);\n        if (res != _Z_RES_OK) {\n            _Z_ERROR(\"Failed to query for sequenced samples\");\n            res = _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states);\n            if (res != _Z_RES_OK) {\n                _Z_WARN(\"Failed to relock mutex after sequenced sample query failure (%d)\", res);\n                return;\n            }\n            state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states,\n                                                                                            &id);\n            if (state != NULL) {\n                state->_pending_queries--;\n            }\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n        }\n        return;\n    }\n}\n\nvoid _ze_advanced_subscriber_liveliness_drop_handler(void *ctx) {\n    _ze_advanced_subscriber_state_rc_t *rc_state = (_ze_advanced_subscriber_state_rc_t *)ctx;\n    if (!_Z_RC_IS_NULL(rc_state)) {\n        _ze_advanced_subscriber_state_rc_drop(rc_state);\n        z_free(ctx);\n    }\n}\n\nvoid _ze_advanced_subscriber_heartbeat_callback(z_loaned_sample_t *sample, void *ctx) {\n    if (z_sample_kind(sample) != Z_SAMPLE_KIND_PUT) {\n        return;\n    }\n\n    _ze_advanced_subscriber_state_rc_t *rc_states = (_ze_advanced_subscriber_state_rc_t *)ctx;\n    if (_Z_RC_IS_NULL(rc_states)) {\n        _Z_ERROR(\"Heartbeat subscriber callback called with NULL state reference\");\n        return;\n    }\n    _ze_advanced_subscriber_state_t *states = _Z_RC_IN_VAL(rc_states);\n\n    const z_loaned_keyexpr_t *ke = z_sample_keyexpr(sample);\n    z_entity_global_id_t id = _z_entity_global_id_null();\n    // Parse key expression to extract ZID and EID\n    if (!_ze_advanced_subscriber_parse_liveliness_keyexpr(ke, &id)) {\n        z_view_string_t kestr;\n        z_keyexpr_as_view_string(ke, &kestr);\n        _Z_WARN(\"Received malformed heartbeat key expression: '%.*s'\\n\", (int)z_string_len(z_view_string_loan(&kestr)),\n                z_string_data(z_view_string_loan(&kestr)));\n        return;\n    }\n\n    const z_loaned_bytes_t *payload = z_sample_payload(sample);\n    if (payload == NULL) {\n        _Z_WARN(\"Received heartbeat with no payload\");\n        return;\n    }\n    if (z_bytes_len(payload) < 4) {\n        _Z_WARN(\"Received heartbeat with invalid payload length: %zu\", z_bytes_len(payload));\n        return;\n    }\n\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(payload);\n    uint32_t heartbeat_sn;\n    if (ze_deserializer_deserialize_uint32(&deserializer, &heartbeat_sn) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to deserialize heartbeat sequence number\");\n        return;\n    }\n    if (!ze_deserializer_is_done(&deserializer)) {\n        _Z_WARN(\"Heartbeat payload contains unexpected data after sequence number\");\n        return;\n    }\n\n    if (_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to lock heartbeat subscriber callback mutex\");\n        return;\n    }\n\n    _ze_advanced_subscriber_sequenced_state_t *state =\n        _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states, &id);\n    if (state == NULL) {\n        if (states->_global_pending_queries > 0) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_TRACE(\"Skipping heartbeat due to pending global query\");\n            return;\n        }\n\n        z_entity_global_id_t *new_id = z_malloc(sizeof(z_entity_global_id_t));\n        if (new_id == NULL) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to allocate memory for new sequenced state ID\");\n            return;\n        }\n        *new_id = id;\n\n        _ze_advanced_subscriber_sequenced_state_t *new_state =\n            z_malloc(sizeof(_ze_advanced_subscriber_sequenced_state_t));\n        if (new_state == NULL) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to allocate memory for new sequenced state\");\n            z_free(new_id);\n            return;\n        }\n        z_result_t res = _ze_advanced_subscriber_sequenced_state_init(new_state, &states->_zn,\n                                                                      z_keyexpr_loan(&states->_keyexpr), &id);\n        if (res != _Z_RES_OK) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to initialize new sequenced state: %i\", res);\n            z_free(new_id);\n            z_free(new_state);\n            return;\n        }\n        state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_insert(&states->_sequenced_states,\n                                                                                           new_id, new_state);\n        if (state == NULL) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to insert new sequenced state into hashmap\");\n            z_free(new_id);\n            z_free(new_state);\n            return;\n        }\n    }\n\n    if (!state->_has_last_delivered ||\n        (_z_seqnumber_diff(heartbeat_sn, state->_last_delivered) > 0 && state->_pending_queries == 0)) {\n        char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];\n        _z_query_param_range_t range = {\n            ._has_start = state->_has_last_delivered,\n            ._start = state->_has_last_delivered ? _z_seqnumber_next(state->_last_delivered) : 0u,\n            ._has_end = true,\n            ._end = heartbeat_sn};\n\n        if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), 0, 0, &range)) {\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n            _Z_ERROR(\"Failed to prepare query for missing samples\");\n            return;\n        }\n\n        state->_pending_queries++;\n\n        _ze_advanced_subscriber_state_unlock_mutex(states);\n        z_result_t res =\n            _ze_advanced_subscriber_sequenced_query(rc_states, z_keyexpr_loan(&state->_query_keyexpr), params, &id);\n        if (res != _Z_RES_OK) {\n            _Z_ERROR(\"Failed to query for missing samples\");\n            res = _ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(states);\n            if (res != _Z_RES_OK) {\n                _Z_WARN(\"failed to relock mutex after missing sample query failure (%d)\", res);\n                return;\n            }\n            state = _z_entity_global_id__ze_advanced_subscriber_sequenced_state_hashmap_get(&states->_sequenced_states,\n                                                                                            &id);\n\n            if (state != NULL) {\n                state->_pending_queries--;\n            }\n            _ze_advanced_subscriber_state_unlock_mutex(states);\n        }\n        return;\n    }\n    _ze_advanced_subscriber_state_unlock_mutex(states);\n}\n\nvoid _ze_advanced_subscriber_heartbeat_drop_handler(void *ctx) {\n    _ze_advanced_subscriber_state_rc_t *rc_state = (_ze_advanced_subscriber_state_rc_t *)ctx;\n    if (!_Z_RC_IS_NULL(rc_state)) {\n        _ze_advanced_subscriber_state_rc_drop(rc_state);\n        z_free(ctx);\n    }\n}\n\n// suffix = KE_ADV_PREFIX / KE_SUB / ZID / EID / [ metadata | KE_EMPTY ]\nstatic z_result_t _ze_advanced_subscriber_ke_suffix(z_owned_keyexpr_t *suffix, const z_entity_global_id_t id,\n                                                    const z_loaned_keyexpr_t *metadata) {\n    z_internal_keyexpr_null(suffix);\n    _Z_RETURN_IF_ERR(_Z_KEYEXPR_APPEND_STR_ARRAY(suffix, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_SUB));\n\n    z_id_t zid = z_entity_global_id_zid(&id);\n    z_owned_string_t zid_str;\n    _Z_CLEAN_RETURN_IF_ERR(z_id_to_string(&zid, &zid_str), z_keyexpr_drop(z_keyexpr_move(suffix)));\n\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_keyexpr_append_substr(suffix, z_string_data(z_string_loan(&zid_str)), z_string_len(z_string_loan(&zid_str))),\n        z_string_drop(z_string_move(&zid_str));\n        z_keyexpr_drop(z_keyexpr_move(suffix)));\n    z_string_drop(z_string_move(&zid_str));\n\n    char buffer[ZE_ADVANCED_SUBSCRIBER_UINT32_STR_BUF_LEN];\n    uint32_t eid = z_entity_global_id_eid(&id);\n    snprintf(buffer, sizeof(buffer), \"%u\", eid);\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(suffix, buffer), z_keyexpr_drop(z_keyexpr_move(suffix)));\n\n    if (metadata != NULL) {\n        _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_suffix(suffix, metadata), z_keyexpr_drop(z_keyexpr_move(suffix)));\n    } else {\n        _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_append_str(suffix, _Z_KEYEXPR_EMPTY), z_keyexpr_drop(z_keyexpr_move(suffix)));\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t ze_declare_advanced_subscriber(const z_loaned_session_t *zs, ze_owned_advanced_subscriber_t *sub,\n                                          const z_loaned_keyexpr_t *keyexpr, z_moved_closure_sample_t *callback,\n                                          ze_advanced_subscriber_options_t *options) {\n    sub->_val = _ze_advanced_subscriber_null();\n\n    // Set options\n    ze_advanced_subscriber_options_t opt;\n    ze_advanced_subscriber_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    // Create Advanced Subscriber state\n    _Z_RETURN_IF_ERR(_ze_advanced_subscriber_state_new(&sub->_val._state, zs, callback, keyexpr, &opt));\n\n    // Common keyexpr for subscribing to publisher liveliness and heartbeat\n    z_owned_keyexpr_t ke_pub;\n    _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_clone(&ke_pub, keyexpr), _ze_advanced_subscriber_state_rc_drop(&sub->_val._state));\n    _Z_CLEAN_RETURN_IF_ERR(\n        _Z_KEYEXPR_APPEND_STR_ARRAY(&ke_pub, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_PUB, _Z_KEYEXPR_STARSTAR),\n        z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n        _ze_advanced_subscriber_state_rc_drop(&sub->_val._state));\n\n    // Declare subscriber\n    _ze_advanced_subscriber_state_rc_t *sub_state = _ze_advanced_subscriber_state_rc_clone_as_ptr(&sub->_val._state);\n    if (_Z_RC_IS_NULL(sub_state)) {\n        _ze_advanced_subscriber_state_rc_drop(&sub->_val._state);\n        z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    z_owned_closure_sample_t subscriber_callback;\n    z_closure_sample(&subscriber_callback, _ze_advanced_subscriber_subscriber_callback,\n                     _ze_advanced_subscriber_subscriber_drop_handler, sub_state);\n    _Z_CLEAN_RETURN_IF_ERR(z_declare_subscriber(zs, &sub->_val._subscriber, keyexpr,\n                                                z_closure_sample_move(&subscriber_callback), &opt.subscriber_options),\n                           z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                           _ze_advanced_subscriber_state_rc_drop(&sub->_val._state));\n\n    if (opt.history.is_enabled) {\n        // Query initial history\n        char params[ZE_ADVANCED_SUBSCRIBER_QUERY_PARAM_BUF_SIZE];\n        if (!_ze_advanced_subscriber_populate_query_params(params, sizeof(params), opt.history.max_samples,\n                                                           opt.history.max_age_ms, NULL)) {\n            z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n            _ze_advanced_subscriber_undeclare(&sub->_val);\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n\n        z_owned_keyexpr_t query_keyexpr;\n        _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_clone(&query_keyexpr, keyexpr), z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               _ze_advanced_subscriber_undeclare(&sub->_val));\n        _Z_CLEAN_RETURN_IF_ERR(_Z_KEYEXPR_APPEND_STR_ARRAY(&query_keyexpr, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_STARSTAR),\n                               z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               z_keyexpr_drop(z_keyexpr_move(&query_keyexpr));\n                               _ze_advanced_subscriber_undeclare(&sub->_val));\n\n        _Z_CLEAN_RETURN_IF_ERR(\n            _ze_advanced_subscriber_initial_query(&sub->_val._state, z_keyexpr_loan(&query_keyexpr), params),\n            z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n            z_keyexpr_drop(z_keyexpr_move(&query_keyexpr)); _ze_advanced_subscriber_undeclare(&sub->_val));\n        z_keyexpr_drop(z_keyexpr_move(&query_keyexpr));\n\n        // Declare liveliness subscriber on keyexpr / KE_ADV_PREFIX / KE_PUB / KE_STARSTAR\n        if (opt.history.detect_late_publishers) {\n            z_liveliness_subscriber_options_t liveliness_options;\n            z_liveliness_subscriber_options_default(&liveliness_options);\n            liveliness_options.history = true;\n\n            _ze_advanced_subscriber_state_rc_t *liveliness_sub_state =\n                _ze_advanced_subscriber_state_rc_clone_as_ptr(&sub->_val._state);\n            if (_Z_RC_IS_NULL(liveliness_sub_state)) {\n                z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                _ze_advanced_subscriber_undeclare(&sub->_val);\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n\n            z_owned_closure_sample_t liveliness_callback;\n            _Z_CLEAN_RETURN_IF_ERR(\n                z_closure_sample(&liveliness_callback, _ze_advanced_subscriber_liveliness_callback,\n                                 _ze_advanced_subscriber_liveliness_drop_handler, liveliness_sub_state),\n                _ze_advanced_subscriber_state_rc_drop(liveliness_sub_state);\n                z_free(liveliness_sub_state); z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                _ze_advanced_subscriber_undeclare(&sub->_val));\n            _Z_CLEAN_RETURN_IF_ERR(\n                z_liveliness_declare_subscriber(zs, &sub->_val._liveliness_subscriber, z_keyexpr_loan(&ke_pub),\n                                                z_closure_sample_move(&liveliness_callback), &liveliness_options),\n                _ze_advanced_subscriber_state_rc_drop(liveliness_sub_state);\n                z_free(liveliness_sub_state); z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                _ze_advanced_subscriber_undeclare(&sub->_val));\n            sub->_val._has_liveliness_subscriber = true;\n        }\n    }\n\n    // Heartbeat subscriber\n    if (opt.recovery.is_enabled && opt.recovery.last_sample_miss_detection.is_enabled &&\n        opt.recovery.last_sample_miss_detection.periodic_queries_period_ms == 0) {\n        _ze_advanced_subscriber_state_rc_t *heartbeat_sub_state =\n            _ze_advanced_subscriber_state_rc_clone_as_ptr(&sub->_val._state);\n        if (_Z_RC_IS_NULL(heartbeat_sub_state)) {\n            z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n            _ze_advanced_subscriber_undeclare(&sub->_val);\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n\n        z_owned_closure_sample_t heartbeat_callback;\n        _Z_CLEAN_RETURN_IF_ERR(z_closure_sample(&heartbeat_callback, _ze_advanced_subscriber_heartbeat_callback,\n                                                _ze_advanced_subscriber_heartbeat_drop_handler, heartbeat_sub_state),\n                               _ze_advanced_subscriber_state_rc_drop(heartbeat_sub_state);\n                               z_free(heartbeat_sub_state); z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               _ze_advanced_subscriber_undeclare(&sub->_val));\n        _Z_CLEAN_RETURN_IF_ERR(z_declare_subscriber(zs, &sub->_val._heartbeat_subscriber, z_keyexpr_loan(&ke_pub),\n                                                    z_closure_sample_move(&heartbeat_callback), NULL),\n                               _ze_advanced_subscriber_state_rc_drop(heartbeat_sub_state);\n                               z_free(heartbeat_sub_state); z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               _ze_advanced_subscriber_undeclare(&sub->_val));\n        sub->_val._has_heartbeat_subscriber = true;\n    }\n\n    // Declare liveliness token on keyexpr/suffix\n    if (opt.subscriber_detection) {\n        _ze_advanced_subscriber_state_t *state = _Z_RC_IN_VAL(&sub->_val._state);\n\n        z_entity_global_id_t id = z_subscriber_id(z_subscriber_loan(&sub->_val._subscriber));\n        z_owned_keyexpr_t suffix;\n        _Z_CLEAN_RETURN_IF_ERR(_ze_advanced_subscriber_ke_suffix(&suffix, id, opt.subscriber_detection_metadata),\n                               z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               _ze_advanced_subscriber_undeclare(&sub->_val));\n        z_owned_keyexpr_t ke;\n        _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_join(&ke, keyexpr, z_keyexpr_loan(&suffix)),\n                               z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               z_keyexpr_drop(z_keyexpr_move(&suffix)); _ze_advanced_subscriber_undeclare(&sub->_val));\n\n#if Z_FEATURE_MULTI_THREAD == 1\n        _Z_CLEAN_RETURN_IF_ERR(z_mutex_lock(z_mutex_loan_mut(&state->_mutex)), z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n                               z_keyexpr_drop(z_keyexpr_move(&suffix)); z_keyexpr_drop(z_keyexpr_move(&ke));\n                               _ze_advanced_subscriber_undeclare(&sub->_val));\n#endif\n\n        z_result_t res = z_liveliness_declare_token(zs, &state->_token, z_keyexpr_loan(&ke), NULL);\n        if (res != _Z_RES_OK) {\n#if Z_FEATURE_MULTI_THREAD == 1\n            z_mutex_unlock(z_mutex_loan_mut(&state->_mutex));\n#endif\n            z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n            z_keyexpr_drop(z_keyexpr_move(&suffix));\n            z_keyexpr_drop(z_keyexpr_move(&ke));\n            _ze_advanced_subscriber_undeclare(&sub->_val);\n            _Z_ERROR_RETURN(res);\n        }\n        state->_has_token = true;\n#if Z_FEATURE_MULTI_THREAD == 1\n        z_mutex_unlock(z_mutex_loan_mut(&state->_mutex));\n#endif\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n        z_keyexpr_drop(z_keyexpr_move(&suffix));\n    }\n    z_keyexpr_drop(z_keyexpr_move(&ke_pub));\n\n    return _Z_RES_OK;\n}\n\nz_result_t ze_declare_background_advanced_subscriber(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                                     z_moved_closure_sample_t *callback,\n                                                     ze_advanced_subscriber_options_t *options) {\n    ze_owned_advanced_subscriber_t sub;\n    _Z_RETURN_IF_ERR(ze_declare_advanced_subscriber(zs, &sub, keyexpr, callback, options));\n    _ze_advanced_subscriber_clear(&sub._val);\n    return _Z_RES_OK;\n}\n\nz_result_t ze_undeclare_advanced_subscriber(ze_moved_advanced_subscriber_t *sub) {\n    return _ze_advanced_subscriber_undeclare(&sub->_this._val);\n}\n\nconst z_loaned_keyexpr_t *ze_advanced_subscriber_keyexpr(const ze_loaned_advanced_subscriber_t *sub) {\n    return z_subscriber_keyexpr(z_subscriber_loan(&sub->_subscriber));\n}\n\nz_entity_global_id_t ze_advanced_subscriber_id(const ze_loaned_advanced_subscriber_t *sub) {\n    return z_subscriber_id(z_subscriber_loan(&sub->_subscriber));\n}\n\nz_result_t ze_advanced_subscriber_declare_sample_miss_listener(const ze_loaned_advanced_subscriber_t *subscriber,\n                                                               ze_owned_sample_miss_listener_t *sample_miss_listener,\n                                                               ze_moved_closure_miss_t *callback) {\n    if (subscriber == NULL || _Z_RC_IS_NULL(&subscriber->_state)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n\n    ze_internal_sample_miss_listener_null(sample_miss_listener);\n\n    _ze_advanced_subscriber_state_t *state = _Z_RC_IN_VAL(&subscriber->_state);\n\n    _Z_CLEAN_RETURN_IF_ERR(_ze_advanced_subscriber_state_lock_mutex_if_not_cancelled(state),\n                           _ze_closure_miss_drop(&callback->_this._val));\n\n    sample_miss_listener->_val._statesref = _ze_advanced_subscriber_state_rc_clone_as_weak(&subscriber->_state);\n    if (_Z_RC_IS_NULL(&sample_miss_listener->_val._statesref)) {\n        _ze_closure_miss_drop(&callback->_this._val);\n        _ze_advanced_subscriber_state_unlock_mutex(state);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    sample_miss_listener->_val._id = state->_next_id++;\n\n    _ze_closure_miss_t *closure = z_malloc(sizeof(_ze_closure_miss_t));\n    if (closure == NULL ||\n        _ze_closure_miss_intmap_insert(&state->_miss_handlers, sample_miss_listener->_val._id, closure) == NULL) {\n        z_free(closure);\n        _ze_closure_miss_drop(&callback->_this._val);\n        _ze_sample_miss_listener_clear(&sample_miss_listener->_val);\n        _ze_advanced_subscriber_state_unlock_mutex(state);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    _ze_closure_miss_move(closure, &callback->_this._val);\n    _ze_advanced_subscriber_state_unlock_mutex(state);\n    return _Z_RES_OK;\n}\n\nz_result_t ze_advanced_subscriber_declare_background_sample_miss_listener(\n    const ze_loaned_advanced_subscriber_t *subscriber, ze_moved_closure_miss_t *callback) {\n    ze_owned_sample_miss_listener_t listener;\n    _Z_RETURN_IF_ERR(ze_advanced_subscriber_declare_sample_miss_listener(subscriber, &listener, callback));\n    _ze_sample_miss_listener_clear(&listener._val);\n    return _Z_RES_OK;\n}\n\nz_result_t ze_undeclare_sample_miss_listener(ze_moved_sample_miss_listener_t *sample_miss_listener) {\n    return _ze_sample_miss_listener_drop(&sample_miss_listener->_this._val);\n}\n\nz_result_t ze_advanced_subscriber_detect_publishers(const ze_loaned_advanced_subscriber_t *subscriber,\n                                                    z_owned_subscriber_t *liveliness_subscriber,\n                                                    z_moved_closure_sample_t *callback,\n                                                    z_liveliness_subscriber_options_t *options) {\n    // Set options\n    z_liveliness_subscriber_options_t opt;\n    z_liveliness_subscriber_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    if (subscriber == NULL || _Z_RC_IS_NULL(&subscriber->_state)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n\n    _ze_advanced_subscriber_state_t *state = _Z_RC_IN_VAL(&subscriber->_state);\n\n    z_owned_keyexpr_t keyexpr;\n    _Z_RETURN_IF_ERR(z_keyexpr_clone(&keyexpr, z_keyexpr_loan(&state->_keyexpr)));\n    _Z_CLEAN_RETURN_IF_ERR(\n        _Z_KEYEXPR_APPEND_STR_ARRAY(&keyexpr, _Z_KEYEXPR_ADV_PREFIX, _Z_KEYEXPR_PUB, _Z_KEYEXPR_STARSTAR),\n        z_keyexpr_drop(z_keyexpr_move(&keyexpr)));\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&state->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        z_keyexpr_drop(z_keyexpr_move(&keyexpr));\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n\n    z_result_t ret =\n        z_liveliness_declare_subscriber(&sess_rc, liveliness_subscriber, z_keyexpr_loan(&keyexpr), callback, &opt);\n    z_keyexpr_drop(z_keyexpr_move(&keyexpr));\n    _z_session_rc_drop(&sess_rc);\n    return ret;\n}\n\nz_result_t ze_advanced_subscriber_detect_publishers_background(const ze_loaned_advanced_subscriber_t *subscriber,\n                                                               z_moved_closure_sample_t *callback,\n                                                               z_liveliness_subscriber_options_t *options) {\n    z_owned_subscriber_t liveliness_subscriber;\n    _Z_RETURN_IF_ERR(ze_advanced_subscriber_detect_publishers(subscriber, &liveliness_subscriber, callback, options));\n    _z_subscriber_clear(&liveliness_subscriber._val);\n    return _Z_RES_OK;\n}\n\nvoid ze_advanced_subscriber_history_options_default(ze_advanced_subscriber_history_options_t *options) {\n    options->is_enabled = true;\n    options->detect_late_publishers = false;\n    options->max_samples = 0;\n    options->max_age_ms = 0;\n}\n\nvoid ze_advanced_subscriber_last_sample_miss_detection_options_default(\n    ze_advanced_subscriber_last_sample_miss_detection_options_t *options) {\n    options->is_enabled = true;\n    options->periodic_queries_period_ms = 0;\n}\n\nvoid ze_advanced_subscriber_recovery_options_default(ze_advanced_subscriber_recovery_options_t *options) {\n    options->is_enabled = true;\n    ze_advanced_subscriber_last_sample_miss_detection_options_default(&options->last_sample_miss_detection);\n    options->last_sample_miss_detection.is_enabled = false;\n}\n\nvoid ze_advanced_subscriber_options_default(ze_advanced_subscriber_options_t *options) {\n    z_subscriber_options_default(&options->subscriber_options);\n\n    ze_advanced_subscriber_history_options_default(&options->history);\n    options->history.is_enabled = false;\n\n    ze_advanced_subscriber_recovery_options_default(&options->recovery);\n    options->recovery.is_enabled = false;\n\n    options->query_timeout_ms = 0;\n    options->subscriber_detection = false;\n    options->subscriber_detection_metadata = NULL;\n}\n\n#endif\n"
  },
  {
    "path": "src/api/api.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/admin_space.h\"\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/olv_macros.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/advanced_cache.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/net/config.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/logger.h\"\n#include \"zenoh-pico/net/matching.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/multicast.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/result.h\"\n#include \"zenoh-pico/utils/uuid.h\"\n\n/********* Data Types Handlers *********/\n\nz_result_t z_view_string_from_str(z_view_string_t *str, const char *value) {\n    str->_val = _z_string_alias_str((char *)value);\n    return _Z_RES_OK;\n}\n\nz_result_t z_view_string_from_substr(z_view_string_t *str, const char *value, size_t len) {\n    str->_val = _z_string_alias_substr((char *)value, len);\n    return _Z_RES_OK;\n}\n\n_z_string_svec_t _z_string_array_null(void) { return _z_string_svec_make(0); }\n\nvoid z_string_array_new(z_owned_string_array_t *a) { a->_val = _z_string_array_null(); }\n\nsize_t z_string_array_push_by_alias(z_loaned_string_array_t *a, const z_loaned_string_t *value) {\n    _z_string_t str = _z_string_alias(*value);\n    _z_string_svec_append(a, &str, true);\n\n    return _z_string_svec_len(a);\n}\n\nsize_t z_string_array_push_by_copy(z_loaned_string_array_t *a, const z_loaned_string_t *value) {\n    _z_string_t str;\n    _z_string_copy(&str, value);\n    _z_string_svec_append(a, &str, true);\n\n    return _z_string_svec_len(a);\n}\n\nconst z_loaned_string_t *z_string_array_get(const z_loaned_string_array_t *a, size_t k) {\n    return _z_string_svec_get(a, k);\n}\n\nsize_t z_string_array_len(const z_loaned_string_array_t *a) { return _z_string_svec_len(a); }\n\nbool z_string_array_is_empty(const z_loaned_string_array_t *a) { return _z_string_svec_is_empty(a); }\n\nz_result_t z_keyexpr_is_canon(const char *start, size_t len) { return _z_keyexpr_is_canon(start, len); }\n\nz_result_t z_keyexpr_canonize(char *start, size_t *len) { return _z_keyexpr_canonize(start, len); }\n\nz_result_t z_keyexpr_canonize_null_terminated(char *start) {\n    size_t len = (start != NULL) ? strlen(start) : 0;\n    z_result_t res = _z_keyexpr_canonize(start, &len);\n    if (res == _Z_RES_OK) {\n        start[len] = '\\0';\n    }\n    return res;\n}\n\nvoid z_view_keyexpr_from_str_unchecked(z_view_keyexpr_t *keyexpr, const char *name) {\n    // SAFETY: Documentation specifies that string should be null-terminated.\n    // Flawfinder: ignore [CWE-126]\n    keyexpr->_val = _z_declared_keyexpr_alias_from_substr(name, strlen(name));\n}\n\nz_result_t z_view_keyexpr_from_substr(z_view_keyexpr_t *keyexpr, const char *name, size_t len) {\n    if (_z_keyexpr_is_canon(name, len) != Z_KEYEXPR_CANON_SUCCESS) {\n        return Z_EINVAL;\n    }\n    keyexpr->_val = _z_declared_keyexpr_alias_from_substr(name, len);\n    return _Z_RES_OK;\n}\n\nz_result_t z_view_keyexpr_from_str(z_view_keyexpr_t *keyexpr, const char *name) {\n    size_t name_len = strlen(name);\n    return z_view_keyexpr_from_substr(keyexpr, name, name_len);\n}\n\nz_result_t z_view_keyexpr_from_substr_autocanonize(z_view_keyexpr_t *keyexpr, char *name, size_t *len) {\n    _Z_RETURN_IF_ERR(z_keyexpr_canonize(name, len));\n    keyexpr->_val = _z_declared_keyexpr_alias_from_substr(name, *len);\n    return _Z_RES_OK;\n}\n\nz_result_t z_view_keyexpr_from_str_autocanonize(z_view_keyexpr_t *keyexpr, char *name) {\n    size_t name_len = strlen(name);\n    return z_view_keyexpr_from_substr_autocanonize(keyexpr, name, &name_len);\n}\n\nvoid z_view_keyexpr_from_substr_unchecked(z_view_keyexpr_t *keyexpr, const char *name, size_t len) {\n    keyexpr->_val = _z_declared_keyexpr_alias_from_substr(name, len);\n}\n\nz_result_t z_keyexpr_as_view_string(const z_loaned_keyexpr_t *keyexpr, z_view_string_t *s) {\n    s->_val = _z_string_alias(keyexpr->_inner._keyexpr);\n    return _Z_RES_OK;\n}\n\nz_result_t z_keyexpr_concat(z_owned_keyexpr_t *key, const z_loaned_keyexpr_t *left, const char *right, size_t len) {\n    return _z_declared_keyexpr_concat(&key->_val, left, right, len);\n}\n\nz_result_t z_keyexpr_join(z_owned_keyexpr_t *key, const z_loaned_keyexpr_t *left, const z_loaned_keyexpr_t *right) {\n    return _z_declared_keyexpr_join(&key->_val, left, right);\n}\n\nz_result_t _z_keyexpr_append_suffix(z_owned_keyexpr_t *prefix, const z_loaned_keyexpr_t *right) {\n    z_owned_keyexpr_t tmp;\n    if (_z_string_len(&prefix->_val._inner._keyexpr) == 0) {\n        if (_z_string_len(&right->_inner._keyexpr) == 0) {\n            _Z_ERROR_RETURN(_Z_ERR_INVALID);\n        }\n        return z_keyexpr_clone(prefix, right);\n    }\n    _Z_RETURN_IF_ERR(z_keyexpr_join(&tmp, z_keyexpr_loan(prefix), right));\n    _z_declared_keyexpr_clear(&prefix->_val);\n    z_keyexpr_take(prefix, z_keyexpr_move(&tmp));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_keyexpr_append_substr(z_owned_keyexpr_t *prefix, const char *right, size_t len) {\n    z_view_keyexpr_t ke_right;\n    z_view_keyexpr_from_substr_unchecked(&ke_right, right, len);\n    return _z_keyexpr_append_suffix(prefix, z_view_keyexpr_loan(&ke_right));\n}\n\nz_result_t _z_keyexpr_append_str_array(z_owned_keyexpr_t *prefix, const char *strs[], size_t count) {\n    for (size_t i = 0; i < count; ++i) {\n        fflush(stdout);\n        _Z_RETURN_IF_ERR(_z_keyexpr_append_str(prefix, strs[i]));\n    }\n    return _Z_RES_OK;\n}\n\nz_keyexpr_intersection_level_t z_keyexpr_relation_to(const z_loaned_keyexpr_t *left, const z_loaned_keyexpr_t *right) {\n    if (z_keyexpr_equals(left, right)) {\n        return Z_KEYEXPR_INTERSECTION_LEVEL_EQUALS;\n    } else if (z_keyexpr_includes(left, right)) {\n        return Z_KEYEXPR_INTERSECTION_LEVEL_INCLUDES;\n    } else if (z_keyexpr_intersects(left, right)) {\n        return Z_KEYEXPR_INTERSECTION_LEVEL_INTERSECTS;\n    }\n    return Z_KEYEXPR_INTERSECTION_LEVEL_DISJOINT;\n}\n\nbool z_keyexpr_includes(const z_loaned_keyexpr_t *l, const z_loaned_keyexpr_t *r) {\n    return _z_declared_keyexpr_includes(l, r);\n}\n\nbool z_keyexpr_intersects(const z_loaned_keyexpr_t *l, const z_loaned_keyexpr_t *r) {\n    return _z_declared_keyexpr_intersects(l, r);\n}\n\nbool z_keyexpr_equals(const z_loaned_keyexpr_t *l, const z_loaned_keyexpr_t *r) {\n    return _z_declared_keyexpr_equals(l, r);\n}\n\nz_result_t z_config_default(z_owned_config_t *config) { return _z_config_default(&config->_val); }\n\nconst char *zp_config_get(const z_loaned_config_t *config, uint8_t key) { return _z_config_get(config, key); }\n\nz_result_t zp_config_insert(z_loaned_config_t *config, uint8_t key, const char *value) {\n    return _zp_config_insert(config, key, value);\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_encoding_t, encoding, _z_encoding_check, _z_encoding_null, _z_encoding_copy,\n                              _z_encoding_move, _z_encoding_clear)\n\nbool z_encoding_equals(const z_loaned_encoding_t *left, const z_loaned_encoding_t *right) {\n    return left->id == right->id && _z_string_equals(&left->schema, &right->schema);\n}\n\nz_result_t z_slice_copy_from_buf(z_owned_slice_t *slice, const uint8_t *data, size_t len) {\n    slice->_val = _z_slice_copy_from_buf(data, len);\n    if (slice->_val.start == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    } else {\n        return _Z_RES_OK;\n    }\n}\n\nz_result_t z_slice_from_buf(z_owned_slice_t *slice, uint8_t *data, size_t len,\n                            void (*deleter)(void *data, void *context), void *context) {\n    slice->_val = _z_slice_from_buf_custom_deleter(data, len, _z_delete_context_create(deleter, context));\n    return _Z_RES_OK;\n}\n\nz_result_t z_view_slice_from_buf(z_view_slice_t *slice, const uint8_t *data, size_t len) {\n    slice->_val = _z_slice_alias_buf(data, len);\n    return _Z_RES_OK;\n}\n\nconst uint8_t *z_slice_data(const z_loaned_slice_t *slice) { return slice->start; }\n\nsize_t z_slice_len(const z_loaned_slice_t *slice) { return slice->len; }\n\nvoid z_slice_empty(z_owned_slice_t *slice) { slice->_val = _z_slice_null(); }\n\nbool z_slice_is_empty(const z_loaned_slice_t *slice) { return _z_slice_is_empty(slice); }\n\nz_result_t z_bytes_to_slice(const z_loaned_bytes_t *bytes, z_owned_slice_t *dst) {\n    dst->_val = _z_slice_null();\n    return _z_bytes_to_slice(bytes, &dst->_val);\n}\n\nz_result_t z_bytes_to_string(const z_loaned_bytes_t *bytes, z_owned_string_t *s) {\n    // Init owned string\n    z_internal_string_null(s);\n    // Convert bytes to string\n    size_t len = _z_bytes_len(bytes);\n    if (len == 0) {\n        return _Z_RES_OK;\n    }\n    s->_val = _z_string_preallocate(len);\n    if (_z_string_len(&s->_val) != len) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    _z_bytes_to_buf(bytes, (uint8_t *)_z_string_data(&s->_val), len);\n    return _Z_RES_OK;\n}\n\nz_result_t z_bytes_from_slice(z_owned_bytes_t *bytes, z_moved_slice_t *slice) {\n    z_bytes_empty(bytes);\n    _z_slice_t s = _z_slice_steal(&slice->_this._val);\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_from_slice(&bytes->_val, &s), _z_slice_clear(&s));\n    return _Z_RES_OK;\n}\n\nz_result_t z_bytes_from_buf(z_owned_bytes_t *bytes, uint8_t *data, size_t len,\n                            void (*deleter)(void *data, void *context), void *context) {\n    z_owned_slice_t s;\n    s._val = _z_slice_from_buf_custom_deleter(data, len, _z_delete_context_create(deleter, context));\n    return z_bytes_from_slice(bytes, z_slice_move(&s));\n}\n\nz_result_t z_bytes_from_static_buf(z_owned_bytes_t *bytes, const uint8_t *data, size_t len) {\n    z_owned_slice_t s;\n    s._val = _z_slice_from_buf_custom_deleter(data, len, _z_delete_context_static());\n    return z_bytes_from_slice(bytes, z_slice_move(&s));\n}\n\nz_result_t z_bytes_copy_from_buf(z_owned_bytes_t *bytes, const uint8_t *data, size_t len) {\n    z_owned_slice_t s;\n    s._val = _z_slice_copy_from_buf(data, len);\n    if (s._val.len != len) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    return z_bytes_from_slice(bytes, z_slice_move(&s));\n}\n\nz_result_t z_bytes_copy_from_slice(z_owned_bytes_t *bytes, const z_loaned_slice_t *slice) {\n    z_owned_slice_t s;\n    _Z_RETURN_IF_ERR(_z_slice_copy(&s._val, slice));\n    return z_bytes_from_slice(bytes, z_slice_move(&s));\n}\n\nz_result_t z_bytes_from_string(z_owned_bytes_t *bytes, z_moved_string_t *s) {\n    z_owned_slice_t slice;\n    size_t str_len = _z_string_len(&s->_this._val);\n    slice._val = _z_slice_steal(&s->_this._val._slice);\n    slice._val.len = str_len;\n    return z_bytes_from_slice(bytes, z_slice_move(&slice));\n}\n\nz_result_t z_bytes_copy_from_string(z_owned_bytes_t *bytes, const z_loaned_string_t *value) {\n    z_owned_string_t s;\n    _Z_RETURN_IF_ERR(_z_string_copy(&s._val, value));\n\n    return z_bytes_from_string(bytes, z_string_move(&s));\n}\n\nz_result_t z_bytes_from_str(z_owned_bytes_t *bytes, char *value, void (*deleter)(void *value, void *context),\n                            void *context) {\n    z_owned_string_t s;\n    s._val = _z_string_from_str_custom_deleter(value, _z_delete_context_create(deleter, context));\n    return z_bytes_from_string(bytes, z_string_move(&s));\n}\n\nz_result_t z_bytes_copy_from_str(z_owned_bytes_t *bytes, const char *value) {\n    z_owned_string_t s;\n    s._val = _z_string_copy_from_str(value);\n    if (s._val._slice.start == NULL && value != NULL) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    return z_bytes_from_string(bytes, z_string_move(&s));\n}\n\nz_result_t z_bytes_from_static_str(z_owned_bytes_t *bytes, const char *value) {\n    z_owned_string_t s;\n    s._val = _z_string_from_str_custom_deleter((char *)value, _z_delete_context_static());\n    return z_bytes_from_string(bytes, z_string_move(&s));\n}\n\nvoid z_bytes_empty(z_owned_bytes_t *bytes) { bytes->_val = _z_bytes_null(); }\n\nsize_t z_bytes_len(const z_loaned_bytes_t *bytes) { return _z_bytes_len(bytes); }\n\nbool z_bytes_is_empty(const z_loaned_bytes_t *bytes) { return _z_bytes_is_empty(bytes); }\n\nz_bytes_reader_t z_bytes_get_reader(const z_loaned_bytes_t *bytes) { return _z_bytes_get_reader(bytes); }\n\nsize_t z_bytes_reader_read(z_bytes_reader_t *reader, uint8_t *dst, size_t len) {\n    return _z_bytes_reader_read(reader, dst, len);\n}\n\nz_result_t z_bytes_reader_seek(z_bytes_reader_t *reader, int64_t offset, int origin) {\n    return _z_bytes_reader_seek(reader, offset, origin);\n}\n\nint64_t z_bytes_reader_tell(z_bytes_reader_t *reader) { return _z_bytes_reader_tell(reader); }\nsize_t z_bytes_reader_remaining(const z_bytes_reader_t *reader) { return _z_bytes_reader_remaining(reader); }\n\nz_bytes_slice_iterator_t z_bytes_get_slice_iterator(const z_loaned_bytes_t *bytes) {\n    return (z_bytes_slice_iterator_t){._bytes = bytes, ._slice_idx = 0};\n}\n\n#if defined(Z_FEATURE_UNSTABLE_API)\nz_result_t z_bytes_get_contiguous_view(const z_loaned_bytes_t *bytes, z_view_slice_t *view) {\n    size_t num_slices = _z_bytes_num_slices(bytes);\n    if (num_slices > 1) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    } else if (num_slices == 1) {\n        _z_arc_slice_t *slice = _z_bytes_get_slice(bytes, 0);\n        z_view_slice_from_buf(view, _z_arc_slice_data(slice), _z_arc_slice_len(slice));\n        return _Z_RES_OK;\n    } else {\n        z_view_slice_empty(view);\n        return _Z_RES_OK;\n    }\n}\n#endif\n\nbool z_bytes_slice_iterator_next(z_bytes_slice_iterator_t *iter, z_view_slice_t *out) {\n    if (iter->_slice_idx >= _z_bytes_num_slices(iter->_bytes)) {\n        return false;\n    }\n    const _z_arc_slice_t *arc_slice = _z_bytes_get_slice(iter->_bytes, iter->_slice_idx);\n    out->_val =\n        _z_slice_alias_buf(_z_slice_simple_rc_value(&arc_slice->slice)->start + arc_slice->start, arc_slice->len);\n    iter->_slice_idx++;\n    return true;\n}\n\nvoid z_bytes_writer_finish(z_moved_bytes_writer_t *writer, z_owned_bytes_t *bytes) {\n    bytes->_val = _z_bytes_writer_finish(&writer->_this._val);\n}\n\nz_result_t z_bytes_writer_empty(z_owned_bytes_writer_t *writer) {\n    writer->_val = _z_bytes_writer_empty();\n    return _Z_RES_OK;\n}\n\nz_result_t z_bytes_writer_write_all(z_loaned_bytes_writer_t *writer, const uint8_t *src, size_t len) {\n    return _z_bytes_writer_write_all(writer, src, len);\n}\n\nz_result_t z_bytes_writer_append(z_loaned_bytes_writer_t *writer, z_moved_bytes_t *bytes) {\n    return _z_bytes_writer_append_z_bytes(writer, &bytes->_this._val);\n}\n\nz_result_t z_timestamp_new(z_timestamp_t *ts, const z_loaned_session_t *zs) {\n    *ts = _z_timestamp_null();\n    _z_time_since_epoch t;\n    _Z_RETURN_IF_ERR(_z_get_time_since_epoch(&t));\n    ts->valid = true;\n    ts->time = _z_timestamp_ntp64_from_time(t.secs, t.nanos);\n    ts->id = _Z_RC_IN_VAL(zs)->_local_zid;\n    return _Z_RES_OK;\n}\n\nuint64_t z_timestamp_ntp64_time(const z_timestamp_t *ts) { return ts->time; }\n\nz_id_t z_timestamp_id(const z_timestamp_t *ts) { return ts->id; }\n\nz_result_t z_entity_global_id_new(z_entity_global_id_t *gid, const z_id_t *zid, uint32_t eid) {\n    *gid = _z_entity_global_id_null();\n    gid->zid = *zid;\n    gid->eid = eid;\n    return _Z_RES_OK;\n}\n\nuint32_t z_entity_global_id_eid(const z_entity_global_id_t *gid) { return gid->eid; }\n\nz_id_t z_entity_global_id_zid(const z_entity_global_id_t *gid) { return gid->zid; }\n\nz_source_info_t z_source_info_new(const z_entity_global_id_t *source_id, uint32_t source_sn) {\n    z_source_info_t si;\n    si._source_id = *source_id;\n    si._source_sn = source_sn;\n    return si;\n}\n\nuint32_t z_source_info_sn(const z_source_info_t *info) { return info->_source_sn; }\n\nz_entity_global_id_t z_source_info_id(const z_source_info_t *info) { return info->_source_id; }\n\nz_query_target_t z_query_target_default(void) { return Z_QUERY_TARGET_DEFAULT; }\n\nz_reply_keyexpr_t z_reply_keyexpr_default(void) { return Z_REPLY_KEYEXPR_DEFAULT; }\n\nz_query_consolidation_t z_query_consolidation_auto(void) {\n    return (z_query_consolidation_t){.mode = Z_CONSOLIDATION_MODE_AUTO};\n}\n\nz_query_consolidation_t z_query_consolidation_latest(void) {\n    return (z_query_consolidation_t){.mode = Z_CONSOLIDATION_MODE_LATEST};\n}\n\nz_query_consolidation_t z_query_consolidation_monotonic(void) {\n    return (z_query_consolidation_t){.mode = Z_CONSOLIDATION_MODE_MONOTONIC};\n}\n\nz_query_consolidation_t z_query_consolidation_none(void) {\n    return (z_query_consolidation_t){.mode = Z_CONSOLIDATION_MODE_NONE};\n}\n\nz_query_consolidation_t z_query_consolidation_default(void) { return z_query_consolidation_auto(); }\n\nvoid z_query_parameters(const z_loaned_query_t *query, z_view_string_t *parameters) {\n    parameters->_val = _z_string_alias(_Z_RC_IN_VAL(query)->_parameters);\n}\n\nz_reply_keyexpr_t z_query_accepts_replies(const z_loaned_query_t *query) {\n    return _Z_RC_IN_VAL(query)->_anyke ? Z_REPLY_KEYEXPR_ANY : Z_REPLY_KEYEXPR_MATCHING_QUERY;\n}\n\nconst z_loaned_bytes_t *z_query_attachment(const z_loaned_query_t *query) { return &_Z_RC_IN_VAL(query)->_attachment; }\n\nconst z_loaned_keyexpr_t *z_query_keyexpr(const z_loaned_query_t *query) { return &_Z_RC_IN_VAL(query)->_key; }\n\nconst z_loaned_bytes_t *z_query_payload(const z_loaned_query_t *query) { return &_Z_RC_IN_VAL(query)->_value.payload; }\n\nconst z_source_info_t *z_query_source_info(const z_loaned_query_t *query) {\n    const z_source_info_t *info = &_Z_RC_IN_VAL(query)->_source_info;\n    return _z_source_info_check(info) ? info : NULL;\n}\n\nconst z_loaned_encoding_t *z_query_encoding(const z_loaned_query_t *query) {\n    return &_Z_RC_IN_VAL(query)->_value.encoding;\n}\n\nvoid z_closure_sample_call(const z_loaned_closure_sample_t *closure, z_loaned_sample_t *sample) {\n    if (closure->call != NULL) {\n        (closure->call)(sample, closure->context);\n    }\n}\n\nvoid z_closure_query_call(const z_loaned_closure_query_t *closure, z_loaned_query_t *query) {\n    if (closure->call != NULL) {\n        (closure->call)(query, closure->context);\n    }\n}\n\nvoid z_closure_reply_call(const z_loaned_closure_reply_t *closure, z_loaned_reply_t *reply) {\n    if (closure->call != NULL) {\n        (closure->call)(reply, closure->context);\n    }\n}\n\nvoid z_closure_hello_call(const z_loaned_closure_hello_t *closure, z_loaned_hello_t *hello) {\n    if (closure->call != NULL) {\n        (closure->call)(hello, closure->context);\n    }\n}\n\nvoid z_closure_zid_call(const z_loaned_closure_zid_t *closure, const z_id_t *id) {\n    if (closure->call != NULL) {\n        (closure->call)(id, closure->context);\n    }\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nvoid z_closure_transport_call(const z_loaned_closure_transport_t *closure, z_loaned_transport_t *transport) {\n    if (closure->call != NULL) {\n        (closure->call)(transport, closure->context);\n    }\n}\n\nvoid z_closure_link_call(const z_loaned_closure_link_t *closure, z_loaned_link_t *link) {\n    if (closure->call != NULL) {\n        (closure->call)(link, closure->context);\n    }\n}\n\nvoid z_closure_transport_event_call(const z_loaned_closure_transport_event_t *closure,\n                                    z_loaned_transport_event_t *event) {\n    if (closure->call != NULL) {\n        (closure->call)(event, closure->context);\n    }\n}\n\nvoid z_closure_link_event_call(const z_loaned_closure_link_event_t *closure, z_loaned_link_event_t *event) {\n    if (closure->call != NULL) {\n        (closure->call)(event, closure->context);\n    }\n}\n#endif\n\nvoid z_closure_matching_status_call(const z_loaned_closure_matching_status_t *closure,\n                                    const z_matching_status_t *status) {\n    if (closure->call != NULL) {\n        (closure->call)(status, closure->context);\n    }\n}\n\nvoid ze_closure_miss_call(const ze_loaned_closure_miss_t *closure, const ze_miss_t *miss) {\n    if (closure->call != NULL) {\n        (closure->call)(miss, closure->context);\n    }\n}\n\nbool _z_config_check(const _z_config_t *config) { return !_z_str_intmap_is_empty(config); }\n_z_config_t _z_config_null(void) { return _z_str_intmap_make(); }\nz_result_t _z_config_copy(_z_config_t *dst, const _z_config_t *src) {\n    *dst = _z_str_intmap_clone(src);\n    return _Z_RES_OK;\n}\nvoid _z_config_drop(_z_config_t *config) { _z_str_intmap_clear(config); }\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_config_t, config, _z_config_check, _z_config_null, _z_config_copy, _z_str_intmap_move,\n                              _z_config_drop)\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_string_t, string, _z_string_check, _z_string_null, _z_string_copy, _z_string_move,\n                              _z_string_clear)\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_value_t, reply_err, _z_value_check, _z_value_null, _z_value_copy, _z_value_move,\n                              _z_value_clear)\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_declared_keyexpr_t, keyexpr, _z_declared_keyexpr_check, _z_declared_keyexpr_null,\n                              _z_declared_keyexpr_copy, _z_declared_keyexpr_move, _z_declared_keyexpr_clear)\n_Z_VIEW_FUNCTIONS_IMPL(_z_declared_keyexpr_t, keyexpr, _z_declared_keyexpr_check, _z_declared_keyexpr_null)\n_Z_VIEW_FUNCTIONS_IMPL(_z_string_t, string, _z_string_check, _z_string_null)\n_Z_VIEW_FUNCTIONS_IMPL(_z_slice_t, slice, _z_slice_check, _z_slice_null)\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_hello_t, hello, _z_hello_check, _z_hello_null, _z_hello_copy, _z_hello_move,\n                              _z_hello_clear)\n\nbool _z_string_array_check(const _z_string_svec_t *val) { return !_z_string_svec_is_empty(val); }\nz_result_t _z_string_array_copy(_z_string_svec_t *dst, const _z_string_svec_t *src) {\n    return _z_string_svec_copy(dst, src, true);\n}\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_string_svec_t, string_array, _z_string_array_check, _z_string_array_null,\n                              _z_string_array_copy, _z_string_svec_move, _z_string_svec_clear)\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_slice_t, slice, _z_slice_check, _z_slice_null, _z_slice_copy, _z_slice_move,\n                              _z_slice_clear)\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_bytes_t, bytes, _z_bytes_check, _z_bytes_null, _z_bytes_copy, _z_bytes_move,\n                              _z_bytes_drop)\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL(_z_bytes_writer_t, bytes_writer, _z_bytes_writer_check, _z_bytes_writer_empty,\n                                      _z_bytes_writer_move, _z_bytes_writer_clear)\n\n#if Z_FEATURE_PUBLICATION == 1 || Z_FEATURE_QUERYABLE == 1 || Z_FEATURE_QUERY == 1\n// Convert a user owned bytes payload to an internal bytes payload, returning an empty one if value invalid\nstatic inline _z_bytes_t *_z_bytes_from_moved(z_moved_bytes_t *bytes) {\n    return (bytes == NULL) ? NULL : &bytes->_this._val;\n}\n\n// Convert a user owned encoding to an internal encoding, return default encoding if value invalid\nstatic inline _z_encoding_t *_z_encoding_from_moved(z_moved_encoding_t *encoding) {\n    return (encoding == NULL) ? NULL : &encoding->_this._val;\n}\n#endif\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_sample_t, sample, _z_sample_check, _z_sample_null, _z_sample_copy, _z_sample_move,\n                              _z_sample_clear)\n_Z_OWNED_FUNCTIONS_RC_IMPL_NO_DROP_CLONE(session)\n\n#if Z_FEATURE_CONNECTIVITY == 1\nbool _z_info_transport_check(const _z_info_transport_t *transport) { return _z_id_check(transport->_zid); }\n_z_info_transport_t _z_info_transport_null(void) { return (_z_info_transport_t){0}; }\nz_result_t _z_info_transport_copy(_z_info_transport_t *dst, const _z_info_transport_t *src) {\n    *dst = *src;\n    return _Z_RES_OK;\n}\nz_result_t _z_info_transport_move(_z_info_transport_t *dst, _z_info_transport_t *src) {\n    *dst = *src;\n    *src = _z_info_transport_null();\n    return _Z_RES_OK;\n}\nvoid _z_info_transport_clear(_z_info_transport_t *transport) { *transport = _z_info_transport_null(); }\n\nbool _z_info_link_check(const _z_info_link_t *link) { return _z_id_check(link->_zid); }\n_z_info_link_t _z_info_link_null(void) {\n    _z_info_link_t link = {0};\n    link._src = _z_string_null();\n    link._dst = _z_string_null();\n    return link;\n}\nz_result_t _z_info_link_copy(_z_info_link_t *dst, const _z_info_link_t *src) {\n    *dst = _z_info_link_null();\n    dst->_zid = src->_zid;\n    dst->_mtu = src->_mtu;\n    dst->_is_streamed = src->_is_streamed;\n    dst->_is_reliable = src->_is_reliable;\n    _Z_RETURN_IF_ERR(_z_string_copy(&dst->_src, &src->_src));\n    _Z_CLEAN_RETURN_IF_ERR(_z_string_copy(&dst->_dst, &src->_dst), _z_string_clear(&dst->_src));\n    return _Z_RES_OK;\n}\nz_result_t _z_info_link_move(_z_info_link_t *dst, _z_info_link_t *src) {\n    *dst = _z_info_link_null();\n    dst->_zid = src->_zid;\n    dst->_mtu = src->_mtu;\n    dst->_is_streamed = src->_is_streamed;\n    dst->_is_reliable = src->_is_reliable;\n    _Z_RETURN_IF_ERR(_z_string_move(&dst->_src, &src->_src));\n    _Z_CLEAN_RETURN_IF_ERR(_z_string_move(&dst->_dst, &src->_dst), _z_string_clear(&dst->_src));\n    *src = _z_info_link_null();\n    return _Z_RES_OK;\n}\nvoid _z_info_link_clear(_z_info_link_t *link) {\n    _z_string_clear(&link->_src);\n    _z_string_clear(&link->_dst);\n    *link = _z_info_link_null();\n}\n\nbool _z_info_transport_event_check(const _z_info_transport_event_t *event) {\n    return _z_info_transport_check(&event->transport);\n}\n_z_info_transport_event_t _z_info_transport_event_null(void) {\n    _z_info_transport_event_t event = {0};\n    event.kind = Z_SAMPLE_KIND_DEFAULT;\n    event.transport = _z_info_transport_null();\n    return event;\n}\nz_result_t _z_info_transport_event_copy(_z_info_transport_event_t *dst, const _z_info_transport_event_t *src) {\n    *dst = *src;\n    return _Z_RES_OK;\n}\nz_result_t _z_info_transport_event_move(_z_info_transport_event_t *dst, _z_info_transport_event_t *src) {\n    *dst = *src;\n    *src = _z_info_transport_event_null();\n    return _Z_RES_OK;\n}\nvoid _z_info_transport_event_clear(_z_info_transport_event_t *event) { *event = _z_info_transport_event_null(); }\n\nbool _z_info_link_event_check(const _z_info_link_event_t *event) { return _z_info_link_check(&event->link); }\n_z_info_link_event_t _z_info_link_event_null(void) {\n    _z_info_link_event_t event = {0};\n    event.kind = Z_SAMPLE_KIND_DEFAULT;\n    event.link = _z_info_link_null();\n    return event;\n}\nz_result_t _z_info_link_event_copy(_z_info_link_event_t *dst, const _z_info_link_event_t *src) {\n    *dst = _z_info_link_event_null();\n    dst->kind = src->kind;\n    return _z_info_link_copy(&dst->link, &src->link);\n}\nz_result_t _z_info_link_event_move(_z_info_link_event_t *dst, _z_info_link_event_t *src) {\n    *dst = _z_info_link_event_null();\n    dst->kind = src->kind;\n    _Z_RETURN_IF_ERR(_z_info_link_move(&dst->link, &src->link));\n    src->kind = Z_SAMPLE_KIND_DEFAULT;\n    return _Z_RES_OK;\n}\nvoid _z_info_link_event_clear(_z_info_link_event_t *event) {\n    _z_info_link_clear(&event->link);\n    event->kind = Z_SAMPLE_KIND_DEFAULT;\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_info_transport_t, transport, _z_info_transport_check, _z_info_transport_null,\n                              _z_info_transport_copy, _z_info_transport_move, _z_info_transport_clear)\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_info_link_t, link, _z_info_link_check, _z_info_link_null, _z_info_link_copy,\n                              _z_info_link_move, _z_info_link_clear)\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_info_transport_event_t, transport_event, _z_info_transport_event_check,\n                              _z_info_transport_event_null, _z_info_transport_event_copy, _z_info_transport_event_move,\n                              _z_info_transport_event_clear)\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_info_link_event_t, link_event, _z_info_link_event_check, _z_info_link_event_null,\n                              _z_info_link_event_copy, _z_info_link_event_move, _z_info_link_event_clear)\n#endif\n\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_sample, _z_closure_sample_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_query, _z_closure_query_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_reply, _z_closure_reply_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_hello, z_closure_hello_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_zid, z_closure_zid_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_matching_status, _z_closure_matching_status_callback_t,\n                                z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL_PREFIX(ze, closure_miss, ze_closure_miss_callback_t, z_closure_drop_callback_t)\n#if Z_FEATURE_CONNECTIVITY == 1\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_transport, z_closure_transport_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_link, z_closure_link_callback_t, z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_transport_event, z_closure_transport_event_callback_t,\n                                z_closure_drop_callback_t)\n_Z_OWNED_FUNCTIONS_CLOSURE_IMPL(closure_link_event, z_closure_link_event_callback_t, z_closure_drop_callback_t)\n#endif\n\n/************* Primitives **************/\n#if Z_FEATURE_SCOUTING == 1\nz_id_t z_hello_zid(const z_loaned_hello_t *hello) { return hello->_zid; }\n\nz_whatami_t z_hello_whatami(const z_loaned_hello_t *hello) { return hello->_whatami; }\n\nconst z_loaned_string_array_t *zp_hello_locators(const z_loaned_hello_t *hello) { return &hello->_locators; }\n\nvoid z_hello_locators(const z_loaned_hello_t *hello, z_owned_string_array_t *locators_out) {\n    z_string_array_clone(locators_out, &hello->_locators);\n}\n\nstatic const char *WHAT_AM_I_TO_STRING_MAP[8] = {\n    \"Other\",              // 0\n    \"Router\",             // 0b1\n    \"Peer\",               // 0b01\n    \"Router|Peer\",        // 0b11,\n    \"Client\",             // 0b100\n    \"Router|Client\",      // 0b101\n    \"Peer|Client\",        // 0b110\n    \"Router|Peer|Client\"  // 0b111\n};\n\nz_result_t z_whatami_to_view_string(z_whatami_t whatami, z_view_string_t *str_out) {\n    uint8_t idx = (uint8_t)whatami;\n    if (idx >= _ZP_ARRAY_SIZE(WHAT_AM_I_TO_STRING_MAP) || idx == 0) {\n        z_view_string_from_str(str_out, WHAT_AM_I_TO_STRING_MAP[0]);\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    } else {\n        z_view_string_from_str(str_out, WHAT_AM_I_TO_STRING_MAP[idx]);\n    }\n    return _Z_RES_OK;\n}\n\ntypedef struct __z_hello_handler_wrapper_t {\n    z_closure_hello_callback_t user_call;\n    void *ctx;\n} __z_hello_handler_wrapper_t;\n\nvoid __z_hello_handler(_z_hello_t *hello, __z_hello_handler_wrapper_t *wrapped_ctx) {\n    wrapped_ctx->user_call(hello, wrapped_ctx->ctx);\n}\n\nz_result_t z_scout(z_moved_config_t *config, z_moved_closure_hello_t *callback, const z_scout_options_t *options) {\n    void *ctx = callback->_this._val.context;\n    callback->_this._val.context = NULL;\n\n    // TODO[API-NET]: When API and NET are a single layer, there is no wrap the user callback and args\n    //                to enclose the z_reply_t into a z_owned_reply_t.\n    __z_hello_handler_wrapper_t *wrapped_ctx =\n        (__z_hello_handler_wrapper_t *)z_malloc(sizeof(__z_hello_handler_wrapper_t));\n    if (wrapped_ctx == NULL) {\n        z_internal_closure_hello_null(&callback->_this);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    wrapped_ctx->user_call = callback->_this._val.call;\n    wrapped_ctx->ctx = ctx;\n\n    z_what_t what;\n    if (options != NULL) {\n        what = options->what;\n    } else {\n        char *opt_as_str = _z_config_get(&config->_this._val, Z_CONFIG_SCOUTING_WHAT_KEY);\n        if (opt_as_str == NULL) {\n            opt_as_str = (char *)Z_CONFIG_SCOUTING_WHAT_DEFAULT;\n        }\n        what = strtol(opt_as_str, NULL, 10);\n    }\n\n    char *opt_as_str = _z_config_get(&config->_this._val, Z_CONFIG_MULTICAST_LOCATOR_KEY);\n    if (opt_as_str == NULL) {\n        opt_as_str = (char *)Z_CONFIG_MULTICAST_LOCATOR_DEFAULT;\n    }\n    _z_string_t mcast_locator = _z_string_alias_str(opt_as_str);\n\n    uint32_t timeout;\n    if (options != NULL) {\n        timeout = options->timeout_ms;\n    } else {\n        opt_as_str = _z_config_get(&config->_this._val, Z_CONFIG_SCOUTING_TIMEOUT_KEY);\n        if (opt_as_str == NULL) {\n            opt_as_str = (char *)Z_CONFIG_SCOUTING_TIMEOUT_DEFAULT;\n        }\n        timeout = (uint32_t)strtoul(opt_as_str, NULL, 10);\n    }\n\n    _z_id_t zid = _z_id_empty();\n    char *zid_str = _z_config_get(&config->_this._val, Z_CONFIG_SESSION_ZID_KEY);\n    if (zid_str != NULL) {\n        _z_uuid_to_bytes(zid.id, zid_str);\n    }\n\n    _z_scout(what, zid, &mcast_locator, timeout, __z_hello_handler, wrapped_ctx, callback->_this._val.drop, ctx);\n\n    z_free(wrapped_ctx);\n    z_config_drop(config);\n    z_internal_closure_hello_null(&callback->_this);\n\n    return _Z_RES_OK;\n}\n#endif\n\nvoid z_open_options_default(z_open_options_t *options) {\n#if Z_FEATURE_ADMIN_SPACE == 1\n    options->auto_start_admin_space = false;\n#endif\n#if Z_FEATURE_MULTI_THREAD == 1\n    options->auto_start_lease_task = false;\n    options->auto_start_read_task = true;\n    options->executor_task_attributes = NULL;\n#endif\n#if Z_FEATURE_ADMIN_SPACE == 0 && Z_FEATURE_MULTI_THREAD == 0\n    options->__dummy = 0;\n#endif\n}\n\nstatic _z_id_t _z_session_get_zid(const _z_config_t *config) {\n    _z_id_t zid = _z_id_empty();\n    char *opt_as_str = _z_config_get(config, Z_CONFIG_SESSION_ZID_KEY);\n    if (opt_as_str != NULL) {\n        _z_uuid_to_bytes(zid.id, opt_as_str);\n    } else {\n        _z_session_generate_zid(&zid, Z_ZID_LENGTH);\n    }\n    return zid;\n}\n\nstatic z_result_t _z_session_rc_init(z_owned_session_t *zs, _z_id_t *zid) {\n    z_internal_session_null(zs);\n    _z_session_t *s = (_z_session_t *)z_malloc(sizeof(_z_session_t));\n    if (s == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    z_result_t ret = _z_session_init(s, zid);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"_z_open failed: %i\", ret);\n        z_free(s);\n        return ret;\n    }\n\n    _z_session_rc_t zsrc = _z_session_rc_new(s);\n    if (zsrc._cnt == NULL) {\n        _z_session_clear(s);\n        z_free(s);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    zs->_rc = zsrc;\n\n    return _Z_RES_OK;\n}\n\nz_result_t z_open(z_owned_session_t *zs, z_moved_config_t *config, const z_open_options_t *options) {\n    z_internal_session_null(zs);\n    z_open_options_t opts;\n    if (options == NULL) {\n        z_open_options_default(&opts);\n    } else {\n        opts = *options;\n    }\n\n    if (config == NULL) {\n        _Z_ERROR(\"A valid config is missing.\");\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    _z_config_t *cfg = &config->_this._val;\n\n    _z_id_t zid = _z_session_get_zid(cfg);\n    if (!_z_id_check(zid)) {\n        _Z_ERROR(\"Invalid ZID.\");\n        z_config_drop(config);\n        return _Z_ERR_INVALID;\n    }\n\n    z_result_t ret = _z_session_rc_init(zs, &zid);\n    if (ret != _Z_RES_OK) {\n        z_config_drop(config);\n        return ret;\n    }\n\n    ret = _z_open(&zs->_rc, cfg, &zid);\n\n    // Move config ownership into the session before starting any background tasks,\n    // as reconnect and async peer-add logic may access it.\n    _Z_OWNED_RC_IN_VAL(zs)->_config = config->_this._val;\n    z_internal_config_null(&config->_this);\n\n    _Z_SET_IF_OK(ret, _zp_start_transport_tasks(_Z_RC_IN_VAL(&zs->_rc)));\n    if (ret != _Z_RES_OK) {\n        z_session_drop(z_session_move(zs));\n        return ret;\n    }\n#if Z_FEATURE_MULTI_THREAD == 1\n    if (opts.auto_start_read_task) {\n        _Z_CLEAN_RETURN_IF_ERR(_z_runtime_start(&_Z_RC_IN_VAL(&zs->_rc)->_runtime, opts.executor_task_attributes),\n                               z_session_drop(z_session_move(zs)));\n    }\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_ADMIN_SPACE == 1\n    if (opts.auto_start_admin_space) {\n        _Z_CLEAN_RETURN_IF_ERR(zp_start_admin_space(z_session_loan_mut(zs)), z_session_drop(z_session_move(zs)));\n    }\n#endif\n#endif\n    return _Z_RES_OK;\n}\n\nvoid z_close_options_default(z_close_options_t *options) { options->__dummy = 0; }\n\nvoid z_session_drop(z_moved_session_t *zs) {\n    if (!_Z_RC_IS_NULL(&zs->_this._rc)) {\n        // force closing of the session (since it might not do it automatically due to temporary pending rc copies)\n        z_close(&zs->_this._rc, NULL);\n        _z_session_rc_drop(&zs->_this._rc);\n    }\n}\n\nz_result_t z_close(z_loaned_session_t *zs, const z_close_options_t *options) {\n    _ZP_UNUSED(options);\n    if (_Z_RC_IS_NULL(zs)) {\n        return _Z_RES_OK;\n    }\n    return _z_session_close(_Z_RC_IN_VAL(zs));\n}\n\nbool z_session_is_closed(const z_loaned_session_t *zs) { return _z_session_is_closed(_Z_RC_IN_VAL(zs)); }\n\n#ifdef Z_FEATURE_UNSTABLE_API\nz_entity_global_id_t z_session_id(const z_loaned_session_t *zs) {\n    z_entity_global_id_t ret;\n    // eid counter starts from 1, so it is safe to use 0 for session\n    z_entity_global_id_new(&ret, &_Z_RC_IN_VAL(zs)->_local_zid, 0);  // never fails\n    return ret;\n}\n#endif\n\nz_result_t z_info_peers_zid(const z_loaned_session_t *zs, z_moved_closure_zid_t *callback) {\n    if (_Z_RC_IN_VAL(zs)->_mode != Z_WHATAMI_PEER) {\n        return _Z_RES_OK;\n    }\n    // Call transport function\n    switch (_Z_RC_IN_VAL(zs)->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            _zp_unicast_fetch_zid(&(_Z_RC_IN_VAL(zs)->_tp), &callback->_this._val);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            _zp_multicast_fetch_zid(&(_Z_RC_IN_VAL(zs)->_tp), &callback->_this._val);\n            break;\n        default:\n            break;\n    }\n    z_closure_zid_drop(callback);\n    return _Z_RES_OK;\n}\n\nz_result_t z_info_routers_zid(const z_loaned_session_t *zs, z_moved_closure_zid_t *callback) {\n    if (_Z_RC_IN_VAL(zs)->_mode != Z_WHATAMI_CLIENT) {\n        return _Z_RES_OK;\n    }\n    // Call transport function\n    switch (_Z_RC_IN_VAL(zs)->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            _zp_unicast_fetch_zid(&(_Z_RC_IN_VAL(zs)->_tp), &callback->_this._val);\n            break;\n        default:\n            break;\n    }\n    z_closure_zid_drop(callback);\n    return _Z_RES_OK;\n}\n\nz_id_t z_info_zid(const z_loaned_session_t *zs) { return _Z_RC_IN_VAL(zs)->_local_zid; }\n\n#if Z_FEATURE_CONNECTIVITY == 1\nvoid _z_info_transport_from_peer(_z_info_transport_t *out, const _z_transport_peer_common_t *peer, bool is_multicast) {\n    *out = _z_info_transport_null();\n    out->_zid = peer->_remote_zid;\n    out->_whatami = peer->_remote_whatami;\n    out->_is_qos = false;\n    out->_is_multicast = is_multicast;\n    out->_is_shm = false;\n}\n\nbool _z_info_transport_filter_match(const _z_info_transport_t *transport, const _z_info_transport_t *filter) {\n    return _z_id_eq(&transport->_zid, &filter->_zid) && transport->_is_multicast == filter->_is_multicast;\n}\n\nstatic z_result_t _z_info_link_make(_z_info_link_t *link, const _z_transport_peer_common_t *peer,\n                                    const _z_transport_common_t *transport_common) {\n    *link = _z_info_link_null();\n    link->_zid = peer->_remote_zid;\n    if (transport_common != NULL && transport_common->_link != NULL) {\n        link->_mtu = transport_common->_link->_mtu;\n        link->_is_streamed = transport_common->_link->_cap._flow == Z_LINK_CAP_FLOW_STREAM;\n        link->_is_reliable = transport_common->_link->_cap._is_reliable;\n    }\n    _Z_RETURN_IF_ERR(_z_string_copy(&link->_src, &peer->_link_src));\n    _Z_CLEAN_RETURN_IF_ERR(_z_string_copy(&link->_dst, &peer->_link_dst), _z_string_clear(&link->_src));\n    return _Z_RES_OK;\n}\n\nvoid z_info_links_options_default(z_info_links_options_t *options) { options->transport = NULL; }\n\nz_result_t z_info_transports(const z_loaned_session_t *zs, z_moved_closure_transport_t *callback) {\n    z_result_t ret = _Z_RES_OK;\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    _z_transport_t *transport = &session->_tp;\n    _z_session_transport_mutex_lock(session);\n    _z_transport_common_t *transport_common = _z_transport_get_common(transport);\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_lock(transport_common);\n    }\n\n    switch (transport->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_peer_unicast_slist_t *curr = transport->_transport._unicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_unicast_slist_next(curr)) {\n                _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(curr);\n                _z_info_transport_t info_transport;\n                _z_info_transport_from_peer(&info_transport, &peer->common, false);\n                z_closure_transport_call(&callback->_this._val, &info_transport);\n            }\n            break;\n        }\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            _z_transport_peer_multicast_slist_t *curr = transport->_transport._multicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_multicast_slist_next(curr)) {\n                _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(curr);\n                _z_info_transport_t info_transport;\n                _z_info_transport_from_peer(&info_transport, &peer->common, true);\n                z_closure_transport_call(&callback->_this._val, &info_transport);\n            }\n            break;\n        }\n        default:\n            break;\n    }\n\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_unlock(transport_common);\n    }\n    _z_session_transport_mutex_unlock(session);\n\n    z_closure_transport_drop(callback);\n    return ret;\n}\n\nz_result_t z_info_links(const z_loaned_session_t *zs, z_moved_closure_link_t *callback,\n                        z_info_links_options_t *options) {\n    z_result_t ret = _Z_RES_OK;\n    z_info_links_options_t opt;\n    z_info_links_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    _z_info_transport_t transport_filter = _z_info_transport_null();\n    bool has_transport_filter = false;\n    if (opt.transport != NULL) {\n        if (!z_internal_transport_check(&opt.transport->_this)) {\n            ret = _Z_ERR_INVALID;\n        } else {\n            transport_filter = *z_transport_loan(&opt.transport->_this);\n            has_transport_filter = true;\n        }\n    }\n\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    _z_transport_t *transport = &session->_tp;\n    if (ret != _Z_RES_OK) {\n        goto out;\n    }\n\n    _z_session_transport_mutex_lock(session);\n    _z_transport_common_t *transport_common = _z_transport_get_common(transport);\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_lock(transport_common);\n    }\n\n    switch (transport->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_peer_unicast_slist_t *curr = transport->_transport._unicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_unicast_slist_next(curr)) {\n                _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(curr);\n                _z_info_transport_t info_transport;\n                _z_info_transport_from_peer(&info_transport, &peer->common, false);\n                if (has_transport_filter && !_z_info_transport_filter_match(&info_transport, &transport_filter)) {\n                    continue;\n                }\n\n                _z_info_link_t info_link;\n                ret = _z_info_link_make(&info_link, &peer->common, transport_common);\n                if (ret != _Z_RES_OK) {\n                    break;\n                }\n                z_closure_link_call(&callback->_this._val, &info_link);\n                _z_info_link_clear(&info_link);\n            }\n            break;\n        }\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            _z_transport_peer_multicast_slist_t *curr = transport->_transport._multicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_multicast_slist_next(curr)) {\n                _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(curr);\n                _z_info_transport_t info_transport;\n                _z_info_transport_from_peer(&info_transport, &peer->common, true);\n                if (has_transport_filter && !_z_info_transport_filter_match(&info_transport, &transport_filter)) {\n                    continue;\n                }\n\n                _z_info_link_t info_link;\n                ret = _z_info_link_make(&info_link, &peer->common, transport_common);\n                if (ret != _Z_RES_OK) {\n                    break;\n                }\n                z_closure_link_call(&callback->_this._val, &info_link);\n                _z_info_link_clear(&info_link);\n            }\n            break;\n        }\n        default:\n            break;\n    }\n\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_unlock(transport_common);\n    }\n    _z_session_transport_mutex_unlock(session);\n\nout:\n    z_transport_drop(opt.transport);\n\n    z_closure_link_drop(callback);\n    return ret;\n}\n\nz_id_t z_transport_zid(const z_loaned_transport_t *transport) { return transport->_zid; }\nz_whatami_t z_transport_whatami(const z_loaned_transport_t *transport) { return transport->_whatami; }\nbool z_transport_is_qos(const z_loaned_transport_t *transport) { return transport->_is_qos; }\nbool z_transport_is_multicast(const z_loaned_transport_t *transport) { return transport->_is_multicast; }\nbool z_transport_is_shm(const z_loaned_transport_t *transport) { return transport->_is_shm; }\n\nz_id_t z_link_zid(const z_loaned_link_t *link) { return link->_zid; }\nz_result_t z_link_src(const z_loaned_link_t *link, z_owned_string_t *str_out) {\n    str_out->_val = _z_string_null();\n    return _z_string_copy(&str_out->_val, &link->_src);\n}\nz_result_t z_link_dst(const z_loaned_link_t *link, z_owned_string_t *str_out) {\n    str_out->_val = _z_string_null();\n    return _z_string_copy(&str_out->_val, &link->_dst);\n}\nuint16_t z_link_mtu(const z_loaned_link_t *link) { return link->_mtu; }\nbool z_link_is_streamed(const z_loaned_link_t *link) { return link->_is_streamed; }\nbool z_link_is_reliable(const z_loaned_link_t *link) { return link->_is_reliable; }\n\nvoid z_link_group(const z_loaned_link_t *link, z_owned_string_t *str_out) {\n    (void)link;\n    str_out->_val = _z_string_null();\n}\nvoid z_link_auth_identifier(const z_loaned_link_t *link, z_owned_string_t *str_out) {\n    (void)link;\n    str_out->_val = _z_string_null();\n}\nvoid z_link_interfaces(const z_loaned_link_t *link, z_owned_string_array_t *interfaces_out) {\n    (void)link;\n    interfaces_out->_val = _z_string_svec_null();\n}\nbool z_link_priorities(const z_loaned_link_t *link, uint8_t *min_out, uint8_t *max_out) {\n    (void)link;\n    (void)min_out;\n    (void)max_out;\n    return false;\n}\nbool z_link_reliability(const z_loaned_link_t *link, z_reliability_t *reliability_out) {\n    (void)link;\n    (void)reliability_out;\n    return false;\n}\n\nz_sample_kind_t z_transport_event_kind(const z_loaned_transport_event_t *event) { return event->kind; }\nconst z_loaned_transport_t *z_transport_event_transport(const z_loaned_transport_event_t *event) {\n    return &event->transport;\n}\nz_loaned_transport_t *z_transport_event_transport_mut(z_loaned_transport_event_t *event) { return &event->transport; }\n\nz_sample_kind_t z_link_event_kind(const z_loaned_link_event_t *event) { return event->kind; }\nconst z_loaned_link_t *z_link_event_link(const z_loaned_link_event_t *event) { return &event->link; }\nz_loaned_link_t *z_link_event_link_mut(z_loaned_link_event_t *event) { return &event->link; }\n#endif\n\nz_result_t z_id_to_string(const z_id_t *id, z_owned_string_t *str) {\n    str->_val = _z_id_to_string(id);\n    if (!_z_string_check(&str->_val)) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nconst z_loaned_keyexpr_t *z_sample_keyexpr(const z_loaned_sample_t *sample) { return &sample->keyexpr; }\nz_sample_kind_t z_sample_kind(const z_loaned_sample_t *sample) { return sample->kind; }\n#ifdef Z_FEATURE_UNSTABLE_API\nz_reliability_t z_sample_reliability(const z_loaned_sample_t *sample) { return sample->reliability; }\nconst z_source_info_t *z_sample_source_info(const z_loaned_sample_t *sample) {\n    const z_source_info_t *info = &sample->source_info;\n    return _z_source_info_check(info) ? info : NULL;\n}\n#endif\nconst z_loaned_bytes_t *z_sample_payload(const z_loaned_sample_t *sample) { return &sample->payload; }\nconst z_timestamp_t *z_sample_timestamp(const z_loaned_sample_t *sample) {\n    if (_z_timestamp_check(&sample->timestamp)) {\n        return &sample->timestamp;\n    } else {\n        return NULL;\n    }\n}\nconst z_loaned_encoding_t *z_sample_encoding(const z_loaned_sample_t *sample) { return &sample->encoding; }\nconst z_loaned_bytes_t *z_sample_attachment(const z_loaned_sample_t *sample) { return &sample->attachment; }\nz_congestion_control_t z_sample_congestion_control(const z_loaned_sample_t *sample) {\n    return _z_n_qos_get_congestion_control(sample->qos);\n}\nbool z_sample_express(const z_loaned_sample_t *sample) { return _z_n_qos_get_express(sample->qos); }\nz_priority_t z_sample_priority(const z_loaned_sample_t *sample) { return _z_n_qos_get_priority(sample->qos); }\n\nconst z_loaned_bytes_t *z_reply_err_payload(const z_loaned_reply_err_t *reply_err) { return &reply_err->payload; }\nconst z_loaned_encoding_t *z_reply_err_encoding(const z_loaned_reply_err_t *reply_err) { return &reply_err->encoding; }\n\nconst char *z_string_data(const z_loaned_string_t *str) { return _z_string_data(str); }\nsize_t z_string_len(const z_loaned_string_t *str) { return _z_string_len(str); }\n\nz_result_t z_string_copy_from_str(z_owned_string_t *str, const char *value) {\n    str->_val = _z_string_copy_from_str(value);\n    if (str->_val._slice.start == NULL && value != NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t z_string_from_str(z_owned_string_t *str, char *value, void (*deleter)(void *value, void *context),\n                             void *context) {\n    str->_val = _z_string_from_str_custom_deleter(value, _z_delete_context_create(deleter, context));\n    return _Z_RES_OK;\n}\n\nvoid z_string_empty(z_owned_string_t *str) { str->_val = _z_string_null(); }\n\nz_result_t z_string_copy_from_substr(z_owned_string_t *str, const char *value, size_t len) {\n    str->_val = _z_string_copy_from_substr(value, len);\n    return _Z_RES_OK;\n}\n\nbool z_string_is_empty(const z_loaned_string_t *str) { return _z_string_is_empty(str); }\n\nconst z_loaned_slice_t *z_string_as_slice(const z_loaned_string_t *str) { return &str->_slice; }\n\nz_priority_t z_priority_default(void) { return Z_PRIORITY_DEFAULT; }\n\n#if Z_FEATURE_PUBLICATION == 1\nvoid _z_publisher_drop(_z_publisher_t *pub) { _z_undeclare_publisher(pub); }\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_publisher_t, publisher, _z_publisher_check, _z_publisher_null,\n                                              _z_publisher_drop)\n\nvoid z_put_options_default(z_put_options_t *options) {\n    options->congestion_control = z_internal_congestion_control_default_push();\n    options->priority = Z_PRIORITY_DEFAULT;\n    options->encoding = NULL;\n    options->is_express = false;\n    options->timestamp = NULL;\n    options->attachment = NULL;\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    options->allowed_destination = z_locality_default();\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->reliability = Z_RELIABILITY_DEFAULT;\n    options->source_info = NULL;\n#endif\n}\n\nvoid z_delete_options_default(z_delete_options_t *options) {\n    options->congestion_control = z_internal_congestion_control_default_push();\n    options->is_express = false;\n    options->timestamp = NULL;\n    options->priority = Z_PRIORITY_DEFAULT;\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    options->allowed_destination = z_locality_default();\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->reliability = Z_RELIABILITY_DEFAULT;\n    options->source_info = NULL;\n#endif\n}\n\nz_result_t z_put(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, z_moved_bytes_t *payload,\n                 const z_put_options_t *options) {\n    z_result_t ret = 0;\n\n    z_put_options_t opt;\n    z_put_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n    z_reliability_t reliability = Z_RELIABILITY_DEFAULT;\n    _z_source_info_t *source_info = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    reliability = opt.reliability;\n    source_info = opt.source_info;\n#endif\n\n    _z_bytes_t *payload_bytes = _z_bytes_from_moved(payload);\n    _z_bytes_t *attachment_bytes = _z_bytes_from_moved(opt.attachment);\n    _z_encoding_t *encoding = _z_encoding_from_moved(opt.encoding);\n    z_locality_t allowed_destination = z_locality_default();\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    allowed_destination = opt.allowed_destination;\n#endif\n    ret = _z_write(_Z_RC_IN_VAL(zs), keyexpr, payload_bytes, encoding, Z_SAMPLE_KIND_PUT, opt.congestion_control,\n                   opt.priority, opt.is_express, opt.timestamp, attachment_bytes, reliability, source_info,\n                   allowed_destination);\n\n    z_encoding_drop(opt.encoding);\n    z_bytes_drop(opt.attachment);\n    z_bytes_drop(payload);\n\n    return ret;\n}\n\nz_result_t z_delete(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                    const z_delete_options_t *options) {\n    z_result_t ret = 0;\n\n    z_delete_options_t opt;\n    z_delete_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n    z_reliability_t reliability = Z_RELIABILITY_DEFAULT;\n    _z_source_info_t *source_info = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    reliability = opt.reliability;\n    source_info = opt.source_info;\n#endif\n    z_locality_t allowed_destination = z_locality_default();\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    allowed_destination = opt.allowed_destination;\n#endif\n    ret = _z_write(_Z_RC_IN_VAL(zs), keyexpr, NULL, NULL, Z_SAMPLE_KIND_DELETE, opt.congestion_control, opt.priority,\n                   opt.is_express, opt.timestamp, NULL, reliability, source_info, allowed_destination);\n    return ret;\n}\n\nvoid z_publisher_options_default(z_publisher_options_t *options) {\n    options->encoding = NULL;\n    options->congestion_control = z_internal_congestion_control_default_push();\n    options->priority = Z_PRIORITY_DEFAULT;\n    options->is_express = false;\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    options->allowed_destination = z_locality_default();\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->reliability = Z_RELIABILITY_DEFAULT;\n#endif\n}\n\nz_result_t z_declare_publisher(const z_loaned_session_t *zs, z_owned_publisher_t *pub,\n                               const z_loaned_keyexpr_t *keyexpr, const z_publisher_options_t *options) {\n    pub->_val = _z_publisher_null();\n    // Set options\n    z_publisher_options_t opt;\n    z_publisher_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n    z_reliability_t reliability = Z_RELIABILITY_DEFAULT;\n#ifdef Z_FEATURE_UNSTABLE_API\n    reliability = opt.reliability;\n#endif\n    z_locality_t allowed_destination = z_locality_default();\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    allowed_destination = opt.allowed_destination;\n#endif\n    z_result_t res =\n        _z_declare_publisher(&pub->_val, zs, keyexpr, opt.encoding == NULL ? NULL : &opt.encoding->_this._val,\n                             opt.congestion_control, opt.priority, opt.is_express, reliability, allowed_destination);\n    _Z_SET_IF_OK(res, _z_write_filter_create(zs, &pub->_val._filter, &pub->_val._key, _Z_INTEREST_FLAG_SUBSCRIBERS,\n                                             false, allowed_destination));\n    if (res != _Z_RES_OK) {\n        _z_publisher_drop(&pub->_val);\n    }\n    return res;\n}\n\nz_result_t z_undeclare_publisher(z_moved_publisher_t *pub) { return _z_undeclare_publisher(&pub->_this._val); }\n\nvoid z_publisher_put_options_default(z_publisher_put_options_t *options) {\n    options->encoding = NULL;\n    options->attachment = NULL;\n    options->timestamp = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->source_info = NULL;\n#endif\n}\n\nvoid z_publisher_delete_options_default(z_publisher_delete_options_t *options) {\n    options->timestamp = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->source_info = NULL;\n#endif\n}\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\nz_result_t _z_publisher_put_impl(const z_loaned_publisher_t *pub, z_moved_bytes_t *payload,\n                                 const z_publisher_put_options_t *options, _ze_advanced_cache_t *cache) {\n#else\nz_result_t _z_publisher_put_impl(const z_loaned_publisher_t *pub, z_moved_bytes_t *payload,\n                                 const z_publisher_put_options_t *options) {\n#endif\n    z_result_t ret = 0;\n    // Build options\n    z_publisher_put_options_t opt;\n    z_publisher_put_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n    z_reliability_t reliability = Z_RELIABILITY_DEFAULT;\n    _z_source_info_t *source_info = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    reliability = pub->reliability;\n    if (opt.source_info != NULL) {\n        source_info = opt.source_info;\n    }\n#endif\n\n    _z_encoding_t encoding;\n    if (opt.encoding == NULL) {\n        encoding = _z_encoding_alias(\n            &pub->_encoding);  // it is safe to use alias, since it will be unaffected by clear operation\n    } else {\n        encoding = _z_encoding_steal(&opt.encoding->_this._val);\n    }\n\n    _z_session_t *session = NULL;\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&pub->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_SESSION_CLOSED);\n        ret = _Z_ERR_SESSION_CLOSED;\n    }\n#else\n    session = _Z_RC_IN_VAL(&pub->_zn);\n#endif\n\n    if (session != NULL) {\n        _z_bytes_t *payload_bytes = _z_bytes_from_moved(payload);\n        _z_bytes_t *attachment_bytes = _z_bytes_from_moved(opt.attachment);\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n        if (cache != NULL) {\n            _z_timestamp_t local_timestamp = (opt.timestamp != NULL) ? *opt.timestamp : _z_timestamp_null();\n            _z_source_info_t local_source_info = (source_info != NULL) ? *source_info : _z_source_info_null();\n            _z_bytes_t local_payload = (payload_bytes != NULL) ? *payload_bytes : _z_bytes_null();\n            _z_bytes_t local_attachment = (attachment_bytes != NULL) ? *attachment_bytes : _z_bytes_null();\n\n            _z_sample_t sample;\n            z_result_t res = _z_sample_copy_data(\n                &sample, &pub->_key, &local_payload, &local_timestamp, &encoding, Z_SAMPLE_KIND_PUT,\n                _z_n_qos_make(pub->_is_express, pub->_congestion_control == Z_CONGESTION_CONTROL_BLOCK, pub->_priority),\n                &local_attachment, reliability, &local_source_info);\n            if (res == _Z_RES_OK) {\n                res = _ze_advanced_cache_add(cache, &sample);\n                if (res != _Z_RES_OK) {\n                    _Z_ERROR(\"Failed to add sample to advanced publisher cache: %i\", res);\n                    _z_sample_clear(&sample);\n                }\n            } else {\n                _Z_ERROR(\"Failed to create sample from data: %i\", res);\n            }\n        }\n#endif\n        // Check if write filter is active before writing\n        if (\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 0\n            session->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE ||\n#endif\n            !_z_write_filter_active(&pub->_filter)) {\n            // Write value\n            ret = _z_write(session, &pub->_key, payload_bytes, &encoding, Z_SAMPLE_KIND_PUT, pub->_congestion_control,\n                           pub->_priority, pub->_is_express, opt.timestamp, attachment_bytes, reliability, source_info,\n                           pub->_allowed_destination);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_SESSION_CLOSED);\n        ret = _Z_ERR_SESSION_CLOSED;\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n\n    // Clean-up\n    _z_encoding_clear(&encoding);\n    z_bytes_drop(opt.attachment);\n    z_bytes_drop(payload);\n    return ret;\n}\n\nz_result_t z_publisher_put(const z_loaned_publisher_t *pub, z_moved_bytes_t *payload,\n                           const z_publisher_put_options_t *options) {\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n    return _z_publisher_put_impl(pub, payload, options, NULL);\n#else\n    return _z_publisher_put_impl(pub, payload, options);\n#endif\n}\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\nz_result_t _z_publisher_delete_impl(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options,\n                                    _ze_advanced_cache_t *cache) {\n#else\nz_result_t _z_publisher_delete_impl(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options) {\n#endif\n    // Build options\n    z_publisher_delete_options_t opt;\n    z_publisher_delete_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n    z_reliability_t reliability = Z_RELIABILITY_DEFAULT;\n    _z_source_info_t *source_info = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    reliability = pub->reliability;\n    source_info = opt.source_info;\n#endif\n\n    _z_session_t *session = NULL;\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&pub->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n#else\n    session = _Z_RC_IN_VAL(&pub->_zn);\n#endif\n    z_result_t ret = _Z_RES_OK;\n    if (\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 0\n        session->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE ||\n#endif\n        !_z_write_filter_active(&pub->_filter)) {\n        ret = _z_write(session, &pub->_key, NULL, NULL, Z_SAMPLE_KIND_DELETE, pub->_congestion_control, pub->_priority,\n                       pub->_is_express, opt.timestamp, NULL, reliability, source_info, pub->_allowed_destination);\n    }\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n    if (cache != NULL) {\n        _z_timestamp_t cache_timestamp = (opt.timestamp != NULL) ? *opt.timestamp : _z_timestamp_null();\n        _z_source_info_t cache_source_info = (source_info != NULL) ? *source_info : _z_source_info_null();\n        _z_bytes_t payload_bytes = _z_bytes_null();\n        _z_bytes_t attachment_bytes = _z_bytes_null();\n\n        _z_sample_t sample;\n        z_result_t res = _z_sample_copy_data(\n            &sample, &pub->_key, &payload_bytes, &cache_timestamp, NULL, Z_SAMPLE_KIND_DELETE,\n            _z_n_qos_make(pub->_is_express, pub->_congestion_control == Z_CONGESTION_CONTROL_BLOCK, pub->_priority),\n            &attachment_bytes, reliability, &cache_source_info);\n        if (res == _Z_RES_OK) {\n            res = _ze_advanced_cache_add(cache, &sample);\n            if (res != _Z_RES_OK) {\n                _Z_ERROR(\"Failed to add sample to advanced publisher cache: %i\", res);\n                _z_sample_clear(&sample);\n            }\n        } else {\n            _Z_ERROR(\"Failed to create sample from data: %i\", res);\n        }\n    }\n#endif\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Clean up\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return ret;\n}\n\nz_result_t z_publisher_delete(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options) {\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n    return _z_publisher_delete_impl(pub, options, NULL);\n#else\n    return _z_publisher_delete_impl(pub, options);\n#endif\n}\n\nconst z_loaned_keyexpr_t *z_publisher_keyexpr(const z_loaned_publisher_t *publisher) {\n    return (const z_loaned_keyexpr_t *)&publisher->_key;\n}\n\n#ifdef Z_FEATURE_UNSTABLE_API\nz_entity_global_id_t z_publisher_id(const z_loaned_publisher_t *publisher) {\n    z_entity_global_id_t egid;\n    _z_session_t *session = NULL;\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&publisher->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n#else\n    session = _Z_RC_IN_VAL(&publisher->_zn);\n#endif\n\n    if (session != NULL) {\n        egid.zid = session->_local_zid;\n        egid.eid = (uint32_t)publisher->_id;\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return egid;\n}\n#endif\n\n#if Z_FEATURE_MATCHING == 1\nz_result_t z_publisher_declare_background_matching_listener(const z_loaned_publisher_t *publisher,\n                                                            z_moved_closure_matching_status_t *callback) {\n    return z_publisher_declare_matching_listener(publisher, NULL, callback);\n}\n\nz_result_t z_publisher_declare_matching_listener(const z_loaned_publisher_t *publisher,\n                                                 z_owned_matching_listener_t *matching_listener,\n                                                 z_moved_closure_matching_status_t *callback) {\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&publisher->_zn);\n    z_result_t ret = _Z_RES_OK;\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        if (matching_listener != NULL) {\n            matching_listener->_val = _z_matching_listener_null();\n            ret = _z_matching_listener_declare(&matching_listener->_val, _Z_RC_IN_VAL(&sess_rc),\n                                               &publisher->_filter.ctx, &callback->_this._val);\n        } else {\n            uint32_t _listener_id;\n            ret = _z_matching_listener_register(&_listener_id, _Z_RC_IN_VAL(&sess_rc), &publisher->_filter.ctx,\n                                                &callback->_this._val);\n        }\n        _z_session_rc_drop(&sess_rc);\n    } else {\n        if (matching_listener != NULL) {\n            matching_listener->_val = _z_matching_listener_null();\n        }\n        _z_closure_matching_status_clear(&callback->_this._val);\n        z_internal_closure_matching_status_null(&callback->_this);\n        ret = _Z_ERR_GENERIC;\n    }\n    return ret;\n}\n\nz_result_t z_publisher_get_matching_status(const z_loaned_publisher_t *publisher,\n                                           z_matching_status_t *matching_status) {\n    matching_status->matching = !_z_write_filter_active(&publisher->_filter);\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_MATCHING == 1\n\n#endif  // Z_FEATURE_PUBLICATION == 1\n\n#if Z_FEATURE_QUERY == 1\nbool _z_reply_check(const _z_reply_t *reply) {\n    if (reply->data._tag == _Z_REPLY_TAG_DATA) {\n        return _z_sample_check(&reply->data._result.sample);\n    } else if (reply->data._tag == _Z_REPLY_TAG_ERROR) {\n        return _z_value_check(&reply->data._result.error);\n    }\n    return false;\n}\n_Z_OWNED_FUNCTIONS_VALUE_IMPL(_z_reply_t, reply, _z_reply_check, _z_reply_null, _z_reply_copy, _z_reply_move,\n                              _z_reply_clear)\n\nvoid z_get_options_default(z_get_options_t *options) {\n    options->target = z_query_target_default();\n    options->consolidation = z_query_consolidation_default();\n    options->congestion_control = z_internal_congestion_control_default_request();\n    options->priority = Z_PRIORITY_DEFAULT;\n    options->is_express = false;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    options->allowed_destination = z_locality_default();\n#endif\n    options->encoding = NULL;\n    options->payload = NULL;\n    options->attachment = NULL;\n    options->timeout_ms = 0;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->source_info = NULL;\n    options->cancellation_token = NULL;\n#endif\n    options->accept_replies = z_reply_keyexpr_default();\n}\n\nz_result_t z_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, const char *parameters,\n                 z_moved_closure_reply_t *callback, z_get_options_t *options) {\n    return z_get_with_parameters_substr(zs, keyexpr, parameters, parameters == NULL ? 0 : strlen(parameters), callback,\n                                        options);\n}\n\nz_result_t z_get_with_parameters_substr(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                        const char *parameters, size_t parameters_len,\n                                        z_moved_closure_reply_t *callback, z_get_options_t *options) {\n    z_result_t ret = _Z_RES_OK;\n    _z_closure_reply_t closure = callback->_this._val;\n    z_internal_closure_reply_null(&callback->_this);\n\n    z_get_options_t opt;\n    if (options != NULL) {\n        opt = *options;\n    } else {\n        z_get_options_default(&opt);\n    }\n    if (opt.timeout_ms == 0) {\n        opt.timeout_ms = Z_GET_TIMEOUT_DEFAULT;\n    }\n    _z_source_info_t *source_info = NULL;\n    _z_cancellation_token_rc_t *cancellation_token = NULL;\n\n#ifdef Z_FEATURE_UNSTABLE_API\n    source_info = opt.source_info;\n    cancellation_token = opt.cancellation_token == NULL ? NULL : &opt.cancellation_token->_this._rc;\n#endif\n    _z_n_qos_t qos = _z_n_qos_make(opt.is_express, opt.congestion_control == Z_CONGESTION_CONTROL_BLOCK, opt.priority);\n    z_locality_t allowed_destination = z_locality_default();\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    allowed_destination = opt.allowed_destination;\n#endif\n    ret = _z_query(zs, _z_optional_id_make_none(), keyexpr, parameters, parameters_len, opt.target,\n                   opt.consolidation.mode, _z_bytes_from_moved(opt.payload), _z_encoding_from_moved(opt.encoding),\n                   closure.call, closure.drop, closure.context, opt.timeout_ms, _z_bytes_from_moved(opt.attachment),\n                   qos, source_info, opt.accept_replies, allowed_destination, cancellation_token);\n    // Clean-up\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_cancellation_token_drop(opt.cancellation_token);\n#endif\n    z_bytes_drop(opt.payload);\n    z_encoding_drop(opt.encoding);\n    z_bytes_drop(opt.attachment);\n    return ret;\n}\n\nvoid _z_querier_drop(_z_querier_t *querier) { _z_undeclare_querier(querier); }\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_querier_t, querier, _z_querier_check, _z_querier_null, _z_querier_drop)\n\nvoid z_querier_get_options_default(z_querier_get_options_t *options) {\n    options->encoding = NULL;\n    options->attachment = NULL;\n    options->payload = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->source_info = NULL;\n    options->cancellation_token = NULL;\n#endif\n}\n\nvoid z_querier_options_default(z_querier_options_t *options) {\n    options->encoding = NULL;\n    options->target = z_query_target_default();\n    options->consolidation = z_query_consolidation_default();\n    options->congestion_control = z_internal_congestion_control_default_request();\n    options->priority = Z_PRIORITY_DEFAULT;\n    options->is_express = false;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    options->allowed_destination = z_locality_default();\n#endif\n    options->timeout_ms = 0;\n    options->accept_replies = z_reply_keyexpr_default();\n}\n\nz_result_t z_declare_querier(const z_loaned_session_t *zs, z_owned_querier_t *querier,\n                             const z_loaned_keyexpr_t *keyexpr, z_querier_options_t *options) {\n    querier->_val = _z_querier_null();\n\n    // Set options\n    z_querier_options_t opt;\n    if (options != NULL) {\n        opt = *options;\n    } else {\n        z_querier_options_default(&opt);\n    }\n    if (opt.timeout_ms == 0) {\n        opt.timeout_ms = Z_GET_TIMEOUT_DEFAULT;\n    }\n    z_reliability_t reliability = Z_RELIABILITY_DEFAULT;\n    z_locality_t allowed_destination = z_locality_default();\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    allowed_destination = opt.allowed_destination;\n#endif\n\n    z_result_t res = _z_declare_querier(&querier->_val, zs, keyexpr, opt.consolidation.mode, opt.congestion_control,\n                                        opt.target, opt.priority, opt.is_express, opt.timeout_ms,\n                                        opt.encoding == NULL ? NULL : &opt.encoding->_this._val, reliability,\n                                        allowed_destination, opt.accept_replies);\n    _Z_SET_IF_OK(res,\n                 _z_write_filter_create(zs, &querier->_val._filter, &querier->_val._key, _Z_INTEREST_FLAG_QUERYABLES,\n                                        querier->_val._target == Z_QUERY_TARGET_ALL_COMPLETE, allowed_destination));\n    return res;\n}\n\nz_result_t z_undeclare_querier(z_moved_querier_t *querier) { return _z_undeclare_querier(&querier->_this._val); }\n\nz_result_t z_querier_get(const z_loaned_querier_t *querier, const char *parameters, z_moved_closure_reply_t *callback,\n                         z_querier_get_options_t *options) {\n    return z_querier_get_with_parameters_substr(querier, parameters, parameters == NULL ? 0 : strlen(parameters),\n                                                callback, options);\n}\n\nz_result_t z_querier_get_with_parameters_substr(const z_loaned_querier_t *querier, const char *parameters,\n                                                size_t parameters_len, z_moved_closure_reply_t *callback,\n                                                z_querier_get_options_t *options) {\n    z_result_t ret = _Z_RES_OK;\n    _z_closure_reply_t closure = callback->_this._val;\n    z_internal_closure_reply_null(&callback->_this);\n\n    z_querier_get_options_t opt;\n    z_querier_get_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    _z_encoding_t encoding;\n    if (opt.encoding == NULL) {\n        encoding = _z_encoding_alias(\n            &querier->_encoding);  // it is safe to use alias, since it is unaffected by clear operation\n    } else {\n        encoding = _z_encoding_steal(&opt.encoding->_this._val);\n    }\n\n    _z_session_t *session = NULL;\n\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&querier->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_SESSION_CLOSED);\n        ret = _Z_ERR_SESSION_CLOSED;\n    }\n\n    _z_source_info_t *source_info = NULL;\n    _z_cancellation_token_rc_t *cancellation_token = NULL;\n    bool should_proceed = ret == _Z_RES_OK && !_z_write_filter_active(&querier->_filter);\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 0\n    should_proceed = should_proceed || (session->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE);\n#endif\n#ifdef Z_FEATURE_UNSTABLE_API\n    source_info = opt.source_info;\n    cancellation_token = opt.cancellation_token == NULL ? NULL : &opt.cancellation_token->_this._rc;\n#endif\n    if (should_proceed) {\n        _z_n_qos_t qos = _z_n_qos_make(querier->_is_express, querier->_congestion_control == Z_CONGESTION_CONTROL_BLOCK,\n                                       querier->_priority);\n        ret = _z_query(&sess_rc, _z_optional_id_make_some(querier->_id), &querier->_key, parameters, parameters_len,\n                       querier->_target, querier->_consolidation_mode, _z_bytes_from_moved(opt.payload), &encoding,\n                       closure.call, closure.drop, closure.context, querier->_timeout_ms,\n                       _z_bytes_from_moved(opt.attachment), qos, source_info, querier->_accept_replies,\n                       querier->_allowed_destination, cancellation_token);\n    } else if (closure.drop != NULL) {\n        closure.drop(closure.context);\n    }\n\n    _z_session_rc_drop(&sess_rc);\n    // Clean-up\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_cancellation_token_drop(opt.cancellation_token);\n#endif\n    z_bytes_drop(opt.payload);\n    _z_encoding_clear(&encoding);\n    z_bytes_drop(opt.attachment);\n    return ret;\n}\n\nconst z_loaned_keyexpr_t *z_querier_keyexpr(const z_loaned_querier_t *querier) {\n    return (const z_loaned_keyexpr_t *)&querier->_key;\n}\n\n#ifdef Z_FEATURE_UNSTABLE_API\nz_entity_global_id_t z_querier_id(const z_loaned_querier_t *querier) {\n    z_entity_global_id_t egid;\n    _z_session_t *session = NULL;\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&querier->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n#else\n    session = _Z_RC_IN_VAL(&querier->_zn);\n#endif\n\n    if (session != NULL) {\n        egid.zid = session->_local_zid;\n        egid.eid = (uint32_t)querier->_id;\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return egid;\n}\n#endif\n\n#if Z_FEATURE_MATCHING == 1\nz_result_t z_querier_declare_background_matching_listener(const z_loaned_querier_t *querier,\n                                                          z_moved_closure_matching_status_t *callback) {\n    return z_querier_declare_matching_listener(querier, NULL, callback);\n}\nz_result_t z_querier_declare_matching_listener(const z_loaned_querier_t *querier,\n                                               z_owned_matching_listener_t *matching_listener,\n                                               z_moved_closure_matching_status_t *callback) {\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&querier->_zn);\n    z_result_t ret = _Z_RES_OK;\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        if (matching_listener != NULL) {\n            matching_listener->_val = _z_matching_listener_null();\n            ret = _z_matching_listener_declare(&matching_listener->_val, _Z_RC_IN_VAL(&sess_rc), &querier->_filter.ctx,\n                                               &callback->_this._val);\n        } else {\n            uint32_t _listener_id;\n            ret = _z_matching_listener_register(&_listener_id, _Z_RC_IN_VAL(&sess_rc), &querier->_filter.ctx,\n                                                &callback->_this._val);\n        }\n        _z_session_rc_drop(&sess_rc);\n    } else {\n        if (matching_listener != NULL) {\n            matching_listener->_val = _z_matching_listener_null();\n        }\n        _z_closure_matching_status_clear(&callback->_this._val);\n        z_internal_closure_matching_status_null(&callback->_this);\n        ret = _Z_ERR_GENERIC;\n    }\n    return ret;\n}\n\nz_result_t z_querier_get_matching_status(const z_loaned_querier_t *querier, z_matching_status_t *matching_status) {\n    matching_status->matching = !_z_write_filter_active(&querier->_filter);\n    return _Z_RES_OK;\n}\n\n#endif  // Z_FEATURE_MATCHING == 1\n\nbool z_reply_is_ok(const z_loaned_reply_t *reply) { return reply->data._tag != _Z_REPLY_TAG_ERROR; }\n\nconst z_loaned_sample_t *z_reply_ok(const z_loaned_reply_t *reply) { return &reply->data._result.sample; }\n\nconst z_loaned_reply_err_t *z_reply_err(const z_loaned_reply_t *reply) { return &reply->data._result.error; }\n\n#ifdef Z_FEATURE_UNSTABLE_API\nbool z_reply_replier_id(const z_loaned_reply_t *reply, z_entity_global_id_t *out_id) {\n    if (_z_entity_global_id_check(&reply->data.replier_id)) {\n        *out_id = reply->data.replier_id;\n        return true;\n    }\n    return false;\n}\n#endif  // Z_FEATURE_UNSTABLE_API\n\n#endif  // Z_FEATURE_QUERY == 1\n\n#if Z_FEATURE_QUERYABLE == 1\n_Z_OWNED_FUNCTIONS_RC_IMPL(query)\n\nz_result_t z_query_take_from_loaned(z_owned_query_t *dst, z_loaned_query_t *src) {\n    dst->_rc = *src;\n    _z_query_t q = _z_query_null();\n    *src = _z_query_rc_new_from_val(&q);\n    if (_Z_RC_IS_NULL(src)) {\n        *src = dst->_rc;  // reset src to its original value\n        z_internal_query_null(dst);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_queryable_drop(_z_queryable_t *queryable) {\n    _z_undeclare_queryable(queryable);\n    _z_queryable_clear(queryable);\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_queryable_t, queryable, _z_queryable_check, _z_queryable_null,\n                                              _z_queryable_drop)\n\nvoid z_queryable_options_default(z_queryable_options_t *options) {\n    options->complete = _Z_QUERYABLE_COMPLETE_DEFAULT;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    options->allowed_origin = z_locality_default();\n#endif\n}\n\nz_result_t z_declare_background_queryable(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                          z_moved_closure_query_t *callback, const z_queryable_options_t *options) {\n    return z_declare_queryable(zs, NULL, keyexpr, callback, options);\n}\n\nz_result_t z_declare_queryable(const z_loaned_session_t *zs, z_owned_queryable_t *queryable,\n                               const z_loaned_keyexpr_t *keyexpr, z_moved_closure_query_t *callback,\n                               const z_queryable_options_t *options) {\n    _z_closure_query_t closure = callback->_this._val;\n    z_internal_closure_query_null(&callback->_this);\n\n    z_queryable_options_t opt;\n    z_queryable_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    z_locality_t allowed_origin = z_locality_default();\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    allowed_origin = opt.allowed_origin;\n#endif\n    if (queryable != NULL) {\n        return _z_declare_queryable(&queryable->_val, zs, keyexpr, opt.complete, closure.call, closure.drop,\n                                    closure.context, allowed_origin);\n    } else {\n        uint32_t _queryable_id;\n        return _z_register_queryable(&_queryable_id, zs, keyexpr, opt.complete, closure.call, closure.drop,\n                                     closure.context, allowed_origin, NULL);\n    }\n}\n\nz_result_t z_undeclare_queryable(z_moved_queryable_t *queryable) {\n    z_result_t ret = _z_undeclare_queryable(&queryable->_this._val);\n    _z_queryable_clear(&queryable->_this._val);\n    return ret;\n}\n\nconst z_loaned_keyexpr_t *z_queryable_keyexpr(const z_loaned_queryable_t *queryable) {\n    // Retrieve keyexpr from session\n    const z_loaned_keyexpr_t *ret = NULL;\n    uint32_t lookup = queryable->_entity_id;\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&queryable->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        return ret;\n    }\n    _z_session_t *zn = _Z_RC_IN_VAL(&sess_rc);\n#else\n    _z_session_t *zn = _z_session_weak_as_unsafe_ptr(&sub->_zn);\n#endif\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to lock session for queryable keyexpr retrieval - session may be closing\");\n#if Z_FEATURE_SESSION_CHECK == 1\n        _z_session_rc_drop(&sess_rc);\n#endif\n        return ret;\n    }\n    _z_session_queryable_rc_slist_t *node = zn->_local_queryable;\n    while (node != NULL) {\n        _z_session_queryable_rc_t *val = _z_session_queryable_rc_slist_value(node);\n        if (_Z_RC_IN_VAL(val)->_id == lookup) {\n            ret = (const z_loaned_keyexpr_t *)&_Z_RC_IN_VAL(val)->_key;\n            break;\n        }\n        node = _z_session_queryable_rc_slist_next(node);\n    }\n    _z_session_mutex_unlock(zn);\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return ret;\n}\n\nvoid z_query_reply_options_default(z_query_reply_options_t *options) {\n    options->encoding = NULL;\n    options->congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n    options->priority = Z_PRIORITY_DEFAULT;\n    options->timestamp = NULL;\n    options->is_express = false;\n    options->attachment = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->source_info = NULL;\n#endif\n}\n\nz_result_t z_query_reply(const z_loaned_query_t *query, const z_loaned_keyexpr_t *keyexpr, z_moved_bytes_t *payload,\n                         const z_query_reply_options_t *options) {\n    // Try upgrading session weak to rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&_Z_RC_IN_VAL(query)->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    // Set options\n    z_query_reply_options_t opts;\n    if (options == NULL) {\n        z_query_reply_options_default(&opts);\n    } else {\n        opts = *options;\n    }\n    _z_source_info_t *source_info = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    source_info = opts.source_info;\n#endif\n    z_result_t ret = _z_send_reply(_Z_RC_IN_VAL(query), &sess_rc, keyexpr, _z_bytes_from_moved(payload),\n                                   _z_encoding_from_moved(opts.encoding), Z_SAMPLE_KIND_PUT, opts.is_express,\n                                   opts.timestamp, _z_bytes_from_moved(opts.attachment), source_info);\n    // Clean-up\n    _z_session_rc_drop(&sess_rc);\n    z_encoding_drop(opts.encoding);\n    z_bytes_drop(opts.attachment);\n    z_bytes_drop(payload);\n    return ret;\n}\n\nz_result_t _z_query_reply_sample(const z_loaned_query_t *query, z_loaned_sample_t *sample,\n                                 const z_query_reply_options_t *options) {\n    // Try upgrading session weak to rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&_Z_RC_IN_VAL(query)->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    // Set options\n    z_query_reply_options_t opts;\n    if (options == NULL) {\n        z_query_reply_options_default(&opts);\n    } else {\n        opts = *options;\n    }\n\n    z_result_t ret =\n        _z_send_reply(_Z_RC_IN_VAL(query), &sess_rc, &sample->keyexpr, &sample->payload, &sample->encoding,\n                      sample->kind, opts.is_express, &sample->timestamp, &sample->attachment, &sample->source_info);\n    // Clean-up\n    _z_session_rc_drop(&sess_rc);\n    return ret;\n}\n\nvoid z_query_reply_del_options_default(z_query_reply_del_options_t *options) {\n    options->congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n    options->priority = Z_PRIORITY_DEFAULT;\n    options->timestamp = NULL;\n    options->is_express = false;\n    options->attachment = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->source_info = NULL;\n#endif\n}\n\nz_result_t z_query_reply_del(const z_loaned_query_t *query, const z_loaned_keyexpr_t *keyexpr,\n                             const z_query_reply_del_options_t *options) {\n    // Try upgrading session weak to rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&_Z_RC_IN_VAL(query)->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    z_query_reply_del_options_t opts;\n    if (options == NULL) {\n        z_query_reply_del_options_default(&opts);\n    } else {\n        opts = *options;\n    }\n    _z_source_info_t *source_info = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    source_info = opts.source_info;\n#endif\n    z_result_t ret = _z_send_reply(_Z_RC_IN_VAL(query), &sess_rc, keyexpr, NULL, NULL, Z_SAMPLE_KIND_DELETE,\n                                   opts.is_express, opts.timestamp, _z_bytes_from_moved(opts.attachment), source_info);\n    // Clean-up\n    _z_session_rc_drop(&sess_rc);\n    z_bytes_drop(opts.attachment);\n    return ret;\n}\n\nvoid z_query_reply_err_options_default(z_query_reply_err_options_t *options) { options->encoding = NULL; }\n\nz_result_t z_query_reply_err(const z_loaned_query_t *query, z_moved_bytes_t *payload,\n                             const z_query_reply_err_options_t *options) {\n    // Try upgrading session weak to rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&_Z_RC_IN_VAL(query)->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    z_query_reply_err_options_t opts;\n    if (options == NULL) {\n        z_query_reply_err_options_default(&opts);\n    } else {\n        opts = *options;\n    }\n    z_result_t ret = _z_send_reply_err(_Z_RC_IN_VAL(query), &sess_rc, _z_bytes_from_moved(payload),\n                                       _z_encoding_from_moved(opts.encoding));\n    // Clean-up\n    _z_session_rc_drop(&sess_rc);\n    z_encoding_drop(opts.encoding);\n    z_bytes_drop(payload);\n    return ret;\n}\n\n#ifdef Z_FEATURE_UNSTABLE_API\nz_entity_global_id_t z_queryable_id(const z_loaned_queryable_t *queryable) {\n    z_entity_global_id_t egid;\n    _z_session_t *session = NULL;\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&queryable->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n#else\n    session = _Z_RC_IN_VAL(&queryable->_zn);\n#endif\n\n    if (session != NULL) {\n        egid.zid = session->_local_zid;\n        egid.eid = queryable->_entity_id;\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return egid;\n}\n#endif\n\n#endif\n\nz_result_t z_keyexpr_from_str_autocanonize(z_owned_keyexpr_t *key, const char *name) {\n    size_t len = strlen(name);\n    return z_keyexpr_from_substr_autocanonize(key, name, &len);\n}\n\nz_result_t z_keyexpr_from_substr_autocanonize(z_owned_keyexpr_t *key, const char *name, size_t *len) {\n    _Z_RETURN_IF_ERR(z_keyexpr_from_substr(key, name, *len));\n\n    _Z_CLEAN_RETURN_IF_ERR(\n        z_keyexpr_canonize((char *)_z_string_data(&key->_val._inner._keyexpr), &key->_val._inner._keyexpr._slice.len),\n        _z_declared_keyexpr_clear(&key->_val));\n    *len = _z_string_len(&key->_val._inner._keyexpr);\n    return _Z_RES_OK;\n}\n\nz_result_t z_keyexpr_from_str(z_owned_keyexpr_t *key, const char *name) {\n    return z_keyexpr_from_substr(key, name, strlen(name));\n}\n\nz_result_t z_keyexpr_from_substr(z_owned_keyexpr_t *key, const char *name, size_t len) {\n    z_internal_keyexpr_null(key);\n    return _z_declared_keyexpr_from_substr(&key->_val, name, len);\n}\n\nz_result_t z_declare_keyexpr(const z_loaned_session_t *zs, z_owned_keyexpr_t *key, const z_loaned_keyexpr_t *keyexpr) {\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 0\n    if (_Z_RC_IN_VAL(zs)->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE) {\n        _Z_WARN(\n            \"Declaring a keyexpr without Z_FEATURE_MULTICAST_DECLARATIONS might generate unknown key expression errors \"\n            \"during communications\\n\");\n    }\n#endif\n    return _z_declared_keyexpr_declare(zs, &key->_val, keyexpr);\n}\n\nz_result_t z_undeclare_keyexpr(const z_loaned_session_t *zs, z_moved_keyexpr_t *keyexpr) {\n    _z_keyexpr_wire_declaration_rc_t *declaration = &keyexpr->_this._val._declaration;\n    z_result_t ret = _Z_RES_OK;\n    if (_Z_RC_IS_NULL(declaration)) {\n        ret = _Z_ERR_INVALID;\n    } else if (!_z_keyexpr_wire_declaration_is_declared_on_session(_Z_RC_IN_VAL(declaration), _Z_RC_IN_VAL(zs))) {\n        ret = _Z_ERR_KEYEXPR_DECLARED_ON_ANOTHER_SESSION;\n    } else if (_z_keyexpr_wire_declaration_rc_strong_count(declaration) == 1) {\n        ret = _z_keyexpr_wire_declaration_undeclare(_Z_RC_IN_VAL(declaration));\n    }\n    z_keyexpr_drop(keyexpr);\n    return ret;\n}\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nvoid _z_subscriber_drop(_z_subscriber_t *sub) {\n    _z_undeclare_subscriber(sub);\n    _z_subscriber_clear(sub);\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_subscriber_t, subscriber, _z_subscriber_check, _z_subscriber_null,\n                                              _z_subscriber_drop)\n\nvoid z_subscriber_options_default(z_subscriber_options_t *options) {\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    options->allowed_origin = z_locality_default();\n#else\n    options->__dummy = 0;\n#endif\n}\n\nz_result_t z_declare_background_subscriber(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                           z_moved_closure_sample_t *callback, const z_subscriber_options_t *options) {\n    return z_declare_subscriber(zs, NULL, keyexpr, callback, options);\n}\n\nz_result_t z_declare_subscriber(const z_loaned_session_t *zs, z_owned_subscriber_t *sub,\n                                const z_loaned_keyexpr_t *keyexpr, z_moved_closure_sample_t *callback,\n                                const z_subscriber_options_t *options) {\n    _z_closure_sample_t closure = callback->_this._val;\n    z_internal_closure_sample_null(&callback->_this);\n\n    z_subscriber_options_t opt;\n    z_subscriber_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    z_locality_t allowed_origin = z_locality_default();\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    allowed_origin = opt.allowed_origin;\n#endif\n    if (sub != NULL) {\n        sub->_val = _z_subscriber_null();\n        return _z_declare_subscriber(&sub->_val, zs, keyexpr, closure.call, closure.drop, closure.context,\n                                     allowed_origin);\n    } else {\n        uint32_t _sub_id;\n        return _z_register_subscriber(&_sub_id, zs, keyexpr, closure.call, closure.drop, closure.context,\n                                      allowed_origin, NULL);\n    }\n}\n\nz_result_t z_undeclare_subscriber(z_moved_subscriber_t *sub) {\n    z_result_t ret = _z_undeclare_subscriber(&sub->_this._val);\n    _z_subscriber_clear(&sub->_this._val);\n    return ret;\n}\n\nconst z_loaned_keyexpr_t *z_subscriber_keyexpr(const z_loaned_subscriber_t *sub) {\n    const z_loaned_keyexpr_t *ret = NULL;\n    // Retrieve keyexpr from session\n    uint32_t lookup = sub->_entity_id;\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&sub->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        return ret;\n    }\n    _z_session_t *zn = _Z_RC_IN_VAL(&sess_rc);\n#else\n    _z_session_t *zn = _z_session_weak_as_unsafe_ptr(&sub->_zn);\n#endif\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to lock session for subscriber keyexpr retrieval - session may be closing\");\n#if Z_FEATURE_SESSION_CHECK == 1\n        _z_session_rc_drop(&sess_rc);\n#endif\n        return ret;\n    }\n    _z_subscription_rc_slist_t *node = zn->_subscriptions;\n    while (node != NULL) {\n        _z_subscription_rc_t *val = _z_subscription_rc_slist_value(node);\n        if (_Z_RC_IN_VAL(val)->_id == lookup) {\n            ret = (const z_loaned_keyexpr_t *)&_Z_RC_IN_VAL(val)->_key;\n            break;\n        }\n        node = _z_subscription_rc_slist_next(node);\n    }\n    _z_session_mutex_unlock(zn);\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return ret;\n}\n\n#ifdef Z_FEATURE_UNSTABLE_API\nz_entity_global_id_t z_subscriber_id(const z_loaned_subscriber_t *subscriber) {\n    z_entity_global_id_t egid;\n    _z_session_t *session = NULL;\n#if Z_FEATURE_SESSION_CHECK == 1\n    // Try to upgrade session rc\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&subscriber->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        session = _Z_RC_IN_VAL(&sess_rc);\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n#else\n    session = _Z_RC_IN_VAL(&subscriber->_zn);\n#endif\n\n    if (session != NULL) {\n        egid.zid = session->_local_zid;\n        egid.eid = subscriber->_entity_id;\n    } else {\n        egid = _z_entity_global_id_null();\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return egid;\n}\n#endif\n#endif\n\n#if Z_FEATURE_BATCHING == 1\nz_result_t zp_batch_start(const z_loaned_session_t *zs) {\n    if (_Z_RC_IS_NULL(zs)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    return _z_transport_start_batching(&session->_tp);\n}\n\nz_result_t zp_batch_flush(const z_loaned_session_t *zs) {\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    if (_Z_RC_IS_NULL(zs)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    // Send current batch without dropping\n    return _z_send_n_batch(session, Z_CONGESTION_CONTROL_BLOCK);\n}\n\nz_result_t zp_batch_stop(const z_loaned_session_t *zs) {\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    if (_Z_RC_IS_NULL(zs)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n    _Z_RETURN_IF_ERR(_z_transport_stop_batching(&session->_tp));\n    // Send remaining batch without dropping\n    return _z_send_n_batch(session, Z_CONGESTION_CONTROL_BLOCK);\n}\n#endif\n\n#if Z_FEATURE_MATCHING == 1\nvoid _z_matching_listener_drop(_z_matching_listener_t *listener) {\n    _z_matching_listener_undeclare(listener);\n    _z_matching_listener_clear(listener);\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_matching_listener_t, matching_listener, _z_matching_listener_check,\n                                              _z_matching_listener_null, _z_matching_listener_drop)\n\nz_result_t z_undeclare_matching_listener(z_moved_matching_listener_t *listener) {\n    z_result_t ret = _z_matching_listener_undeclare(&listener->_this._val);\n    _z_matching_listener_clear(&listener->_this._val);\n    return ret;\n}\n#endif\n#if Z_FEATURE_MULTI_THREAD == 1\n/**************** Tasks ****************/\nvoid zp_task_read_options_default(zp_task_read_options_t *options) { options->task_attributes = NULL; }\n\nz_result_t zp_start_read_task(z_loaned_session_t *zs, const zp_task_read_options_t *options) {\n    return _z_background_executor_start(&_Z_RC_IN_VAL(zs)->_runtime, options == NULL ? NULL : options->task_attributes);\n}\n\nz_result_t zp_stop_read_task(z_loaned_session_t *zs) {\n    return _z_runtime_stop((_z_runtime_t *)&_Z_RC_IN_VAL(zs)->_runtime);\n}\n\nbool zp_read_task_is_running(const z_loaned_session_t *zs) {\n    return _z_background_executor_is_running(&_Z_RC_IN_VAL(zs)->_runtime);\n}\n\nvoid zp_task_lease_options_default(zp_task_lease_options_t *options) { options->task_attributes = NULL; }\n\nz_result_t zp_start_lease_task(z_loaned_session_t *zs, const zp_task_lease_options_t *options) {\n    _ZP_UNUSED(zs);\n    _ZP_UNUSED(options);\n    return _Z_RES_OK;\n}\n\nz_result_t zp_stop_lease_task(z_loaned_session_t *zs) {\n    _ZP_UNUSED(zs);\n    return _Z_RES_OK;\n}\n\nbool zp_lease_task_is_running(const z_loaned_session_t *zs) {\n    return _z_background_executor_is_running(&_Z_RC_IN_VAL(zs)->_runtime);\n}\n#else\nvoid zp_read_options_default(zp_read_options_t *options) { options->single_read = false; }\n\nz_result_t zp_read(const z_loaned_session_t *zs, const zp_read_options_t *options) {\n    zp_read_options_t opt;\n    if (options != NULL) {\n        opt = *options;\n    } else {\n        zp_read_options_default(&opt);\n    }\n    return _zp_read(_Z_RC_IN_VAL(zs), opt.single_read);\n}\n\nvoid zp_send_keep_alive_options_default(zp_send_keep_alive_options_t *options) { options->__dummy = 0; }\n\nz_result_t zp_send_keep_alive(const z_loaned_session_t *zs, const zp_send_keep_alive_options_t *options) {\n    (void)(options);\n    return _zp_send_keep_alive(_Z_RC_IN_VAL(zs));\n}\n\nvoid zp_send_join_options_default(zp_send_join_options_t *options) { options->__dummy = 0; }\n\nz_result_t zp_send_join(const z_loaned_session_t *zs, const zp_send_join_options_t *options) {\n    (void)(options);\n    return _zp_send_join(_Z_RC_IN_VAL(zs));\n}\n\nvoid zp_spin_once(const z_loaned_session_t *zs) {\n    if (!z_session_is_closed(zs)) {\n        _z_runtime_spin_once((_z_runtime_t *)&_Z_RC_IN_VAL(zs)->_runtime);\n    }\n}\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\nz_reliability_t z_reliability_default(void) { return Z_RELIABILITY_DEFAULT; }\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_QUERY == 1\n\n_Z_OWNED_FUNCTIONS_RC_IMPL(cancellation_token)\n\nz_result_t z_cancellation_token_new(z_owned_cancellation_token_t *cancellation_token) {\n    _z_cancellation_token_t *ct = (_z_cancellation_token_t *)z_malloc(sizeof(_z_cancellation_token_t));\n    if (ct == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    _Z_CLEAN_RETURN_IF_ERR(_z_cancellation_token_create(ct), z_free(ct));\n\n    cancellation_token->_rc = _z_cancellation_token_rc_new(ct);\n    if (_Z_RC_IS_NULL(&cancellation_token->_rc)) {\n        _z_cancellation_token_clear(ct);\n        z_free(ct);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t z_cancellation_token_cancel(z_loaned_cancellation_token_t *cancellation_token) {\n    return _z_cancellation_token_cancel(_Z_RC_IN_VAL(cancellation_token));\n}\n\nbool z_cancellation_token_is_cancelled(const z_loaned_cancellation_token_t *cancellation_token) {\n    return _z_cancellation_token_is_cancelled(_Z_RC_IN_VAL(cancellation_token));\n}\n#endif\n#endif\n"
  },
  {
    "path": "src/api/connectivity.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdbool.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_CONNECTIVITY == 1\n\nstatic inline void _z_connectivity_transport_from_event_data(_z_info_transport_t *out,\n                                                             const _z_connectivity_peer_event_data_t *peer,\n                                                             bool is_multicast) {\n    *out = (_z_info_transport_t){0};\n    out->_zid = peer->_remote_zid;\n    out->_whatami = peer->_remote_whatami;\n    out->_is_qos = false;\n    out->_is_multicast = is_multicast;\n    out->_is_shm = false;\n}\n\nstatic z_result_t _z_connectivity_link_fill(_z_info_link_t *link, const _z_connectivity_peer_event_data_t *peer,\n                                            uint16_t mtu, bool is_streamed, bool is_reliable) {\n    *link = (_z_info_link_t){0};\n    link->_src = _z_string_null();\n    link->_dst = _z_string_null();\n    link->_zid = peer->_remote_zid;\n    link->_mtu = mtu;\n    link->_is_streamed = is_streamed;\n    link->_is_reliable = is_reliable;\n    if (_z_string_check(&peer->_link_src)) {\n        _Z_RETURN_IF_ERR(_z_string_copy(&link->_src, &peer->_link_src));\n    }\n    if (_z_string_check(&peer->_link_dst)) {\n        _Z_CLEAN_RETURN_IF_ERR(_z_string_copy(&link->_dst, &peer->_link_dst), _z_string_clear(&link->_src));\n    }\n    return _Z_RES_OK;\n}\n\nstatic inline void _z_connectivity_link_clear(_z_info_link_t *link) {\n    _z_string_clear(&link->_src);\n    _z_string_clear(&link->_dst);\n    *link = (_z_info_link_t){0};\n}\n\nstatic inline void _z_connectivity_link_event_clear(_z_info_link_event_t *event) {\n    _z_connectivity_link_clear(&event->link);\n    event->kind = Z_SAMPLE_KIND_DEFAULT;\n}\n\nstatic bool _z_connectivity_dispatch_link_put_for_peer(_z_closure_link_event_t *callback,\n                                                       const _z_transport_common_t *transport_common,\n                                                       const _z_transport_peer_common_t *peer, bool is_multicast,\n                                                       bool has_transport_filter,\n                                                       const _z_info_transport_t *transport_filter) {\n    _z_connectivity_peer_event_data_t peer_event_data = {0};\n    _z_connectivity_peer_event_data_alias_from_common(&peer_event_data, peer);\n\n    _z_info_transport_t info_transport;\n    _z_connectivity_transport_from_event_data(&info_transport, &peer_event_data, is_multicast);\n    if (has_transport_filter && !_z_info_transport_filter_match(&info_transport, transport_filter)) {\n        return true;\n    }\n\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    _z_transport_link_properties_from_transport(transport_common, &mtu, &is_streamed, &is_reliable);\n\n    _z_info_link_event_t event = {0};\n    event.kind = Z_SAMPLE_KIND_PUT;\n    if (_z_connectivity_link_fill(&event.link, &peer_event_data, mtu, is_streamed, is_reliable) != _Z_RES_OK) {\n        _z_connectivity_link_event_clear(&event);\n        return false;\n    }\n\n    callback->call(&event, callback->context);\n    _z_connectivity_link_event_clear(&event);\n    return true;\n}\n\ntypedef struct {\n    _z_closure_transport_event_t _closure;\n    _z_sync_group_notifier_t _session_callback_drop_notifier;\n    _z_sync_group_notifier_t _listener_callback_drop_notifier;\n} _z_connectivity_transport_cb_state_t;\n\ntypedef struct {\n    _z_closure_link_event_t _closure;\n    _z_sync_group_notifier_t _session_callback_drop_notifier;\n    _z_sync_group_notifier_t _listener_callback_drop_notifier;\n} _z_connectivity_link_cb_state_t;\n\nstatic void _z_connectivity_transport_cb_state_clear(_z_connectivity_transport_cb_state_t *state) {\n    if (state == NULL) {\n        return;\n    }\n    if (state->_closure.drop != NULL) {\n        state->_closure.drop(state->_closure.context);\n    }\n    state->_closure.call = NULL;\n    state->_closure.drop = NULL;\n    state->_closure.context = NULL;\n    _z_sync_group_notifier_drop(&state->_session_callback_drop_notifier);\n    _z_sync_group_notifier_drop(&state->_listener_callback_drop_notifier);\n}\n\nstatic void _z_connectivity_link_cb_state_clear(_z_connectivity_link_cb_state_t *state) {\n    if (state == NULL) {\n        return;\n    }\n    if (state->_closure.drop != NULL) {\n        state->_closure.drop(state->_closure.context);\n    }\n    state->_closure.call = NULL;\n    state->_closure.drop = NULL;\n    state->_closure.context = NULL;\n    _z_sync_group_notifier_drop(&state->_session_callback_drop_notifier);\n    _z_sync_group_notifier_drop(&state->_listener_callback_drop_notifier);\n}\n\nstatic void _z_connectivity_transport_event_callback_drop(void *callback) {\n    _z_connectivity_transport_cb_state_t *state = (_z_connectivity_transport_cb_state_t *)callback;\n    _z_connectivity_transport_cb_state_clear(state);\n}\n\nstatic void _z_connectivity_link_event_callback_drop(void *callback) {\n    _z_connectivity_link_cb_state_t *state = (_z_connectivity_link_cb_state_t *)callback;\n    _z_connectivity_link_cb_state_clear(state);\n}\n\nstatic z_result_t _z_connectivity_take_transport_callback(\n    _z_void_rc_t *out, z_moved_closure_transport_event_t *callback,\n    const _z_sync_group_t *session_callback_drop_sync_group,\n    const _z_sync_group_t *opt_listener_callback_drop_sync_group) {\n    *out = _z_void_rc_null();\n\n    _z_closure_transport_event_t closure = callback->_this._val;\n    z_internal_closure_transport_event_null(&callback->_this);\n\n    _z_connectivity_transport_cb_state_t *stored =\n        (_z_connectivity_transport_cb_state_t *)z_malloc(sizeof(_z_connectivity_transport_cb_state_t));\n    if (stored == NULL) {\n        if (closure.drop != NULL) {\n            closure.drop(closure.context);\n        }\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *stored = (_z_connectivity_transport_cb_state_t){\n        ._closure = closure,\n        ._session_callback_drop_notifier = _z_sync_group_notifier_null(),\n        ._listener_callback_drop_notifier = _z_sync_group_notifier_null(),\n    };\n\n    z_result_t ret =\n        _z_sync_group_create_notifier(session_callback_drop_sync_group, &stored->_session_callback_drop_notifier);\n    if (ret == _Z_RES_OK && opt_listener_callback_drop_sync_group != NULL &&\n        _z_sync_group_check(opt_listener_callback_drop_sync_group)) {\n        ret = _z_sync_group_create_notifier(opt_listener_callback_drop_sync_group,\n                                            &stored->_listener_callback_drop_notifier);\n    }\n    if (ret != _Z_RES_OK) {\n        _z_connectivity_transport_cb_state_clear(stored);\n        z_free(stored);\n        return ret;\n    }\n\n    *out = _z_void_rc_rc_new(stored, _z_connectivity_transport_event_callback_drop);\n    if (_Z_RC_IS_NULL(out)) {\n        _z_connectivity_transport_cb_state_clear(stored);\n        z_free(stored);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_connectivity_take_link_callback(_z_void_rc_t *out, z_moved_closure_link_event_t *callback,\n                                                     const _z_sync_group_t *session_callback_drop_sync_group,\n                                                     const _z_sync_group_t *opt_listener_callback_drop_sync_group) {\n    *out = _z_void_rc_null();\n\n    _z_closure_link_event_t closure = callback->_this._val;\n    z_internal_closure_link_event_null(&callback->_this);\n\n    _z_connectivity_link_cb_state_t *stored =\n        (_z_connectivity_link_cb_state_t *)z_malloc(sizeof(_z_connectivity_link_cb_state_t));\n    if (stored == NULL) {\n        if (closure.drop != NULL) {\n            closure.drop(closure.context);\n        }\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *stored = (_z_connectivity_link_cb_state_t){\n        ._closure = closure,\n        ._session_callback_drop_notifier = _z_sync_group_notifier_null(),\n        ._listener_callback_drop_notifier = _z_sync_group_notifier_null(),\n    };\n\n    z_result_t ret =\n        _z_sync_group_create_notifier(session_callback_drop_sync_group, &stored->_session_callback_drop_notifier);\n    if (ret == _Z_RES_OK && opt_listener_callback_drop_sync_group != NULL &&\n        _z_sync_group_check(opt_listener_callback_drop_sync_group)) {\n        ret = _z_sync_group_create_notifier(opt_listener_callback_drop_sync_group,\n                                            &stored->_listener_callback_drop_notifier);\n    }\n    if (ret != _Z_RES_OK) {\n        _z_connectivity_link_cb_state_clear(stored);\n        z_free(stored);\n        return ret;\n    }\n\n    *out = _z_void_rc_rc_new(stored, _z_connectivity_link_event_callback_drop);\n    if (_Z_RC_IS_NULL(out)) {\n        _z_connectivity_link_cb_state_clear(stored);\n        z_free(stored);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nstatic inline _z_connectivity_transport_cb_state_t *_z_connectivity_transport_listener_state(\n    const _z_connectivity_transport_listener_t *listener) {\n    return (_z_connectivity_transport_cb_state_t *)listener->_callback._val;\n}\n\nstatic inline _z_connectivity_link_cb_state_t *_z_connectivity_link_listener_state(\n    const _z_connectivity_link_listener_t *listener) {\n    return (_z_connectivity_link_cb_state_t *)listener->_callback._val;\n}\n\nstatic inline _z_closure_transport_event_t *_z_connectivity_transport_listener_callback(\n    const _z_connectivity_transport_listener_t *listener) {\n    _z_connectivity_transport_cb_state_t *state = _z_connectivity_transport_listener_state(listener);\n    return state != NULL ? &state->_closure : NULL;\n}\n\nstatic inline _z_closure_link_event_t *_z_connectivity_link_listener_callback(\n    const _z_connectivity_link_listener_t *listener) {\n    _z_connectivity_link_cb_state_t *state = _z_connectivity_link_listener_state(listener);\n    return state != NULL ? &state->_closure : NULL;\n}\n\nstatic void _z_connectivity_dispatch_transport_event(_z_session_t *session, _z_info_transport_event_t *event) {\n    _z_connectivity_transport_listener_intmap_t snapshot = _z_connectivity_transport_listener_intmap_make();\n\n    _z_session_mutex_lock(session);\n    snapshot = _z_connectivity_transport_listener_intmap_clone(&session->_connectivity_transport_event_listeners);\n    _z_session_mutex_unlock(session);\n\n    _z_connectivity_transport_listener_intmap_iterator_t it =\n        _z_connectivity_transport_listener_intmap_iterator_make(&snapshot);\n    while (_z_connectivity_transport_listener_intmap_iterator_next(&it)) {\n        _z_connectivity_transport_listener_t *listener = _z_connectivity_transport_listener_intmap_iterator_value(&it);\n        _z_closure_transport_event_t *closure = _z_connectivity_transport_listener_callback(listener);\n        if (closure != NULL && closure->call != NULL) {\n            closure->call(event, closure->context);\n        }\n    }\n\n    _z_connectivity_transport_listener_intmap_clear(&snapshot);\n}\n\nstatic void _z_connectivity_dispatch_link_event(_z_session_t *session, _z_info_link_event_t *event, bool is_multicast) {\n    _z_connectivity_link_listener_intmap_t snapshot = _z_connectivity_link_listener_intmap_make();\n\n    _z_session_mutex_lock(session);\n    snapshot = _z_connectivity_link_listener_intmap_clone(&session->_connectivity_link_event_listeners);\n    _z_session_mutex_unlock(session);\n\n    _z_connectivity_link_listener_intmap_iterator_t it = _z_connectivity_link_listener_intmap_iterator_make(&snapshot);\n    while (_z_connectivity_link_listener_intmap_iterator_next(&it)) {\n        _z_connectivity_link_listener_t *listener = _z_connectivity_link_listener_intmap_iterator_value(&it);\n        if (listener->_has_transport_filter && (!_z_id_eq(&listener->_transport_zid, &event->link._zid) ||\n                                                listener->_transport_is_multicast != is_multicast)) {\n            continue;\n        }\n\n        _z_closure_link_event_t *closure = _z_connectivity_link_listener_callback(listener);\n        if (closure != NULL && closure->call != NULL) {\n            closure->call(event, closure->context);\n        }\n    }\n\n    _z_connectivity_link_listener_intmap_clear(&snapshot);\n}\n\nstatic void _z_connectivity_replay_transport_history(_z_session_t *session,\n                                                     _z_connectivity_transport_cb_state_t *callback_state) {\n    if (callback_state == NULL || callback_state->_closure.call == NULL) {\n        return;\n    }\n    _z_closure_transport_event_t *callback = &callback_state->_closure;\n\n    _z_transport_t *transport = &session->_tp;\n    _z_transport_common_t *transport_common = _z_transport_get_common(transport);\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_lock(transport_common);\n    }\n\n    switch (transport->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_peer_unicast_slist_t *curr = transport->_transport._unicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_unicast_slist_next(curr)) {\n                _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(curr);\n                _z_info_transport_event_t event = {0};\n                event.kind = Z_SAMPLE_KIND_PUT;\n                _z_info_transport_from_peer(&event.transport, &peer->common, false);\n                callback->call(&event, callback->context);\n            }\n            break;\n        }\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            _z_transport_peer_multicast_slist_t *curr = transport->_transport._multicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_multicast_slist_next(curr)) {\n                _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(curr);\n                _z_info_transport_event_t event = {0};\n                event.kind = Z_SAMPLE_KIND_PUT;\n                _z_info_transport_from_peer(&event.transport, &peer->common, true);\n                callback->call(&event, callback->context);\n            }\n            break;\n        }\n        default:\n            break;\n    }\n\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_unlock(transport_common);\n    }\n}\n\nstatic void _z_connectivity_replay_link_history(_z_session_t *session, _z_connectivity_link_cb_state_t *callback_state,\n                                                bool has_transport_filter,\n                                                const _z_info_transport_t *transport_filter) {\n    if (callback_state == NULL || callback_state->_closure.call == NULL) {\n        return;\n    }\n    _z_closure_link_event_t *callback = &callback_state->_closure;\n\n    _z_transport_t *transport = &session->_tp;\n    _z_transport_common_t *transport_common = _z_transport_get_common(transport);\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_lock(transport_common);\n    }\n\n    switch (transport->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_peer_unicast_slist_t *curr = transport->_transport._unicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_unicast_slist_next(curr)) {\n                _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(curr);\n                if (!_z_connectivity_dispatch_link_put_for_peer(callback, transport_common, &peer->common, false,\n                                                                has_transport_filter, transport_filter)) {\n                    break;\n                }\n            }\n            break;\n        }\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            _z_transport_peer_multicast_slist_t *curr = transport->_transport._multicast._peers;\n            for (; curr != NULL; curr = _z_transport_peer_multicast_slist_next(curr)) {\n                _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(curr);\n                if (!_z_connectivity_dispatch_link_put_for_peer(callback, transport_common, &peer->common, true,\n                                                                has_transport_filter, transport_filter)) {\n                    break;\n                }\n            }\n            break;\n        }\n        default:\n            break;\n    }\n\n    if (transport_common != NULL) {\n        _z_transport_peer_mutex_unlock(transport_common);\n    }\n}\n\nbool _z_transport_events_listener_check(const _z_transport_events_listener_t *listener) {\n    return !_Z_RC_IS_NULL(&listener->_session);\n}\n\n_z_transport_events_listener_t _z_transport_events_listener_null(void) { return (_z_transport_events_listener_t){0}; }\n\nvoid _z_transport_events_listener_clear(_z_transport_events_listener_t *listener) {\n    _z_session_weak_drop(&listener->_session);\n    _z_sync_group_drop(&listener->_callback_drop_sync_group);\n    *listener = _z_transport_events_listener_null();\n}\n\nstatic z_result_t _z_transport_events_listener_undeclare(_z_transport_events_listener_t *listener) {\n    _z_session_rc_t session_rc = _z_session_weak_upgrade(&listener->_session);\n    if (!_Z_RC_IS_NULL(&session_rc)) {\n        _z_session_t *session = _Z_RC_IN_VAL(&session_rc);\n        _z_session_mutex_lock(session);\n        _z_connectivity_transport_listener_intmap_remove(&session->_connectivity_transport_event_listeners,\n                                                         listener->_id);\n        _z_session_mutex_unlock(session);\n        _z_session_rc_drop(&session_rc);\n    }\n\n    if (_z_sync_group_check(&listener->_callback_drop_sync_group)) {\n        return _z_sync_group_wait(&listener->_callback_drop_sync_group);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_transport_events_listener_drop(_z_transport_events_listener_t *listener) {\n    _z_transport_events_listener_undeclare(listener);\n    _z_transport_events_listener_clear(listener);\n}\n\nbool _z_link_events_listener_check(const _z_link_events_listener_t *listener) {\n    return !_Z_RC_IS_NULL(&listener->_session);\n}\n\n_z_link_events_listener_t _z_link_events_listener_null(void) { return (_z_link_events_listener_t){0}; }\n\nvoid _z_link_events_listener_clear(_z_link_events_listener_t *listener) {\n    _z_session_weak_drop(&listener->_session);\n    _z_sync_group_drop(&listener->_callback_drop_sync_group);\n    *listener = _z_link_events_listener_null();\n}\n\nstatic z_result_t _z_link_events_listener_undeclare(_z_link_events_listener_t *listener) {\n    _z_session_rc_t session_rc = _z_session_weak_upgrade(&listener->_session);\n    if (!_Z_RC_IS_NULL(&session_rc)) {\n        _z_session_t *session = _Z_RC_IN_VAL(&session_rc);\n        _z_session_mutex_lock(session);\n        _z_connectivity_link_listener_intmap_remove(&session->_connectivity_link_event_listeners, listener->_id);\n        _z_session_mutex_unlock(session);\n        _z_session_rc_drop(&session_rc);\n    }\n\n    if (_z_sync_group_check(&listener->_callback_drop_sync_group)) {\n        return _z_sync_group_wait(&listener->_callback_drop_sync_group);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_link_events_listener_drop(_z_link_events_listener_t *listener) {\n    _z_link_events_listener_undeclare(listener);\n    _z_link_events_listener_clear(listener);\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_transport_events_listener_t, transport_events_listener,\n                                              _z_transport_events_listener_check, _z_transport_events_listener_null,\n                                              _z_transport_events_listener_drop)\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_link_events_listener_t, link_events_listener,\n                                              _z_link_events_listener_check, _z_link_events_listener_null,\n                                              _z_link_events_listener_drop)\n\nvoid z_transport_events_listener_options_default(z_transport_events_listener_options_t *options) {\n    options->history = false;\n}\n\nvoid z_link_events_listener_options_default(z_link_events_listener_options_t *options) {\n    options->history = false;\n    options->transport = NULL;\n}\n\nz_result_t z_declare_transport_events_listener(const z_loaned_session_t *zs,\n                                               z_owned_transport_events_listener_t *listener,\n                                               z_moved_closure_transport_event_t *callback,\n                                               const z_transport_events_listener_options_t *options) {\n    listener->_val = _z_transport_events_listener_null();\n\n    if (zs == NULL || _Z_RC_IS_NULL(zs)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n\n    z_transport_events_listener_options_t opt;\n    z_transport_events_listener_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    _z_sync_group_t callback_drop_sync_group = _z_sync_group_null();\n    _Z_RETURN_IF_ERR(_z_sync_group_create(&callback_drop_sync_group));\n\n    _z_void_rc_t callback_rc;\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_connectivity_take_transport_callback(&callback_rc, callback, &_Z_RC_IN_VAL(zs)->_callback_drop_sync_group,\n                                                &callback_drop_sync_group),\n        _z_sync_group_drop(&callback_drop_sync_group));\n\n    _z_connectivity_transport_listener_t *listener_state =\n        (_z_connectivity_transport_listener_t *)z_malloc(sizeof(_z_connectivity_transport_listener_t));\n    if (listener_state == NULL) {\n        _z_void_rc_drop(&callback_rc);\n        _z_sync_group_drop(&callback_drop_sync_group);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *listener_state = (_z_connectivity_transport_listener_t){._callback = callback_rc};\n\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    _z_transport_common_t *locked_transport_common = NULL;\n    z_result_t ret = _Z_RES_OK;\n    size_t id = 0;\n    bool listener_registered = false;\n    if (opt.history) {\n        locked_transport_common = _z_transport_get_common(&session->_tp);\n        if (locked_transport_common != NULL) {\n            _z_transport_peer_mutex_lock(locked_transport_common);\n        }\n    }\n\n    if (opt.history) {\n        _z_void_rc_t callback_snapshot = _z_void_rc_clone(&callback_rc);\n        if (_Z_RC_IS_NULL(&callback_snapshot)) {\n            ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            goto exit;\n        }\n\n        _z_connectivity_transport_cb_state_t *callback_state =\n            (_z_connectivity_transport_cb_state_t *)callback_snapshot._val;\n        _z_connectivity_replay_transport_history(session, callback_state);\n        _z_void_rc_drop(&callback_snapshot);\n    }\n\n    ret = _z_session_mutex_lock_if_open(session);\n    if (ret != _Z_RES_OK) {\n        goto exit;\n    }\n    id = session->_connectivity_next_listener_id++;\n    if (_z_connectivity_transport_listener_intmap_insert(&session->_connectivity_transport_event_listeners, id,\n                                                         listener_state) == NULL) {\n        _z_session_mutex_unlock(session);\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto exit;\n    }\n    listener_registered = true;\n    _z_session_mutex_unlock(session);\n\n    _z_session_weak_t weak = _z_session_rc_clone_as_weak(zs);\n    if (_Z_RC_IS_NULL(&weak)) {\n        _z_session_mutex_lock(session);\n        _z_connectivity_transport_listener_intmap_remove(&session->_connectivity_transport_event_listeners, id);\n        _z_session_mutex_unlock(session);\n        listener_registered = false;\n        listener_state = NULL;\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto exit;\n    }\n\n    listener->_val = (_z_transport_events_listener_t){\n        ._id = id,\n        ._session = weak,\n        ._callback_drop_sync_group = callback_drop_sync_group,\n    };\n    callback_drop_sync_group = _z_sync_group_null();\n\nexit:\n    if (!listener_registered && listener_state != NULL) {\n        _z_connectivity_transport_listener_clear(listener_state);\n        z_free(listener_state);\n    }\n    if (locked_transport_common != NULL) {\n        _z_transport_peer_mutex_unlock(locked_transport_common);\n    }\n    _z_sync_group_drop(&callback_drop_sync_group);\n    return ret;\n}\n\nz_result_t z_declare_background_transport_events_listener(const z_loaned_session_t *zs,\n                                                          z_moved_closure_transport_event_t *callback,\n                                                          const z_transport_events_listener_options_t *options) {\n    z_owned_transport_events_listener_t listener;\n    _Z_RETURN_IF_ERR(z_declare_transport_events_listener(zs, &listener, callback, options));\n    _z_transport_events_listener_clear(&listener._val);\n    return _Z_RES_OK;\n}\n\nz_result_t z_undeclare_transport_events_listener(z_moved_transport_events_listener_t *listener) {\n    z_result_t ret = _z_transport_events_listener_undeclare(&listener->_this._val);\n    _z_transport_events_listener_clear(&listener->_this._val);\n    return ret;\n}\n\nz_result_t z_declare_link_events_listener(const z_loaned_session_t *zs, z_owned_link_events_listener_t *listener,\n                                          z_moved_closure_link_event_t *callback,\n                                          z_link_events_listener_options_t *options) {\n    listener->_val = _z_link_events_listener_null();\n\n    if (zs == NULL || _Z_RC_IS_NULL(zs)) {\n        _Z_ERROR_RETURN(_Z_ERR_SESSION_CLOSED);\n    }\n\n    z_link_events_listener_options_t opt;\n    z_link_events_listener_options_default(&opt);\n    if (options != NULL) {\n        opt = *options;\n    }\n\n    _z_sync_group_t callback_drop_sync_group = _z_sync_group_null();\n    _Z_RETURN_IF_ERR(_z_sync_group_create(&callback_drop_sync_group));\n\n    _z_void_rc_t callback_rc;\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_connectivity_take_link_callback(&callback_rc, callback, &_Z_RC_IN_VAL(zs)->_callback_drop_sync_group,\n                                           &callback_drop_sync_group),\n        _z_sync_group_drop(&callback_drop_sync_group));\n\n    bool has_transport_filter = false;\n    _z_id_t transport_filter_zid = {0};\n    bool transport_filter_is_multicast = false;\n    z_result_t ret = _Z_RES_OK;\n\n    if (opt.transport != NULL) {\n        if (!z_internal_transport_check(&opt.transport->_this)) {\n            ret = _Z_ERR_INVALID;\n        } else {\n            const z_loaned_transport_t *transport = z_transport_loan(&opt.transport->_this);\n            has_transport_filter = true;\n            transport_filter_zid = transport->_zid;\n            transport_filter_is_multicast = transport->_is_multicast;\n        }\n    }\n\n    z_transport_drop(opt.transport);\n\n    if (ret != _Z_RES_OK) {\n        _z_void_rc_drop(&callback_rc);\n        _z_sync_group_drop(&callback_drop_sync_group);\n        return ret;\n    }\n\n    _z_connectivity_link_listener_t *listener_state =\n        (_z_connectivity_link_listener_t *)z_malloc(sizeof(_z_connectivity_link_listener_t));\n    if (listener_state == NULL) {\n        _z_void_rc_drop(&callback_rc);\n        _z_sync_group_drop(&callback_drop_sync_group);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    *listener_state = (_z_connectivity_link_listener_t){\n        ._callback = callback_rc,\n        ._has_transport_filter = has_transport_filter,\n        ._transport_zid = transport_filter_zid,\n        ._transport_is_multicast = transport_filter_is_multicast,\n    };\n\n    _z_session_t *session = _Z_RC_IN_VAL(zs);\n    _z_transport_common_t *locked_transport_common = NULL;\n    size_t id = 0;\n    bool listener_registered = false;\n    if (opt.history) {\n        locked_transport_common = _z_transport_get_common(&session->_tp);\n        if (locked_transport_common != NULL) {\n            _z_transport_peer_mutex_lock(locked_transport_common);\n        }\n    }\n\n    if (opt.history) {\n        _z_void_rc_t callback_snapshot = _z_void_rc_clone(&callback_rc);\n        if (_Z_RC_IS_NULL(&callback_snapshot)) {\n            ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            goto exit;\n        }\n\n        _z_info_transport_t transport_filter = {0};\n        transport_filter._zid = transport_filter_zid;\n        transport_filter._is_multicast = transport_filter_is_multicast;\n        _z_connectivity_link_cb_state_t *callback_state = (_z_connectivity_link_cb_state_t *)callback_snapshot._val;\n        _z_connectivity_replay_link_history(session, callback_state, has_transport_filter, &transport_filter);\n        _z_void_rc_drop(&callback_snapshot);\n    }\n\n    ret = _z_session_mutex_lock_if_open(session);\n    if (ret != _Z_RES_OK) {\n        goto exit;\n    }\n    id = session->_connectivity_next_listener_id++;\n    if (_z_connectivity_link_listener_intmap_insert(&session->_connectivity_link_event_listeners, id, listener_state) ==\n        NULL) {\n        _z_session_mutex_unlock(session);\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto exit;\n    }\n    listener_registered = true;\n    _z_session_mutex_unlock(session);\n\n    _z_session_weak_t weak = _z_session_rc_clone_as_weak(zs);\n    if (_Z_RC_IS_NULL(&weak)) {\n        _z_session_mutex_lock(session);\n        _z_connectivity_link_listener_intmap_remove(&session->_connectivity_link_event_listeners, id);\n        _z_session_mutex_unlock(session);\n        listener_registered = false;\n        listener_state = NULL;\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto exit;\n    }\n\n    listener->_val = (_z_link_events_listener_t){\n        ._id = id,\n        ._session = weak,\n        ._callback_drop_sync_group = callback_drop_sync_group,\n    };\n    callback_drop_sync_group = _z_sync_group_null();\n\nexit:\n    if (!listener_registered && listener_state != NULL) {\n        _z_connectivity_link_listener_clear(listener_state);\n        z_free(listener_state);\n    }\n    if (locked_transport_common != NULL) {\n        _z_transport_peer_mutex_unlock(locked_transport_common);\n    }\n    _z_sync_group_drop(&callback_drop_sync_group);\n    return ret;\n}\n\nz_result_t z_declare_background_link_events_listener(const z_loaned_session_t *zs,\n                                                     z_moved_closure_link_event_t *callback,\n                                                     z_link_events_listener_options_t *options) {\n    z_owned_link_events_listener_t listener;\n    _Z_RETURN_IF_ERR(z_declare_link_events_listener(zs, &listener, callback, options));\n    _z_link_events_listener_clear(&listener._val);\n    return _Z_RES_OK;\n}\n\nz_result_t z_undeclare_link_events_listener(z_moved_link_events_listener_t *listener) {\n    z_result_t ret = _z_link_events_listener_undeclare(&listener->_this._val);\n    _z_link_events_listener_clear(&listener->_this._val);\n    return ret;\n}\n\nvoid _z_connectivity_peer_connected(_z_session_t *session, const _z_connectivity_peer_event_data_t *peer,\n                                    bool is_multicast, uint16_t mtu, bool is_streamed, bool is_reliable) {\n    if (session == NULL || peer == NULL) {\n        return;\n    }\n\n    _z_info_transport_event_t transport_event = {0};\n    transport_event.kind = Z_SAMPLE_KIND_PUT;\n    _z_connectivity_transport_from_event_data(&transport_event.transport, peer, is_multicast);\n    _z_connectivity_dispatch_transport_event(session, &transport_event);\n\n    _z_info_link_event_t link_event = {0};\n    link_event.kind = Z_SAMPLE_KIND_PUT;\n    if (_z_connectivity_link_fill(&link_event.link, peer, mtu, is_streamed, is_reliable) == _Z_RES_OK) {\n        _z_connectivity_dispatch_link_event(session, &link_event, is_multicast);\n    }\n    _z_connectivity_link_event_clear(&link_event);\n}\n\nvoid _z_connectivity_peer_disconnected(_z_session_t *session, const _z_connectivity_peer_event_data_t *peer,\n                                       bool is_multicast, uint16_t mtu, bool is_streamed, bool is_reliable) {\n    if (session == NULL || peer == NULL) {\n        return;\n    }\n\n    _z_info_link_event_t link_event = {0};\n    link_event.kind = Z_SAMPLE_KIND_DELETE;\n    if (_z_connectivity_link_fill(&link_event.link, peer, mtu, is_streamed, is_reliable) == _Z_RES_OK) {\n        _z_connectivity_dispatch_link_event(session, &link_event, is_multicast);\n    }\n    _z_connectivity_link_event_clear(&link_event);\n\n    _z_info_transport_event_t transport_event = {0};\n    transport_event.kind = Z_SAMPLE_KIND_DELETE;\n    _z_connectivity_transport_from_event_data(&transport_event.transport, peer, is_multicast);\n    _z_connectivity_dispatch_transport_event(session, &transport_event);\n}\n\nvoid _z_connectivity_peer_disconnected_from_transport(_z_session_t *session, const _z_transport_common_t *transport,\n                                                      const _z_connectivity_peer_event_data_t *peer,\n                                                      bool is_multicast) {\n    if (peer == NULL) {\n        return;\n    }\n\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    _z_transport_link_properties_from_transport(transport, &mtu, &is_streamed, &is_reliable);\n\n    _z_connectivity_peer_disconnected(session, peer, is_multicast, mtu, is_streamed, is_reliable);\n}\n\n#endif\n"
  },
  {
    "path": "src/api/encoding.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#if Z_FEATURE_ENCODING_VALUES == 1\n#define ENCODING_SCHEMA_SEPARATOR ';'\n\n#define ENCODING_CONSTANT_MACRO(_cname, _fname, _id)                                                                \\\n    const z_owned_encoding_t ZP_ENCODING_##_cname = {                                                               \\\n        ._val = {                                                                                                   \\\n            .id = _id,                                                                                              \\\n            .schema = {._slice = {.start = NULL, .len = 0, ._delete_context = {.deleter = NULL, .context = NULL}}}, \\\n        }};                                                                                                         \\\n    const z_loaned_encoding_t *z_encoding_##_fname(void) { return &ZP_ENCODING_##_cname._val; }\n\nENCODING_CONSTANT_MACRO(ZENOH_BYTES, zenoh_bytes, 0)\nENCODING_CONSTANT_MACRO(ZENOH_STRING, zenoh_string, 1)\nENCODING_CONSTANT_MACRO(ZENOH_SERIALIZED, zenoh_serialized, 2)\nENCODING_CONSTANT_MACRO(APPLICATION_OCTET_STREAM, application_octet_stream, 3)\nENCODING_CONSTANT_MACRO(TEXT_PLAIN, text_plain, 4)\nENCODING_CONSTANT_MACRO(APPLICATION_JSON, application_json, 5)\nENCODING_CONSTANT_MACRO(TEXT_JSON, text_json, 6)\nENCODING_CONSTANT_MACRO(APPLICATION_CDR, application_cdr, 7)\nENCODING_CONSTANT_MACRO(APPLICATION_CBOR, application_cbor, 8)\nENCODING_CONSTANT_MACRO(APPLICATION_YAML, application_yaml, 9)\nENCODING_CONSTANT_MACRO(TEXT_YAML, text_yaml, 10)\nENCODING_CONSTANT_MACRO(TEXT_JSON5, text_json5, 11)\nENCODING_CONSTANT_MACRO(APPLICATION_PYTHON_SERIALIZED_OBJECT, application_python_serialized_object, 12)\nENCODING_CONSTANT_MACRO(APPLICATION_PROTOBUF, application_protobuf, 13)\nENCODING_CONSTANT_MACRO(APPLICATION_JAVA_SERIALIZED_OBJECT, application_java_serialized_object, 14)\nENCODING_CONSTANT_MACRO(APPLICATION_OPENMETRICS_TEXT, application_openmetrics_text, 15)\nENCODING_CONSTANT_MACRO(IMAGE_PNG, image_png, 16)\nENCODING_CONSTANT_MACRO(IMAGE_JPEG, image_jpeg, 17)\nENCODING_CONSTANT_MACRO(IMAGE_GIF, image_gif, 18)\nENCODING_CONSTANT_MACRO(IMAGE_BMP, image_bmp, 19)\nENCODING_CONSTANT_MACRO(IMAGE_WEBP, image_webp, 20)\nENCODING_CONSTANT_MACRO(APPLICATION_XML, application_xml, 21)\nENCODING_CONSTANT_MACRO(APPLICATION_X_WWW_FORM_URLENCODED, application_x_www_form_urlencoded, 22)\nENCODING_CONSTANT_MACRO(TEXT_HTML, text_html, 23)\nENCODING_CONSTANT_MACRO(TEXT_XML, text_xml, 24)\nENCODING_CONSTANT_MACRO(TEXT_CSS, text_css, 25)\nENCODING_CONSTANT_MACRO(TEXT_JAVASCRIPT, text_javascript, 26)\nENCODING_CONSTANT_MACRO(TEXT_MARKDOWN, text_markdown, 27)\nENCODING_CONSTANT_MACRO(TEXT_CSV, text_csv, 28)\nENCODING_CONSTANT_MACRO(APPLICATION_SQL, application_sql, 29)\nENCODING_CONSTANT_MACRO(APPLICATION_COAP_PAYLOAD, application_coap_payload, 30)\nENCODING_CONSTANT_MACRO(APPLICATION_JSON_PATCH_JSON, application_json_patch_json, 31)\nENCODING_CONSTANT_MACRO(APPLICATION_JSON_SEQ, application_json_seq, 32)\nENCODING_CONSTANT_MACRO(APPLICATION_JSONPATH, application_jsonpath, 33)\nENCODING_CONSTANT_MACRO(APPLICATION_JWT, application_jwt, 34)\nENCODING_CONSTANT_MACRO(APPLICATION_MP4, application_mp4, 35)\nENCODING_CONSTANT_MACRO(APPLICATION_SOAP_XML, application_soap_xml, 36)\nENCODING_CONSTANT_MACRO(APPLICATION_YANG, application_yang, 37)\nENCODING_CONSTANT_MACRO(AUDIO_AAC, audio_aac, 38)\nENCODING_CONSTANT_MACRO(AUDIO_FLAC, audio_flac, 39)\nENCODING_CONSTANT_MACRO(AUDIO_MP4, audio_mp4, 40)\nENCODING_CONSTANT_MACRO(AUDIO_OGG, audio_ogg, 41)\nENCODING_CONSTANT_MACRO(AUDIO_VORBIS, audio_vorbis, 42)\nENCODING_CONSTANT_MACRO(VIDEO_H261, video_h261, 43)\nENCODING_CONSTANT_MACRO(VIDEO_H263, video_h263, 44)\nENCODING_CONSTANT_MACRO(VIDEO_H264, video_h264, 45)\nENCODING_CONSTANT_MACRO(VIDEO_H265, video_h265, 46)\nENCODING_CONSTANT_MACRO(VIDEO_H266, video_h266, 47)\nENCODING_CONSTANT_MACRO(VIDEO_MP4, video_mp4, 48)\nENCODING_CONSTANT_MACRO(VIDEO_OGG, video_ogg, 49)\nENCODING_CONSTANT_MACRO(VIDEO_RAW, video_raw, 50)\nENCODING_CONSTANT_MACRO(VIDEO_VP8, video_vp8, 51)\nENCODING_CONSTANT_MACRO(VIDEO_VP9, video_vp9, 52)\n\nconst char *ENCODING_VALUES_ID_TO_STR[] = {\n    \"zenoh/bytes\",\n    \"zenoh/string\",\n    \"zenoh/serialized\",\n    \"application/octet-stream\",\n    \"text/plain\",\n    \"application/json\",\n    \"text/json\",\n    \"application/cdr\",\n    \"application/cbor\",\n    \"application/yaml\",\n    \"text/yaml\",\n    \"text/json5\",\n    \"application/python-serialized-object\",\n    \"application/protobuf\",\n    \"application/java-serialized-object\",\n    \"application/openmetrics-text\",\n    \"image/png\",\n    \"image/jpeg\",\n    \"image/gif\",\n    \"image/bmp\",\n    \"image/webp\",\n    \"application/xml\",\n    \"application/x-www-form-urlencoded\",\n    \"text/html\",\n    \"text/xml\",\n    \"text/css\",\n    \"text/javascript\",\n    \"text/markdown\",\n    \"text/csv\",\n    \"application/sql\",\n    \"application/coap-payload\",\n    \"application/json-patch+json\",\n    \"application/json-seq\",\n    \"application/jsonpath\",\n    \"application/jwt\",\n    \"application/mp4\",\n    \"application/soap+xml\",\n    \"application/yang\",\n    \"audio/aac\",\n    \"audio/flac\",\n    \"audio/mp4\",\n    \"audio/ogg\",\n    \"audio/vorbis\",\n    \"video/h261\",\n    \"video/h263\",\n    \"video/h264\",\n    \"video/h265\",\n    \"video/h266\",\n    \"video/mp4\",\n    \"video/ogg\",\n    \"video/raw\",\n    \"video/vp8\",\n    \"video/vp9\",\n};\n\nstatic uint16_t _z_encoding_values_str_to_int(const char *schema, size_t len) {\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(ENCODING_VALUES_ID_TO_STR); i++) {\n        if (strncmp(schema, ENCODING_VALUES_ID_TO_STR[i], len) == 0) {\n            return (uint16_t)i;\n        }\n    }\n    return UINT16_MAX;\n}\n\nstatic z_result_t _z_encoding_convert_from_substr(z_owned_encoding_t *encoding, const char *s, size_t len) {\n    size_t pos = 0;\n    for (; pos < len; ++pos) {\n        if (s[pos] == ENCODING_SCHEMA_SEPARATOR) break;\n    }\n\n    // Check id_end value + corner cases\n    if (pos != 0) {\n        uint16_t id = _z_encoding_values_str_to_int(s, pos);\n        // Check id\n        if (id != UINT16_MAX) {\n            const char *ptr = NULL;\n            size_t remaining = 0;\n            if (pos + 1 < len) {\n                ptr = s + pos + 1;\n                remaining = len - pos - 1;\n            }\n            return _z_encoding_make(&encoding->_val, id, ptr, remaining);\n        }\n    }\n    // By default store the string as schema\n    return _z_encoding_make(&encoding->_val, _Z_ENCODING_ID_DEFAULT, s, len);\n}\n\nstatic z_result_t _z_encoding_convert_into_string(const z_loaned_encoding_t *encoding, z_owned_string_t *s) {\n    const char *prefix = NULL;\n    size_t prefix_len = 0;\n    // Convert id\n    if (encoding->id < _ZP_ARRAY_SIZE(ENCODING_VALUES_ID_TO_STR)) {\n        prefix = ENCODING_VALUES_ID_TO_STR[encoding->id];\n        prefix_len = strlen(prefix);\n    }\n    bool has_schema = _z_string_len(&encoding->schema) > 0;\n    // Size include null terminator\n    size_t total_len = prefix_len + _z_string_len(&encoding->schema) + 1;\n    // Check for schema separator\n    if (has_schema) {\n        total_len += 1;\n    }\n    // Allocate string\n    char *value = (char *)z_malloc(sizeof(char) * total_len);\n    if (value == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    memset(value, 0, total_len);\n    // Copy prefix\n    (void)strncpy(value, prefix, prefix_len);\n    // Copy schema and separator\n    if (has_schema) {\n        _z_str_append(value, ENCODING_SCHEMA_SEPARATOR);\n        (void)strncat(value, _z_string_data(&encoding->schema), _z_string_len(&encoding->schema));\n    }\n    // Fill container\n    s->_val = _z_string_from_str_custom_deleter(value, _z_delete_context_default());\n    return _Z_RES_OK;\n}\n\n#else\nstatic z_result_t _z_encoding_convert_from_substr(z_owned_encoding_t *encoding, const char *s, size_t len) {\n    return _z_encoding_make(&encoding->_val, _Z_ENCODING_ID_DEFAULT, s, len);\n}\n\nstatic z_result_t _z_encoding_convert_into_string(const z_loaned_encoding_t *encoding, z_owned_string_t *s) {\n    _z_string_copy(&s->_val, &encoding->schema);\n    return _Z_RES_OK;\n}\n#endif\n\nz_result_t z_encoding_from_str(z_owned_encoding_t *encoding, const char *s) {\n    // Init owned encoding\n    z_internal_encoding_null(encoding);\n    // Convert string to encoding\n    if (s != NULL) {\n        return _z_encoding_convert_from_substr(encoding, s, strlen(s));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t z_encoding_from_substr(z_owned_encoding_t *encoding, const char *s, size_t len) {\n    // Init owned encoding\n    z_internal_encoding_null(encoding);\n    // Convert string to encoding\n    if (s != NULL) {\n        return _z_encoding_convert_from_substr(encoding, s, len);\n    }\n    return _Z_RES_OK;\n}\nz_result_t z_encoding_set_schema_from_str(z_loaned_encoding_t *encoding, const char *schema) {\n    return z_encoding_set_schema_from_substr(encoding, schema, strlen(schema));\n}\n\nz_result_t z_encoding_set_schema_from_substr(z_loaned_encoding_t *encoding, const char *schema, size_t len) {\n    _z_string_clear(&encoding->schema);\n    if (schema == NULL && len > 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    encoding->schema = _z_string_copy_from_substr(schema, len);\n    if (_z_string_len(&encoding->schema) != len) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t z_encoding_to_string(const z_loaned_encoding_t *encoding, z_owned_string_t *s) {\n    // Init owned string\n    z_internal_string_null(s);\n    // Convert encoding to string\n    _z_encoding_convert_into_string(encoding, s);\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_ENCODING_VALUES == 1\nconst z_loaned_encoding_t *z_encoding_loan_default(void) { return z_encoding_zenoh_bytes(); }\n#endif\n"
  },
  {
    "path": "src/api/liveliness.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/api/liveliness.h\"\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/net/liveliness.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_LIVELINESS == 1\n\n/**************** Liveliness Token ****************/\n\nbool _z_liveliness_token_check(const _z_liveliness_token_t *token) { return !_Z_RC_IS_NULL(&token->_zn); }\n\n_z_liveliness_token_t _z_liveliness_token_null(void) {\n    _z_liveliness_token_t s = {0};\n    return s;\n}\n\nz_result_t _z_liveliness_token_clear(_z_liveliness_token_t *token) {\n    z_result_t ret = _Z_RES_OK;\n    if (_Z_RC_IS_NULL(&token->_zn)) {\n        return ret;\n    }\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&token->_zn);\n    if (!_Z_RC_IS_NULL(&sess_rc)) {\n        ret = _z_undeclare_liveliness_token(token);\n        _z_session_rc_drop(&sess_rc);\n    }\n    _z_session_weak_drop(&token->_zn);\n    *token = _z_liveliness_token_null();\n\n    return ret;\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_NO_MOVE_IMPL(_z_liveliness_token_t, liveliness_token, _z_liveliness_token_check,\n                                              _z_liveliness_token_null, _z_liveliness_token_clear)\n\nz_result_t z_liveliness_token_options_default(z_liveliness_token_options_t *options) {\n    options->__dummy = 0;\n    return _Z_RES_OK;\n}\n\nz_result_t z_liveliness_declare_token(const z_loaned_session_t *zs, z_owned_liveliness_token_t *token,\n                                      const z_loaned_keyexpr_t *keyexpr, const z_liveliness_token_options_t *options) {\n    (void)options;\n    return _z_declare_liveliness_token(zs, &token->_val, keyexpr);\n}\n\nz_result_t z_liveliness_undeclare_token(z_moved_liveliness_token_t *token) {\n    return _z_liveliness_token_clear(&token->_this._val);\n}\n\n/**************** Liveliness Subscriber ****************/\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nz_result_t z_liveliness_subscriber_options_default(z_liveliness_subscriber_options_t *options) {\n    options->history = false;\n    return _Z_RES_OK;\n}\n\nz_result_t z_liveliness_declare_subscriber(const z_loaned_session_t *zs, z_owned_subscriber_t *sub,\n                                           const z_loaned_keyexpr_t *keyexpr, z_moved_closure_sample_t *callback,\n                                           z_liveliness_subscriber_options_t *options) {\n    _z_closure_sample_t closure = callback->_this._val;\n    z_internal_closure_sample_null(&callback->_this);\n\n    z_liveliness_subscriber_options_t opt;\n    if (options == NULL) {\n        z_liveliness_subscriber_options_default(&opt);\n    } else {\n        opt = *options;\n    }\n\n    if (sub != NULL) {\n        sub->_val = _z_subscriber_null();\n        return _z_declare_liveliness_subscriber(&sub->_val, zs, keyexpr, closure.call, closure.drop, opt.history,\n                                                closure.context);\n    } else {\n        uint32_t _sub_id;\n        return _z_register_liveliness_subscriber(&_sub_id, zs, keyexpr, closure.call, closure.drop, opt.history,\n                                                 closure.context, NULL);\n    }\n}\n\nz_result_t z_liveliness_declare_background_subscriber(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                                      z_moved_closure_sample_t *callback,\n                                                      z_liveliness_subscriber_options_t *options) {\n    return z_liveliness_declare_subscriber(zs, NULL, keyexpr, callback, options);\n}\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n/**************** Liveliness Query ****************/\n\n#if Z_FEATURE_QUERY == 1\nz_result_t z_liveliness_get_options_default(z_liveliness_get_options_t *options) {\n    options->timeout_ms = 0;\n#ifdef Z_FEATURE_UNSTABLE_API\n    options->cancellation_token = NULL;\n#endif\n    return _Z_RES_OK;\n}\n\nz_result_t z_liveliness_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                            z_moved_closure_reply_t *callback, z_liveliness_get_options_t *options) {\n    z_result_t ret = _Z_RES_OK;\n\n    void *ctx = callback->_this._val.context;\n    callback->_this._val.context = NULL;\n\n    z_liveliness_get_options_t opt;\n    if (options == NULL) {\n        z_liveliness_get_options_default(&opt);\n    } else {\n        opt = *options;\n    }\n    if (opt.timeout_ms == 0) {\n        opt.timeout_ms = Z_GET_TIMEOUT_DEFAULT;\n    }\n\n    _z_cancellation_token_rc_t *cancellation_token = NULL;\n#ifdef Z_FEATURE_UNSTABLE_API\n    cancellation_token = opt.cancellation_token == NULL ? NULL : &opt.cancellation_token->_this._rc;\n#else\n\n#endif\n    ret = _z_liveliness_query(zs, keyexpr, callback->_this._val.call, callback->_this._val.drop, ctx, opt.timeout_ms,\n                              cancellation_token);\n\n#ifdef Z_FEATURE_UNSTABLE_API\n    z_cancellation_token_drop(opt.cancellation_token);\n#endif\n    z_internal_closure_reply_null(\n        &callback->_this);  // call and drop passed to _z_liveliness_query, so we nullify the closure here\n    return ret;\n}\n#endif  // Z_FEATURE_QUERY == 1\n\n#endif  // Z_FEATURE_LIVELINESS == 1\n"
  },
  {
    "path": "src/api/serialization.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#include \"zenoh-pico/api/serialization.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/protocol/codec/core.h\"\n\nbool _ze_serializer_check(const _ze_serializer_t *serializer) { return _z_bytes_writer_check(&serializer->_writer); }\n\n_ze_serializer_t _ze_serializer_empty(void) {\n    _ze_serializer_t s;\n    s._writer = _z_bytes_writer_empty();\n    return s;\n}\n\nvoid _ze_serializer_clear(_ze_serializer_t *serializer) { _z_bytes_writer_clear(&serializer->_writer); }\nz_result_t _ze_serializer_move(_ze_serializer_t *dst, _ze_serializer_t *src) {\n    return _z_bytes_writer_move(&dst->_writer, &src->_writer);\n}\n\n_Z_OWNED_FUNCTIONS_VALUE_NO_COPY_IMPL_PREFIX(ze, _ze_serializer_t, serializer, _ze_serializer_check,\n                                             _ze_serializer_empty, _ze_serializer_move, _ze_serializer_clear)\n\nz_result_t ze_serializer_empty(ze_owned_serializer_t *serializer) {\n    serializer->_val._writer = _z_bytes_writer_empty();\n    return _Z_RES_OK;\n}\n\nvoid ze_serializer_finish(ze_moved_serializer_t *serializer, z_owned_bytes_t *bytes) {\n    bytes->_val = _z_bytes_writer_finish(&serializer->_this._val._writer);\n}\n\nze_deserializer_t ze_deserializer_from_bytes(const z_loaned_bytes_t *bytes) {\n    ze_deserializer_t d;\n    d._reader = z_bytes_get_reader(bytes);\n    return d;\n}\n\nz_result_t __read_single_byte(uint8_t *b, void *context) {\n    z_bytes_reader_t *reader = (z_bytes_reader_t *)context;\n    if (_z_bytes_reader_read(reader, b, 1) != 1) {\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t __read_zint(z_bytes_reader_t *reader, _z_zint_t *zint) {\n    return _z_zsize_decode_with_reader(zint, __read_single_byte, reader);\n}\n\nz_result_t ze_serializer_serialize_sequence_length(ze_loaned_serializer_t *serializer, size_t len) {\n    uint8_t buf[16];\n    size_t bytes_used = _z_zsize_encode_buf(buf, len);\n    return _z_bytes_writer_write_all(&serializer->_writer, buf, bytes_used);\n}\n\nz_result_t ze_deserializer_deserialize_sequence_length(ze_deserializer_t *deserializer, size_t *len) {\n    return __read_zint(&deserializer->_reader, len);\n}\n\nz_result_t ze_serializer_serialize_buf(ze_loaned_serializer_t *serializer, const uint8_t *val, size_t len) {\n    _Z_RETURN_IF_ERR(ze_serializer_serialize_sequence_length(serializer, len));\n    _Z_RETURN_IF_ERR(_z_bytes_writer_write_all(&serializer->_writer, val, len));\n    return Z_OK;\n}\n\nz_result_t ze_serializer_serialize_slice(ze_loaned_serializer_t *serializer, const z_loaned_slice_t *val) {\n    return ze_serializer_serialize_buf(serializer, z_slice_data(val), z_slice_len(val));\n}\n\nz_result_t ze_deserializer_deserialize_slice(ze_deserializer_t *deserializer, z_owned_slice_t *val) {\n    size_t len = 0;\n    _Z_RETURN_IF_ERR(ze_deserializer_deserialize_sequence_length(deserializer, &len));\n    _Z_RETURN_IF_ERR(_z_slice_init(&val->_val, len));\n    if (z_bytes_reader_read(&deserializer->_reader, (uint8_t *)val->_val.start, len) != len) {\n        _z_slice_clear(&val->_val);\n        _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    };\n    return Z_OK;\n}\n\nz_result_t ze_serializer_serialize_substr(ze_loaned_serializer_t *serializer, const char *start, size_t len) {\n    // TODO: perform a UTF-8 correctness check.\n    return ze_serializer_serialize_buf(serializer, (const uint8_t *)start, len);\n}\n\nz_result_t ze_serializer_serialize_str(ze_loaned_serializer_t *serializer, const char *val) {\n    return ze_serializer_serialize_substr(serializer, val, strlen(val));\n}\n\nz_result_t ze_serializer_serialize_string(ze_loaned_serializer_t *serializer, const z_loaned_string_t *val) {\n    return ze_serializer_serialize_buf(serializer, (const uint8_t *)z_string_data(val), z_string_len(val));\n}\n\nz_result_t ze_deserializer_deserialize_string(ze_deserializer_t *deserializer, z_owned_string_t *val) {\n    z_owned_slice_t s;\n    _Z_RETURN_IF_ERR(ze_deserializer_deserialize_slice(deserializer, &s));\n    val->_val._slice = s._val;\n    return _Z_RES_OK;\n}\n\n#define _Z_BUILD_BYTES_FROM_SERIALIZER(expr)                         \\\n    z_bytes_empty(bytes);                                            \\\n    _ze_serializer_t serializer = _ze_serializer_empty();            \\\n    _Z_CLEAN_RETURN_IF_ERR(expr, _ze_serializer_clear(&serializer)); \\\n    bytes->_val = _z_bytes_writer_finish(&serializer._writer);\n\nz_result_t ze_serialize_buf(z_owned_bytes_t *bytes, const uint8_t *data, size_t len) {\n    _Z_BUILD_BYTES_FROM_SERIALIZER(ze_serializer_serialize_buf(&serializer, data, len));\n    return _Z_RES_OK;\n}\n\nz_result_t ze_serialize_slice(z_owned_bytes_t *bytes, const z_loaned_slice_t *data) {\n    _Z_BUILD_BYTES_FROM_SERIALIZER(ze_serializer_serialize_slice(&serializer, data));\n    return _Z_RES_OK;\n}\n\nz_result_t ze_deserialize_slice(const z_loaned_bytes_t *bytes, z_owned_slice_t *data) {\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(bytes);\n    return ze_deserializer_deserialize_slice(&deserializer, data);\n}\n\nz_result_t ze_serialize_substr(z_owned_bytes_t *bytes, const char *start, size_t len) {\n    _Z_BUILD_BYTES_FROM_SERIALIZER(ze_serializer_serialize_substr(&serializer, start, len));\n    return _Z_RES_OK;\n}\n\nz_result_t ze_serialize_str(z_owned_bytes_t *bytes, const char *data) {\n    _Z_BUILD_BYTES_FROM_SERIALIZER(ze_serializer_serialize_str(&serializer, data));\n    return _Z_RES_OK;\n}\n\nz_result_t ze_serialize_string(z_owned_bytes_t *bytes, const z_loaned_string_t *data) {\n    _Z_BUILD_BYTES_FROM_SERIALIZER(ze_serializer_serialize_string(&serializer, data));\n    return _Z_RES_OK;\n}\n\nz_result_t ze_deserialize_string(const z_loaned_bytes_t *bytes, z_owned_string_t *data) {\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(bytes);\n    return ze_deserializer_deserialize_string(&deserializer, data);\n}\n\n#define _Z_IMPLEMENT_ZBYTES_ARITHMETIC(suffix, type)                                        \\\n    z_result_t ze_serialize_##suffix(z_owned_bytes_t *bytes, type data) {                   \\\n        _Z_BUILD_BYTES_FROM_SERIALIZER(ze_serializer_serialize_##suffix(&serializer, data)) \\\n        return _Z_RES_OK;                                                                   \\\n    }                                                                                       \\\n    z_result_t ze_deserialize_##suffix(const z_loaned_bytes_t *bytes, type *data) {         \\\n        ze_deserializer_t deserializer = ze_deserializer_from_bytes(bytes);                 \\\n        z_result_t err = ze_deserializer_deserialize_##suffix(&deserializer, data);         \\\n        if (err == Z_OK && !ze_deserializer_is_done(&deserializer)) {                       \\\n            err = Z_EDESERIALIZE;                                                           \\\n        }                                                                                   \\\n        return err;                                                                         \\\n    }\n\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(uint8, uint8_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(uint16, uint16_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(uint32, uint32_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(uint64, uint64_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(int8, int8_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(int16, int16_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(int32, int32_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(int64, int64_t)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(float, float)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(double, double)\n_Z_IMPLEMENT_ZBYTES_ARITHMETIC(bool, bool)\n\nbool ze_deserializer_is_done(const ze_deserializer_t *deserializer) {\n    return _z_bytes_reader_remaining(&deserializer->_reader) == 0;\n}\n"
  },
  {
    "path": "src/collections/advanced_cache.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include \"zenoh-pico/collections/advanced_cache.h\"\n\n#include <ctype.h>\n#include <limits.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n#include \"zenoh-pico/utils/time_range.h\"\n\n#define _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED -1\n#define _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_MAX_UNBOUNDED SIZE_MAX\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1\n\ntypedef struct {\n    int64_t start;\n    int64_t end;\n} _ze_advanced_cache_range_t;\n\ntypedef struct {\n    _ze_advanced_cache_range_t range;\n    size_t max;\n    _z_time_range_t time;\n} _ze_advanced_cache_query_parameters_t;\n\nstatic bool _ze_advanced_cache_query_match_key(const char *key_start, size_t key_len, const char *expected_key,\n                                               size_t expected_key_len) {\n    return (key_len == expected_key_len && strncmp(key_start, expected_key, key_len) == 0);\n}\n\nstatic void _ze_advanced_cache_query_parse_max(const _z_str_se_t *str, size_t *max) {\n    *max = _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_MAX_UNBOUNDED;\n    if (_z_ptr_char_diff(str->end, str->start) > 0) {\n        uint32_t value;\n        if (_z_str_se_atoui(str, &value)) {\n            *max = value;\n        }\n    }\n}\n\nstatic void _ze_advanced_cache_query_parse_range(const _z_str_se_t *str, _ze_advanced_cache_range_t *range) {\n    range->start = _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED;\n    range->end = _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED;\n\n    if (_z_ptr_char_diff(str->end, str->start) > 0) {\n        _z_splitstr_t ss = {.s = *str, .delimiter = \"..\"};\n\n        _z_str_se_t token = _z_splitstr_next(&ss);\n        uint32_t value;\n        if (_z_str_se_atoui(&token, &value)) {\n            range->start = value;\n        }\n        token = _z_splitstr_next(&ss);\n        if (_z_str_se_atoui(&token, &value)) {\n            range->end = value;\n        }\n    }\n}\n\nstatic void _ze_advanced_cache_query_parse_time(const _z_str_se_t *str, _z_time_range_t *time) {\n    _z_time_range_t range;\n    if (_z_time_range_from_str(str->start, _z_ptr_char_diff(str->end, str->start), &range)) {\n        *time = range;\n    } else {\n        time->start.bound = _Z_TIME_BOUND_UNBOUNDED;\n        time->end.bound = _Z_TIME_BOUND_UNBOUNDED;\n    }\n}\n\nstatic void _ze_advanced_cache_query_parse_parameters(_ze_advanced_cache_query_parameters_t *params,\n                                                      const z_loaned_string_t *raw_params) {\n    params->range.start = _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED;\n    params->range.end = _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED;\n    params->max = _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_MAX_UNBOUNDED;\n    params->time.start.bound = _Z_TIME_BOUND_UNBOUNDED;\n    params->time.end.bound = _Z_TIME_BOUND_UNBOUNDED;\n\n    _z_str_se_t str;\n    str.start = z_string_data(raw_params);\n    str.end = str.start + z_string_len(raw_params);\n    while (str.start != NULL) {\n        _z_query_param_t param = _z_query_params_next(&str);\n        if (param.key.start != NULL) {\n            size_t key_len = _z_ptr_char_diff(param.key.end, param.key.start);\n            if (_ze_advanced_cache_query_match_key(param.key.start, key_len, _Z_QUERY_PARAMS_KEY_RANGE,\n                                                   _Z_QUERY_PARAMS_KEY_RANGE_LEN)) {\n                _ze_advanced_cache_query_parse_range(&param.value, &params->range);\n            } else if (_ze_advanced_cache_query_match_key(param.key.start, key_len, _Z_QUERY_PARAMS_KEY_MAX,\n                                                          _Z_QUERY_PARAMS_KEY_MAX_LEN)) {\n                _ze_advanced_cache_query_parse_max(&param.value, &params->max);\n            } else if (_ze_advanced_cache_query_match_key(param.key.start, key_len, _Z_QUERY_PARAMS_KEY_TIME,\n                                                          _Z_QUERY_PARAMS_KEY_TIME_LEN)) {\n                _ze_advanced_cache_query_parse_time(&param.value, &params->time);\n            }\n        }\n    }\n}\n\nstatic bool _ze_advanced_cache_range_contains(const _ze_advanced_cache_range_t *range, uint32_t sn) {\n    return ((range->start == _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED || range->start <= sn) &&\n            (range->end == _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED || sn <= range->end));\n}\n\nstatic void _ze_advanced_cache_query_handler(z_loaned_query_t *query, void *ctx) {\n    _ze_advanced_cache_t *cache = (_ze_advanced_cache_t *)ctx;\n\n    z_view_string_t param_str;\n    z_query_parameters(query, &param_str);\n\n    _ze_advanced_cache_query_parameters_t params;\n    _ze_advanced_cache_query_parse_parameters(&params, z_view_string_loan(&param_str));\n\n    _z_time_since_epoch now;\n    z_result_t res = _z_get_time_since_epoch(&now);\n    if (res != _Z_RES_OK) {\n        _Z_ERROR(\"Dropped advanced cache query - failed to determine current system time: %i\", res);\n        return;\n    }\n    _z_ntp64_t now_ntp64 = _z_timestamp_ntp64_from_time(now.secs, now.nanos);\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    res = _z_mutex_lock(&cache->_outbox_mutex);\n    if (res != _Z_RES_OK) {\n        _Z_ERROR(\"Dropped advanced cache query - failed to lock outbox mutex: %i\", res);\n        return;\n    }\n    res = _z_mutex_lock(&cache->_mutex);\n    if (res != _Z_RES_OK) {\n        _Z_ERROR(\"Dropped advanced cache query - failed to lock mutex: %i\", res);\n        _z_mutex_unlock(&cache->_outbox_mutex);\n        return;\n    }\n#endif\n    size_t cap = _z_sample_ring_capacity(&cache->_cache);\n    size_t max = (params.max != _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_MAX_UNBOUNDED) ? params.max : cap;\n    if (max > cap) max = cap;\n    if (max > cache->_outbox_cap) max = cache->_outbox_cap;\n\n    const bool range_filter = (params.range.start != _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED) ||\n                              (params.range.end != _ZE_ADVANCED_CACHE_QUERY_PARAMETERS_RANGE_UNBOUNDED);\n    const bool time_filter =\n        (params.time.start.bound != _Z_TIME_BOUND_UNBOUNDED) || (params.time.end.bound != _Z_TIME_BOUND_UNBOUNDED);\n\n    _z_sample_ring_reverse_iterator_t iter = _z_sample_ring_reverse_iterator_make(&cache->_cache);\n\n    size_t to_send = 0;\n    while (max > 0 && _z_sample_ring_reverse_iterator_next(&iter)) {\n        _z_sample_t *sample = _z_sample_ring_reverse_iterator_value(&iter);\n        if (range_filter && (!_z_source_info_check(&sample->source_info) ||\n                             !_ze_advanced_cache_range_contains(&params.range, sample->source_info._source_sn))) {\n            continue;\n        }\n        if (time_filter && (!_z_timestamp_check(&sample->timestamp) ||\n                            !_z_time_range_contains_at_time(&params.time, sample->timestamp.time, now_ntp64))) {\n            continue;\n        }\n\n        res = _z_sample_copy(&cache->_outbox[to_send], sample);\n        if (res != _Z_RES_OK) {\n            _Z_ERROR(\"Sample dropped from advanced cache query reply - failed to copy sample: %i\", res);\n        } else {\n            to_send++;\n            max--;\n        }\n    }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_unlock(&cache->_mutex);\n#endif\n\n    z_query_reply_options_t opt;\n    z_query_reply_options_default(&opt);\n    opt.congestion_control = cache->_congestion_control;\n    opt.priority = cache->_priority;\n    opt.is_express = cache->_is_express;\n\n    // Send samples in order\n    while (to_send > 0) {\n        to_send--;\n        _z_sample_t *sample = &cache->_outbox[to_send];\n        res = _z_query_reply_sample(query, sample, &opt);\n        _z_sample_clear(sample);\n        if (res != _Z_RES_OK) {\n            _Z_ERROR(\"Sample dropped from advanced cache query reply - failed to send sample: %i\", res);\n        }\n    }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_unlock(&cache->_outbox_mutex);\n#endif\n}\n\nstatic z_result_t _ze_advanced_cache_init(_ze_advanced_cache_t *cache, const z_loaned_session_t *zs,\n                                          const z_loaned_keyexpr_t *keyexpr, const z_loaned_keyexpr_t *suffix,\n                                          const ze_advanced_publisher_cache_options_t options) {\n    if (options.max_samples == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    _Z_RETURN_IF_ERR(_z_sample_ring_init(&cache->_cache, options.max_samples));\n    cache->_outbox_cap = options.max_samples;\n    cache->_outbox = (_z_sample_t *)z_malloc(sizeof(_z_sample_t) * cache->_outbox_cap);\n    if (cache->_outbox == NULL) {\n        _z_sample_ring_clear(&cache->_cache);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    memset(cache->_outbox, 0, sizeof(_z_sample_t) * cache->_outbox_cap);\n\n    cache->_congestion_control = options.congestion_control;\n    cache->_priority = options.priority;\n    cache->_is_express = options.is_express;\n\n    z_owned_keyexpr_t ke;\n    z_internal_keyexpr_null(&ke);\n    if (suffix != NULL) {\n        _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_join(&ke, keyexpr, suffix), _z_sample_ring_clear(&cache->_cache);\n                               z_free(cache->_outbox); cache->_outbox = NULL);\n    } else {\n        _Z_CLEAN_RETURN_IF_ERR(z_keyexpr_clone(&ke, keyexpr), _z_sample_ring_clear(&cache->_cache);\n                               z_free(cache->_outbox); cache->_outbox = NULL);\n    }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_CLEAN_RETURN_IF_ERR(_z_mutex_init(&cache->_mutex), z_keyexpr_drop(z_keyexpr_move(&ke));\n                           _z_sample_ring_clear(&cache->_cache); z_free(cache->_outbox); cache->_outbox = NULL);\n    _Z_CLEAN_RETURN_IF_ERR(_z_mutex_init(&cache->_outbox_mutex), z_keyexpr_drop(z_keyexpr_move(&ke));\n                           _z_sample_ring_clear(&cache->_cache); z_free(cache->_outbox); cache->_outbox = NULL;\n                           _z_mutex_drop(&cache->_mutex));\n#endif\n\n    z_result_t res = _Z_RES_OK;\n    z_internal_liveliness_token_null(&cache->_liveliness);\n    if (options._liveliness) {\n        res = z_liveliness_declare_token(zs, &cache->_liveliness, z_keyexpr_loan(&ke), NULL);\n        if (res != _Z_RES_OK) {\n            z_keyexpr_drop(z_keyexpr_move(&ke));\n            _z_sample_ring_clear(&cache->_cache);\n            z_free(cache->_outbox);\n            cache->_outbox = NULL;\n#if Z_FEATURE_MULTI_THREAD == 1\n            _z_mutex_drop(&cache->_mutex);\n            _z_mutex_drop(&cache->_outbox_mutex);\n#endif\n            _Z_ERROR_RETURN(res);\n        }\n    }\n\n    z_internal_queryable_null(&cache->_queryable);\n    z_owned_closure_query_t callback;\n    res = z_closure_query(&callback, _ze_advanced_cache_query_handler, NULL, cache);\n    if (res != _Z_RES_OK) {\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n        z_liveliness_token_drop(z_liveliness_token_move(&cache->_liveliness));\n        _z_sample_ring_clear(&cache->_cache);\n        z_free(cache->_outbox);\n        cache->_outbox = NULL;\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_drop(&cache->_mutex);\n        _z_mutex_drop(&cache->_outbox_mutex);\n#endif\n        _Z_ERROR_RETURN(res);\n    }\n    res = z_declare_queryable(zs, &cache->_queryable, z_keyexpr_loan(&ke), z_closure_query_move(&callback), NULL);\n    if (res != _Z_RES_OK) {\n        z_keyexpr_drop(z_keyexpr_move(&ke));\n        z_liveliness_token_drop(z_liveliness_token_move(&cache->_liveliness));\n        z_closure_query_drop(z_closure_query_move(&callback));\n        _z_sample_ring_clear(&cache->_cache);\n        z_free(cache->_outbox);\n        cache->_outbox = NULL;\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_drop(&cache->_mutex);\n        _z_mutex_drop(&cache->_outbox_mutex);\n#endif\n        _Z_ERROR_RETURN(res);\n    }\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n\n    return res;\n}\n\n_ze_advanced_cache_t *_ze_advanced_cache_new(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr,\n                                             const z_loaned_keyexpr_t *suffix,\n                                             const ze_advanced_publisher_cache_options_t options) {\n    _ze_advanced_cache_t *cache = (_ze_advanced_cache_t *)z_malloc(sizeof(_ze_advanced_cache_t));\n    if (cache == NULL) {\n        _Z_ERROR(\"Failed to create advanced cache: out of memory\");\n        return NULL;\n    }\n\n    z_result_t ret = _ze_advanced_cache_init(cache, zs, keyexpr, suffix, options);\n    if (ret != _Z_RES_OK) {\n        z_free(cache);\n        return NULL;\n    }\n\n    return cache;\n}\n\nz_result_t _ze_advanced_cache_add(_ze_advanced_cache_t *cache, _z_sample_t *sample) {\n    if (cache == NULL || sample == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    _z_sample_t *s = (_z_sample_t *)z_malloc(sizeof(_z_sample_t));\n    if (s == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    _Z_CLEAN_RETURN_IF_ERR(_z_sample_move(s, sample), z_free((void *)s));\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_CLEAN_RETURN_IF_ERR(_z_mutex_lock(&cache->_mutex), z_free((void *)s));\n#endif\n    _z_sample_ring_push_force_drop(&cache->_cache, s);\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_unlock(&cache->_mutex);\n#endif\n\n    return _Z_RES_OK;\n}\n\nvoid _ze_advanced_cache_free(_ze_advanced_cache_t **pcache) {\n    _ze_advanced_cache_t *cache = (_ze_advanced_cache_t *)*pcache;\n    if (cache != NULL) {\n        z_queryable_drop(z_queryable_move(&cache->_queryable));\n        z_liveliness_token_drop(z_liveliness_token_move(&cache->_liveliness));\n\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_lock(&cache->_outbox_mutex);\n        _z_mutex_lock(&cache->_mutex);\n#endif\n        _z_sample_ring_clear(&cache->_cache);\n        z_free(cache->_outbox);\n\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_unlock(&cache->_mutex);\n        _z_mutex_drop(&cache->_mutex);\n        _z_mutex_unlock(&cache->_outbox_mutex);\n        _z_mutex_drop(&cache->_outbox_mutex);\n#endif\n\n        z_free(cache);\n        *pcache = NULL;\n    }\n}\n\n#endif  // Z_FEATURE_ADVANCED_PUBLICATION == 1\n"
  },
  {
    "path": "src/collections/arc_slice.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/arc_slice.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n\n_z_arc_slice_t _z_arc_slice_wrap(_z_slice_t* s, size_t offset, size_t len) {\n    assert(offset + len <= s->len);\n    _z_arc_slice_t arc_s;\n\n    arc_s.slice = _z_slice_simple_rc_new_from_val(s);\n    if (_z_slice_simple_rc_is_null(&arc_s.slice)) {\n        return _z_arc_slice_empty();\n    }\n    arc_s.len = len;\n    arc_s.start = offset;\n    return arc_s;\n}\n\n_z_arc_slice_t _z_arc_slice_get_subslice(const _z_arc_slice_t* s, size_t offset, size_t len) {\n    assert(offset + len <= s->len);\n    assert(!_z_slice_simple_rc_is_null(&s->slice) || (len == 0 && offset == 0));\n\n    _z_arc_slice_t out;\n    out.slice = _z_slice_simple_rc_clone(&s->slice);\n    out.len = len;\n    out.start = s->start + offset;\n    return out;\n}\n\nz_result_t _z_arc_slice_copy(_z_arc_slice_t* dst, const _z_arc_slice_t* src) {\n    _z_slice_simple_rc_copy(&dst->slice, &src->slice);\n    dst->len = src->len;\n    dst->start = src->start;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_arc_slice_move(_z_arc_slice_t* dst, _z_arc_slice_t* src) {\n    dst->slice = src->slice;\n    dst->len = src->len;\n    dst->start = src->start;\n    src->len = 0;\n    src->start = 0;\n    src->slice = _z_slice_simple_rc_null();\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/collections/atomic.c",
    "content": "#include \"zenoh-pico/collections/atomic.h\"\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#if ZENOH_C_STANDARD != 99\n#ifndef __cplusplus\n#include <stdatomic.h>\ntypedef _Atomic(size_t) _z_atomic_t;\n_Static_assert(sizeof(size_t) == sizeof(_z_atomic_t), \"_Atomic(size_t) must have same size as size_t\");\nstatic const memory_order _z_memory_order_map[] = {memory_order_relaxed, memory_order_acquire, memory_order_release,\n                                                   memory_order_acq_rel, memory_order_seq_cst};\nvoid _z_atomic_size_init(_z_atomic_size_t *var, size_t value) { atomic_init((_z_atomic_t *)&var->_value, value); }\nsize_t _z_atomic_size_load(_z_atomic_size_t *var, _z_memory_order_t order) {\n    return atomic_load_explicit((_z_atomic_t *)&var->_value, _z_memory_order_map[order]);\n}\nvoid _z_atomic_size_store(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    atomic_store_explicit((_z_atomic_t *)&var->_value, val, _z_memory_order_map[order]);\n}\nsize_t _z_atomic_size_fetch_add(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    return atomic_fetch_add_explicit((_z_atomic_t *)&var->_value, val, _z_memory_order_map[order]);\n}\nsize_t _z_atomic_size_fetch_sub(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    return atomic_fetch_sub_explicit((_z_atomic_t *)&var->_value, val, _z_memory_order_map[order]);\n}\nbool _z_atomic_size_compare_exchange_strong(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                            _z_memory_order_t success, _z_memory_order_t failure) {\n    // to silence C4100 warning on MSVC\n    (void)success;\n    (void)failure;\n    return atomic_compare_exchange_strong_explicit((_z_atomic_t *)&var->_value, expected, desired,\n                                                   _z_memory_order_map[success], _z_memory_order_map[failure]);\n}\nbool _z_atomic_size_compare_exchange_weak(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                          _z_memory_order_t success, _z_memory_order_t failure) {\n    // to silence C4100 warning on MSVC\n    (void)success;\n    (void)failure;\n    return atomic_compare_exchange_weak_explicit((_z_atomic_t *)&var->_value, expected, desired,\n                                                 _z_memory_order_map[success], _z_memory_order_map[failure]);\n}\nvoid _z_atomic_thread_fence(_z_memory_order_t order) { atomic_thread_fence(_z_memory_order_map[order]); }\n\n#else\n#include <atomic>\nstatic_assert(sizeof(size_t) == sizeof(std::atomic<size_t>), \"std::atomic<size_t> must have the same size as size_t\");\nstatic const std::memory_order _z_memory_order_map[] = {std::memory_order_relaxed, std::memory_order_acquire,\n                                                        std::memory_order_release, std::memory_order_acq_rel,\n                                                        std::memory_order_seq_cst};\ntypedef std::atomic<size_t> _z_atomic_t;\nvoid _z_atomic_size_init(_z_atomic_size_t *var, size_t value) {\n    reinterpret_cast<_z_atomic_t *>(&var->_value)->store(value, _z_memory_order_map[_z_memory_order_relaxed]);\n}\nsize_t _z_atomic_size_load(_z_atomic_size_t *var, _z_memory_order_t order) {\n    return reinterpret_cast<_z_atomic_t *>(&var->_value)->load(_z_memory_order_map[order]);\n}\nvoid _z_atomic_size_store(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    reinterpret_cast<_z_atomic_t *>(&var->_value)->store(val, _z_memory_order_map[order]);\n}\nsize_t _z_atomic_size_fetch_add(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    return reinterpret_cast<_z_atomic_t *>(&var->_value)->fetch_add(val, _z_memory_order_map[order]);\n}\nsize_t _z_atomic_size_fetch_sub(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    return reinterpret_cast<_z_atomic_t *>(&var->_value)->fetch_sub(val, _z_memory_order_map[order]);\n}\nbool _z_atomic_size_compare_exchange_strong(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                            _z_memory_order_t success, _z_memory_order_t failure) {\n    return reinterpret_cast<_z_atomic_t *>(&var->_value)\n        ->compare_exchange_strong(*expected, desired, _z_memory_order_map[success], _z_memory_order_map[failure]);\n}\nbool _z_atomic_size_compare_exchange_weak(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                          _z_memory_order_t success, _z_memory_order_t failure) {\n    return reinterpret_cast<_z_atomic_t *>(&var->_value)\n        ->compare_exchange_weak(*expected, desired, _z_memory_order_map[success], _z_memory_order_map[failure]);\n}\nvoid _z_atomic_thread_fence(_z_memory_order_t order) { std::atomic_thread_fence(_z_memory_order_map[order]); }\n#endif\n#else\n#ifdef ZENOH_COMPILER_GCC\nstatic const int _z_memory_order_map[] = {__ATOMIC_RELAXED, __ATOMIC_ACQUIRE, __ATOMIC_RELEASE, __ATOMIC_ACQ_REL,\n                                          __ATOMIC_SEQ_CST};\nvoid _z_atomic_size_init(_z_atomic_size_t *var, size_t value) {\n    __atomic_store_n(&var->_value, value, _z_memory_order_map[_z_memory_order_relaxed]);\n}\nsize_t _z_atomic_size_load(_z_atomic_size_t *var, _z_memory_order_t order) {\n    return __atomic_load_n(&var->_value, _z_memory_order_map[order]);\n}\nvoid _z_atomic_size_store(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    __atomic_store_n(&var->_value, val, _z_memory_order_map[order]);\n}\nsize_t _z_atomic_size_fetch_add(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    return __atomic_fetch_add(&var->_value, val, _z_memory_order_map[order]);\n}\nsize_t _z_atomic_size_fetch_sub(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    return __atomic_fetch_sub(&var->_value, val, _z_memory_order_map[order]);\n}\nbool _z_atomic_size_compare_exchange_strong(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                            _z_memory_order_t success, _z_memory_order_t failure) {\n    return __atomic_compare_exchange_n(&var->_value, expected, desired, false, _z_memory_order_map[success],\n                                       _z_memory_order_map[failure]);\n}\nbool _z_atomic_size_compare_exchange_weak(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                          _z_memory_order_t success, _z_memory_order_t failure) {\n    return __atomic_compare_exchange_n(&var->_value, expected, desired, true, _z_memory_order_map[success],\n                                       _z_memory_order_map[failure]);\n}\nvoid _z_atomic_thread_fence(_z_memory_order_t order) { __atomic_thread_fence(_z_memory_order_map[order]); }\n#else\n#error \"Atomic operations in C99 only exists for GCC, use GCC or C11 or deactivate multi-thread\"\n#endif\n#endif\n#else\nvoid _z_atomic_size_init(_z_atomic_size_t *var, size_t value) { var->_value = value; }\nsize_t _z_atomic_size_load(_z_atomic_size_t *var, _z_memory_order_t order) {\n    (void)order;\n    return var->_value;\n}\nvoid _z_atomic_size_store(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    (void)order;\n    var->_value = val;\n}\nsize_t _z_atomic_size_fetch_add(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    (void)order;\n    size_t old = var->_value;\n    var->_value += val;\n    return old;\n}\nsize_t _z_atomic_size_fetch_sub(_z_atomic_size_t *var, size_t val, _z_memory_order_t order) {\n    (void)order;\n    size_t old = var->_value;\n    var->_value -= val;\n    return old;\n}\nbool _z_atomic_size_compare_exchange_strong(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                            _z_memory_order_t success, _z_memory_order_t failure) {\n    (void)success;\n    (void)failure;\n    if (*expected == var->_value) {\n        var->_value = desired;\n        return true;\n    }\n    *expected = var->_value;\n    return false;\n}\nbool _z_atomic_size_compare_exchange_weak(_z_atomic_size_t *var, size_t *expected, size_t desired,\n                                          _z_memory_order_t success, _z_memory_order_t failure) {\n    (void)success;\n    (void)failure;\n    return _z_atomic_size_compare_exchange_strong(var, expected, desired, success, failure);\n}\nvoid _z_atomic_thread_fence(_z_memory_order_t order) {\n    (void)order;\n    // No-op in single-threaded mode\n}\n#endif\n"
  },
  {
    "path": "src/collections/bytes.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/bytes.h\"\n\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/olv_macros.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*-------- Bytes --------*/\nbool _z_bytes_check(const _z_bytes_t *bytes) { return !_z_bytes_is_empty(bytes); }\n\nz_result_t _z_bytes_copy(_z_bytes_t *dst, const _z_bytes_t *src) {\n    return _z_arc_slice_svec_copy(&dst->_slices, &src->_slices, true);\n}\n\n_z_bytes_t _z_bytes_duplicate(const _z_bytes_t *src) {\n    _z_bytes_t dst = _z_bytes_null();\n    _z_bytes_copy(&dst, src);\n    return dst;\n}\n\nsize_t _z_bytes_len(const _z_bytes_t *bs) {\n    size_t len = 0;\n    for (size_t i = 0; i < _z_arc_slice_svec_len(&bs->_slices); ++i) {\n        const _z_arc_slice_t *s = _z_arc_slice_svec_get(&bs->_slices, i);\n        len += _z_arc_slice_len(s);\n    }\n    return len;\n}\n\nbool _z_bytes_is_empty(const _z_bytes_t *bs) {\n    for (size_t i = 0; i < _z_arc_slice_svec_len(&bs->_slices); i++) {\n        const _z_arc_slice_t *s = _z_arc_slice_svec_get(&bs->_slices, i);\n        if (_z_arc_slice_len(s) > 0) return false;\n    }\n    return true;\n}\n\nvoid _z_bytes_free(_z_bytes_t **bs) {\n    _z_bytes_t *ptr = *bs;\n\n    if (ptr != NULL) {\n        _z_bytes_drop(ptr);\n\n        z_free(ptr);\n        *bs = NULL;\n    }\n}\n\nsize_t _z_bytes_to_buf(const _z_bytes_t *bytes, uint8_t *dst, size_t len) {\n    uint8_t *start = dst;\n    size_t remaining = len;\n    for (size_t i = 0; i < _z_bytes_num_slices(bytes) && remaining > 0; ++i) {\n        // Recopy data\n        _z_arc_slice_t *s = _z_bytes_get_slice(bytes, i);\n        size_t s_len = _z_arc_slice_len(s);\n        size_t len_to_copy = remaining >= s_len ? s_len : remaining;\n        memcpy(start, _z_arc_slice_data(s), len_to_copy);\n        start += len_to_copy;\n        remaining -= len_to_copy;\n    }\n\n    return len - remaining;\n}\nz_result_t _z_bytes_from_slice(_z_bytes_t *b, _z_slice_t *s) {\n    *b = _z_bytes_null();\n    _z_arc_slice_t arc_s = _z_arc_slice_wrap(s, 0, s->len);\n    if (_z_arc_slice_len(&arc_s) != s->len) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    return _z_arc_slice_svec_append(&b->_slices, &arc_s, true);\n}\n\nz_result_t _z_bytes_from_buf(_z_bytes_t *b, const uint8_t *src, size_t len) {\n    *b = _z_bytes_null();\n    if (len == 0) return _Z_RES_OK;\n    _z_slice_t s = _z_slice_copy_from_buf(src, len);\n    if (s.len != len) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    return _z_bytes_from_slice(b, &s);\n}\n\nz_result_t _z_bytes_to_slice(const _z_bytes_t *bytes, _z_slice_t *s) {\n    // TODO: consider return a slice with custom deleter referencing the corresponding _arc_slice\n    // to avoid extra copy\n    // Allocate slice\n    size_t len = _z_bytes_len(bytes);\n    *s = _z_slice_make(len);\n    if (!_z_slice_check(s) && len > 0) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    uint8_t *start = (uint8_t *)s->start;\n    for (size_t i = 0; i < _z_bytes_num_slices(bytes); ++i) {\n        // Recopy data\n        _z_arc_slice_t *arc_s = _z_bytes_get_slice(bytes, i);\n        size_t s_len = _z_arc_slice_len(arc_s);\n        memcpy(start, _z_arc_slice_data(arc_s), s_len);\n        start += s_len;\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_append_slice(_z_bytes_t *dst, _z_arc_slice_t *s) {\n    z_result_t ret = _Z_RES_OK;\n    ret = _z_arc_slice_svec_append(&dst->_slices, s, true);\n    if (ret != _Z_RES_OK) {\n        _z_arc_slice_drop(s);\n    }\n    return ret;\n}\n\nz_result_t _z_bytes_append_bytes(_z_bytes_t *dst, _z_bytes_t *src) {\n    z_result_t res = _Z_RES_OK;\n    for (size_t i = 0; i < _z_bytes_num_slices(src); ++i) {\n        _z_arc_slice_t s;\n        _z_arc_slice_move(&s, _z_bytes_get_slice(src, i));\n        res = _z_bytes_append_slice(dst, &s);\n        if (res != _Z_RES_OK) {\n            break;\n        }\n    }\n\n    _z_bytes_drop(src);\n    return res;\n}\n\n_z_slice_t _z_bytes_try_get_contiguous(const _z_bytes_t *bs) {\n    if (_z_bytes_num_slices(bs) == 1) {\n        _z_arc_slice_t *arc_s = _z_bytes_get_slice(bs, 0);\n        return _z_slice_alias_buf(_z_arc_slice_data(arc_s), _z_arc_slice_len(arc_s));\n    }\n    return _z_slice_null();\n}\n\nz_result_t _z_bytes_move(_z_bytes_t *dst, _z_bytes_t *src) {\n    if (src->_slices._aliased) {\n        *dst = _z_bytes_null();\n        _z_bytes_t csrc;\n        _Z_RETURN_IF_ERR(_z_arc_slice_svec_copy(&csrc._slices, &src->_slices, false));\n        *src = csrc;\n    }\n    *dst = *src;\n    *src = _z_bytes_null();\n    return _Z_RES_OK;\n}\n\n_z_bytes_reader_t _z_bytes_get_reader(const _z_bytes_t *bytes) {\n    _z_bytes_reader_t r;\n    r.bytes = bytes;\n    r.slice_idx = 0;\n    r.byte_idx = 0;\n    r.in_slice_idx = 0;\n    return r;\n}\n\nz_result_t _z_bytes_reader_seek_forward(_z_bytes_reader_t *reader, size_t offset) {\n    size_t start_slice = reader->slice_idx;\n    for (size_t i = start_slice; i < _z_bytes_num_slices(reader->bytes); ++i) {\n        _z_arc_slice_t *s = _z_bytes_get_slice(reader->bytes, i);\n        size_t remaining = _z_arc_slice_len(s) - reader->in_slice_idx;\n        if (offset >= remaining) {\n            reader->slice_idx += 1;\n            reader->in_slice_idx = 0;\n            reader->byte_idx += remaining;\n            offset -= remaining;\n        } else {\n            reader->in_slice_idx += offset;\n            reader->byte_idx += offset;\n            offset = 0;\n        }\n        if (offset == 0) break;\n    }\n\n    if (offset > 0) _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_reader_seek_backward(_z_bytes_reader_t *reader, size_t offset) {\n    while (offset != 0) {\n        if (reader->in_slice_idx == 0) {\n            if (reader->slice_idx == 0) _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n            reader->slice_idx--;\n            _z_arc_slice_t *s = _z_bytes_get_slice(reader->bytes, reader->slice_idx);\n            reader->in_slice_idx = _z_arc_slice_len(s);\n        }\n\n        if (offset > reader->in_slice_idx) {\n            offset -= reader->in_slice_idx;\n            reader->byte_idx -= reader->in_slice_idx;\n            reader->in_slice_idx = 0;\n        } else {\n            reader->byte_idx -= offset;\n            reader->in_slice_idx -= offset;\n            offset = 0;\n        }\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_reader_seek(_z_bytes_reader_t *reader, int64_t offset, int origin) {\n    switch (origin) {\n        case SEEK_SET: {\n            reader->byte_idx = 0;\n            reader->in_slice_idx = 0;\n            reader->slice_idx = 0;\n            if (offset < 0) _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n            return _z_bytes_reader_seek_forward(reader, (size_t)offset);\n        }\n        case SEEK_CUR: {\n            if (offset >= 0)\n                return _z_bytes_reader_seek_forward(reader, (size_t)offset);\n            else\n                return _z_bytes_reader_seek_backward(reader, (size_t)(-offset));\n        }\n        case SEEK_END: {\n            reader->byte_idx = _z_bytes_len(reader->bytes);\n            reader->in_slice_idx = 0;\n            reader->slice_idx = _z_bytes_num_slices(reader->bytes);\n            if (offset > 0)\n                _Z_ERROR_RETURN(_Z_ERR_DID_NOT_READ);\n            else\n                return _z_bytes_reader_seek_backward(reader, (size_t)(-offset));\n        }\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n}\n\nint64_t _z_bytes_reader_tell(const _z_bytes_reader_t *reader) { return (int64_t)reader->byte_idx; }\n\nsize_t _z_bytes_reader_read(_z_bytes_reader_t *reader, uint8_t *buf, size_t len) {\n    uint8_t *buf_start = buf;\n    size_t to_read = len;\n    for (size_t i = reader->slice_idx; i < _z_bytes_num_slices(reader->bytes); ++i) {\n        _z_arc_slice_t *s = _z_bytes_get_slice(reader->bytes, i);\n        size_t remaining = _z_arc_slice_len(s) - reader->in_slice_idx;\n        if (len >= remaining) {\n            memcpy(buf_start, _z_arc_slice_data(s) + reader->in_slice_idx, remaining);\n            reader->slice_idx += 1;\n            reader->in_slice_idx = 0;\n            reader->byte_idx += remaining;\n            len -= remaining;\n            buf_start += remaining;\n        } else {\n            memcpy(buf_start, _z_arc_slice_data(s) + reader->in_slice_idx, len);\n            reader->in_slice_idx += len;\n            reader->byte_idx += len;\n            len = 0;\n        }\n        if (len == 0) break;\n    }\n\n    return to_read - len;\n}\n\nz_result_t _z_bytes_reader_read_slices(_z_bytes_reader_t *reader, size_t len, _z_bytes_t *out) {\n    *out = _z_bytes_null();\n    z_result_t res = _Z_RES_OK;\n\n    for (size_t i = reader->slice_idx; i < _z_bytes_num_slices(reader->bytes) && len > 0; ++i) {\n        _z_arc_slice_t *s = _z_bytes_get_slice(reader->bytes, i);\n        size_t s_len = _z_arc_slice_len(s);\n\n        size_t remaining = s_len - reader->in_slice_idx;\n        size_t len_to_copy = remaining > len ? len : remaining;\n        _z_arc_slice_t ss = _z_arc_slice_get_subslice(s, reader->in_slice_idx, len_to_copy);\n        reader->in_slice_idx += len_to_copy;\n        reader->byte_idx += len_to_copy;\n        if (reader->in_slice_idx == s_len) {\n            reader->slice_idx++;\n            reader->in_slice_idx = 0;\n        }\n\n        if (_z_slice_simple_rc_is_null(&ss.slice)) {\n            _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            res = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            break;\n        }\n\n        res = _z_bytes_append_slice(out, &ss);\n        if (res != _Z_RES_OK) {\n            _z_arc_slice_drop(&ss);\n            break;\n        }\n        len -= len_to_copy;\n    }\n    if (len > 0 && res == _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_DID_NOT_READ);\n        res = _Z_ERR_DID_NOT_READ;\n    }\n    if (res != _Z_RES_OK) {\n        _z_bytes_drop(out);\n        _Z_ERROR_RETURN(res);\n    }\n    return _Z_RES_OK;\n}\n\n_z_bytes_writer_t _z_bytes_writer_from_bytes(_z_bytes_t *bytes) {\n    _z_bytes_writer_t writer;\n    writer.cache = NULL;\n    writer.bytes = _z_bytes_steal(bytes);\n    return writer;\n}\n\n_z_bytes_writer_t _z_bytes_writer_empty(void) {\n    _z_bytes_writer_t writer;\n    writer.cache = NULL;\n    writer.bytes = _z_bytes_null();\n    return writer;\n}\n\nbool _z_bytes_writer_is_empty(const _z_bytes_writer_t *writer) { return _z_bytes_is_empty(&writer->bytes); }\n\nbool _z_bytes_writer_check(const _z_bytes_writer_t *writer) { return !_z_bytes_writer_is_empty(writer); }\n\nz_result_t _z_bytes_writer_ensure_cache(_z_bytes_writer_t *writer) {\n    assert(writer->cache != NULL);\n\n    if (_z_slice_simple_rc_value(&writer->cache->slice)->len > writer->cache->len) {\n        return _Z_RES_OK;\n    }\n    // otherwise we allocate a new cache\n    _z_slice_t s = _z_slice_make(writer->cache->len * 2);\n    if (s.start == NULL) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    _z_arc_slice_t cache = _z_arc_slice_wrap(&s, 0, 0);\n    if (_z_slice_simple_rc_is_null(&cache.slice)) {\n        _z_slice_clear(&s);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_append_slice(&writer->bytes, &cache), _z_arc_slice_drop(&cache));\n    writer->cache = _z_bytes_get_slice(&writer->bytes, _z_bytes_num_slices(&writer->bytes) - 1);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_writer_init_cache(_z_bytes_writer_t *writer, const uint8_t *src, size_t len) {\n    assert(writer->cache == NULL);\n\n    _z_slice_t s = _z_slice_copy_from_buf(src, len);\n    if (s.len != len) _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    _z_arc_slice_t arc_s = _z_arc_slice_wrap(&s, 0, len);\n    if (_z_slice_simple_rc_is_null(&arc_s.slice)) {\n        _z_slice_clear(&s);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    _Z_RETURN_IF_ERR(_z_bytes_append_slice(&writer->bytes, &arc_s));\n    writer->cache = _z_bytes_get_slice(&writer->bytes, _z_bytes_num_slices(&writer->bytes) - 1);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_writer_write_all(_z_bytes_writer_t *writer, const uint8_t *src, size_t len) {\n    if (writer->cache == NULL) {  // no cache - append data as a single slice\n        return _z_bytes_writer_init_cache(writer, src, len);\n    }\n\n    while (len > 0) {\n        _Z_RETURN_IF_ERR(_z_bytes_writer_ensure_cache(writer));\n        size_t remaining_in_cache = _z_slice_simple_rc_value(&writer->cache->slice)->len - writer->cache->len;\n        size_t to_copy = remaining_in_cache < len ? remaining_in_cache : len;\n        uint8_t *buffer_start = (uint8_t *)_z_slice_simple_rc_value(&writer->cache->slice)->start + writer->cache->len;\n        memcpy(buffer_start, src, to_copy);\n        len -= to_copy;\n        writer->cache->len += to_copy;\n        src += to_copy;\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_writer_append_z_bytes(_z_bytes_writer_t *writer, _z_bytes_t *src) {\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_append_bytes(&writer->bytes, src), _z_bytes_drop(src));\n    writer->cache = NULL;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_writer_append_slice(_z_bytes_writer_t *writer, _z_arc_slice_t *src) {\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_append_slice(&writer->bytes, src), _z_arc_slice_drop(src));\n    writer->cache = NULL;\n    return _Z_RES_OK;\n}\n\n_z_bytes_t _z_bytes_writer_finish(_z_bytes_writer_t *writer) {\n    _z_bytes_t out;\n    _z_bytes_move(&out, &writer->bytes);\n    writer->cache = NULL;\n    return out;\n}\n\nvoid _z_bytes_writer_clear(_z_bytes_writer_t *writer) {\n    _z_bytes_drop(&writer->bytes);\n    writer->cache = NULL;\n}\n\nz_result_t _z_bytes_writer_move(_z_bytes_writer_t *dst, _z_bytes_writer_t *src) {\n    dst->cache = src->cache;\n    _z_bytes_move(&dst->bytes, &src->bytes);\n    src->cache = NULL;\n    return _Z_RES_OK;\n}\n\nsize_t _z_bytes_reader_remaining(const _z_bytes_reader_t *reader) {\n    return _z_bytes_len(reader->bytes) - reader->byte_idx;\n}\n"
  },
  {
    "path": "src/collections/fifo.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include \"zenoh-pico/collections/fifo.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n/*-------- fifo --------*/\nz_result_t _z_fifo_init(_z_fifo_t *r, size_t capacity) {\n    _z_ring_init(&r->_ring, capacity);\n    return 0;\n}\n\n_z_fifo_t _z_fifo_make(size_t capacity) {\n    _z_fifo_t v;\n    _z_fifo_init(&v, capacity);\n    return v;\n}\n\nsize_t _z_fifo_capacity(const _z_fifo_t *r) { return _z_ring_capacity(&r->_ring); }\nsize_t _z_fifo_len(const _z_fifo_t *r) { return _z_ring_len(&r->_ring); }\nbool _z_fifo_is_empty(const _z_fifo_t *r) { return _z_ring_is_empty(&r->_ring); }\nbool _z_fifo_is_full(const _z_fifo_t *r) { return _z_fifo_len(r) == _z_fifo_capacity(r); }\n\nvoid *_z_fifo_push(_z_fifo_t *r, void *e) { return _z_ring_push(&r->_ring, e); }\nvoid _z_fifo_push_drop(_z_fifo_t *r, void *e, z_element_free_f free_f) {\n    void *ret = _z_fifo_push(r, e);\n    if (ret != NULL) {\n        free_f(&ret);\n    }\n}\nvoid *_z_fifo_pull(_z_fifo_t *r) { return _z_ring_pull(&r->_ring); }\nvoid _z_fifo_clear(_z_fifo_t *r, z_element_free_f free_f) { _z_ring_clear(&r->_ring, free_f); }\nvoid _z_fifo_free(_z_fifo_t **r, z_element_free_f free_f) {\n    _z_fifo_t *ptr = (_z_fifo_t *)*r;\n    if (ptr != NULL) {\n        _z_fifo_clear(ptr, free_f);\n        z_free(ptr);\n        *r = NULL;\n    }\n}\n"
  },
  {
    "path": "src/collections/fifo_mt.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/fifo_mt.h\"\n\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*-------- Fifo Buffer Multithreaded --------*/\nz_result_t _z_fifo_mt_init(_z_fifo_mt_t *fifo, size_t capacity) {\n    _Z_RETURN_IF_ERR(_z_fifo_init(&fifo->_fifo, capacity))\n    fifo->is_closed = false;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_init(&fifo->_mutex))\n    _Z_RETURN_IF_ERR(_z_condvar_init(&fifo->_cv_not_full))\n    _Z_RETURN_IF_ERR(_z_condvar_init(&fifo->_cv_not_empty))\n#endif\n\n    return _Z_RES_OK;\n}\n\n_z_fifo_mt_t *_z_fifo_mt_new(size_t capacity) {\n    _z_fifo_mt_t *fifo = (_z_fifo_mt_t *)z_malloc(sizeof(_z_fifo_mt_t));\n    if (fifo == NULL) {\n        _Z_ERROR(\"z_malloc failed\");\n        return NULL;\n    }\n\n    z_result_t ret = _z_fifo_mt_init(fifo, capacity);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"_z_fifo_mt_init failed: %i\", ret);\n        z_free(fifo);\n        return NULL;\n    }\n\n    return fifo;\n}\n\nvoid _z_fifo_mt_clear(_z_fifo_mt_t *fifo, z_element_free_f free_f) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_drop(&fifo->_mutex);\n    _z_condvar_drop(&fifo->_cv_not_full);\n    _z_condvar_drop(&fifo->_cv_not_empty);\n#endif\n\n    _z_fifo_clear(&fifo->_fifo, free_f);\n}\n\nvoid _z_fifo_mt_free(_z_fifo_mt_t *fifo, z_element_free_f free_f) {\n    _z_fifo_mt_clear(fifo, free_f);\n    z_free(fifo);\n}\n\nz_result_t _z_fifo_mt_push(const void *elem, void *context, z_element_free_f element_free) {\n    _ZP_UNUSED(element_free);\n    if (elem == NULL || context == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_fifo_mt_t *f = (_z_fifo_mt_t *)context;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&f->_mutex))\n    while (elem != NULL) {\n        elem = _z_fifo_push(&f->_fifo, (void *)elem);\n        if (elem != NULL) {\n            _Z_RETURN_IF_ERR(_z_condvar_wait(&f->_cv_not_full, &f->_mutex))\n        } else {\n            _Z_RETURN_IF_ERR(_z_condvar_signal(&f->_cv_not_empty))\n        }\n    }\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&f->_mutex))\n#else   // Z_FEATURE_MULTI_THREAD == 1\n    _z_fifo_push_drop(&f->_fifo, (void *)elem, element_free);\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_fifo_mt_close(_z_fifo_mt_t *fifo) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&fifo->_mutex))\n    fifo->is_closed = true;\n    _Z_RETURN_IF_ERR(_z_condvar_signal_all(&fifo->_cv_not_empty))\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&fifo->_mutex))\n#else\n    fifo->is_closed = true;\n#endif\n    return _Z_RES_OK;\n}\n\nz_result_t _z_fifo_mt_pull(void *dst, void *context, z_element_move_f element_move) {\n    _z_fifo_mt_t *f = (_z_fifo_mt_t *)context;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    void *src = NULL;\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&f->_mutex))\n    while (src == NULL) {\n        src = _z_fifo_pull(&f->_fifo);\n        if (src == NULL) {\n            if (f->is_closed) break;\n            _Z_RETURN_IF_ERR(_z_condvar_wait(&f->_cv_not_empty, &f->_mutex))\n        } else {\n            _Z_RETURN_IF_ERR(_z_condvar_signal(&f->_cv_not_full))\n        }\n    }\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&f->_mutex))\n    if (f->is_closed && src == NULL) return _Z_RES_CHANNEL_CLOSED;\n    element_move(dst, src);\n#else   // Z_FEATURE_MULTI_THREAD == 1\n    void *src = _z_fifo_pull(&f->_fifo);\n    if (src != NULL) {\n        element_move(dst, src);\n    } else if (f->is_closed) {\n        return _Z_RES_CHANNEL_CLOSED;\n    }\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_fifo_mt_try_pull(void *dst, void *context, z_element_move_f element_move) {\n    _z_fifo_mt_t *f = (_z_fifo_mt_t *)context;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    void *src = NULL;\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&f->_mutex))\n    src = _z_fifo_pull(&f->_fifo);\n    if (src != NULL) {\n        _Z_RETURN_IF_ERR(_z_condvar_signal(&f->_cv_not_full))\n    }\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&f->_mutex))\n#else   // Z_FEATURE_MULTI_THREAD == 1\n    void *src = _z_fifo_pull(&f->_fifo);\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    if (src != NULL) {\n        element_move(dst, src);\n    } else if (f->is_closed) {\n        return _Z_RES_CHANNEL_CLOSED;\n    } else {\n        return _Z_RES_CHANNEL_NODATA;\n    }\n\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/collections/hashmap.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/hashmap.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\n/*-------- hashmap --------*/\nvoid _z_hashmap_init(_z_hashmap_t *map, size_t capacity, z_element_hash_f f_hash, z_element_eq_f f_equals) {\n    map->_capacity = capacity;\n    map->_vals = NULL;\n    map->_f_hash = f_hash;\n    map->_f_equals = f_equals;\n}\n\n_z_hashmap_t _z_hashmap_make(size_t capacity, z_element_hash_f f_hash, z_element_eq_f f_equals) {\n    _z_hashmap_t map;\n    _z_hashmap_init(&map, capacity, f_hash, f_equals);\n    return map;\n}\n\nsize_t _z_hashmap_capacity(const _z_hashmap_t *map) { return map->_capacity; }\n\nsize_t _z_hashmap_len(const _z_hashmap_t *map) {\n    size_t len = 0;\n\n    if (map->_vals != NULL) {\n        for (size_t idx = 0; idx < map->_capacity; idx++) {\n            len = len + _z_list_len(map->_vals[idx]);\n        }\n    }\n\n    return len;\n}\n\nz_result_t _z_hashmap_copy(_z_hashmap_t *dst, const _z_hashmap_t *src, z_element_clone_f f_c) {\n    assert((dst != NULL) && (src != NULL) && (dst->_capacity == src->_capacity));\n    for (size_t idx = 0; idx < src->_capacity; idx++) {\n        const _z_list_t *src_list = src->_vals[idx];\n        if (src_list == NULL) {\n            continue;\n        }\n        // Allocate entry\n        dst->_vals[idx] = _z_list_clone(src_list, f_c);\n        if (dst->_vals[idx] == NULL) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n    }\n    dst->_f_hash = src->_f_hash;\n    dst->_f_equals = src->_f_equals;\n    return _Z_RES_OK;\n}\n\n_z_hashmap_t _z_hashmap_clone(const _z_hashmap_t *src, z_element_clone_f f_c, z_element_free_f f_f) {\n    _z_hashmap_t dst = {\n        ._capacity = src->_capacity, ._vals = NULL, ._f_hash = src->_f_hash, ._f_equals = src->_f_equals};\n    if (src->_vals == NULL) {\n        return dst;\n    }\n    // Lazily allocate and initialize to NULL all the pointers\n    size_t len = dst._capacity * sizeof(_z_list_t *);\n    dst._vals = (_z_list_t **)z_malloc(len);\n    if (dst._vals == NULL) {\n        return dst;\n    }\n    (void)memset(dst._vals, 0, len);\n    // Copy elements\n    if (_z_hashmap_copy(&dst, src, f_c) != _Z_RES_OK) {\n        // Free the map\n        _z_hashmap_clear(&dst, f_f);\n    }\n    return dst;\n}\n\nbool _z_hashmap_is_empty(const _z_hashmap_t *map) { return _z_hashmap_len(map) == (size_t)0; }\n\nvoid _z_hashmap_remove(_z_hashmap_t *map, const void *k, z_element_free_f f) {\n    if (map->_vals != NULL) {\n        size_t idx = map->_f_hash(k) % map->_capacity;\n        _z_hashmap_entry_t e;\n        e._key = (void *)k;  // k will not be mutated by this operation\n        e._val = NULL;\n\n        map->_vals[idx] = _z_list_drop_filter(map->_vals[idx], f, map->_f_equals, &e, true);\n    }\n}\n\n_z_hashmap_entry_t _z_hashmap_extract(_z_hashmap_t *map, const void *key) {\n    _z_hashmap_entry_t out;\n    out._key = NULL;\n    out._val = NULL;\n    if (map->_vals != NULL) {\n        size_t idx = map->_f_hash(key) % map->_capacity;\n        _z_hashmap_entry_t e;\n        e._key = (void *)key;  // k will not be mutated by this operation\n        e._val = NULL;\n        _z_list_t *extracted;\n        map->_vals[idx] = _z_list_extract_filter(map->_vals[idx], map->_f_equals, &e, &extracted, true);\n        if (extracted != NULL) {\n            _z_hashmap_entry_t *kv = (_z_hashmap_entry_t *)((extracted)->_val);\n            out._key = kv->_key;\n            out._val = kv->_val;\n            z_free(kv);\n            z_free(extracted);\n        }\n    }\n    return out;\n}\n\nvoid *_z_hashmap_insert(_z_hashmap_t *map, void *k, void *v, z_element_free_f f_f, bool replace) {\n    if (map->_vals == NULL) {\n        // Lazily allocate and initialize to NULL all the pointers\n        size_t len = map->_capacity * sizeof(_z_list_t *);\n        map->_vals = (_z_list_t **)z_malloc(len);\n        if (map->_vals != NULL) {\n            (void)memset(map->_vals, 0, len);\n        } else {\n            return NULL;\n        }\n    }\n\n    if (replace) {\n        // Free any old value\n        _z_hashmap_remove(map, k, f_f);\n    }\n\n    // Insert the element\n    _z_hashmap_entry_t *entry = (_z_hashmap_entry_t *)z_malloc(sizeof(_z_hashmap_entry_t));\n    if (entry != NULL) {\n        entry->_key = k;\n        entry->_val = v;\n\n        size_t idx = map->_f_hash(k) % map->_capacity;\n        map->_vals[idx] = _z_list_push(map->_vals[idx], entry);\n    } else {\n        return NULL;\n    }\n\n    return v;\n}\n\nvoid *_z_hashmap_get(const _z_hashmap_t *map, const void *k) {\n    void *ret = NULL;\n\n    if (map->_vals != NULL) {\n        size_t idx = map->_f_hash(k) % map->_capacity;\n\n        _z_hashmap_entry_t e;\n        e._key = (void *)k;  // k will not be mutated by this operation\n        e._val = NULL;\n\n        _z_list_t *xs = _z_list_find(map->_vals[idx], map->_f_equals, &e);\n        if (xs != NULL) {\n            _z_hashmap_entry_t *h = (_z_hashmap_entry_t *)_z_list_value(xs);\n            ret = h->_val;\n        }\n    }\n\n    return ret;\n}\n\n_z_list_t *_z_hashmap_get_all(const _z_hashmap_t *map, const void *k) {\n    if (map->_vals != NULL) {\n        size_t idx = map->_f_hash(k) % map->_capacity;\n\n        _z_hashmap_entry_t e;\n        e._key = (void *)k;  // k will not be mutated by this operation\n        e._val = NULL;\n\n        return _z_list_find(map->_vals[idx], map->_f_equals, &e);\n    }\n    return NULL;\n}\n\n_z_hashmap_iterator_t _z_hashmap_iterator_make(const _z_hashmap_t *map) {\n    _z_hashmap_iterator_t iter = {0};\n\n    iter._map = map;\n\n    return iter;\n}\n\nbool _z_hashmap_iterator_next(_z_hashmap_iterator_t *iter) {\n    if (iter->_map->_vals == NULL) {\n        return false;\n    }\n\n    while (iter->_idx < iter->_map->_capacity) {\n        if (iter->_list_ptr == NULL) {\n            iter->_list_ptr = iter->_map->_vals[iter->_idx];\n        } else {\n            iter->_list_ptr = _z_list_next(iter->_list_ptr);\n        }\n        if (iter->_list_ptr == NULL) {\n            iter->_idx++;\n            continue;\n        }\n\n        iter->_entry = iter->_list_ptr->_val;\n\n        return true;\n    }\n    return false;\n}\n\nvoid *_z_hashmap_iterator_key(const _z_hashmap_iterator_t *iter) { return iter->_entry->_key; }\n\nvoid *_z_hashmap_iterator_value(const _z_hashmap_iterator_t *iter) { return iter->_entry->_val; }\n\nvoid _z_hashmap_clear(_z_hashmap_t *map, z_element_free_f f_f) {\n    if (map->_vals != NULL) {\n        for (size_t idx = 0; idx < map->_capacity; idx++) {\n            _z_list_free(&map->_vals[idx], f_f);\n        }\n\n        z_free(map->_vals);\n        map->_vals = NULL;\n    }\n}\n\nvoid _z_hashmap_free(_z_hashmap_t **map, z_element_free_f f) {\n    _z_hashmap_t *ptr = *map;\n    if (ptr != NULL) {\n        _z_hashmap_clear(ptr, f);\n\n        z_free(ptr);\n        *map = NULL;\n    }\n}\n"
  },
  {
    "path": "src/collections/lifo.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include \"zenoh-pico/collections/lifo.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n/*-------- lifo --------*/\nz_result_t _z_lifo_init(_z_lifo_t *r, size_t capacity) {\n    memset(r, 0, sizeof(_z_lifo_t));\n    if (capacity != (size_t)0) {\n        r->_val = (void **)z_malloc(sizeof(void *) * capacity);\n    }\n    if (r->_val != NULL) {\n        memset(r->_val, 0, capacity);\n        r->_capacity = capacity;\n    }\n    return 0;\n}\n\n_z_lifo_t _z_lifo_make(size_t capacity) {\n    _z_lifo_t v;\n    _z_lifo_init(&v, capacity);\n    return v;\n}\n\nsize_t _z_lifo_capacity(const _z_lifo_t *r) { return r->_capacity; }\nsize_t _z_lifo_len(const _z_lifo_t *r) { return r->_len; }\nbool _z_lifo_is_empty(const _z_lifo_t *r) { return r->_len == 0; }\nbool _z_lifo_is_full(const _z_lifo_t *r) { return r->_len == r->_capacity; }\n\nvoid *_z_lifo_push(_z_lifo_t *r, void *e) {\n    void *ret = e;\n    if (!_z_lifo_is_full(r)) {\n        r->_val[r->_len] = e;\n        r->_len++;\n        ret = NULL;\n    }\n    return ret;\n}\n\nvoid _z_lifo_push_drop(_z_lifo_t *r, void *e, z_element_free_f free_f) {\n    void *ret = _z_lifo_push(r, e);\n    if (ret != NULL) {\n        free_f(&ret);\n    }\n}\n\nvoid *_z_lifo_pull(_z_lifo_t *r) {\n    void *ret = NULL;\n    if (!_z_lifo_is_empty(r)) {\n        r->_len--;\n        ret = r->_val[r->_len];\n    }\n    return ret;\n}\n\nvoid _z_lifo_clear(_z_lifo_t *r, z_element_free_f free_f) {\n    void *e = _z_lifo_pull(r);\n    while (e != NULL) {\n        free_f(&e);\n        e = _z_lifo_pull(r);\n    }\n    z_free(r->_val);\n\n    r->_val = NULL;\n    r->_capacity = (size_t)0;\n    r->_len = (size_t)0;\n}\n\nvoid _z_lifo_free(_z_lifo_t **r, z_element_free_f free_f) {\n    _z_lifo_t *ptr = (_z_lifo_t *)*r;\n    if (ptr != NULL) {\n        _z_lifo_clear(ptr, free_f);\n        z_free(ptr);\n        *r = NULL;\n    }\n}\n"
  },
  {
    "path": "src/collections/list.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/list.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n/*-------- Inner single-linked list --------*/\nstatic _z_list_t *_z_list_new(void *x) {\n    _z_list_t *xs = (_z_list_t *)z_malloc(sizeof(_z_list_t));\n    if (xs == NULL) {\n        _Z_ERROR(\"Failed to allocate list element.\");\n        return NULL;\n    }\n    xs->_val = x;\n    xs->_next = NULL;\n    return xs;\n}\n\n_z_list_t *_z_list_push(_z_list_t *xs, void *x) {\n    _z_list_t *lst = _z_list_new(x);\n    if (lst == NULL) {\n        return xs;\n    }\n    lst->_next = xs;\n    return lst;\n}\n\n_z_list_t *_z_list_push_after(_z_list_t *xs, void *x) {\n    _z_list_t *l = _z_list_new(x);\n    if (l == NULL || xs == NULL) {\n        return l;\n    }\n\n    l->_next = xs->_next;\n    xs->_next = l;\n\n    return xs;\n}\n\n_z_list_t *_z_list_push_back(_z_list_t *xs, void *x) {\n    if (xs == NULL) {\n        return _z_list_new(x);\n    }\n    _z_list_t *l = xs;\n    while (l->_next != NULL) {\n        l = l->_next;\n    }\n    l->_next = _z_list_new(x);\n    return xs;\n}\n\n_z_list_t *_z_list_push_sorted(_z_list_t *xs, z_element_cmp_f c_f, void *x) {\n    if (xs == NULL) {\n        return _z_list_new(x);\n    }\n\n    _z_list_t *l = xs;\n    _z_list_t *prev = NULL;\n\n    while (l != NULL && c_f(l->_val, x) <= 0) {\n        prev = l;\n        l = l->_next;\n    }\n\n    _z_list_t *new_elem = _z_list_new(x);\n    if (new_elem == NULL) {\n        return xs;\n    }\n\n    if (prev == NULL) {\n        new_elem->_next = xs;\n        return new_elem;\n    } else {\n        new_elem->_next = l;\n        prev->_next = new_elem;\n        return xs;\n    }\n}\n\nsize_t _z_list_len(const _z_list_t *xs) {\n    size_t len = 0;\n    _z_list_t *l = (_z_list_t *)xs;\n    while (l != NULL) {\n        len = len + (size_t)1;\n        l = _z_list_next(l);\n    }\n    return len;\n}\n\n_z_list_t *_z_list_pop(_z_list_t *xs, z_element_free_f f_f, void **x) {\n    if (xs == NULL) {\n        return xs;\n    }\n    _z_list_t *head = xs;\n    _z_list_t *l = head->_next;\n    if (x != NULL) {\n        *x = head->_val;\n    } else {\n        f_f(&head->_val);\n    }\n    z_free(head);\n    return l;\n}\n\n_z_list_t *_z_list_find(const _z_list_t *xs, z_element_eq_f c_f, const void *e) {\n    _z_list_t *l = (_z_list_t *)xs;\n    _z_list_t *ret = NULL;\n    while (l != NULL) {\n        void *head = _z_list_value(l);\n        if (c_f(e, head)) {\n            ret = l;\n            break;\n        }\n        l = _z_list_next(l);\n    }\n    return ret;\n}\n\n_z_list_t *_z_list_drop_element(_z_list_t *list, _z_list_t *prev, z_element_free_f f_f) {\n    _z_list_t *dropped = NULL;\n    if (prev == NULL) {  // Head removal\n        dropped = list;\n        list = list->_next;\n    } else {  // Other cases\n        dropped = prev->_next;\n        if (dropped != NULL) {\n            prev->_next = dropped->_next;\n        }\n    }\n    if (dropped != NULL) {\n        f_f(&dropped->_val);\n        z_free(dropped);\n    }\n    return list;\n}\n\n_z_list_t *_z_list_drop_filter(_z_list_t *xs, z_element_free_f f_f, z_element_eq_f c_f, const void *left,\n                               bool only_first) {\n    _z_list_t *l = (_z_list_t *)xs;\n    _z_list_t *previous = xs;\n    _z_list_t *current = xs;\n\n    while (current != NULL) {\n        if (c_f(left, current->_val)) {\n            _z_list_t *next = current->_next;\n            _z_list_t *this_ = current;\n\n            // head removal\n            if (this_ == l) {\n                l = l->_next;\n            }\n            // tail removal\n            else if (this_->_next == NULL) {\n                previous->_next = NULL;\n            }\n            // middle removal\n            else {\n                previous->_next = this_->_next;\n            }\n\n            f_f(&this_->_val);\n            z_free(this_);\n            if (only_first) {\n                break;\n            }\n            current = next;\n        } else {\n            previous = current;\n            current = current->_next;\n        }\n    }\n\n    return l;\n}\n\n_z_list_t *_z_list_extract_filter(_z_list_t *head, z_element_eq_f c_f, const void *left, _z_list_t **extracted,\n                                  bool only_first) {\n    _z_list_t self_head = {0};\n    _z_list_t extracted_head = {0};\n    _z_list_t *self_tail = &self_head;\n    _z_list_t *extracted_tail = &extracted_head;\n    _z_list_t *current = head;\n    while (current != NULL) {\n        _z_list_t *next = current->_next;\n        current->_next = NULL;\n        if (c_f(left, current->_val)) {\n            extracted_tail->_next = current;\n            extracted_tail = extracted_tail->_next;\n            if (only_first) {\n                self_tail->_next = next;\n                break;\n            }\n        } else {\n            self_tail->_next = current;\n            self_tail = self_tail->_next;\n        }\n        current = next;\n    }\n\n    *extracted = extracted_head._next;\n    return self_head._next;\n}\n\n_z_list_t *_z_list_clone(const _z_list_t *xs, z_element_clone_f d_f) {\n    _z_list_t *new = NULL;\n\n    const _z_list_t *curr = xs;\n    while (curr != NULL) {\n        void *x = d_f(_z_list_value(curr));\n        new = _z_list_push_back(new, x);\n        curr = _z_list_next(curr);\n    }\n\n    return new;\n}\n\n/**\n * Free the list in deep. This function frees\n * the inner void * to the element of the list.\n */\nvoid _z_list_free(_z_list_t **xs, z_element_free_f f) {\n    _z_list_t *ptr = *xs;\n    while (ptr != NULL) {\n        ptr = _z_list_pop(ptr, f, NULL);\n    }\n\n    *xs = NULL;\n}\n\n/*-------- Inner sized single-linked list --------*/\ntypedef struct _z_slist_node_data_t {\n    _z_slist_t *next;\n} _z_slist_node_data_t;\n\n#define NODE_DATA_SIZE sizeof(_z_slist_node_data_t)\n\nstatic inline _z_slist_node_data_t *_z_slist_node_data(const _z_slist_t *list) { return (_z_slist_node_data_t *)list; }\n\nstatic inline void *_z_slist_node_value(const _z_slist_t *node) {\n    return (void *)_z_ptr_u8_offset((uint8_t *)node, (ptrdiff_t)NODE_DATA_SIZE);\n}\n\nstatic _z_slist_t *_z_slist_new(const void *value, size_t value_size, z_element_copy_f d_f, bool use_elem_f) {\n    size_t node_size = NODE_DATA_SIZE + value_size;\n    _z_slist_t *node = (_z_slist_t *)z_malloc(node_size);\n    if (node == NULL) {\n        _Z_ERROR(\"Failed to allocate list element.\");\n        return node;\n    }\n    memset(node, 0, NODE_DATA_SIZE);\n    if (use_elem_f) {\n        d_f(_z_slist_node_value(node), value);\n    } else {\n        memcpy(_z_slist_node_value(node), value, value_size);\n    }\n    return node;\n}\n\nstatic _z_slist_t *_z_slist_new_empty(size_t value_size) {\n    size_t node_size = NODE_DATA_SIZE + value_size;\n    _z_slist_t *node = (_z_slist_t *)z_malloc(node_size);\n    if (node == NULL) {\n        _Z_ERROR(\"Failed to allocate list element.\");\n        return node;\n    }\n    memset(node, 0, NODE_DATA_SIZE);\n    return node;\n}\n\n_z_slist_t *_z_slist_push_empty(_z_slist_t *node, size_t value_size) {\n    _z_slist_t *new_node = _z_slist_new_empty(value_size);\n    if (new_node == NULL) {\n        return node;\n    }\n    _z_slist_node_data_t *node_data = _z_slist_node_data(new_node);\n    node_data->next = node;\n    return new_node;\n}\n\n_z_slist_t *_z_slist_push(_z_slist_t *node, const void *value, size_t value_size, z_element_copy_f d_f,\n                          bool use_elem_f) {\n    _z_slist_t *new_node = _z_slist_new(value, value_size, d_f, use_elem_f);\n    if (new_node == NULL) {\n        return node;\n    }\n    _z_slist_node_data_t *node_data = _z_slist_node_data(new_node);\n    node_data->next = node;\n    return new_node;\n}\n\n_z_slist_t *_z_slist_push_back(_z_slist_t *node, const void *value, size_t value_size, z_element_copy_f d_f,\n                               bool use_elem_f) {\n    if (node == NULL) {\n        return _z_slist_new(value, value_size, d_f, use_elem_f);\n    }\n    _z_slist_node_data_t *node_data = _z_slist_node_data(node);\n    while (node_data->next != NULL) {\n        node_data = _z_slist_node_data(node_data->next);\n    }\n    node_data->next = _z_slist_new(value, value_size, d_f, use_elem_f);\n    return node;\n}\n\nvoid *_z_slist_value(const _z_slist_t *node) { return _z_slist_node_value(node); }\n\n_z_slist_t *_z_slist_next(const _z_slist_t *node) {\n    _z_slist_node_data_t *node_data = _z_slist_node_data(node);\n    return _z_slist_node_data(node_data)->next;\n}\n\nsize_t _z_slist_len(const _z_slist_t *node) {\n    size_t len = 0;\n    _z_slist_node_data_t *node_data = _z_slist_node_data(node);\n    while (node_data != NULL) {\n        len += (size_t)1;\n        node_data = _z_slist_node_data(node_data->next);\n    }\n    return len;\n}\n\n_z_slist_t *_z_slist_pop(_z_slist_t *node, z_element_clear_f f_f) {\n    if (node == NULL) {\n        return node;\n    }\n    _z_slist_t *next_node = _z_slist_node_data(node)->next;\n    f_f(_z_slist_node_value(node));\n    z_free(node);\n    return next_node;\n}\n\n_z_slist_t *_z_slist_find(const _z_slist_t *node, z_element_eq_f c_f, const void *target_val) {\n    _z_slist_t *curr_node = (_z_slist_t *)node;\n    _z_slist_node_data_t *node_data = _z_slist_node_data(curr_node);\n    while (node_data != NULL) {\n        if (c_f(target_val, _z_slist_node_value(curr_node))) {\n            return curr_node;\n        }\n        curr_node = node_data->next;\n        node_data = _z_slist_node_data(curr_node);\n    }\n    return NULL;\n}\n\n_z_slist_t *_z_slist_drop_element(_z_slist_t *list, _z_slist_t *prev, z_element_clear_f f_f) {\n    _z_slist_t *dropped = NULL;\n    if (prev == NULL) {  // Head removal\n        dropped = list;\n        list = _z_slist_node_data(list)->next;\n    } else {  // Other cases\n        dropped = _z_slist_node_data(prev)->next;\n        if (dropped != NULL) {\n            _z_slist_node_data(prev)->next = _z_slist_node_data(dropped)->next;\n        }\n    }\n    if (dropped != NULL) {\n        f_f(_z_slist_node_value(dropped));\n        z_free(dropped);\n    }\n    return list;\n}\n\n_z_slist_t *_z_slist_drop_filter(_z_slist_t *head, z_element_clear_f f_f, z_element_eq_f c_f, const void *target_val,\n                                 bool only_first) {\n    _z_slist_t *previous = head;\n    _z_slist_t *current = head;\n    while (current != NULL) {\n        if (c_f(target_val, _z_slist_node_value(current))) {\n            if (current == head) {  // head removal\n                head = _z_slist_node_data(head)->next;\n            } else if (_z_slist_node_data(current)->next == NULL) {  // tail removal\n                _z_slist_node_data(previous)->next = NULL;\n            } else {  // middle removal\n                _z_slist_node_data(previous)->next = _z_slist_node_data(current)->next;\n            }\n            _z_slist_t *next = _z_slist_node_data(current)->next;\n            f_f(_z_slist_node_value(current));\n            z_free(current);\n            if (only_first) {\n                break;\n            }\n            current = next;\n        } else {\n            previous = current;\n            current = _z_slist_node_data(current)->next;\n        }\n    }\n    return head;\n}\n\n_z_slist_t *_z_slist_extract_filter(_z_slist_t *head, z_element_eq_f c_f, const void *target_val,\n                                    _z_slist_t **extracted, bool only_first) {\n    _z_slist_node_data_t self_head = {0};\n    _z_slist_node_data_t extracted_head = {0};\n    _z_slist_node_data_t *self_tail = &self_head;\n    _z_slist_node_data_t *extracted_tail = &extracted_head;\n    _z_slist_t *current = head;\n    while (current != NULL) {\n        _z_slist_t *next = _z_slist_node_data(current)->next;\n        _z_slist_node_data(current)->next = NULL;\n        if (c_f(target_val, _z_slist_node_value(current))) {\n            extracted_tail->next = current;\n            extracted_tail = _z_slist_node_data(extracted_tail->next);\n            if (only_first) {\n                self_tail->next = next;\n                break;\n            }\n        } else {\n            self_tail->next = current;\n            self_tail = _z_slist_node_data(self_tail->next);\n        }\n        current = next;\n    }\n\n    *extracted = extracted_head.next;\n    return self_head.next;\n}\n\n_z_slist_t *_z_slist_clone(const _z_slist_t *node, size_t value_size, z_element_copy_f d_f, bool use_elem_f) {\n    _z_slist_t *new_node = NULL;\n    _z_slist_t *curr_node = (_z_slist_t *)node;\n    while (curr_node != NULL) {\n        void *value = _z_slist_node_value(curr_node);\n        new_node = _z_slist_push(new_node, value, value_size, d_f, use_elem_f);\n        curr_node = _z_slist_node_data(curr_node)->next;\n    }\n    return new_node;\n}\n\nvoid _z_slist_free(_z_slist_t **node, z_element_clear_f f) {\n    _z_slist_t *ptr = *node;\n    while (ptr != NULL) {\n        ptr = _z_slist_pop(ptr, f);\n    }\n    *node = NULL;\n}\n"
  },
  {
    "path": "src/collections/lru_cache.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/lru_cache.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n// Nodes are chained as double linked list for lru insertion/deletion.\ntypedef struct _z_lru_cache_node_data_t {\n    _z_lru_cache_node_t *prev;  // List previous node\n    _z_lru_cache_node_t *next;  // List next node\n} _z_lru_cache_node_data_t;\n\n#define NODE_DATA_SIZE sizeof(_z_lru_cache_node_data_t)\n\n// Generic static functions\nstatic inline _z_lru_cache_t _z_lru_cache_null(void) { return (_z_lru_cache_t){0}; }\n\nstatic inline _z_lru_cache_node_data_t *_z_lru_cache_node_data(_z_lru_cache_node_t *node) {\n    return (_z_lru_cache_node_data_t *)node;\n}\n\nstatic inline void *_z_lru_cache_node_value(_z_lru_cache_node_t *node) {\n    return (void *)_z_ptr_u8_offset((uint8_t *)node, (ptrdiff_t)NODE_DATA_SIZE);\n}\n\nstatic _z_lru_cache_node_t *_z_lru_cache_node_create(void *value, size_t value_size) {\n    size_t node_size = NODE_DATA_SIZE + value_size;\n    _z_lru_cache_node_t *node = (_z_lru_cache_node_t *)z_malloc(node_size);\n    if (node == NULL) {\n        return node;\n    }\n    memset(node, 0, NODE_DATA_SIZE);\n    memcpy(_z_lru_cache_node_value(node), value, value_size);\n    return node;\n}\n\n// List functions\nstatic void _z_lru_cache_insert_list_node(_z_lru_cache_t *cache, _z_lru_cache_node_t *node) {\n    _z_lru_cache_node_data_t *node_data = _z_lru_cache_node_data(node);\n    node_data->prev = NULL;\n    node_data->next = cache->head;\n\n    if (cache->head != NULL) {\n        _z_lru_cache_node_data_t *head_data = _z_lru_cache_node_data(cache->head);\n        head_data->prev = node;\n    }\n    cache->head = node;\n    if (cache->tail == NULL) {\n        cache->tail = node;\n    }\n}\n\nstatic void _z_lru_cache_remove_list_node(_z_lru_cache_t *cache, _z_lru_cache_node_t *node) {\n    _z_lru_cache_node_data_t *node_data = _z_lru_cache_node_data(node);\n\n    // Nominal case\n    if ((node_data->prev != NULL) && (node_data->next != NULL)) {\n        _z_lru_cache_node_data_t *prev_data = _z_lru_cache_node_data(node_data->prev);\n        _z_lru_cache_node_data_t *next_data = _z_lru_cache_node_data(node_data->next);\n        prev_data->next = node_data->next;\n        next_data->prev = node_data->prev;\n    }\n    if (node_data->prev == NULL) {\n        assert(cache->head == node);\n        cache->head = node_data->next;\n        if (node_data->next != NULL) {\n            _z_lru_cache_node_data_t *next_data = _z_lru_cache_node_data(node_data->next);\n            next_data->prev = NULL;\n        }\n    }\n    if (node_data->next == NULL) {\n        assert(cache->tail == node);\n        cache->tail = node_data->prev;\n        if (node_data->prev != NULL) {\n            _z_lru_cache_node_data_t *prev_data = _z_lru_cache_node_data(node_data->prev);\n            prev_data->next = NULL;\n        }\n    }\n}\n\nstatic void _z_lru_cache_update_list(_z_lru_cache_t *cache, _z_lru_cache_node_t *node) {\n    _z_lru_cache_remove_list_node(cache, node);\n    _z_lru_cache_insert_list_node(cache, node);\n}\n\nstatic void _z_lru_cache_clear_list(_z_lru_cache_t *cache, z_element_clear_f clear) {\n    _z_lru_cache_node_data_t *node = cache->head;\n    while (node != NULL) {\n        _z_lru_cache_node_t *tmp = node;\n        _z_lru_cache_node_data_t *node_data = _z_lru_cache_node_data(node);\n        void *node_value = _z_lru_cache_node_value(node);\n        node = node_data->next;\n        clear(node_value);\n        z_free(tmp);\n    }\n}\n\n// Sorted list function\nstatic _z_lru_cache_node_t *_z_lru_cache_search_slist(_z_lru_cache_t *cache, void *value, _z_lru_val_cmp_f compare,\n                                                      size_t *idx) {\n    int l_idx = 0;\n    int h_idx = (int)cache->len - 1;\n    while (l_idx <= h_idx) {\n        int curr_idx = (l_idx + h_idx) / 2;\n        int res = compare(_z_lru_cache_node_value(cache->slist[curr_idx]), value);\n        if (res == 0) {\n            *idx = (size_t)curr_idx;\n            return cache->slist[curr_idx];\n        } else if (res < 0) {\n            l_idx = curr_idx + 1;\n        } else {\n            h_idx = curr_idx - 1;\n        }\n    }\n    return NULL;\n}\n\nstatic int _z_lru_cache_find_position(_z_lru_cache_node_t **slist, _z_lru_val_cmp_f compare, void *node_val,\n                                      size_t slist_size) {\n    int start = 0;\n    int end = (int)slist_size - 1;\n    while (start <= end) {\n        int mid = start + (end - start) / 2;\n        if (compare(_z_lru_cache_node_value(slist[mid]), node_val) < 0) {\n            start = mid + 1;\n        } else {\n            end = mid - 1;\n        }\n    }\n    return start;\n}\n\nstatic void _z_lru_cache_move_elem_slist(_z_lru_cache_t *cache, size_t *add_idx_addr, size_t *del_idx_addr) {\n    size_t del_idx = (del_idx_addr == NULL) ? cache->len : *del_idx_addr;\n    size_t add_idx = *add_idx_addr;\n    if (add_idx == del_idx) {\n        return;\n    }\n    // Move elements between the indices on the right\n    if (del_idx >= add_idx) {\n        memmove(&cache->slist[add_idx + 1], &cache->slist[add_idx],\n                (del_idx - add_idx) * sizeof(_z_lru_cache_node_t *));\n    } else {  // Move them on the left\n        // Rightmost value doesn't move unless we have a new maximum\n        if (add_idx != cache->capacity - 1) {\n            *add_idx_addr -= 1;\n            add_idx -= 1;\n        }\n        memmove(&cache->slist[del_idx], &cache->slist[del_idx + 1],\n                (add_idx - del_idx) * sizeof(_z_lru_cache_node_t *));\n    }\n}\n\nstatic void _z_lru_cache_insert_slist(_z_lru_cache_t *cache, _z_lru_cache_node_t *node, _z_lru_val_cmp_f compare,\n                                      size_t *del_idx) {\n    // Find insert position:\n    if (cache->len == 0) {\n        cache->slist[0] = node;\n        return;\n    }\n    void *node_val = _z_lru_cache_node_value(node);\n    size_t pos = (size_t)_z_lru_cache_find_position(cache->slist, compare, node_val, cache->len);\n    // Move elements\n    _z_lru_cache_move_elem_slist(cache, &pos, del_idx);\n    // Store element\n    cache->slist[pos] = node;\n}\n\nstatic size_t _z_lru_cache_delete_slist(_z_lru_cache_t *cache, _z_lru_cache_node_t *node, _z_lru_val_cmp_f compare) {\n    size_t del_idx = 0;\n    // Don't delete, return the index\n    (void)_z_lru_cache_search_slist(cache, _z_lru_cache_node_value(node), compare, &del_idx);\n    return del_idx;\n}\n\n// Main static functions\nstatic size_t _z_lru_cache_delete_last(_z_lru_cache_t *cache, _z_lru_val_cmp_f compare) {\n    _z_lru_cache_node_t *last = cache->tail;\n    assert(last != NULL);\n    _z_lru_cache_remove_list_node(cache, last);\n    size_t del_idx = _z_lru_cache_delete_slist(cache, last, compare);\n    z_free(last);\n    cache->len--;\n    return del_idx;\n}\n\nstatic void _z_lru_cache_insert_node(_z_lru_cache_t *cache, _z_lru_cache_node_t *node, _z_lru_val_cmp_f compare,\n                                     size_t *del_idx) {\n    _z_lru_cache_insert_list_node(cache, node);\n    _z_lru_cache_insert_slist(cache, node, compare, del_idx);\n    cache->len++;\n}\n\nstatic _z_lru_cache_node_t *_z_lru_cache_search_node(_z_lru_cache_t *cache, void *value, _z_lru_val_cmp_f compare) {\n    size_t idx = 0;\n    return _z_lru_cache_search_slist(cache, value, compare, &idx);\n}\n\n// Public functions\n_z_lru_cache_t _z_lru_cache_init(size_t capacity) {\n    _z_lru_cache_t cache = _z_lru_cache_null();\n    cache.capacity = capacity;\n    return cache;\n}\n\nvoid *_z_lru_cache_get(_z_lru_cache_t *cache, void *value, _z_lru_val_cmp_f compare) {\n    // Lookup if node exists.\n    _z_lru_cache_node_t *node = _z_lru_cache_search_node(cache, value, compare);\n    if (node == NULL) {\n        return NULL;\n    }\n    // Update list with node as most recent\n    _z_lru_cache_update_list(cache, node);\n    return _z_lru_cache_node_value(node);\n}\n\nz_result_t _z_lru_cache_insert(_z_lru_cache_t *cache, void *value, size_t value_size, _z_lru_val_cmp_f compare) {\n    assert(cache->capacity > 0);\n    // Init slist\n    if (cache->slist == NULL) {\n        cache->slist = (_z_lru_cache_node_t **)z_malloc(cache->capacity * sizeof(void *));\n        if (cache->slist == NULL) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        memset(cache->slist, 0, cache->capacity * sizeof(void *));\n    }\n    // Create node\n    _z_lru_cache_node_t *node = _z_lru_cache_node_create(value, value_size);\n    size_t *del_idx_addr = NULL;\n    size_t del_idx = 0;\n    if (node == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Check capacity\n    if (cache->len == cache->capacity) {\n        // Delete lru entry\n        del_idx = _z_lru_cache_delete_last(cache, compare);\n        del_idx_addr = &del_idx;\n    }\n    // Update the cache\n    _z_lru_cache_insert_node(cache, node, compare, del_idx_addr);\n    return _Z_RES_OK;\n}\n\nvoid _z_lru_cache_clear(_z_lru_cache_t *cache, z_element_clear_f clear) {\n    // Reset slist\n    if (cache->slist != NULL) {\n        memset(cache->slist, 0, cache->capacity * sizeof(void *));\n    }\n    // Clear list\n    _z_lru_cache_clear_list(cache, clear);\n    // Reset cache\n    cache->len = 0;\n    cache->head = NULL;\n    cache->tail = NULL;\n}\n\nvoid _z_lru_cache_delete(_z_lru_cache_t *cache, z_element_clear_f clear) {\n    _z_lru_cache_clear(cache, clear);\n    z_free(cache->slist);\n    cache->slist = NULL;\n}\n"
  },
  {
    "path": "src/collections/refcount.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/refcount.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/collections/atomic.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#define _Z_RC_MAX_COUNT INT32_MAX  // Based on Rust lazy overflow check\ntypedef struct {\n    _z_atomic_size_t _strong_cnt;\n    _z_atomic_size_t _weak_cnt;\n} _z_inner_rc_t;\n\nstatic inline _z_inner_rc_t* _z_rc_inner(void* rc) { return (_z_inner_rc_t*)rc; }\n\nz_result_t _z_rc_init(void** cnt) {\n    *cnt = z_malloc(sizeof(_z_inner_rc_t));\n    if ((*cnt) == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    _z_inner_rc_t* rc = *cnt;\n    _z_atomic_size_init(&rc->_strong_cnt, 1);\n    _z_atomic_size_init(&rc->_weak_cnt, 1);\n    // Note we increase weak count by 1 when creating a new rc, to take ownership of counter.\n    return _Z_RES_OK;\n}\n\nz_result_t _z_rc_increase_strong(void* cnt) {\n    _z_inner_rc_t* c = (_z_inner_rc_t*)cnt;\n    if (c == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    if (_z_atomic_size_fetch_add(&c->_strong_cnt, 1, _z_memory_order_relaxed) >= _Z_RC_MAX_COUNT) {\n        _Z_ERROR(\"Rc strong count overflow\");\n        _Z_ERROR_RETURN(_Z_ERR_OVERFLOW);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_rc_increase_weak(void* cnt) {\n    _z_inner_rc_t* c = (_z_inner_rc_t*)cnt;\n    if (c == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    if (_z_atomic_size_fetch_add(&c->_weak_cnt, 1, _z_memory_order_relaxed) >= _Z_RC_MAX_COUNT) {\n        _Z_ERROR(\"Rc weak count overflow\");\n        _Z_ERROR_RETURN(_Z_ERR_OVERFLOW);\n    }\n    return _Z_RES_OK;\n}\n\nbool _z_rc_decrease_strong(void** cnt) {\n    _z_inner_rc_t* c = (_z_inner_rc_t*)*cnt;\n    if (_z_atomic_size_fetch_sub(&c->_strong_cnt, 1, _z_memory_order_release) > 1) {\n        return false;\n    }\n    // destroy fake weak that we created during strong init\n    _z_rc_decrease_weak(cnt);\n    return true;\n}\n\nbool _z_rc_decrease_weak(void** cnt) {\n    _z_inner_rc_t* c = (_z_inner_rc_t*)*cnt;\n    if (_z_atomic_size_fetch_sub(&c->_weak_cnt, 1, _z_memory_order_release) > 1) {\n        return false;\n    }\n    _z_atomic_thread_fence(\n        _z_memory_order_acquire);  // ensure we see the latest state of strong count before we free the counter\n    z_free(*cnt);\n    *cnt = NULL;\n    return true;\n}\n\nz_result_t _z_rc_weak_upgrade(void* cnt) {\n    if (cnt == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    _z_inner_rc_t* c = (_z_inner_rc_t*)cnt;\n    size_t prev = _z_atomic_size_load(&c->_strong_cnt, _z_memory_order_relaxed);\n    while ((prev != 0) && (prev < _Z_RC_MAX_COUNT)) {\n        if (_z_atomic_size_compare_exchange_weak(&c->_strong_cnt, &prev, prev + 1, _z_memory_order_acquire,\n                                                 _z_memory_order_relaxed)) {\n            return _Z_RES_OK;\n        }\n    }\n    _Z_ERROR_RETURN(_Z_ERR_INVALID);\n}\n\nsize_t _z_rc_weak_count(void* rc) {\n    if (rc == NULL) {\n        return 0;\n    }\n    size_t strong_count = _z_atomic_size_load(&_z_rc_inner(rc)->_strong_cnt, _z_memory_order_relaxed);\n    size_t weak_count = _z_atomic_size_load(&_z_rc_inner(rc)->_weak_cnt, _z_memory_order_relaxed);\n    if (weak_count == 0) {\n        return 0;\n    }\n    return (strong_count > 0) ? weak_count - 1 : weak_count;  // substruct 1 weak ref that we added during strong init\n}\n\nsize_t _z_rc_strong_count(void* rc) {\n    return rc == NULL ? 0 : _z_atomic_size_load(&_z_rc_inner(rc)->_strong_cnt, _z_memory_order_relaxed);\n}\n\ntypedef struct {\n    _z_atomic_size_t _strong_cnt;\n} _z_inner_simple_rc_t;\n\n#define RC_CNT_SIZE sizeof(_z_inner_simple_rc_t)\n\nstatic inline _z_inner_simple_rc_t* _z_simple_rc_inner(void* rc) { return (_z_inner_simple_rc_t*)rc; }\n\nvoid* _z_simple_rc_value(void* rc) { return (void*)_z_ptr_u8_offset((uint8_t*)rc, (ptrdiff_t)RC_CNT_SIZE); }\n\nz_result_t _z_simple_rc_init(void** rc, const void* val, size_t val_size) {\n    *rc = z_malloc(RC_CNT_SIZE + val_size);\n    if ((*rc) == NULL) {\n        _Z_ERROR(\"Failed to allocate rc\");\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    _z_inner_simple_rc_t* inner = _z_simple_rc_inner(*rc);\n    _z_atomic_size_init(&inner->_strong_cnt, 1);\n    memcpy(_z_simple_rc_value(*rc), val, val_size);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_simple_rc_increase(void* rc) {\n    _z_inner_simple_rc_t* c = _z_simple_rc_inner(rc);\n    if (_z_atomic_size_fetch_add(&c->_strong_cnt, 1, _z_memory_order_relaxed) >= _Z_RC_MAX_COUNT) {\n        _Z_ERROR(\"Rc strong count overflow\");\n        _Z_ERROR_RETURN(_Z_ERR_OVERFLOW);\n    }\n    return _Z_RES_OK;\n}\n\nbool _z_simple_rc_decrease(void* rc) {\n    _z_inner_simple_rc_t* c = _z_simple_rc_inner(rc);\n    if (_z_atomic_size_fetch_sub(&c->_strong_cnt, 1, _z_memory_order_release) > 1) {\n        return false;\n    }\n    return true;\n}\n\nsize_t _z_simple_rc_strong_count(void* rc) {\n    return rc == NULL ? 0 : _z_atomic_size_load(&(_z_simple_rc_inner(rc)->_strong_cnt), _z_memory_order_relaxed);\n}\n"
  },
  {
    "path": "src/collections/ring.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/ring.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n/*-------- ring --------*/\nz_result_t _z_ring_init(_z_ring_t *r, size_t capacity) {\n    // We need one more element to differentiate wether the ring is empty or full\n    capacity++;\n\n    memset(r, 0, sizeof(_z_ring_t));\n    if (capacity != (size_t)0) {\n        r->_val = (void **)z_malloc(sizeof(void *) * capacity);\n    }\n    if (r->_val != NULL) {\n        memset(r->_val, 0, capacity);\n        r->_capacity = capacity;\n    }\n    return 0;\n}\n\n_z_ring_t _z_ring_make(size_t capacity) {\n    _z_ring_t v;\n    _z_ring_init(&v, capacity);\n    return v;\n}\n\nsize_t _z_ring_capacity(const _z_ring_t *r) { return r->_capacity - (size_t)1; }\n\nsize_t _z_ring_len(const _z_ring_t *r) {\n    if (r->_w_idx >= r->_r_idx) {\n        return r->_w_idx - r->_r_idx;\n    } else {\n        return r->_w_idx + (r->_capacity - r->_r_idx);\n    }\n}\n\nbool _z_ring_is_empty(const _z_ring_t *r) { return r->_w_idx == r->_r_idx; }\n\nbool _z_ring_is_full(const _z_ring_t *r) { return _z_ring_len(r) == _z_ring_capacity(r); }\n\nvoid *_z_ring_push(_z_ring_t *r, void *e) {\n    void *ret = e;\n    if (!_z_ring_is_full(r)) {\n        r->_val[r->_w_idx] = e;\n        r->_w_idx = (r->_w_idx + (size_t)1) % r->_capacity;\n        ret = NULL;\n    }\n    return ret;\n}\n\nvoid *_z_ring_push_force(_z_ring_t *r, void *e) {\n    void *ret = _z_ring_push(r, e);\n    if (ret != NULL) {\n        ret = _z_ring_pull(r);\n        _z_ring_push(r, e);\n    }\n    return ret;\n}\n\nvoid _z_ring_push_force_drop(_z_ring_t *r, void *e, z_element_free_f free_f) {\n    void *ret = _z_ring_push_force(r, e);\n    if (ret != NULL) {\n        free_f(&ret);\n    }\n}\n\nvoid *_z_ring_pull(_z_ring_t *r) {\n    void *ret = NULL;\n    if (!_z_ring_is_empty(r)) {\n        ret = r->_val[r->_r_idx];\n        r->_val[r->_r_idx] = NULL;\n        r->_r_idx = (r->_r_idx + (size_t)1) % r->_capacity;\n    }\n    return ret;\n}\n\nvoid _z_ring_clear(_z_ring_t *r, z_element_free_f free_f) {\n    void *e = _z_ring_pull(r);\n    while (e != NULL) {\n        free_f(&e);\n        e = _z_ring_pull(r);\n    }\n    z_free(r->_val);\n\n    r->_val = NULL;\n    r->_capacity = (size_t)0;\n    r->_len = (size_t)0;\n    r->_r_idx = (size_t)0;\n    r->_w_idx = (size_t)0;\n}\n\nvoid _z_ring_free(_z_ring_t **r, z_element_free_f free_f) {\n    _z_ring_t *ptr = (_z_ring_t *)*r;\n    if (ptr != NULL) {\n        _z_ring_clear(ptr, free_f);\n        z_free(ptr);\n        *r = NULL;\n    }\n}\n\n_z_ring_iterator_t _z_ring_iterator_make(const _z_ring_t *ring) {\n    _z_ring_iterator_t iter = {0};\n\n    iter._ring = ring;\n    iter._r_idx = ring->_r_idx;\n    iter._w_idx = ring->_w_idx;\n\n    return iter;\n}\n\nbool _z_ring_iterator_next(_z_ring_iterator_t *iter) {\n    if (iter->_r_idx != iter->_w_idx) {\n        iter->_val = iter->_ring->_val[iter->_r_idx];\n        iter->_r_idx = (iter->_r_idx + (size_t)1) % iter->_ring->_capacity;\n        return true;\n    }\n    return false;\n}\n\nvoid *_z_ring_iterator_value(const _z_ring_iterator_t *iter) { return iter->_val; }\n\n_z_ring_reverse_iterator_t _z_ring_reverse_iterator_make(const _z_ring_t *ring) {\n    _z_ring_reverse_iterator_t iter = {0};\n\n    iter._ring = ring;\n    iter._r_idx = (ring->_w_idx == 0) ? ring->_capacity - 1 : ring->_w_idx - 1;\n    iter._w_idx = (ring->_r_idx == 0) ? ring->_capacity - 1 : ring->_r_idx - 1;\n\n    return iter;\n}\n\nbool _z_ring_reverse_iterator_next(_z_ring_reverse_iterator_t *iter) {\n    if (iter->_r_idx != iter->_w_idx) {\n        iter->_val = iter->_ring->_val[iter->_r_idx];\n        iter->_r_idx = (iter->_r_idx == 0) ? iter->_ring->_capacity - 1 : iter->_r_idx - 1;\n        return true;\n    }\n    return false;\n}\n\nvoid *_z_ring_reverse_iterator_value(const _z_ring_reverse_iterator_t *iter) { return iter->_val; }\n"
  },
  {
    "path": "src/collections/ring_mt.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/ring_mt.h\"\n\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/*-------- Ring Buffer Multithreaded --------*/\nz_result_t _z_ring_mt_init(_z_ring_mt_t *ring, size_t capacity) {\n    _Z_RETURN_IF_ERR(_z_ring_init(&ring->_ring, capacity))\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_init(&ring->_mutex))\n    _Z_RETURN_IF_ERR(_z_condvar_init(&ring->_cv_not_empty))\n#endif\n    ring->is_closed = false;\n    return _Z_RES_OK;\n}\n\n_z_ring_mt_t *_z_ring_mt_new(size_t capacity) {\n    _z_ring_mt_t *ring = (_z_ring_mt_t *)z_malloc(sizeof(_z_ring_mt_t));\n    if (ring == NULL) {\n        _Z_ERROR(\"z_malloc failed\");\n        return NULL;\n    }\n\n    z_result_t ret = _z_ring_mt_init(ring, capacity);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"_z_ring_mt_init failed: %i\", ret);\n        return NULL;\n    }\n\n    return ring;\n}\n\nvoid _z_ring_mt_clear(_z_ring_mt_t *ring, z_element_free_f free_f) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_drop(&ring->_mutex);\n    _z_condvar_drop(&ring->_cv_not_empty);\n#endif\n\n    _z_ring_clear(&ring->_ring, free_f);\n}\n\nvoid _z_ring_mt_free(_z_ring_mt_t *ring, z_element_free_f free_f) {\n    _z_ring_mt_clear(ring, free_f);\n\n    z_free(ring);\n}\n\nz_result_t _z_ring_mt_push(const void *elem, void *context, z_element_free_f element_free) {\n    if (elem == NULL || context == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_ring_mt_t *r = (_z_ring_mt_t *)context;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&r->_mutex))\n#endif\n\n    _z_ring_push_force_drop(&r->_ring, (void *)elem, element_free);\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_condvar_signal(&r->_cv_not_empty))\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&r->_mutex))\n#endif\n    return _Z_RES_OK;\n}\n\nz_result_t _z_ring_mt_close(_z_ring_mt_t *ring) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&ring->_mutex))\n    ring->is_closed = true;\n    _Z_RETURN_IF_ERR(_z_condvar_signal_all(&ring->_cv_not_empty))\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&ring->_mutex))\n#else\n    ring->is_closed = true;\n#endif\n    return _Z_RES_OK;\n}\n\nz_result_t _z_ring_mt_pull(void *dst, void *context, z_element_move_f element_move) {\n    _z_ring_mt_t *r = (_z_ring_mt_t *)context;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    void *src = NULL;\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&r->_mutex))\n    while (src == NULL) {\n        src = _z_ring_pull(&r->_ring);\n        if (src == NULL) {\n            if (r->is_closed) break;\n            _Z_RETURN_IF_ERR(_z_condvar_wait(&r->_cv_not_empty, &r->_mutex))\n        }\n    }\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&r->_mutex))\n#else   // Z_FEATURE_MULTI_THREAD == 1\n    void *src = _z_ring_pull(&r->_ring);\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    if (r->is_closed && src == NULL) {\n        return _Z_RES_CHANNEL_CLOSED;\n    }\n\n    if (src != NULL) {\n        element_move(dst, src);\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_ring_mt_try_pull(void *dst, void *context, z_element_move_f element_move) {\n    _z_ring_mt_t *r = (_z_ring_mt_t *)context;\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&r->_mutex))\n#endif\n\n    void *src = _z_ring_pull(&r->_ring);\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_unlock(&r->_mutex))\n#endif\n\n    if (src != NULL) {\n        element_move(dst, src);\n    } else if (r->is_closed) {\n        return _Z_RES_CHANNEL_CLOSED;\n    } else {\n        return _Z_RES_CHANNEL_NODATA;\n    }\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/collections/slice.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/slice.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/result.h\"\n\nvoid _z_default_deleter(void *data, void *context) {\n    _ZP_UNUSED(context);\n    z_free(data);\n}\nvoid _z_static_deleter(void *data, void *context) {\n    _ZP_UNUSED(data);\n    _ZP_UNUSED(context);\n}\n_z_delete_context_t _z_delete_context_default(void) { return _z_delete_context_create(_z_default_deleter, NULL); }\n_z_delete_context_t _z_delete_context_static(void) { return _z_delete_context_create(_z_static_deleter, NULL); }\n\n/*-------- Slice --------*/\nz_result_t _z_slice_init(_z_slice_t *bs, size_t capacity) {\n    assert(bs != NULL);\n    if (capacity == 0) {\n        *bs = _z_slice_null();\n        return _Z_RES_OK;\n    }\n    bs->start = (uint8_t *)z_malloc(capacity);\n    if (bs->start == NULL) {\n        bs->len = 0;\n        bs->_delete_context = _z_delete_context_null();\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    bs->len = capacity;\n    bs->_delete_context = _z_delete_context_default();\n    return _Z_RES_OK;\n}\n\n_z_slice_t _z_slice_make(size_t capacity) {\n    _z_slice_t bs;\n    (void)_z_slice_init(&bs, capacity);\n    return bs;\n}\n\n_z_slice_t _z_slice_copy_from_buf(const uint8_t *p, size_t len) {\n    if (len == 0) {\n        return _z_slice_null();\n    }\n    _z_slice_t bs = _z_slice_alias_buf(p, len);\n    return _z_slice_duplicate(&bs);\n}\n\nvoid _z_slice_free(_z_slice_t **bs) {\n    _z_slice_t *ptr = *bs;\n\n    if (ptr != NULL) {\n        _z_slice_clear(ptr);\n\n        z_free(ptr);\n        *bs = NULL;\n    }\n}\n\nz_result_t _z_slice_copy(_z_slice_t *dst, const _z_slice_t *src) {\n    assert(src != NULL);\n    assert(src->len == 0 || src->start != NULL);\n    if (src->len == 0) {\n        *dst = _z_slice_null();\n        return _Z_RES_OK;\n    }\n    // Make sure dst slice is not init beforehand, or suffer memory leak\n    z_result_t ret = _z_slice_init(dst, src->len);\n    if (ret == _Z_RES_OK) {\n        (void)memcpy((uint8_t *)dst->start, src->start, src->len);\n    }\n    return ret;\n}\n\nz_result_t _z_slice_n_copy(_z_slice_t *dst, const _z_slice_t *src, size_t offset, size_t len) {\n    assert(offset + len <= src->len);\n    if (len == 0) {\n        *dst = _z_slice_null();\n        return _Z_RES_OK;\n    }\n    // Make sure dst slice is not init beforehand, or suffer memory leak\n    z_result_t ret = _z_slice_init(dst, len);\n    if (ret == _Z_RES_OK) {\n        const uint8_t *start = _z_cptr_u8_offset(src->start, (ptrdiff_t)offset);\n        (void)memcpy((uint8_t *)dst->start, start, len);\n    }\n    return ret;\n}\n\nz_result_t _z_slice_move(_z_slice_t *dst, _z_slice_t *src) {\n    // avoid moving of aliased slices\n    if (!_z_slice_is_alloced(src)) {\n        *dst = _z_slice_null();\n        _z_slice_t csrc;\n        _Z_RETURN_IF_ERR(_z_slice_copy(&csrc, src));\n        *src = csrc;\n    }\n    *dst = *src;\n    _z_slice_reset(src);\n    return _Z_RES_OK;\n}\n\n_z_slice_t _z_slice_duplicate(const _z_slice_t *src) {\n    _z_slice_t dst = _z_slice_null();\n    _z_slice_copy(&dst, src);\n    return dst;\n}\n\n_z_slice_t _z_slice_steal(_z_slice_t *b) {\n    _z_slice_t ret = *b;\n    *b = _z_slice_null();\n    return ret;\n}\nbool _z_slice_eq(const _z_slice_t *left, const _z_slice_t *right) {\n    assert(left != NULL);\n    assert(right != NULL);\n    if (left->len != right->len) {\n        return false;\n    }\n    if (left->len == 0) {\n        return true;\n    }\n    assert(left->start != NULL);\n    assert(right->start != NULL);\n    return memcmp(left->start, right->start, left->len) == 0;\n}\n\nbool _z_slice_is_alloced(const _z_slice_t *s) { return !_z_delete_context_is_null(&s->_delete_context); }\n"
  },
  {
    "path": "src/collections/sortedmap.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/sortedmap.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\n/*-------- sortedmap --------*/\nvoid _z_sortedmap_init(_z_sortedmap_t *map, z_element_cmp_f f_cmp) {\n    map->_vals = NULL;\n    map->_f_cmp = f_cmp;\n}\n\n_z_sortedmap_t _z_sortedmap_make(z_element_cmp_f f_cmp) {\n    _z_sortedmap_t map;\n    _z_sortedmap_init(&map, f_cmp);\n    return map;\n}\n\nsize_t _z_sortedmap_len(const _z_sortedmap_t *map) { return _z_list_len(map->_vals); }\n\nbool _z_sortedmap_is_empty(const _z_sortedmap_t *map) { return _z_sortedmap_len(map) == (size_t)0; }\n\nz_result_t _z_sortedmap_copy(_z_sortedmap_t *dst, const _z_sortedmap_t *src, z_element_clone_f f_c) {\n    assert((dst != NULL) && (src != NULL));\n    if (src->_vals != NULL) {\n        dst->_vals = _z_list_clone(src->_vals, f_c);\n        if (dst->_vals == NULL) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n    }\n    dst->_f_cmp = src->_f_cmp;\n    return _Z_RES_OK;\n}\n\n_z_sortedmap_t _z_sortedmap_clone(const _z_sortedmap_t *src, z_element_clone_f f_c, z_element_free_f f_f) {\n    _z_sortedmap_t dst = {._vals = NULL, ._f_cmp = src->_f_cmp};\n    if (src->_vals == NULL) {\n        return dst;\n    }\n    if (_z_sortedmap_copy(&dst, src, f_c) != _Z_RES_OK) {\n        // Free the map\n        _z_sortedmap_clear(&dst, f_f);\n    }\n    return dst;\n}\n\nvoid *_z_sortedmap_insert(_z_sortedmap_t *map, void *k, void *v, z_element_free_f f_f, bool replace) {\n    if (map == NULL) {\n        return NULL;\n    }\n\n    _z_list_t *prev = NULL;\n    _z_list_t *curr = map->_vals;\n\n    while (curr != NULL) {\n        _z_sortedmap_entry_t *entry = (_z_sortedmap_entry_t *)_z_list_value(curr);\n        int cmp = map->_f_cmp(k, entry->_key);\n\n        if (cmp == 0) {\n            if (!replace) {\n                return NULL;\n            }\n            map->_vals = _z_list_drop_element(map->_vals, prev, f_f);\n            break;\n        } else if (cmp < 0) {\n            break;  // Found insertion point\n        }\n\n        prev = curr;\n        curr = _z_list_next(curr);\n    }\n\n    _z_sortedmap_entry_t *entry = (_z_sortedmap_entry_t *)z_malloc(sizeof(_z_sortedmap_entry_t));\n    if (entry == NULL) {\n        return NULL;\n    }\n    entry->_key = k;\n    entry->_val = v;\n\n    if (prev == NULL) {\n        map->_vals = _z_list_push(map->_vals, entry);\n        if (map->_vals == NULL) {\n            z_free(entry);\n            return NULL;\n        }\n    } else {\n        _z_list_t *list = _z_list_push_after(prev, entry);\n        if (list == NULL) {\n            z_free(entry);\n            return NULL;\n        }\n    }\n\n    return v;\n}\n\nvoid *_z_sortedmap_get(const _z_sortedmap_t *map, const void *k) {\n    void *ret = NULL;\n\n    if (map->_vals != NULL) {\n        _z_list_t *l = map->_vals;\n        while (l != NULL) {\n            // Check if the key matches\n            _z_sortedmap_entry_t *entry = (_z_sortedmap_entry_t *)_z_list_value(l);\n            if (map->_f_cmp(k, entry->_key) == 0) {\n                ret = entry->_val;\n                break;\n            }\n            l = _z_list_next(l);\n        }\n    }\n    return ret;\n}\n\n_z_sortedmap_entry_t *_z_sortedmap_pop_first(_z_sortedmap_t *map) {\n    _z_sortedmap_entry_t *ret = NULL;\n\n    if (map->_vals != NULL) {\n        _z_list_t *l = map->_vals;\n        if (l != NULL) {\n            ret = (_z_sortedmap_entry_t *)_z_list_value(l);\n            map->_vals = _z_list_drop_element(map->_vals, NULL, _z_noop_free);\n        }\n    }\n    return ret;\n}\n\nvoid _z_sortedmap_remove(_z_sortedmap_t *map, const void *k, z_element_free_f f) {\n    if (map->_vals != NULL) {\n        _z_list_t *prev = NULL;\n        _z_list_t *curr = map->_vals;\n\n        while (curr != NULL) {\n            _z_sortedmap_entry_t *entry = (_z_sortedmap_entry_t *)_z_list_value(curr);\n            if (map->_f_cmp(k, entry->_key) == 0) {\n                map->_vals = _z_list_drop_element(map->_vals, prev, f);\n                break;\n            }\n            prev = curr;\n            curr = _z_list_next(curr);\n        }\n    }\n}\n\n_z_sortedmap_iterator_t _z_sortedmap_iterator_make(const _z_sortedmap_t *map) {\n    _z_sortedmap_iterator_t iter = {0};\n    iter._map = map;\n    iter._list_ptr = map->_vals;\n    return iter;\n}\n\nbool _z_sortedmap_iterator_next(_z_sortedmap_iterator_t *iter) {\n    if (!iter->_initialized) {\n        iter->_list_ptr = iter->_map->_vals;\n        iter->_initialized = true;\n    } else if (iter->_list_ptr != NULL) {\n        iter->_list_ptr = _z_list_next(iter->_list_ptr);\n    }\n\n    if (iter->_list_ptr != NULL) {\n        iter->_entry = (_z_sortedmap_entry_t *)_z_list_value(iter->_list_ptr);\n        return true;\n    }\n\n    return false;\n}\n\nvoid *_z_sortedmap_iterator_key(const _z_sortedmap_iterator_t *iter) { return iter->_entry->_key; }\n\nvoid *_z_sortedmap_iterator_value(const _z_sortedmap_iterator_t *iter) { return iter->_entry->_val; }\n\nvoid _z_sortedmap_clear(_z_sortedmap_t *map, z_element_free_f f_f) {\n    if (map->_vals != NULL) {\n        _z_list_free(&map->_vals, f_f);\n        map->_vals = NULL;\n    }\n}\n\nvoid _z_sortedmap_free(_z_sortedmap_t **map, z_element_free_f f) {\n    _z_sortedmap_t *ptr = *map;\n    if (ptr != NULL) {\n        _z_sortedmap_clear(ptr, f);\n\n        z_free(ptr);\n        *map = NULL;\n    }\n}\n"
  },
  {
    "path": "src/collections/string.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/string.h\"\n\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n/*-------- string --------*/\n_z_string_t _z_string_copy_from_str(const char *value) {\n    _z_string_t s;\n    s._slice = _z_slice_copy_from_buf((uint8_t *)value, strlen(value));\n    return s;\n}\n\n_z_string_t _z_string_copy_from_substr(const char *value, size_t len) {\n    _z_string_t s;\n    s._slice = _z_slice_copy_from_buf((uint8_t *)value, len);\n    return s;\n}\n\n_z_string_t *_z_string_copy_from_str_as_ptr(const char *value) {\n    _z_string_t *s = (_z_string_t *)z_malloc(sizeof(_z_string_t));\n    if (s == NULL) {\n        return NULL;\n    }\n    *s = _z_string_copy_from_str(value);\n    if (_z_slice_is_empty(&s->_slice) && value != NULL) {\n        z_free(s);\n        return NULL;\n    }\n    return s;\n}\n\nz_result_t _z_string_copy(_z_string_t *dst, const _z_string_t *src) {\n    return _z_slice_copy(&dst->_slice, &src->_slice);\n}\n\nz_result_t _z_string_copy_substring(_z_string_t *dst, const _z_string_t *src, size_t offset, size_t len) {\n    return _z_slice_n_copy(&dst->_slice, &src->_slice, offset, len);\n}\n\nz_result_t _z_string_move(_z_string_t *dst, _z_string_t *src) { return _z_slice_move(&dst->_slice, &src->_slice); }\n\n_z_string_t _z_string_steal(_z_string_t *str) {\n    _z_string_t ret;\n    ret._slice = _z_slice_steal(&str->_slice);\n    return ret;\n}\n\nvoid _z_string_move_str(_z_string_t *dst, char *src) { *dst = _z_string_alias_str(src); }\n\nvoid _z_string_free(_z_string_t **str) {\n    _z_string_t *ptr = *str;\n    if (ptr != NULL) {\n        _z_string_clear(ptr);\n\n        z_free(ptr);\n        *str = NULL;\n    }\n}\nint _z_substring_compare(const _z_string_t *left, size_t left_start, size_t left_len, const _z_string_t *right,\n                         size_t right_start, size_t right_len) {\n    int result = strncmp(_z_string_data(left) + left_start, _z_string_data(right) + right_start,\n                         left_len < right_len ? left_len : right_len);\n\n    if (result == 0) {\n        if (left_len < right_len) {\n            return -1;\n        } else if (left_len > right_len) {\n            return 1;\n        }\n    }\n\n    return result;\n}\n\nint _z_string_compare(const _z_string_t *left, const _z_string_t *right) {\n    return _z_substring_compare(left, 0, _z_string_len(left), right, 0, _z_string_len(right));\n}\n\nbool _z_string_equals(const _z_string_t *left, const _z_string_t *right) {\n    if (_z_string_len(left) != _z_string_len(right)) {\n        return false;\n    }\n    return (strncmp(_z_string_data(left), _z_string_data(right), _z_string_len(left)) == 0);\n}\n\n_z_string_t _z_string_convert_bytes_le(const _z_slice_t *bs) {\n    _z_string_t s = _z_string_null();\n    size_t len = bs->len * (size_t)2;\n    char *s_val = (char *)z_malloc((len) * sizeof(char));\n    if (s_val == NULL) {\n        return s;\n    }\n\n    const char c[] = \"0123456789abcdef\";\n    size_t pos = bs->len * 2;\n    for (size_t i = 0; i < bs->len; i++) {\n        s_val[--pos] = c[bs->start[i] & (uint8_t)0x0F];\n        s_val[--pos] = c[(bs->start[i] & (uint8_t)0xF0) >> (uint8_t)4];\n    }\n    s._slice = _z_slice_from_buf_custom_deleter((const uint8_t *)s_val, len, _z_delete_context_default());\n    return s;\n}\n\n_z_string_t _z_string_preallocate(size_t len) {\n    _z_string_t s;\n    // As long as _z_string_t is only a slice, no need to do anything more\n    if (_z_slice_init(&s._slice, len) != _Z_RES_OK) {\n        _Z_ERROR(\"String allocation failed\");\n    }\n    return s;\n}\n\nconst char *_z_string_rchr(_z_string_t *str, char filter) {\n    const char *curr_res = NULL;\n    const char *ret = NULL;\n    const char *curr_addr = _z_string_data(str);\n    size_t curr_len = _z_string_len(str);\n    do {\n        curr_res = (char *)memchr(curr_addr, (int)filter, curr_len);\n        if (curr_res != NULL) {\n            ret = curr_res;\n            curr_addr = curr_res + 1;\n            curr_len = _z_ptr_char_diff(curr_addr, _z_string_data(str));\n            if (curr_len >= _z_string_len(str)) {\n                break;\n            }\n            curr_len = _z_string_len(str) - curr_len;\n        }\n    } while (curr_res != NULL);\n    return ret;\n}\n\nchar *_z_string_pbrk(_z_string_t *str, const char *filter) {\n    const char *data = _z_string_data(str);\n    for (size_t idx = 0; idx < _z_string_len(str); idx++) {\n        const char *curr_char = filter;\n        while (*curr_char != '\\0') {\n            if (data[idx] == *curr_char) {\n                return (char *)&data[idx];\n            }\n            curr_char++;\n        }\n    }\n    return NULL;\n}\n\n/*-------- str --------*/\nsize_t _z_str_size(const char *src) { return strlen(src) + (size_t)1; }\n\nvoid _z_str_clear(char *src) { z_free(src); }\n\nvoid _z_str_free(char **src) {\n    char *ptr = *src;\n    if (ptr != NULL) {\n        _z_str_clear(ptr);\n\n        *src = NULL;\n    }\n}\n\nvoid _z_str_copy(char *dst, const char *src) {\n    size_t size = _z_str_size(src);\n    strncpy(dst, src, size - 1);\n    dst[size - 1] = '\\0';  // No matter what, strings are always null-terminated upon copy\n}\n\nvoid _z_str_n_copy(char *dst, const char *src, size_t size) {\n    strncpy(dst, src, size - 1);\n    dst[size - 1] = '\\0';  // No matter what, strings are always null-terminated upon copy\n}\n\nchar *_z_str_clone(const char *src) {\n    size_t len = _z_str_size(src);\n    char *dst = (char *)z_malloc(len);\n    if (dst != NULL) {\n        _z_str_n_copy(dst, src, len);\n    }\n\n    return dst;\n}\n\nchar *_z_str_n_clone(const char *src, size_t len) {\n    char *dst = (char *)z_malloc(len + 1);\n    if (dst != NULL) {\n        _z_str_n_copy(dst, src, len + 1);\n    }\n\n    return dst;\n}\n\nchar *_z_str_from_string_clone(const _z_string_t *str) {\n    return _z_str_n_clone((const char *)str->_slice.start, str->_slice.len);\n}\n\nbool _z_str_eq(const char *left, const char *right) { return strcmp(left, right) == 0; }\n\nint _z_str_cmp(const char *left, const char *right) { return strcmp(left, right); }\n\nz_result_t _z_string_concat_substr(_z_string_t *s, const _z_string_t *left, const char *right, size_t len,\n                                   const char *separator, size_t separator_len) {\n    if (separator == NULL && separator_len != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    *s = _z_string_null();\n    size_t left_len = _z_string_len(left);\n    if (len == 0) {\n        return _z_string_copy(s, left);\n    } else if (right == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    } else if (left_len == 0) {\n        *s = _z_string_copy_from_substr(right, len);\n        if (!_z_string_check(s)) {\n            return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        }\n    }\n\n    *s = _z_string_preallocate(left_len + len + separator_len);\n    if (!_z_string_check(s)) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    uint8_t *curr_ptr = (uint8_t *)_z_string_data(s);\n    // SAFETY: _z_string_preallocate and check of its result above ensures bound checks.\n    // Flawfinder: ignore [CWE-120]\n    memcpy(curr_ptr, _z_string_data(left), left_len);\n    curr_ptr += left_len;\n    if (separator_len > 0) {\n        // SAFETY: _z_string_preallocate and check of its result above ensures bound checks.\n        // Flawfinder: ignore [CWE-120]\n        memcpy(curr_ptr, separator, separator_len);\n        curr_ptr += separator_len;\n    }\n    // SAFETY: _z_string_preallocate and check of its result above ensures bound checks.\n    // Flawfinder: ignore [CWE-120]\n    memcpy(curr_ptr, right, len);\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/collections/sync_group.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/sync_group.h\"\n\n#include \"assert.h\"\n\nstatic inline bool __unsafe_z_sync_group_has_no_alive_notifiers(const _z_sync_group_t* sync_group) {\n    // NOTE: the function is unsafe because it requires sync_group_state mutex to be locked\n    return _z_sync_group_state_rc_weak_count(&sync_group->_state) == 0;\n}\n\nz_result_t _z_sync_group_state_create(_z_sync_group_state_t* state) {\n    state->is_closed = true;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_init(&state->counter_mutex));\n    _Z_CLEAN_RETURN_IF_ERR(_z_condvar_init(&state->counter_condvar), _z_mutex_drop(&state->counter_mutex));\n#endif\n    state->is_closed = false;\n    return Z_OK;\n}\n\nvoid _z_sync_group_state_clear(_z_sync_group_state_t* state) {\n    if (state != NULL) {\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_drop(&state->counter_mutex);\n        _z_condvar_drop(&state->counter_condvar);\n#endif\n    }\n}\n\nz_result_t _z_sync_group_wait(_z_sync_group_t* sync_group) {\n    if (_Z_RC_IS_NULL(&sync_group->_state)) {\n        return _Z_ERR_NULL;\n    }\n    _z_sync_group_state_t* state = _Z_RC_IN_VAL(&sync_group->_state);\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&state->counter_mutex));\n    while (!state->is_closed && !__unsafe_z_sync_group_has_no_alive_notifiers(sync_group)) {\n        _Z_RETURN_IF_ERR(_z_condvar_wait(&state->counter_condvar, &state->counter_mutex));\n    }\n    z_result_t ret = _Z_RES_OK;\n    if (state->is_closed) {\n        ret = Z_SYNC_GROUP_CLOSED;\n    } else {\n        state->is_closed = true;\n    }\n    _z_mutex_unlock(&state->counter_mutex);\n    return ret;\n#else\n    if (state->is_closed) {\n        return Z_SYNC_GROUP_CLOSED;\n    } else if (__unsafe_z_sync_group_has_no_alive_notifiers(sync_group)) {\n        state->is_closed = true;\n        return _Z_RES_OK;\n    } else {\n        return _Z_ERR_GENERIC;\n    }\n#endif\n}\n\nvoid _z_sync_group_close(_z_sync_group_t* sync_group) {\n    if (_Z_RC_IS_NULL(&sync_group->_state)) {\n        return;\n    }\n    _z_sync_group_state_t* state = _Z_RC_IN_VAL(&sync_group->_state);\n#if Z_FEATURE_MULTI_THREAD == 1\n    if (_z_mutex_lock(&state->counter_mutex) != _Z_RES_OK) {\n        return;\n    }\n#endif\n    state->is_closed = true;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_condvar_signal_all(&state->counter_condvar);\n    _z_mutex_unlock(&state->counter_mutex);\n#endif\n}\n\nz_result_t _z_sync_group_wait_deadline(_z_sync_group_t* sync_group, const z_clock_t* deadline) {\n    if (_Z_RC_IS_NULL(&sync_group->_state)) {\n        return _Z_ERR_NULL;\n    }\n    _z_sync_group_state_t* state = _Z_RC_IN_VAL(&sync_group->_state);\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_result_t ret = _Z_RES_OK;\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&state->counter_mutex));\n    while (!state->is_closed && !__unsafe_z_sync_group_has_no_alive_notifiers(sync_group)) {\n        ret = _z_condvar_wait_until(&state->counter_condvar, &state->counter_mutex, deadline);\n        if (ret == Z_ETIMEDOUT) {\n            break;\n        } else if (ret != _Z_RES_OK) {\n            return ret;\n        }\n    }\n    if (state->is_closed) {\n        ret = Z_SYNC_GROUP_CLOSED;\n    } else if (ret == _Z_RES_OK) {\n        state->is_closed = true;\n    }\n    _z_mutex_unlock(&state->counter_mutex);\n    return ret;\n#else\n    _ZP_UNUSED(deadline);\n    if (state->is_closed) {\n        return Z_SYNC_GROUP_CLOSED;\n    } else if (__unsafe_z_sync_group_has_no_alive_notifiers(sync_group)) {\n        state->is_closed = true;\n        return _Z_RES_OK;\n    } else {\n        return Z_ETIMEDOUT;\n    }\n#endif\n}\n\nz_result_t _z_sync_group_create(_z_sync_group_t* sync_group) {\n    _z_sync_group_state_t* state = (_z_sync_group_state_t*)z_malloc(sizeof(_z_sync_group_state_t));\n    if (state == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_sync_group_state_create(state), z_free(state));\n    sync_group->_state = _z_sync_group_state_rc_new(state);\n    if (_Z_RC_IS_NULL(&sync_group->_state)) {\n        _z_sync_group_state_clear(state);\n        z_free(state);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_sync_group_drop(_z_sync_group_t* sync_group) { _z_sync_group_state_rc_drop(&sync_group->_state); }\n\nz_result_t _z_sync_group_create_notifier(const _z_sync_group_t* sync_group, _z_sync_group_notifier_t* notifier) {\n    if (_Z_RC_IS_NULL(&sync_group->_state)) {\n        return _Z_ERR_NULL;\n    }\n    *notifier = _z_sync_group_notifier_null();\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&_Z_RC_IN_VAL(&sync_group->_state)->counter_mutex));\n#endif\n    if (_Z_RC_IN_VAL(&sync_group->_state)->is_closed) {\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_unlock(&_Z_RC_IN_VAL(&sync_group->_state)->counter_mutex);\n#endif\n        return Z_SYNC_GROUP_CLOSED;\n    }\n    notifier->_state = _z_sync_group_state_rc_clone_as_weak(&sync_group->_state);\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_unlock(&_Z_RC_IN_VAL(&sync_group->_state)->counter_mutex);\n#endif\n    return _Z_RC_IS_NULL(&notifier->_state) ? _Z_ERR_SYSTEM_OUT_OF_MEMORY : _Z_RES_OK;\n}\n\nvoid _z_sync_group_notifier_drop(_z_sync_group_notifier_t* notifier) {\n    if (_Z_RC_IS_NULL(&notifier->_state)) {\n        return;\n    }\n    _z_sync_group_state_rc_t state_rc = _z_sync_group_state_weak_upgrade(&notifier->_state);\n    if (!_Z_RC_IS_NULL(&state_rc)) {\n#if Z_FEATURE_MULTI_THREAD == 1\n        if (_z_mutex_lock(&_Z_RC_IN_VAL(&state_rc)->counter_mutex) != _Z_RES_OK) {\n            _z_sync_group_state_weak_drop(&notifier->_state);\n            _z_sync_group_state_rc_drop(&state_rc);\n            return;\n        }\n#endif\n        _z_sync_group_state_weak_drop(&notifier->_state);\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_condvar_signal_all(&_Z_RC_IN_VAL(&state_rc)->counter_condvar);\n        _z_mutex_unlock(&_Z_RC_IN_VAL(&state_rc)->counter_mutex);\n#endif\n        _z_sync_group_state_rc_drop(&state_rc);\n    } else {\n        _z_sync_group_state_weak_drop(&notifier->_state);\n    }\n}\n\nbool _z_sync_group_is_closed(const _z_sync_group_t* sync_group) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    if (_z_mutex_lock(&_Z_RC_IN_VAL(&sync_group->_state)->counter_mutex) != _Z_RES_OK) {\n        return true;\n    }\n#endif\n    bool ret = _Z_RC_IN_VAL(&sync_group->_state)->is_closed;\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_unlock(&_Z_RC_IN_VAL(&sync_group->_state)->counter_mutex);\n#endif\n    return ret;\n}\n"
  },
  {
    "path": "src/collections/vec.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/collections/vec.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\n/*-------- vec --------*/\n_z_vec_t _z_vec_make(size_t capacity) {\n    _z_vec_t v = {0};\n    if (capacity != 0) {\n        v._val = (void **)z_malloc(sizeof(void *) * capacity);\n        if (v._val != NULL) {\n            v._capacity = capacity;\n        }\n    }\n    return v;\n}\n\nvoid _z_vec_copy(_z_vec_t *dst, const _z_vec_t *src, z_element_clone_f d_f) {\n    dst->_capacity = src->_capacity;\n    dst->_len = src->_len;\n    dst->_val = (void **)z_malloc(sizeof(void *) * src->_capacity);\n    if (dst->_val != NULL) {\n        for (size_t i = 0; i < src->_len; i++) {\n            dst->_val[i] = d_f(src->_val[i]);\n        }\n    }\n}\n\nvoid _z_vec_move(_z_vec_t *dst, _z_vec_t *src) {\n    *dst = *src;\n    *src = _z_vec_null();\n}\n\nvoid _z_vec_reset(_z_vec_t *v, z_element_free_f free_f) {\n    for (size_t i = 0; i < v->_len; i++) {\n        free_f(&v->_val[i]);\n    }\n\n    v->_len = 0;\n}\n\nvoid _z_vec_clear(_z_vec_t *v, z_element_free_f free_f) {\n    for (size_t i = 0; i < v->_len; i++) {\n        free_f(&v->_val[i]);\n    }\n    _z_vec_release(v);\n}\n\nvoid _z_vec_release(_z_vec_t *v) {\n    z_free(v->_val);\n    v->_val = NULL;\n\n    v->_capacity = 0;\n    v->_len = 0;\n}\n\nvoid _z_vec_free(_z_vec_t **v, z_element_free_f free_f) {\n    _z_vec_t *ptr = (_z_vec_t *)*v;\n\n    if (ptr != NULL) {\n        _z_vec_clear(ptr, free_f);\n\n        z_free(ptr);\n        *v = NULL;\n    }\n}\n\nvoid _z_vec_append(_z_vec_t *v, void *e) {\n    if (v->_len == v->_capacity) {\n        // Allocate a new vector\n        size_t _capacity = (v->_capacity << 1) | 0x01;\n        void **_val = (void **)z_malloc(_capacity * sizeof(void *));\n        if (_val != NULL) {\n            (void)memcpy(_val, v->_val, v->_capacity * sizeof(void *));\n\n            // Free the old vector\n            z_free(v->_val);\n\n            // Update the current vector\n            v->_val = _val;\n            v->_capacity = _capacity;\n\n            v->_val[v->_len] = e;\n            v->_len = v->_len + 1;\n        }\n    } else {\n        v->_val[v->_len] = e;\n        v->_len = v->_len + 1;\n    }\n}\n\nvoid _z_vec_set(_z_vec_t *v, size_t i, void *e, z_element_free_f free_f) {\n    assert(i < v->_len);\n\n    if (v->_val[i] != NULL) {\n        free_f(&v->_val[i]);\n    }\n    v->_val[i] = e;\n}\n\nvoid _z_vec_remove(_z_vec_t *v, size_t pos, z_element_free_f free_f) {\n    free_f(&v->_val[pos]);\n    for (size_t i = pos; i < v->_len; i++) {\n        v->_val[pos] = v->_val[pos + (size_t)1];\n    }\n\n    v->_val[v->_len] = NULL;\n    v->_len = v->_len - 1;\n}\n\n/*-------- svec --------*/\n_z_svec_t _z_svec_make(size_t capacity, size_t element_size) {\n    _z_svec_t v = _z_svec_null();\n    if (capacity != 0) {\n        v._val = z_malloc(element_size * capacity);\n    }\n    if (v._val != NULL) {\n        v._capacity = capacity;\n    }\n    return v;\n}\n\nvoid _z_svec_init(_z_svec_t *v, size_t offset, size_t element_size) {\n    assert(offset <= v->_capacity);\n    void *start = _z_svec_get_mut(v, offset, element_size);\n    memset(start, 0, (v->_capacity - offset) * element_size);\n}\n\nstatic inline void __z_svec_move_inner(void *dst, void *src, z_element_move_f move, size_t num_elements,\n                                       size_t element_size, bool use_elem_f) {\n    if (use_elem_f) {\n        size_t offset = 0;\n        for (size_t i = 0; i < num_elements; i++) {\n            move((uint8_t *)dst + offset, (uint8_t *)src + offset);\n            offset += element_size;\n        }\n    } else {\n        memmove(dst, src, num_elements * element_size);\n    }\n}\n\nvoid _z_svec_move(_z_svec_t *dst, _z_svec_t *src) {\n    *dst = *src;\n    *src = _z_svec_null();\n}\n\nz_result_t _z_svec_copy(_z_svec_t *dst, const _z_svec_t *src, z_element_copy_f copy, size_t element_size,\n                        bool use_elem_f) {\n    *dst = _z_svec_null();\n    if (src->_capacity == 0) {\n        return _Z_RES_OK;\n    }\n    dst->_val = z_malloc(element_size * src->_capacity);\n    if (dst->_val == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    dst->_capacity = src->_capacity;\n    dst->_len = src->_len;\n    // Copy data to new vector\n    if (use_elem_f) {\n        size_t offset = 0;\n        for (size_t i = 0; i < src->_len; i++) {\n            copy((uint8_t *)dst->_val + offset, (uint8_t *)src->_val + offset);\n            offset += element_size;\n        }\n    } else {\n        memcpy(dst->_val, src->_val, src->_len * element_size);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_svec_reset(_z_svec_t *v, z_element_clear_f clear, size_t element_size) {\n    if (clear != NULL) {\n        size_t offset = 0;\n        for (size_t i = 0; i < v->_len; i++) {\n            clear((uint8_t *)v->_val + offset);\n            offset += element_size;\n        }\n    }\n    v->_len = 0;\n}\n\nvoid _z_svec_clear(_z_svec_t *v, z_element_clear_f clear_f, size_t element_size) {\n    _z_svec_reset(v, clear_f, element_size);\n    if (!v->_aliased) {\n        _z_svec_release(v);\n    }\n}\n\nvoid _z_svec_release(_z_svec_t *v) {\n    z_free(v->_val);\n    v->_capacity = 0;\n    v->_val = NULL;\n}\n\nvoid _z_svec_free(_z_svec_t **v, z_element_clear_f clear, size_t element_size) {\n    _z_svec_t *ptr = (_z_svec_t *)*v;\n\n    if (ptr != NULL) {\n        _z_svec_clear(ptr, clear, element_size);\n\n        z_free(ptr);\n        *v = NULL;\n    }\n}\n\nz_result_t _z_svec_expand(_z_svec_t *v, z_element_move_f move, size_t element_size, bool use_elem_f) {\n    // Allocate a new vector\n    size_t _capacity = v->_capacity == 0 ? 1 : v->_capacity << 1;\n    void *_val = (void *)z_malloc(_capacity * element_size);\n    if (_val == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Move and clear old data\n    __z_svec_move_inner(_val, v->_val, move, v->_len, element_size, use_elem_f);\n    z_free(v->_val);\n    // Update the current vector\n    v->_val = _val;\n    v->_capacity = _capacity;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_svec_append(_z_svec_t *v, const void *e, z_element_move_f move, size_t element_size, bool use_elem_f) {\n    if (v->_len == v->_capacity) {\n        _Z_RETURN_IF_ERR(_z_svec_expand(v, move, element_size, use_elem_f));\n    }\n    // Append element\n    memcpy((uint8_t *)v->_val + v->_len * element_size, e, element_size);\n    v->_len++;\n    return _Z_RES_OK;\n}\n\nvoid _z_svec_set(_z_svec_t *v, size_t i, void *e, z_element_clear_f clear, size_t element_size) {\n    assert(i < v->_len);\n    clear((uint8_t *)v->_val + i * element_size);\n    memcpy((uint8_t *)v->_val + i * element_size, e, element_size);\n}\n\nvoid _z_svec_remove(_z_svec_t *v, size_t pos, z_element_clear_f clear, z_element_move_f move, size_t element_size,\n                    bool use_elem_f) {\n    assert(pos < v->_len);\n    clear((uint8_t *)v->_val + pos * element_size);\n    __z_svec_move_inner((uint8_t *)v->_val + pos * element_size, (uint8_t *)v->_val + (pos + 1) * element_size, move,\n                        (v->_len - pos - 1) * element_size, element_size, use_elem_f);\n\n    v->_len--;\n}\n"
  },
  {
    "path": "src/link/config/bt.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/link/config/bt.h\"\n\n#include <string.h>\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n\nsize_t _z_bt_config_strlen(const _z_str_intmap_t *s) {\n    BT_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_strlen(s, BT_CONFIG_ARGC, args);\n}\n\nvoid _z_bt_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    BT_CONFIG_MAPPING_BUILD\n\n    _z_str_intmap_onto_str(dst, dst_len, s, BT_CONFIG_ARGC, args);\n}\n\nchar *_z_bt_config_to_str(const _z_str_intmap_t *s) {\n    BT_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_to_str(s, BT_CONFIG_ARGC, args);\n}\n\nz_result_t _z_bt_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    BT_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_strn(strint, s, BT_CONFIG_ARGC, args, n);\n}\n\nz_result_t _z_bt_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    BT_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_str(strint, s, BT_CONFIG_ARGC, args);\n}\n#endif\n"
  },
  {
    "path": "src/link/config/serial.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/serial.h\"\n\n#include <string.h>\n\n#if Z_FEATURE_LINK_SERIAL == 1\n\nsize_t _z_serial_config_strlen(const _z_str_intmap_t *s) {\n    SERIAL_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_strlen(s, SERIAL_CONFIG_ARGC, args);\n}\n\nvoid _z_serial_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    SERIAL_CONFIG_MAPPING_BUILD\n\n    _z_str_intmap_onto_str(dst, dst_len, s, SERIAL_CONFIG_ARGC, args);\n}\n\nchar *_z_serial_config_to_str(const _z_str_intmap_t *s) {\n    SERIAL_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_to_str(s, SERIAL_CONFIG_ARGC, args);\n}\n\nz_result_t _z_serial_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    SERIAL_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_strn(strint, s, SERIAL_CONFIG_ARGC, args, n);\n}\n\nz_result_t _z_serial_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    SERIAL_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_str(strint, s, SERIAL_CONFIG_ARGC, args);\n}\n#endif\n"
  },
  {
    "path": "src/link/config/tcp.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/tcp.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_LINK_TCP == 1\n\nsize_t _z_tcp_config_strlen(const _z_str_intmap_t *s) {\n    TCP_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_strlen(s, TCP_CONFIG_ARGC, args);\n}\n\nvoid _z_tcp_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    TCP_CONFIG_MAPPING_BUILD\n\n    _z_str_intmap_onto_str(dst, dst_len, s, TCP_CONFIG_ARGC, args);\n}\n\nchar *_z_tcp_config_to_str(const _z_str_intmap_t *s) {\n    TCP_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_to_str(s, TCP_CONFIG_ARGC, args);\n}\n\nz_result_t _z_tcp_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    TCP_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_strn(strint, s, TCP_CONFIG_ARGC, args, n);\n}\n\nz_result_t _z_tcp_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    return _z_tcp_config_from_strn(strint, s, strlen(s));\n}\n#endif\n"
  },
  {
    "path": "src/link/config/tls.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/tls.h\"\n\n#include <string.h>\n\n#if Z_FEATURE_LINK_TLS == 1\n\nsize_t _z_tls_config_strlen(const _z_str_intmap_t *s) {\n    TLS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_strlen(s, TLS_CONFIG_ARGC, args);\n}\n\nvoid _z_tls_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    TLS_CONFIG_MAPPING_BUILD\n\n    _z_str_intmap_onto_str(dst, dst_len, s, TLS_CONFIG_ARGC, args);\n}\n\nchar *_z_tls_config_to_str(const _z_str_intmap_t *s) {\n    TLS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_to_str(s, TLS_CONFIG_ARGC, args);\n}\n\nz_result_t _z_tls_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    TLS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_strn(strint, s, TLS_CONFIG_ARGC, args, n);\n}\n\nz_result_t _z_tls_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    TLS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_str(strint, s, TLS_CONFIG_ARGC, args);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/config/udp.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/udp.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n\nsize_t _z_udp_config_strlen(const _z_str_intmap_t *s) {\n    UDP_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_strlen(s, UDP_CONFIG_ARGC, args);\n}\n\nvoid _z_udp_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    UDP_CONFIG_MAPPING_BUILD\n\n    _z_str_intmap_onto_str(dst, dst_len, s, UDP_CONFIG_ARGC, args);\n}\n\nchar *_z_udp_config_to_str(const _z_str_intmap_t *s) {\n    UDP_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_to_str(s, UDP_CONFIG_ARGC, args);\n}\n\nz_result_t _z_udp_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    UDP_CONFIG_MAPPING_BUILD\n    return _z_str_intmap_from_strn(strint, s, UDP_CONFIG_ARGC, args, n);\n}\n\nz_result_t _z_udp_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    return _z_udp_config_from_strn(strint, s, strlen(s));\n}\n\n#endif\n"
  },
  {
    "path": "src/link/config/ws.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/ws.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n\n#if Z_FEATURE_LINK_WS == 1\n\nsize_t _z_ws_config_strlen(const _z_str_intmap_t *s) {\n    WS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_strlen(s, argc, args);\n}\n\nvoid _z_ws_config_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    WS_CONFIG_MAPPING_BUILD\n    _z_str_intmap_onto_str(dst, dst_len, s, argc, args);\n}\n\nchar *_z_ws_config_to_str(const _z_str_intmap_t *s) {\n    WS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_to_str(s, argc, args);\n}\n\nz_result_t _z_ws_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    WS_CONFIG_MAPPING_BUILD\n\n    return _z_str_intmap_from_strn(strint, s, argc, args, n);\n}\n\nz_result_t _z_ws_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    return _z_ws_config_from_strn(strint, s, strlen(s));\n}\n#endif\n"
  },
  {
    "path": "src/link/endpoint.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/endpoint.h\"\n\n#include <errno.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#if Z_FEATURE_LINK_TCP == 1\n#include \"zenoh-pico/link/config/tcp.h\"\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n#include \"zenoh-pico/link/config/udp.h\"\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#include \"zenoh-pico/link/config/bt.h\"\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n#include \"zenoh-pico/link/config/serial.h\"\n#endif\n#if Z_FEATURE_LINK_WS == 1\n#include \"zenoh-pico/link/config/ws.h\"\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n#include \"zenoh-pico/link/config/tls.h\"\n#endif\n#include \"zenoh-pico/link/config/raweth.h\"\n\n/*------------------ Locator ------------------*/\nvoid _z_locator_init(_z_locator_t *locator) {\n    locator->_protocol = _z_string_null();\n    locator->_address = _z_string_null();\n    locator->_metadata = _z_str_intmap_make();\n}\n\nvoid _z_locator_clear(_z_locator_t *lc) {\n    _z_string_clear(&lc->_protocol);\n    _z_string_clear(&lc->_address);\n    _z_str_intmap_clear(&lc->_metadata);\n}\n\nvoid _z_locator_free(_z_locator_t **lc) {\n    _z_locator_t *ptr = *lc;\n\n    if (ptr != NULL) {\n        _z_locator_clear(ptr);\n\n        z_free(ptr);\n        *lc = NULL;\n    }\n}\n\nz_result_t _z_locator_copy(_z_locator_t *dst, const _z_locator_t *src) {\n    _Z_RETURN_IF_ERR(_z_string_copy(&dst->_protocol, &src->_protocol));\n    _Z_RETURN_IF_ERR(_z_string_copy(&dst->_address, &src->_address));\n\n    // @TODO: implement copy for metadata\n    dst->_metadata = _z_str_intmap_make();\n    return _Z_RES_OK;\n}\n\nbool _z_locator_eq(const _z_locator_t *left, const _z_locator_t *right) {\n    bool res = false;\n\n    res = _z_string_equals(&left->_protocol, &right->_protocol);\n    if (res == true) {\n        res = _z_string_equals(&left->_address, &right->_address);\n        // if (res == true) {\n        //     // @TODO: implement eq for metadata\n        // }\n    }\n\n    return res;\n}\n\nstatic z_result_t _z_locator_protocol_from_string(_z_string_t *protocol, const _z_string_t *str) {\n    *protocol = _z_string_null();\n\n    const char *p_start = _z_string_data(str);\n    const char *p_end = (char *)memchr(p_start, (int)LOCATOR_PROTOCOL_SEPARATOR, _z_string_len(str));\n    if ((p_end == NULL) || (p_start == p_end)) {\n        _Z_ERROR_RETURN(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    size_t p_len = _z_ptr_char_diff(p_end, p_start);\n    return _z_string_copy_substring(protocol, str, 0, p_len);\n}\n\nstatic z_result_t _z_locator_address_from_string(_z_string_t *address, const _z_string_t *str) {\n    *address = _z_string_null();\n\n    // Find protocol separator\n    const char *p_start = (char *)memchr(_z_string_data(str), (int)LOCATOR_PROTOCOL_SEPARATOR, _z_string_len(str));\n    if (p_start == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    // Skip protocol separator\n    p_start = _z_cptr_char_offset(p_start, 1);\n    size_t start_offset = _z_ptr_char_diff(p_start, _z_string_data(str));\n    if (start_offset >= _z_string_len(str)) {\n        _Z_ERROR_RETURN(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    // Find metadata separator\n    size_t curr_len = _z_string_len(str) - start_offset;\n    const char *p_end = (char *)memchr(p_start, (int)LOCATOR_METADATA_SEPARATOR, curr_len);\n    // There is no metadata separator, then look for config separator\n    if (p_end == NULL) {\n        p_end = memchr(p_start, (int)ENDPOINT_CONFIG_SEPARATOR, curr_len);\n    }\n    // There is no config separator, then address goes to the end of string\n    if (p_end == NULL) {\n        p_end = _z_cptr_char_offset(_z_string_data(str), (ptrdiff_t)_z_string_len(str));\n    }\n    if (p_start >= p_end) {\n        _Z_ERROR_RETURN(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    // Copy data\n    size_t addr_len = _z_ptr_char_diff(p_end, p_start);\n    return _z_string_copy_substring(address, str, start_offset, addr_len);\n}\n\nz_result_t _z_locator_metadata_from_string(_z_str_intmap_t *strint, const _z_string_t *str) {\n    *strint = _z_str_intmap_make();\n\n    // Find metadata separator\n    const char *p_start = (char *)memchr(_z_string_data(str), LOCATOR_METADATA_SEPARATOR, _z_string_len(str));\n    if (p_start == NULL) {\n        return _Z_RES_OK;\n    }\n    p_start = _z_cptr_char_offset(p_start, 1);\n    size_t start_offset = _z_ptr_char_diff(p_start, _z_string_data(str));\n    if (start_offset > _z_string_len(str)) {\n        _Z_ERROR_RETURN(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    if (start_offset == _z_string_len(str)) {\n        return _Z_RES_OK;\n    }\n\n    const char *p_end = (char *)memchr(_z_string_data(str), ENDPOINT_CONFIG_SEPARATOR, _z_string_len(str));\n    if (p_end == NULL) {\n        p_end = _z_cptr_char_offset(_z_string_data(str), (ptrdiff_t)_z_string_len(str) + 1);\n    }\n\n    if (p_start != p_end) {\n        size_t p_len = _z_ptr_char_diff(p_end, p_start);\n        return _z_str_intmap_from_strn(strint, p_start, 0, NULL, p_len);\n    }\n    return _Z_RES_OK;\n}\n\nsize_t _z_locator_metadata_strlen(const _z_str_intmap_t *s) {\n    // @TODO: define protocol-level metadata\n    return _z_str_intmap_strlen(s, 0, NULL);\n}\n\nvoid _z_locator_metadata_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s) {\n    // @TODO: define protocol-level metadata\n    _z_str_intmap_onto_str(dst, dst_len, s, 0, NULL);\n}\n\nz_result_t _z_locator_from_string(_z_locator_t *lc, const _z_string_t *str) {\n    if (str == NULL || !_z_string_check(str)) {\n        _Z_ERROR_RETURN(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    // Parse protocol\n    _Z_RETURN_IF_ERR(_z_locator_protocol_from_string(&lc->_protocol, str));\n    // Parse address\n    _Z_CLEAN_RETURN_IF_ERR(_z_locator_address_from_string(&lc->_address, str), _z_locator_clear(lc));\n    // Parse metadata\n    _Z_CLEAN_RETURN_IF_ERR(_z_locator_metadata_from_string(&lc->_metadata, str), _z_locator_clear(lc));\n    return _Z_RES_OK;\n}\n\nsize_t _z_locator_strlen(const _z_locator_t *l) {\n    size_t ret = 0;\n\n    if (l != NULL) {\n        // Calculate the string length to allocate\n        ret = _z_string_len(&l->_protocol) + _z_string_len(&l->_address) + 1;\n\n        // @TODO: define protocol-level metadata\n        size_t md_len = _z_locator_metadata_strlen(&l->_metadata);\n        if (md_len > (size_t)0) {\n            ret = ret + (size_t)1;  // Locator metadata separator\n            ret = ret + md_len;     // Locator metadata content\n        }\n    }\n    return ret;\n}\n\n/**\n * Converts a :c:type:`_z_locator_t` into its string format.\n *\n * Parameters:\n *   dst: Pointer to the destination string. It MUST be already allocated with enough space to store the locator in\n * its string format. loc: :c:type:`_z_locator_t` to be converted into its string format.\n */\nstatic void __z_locator_onto_string(_z_string_t *dst, const _z_locator_t *loc) {\n    char *curr_dst = (char *)_z_string_data(dst);\n    const char psep = LOCATOR_PROTOCOL_SEPARATOR;\n    const char msep = LOCATOR_METADATA_SEPARATOR;\n\n    size_t prot_len = _z_string_len(&loc->_protocol);\n    size_t addr_len = _z_string_len(&loc->_address);\n\n    if ((prot_len + addr_len + 1) > _z_string_len(dst)) {\n        _Z_ERROR(\"Buffer too small to write locator\");\n        return;\n    }\n    // Locator protocol\n    memcpy(curr_dst, _z_string_data(&loc->_protocol), prot_len);\n    curr_dst = _z_ptr_char_offset(curr_dst, (ptrdiff_t)prot_len);\n    // Locator protocol separator\n    memcpy(curr_dst, &psep, 1);\n    curr_dst = _z_ptr_char_offset(curr_dst, 1);\n    // Locator address\n    memcpy(curr_dst, _z_string_data(&loc->_address), addr_len);\n    curr_dst = _z_ptr_char_offset(curr_dst, (ptrdiff_t)addr_len);\n    // @TODO: define protocol-level metadata\n    size_t md_len = _z_locator_metadata_strlen(&loc->_metadata);\n    if (md_len > (size_t)0) {\n        size_t curr_len = _z_string_len(dst) - _z_ptr_char_diff(curr_dst, _z_string_data(dst));\n        if (curr_len == 0) {\n            _Z_ERROR(\"Buffer too small to write metadata\");\n            return;\n        }\n        // Locator metadata separator\n        memcpy(curr_dst, &msep, 1);\n        curr_dst = _z_ptr_char_offset(curr_dst, 1);\n        // Locator metadata\n        _z_locator_metadata_onto_str(curr_dst, curr_len, &loc->_metadata);\n    }\n}\n\n/**\n * Converts a :c:type:`_z_locator_t` into its _z_string format.\n *\n * Parameters:\n *   loc: :c:type:`_z_locator_t` to be converted into its _z_string format.\n *\n * Returns:\n *   The z_stringified :c:type:`_z_locator_t`.\n */\n_z_string_t _z_locator_to_string(const _z_locator_t *loc) {\n    _z_string_t s = _z_string_preallocate(_z_locator_strlen(loc));\n    if (!_z_string_check(&s)) {\n        return s;\n    }\n    __z_locator_onto_string(&s, loc);\n    return s;\n}\n\nstatic const char *_z_endpoint_rchr(const _z_string_t *addr, char filter) {\n    const char *addr_data = _z_string_data(addr);\n    size_t addr_len = _z_string_len(addr);\n\n    while (addr_len > 0) {\n        addr_len--;\n        if (addr_data[addr_len] == filter) {\n            return &addr_data[addr_len];\n        }\n    }\n\n    return NULL;\n}\n\nchar *_z_endpoint_parse_host(const _z_string_t *addr) {\n    if (addr == NULL) {\n        return NULL;\n    }\n\n    const char *addr_data = _z_string_data(addr);\n    const size_t addr_len = _z_string_len(addr);\n    if (addr_data == NULL || addr_len == 0) {\n        return NULL;\n    }\n\n    const char *colon = _z_endpoint_rchr(addr, ':');\n    if (colon == NULL) {\n        return NULL;\n    }\n\n    // IPv6\n    const char *host_start = addr_data;\n    const char *host_end = colon;\n    if ((host_end > host_start) && (host_start[0] == '[') && (host_end[-1] == ']')) {\n        host_start = _z_cptr_char_offset(host_start, 1);\n        host_end = _z_cptr_char_offset(host_end, -1);\n    }\n\n    if (host_end <= host_start) {\n        return NULL;\n    }\n\n    const size_t host_len = _z_ptr_char_diff(host_end, host_start);\n    char *host_copy = (char *)z_malloc(host_len + 1);\n    if (host_copy == NULL) {\n        return NULL;\n    }\n\n    _z_str_n_copy(host_copy, host_start, host_len + 1);\n    return host_copy;\n}\n\nchar *_z_endpoint_parse_port(const _z_string_t *addr) {\n    if (addr == NULL) {\n        return NULL;\n    }\n\n    const char *addr_data = _z_string_data(addr);\n    const size_t addr_len = _z_string_len(addr);\n    if (addr_data == NULL || addr_len == 0) {\n        return NULL;\n    }\n\n    const char *colon = _z_endpoint_rchr(addr, ':');\n    if (colon == NULL) {\n        return NULL;\n    }\n\n    const char *addr_end = _z_cptr_char_offset(addr_data, (ptrdiff_t)addr_len);\n    const char *port_start = _z_cptr_char_offset(colon, 1);\n    if (port_start >= addr_end) {\n        return NULL;\n    }\n\n    const size_t port_len = _z_ptr_char_diff(addr_end, port_start);\n    char *port = (char *)z_malloc(port_len + 1);\n    if (port == NULL) {\n        return NULL;\n    }\n\n    _z_str_n_copy(port, port_start, port_len + 1);\n\n    char *endptr = NULL;\n    errno = 0;\n    unsigned long port_val = strtoul(port, &endptr, 10);\n    if ((errno != 0) || (endptr == port) || (*endptr != '\\0') || (port_val == 0) || (port_val > 65535)) {\n        z_free(port);\n        return NULL;\n    }\n\n    return port;\n}\n\n/*------------------ Endpoint ------------------*/\nvoid _z_endpoint_init(_z_endpoint_t *endpoint) {\n    _z_locator_init(&endpoint->_locator);\n    endpoint->_config = _z_str_intmap_make();\n}\n\nvoid _z_endpoint_clear(_z_endpoint_t *ep) {\n    _z_locator_clear(&ep->_locator);\n    _z_str_intmap_clear(&ep->_config);\n}\n\nvoid _z_endpoint_free(_z_endpoint_t **ep) {\n    _z_endpoint_t *ptr = *ep;\n\n    if (ptr != NULL) {\n        _z_locator_clear(&ptr->_locator);\n        _z_str_intmap_clear(&ptr->_config);\n\n        z_free(ptr);\n        *ep = NULL;\n    }\n}\n\nz_result_t _z_endpoint_config_from_string(_z_str_intmap_t *strint, const _z_string_t *str, _z_string_t *proto) {\n    char *p_start = (char *)memchr(_z_string_data(str), ENDPOINT_CONFIG_SEPARATOR, _z_string_len(str));\n    if (p_start != NULL) {\n        p_start = _z_ptr_char_offset(p_start, 1);\n        size_t cfg_size = _z_string_len(str) - _z_ptr_char_diff(p_start, _z_string_data(str));\n\n        // Call the right configuration parser depending on the protocol\n        _z_string_t cmp_str = _z_string_null();\n#if Z_FEATURE_LINK_TCP == 1\n        cmp_str = _z_string_alias_str(TCP_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_tcp_config_from_strn(strint, p_start, cfg_size);\n        }\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n        cmp_str = _z_string_alias_str(UDP_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_udp_config_from_strn(strint, p_start, cfg_size);\n        }\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n        cmp_str = _z_string_alias_str(BT_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_bt_config_from_strn(strint, p_start, cfg_size);\n        }\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        cmp_str = _z_string_alias_str(SERIAL_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_serial_config_from_strn(strint, p_start, cfg_size);\n        }\n#endif\n#if Z_FEATURE_LINK_WS == 1\n        cmp_str = _z_string_alias_str(WS_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_ws_config_from_strn(strint, p_start, cfg_size);\n        }\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n        cmp_str = _z_string_alias_str(TLS_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_tls_config_from_strn(strint, p_start, cfg_size);\n        }\n#endif\n        cmp_str = _z_string_alias_str(RAWETH_SCHEMA);\n        if (_z_string_equals(proto, &cmp_str)) {\n            return _z_raweth_config_from_strn(strint, p_start, cfg_size);\n        }\n    }\n    return _Z_RES_OK;\n}\n\nsize_t _z_endpoint_config_strlen(const _z_str_intmap_t *s, _z_string_t *proto) {\n    // Call the right configuration parser depending on the protocol\n    _z_string_t cmp_str = _z_string_null();\n#if Z_FEATURE_LINK_TCP == 1\n    cmp_str = _z_string_alias_str(TCP_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_tcp_config_strlen(s);\n    }\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n    cmp_str = _z_string_alias_str(UDP_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_udp_config_strlen(s);\n    }\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n    cmp_str = _z_string_alias_str(BT_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_bt_config_strlen(s);\n    }\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n    cmp_str = _z_string_alias_str(SERIAL_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_serial_config_strlen(s);\n    }\n#endif\n#if Z_FEATURE_LINK_WS == 1\n    cmp_str = _z_string_alias_str(WS_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_ws_config_strlen(s);\n    }\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n    cmp_str = _z_string_alias_str(TLS_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_tls_config_strlen(s);\n    }\n#endif\n    cmp_str = _z_string_alias_str(RAWETH_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_raweth_config_strlen(s);\n    }\n    return 0;\n}\n\nchar *_z_endpoint_config_to_string(const _z_str_intmap_t *s, const _z_string_t *proto) {\n    // Call the right configuration parser depending on the protocol\n    _z_string_t cmp_str = _z_string_null();\n\n#if Z_FEATURE_LINK_TCP == 1\n    cmp_str = _z_string_alias_str(TCP_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_tcp_config_to_str(s);\n    }\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n    cmp_str = _z_string_alias_str(UDP_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_udp_config_to_str(s);\n    }\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n    cmp_str = _z_string_alias_str(BT_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_bt_config_to_str(s);\n    }\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n    cmp_str = _z_string_alias_str(SERIAL_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_serial_config_to_str(s);\n    }\n#endif\n#if Z_FEATURE_LINK_WS == 1\n    cmp_str = _z_string_alias_str(WS_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_ws_config_to_str(s);\n    }\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n    cmp_str = _z_string_alias_str(TLS_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_tls_config_to_str(s);\n    }\n#endif\n    cmp_str = _z_string_alias_str(RAWETH_SCHEMA);\n    if (_z_string_equals(proto, &cmp_str)) {\n        return _z_raweth_config_to_str(s);\n    }\n    return NULL;\n}\n\nz_result_t _z_endpoint_from_string(_z_endpoint_t *ep, const _z_string_t *str) {\n    _z_endpoint_init(ep);\n    _Z_CLEAN_RETURN_IF_ERR(_z_locator_from_string(&ep->_locator, str), _z_endpoint_clear(ep));\n    _Z_CLEAN_RETURN_IF_ERR(_z_endpoint_config_from_string(&ep->_config, str, &ep->_locator._protocol),\n                           _z_endpoint_clear(ep));\n    return _Z_RES_OK;\n}\n\n_z_string_t _z_endpoint_to_string(const _z_endpoint_t *endpoint) {\n    _z_string_t ret = _z_string_null();\n    // Retrieve locator\n    _z_string_t locator = _z_locator_to_string(&endpoint->_locator);\n    if (!_z_string_check(&locator)) {\n        return _z_string_null();\n    }\n    size_t curr_len = _z_string_len(&locator);\n    // Retrieve config\n    char *config = _z_endpoint_config_to_string(&endpoint->_config, &endpoint->_locator._protocol);\n    size_t config_len = 0;\n    if (config != NULL) {\n        config_len = strlen(config);\n        curr_len += config_len;\n    }\n    // Reconstruct the endpoint as a string\n    ret = _z_string_preallocate(curr_len);\n    if (!_z_string_check(&ret)) {\n        // cppcheck-suppress misra-c2012-17.3\n        _z_string_clear(&locator);\n        if (config != NULL) {\n            // cppcheck-suppress misra-c2012-17.3\n            z_free(config);\n        }\n        return ret;\n    }\n    // Copy locator\n    char *curr_dst = (char *)_z_string_data(&ret);\n    memcpy(curr_dst, _z_string_data(&locator), _z_string_len(&locator));\n    curr_dst = _z_ptr_char_offset(curr_dst, (ptrdiff_t)_z_string_len(&locator));\n    // Copy config\n    if (config != NULL) {\n        memcpy(curr_dst, config, config_len);\n        // cppcheck-suppress misra-c2012-17.3\n        z_free(config);\n    }\n    // Clean up\n    _z_string_clear(&locator);\n    return ret;\n}\n"
  },
  {
    "path": "src/link/link.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/link.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/config/raweth.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nz_result_t _z_open_socket(const _z_string_t *locator, const _z_config_t *session_cfg, _z_sys_net_socket_t *socket) {\n#if Z_FEATURE_LINK_TLS != 1\n    _ZP_UNUSED(session_cfg);\n#endif\n    _z_endpoint_t ep;\n    z_result_t ret = _Z_RES_OK;\n    _Z_RETURN_IF_ERR(_z_endpoint_from_string(&ep, locator));\n    if (_z_endpoint_tcp_valid(&ep) == _Z_RES_OK) {\n        ret = _z_new_peer_tcp(&ep, socket);\n#if Z_FEATURE_LINK_TLS == 1\n    } else if (_z_endpoint_tls_valid(&ep) == _Z_RES_OK) {\n        ret = _z_new_peer_tls(&ep, socket, session_cfg);\n#endif\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN);\n        ret = _Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN;\n    }\n    _z_endpoint_clear(&ep);\n    return ret;\n}\n\nz_result_t _z_open_link(_z_link_t *zl, const _z_string_t *locator, const _z_config_t *session_cfg) {\n#if Z_FEATURE_LINK_TLS != 1\n    _ZP_UNUSED(session_cfg);\n#endif\n    z_result_t ret = _Z_RES_OK;\n\n    _z_endpoint_t ep;\n    ret = _z_endpoint_from_string(&ep, locator);\n    if (ret == _Z_RES_OK) {\n        // Create transport link\n        if (_z_endpoint_tcp_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_tcp(zl, &ep);\n        } else\n#if Z_FEATURE_LINK_UDP_UNICAST == 1\n            if (_z_endpoint_udp_unicast_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_udp_unicast(zl, ep);\n        } else\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n            if (_z_endpoint_bt_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_bt(zl, ep);\n        } else\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n            if (_z_endpoint_serial_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_serial(zl, ep);\n        } else\n#endif\n#if Z_FEATURE_LINK_WS == 1\n            if (_z_endpoint_ws_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_ws(zl, &ep);\n        } else\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n            if (_z_endpoint_tls_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_tls(zl, &ep, session_cfg);\n        } else\n#endif\n        {\n            _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN);\n            ret = _Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN;\n        }\n        if (ret == _Z_RES_OK) {\n            // Open transport link for communication\n            if (zl->_open_f(zl) != _Z_RES_OK) {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_FAILED);\n                ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n                _z_link_clear(zl);\n            }\n        } else {\n            _z_endpoint_clear(&ep);\n        }\n    } else {\n        _z_endpoint_clear(&ep);\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_link(_z_link_t *zl, const _z_string_t *locator, const _z_config_t *session_cfg) {\n#if Z_FEATURE_LINK_TLS != 1\n    _ZP_UNUSED(session_cfg);\n#endif\n    z_result_t ret = _Z_RES_OK;\n\n    _z_endpoint_t ep;\n    ret = _z_endpoint_from_string(&ep, locator);\n    if (ret == _Z_RES_OK) {\n        // Create transport link\n        if (_z_endpoint_tcp_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_tcp(zl, &ep);\n        } else\n#if Z_FEATURE_LINK_TLS == 1\n            if (_z_endpoint_tls_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_tls(zl, &ep, session_cfg);\n        } else\n#endif\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1\n            if (_z_endpoint_udp_multicast_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_udp_multicast(zl, ep);\n        } else\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n            if (_z_endpoint_bt_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_bt(zl, ep);\n        } else\n#endif\n            if (_z_endpoint_raweth_valid(&ep) == _Z_RES_OK) {\n            ret = _z_new_link_raweth(zl, ep);\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN);\n            ret = _Z_ERR_CONFIG_LOCATOR_SCHEMA_UNKNOWN;\n        }\n        if (ret == _Z_RES_OK) {\n            // Open transport link for listening\n            if (zl->_listen_f(zl) != _Z_RES_OK) {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_FAILED);\n                ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n                _z_link_clear(zl);\n            }\n        } else {\n            _z_endpoint_clear(&ep);\n        }\n    } else {\n        _z_endpoint_clear(&ep);\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    return ret;\n}\n\nvoid _z_link_clear(_z_link_t *l) {\n    if (l->_close_f != NULL) {\n        l->_close_f(l);\n    }\n    if (l->_free_f != NULL) {\n        l->_free_f(l);\n    }\n    _z_endpoint_clear(&l->_endpoint);\n}\n\nvoid _z_link_free(_z_link_t **l) {\n    _z_link_t *ptr = *l;\n\n    if (ptr != NULL) {\n        _z_link_clear(ptr);\n\n        z_free(ptr);\n        *l = NULL;\n    }\n}\n\nsize_t _z_link_recv_zbuf(const _z_link_t *link, _z_zbuf_t *zbf, _z_slice_t *addr) {\n    size_t rb = link->_read_f(link, _z_zbuf_get_wptr(zbf), _z_zbuf_space_left(zbf), addr);\n    if (rb != SIZE_MAX) {\n        _z_zbuf_set_wpos(zbf, _z_zbuf_get_wpos(zbf) + rb);\n    }\n    return rb;\n}\n\nsize_t _z_link_recv_exact_zbuf(const _z_link_t *link, _z_zbuf_t *zbf, size_t len, _z_slice_t *addr,\n                               _z_sys_net_socket_t *socket) {\n    size_t rb = link->_read_exact_f(link, _z_zbuf_get_wptr(zbf), len, addr, socket);\n    if (rb != SIZE_MAX) {\n        _z_zbuf_set_wpos(zbf, _z_zbuf_get_wpos(zbf) + rb);\n    }\n    return rb;\n}\n\nsize_t _z_link_socket_recv_zbuf(const _z_link_t *link, _z_zbuf_t *zbf, const _z_sys_net_socket_t socket) {\n    size_t rb = link->_read_socket_f(socket, _z_zbuf_get_wptr(zbf), _z_zbuf_space_left(zbf));\n    if (rb != SIZE_MAX) {\n        _z_zbuf_set_wpos(zbf, _z_zbuf_get_wpos(zbf) + rb);\n    }\n    return rb;\n}\n\nz_result_t _z_link_send_wbuf(const _z_link_t *link, const _z_wbuf_t *wbf, _z_sys_net_socket_t *socket) {\n    z_result_t ret = _Z_RES_OK;\n    bool link_is_streamed = link->_cap._flow == Z_LINK_CAP_FLOW_STREAM;\n\n    for (size_t i = 0; (i < _z_wbuf_len_iosli(wbf)) && (ret == _Z_RES_OK); i++) {\n        _z_slice_t bs = _z_iosli_to_bytes(_z_wbuf_get_iosli(wbf, i));\n        size_t n = bs.len;\n        do {\n            size_t wb = link->_write_f(link, bs.start, n, socket);\n            if ((wb == SIZE_MAX) || (wb > n)) {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n                ret = _Z_ERR_TRANSPORT_TX_FAILED;\n                break;\n            }\n            if (link_is_streamed && wb != n) {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n                ret = _Z_ERR_TRANSPORT_TX_FAILED;\n                break;\n            }\n            n = n - wb;\n            bs.start = bs.start + (bs.len - n);\n        } while (n > (size_t)0);\n    }\n\n    return ret;\n}\n\nconst _z_sys_net_socket_t *_z_link_get_socket(const _z_link_t *link) {\n    switch (link->_type) {\n#if Z_FEATURE_LINK_TCP == 1\n        case _Z_LINK_TYPE_TCP:\n            return &link->_socket._tcp._sock;\n#endif\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n        case _Z_LINK_TYPE_UDP:\n            return &link->_socket._udp._sock;\n#endif\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n        case _Z_LINK_TYPE_BT:\n            return &link->_socket._bt._sock;\n#endif\n#if Z_FEATURE_LINK_SERIAL == 1\n        case _Z_LINK_TYPE_SERIAL:\n            return &link->_socket._serial._sock;\n#endif\n#if Z_FEATURE_LINK_WS == 1\n        case _Z_LINK_TYPE_WS:\n            return &link->_socket._ws._sock;\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n        case _Z_LINK_TYPE_TLS:\n            return &link->_socket._tls._sock;\n#endif\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n        case _Z_LINK_TYPE_RAWETH:\n            return &link->_socket._raweth._sock;\n#endif\n        default:\n            _Z_INFO(\"Unknown link type\");\n            return NULL;\n    }\n}\n"
  },
  {
    "path": "src/link/multicast/bt.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/link/config/bt.h\"\n\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/bt.h\"\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n\n#define SPP_MAXIMUM_PAYLOAD 128\n\nz_result_t _z_endpoint_bt_valid(_z_endpoint_t *ep) {\n    _z_string_t bt_str = _z_string_alias_str(BT_SCHEMA);\n    if (!_z_string_equals(&ep->_locator._protocol, &bt_str)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    if (_z_string_len(&ep->_locator._address) == (size_t)0) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic char *__z_convert_address_bt(_z_string_t *address) {\n    char *ret = (char *)z_malloc(_z_string_len(address) + 1);\n    if (ret != NULL) {\n        _z_str_n_copy(ret, _z_string_data(address), _z_string_len(address) + 1);\n    }\n    return ret;\n}\n\nz_result_t _z_f_link_open_bt(_z_link_t *self) {\n    const char *mode_str = _z_str_intmap_get(&self->_endpoint._config, BT_CONFIG_MODE_KEY);\n    uint8_t mode = (strcmp(mode_str, \"master\") == 0) ? _Z_BT_MODE_MASTER : _Z_BT_MODE_SLAVE;\n    const char *profile_str = _z_str_intmap_get(&self->_endpoint._config, BT_CONFIG_PROFILE_KEY);\n    uint8_t profile = (strcmp(profile_str, \"spp\") == 0) ? _Z_BT_PROFILE_SPP : _Z_BT_PROFILE_UNSUPPORTED;\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&self->_endpoint._config, BT_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    self->_socket._bt._gname = __z_convert_address_bt(&self->_endpoint._locator._address);\n    return _z_open_bt(&self->_socket._bt._sock, self->_socket._bt._gname, mode, profile, tout);\n}\n\nz_result_t _z_f_link_listen_bt(_z_link_t *self) {\n    const char *mode_str = _z_str_intmap_get(&self->_endpoint._config, BT_CONFIG_MODE_KEY);\n    uint8_t mode = (strcmp(mode_str, \"master\") == 0) ? _Z_BT_MODE_MASTER : _Z_BT_MODE_SLAVE;\n    const char *profile_str = _z_str_intmap_get(&self->_endpoint._config, BT_CONFIG_PROFILE_KEY);\n    uint8_t profile = (strcmp(profile_str, \"spp\") == 0) ? _Z_BT_PROFILE_SPP : _Z_BT_PROFILE_UNSUPPORTED;\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&self->_endpoint._config, BT_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    self->_socket._bt._gname = __z_convert_address_bt(&self->_endpoint._locator._address);\n    return _z_listen_bt(&self->_socket._bt._sock, self->_socket._bt._gname, mode, profile, tout);\n}\n\nvoid _z_f_link_close_bt(_z_link_t *self) { _z_close_bt(&self->_socket._bt._sock); }\n\nvoid _z_f_link_free_bt(_z_link_t *self) { _ZP_UNUSED(self); }\n\nsize_t _z_f_link_write_bt(const _z_link_t *self, const uint8_t *ptr, size_t len, _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    return _z_send_bt(self->_socket._bt._sock, ptr, len);\n}\n\nsize_t _z_f_link_write_all_bt(const _z_link_t *self, const uint8_t *ptr, size_t len) {\n    return _z_send_bt(self->_socket._bt._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_bt(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    size_t rb = _z_read_bt(self->_socket._bt._sock, ptr, len);\n    if ((rb > (size_t)0) && (addr != NULL)) {\n        addr->len = strlen(self->_socket._bt._gname);\n        (void)memcpy((uint8_t *)addr->start, self->_socket._bt._gname, strlen(self->_socket._bt._gname));\n    }\n\n    return rb;\n}\n\nsize_t _z_f_link_read_exact_bt(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                               _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    size_t rb = _z_read_exact_bt(self->_socket._bt._sock, ptr, len);\n    if ((rb == len) && (addr != NULL)) {\n        addr->len = strlen(self->_socket._bt._gname);\n        (void)memcpy((uint8_t *)addr->start, self->_socket._bt._gname, strlen(self->_socket._bt._gname));\n    }\n\n    return rb;\n}\n\nuint16_t _z_get_link_mtu_bt(void) { return SPP_MAXIMUM_PAYLOAD; }\n\nz_result_t _z_new_link_bt(_z_link_t *zl, _z_endpoint_t endpoint) {\n    zl->_type = _Z_LINK_TYPE_BT;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_MULTICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_STREAM;\n    zl->_cap._is_reliable = false;\n\n    zl->_mtu = _z_get_link_mtu_bt();\n\n    zl->_endpoint = endpoint;\n\n    zl->_open_f = _z_f_link_open_bt;\n    zl->_listen_f = _z_f_link_listen_bt;\n    zl->_close_f = _z_f_link_close_bt;\n    zl->_free_f = _z_f_link_free_bt;\n\n    zl->_write_f = _z_f_link_write_bt;\n    zl->_write_all_f = _z_f_link_write_all_bt;\n    zl->_read_f = _z_f_link_read_bt;\n    zl->_read_exact_f = _z_f_link_read_exact_bt;\n    zl->_read_socket_f = _z_noop_link_read_socket;\n\n    return _Z_RES_OK;\n}\n#endif\n"
  },
  {
    "path": "src/link/multicast/udp.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/udp.h\"\n\n#include <stddef.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1\n\nz_result_t _z_endpoint_udp_multicast_valid(_z_endpoint_t *endpoint) {\n    _z_string_t udp_str = _z_string_alias_str(UDP_SCHEMA);\n    if (!_z_string_equals(&endpoint->_locator._protocol, &udp_str)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    z_result_t ret = _z_udp_unicast_address_valid(&endpoint->_locator._address);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return ret;\n    }\n\n    const char *iface = _z_str_intmap_get(&endpoint->_config, UDP_CONFIG_IFACE_KEY);\n    if (iface == NULL) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_f_link_open_udp_multicast(_z_link_t *self) {\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&self->_endpoint._config, UDP_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    const char *iface = _z_str_intmap_get(&self->_endpoint._config, UDP_CONFIG_IFACE_KEY);\n    return _z_udp_multicast_open(&self->_socket._udp._sock, self->_socket._udp._rep, &self->_socket._udp._lep, tout,\n                                 iface);\n}\n\nz_result_t _z_f_link_listen_udp_multicast(_z_link_t *self) {\n    z_result_t ret = _Z_RES_OK;\n\n    const char *iface = _z_str_intmap_get(&self->_endpoint._config, UDP_CONFIG_IFACE_KEY);\n    const char *join = _z_str_intmap_get(&self->_endpoint._config, UDP_CONFIG_JOIN_KEY);\n    ret = _z_udp_multicast_listen(&self->_socket._udp._sock, self->_socket._udp._rep, Z_CONFIG_SOCKET_TIMEOUT, iface,\n                                  join);\n    ret |= _z_udp_multicast_open(&self->_socket._udp._msock, self->_socket._udp._rep, &self->_socket._udp._lep,\n                                 Z_CONFIG_SOCKET_TIMEOUT, iface);\n\n    return ret;\n}\n\nvoid _z_f_link_close_udp_multicast(_z_link_t *self) {\n    _z_udp_multicast_close(&self->_socket._udp._sock, &self->_socket._udp._msock, self->_socket._udp._rep,\n                           self->_socket._udp._lep);\n}\n\nvoid _z_f_link_free_udp_multicast(_z_link_t *self) {\n    _z_udp_multicast_endpoint_clear(&self->_socket._udp._lep);\n    _z_udp_multicast_endpoint_clear(&self->_socket._udp._rep);\n}\n\nsize_t _z_f_link_write_udp_multicast(const _z_link_t *self, const uint8_t *ptr, size_t len,\n                                     _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    return _z_udp_multicast_write(self->_socket._udp._msock, ptr, len, self->_socket._udp._rep);\n}\n\nsize_t _z_f_link_write_all_udp_multicast(const _z_link_t *self, const uint8_t *ptr, size_t len) {\n    return _z_udp_multicast_write(self->_socket._udp._msock, ptr, len, self->_socket._udp._rep);\n}\n\nsize_t _z_f_link_read_udp_multicast(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    return _z_udp_multicast_read(self->_socket._udp._sock, ptr, len, self->_socket._udp._lep, addr);\n}\n\nsize_t _z_f_link_read_exact_udp_multicast(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                          _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    return _z_udp_multicast_read_exact(self->_socket._udp._sock, ptr, len, self->_socket._udp._lep, addr);\n}\n\nuint16_t _z_get_link_mtu_udp_multicast(void) {\n    // @TODO: the return value should change depending on the target platform.\n    return 1450;\n}\n\nz_result_t _z_new_link_udp_multicast(_z_link_t *zl, _z_endpoint_t endpoint) {\n    zl->_type = _Z_LINK_TYPE_UDP;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_MULTICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_DATAGRAM;\n    zl->_cap._is_reliable = false;\n\n    zl->_mtu = _z_get_link_mtu_udp_multicast();\n\n    zl->_endpoint = endpoint;\n    z_result_t ret = _z_udp_multicast_endpoint_init_from_address(&zl->_socket._udp._rep, &endpoint._locator._address);\n    memset(&zl->_socket._udp._lep, 0, sizeof(zl->_socket._udp._lep));\n\n    zl->_open_f = _z_f_link_open_udp_multicast;\n    zl->_listen_f = _z_f_link_listen_udp_multicast;\n    zl->_close_f = _z_f_link_close_udp_multicast;\n    zl->_free_f = _z_f_link_free_udp_multicast;\n\n    zl->_write_f = _z_f_link_write_udp_multicast;\n    zl->_write_all_f = _z_f_link_write_all_udp_multicast;\n    zl->_read_f = _z_f_link_read_udp_multicast;\n    zl->_read_exact_f = _z_f_link_read_exact_udp_multicast;\n    zl->_read_socket_f = _z_noop_link_read_socket;\n\n    return ret;\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/bt/bt_arduino_esp32.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ARDUINO_ESP32) && Z_FEATURE_LINK_BLUETOOTH == 1\n\n#include <BluetoothSerial.h>\n\nextern \"C\" {\n\n#include <stddef.h>\n\n#include \"zenoh-pico/link/transport/bt.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_open_bt(_z_sys_net_socket_t *sock, const char *gname, uint8_t mode, uint8_t profile, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (profile == _Z_BT_PROFILE_SPP) {\n        sock->_bts = new BluetoothSerial();\n        if (mode == _Z_BT_MODE_SLAVE) {\n            sock->_bts->begin(gname, false);\n        } else if (mode == _Z_BT_MODE_MASTER) {\n            sock->_bts->begin(gname, true);\n            uint8_t connected = sock->_bts->connect(gname);\n            if (!connected) {\n                while (!sock->_bts->connected(tout)) {\n                    ZP_ASM_NOP;\n                }\n            }\n        } else {\n            delete sock->_bts;\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_bt(_z_sys_net_socket_t *sock, const char *gname, uint8_t mode, uint8_t profile, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (profile == _Z_BT_PROFILE_SPP) {\n        sock->_bts = new BluetoothSerial();\n        if (mode == _Z_BT_MODE_SLAVE) {\n            sock->_bts->begin(gname, false);\n        } else if (mode == _Z_BT_MODE_MASTER) {\n            sock->_bts->begin(gname, true);\n            uint8_t connected = sock->_bts->connect(gname);\n            if (!connected) {\n                while (!sock->_bts->connected(tout)) {\n                    ZP_ASM_NOP;\n                }\n            }\n        } else {\n            delete sock->_bts;\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nvoid _z_close_bt(_z_sys_net_socket_t *sock) {\n    sock->_bts->end();\n    delete sock->_bts;\n}\n\nsize_t _z_read_bt(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t i = 0;\n    for (i = 0; i < len; i++) {\n        // flawfinder: ignore\n        int c = sock._bts->read();\n        if (c == -1) {\n            delay(1);\n            break;\n        }\n        ptr[i] = (uint8_t)c;\n    }\n\n    return i;\n}\n\nsize_t _z_read_exact_bt(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_bt(sock, pos, len - n);\n        if (rb == SIZE_MAX) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_bt(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    sock._bts->write(ptr, len);\n    return len;\n}\n\n}  // extern \"C\"\n\n#endif\n"
  },
  {
    "path": "src/link/transport/common/address.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_LINUX) || defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n#include <arpa/inet.h>\n#endif\n#if defined(ZENOH_FREERTOS_LWIP)\n#include \"lwip/inet.h\"\n#endif\n#if defined(ZENOH_ZEPHYR)\n#include <zephyr/net/socket.h>\n#endif\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if defined(ZENOH_WINDOWS) || defined(ZENOH_LINUX) || defined(ZENOH_MACOS) || defined(ZENOH_BSD) || \\\n    defined(ZENOH_FREERTOS_LWIP) || defined(ZENOH_ZEPHYR)\n\nstatic z_result_t _z_ipv4_port_to_endpoint(const uint8_t *address, uint16_t port, char *dst, size_t dst_len) {\n    char ip[INET_ADDRSTRLEN] = {0};\n    int written = -1;\n\n#if defined(ZENOH_ZEPHYR)\n    if (zsock_inet_ntop(AF_INET, address, ip, sizeof(ip)) == NULL) {\n#else\n    if (inet_ntop(AF_INET, address, ip, sizeof(ip)) == NULL) {\n#endif\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    written = snprintf(dst, dst_len, \"%s:%u\", ip, (unsigned)port);\n    if ((written < 0) || ((size_t)written >= dst_len)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_ipv6_port_to_endpoint(const uint8_t *address, uint16_t port, char *dst, size_t dst_len) {\n    char ip[INET6_ADDRSTRLEN] = {0};\n    int written = -1;\n\n#if defined(ZENOH_ZEPHYR)\n    if (zsock_inet_ntop(AF_INET6, address, ip, sizeof(ip)) == NULL) {\n#else\n    if (inet_ntop(AF_INET6, address, ip, sizeof(ip)) == NULL) {\n#endif\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    written = snprintf(dst, dst_len, \"[%s]:%u\", ip, (unsigned)port);\n    if ((written < 0) || ((size_t)written >= dst_len)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_ip_port_to_endpoint(const uint8_t *address, size_t address_len, uint16_t port, char *dst,\n                                  size_t dst_len) {\n    if (address == NULL || dst == NULL || dst_len == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    if (address_len == sizeof(uint32_t)) {\n        return _z_ipv4_port_to_endpoint(address, port, dst, dst_len);\n    } else if (address_len == 16) {\n        return _z_ipv6_port_to_endpoint(address, port, dst, dst_len);\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n}\n\n#else\n\nz_result_t _z_ip_port_to_endpoint(const uint8_t *address, size_t address_len, uint16_t port, char *dst,\n                                  size_t dst_len) {\n    _ZP_UNUSED(address);\n    _ZP_UNUSED(address_len);\n    _ZP_UNUSED(port);\n    _ZP_UNUSED(dst);\n    _ZP_UNUSED(dst_len);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/common/endpoints.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_WINDOWS)\n\n#include <winsock2.h>\n#include <ws2tcpip.h>\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic z_result_t _z_sockaddr_to_endpoint(const SOCKADDR *addr, char *dst, size_t dst_len) {\n    if (addr->sa_family == AF_INET) {\n        const SOCKADDR_IN *addr4 = (const SOCKADDR_IN *)addr;\n        const uint8_t *bytes = (const uint8_t *)&addr4->sin_addr;\n        return _z_ip_port_to_endpoint(bytes, sizeof(addr4->sin_addr), ntohs(addr4->sin_port), dst, dst_len);\n    } else if (addr->sa_family == AF_INET6) {\n        const SOCKADDR_IN6 *addr6 = (const SOCKADDR_IN6 *)addr;\n        const uint8_t *bytes = (const uint8_t *)&addr6->sin6_addr;\n        return _z_ip_port_to_endpoint(bytes, sizeof(addr6->sin6_addr), ntohs(addr6->sin6_port), dst, dst_len);\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n}\n\nz_result_t _z_socket_get_endpoints(const _z_sys_net_socket_t *sock, char *local, size_t local_len, char *remote,\n                                   size_t remote_len) {\n    SOCKADDR_STORAGE local_addr = {0};\n    SOCKADDR_STORAGE remote_addr = {0};\n    int local_addr_len = sizeof(local_addr);\n    int remote_addr_len = sizeof(remote_addr);\n    SOCKET fd;\n\n    if (sock == NULL || local == NULL || remote == NULL || local_len == 0 || remote_len == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    fd = sock->_sock._fd;\n    if (fd == INVALID_SOCKET) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    if (getsockname(fd, (SOCKADDR *)&local_addr, &local_addr_len) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (getpeername(fd, (SOCKADDR *)&remote_addr, &remote_addr_len) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    _Z_RETURN_IF_ERR(_z_sockaddr_to_endpoint((const SOCKADDR *)&local_addr, local, local_len));\n    _Z_RETURN_IF_ERR(_z_sockaddr_to_endpoint((const SOCKADDR *)&remote_addr, remote, remote_len));\n    return _Z_RES_OK;\n}\n\n#elif defined(ZENOH_LINUX) || defined(ZENOH_MACOS) || defined(ZENOH_BSD) || defined(ZENOH_ZEPHYR)\n\n#include <stddef.h>\n\n#if defined(ZENOH_ZEPHYR)\n#include <netdb.h>\n#include <sys/socket.h>\n#include <zephyr/net/socket.h>\n#else\n#include <netinet/in.h>\n#include <sys/socket.h>\n#endif\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic z_result_t _z_sockaddr_to_endpoint(const struct sockaddr *addr, char *dst, size_t dst_len) {\n    if (addr->sa_family == AF_INET) {\n        const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;\n        const uint8_t *bytes = (const uint8_t *)&addr4->sin_addr;\n        return _z_ip_port_to_endpoint(bytes, sizeof(addr4->sin_addr), ntohs(addr4->sin_port), dst, dst_len);\n    } else if (addr->sa_family == AF_INET6) {\n        const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;\n        const uint8_t *bytes = (const uint8_t *)&addr6->sin6_addr;\n        return _z_ip_port_to_endpoint(bytes, sizeof(addr6->sin6_addr), ntohs(addr6->sin6_port), dst, dst_len);\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n}\n\nz_result_t _z_socket_get_endpoints(const _z_sys_net_socket_t *sock, char *local, size_t local_len, char *remote,\n                                   size_t remote_len) {\n    struct sockaddr_storage local_addr = {0};\n    struct sockaddr_storage remote_addr = {0};\n    socklen_t local_addr_len = sizeof(local_addr);\n    socklen_t remote_addr_len = sizeof(remote_addr);\n\n    if (sock == NULL || local == NULL || remote == NULL || local_len == 0 || remote_len == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    if (sock->_fd < 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    if (getsockname(sock->_fd, (struct sockaddr *)&local_addr, &local_addr_len) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (getpeername(sock->_fd, (struct sockaddr *)&remote_addr, &remote_addr_len) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    _Z_RETURN_IF_ERR(_z_sockaddr_to_endpoint((const struct sockaddr *)&local_addr, local, local_len));\n    _Z_RETURN_IF_ERR(_z_sockaddr_to_endpoint((const struct sockaddr *)&remote_addr, remote, remote_len));\n    return _Z_RES_OK;\n}\n\n#else\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nz_result_t _z_socket_get_endpoints(const _z_sys_net_socket_t *sock, char *local, size_t local_len, char *remote,\n                                   size_t remote_len) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(local);\n    _ZP_UNUSED(local_len);\n    _ZP_UNUSED(remote);\n    _ZP_UNUSED(remote_len);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/serial/tty_posix.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1 && (defined(ZENOH_LINUX) || defined(ZENOH_MACOS) || defined(ZENOH_BSD))\n\n#include <errno.h>\n#include <fcntl.h>\n#include <limits.h>\n#include <termios.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic speed_t _z_posix_tty_baudrate_to_speed(uint32_t baudrate) {\n    switch (baudrate) {\n        case 1200:\n            return B1200;\n        case 2400:\n            return B2400;\n        case 4800:\n            return B4800;\n        case 9600:\n            return B9600;\n        case 19200:\n            return B19200;\n        case 38400:\n            return B38400;\n#ifdef B57600\n        case 57600:\n            return B57600;\n#endif\n#ifdef B115200\n        case 115200:\n            return B115200;\n#endif\n#ifdef B230400\n        case 230400:\n            return B230400;\n#endif\n        default:\n            return (speed_t)0;\n    }\n}\n\nstatic z_result_t _z_posix_tty_open_impl(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    if (sock == NULL || dev == NULL || baudrate == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    speed_t speed = _z_posix_tty_baudrate_to_speed(baudrate);\n    if (speed == (speed_t)0) {\n        _Z_ERROR(\"Unsupported serial baudrate: %u\", (unsigned)baudrate);\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    // flawfinder: ignore\n    int fd = open(dev, O_RDWR | O_NOCTTY);\n    if (fd < 0) {\n        _Z_ERROR(\"Failed to open serial device %s: errno=%d\", dev, errno);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    struct termios tty;\n    if (tcgetattr(fd, &tty) != 0) {\n        close(fd);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    cfmakeraw(&tty);\n    tty.c_cflag |= (tcflag_t)(CLOCAL | CREAD);\n#ifdef CRTSCTS\n    tty.c_cflag &= (tcflag_t)~CRTSCTS;\n#endif\n    tty.c_cflag &= (tcflag_t)~CSTOPB;\n    tty.c_cflag &= (tcflag_t)~PARENB;\n    tty.c_cflag &= (tcflag_t)~CSIZE;\n    tty.c_cflag |= (tcflag_t)CS8;\n    tty.c_cc[VMIN] = 1;\n    tty.c_cc[VTIME] = 0;\n\n    if (cfsetispeed(&tty, speed) != 0 || cfsetospeed(&tty, speed) != 0) {\n        close(fd);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (tcsetattr(fd, TCSANOW, &tty) != 0) {\n        close(fd);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (tcflush(fd, TCIOFLUSH) != 0) {\n        close(fd);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_fd = fd;\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_posix_tty_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                              uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(txpin);\n    _ZP_UNUSED(rxpin);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_INVALID);\n}\n\nstatic z_result_t _z_posix_tty_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_posix_tty_open_impl(sock, dev, baudrate);\n}\n\nstatic z_result_t _z_posix_tty_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                uint32_t baudrate) {\n    return _z_posix_tty_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_posix_tty_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_posix_tty_open_impl(sock, dev, baudrate);\n}\n\nstatic void _z_posix_tty_close(_z_sys_net_socket_t *sock) {\n    if (sock != NULL && sock->_fd >= 0) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_posix_tty_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t count = len > (size_t)SSIZE_MAX ? (size_t)SSIZE_MAX : len;\n    // flawfinder: ignore\n    ssize_t rb = read(sock._fd, ptr, count);\n    if (rb <= 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_posix_tty_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    size_t count = len > (size_t)SSIZE_MAX ? (size_t)SSIZE_MAX : len;\n    ssize_t wb = write(sock._fd, ptr, count);\n    if (wb <= 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)wb;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_posix_tty_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_posix_tty_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_posix_tty_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_posix_tty_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_posix_tty_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_posix_tty_read(sock, ptr, len); }\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_posix_tty_write(sock, ptr, len);\n}\n\n#endif /* Z_FEATURE_LINK_SERIAL == 1 && POSIX */\n"
  },
  {
    "path": "src/link/transport/serial/uart_arduino_esp32.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ARDUINO_ESP32)\n\n#include <Arduino.h>\n#include <string.h>\n\nextern \"C\" {\n#include \"zenoh-pico/link/transport/serial.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1\n\nstatic z_result_t _z_uart_arduino_esp32_map_pins(uint32_t txpin, uint32_t rxpin, uint8_t *uart) {\n    if (txpin == 1 && rxpin == 3) {\n        *uart = 0;\n    } else if (txpin == 10 && rxpin == 9) {\n        *uart = 1;\n    } else if (txpin == 17 && rxpin == 16) {\n        *uart = 2;\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_arduino_esp32_map_dev(const char *dev, uint8_t *uart, uint32_t *txpin, uint32_t *rxpin) {\n    if (strcmp(dev, \"UART_0\") == 0) {\n        *uart = 0;\n        *txpin = 1;\n        *rxpin = 3;\n    } else if (strcmp(dev, \"UART_1\") == 0) {\n        *uart = 1;\n        *txpin = 10;\n        *rxpin = 9;\n    } else if (strcmp(dev, \"UART_2\") == 0) {\n        *uart = 2;\n        *txpin = 17;\n        *rxpin = 16;\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_arduino_esp32_open_impl(_z_sys_net_socket_t *sock, uint8_t uart, uint32_t txpin,\n                                                  uint32_t rxpin, uint32_t baudrate) {\n    if (sock == NULL || baudrate == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    // Keep the lines high before the UART is initialized to reduce the initial glitch.\n    pinMode((int)rxpin, INPUT_PULLUP);\n    pinMode((int)txpin, OUTPUT);\n    digitalWrite((int)txpin, HIGH);\n\n    sock->_serial = new HardwareSerial(uart);\n    if (sock->_serial == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_serial->begin(baudrate);\n    sock->_serial->flush();\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_arduino_esp32_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                       uint32_t baudrate) {\n    uint8_t uart = 0;\n    _Z_RETURN_IF_ERR(_z_uart_arduino_esp32_map_pins(txpin, rxpin, &uart));\n    return _z_uart_arduino_esp32_open_impl(sock, uart, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_uart_arduino_esp32_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    uint8_t uart = 0;\n    uint32_t txpin = 0;\n    uint32_t rxpin = 0;\n    _Z_RETURN_IF_ERR(_z_uart_arduino_esp32_map_dev(dev, &uart, &txpin, &rxpin));\n    return _z_uart_arduino_esp32_open_impl(sock, uart, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_uart_arduino_esp32_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                         uint32_t baudrate) {\n    return _z_uart_arduino_esp32_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_uart_arduino_esp32_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_arduino_esp32_open_from_dev(sock, dev, baudrate);\n}\n\nstatic void _z_uart_arduino_esp32_close(_z_sys_net_socket_t *sock) {\n    if (sock != NULL && sock->_serial != NULL) {\n        sock->_serial->end();\n        delete sock->_serial;\n        sock->_serial = NULL;\n    }\n}\n\nstatic size_t _z_uart_arduino_esp32_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t rb = 0;\n    while (rb < len) {\n        while (sock._serial->available() < 1) {\n            z_sleep_ms(1);\n        }\n        // flawfinder: ignore\n        int byte = sock._serial->read();\n        if (byte < 0) {\n            return SIZE_MAX;\n        }\n        ptr[rb++] = (uint8_t)byte;\n    }\n\n    return rb;\n}\n\nstatic size_t _z_uart_arduino_esp32_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    size_t wb = sock._serial->write(ptr, len);\n    if (wb == 0) {\n        return SIZE_MAX;\n    }\n    return wb;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_arduino_esp32_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_arduino_esp32_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_arduino_esp32_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_arduino_esp32_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_uart_arduino_esp32_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_uart_arduino_esp32_read(sock, ptr, len);\n}\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_uart_arduino_esp32_write(sock, ptr, len);\n}\n\n#endif /* Z_FEATURE_LINK_SERIAL == 1 */\n}  // extern \"C\"\n\n#endif /* defined(ZENOH_ARDUINO_ESP32) */\n"
  },
  {
    "path": "src/link/transport/serial/uart_espidf.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1 && defined(ZENOH_ESPIDF)\n\n#include <driver/uart.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/queue.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic z_result_t _z_espidf_uart_map_dev(const char *dev, uart_port_t *serial, uint32_t *txpin, uint32_t *rxpin) {\n    if (strcmp(dev, \"UART_0\") == 0) {\n        *serial = UART_NUM_0;\n        *txpin = 1;\n        *rxpin = 3;\n    } else if (strcmp(dev, \"UART_1\") == 0) {\n        *serial = UART_NUM_1;\n        *txpin = 10;\n        *rxpin = 9;\n    } else if (strcmp(dev, \"UART_2\") == 0) {\n        *serial = UART_NUM_2;\n        *txpin = 17;\n        *rxpin = 16;\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_espidf_uart_map_pins(uint32_t txpin, uint32_t rxpin, uart_port_t *serial) {\n    if (txpin == 1 && rxpin == 3) {\n        *serial = UART_NUM_0;\n    } else if (txpin == 10 && rxpin == 9) {\n        *serial = UART_NUM_1;\n    } else if (txpin == 17 && rxpin == 16) {\n        *serial = UART_NUM_2;\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_espidf_uart_open_impl(_z_sys_net_socket_t *sock, uart_port_t serial, uint32_t txpin,\n                                           uint32_t rxpin, uint32_t baudrate) {\n    if (sock == NULL || baudrate == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    sock->_serial = serial;\n\n    const uart_config_t config = {\n        .baud_rate = (int)baudrate,\n        .parity = UART_PARITY_DISABLE,\n        .stop_bits = UART_STOP_BITS_1,\n        .data_bits = UART_DATA_8_BITS,\n        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,\n    };\n    if (uart_param_config(sock->_serial, &config) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (uart_set_pin(sock->_serial, (int)txpin, (int)rxpin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    const int uart_buffer_size = 1024 * 2;\n    QueueHandle_t uart_queue = NULL;\n    if (uart_driver_install(sock->_serial, uart_buffer_size, 0, 100, &uart_queue, 0) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    uart_flush_input(sock->_serial);\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_espidf_uart_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                uint32_t baudrate) {\n    uart_port_t serial = UART_NUM_0;\n    _Z_RETURN_IF_ERR(_z_espidf_uart_map_pins(txpin, rxpin, &serial));\n    return _z_espidf_uart_open_impl(sock, serial, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_espidf_uart_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    uart_port_t serial = UART_NUM_0;\n    uint32_t txpin = 0;\n    uint32_t rxpin = 0;\n    _Z_RETURN_IF_ERR(_z_espidf_uart_map_dev(dev, &serial, &txpin, &rxpin));\n    return _z_espidf_uart_open_impl(sock, serial, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_espidf_uart_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                  uint32_t baudrate) {\n    return _z_espidf_uart_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_espidf_uart_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_espidf_uart_open_from_dev(sock, dev, baudrate);\n}\n\nstatic void _z_espidf_uart_close(_z_sys_net_socket_t *sock) {\n    if (sock != NULL) {\n        uart_wait_tx_done(sock->_serial, 1000 / portTICK_PERIOD_MS);\n        uart_flush(sock->_serial);\n        uart_driver_delete(sock->_serial);\n    }\n}\n\nstatic size_t _z_espidf_uart_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    int rb = uart_read_bytes(sock._serial, ptr, len, 1000 / portTICK_PERIOD_MS);\n    if (rb <= 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_espidf_uart_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    int wb = uart_write_bytes(sock._serial, ptr, len);\n    if (wb <= 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)wb;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_espidf_uart_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_espidf_uart_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_espidf_uart_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_espidf_uart_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_espidf_uart_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_espidf_uart_read(sock, ptr, len);\n}\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_espidf_uart_write(sock, ptr, len);\n}\n\n#endif /* Z_FEATURE_LINK_SERIAL == 1 && defined(ZENOH_ESPIDF) */\n"
  },
  {
    "path": "src/link/transport/serial/uart_flipper.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial.h\"\n\n#if defined(ZENOH_FLIPPER) && (Z_FEATURE_LINK_SERIAL == 1)\n\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic void _z_uart_flipper_received_byte_callback(FuriHalSerialHandle *handle, FuriHalSerialRxEvent event,\n                                                   void *context) {\n    if (context == NULL) {\n        return;\n    }\n\n    if (event == FuriHalSerialRxEventData) {\n        uint8_t data = furi_hal_serial_async_rx(handle);\n        furi_stream_buffer_send((FuriStreamBuffer *)context, &data, 1, FLIPPER_SERIAL_STREAM_TRIGGERED_LEVEL);\n    }\n}\n\nstatic z_result_t _z_uart_flipper_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                 uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(txpin);\n    _ZP_UNUSED(rxpin);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic z_result_t _z_uart_flipper_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    if (furi_hal_serial_control_is_busy(FuriHalSerialIdUsart)) {\n        _Z_ERROR(\"Serial port is busy\");\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_OPEN_FAILED);\n    }\n\n    FuriHalSerialId sid;\n    if (!strcmp(dev, \"usart\")) {\n        sid = FuriHalSerialIdUsart;\n    } else if (!strcmp(dev, \"lpuart\")) {\n        sid = FuriHalSerialIdLpuart;\n    } else {\n        _Z_ERROR(\"Unknown serial port device: %s\", dev);\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_OPEN_FAILED);\n    }\n\n    sock->_serial = furi_hal_serial_control_acquire(sid);\n    if (sock->_serial == NULL) {\n        _Z_ERROR(\"Serial port control acquire failed\");\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_OPEN_FAILED);\n    }\n\n    furi_hal_serial_init(sock->_serial, baudrate);\n    sock->_rx_stream =\n        furi_stream_buffer_alloc(FLIPPER_SERIAL_STREAM_BUFFER_SIZE, FLIPPER_SERIAL_STREAM_TRIGGERED_LEVEL);\n    if (sock->_rx_stream == NULL) {\n        _Z_ERROR(\"Serial stream buffer allocation failed\");\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NO_SPACE);\n    }\n\n    furi_hal_serial_async_rx_start(sock->_serial, _z_uart_flipper_received_byte_callback, sock->_rx_stream, false);\n    _Z_DEBUG(\"Serial port opened: %s (%li)\", dev, baudrate);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_flipper_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                   uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(txpin);\n    _ZP_UNUSED(rxpin);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic z_result_t _z_uart_flipper_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(dev);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic void _z_uart_flipper_close(_z_sys_net_socket_t *sock) {\n    if (sock->_serial != NULL) {\n        furi_hal_serial_async_rx_stop(sock->_serial);\n        furi_hal_serial_deinit(sock->_serial);\n        furi_hal_serial_control_release(sock->_serial);\n        z_sleep_ms(FLIPPER_SERIAL_TIMEOUT_MS * 2);\n        furi_stream_buffer_free(sock->_rx_stream);\n        sock->_serial = NULL;\n        sock->_rx_stream = NULL;\n    }\n    _Z_DEBUG(\"Serial port closed\");\n}\n\nstatic size_t _z_uart_flipper_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        size_t received = furi_stream_buffer_receive(sock._rx_stream, &ptr[i], 1, FLIPPER_SERIAL_TIMEOUT_MS);\n        if (received != 1) {\n            return SIZE_MAX;\n        }\n    }\n    return len;\n}\n\nstatic size_t _z_uart_flipper_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    furi_hal_serial_tx(sock._serial, ptr, len);\n    furi_hal_serial_tx_wait_complete(sock._serial);\n    return len;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_flipper_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_flipper_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_flipper_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_flipper_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_uart_flipper_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_uart_flipper_read(sock, ptr, len);\n}\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_uart_flipper_write(sock, ptr, len);\n}\n\n#endif /* defined(ZENOH_FLIPPER) && (Z_FEATURE_LINK_SERIAL == 1) */\n"
  },
  {
    "path": "src/link/transport/serial/uart_mbed.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_MBED)\n\n#include <mbed.h>\n\nextern \"C\" {\n#include <stddef.h>\n\n#include \"zenoh-pico/link/transport/serial.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic z_result_t _z_uart_mbed_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                              uint32_t baudrate) {\n    sock->_serial = new BufferedSerial(PinName(txpin), PinName(rxpin), baudrate);\n    if (sock->_serial == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_serial->set_format(8, BufferedSerial::None, 1);\n    sock->_serial->enable_input(true);\n    sock->_serial->enable_output(true);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_mbed_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(dev);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic z_result_t _z_uart_mbed_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                uint32_t baudrate) {\n    return _z_uart_mbed_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_uart_mbed_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(dev);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic void _z_uart_mbed_close(_z_sys_net_socket_t *sock) {\n    if (sock != NULL && sock->_serial != NULL) {\n        delete sock->_serial;\n        sock->_serial = NULL;\n    }\n}\n\nstatic size_t _z_uart_mbed_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    // flawfinder: ignore\n    ssize_t rb = sock._serial->read(ptr, len);\n    if (rb <= 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_uart_mbed_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    ssize_t wb = sock._serial->write(ptr, len);\n    if (wb <= 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)wb;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_mbed_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_mbed_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_mbed_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_mbed_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_uart_mbed_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_uart_mbed_read(sock, ptr, len); }\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_uart_mbed_write(sock, ptr, len);\n}\n}  // extern \"C\"\n\n#endif /* defined(ZENOH_MBED) */\n"
  },
  {
    "path": "src/link/transport/serial/uart_rpi_pico.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial.h\"\n\n#if defined(ZENOH_RPI_PICO) && (Z_FEATURE_LINK_SERIAL == 1)\n\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n\ntypedef struct {\n    uint32_t tx_pin;\n    uint32_t rx_pin;\n    uart_inst_t *uart;\n    const char *alias;\n} _z_uart_rpi_pico_pins_t;\n\nstatic const _z_uart_rpi_pico_pins_t _z_uart_rpi_pico_allowed_pins[] = {{0, 1, uart0, \"uart0_0\"},\n                                                                        {4, 5, uart1, \"uart1_0\"},\n                                                                        {8, 9, uart1, \"uart1_1\"},\n                                                                        {12, 13, uart0, \"uart0_1\"},\n                                                                        {16, 17, uart0, \"uart0_2\"}};\n\n#define _Z_UART_RPI_PICO_NUM_PIN_COMBINATIONS \\\n    (sizeof(_z_uart_rpi_pico_allowed_pins) / sizeof(_z_uart_rpi_pico_allowed_pins[0]))\n\nstatic void _z_uart_rpi_pico_open_impl(uart_inst_t *uart, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    uart_init(uart, baudrate);\n    gpio_set_function(txpin, UART_FUNCSEL_NUM(uart, txpin));\n    gpio_set_function(rxpin, UART_FUNCSEL_NUM(uart, rxpin));\n    uart_set_format(uart, 8, 1, UART_PARITY_NONE);\n}\n\nstatic z_result_t _z_uart_rpi_pico_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                  uint32_t baudrate) {\n    if (sock == NULL || baudrate == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    sock->_serial = NULL;\n    for (size_t i = 0; i < _Z_UART_RPI_PICO_NUM_PIN_COMBINATIONS; i++) {\n        if (_z_uart_rpi_pico_allowed_pins[i].tx_pin == txpin && _z_uart_rpi_pico_allowed_pins[i].rx_pin == rxpin) {\n            sock->_serial = _z_uart_rpi_pico_allowed_pins[i].uart;\n            break;\n        }\n    }\n\n    if (sock->_serial == NULL) {\n        _Z_ERROR(\"invalid pin combination\");\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    _z_uart_rpi_pico_open_impl(sock->_serial, txpin, rxpin, baudrate);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_rpi_pico_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    sock->_serial = NULL;\n\n#if Z_FEATURE_LINK_SERIAL_USB == 1\n    if (strcmp(\"usb\", dev) == 0) {\n        _z_usb_uart_init();\n        return _Z_RES_OK;\n    }\n#endif\n\n    uint32_t txpin = 0;\n    uint32_t rxpin = 0;\n    for (size_t i = 0; i < _Z_UART_RPI_PICO_NUM_PIN_COMBINATIONS; i++) {\n        if (strcmp(_z_uart_rpi_pico_allowed_pins[i].alias, dev) == 0) {\n            sock->_serial = _z_uart_rpi_pico_allowed_pins[i].uart;\n            txpin = _z_uart_rpi_pico_allowed_pins[i].tx_pin;\n            rxpin = _z_uart_rpi_pico_allowed_pins[i].rx_pin;\n            break;\n        }\n    }\n\n    if (sock->_serial == NULL) {\n        _Z_ERROR(\"invalid device name\");\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    _z_uart_rpi_pico_open_impl(sock->_serial, txpin, rxpin, baudrate);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_uart_rpi_pico_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                    uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(txpin);\n    _ZP_UNUSED(rxpin);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic z_result_t _z_uart_rpi_pico_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(dev);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_uart_rpi_pico_close(_z_sys_net_socket_t *sock) {\n    if (sock->_serial != NULL) {\n        uart_deinit(sock->_serial);\n    } else {\n#if Z_FEATURE_LINK_SERIAL_USB == 1\n        _z_usb_uart_deinit();\n#endif\n    }\n}\n\nstatic size_t _z_uart_rpi_pico_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n#if Z_FEATURE_LINK_SERIAL_USB == 1\n        ptr[i] = (sock._serial == NULL) ? _z_usb_uart_getc() : uart_getc(sock._serial);\n#else\n        ptr[i] = uart_getc(sock._serial);\n#endif\n    }\n    return len;\n}\n\nstatic size_t _z_uart_rpi_pico_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    if (sock._serial == NULL) {\n#if Z_FEATURE_LINK_SERIAL_USB == 1\n        _z_usb_uart_write(ptr, (int)len);\n#endif\n    } else {\n        uart_write_blocking(sock._serial, ptr, len);\n    }\n    return len;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_rpi_pico_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_rpi_pico_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_uart_rpi_pico_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_uart_rpi_pico_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_uart_rpi_pico_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_uart_rpi_pico_read(sock, ptr, len);\n}\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_uart_rpi_pico_write(sock, ptr, len);\n}\n\n#endif /* defined(ZENOH_RPI_PICO) && (Z_FEATURE_LINK_SERIAL == 1) */\n"
  },
  {
    "path": "src/link/transport/serial/uart_threadx_stm32.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1 && defined(ZENOH_THREADX_STM32)\n\n#include <stdbool.h>\n#include <string.h>\n\n#include \"hal.h\"\n#include \"zenoh-pico/link/transport/serial_protocol.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#define RX_DMA_BUFFER_SIZE (_Z_SERIAL_MAX_COBS_BUF_SIZE * 2 + 2)\n\nstatic uint8_t _z_threadx_stm32_dma_buffer[RX_DMA_BUFFER_SIZE];\nstatic uint16_t _z_threadx_stm32_delimiter_offset = 0;\nstatic TX_SEMAPHORE _z_threadx_stm32_data_ready_semaphore;\nstatic TX_SEMAPHORE _z_threadx_stm32_data_processing_semaphore;\nstatic uint8_t _z_threadx_stm32_frame_buffer[_Z_SERIAL_MAX_COBS_BUF_SIZE];\nstatic size_t _z_threadx_stm32_frame_len = 0;\nstatic size_t _z_threadx_stm32_frame_offset = 0;\nstatic bool _z_threadx_stm32_initialized = false;\nstatic uint16_t _z_threadx_stm32_last_dma_offset = 0;\nextern UART_HandleTypeDef ZENOH_HUART;\n\nstatic z_result_t _z_threadx_stm32_uart_open_impl(void) {\n    if (!_z_threadx_stm32_initialized) {\n        tx_semaphore_create(&_z_threadx_stm32_data_ready_semaphore, \"Data Ready\", 0);\n        tx_semaphore_create(&_z_threadx_stm32_data_processing_semaphore, \"Data Processing\", 1);\n        _z_threadx_stm32_initialized = true;\n    }\n\n    _z_threadx_stm32_delimiter_offset = 0;\n    _z_threadx_stm32_last_dma_offset = 0;\n    _z_threadx_stm32_frame_len = 0;\n    _z_threadx_stm32_frame_offset = 0;\n    memset(_z_threadx_stm32_dma_buffer, 0, sizeof(_z_threadx_stm32_dma_buffer));\n\n    if (HAL_UARTEx_ReceiveToIdle_DMA(&ZENOH_HUART, _z_threadx_stm32_dma_buffer, RX_DMA_BUFFER_SIZE) != HAL_OK) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_threadx_stm32_uart_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                       uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(txpin);\n    _ZP_UNUSED(rxpin);\n    _ZP_UNUSED(baudrate);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic z_result_t _z_threadx_stm32_uart_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(dev);\n    _ZP_UNUSED(baudrate);\n    return _z_threadx_stm32_uart_open_impl();\n}\n\nstatic z_result_t _z_threadx_stm32_uart_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                         uint32_t baudrate) {\n    return _z_threadx_stm32_uart_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_threadx_stm32_uart_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(dev);\n    _ZP_UNUSED(baudrate);\n    return _z_threadx_stm32_uart_open_impl();\n}\n\nstatic void _z_threadx_stm32_uart_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\nstatic size_t _z_threadx_stm32_uart_fill_frame(void) {\n    size_t rb = 0;\n\n    if (tx_semaphore_get(&_z_threadx_stm32_data_ready_semaphore, TX_TIMER_TICKS_PER_SECOND) != TX_SUCCESS) {\n        return SIZE_MAX;\n    }\n\n    if (_z_threadx_stm32_delimiter_offset < _z_threadx_stm32_last_dma_offset) {\n        rb = (RX_DMA_BUFFER_SIZE - _z_threadx_stm32_last_dma_offset) + _z_threadx_stm32_delimiter_offset;\n    } else {\n        rb = _z_threadx_stm32_delimiter_offset - _z_threadx_stm32_last_dma_offset;\n    }\n    if (rb == 0 || rb > sizeof(_z_threadx_stm32_frame_buffer)) {\n        return SIZE_MAX;\n    }\n\n    if (_z_threadx_stm32_delimiter_offset < _z_threadx_stm32_last_dma_offset) {\n        size_t second_part = RX_DMA_BUFFER_SIZE - _z_threadx_stm32_last_dma_offset;\n        // flawfinder: ignore\n        memcpy(_z_threadx_stm32_frame_buffer, _z_threadx_stm32_dma_buffer + _z_threadx_stm32_last_dma_offset,\n               second_part);\n        // flawfinder: ignore\n        memcpy(_z_threadx_stm32_frame_buffer + second_part, _z_threadx_stm32_dma_buffer,\n               _z_threadx_stm32_delimiter_offset);\n    } else {\n        // flawfinder: ignore\n        memcpy(_z_threadx_stm32_frame_buffer, _z_threadx_stm32_dma_buffer + _z_threadx_stm32_last_dma_offset, rb);\n    }\n    _z_threadx_stm32_last_dma_offset = _z_threadx_stm32_delimiter_offset;\n\n    tx_semaphore_put(&_z_threadx_stm32_data_processing_semaphore);\n\n    _z_threadx_stm32_frame_len = rb;\n    _z_threadx_stm32_frame_offset = 0;\n    return rb;\n}\n\nstatic size_t _z_threadx_stm32_uart_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    _ZP_UNUSED(sock);\n\n    if (_z_threadx_stm32_frame_offset == _z_threadx_stm32_frame_len) {\n        if (_z_threadx_stm32_uart_fill_frame() == SIZE_MAX) {\n            return SIZE_MAX;\n        }\n    }\n\n    size_t available = _z_threadx_stm32_frame_len - _z_threadx_stm32_frame_offset;\n    size_t chunk = len < available ? len : available;\n    // flawfinder: ignore\n    memcpy(ptr, &_z_threadx_stm32_frame_buffer[_z_threadx_stm32_frame_offset], chunk);\n    _z_threadx_stm32_frame_offset += chunk;\n\n    if (_z_threadx_stm32_frame_offset == _z_threadx_stm32_frame_len) {\n        _z_threadx_stm32_frame_len = 0;\n        _z_threadx_stm32_frame_offset = 0;\n    }\n\n    return chunk;\n}\n\nstatic size_t _z_threadx_stm32_uart_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    _ZP_UNUSED(sock);\n\n    if (HAL_UART_Transmit(&ZENOH_HUART, (uint8_t *)ptr, len, 2000) != HAL_OK) {\n        _Z_ERROR(\"Could not send to serial device!\");\n        return SIZE_MAX;\n    }\n\n    return len;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_threadx_stm32_uart_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_threadx_stm32_uart_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_threadx_stm32_uart_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_threadx_stm32_uart_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_threadx_stm32_uart_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_threadx_stm32_uart_read(sock, ptr, len);\n}\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_threadx_stm32_uart_write(sock, ptr, len);\n}\n\nvoid zptxstm32_rx_event_cb(UART_HandleTypeDef *huart, uint16_t offset) {\n    static uint16_t last_offset = 0;\n    if (huart != &ZENOH_HUART) {\n        return;\n    }\n    if (offset == last_offset) {\n        return;\n    }\n    if (offset < last_offset) {\n        last_offset = 0;\n    }\n\n    while (last_offset < offset) {\n        if (_z_threadx_stm32_dma_buffer[last_offset] == (uint8_t)0x00) {\n            tx_semaphore_get(&_z_threadx_stm32_data_processing_semaphore, TX_WAIT_FOREVER);\n            _z_threadx_stm32_delimiter_offset = last_offset + 1;\n            tx_semaphore_put(&_z_threadx_stm32_data_ready_semaphore);\n        }\n        ++last_offset;\n    }\n}\n\nvoid zptxstm32_error_event_cb(UART_HandleTypeDef *huart) {\n    if (huart != &ZENOH_HUART) {\n        return;\n    }\n\n    _Z_ERROR(\"UART error!\");\n    HAL_UARTEx_ReceiveToIdle_DMA(&ZENOH_HUART, _z_threadx_stm32_dma_buffer, RX_DMA_BUFFER_SIZE);\n}\n\n#if ZENOH_THREADX_STM32_GEN_IRQ == 1\nvoid HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t offset) { zptxstm32_rx_event_cb(huart, offset); }\n\nvoid HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {\n    HAL_UART_DMAStop(huart);\n    HAL_UART_Abort(huart);\n    __HAL_UART_CLEAR_IDLEFLAG(huart);\n    __HAL_UART_CLEAR_OREFLAG(huart);\n    __HAL_UART_CLEAR_PEFLAG(huart);\n    __HAL_UART_CLEAR_FEFLAG(huart);\n    zptxstm32_error_event_cb(huart);\n}\n#endif\n\n#endif /* Z_FEATURE_LINK_SERIAL == 1 && defined(ZENOH_THREADX_STM32) */\n"
  },
  {
    "path": "src/link/transport/serial/uart_zephyr.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1 && defined(ZENOH_ZEPHYR)\n\n#include <version.h>\n\n#if KERNEL_VERSION_MAJOR == 2\n#include <drivers/uart.h>\n#else\n#include <zephyr/drivers/uart.h>\n#endif\n\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic z_result_t _z_zephyr_uart_open_impl(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    if (sock == NULL || dev == NULL || baudrate == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    sock->_serial = device_get_binding(dev);\n    if (sock->_serial == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    const struct uart_config config = {\n        .baudrate = baudrate,\n        .parity = UART_CFG_PARITY_NONE,\n        .stop_bits = UART_CFG_STOP_BITS_1,\n        .data_bits = UART_CFG_DATA_BITS_8,\n        .flow_ctrl = UART_CFG_FLOW_CTRL_NONE,\n    };\n    if (uart_configure(sock->_serial, &config) != 0) {\n        sock->_serial = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_zephyr_uart_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                uint32_t baudrate) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(txpin);\n    _ZP_UNUSED(rxpin);\n    _ZP_UNUSED(baudrate);\n\n    // @TODO: To be implemented\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic z_result_t _z_zephyr_uart_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_zephyr_uart_open_impl(sock, dev, baudrate);\n}\n\nstatic z_result_t _z_zephyr_uart_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin,\n                                                  uint32_t baudrate) {\n    return _z_zephyr_uart_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nstatic z_result_t _z_zephyr_uart_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_zephyr_uart_open_impl(sock, dev, baudrate);\n}\n\nstatic void _z_zephyr_uart_close(_z_sys_net_socket_t *sock) {\n    if (sock != NULL) {\n        sock->_serial = NULL;\n    }\n}\n\nstatic size_t _z_zephyr_uart_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        int res = -1;\n        while (res != 0) {\n            res = uart_poll_in(sock._serial, &ptr[i]);\n        }\n    }\n\n    return len;\n}\n\nstatic size_t _z_zephyr_uart_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        uart_poll_out(sock._serial, ptr[i]);\n    }\n\n    return len;\n}\n\nz_result_t _z_serial_open_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_zephyr_uart_open_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_open_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_zephyr_uart_open_from_dev(sock, dev, baudrate);\n}\n\nz_result_t _z_serial_listen_from_pins(_z_sys_net_socket_t *sock, uint32_t txpin, uint32_t rxpin, uint32_t baudrate) {\n    return _z_zephyr_uart_listen_from_pins(sock, txpin, rxpin, baudrate);\n}\n\nz_result_t _z_serial_listen_from_dev(_z_sys_net_socket_t *sock, const char *dev, uint32_t baudrate) {\n    return _z_zephyr_uart_listen_from_dev(sock, dev, baudrate);\n}\n\nvoid _z_serial_close(_z_sys_net_socket_t *sock) { _z_zephyr_uart_close(sock); }\n\nsize_t _z_serial_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_zephyr_uart_read(sock, ptr, len);\n}\n\nsize_t _z_serial_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_zephyr_uart_write(sock, ptr, len);\n}\n\n#endif /* Z_FEATURE_LINK_SERIAL == 1 && defined(ZENOH_ZEPHYR) */\n"
  },
  {
    "path": "src/link/transport/tcp/address.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdlib.h>\n\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/link/transport/tcp.h\"\n\nchar *_z_tcp_address_parse_host(const _z_string_t *address) { return _z_endpoint_parse_host(address); }\n\nz_result_t _z_tcp_address_valid(const _z_string_t *address) {\n    char *host = _z_tcp_address_parse_host(address);\n    char *port = _z_endpoint_parse_port(address);\n    z_result_t ret = ((host != NULL) && (port != NULL)) ? _Z_RES_OK : _Z_ERR_CONFIG_LOCATOR_INVALID;\n\n    z_free(host);\n    z_free(port);\n    return ret;\n}\n\nz_result_t _z_tcp_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    z_result_t ret = _Z_RES_OK;\n    char *host = _z_tcp_address_parse_host(address);\n    char *port = _z_endpoint_parse_port(address);\n\n    if ((host == NULL) || (port == NULL)) {\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n    } else {\n        ret = _z_tcp_endpoint_init(ep, host, port);\n    }\n\n    z_free(host);\n    z_free(port);\n    return ret;\n}\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_esp32.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ESP32)\n\n#include <netdb.h>\n#include <stddef.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_esp32_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_esp32_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp == NULL)) {\n        return;\n    }\n\n    freeaddrinfo(ep->_iptcp);\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_tcp_esp32_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(tout);\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        int optflag = 1;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optflag, sizeof(optflag)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&optflag, sizeof(optflag)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n\n#if LWIP_SO_LINGER == 1\n        struct linger ling;\n        ling.l_onoff = 1;\n        ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n\n        for (struct addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n            if ((ret == _Z_RES_OK) && (connect(sock->_fd, it->ai_addr, it->ai_addrlen) < 0)) {\n                if (it->ai_next == NULL) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                    break;\n                }\n            } else {\n                break;\n            }\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_esp32_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n    int optflag = 1;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(sock->_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&optflag, sizeof(optflag)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#endif\n    if (ret != _Z_RES_OK) {\n        close(sock->_fd);\n        sock->_fd = -1;\n        return ret;\n    }\n\n    for (struct addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n        if (bind(sock->_fd, it->ai_addr, it->ai_addrlen) < 0) {\n            if (it->ai_next == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n            }\n        }\n        if (listen(sock->_fd, Z_LISTEN_MAX_CONNECTION_NB) < 0) {\n            if (it->ai_next == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n            }\n        }\n    }\n\n    if (ret != _Z_RES_OK) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_esp32_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    struct sockaddr naddr;\n    socklen_t nlen = sizeof(naddr);\n    sock_out->_fd = -1;\n    int con_socket = accept(sock_in->_fd, &naddr, &nlen);\n    if (con_socket < 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    int optflag = 1;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&optflag, sizeof(optflag)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#if Z_FEATURE_TCP_NODELAY == 1\n    if (setsockopt(con_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&optflag, sizeof(optflag)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n#if LWIP_SO_LINGER == 1\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n\n    sock_out->_fd = con_socket;\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_esp32_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        shutdown(sock->_fd, SHUT_RDWR);\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_tcp_esp32_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    ssize_t rb = recv(sock._fd, ptr, len, 0);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_esp32_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_esp32_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_esp32_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    ssize_t wb = send(sock._fd, ptr, len, 0);\n    if (wb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)wb;\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_esp32_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_esp32_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_esp32_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_esp32_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_esp32_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_esp32_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_esp32_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_esp32_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_esp32_write(sock, ptr, len);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_ESP32) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_freertos_plus_tcp.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_FREERTOS_PLUS_TCP)\n\n#include <stdlib.h>\n\n#include \"FreeRTOS.h\"\n#include \"FreeRTOS_IP.h\"\n#include \"FreeRTOS_Sockets.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_freertos_plus_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address,\n                                                         const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (FreeRTOS_getaddrinfo(s_address, NULL, NULL, &ep->_iptcp) < 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n        return ret;\n    }\n\n    ep->_iptcp->ai_addr->sin_family = ep->_iptcp->ai_family;\n\n    uint32_t port = strtoul(s_port, NULL, 10);\n    if ((port > (uint32_t)0) && (port <= (uint32_t)65535)) {\n        ep->_iptcp->ai_addr->sin_port = FreeRTOS_htons((uint16_t)port);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_freertos_plus_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp == NULL)) {\n        return;\n    }\n\n    FreeRTOS_freeaddrinfo(ep->_iptcp);\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_tcp_freertos_plus_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint,\n                                                uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_socket = FreeRTOS_socket(endpoint._iptcp->ai_family, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);\n    if (sock->_socket != FREERTOS_INVALID_SOCKET) {\n        TickType_t receive_timeout = pdMS_TO_TICKS(tout);\n\n        if (FreeRTOS_setsockopt(sock->_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, 0) != 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        } else if (FreeRTOS_connect(sock->_socket, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            FreeRTOS_closesocket(sock->_socket);\n            sock->_socket = FREERTOS_INVALID_SOCKET;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_freertos_plus_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    sock->_socket = FreeRTOS_socket(endpoint._iptcp->ai_family, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);\n    if (sock->_socket == FREERTOS_INVALID_SOCKET) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (FreeRTOS_bind(sock->_socket, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen) != 0) {\n        FreeRTOS_closesocket(sock->_socket);\n        sock->_socket = FREERTOS_INVALID_SOCKET;\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (FreeRTOS_listen(sock->_socket, Z_LISTEN_MAX_CONNECTION_NB) != 0) {\n        FreeRTOS_closesocket(sock->_socket);\n        sock->_socket = FREERTOS_INVALID_SOCKET;\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_tcp_freertos_plus_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    struct freertos_sockaddr naddr;\n    socklen_t nlen = sizeof(naddr);\n    sock_out->_socket = FREERTOS_INVALID_SOCKET;\n    Socket_t con_socket = FreeRTOS_accept(sock_in->_socket, &naddr, &nlen);\n    if (con_socket == FREERTOS_INVALID_SOCKET) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    TickType_t receive_timeout = pdMS_TO_TICKS(Z_CONFIG_SOCKET_TIMEOUT);\n    if (FreeRTOS_setsockopt(con_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, 0) != 0) {\n        FreeRTOS_closesocket(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock_out->_socket = con_socket;\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_freertos_plus_tcp_close(_z_sys_net_socket_t *sock) {\n    if (sock->_socket != FREERTOS_INVALID_SOCKET) {\n        FreeRTOS_closesocket(sock->_socket);\n        sock->_socket = FREERTOS_INVALID_SOCKET;\n    }\n}\n\nstatic size_t _z_tcp_freertos_plus_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    BaseType_t rb = FreeRTOS_recv(sock._socket, ptr, len, 0);\n    if (rb < 0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_freertos_plus_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_freertos_plus_tcp_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_freertos_plus_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return (size_t)FreeRTOS_send(sock._socket, ptr, len, 0);\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_freertos_plus_tcp_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_freertos_plus_tcp_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_freertos_plus_tcp_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_freertos_plus_tcp_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_freertos_plus_tcp_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_freertos_plus_tcp_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_freertos_plus_tcp_read(sock, ptr, len);\n}\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_freertos_plus_tcp_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_freertos_plus_tcp_write(sock, ptr, len);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_FREERTOS_PLUS_TCP) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_lwip.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP) && (Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_TLS == 1 || Z_FEATURE_LINK_WS == 1)\n\n#include <stddef.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"lwip/netdb.h\"\n#include \"lwip/sockets.h\"\n#include \"zenoh-pico/link/transport/lwip_socket.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_lwip_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    } else if (ep->_iptcp != NULL && ep->_iptcp->ai_addr != NULL) {\n        ep->_iptcp->ai_addr->sa_family = ep->_iptcp->ai_family;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_lwip_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp == NULL)) {\n        return;\n    }\n\n    freeaddrinfo(ep->_iptcp);\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_tcp_lwip_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_lwip_socket_set(sock,\n                       socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol));\n    if (_z_lwip_socket_get(*sock) != -1) {\n        z_time_t tv;\n        tv.tv_sec = tout / (uint32_t)1000;\n        tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        int flags = 1;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#if Z_FEATURE_TCP_NODELAY == 1\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(_z_lwip_socket_get(*sock), IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n        struct linger ling;\n        ling.l_onoff = 1;\n        ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        for (struct addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n            if ((ret == _Z_RES_OK) && (connect(_z_lwip_socket_get(*sock), it->ai_addr, it->ai_addrlen) < 0)) {\n                if (it->ai_next == NULL) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                    break;\n                }\n            } else {\n                break;\n            }\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(_z_lwip_socket_get(*sock));\n            _z_lwip_socket_set(sock, -1);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_lwip_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_lwip_socket_set(sock,\n                       socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol));\n    if (_z_lwip_socket_get(*sock) == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    int flags = 1;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#if Z_FEATURE_TCP_NODELAY == 1\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(_z_lwip_socket_get(*sock), IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#endif\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        close(_z_lwip_socket_get(*sock));\n        _z_lwip_socket_set(sock, -1);\n        return ret;\n    }\n\n    for (struct addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n        if (bind(_z_lwip_socket_get(*sock), it->ai_addr, it->ai_addrlen) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n            break;\n        }\n        if (listen(_z_lwip_socket_get(*sock), Z_LISTEN_MAX_CONNECTION_NB) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n            break;\n        }\n    }\n\n    if (ret != _Z_RES_OK) {\n        close(_z_lwip_socket_get(*sock));\n        _z_lwip_socket_set(sock, -1);\n    }\n    return ret;\n}\n\nstatic z_result_t _z_tcp_lwip_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    struct sockaddr naddr;\n    socklen_t nlen = sizeof(naddr);\n    _z_lwip_socket_set(sock_out, -1);\n    int con_socket = lwip_accept(_z_lwip_socket_get(*sock_in), &naddr, &nlen);\n    if (con_socket < 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    z_time_t tv;\n    tv.tv_sec = Z_CONFIG_SOCKET_TIMEOUT / (uint32_t)1000;\n    tv.tv_usec = (Z_CONFIG_SOCKET_TIMEOUT % (uint32_t)1000) * (uint32_t)1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0) {\n        lwip_close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    int flags = 1;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {\n        lwip_close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#if Z_FEATURE_TCP_NODELAY == 1\n    if (setsockopt(con_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0) {\n        lwip_close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0) {\n        lwip_close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_lwip_socket_set(sock_out, con_socket);\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_lwip_close(_z_sys_net_socket_t *sock) {\n    if (_z_lwip_socket_get(*sock) >= 0) {\n        shutdown(_z_lwip_socket_get(*sock), SHUT_RDWR);\n        close(_z_lwip_socket_get(*sock));\n        _z_lwip_socket_set(sock, -1);\n    }\n}\n\nstatic size_t _z_tcp_lwip_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    ssize_t rb = recv(_z_lwip_socket_get(sock), ptr, len, 0);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_lwip_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_lwip_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_lwip_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return (size_t)send(_z_lwip_socket_get(sock), ptr, len, 0);\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_lwip_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_lwip_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_lwip_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_lwip_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_lwip_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_lwip_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_lwip_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_lwip_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_lwip_write(sock, ptr, len);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_LWIP) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_mbed.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_MBED)\n\n#include <NetworkInterface.h>\n#include <mbed.h>\n\nextern \"C\" {\n#include <stddef.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_mbed_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    uint32_t port = strtoul(s_port, NULL, 10);\n    if ((port == 0U) || (port > 65535U)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    ep->_iptcp = new SocketAddress(s_address, port);\n    if (ep->_iptcp == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_mbed_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp == NULL)) {\n        return;\n    }\n\n    delete ep->_iptcp;\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_tcp_mbed_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    NetworkInterface *iface = NetworkInterface::get_default_instance();\n    if (iface == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_tcp = new TCPSocket();\n    if (sock->_tcp == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_tcp->set_timeout((int)tout);\n    // flawfinder: ignore\n    if (sock->_tcp->open(iface) < 0) {\n        delete sock->_tcp;\n        sock->_tcp = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    if (sock->_tcp->connect(*endpoint._iptcp) < 0) {\n        sock->_tcp->close();\n        delete sock->_tcp;\n        sock->_tcp = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_tcp_mbed_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic z_result_t _z_tcp_mbed_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    _ZP_UNUSED(sock_in);\n    _ZP_UNUSED(sock_out);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic void _z_tcp_mbed_close(_z_sys_net_socket_t *sock) {\n    if (sock->_tcp != NULL) {\n        sock->_tcp->close();\n        delete sock->_tcp;\n        sock->_tcp = NULL;\n    }\n}\n\nstatic size_t _z_tcp_mbed_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    nsapi_size_or_error_t rb = sock._tcp->recv(ptr, len);\n    if (rb < 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_mbed_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_mbed_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_mbed_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    nsapi_size_or_error_t wb = sock._tcp->send(ptr, len);\n    if (wb < 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)wb;\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_mbed_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_mbed_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_mbed_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_mbed_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_mbed_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_mbed_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_mbed_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_mbed_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_mbed_write(sock, ptr, len);\n}\n}  // extern \"C\"\n\n#endif /* defined(ZP_PLATFORM_SOCKET_MBED) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_opencr.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_OPENCR)\n\n#include <Arduino.h>\n#include <WiFiClient.h>\n#include <stddef.h>\n#include <stdlib.h>\n\nextern \"C\" {\n#include \"zenoh-pico/link/transport/tcp.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_opencr_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    ep->_iptcp._addr = new IPAddress();\n    if (!ep->_iptcp._addr->fromString(s_address)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    ep->_iptcp._port = strtoul(s_port, NULL, 10);\n    if ((ep->_iptcp._port < (uint32_t)1) ||\n        (ep->_iptcp._port > (uint32_t)65535)) {  // Port numbers should range from 1 to 65535\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        delete ep->_iptcp._addr;\n        ep->_iptcp._addr = NULL;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_opencr_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp._addr == NULL)) {\n        return;\n    }\n\n    delete ep->_iptcp._addr;\n    ep->_iptcp._addr = NULL;\n}\n\nstatic z_result_t _z_tcp_opencr_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(tout);\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_tcp = new WiFiClient();\n    if (!sock->_tcp->connect(*endpoint._iptcp._addr, endpoint._iptcp._port)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        delete sock->_tcp;\n        sock->_tcp = NULL;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_opencr_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic z_result_t _z_tcp_opencr_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    _ZP_UNUSED(sock_in);\n    _ZP_UNUSED(sock_out);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_tcp_opencr_close(_z_sys_net_socket_t *sock) {\n    if (sock->_tcp != NULL) {\n        sock->_tcp->stop();\n        delete sock->_tcp;\n        sock->_tcp = NULL;\n    }\n}\n\nstatic size_t _z_tcp_opencr_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    if (sock._tcp->available() > 0) {\n        // flawfinder: ignore\n        int rb = sock._tcp->read(ptr, len);\n        if (rb < 0) {\n            return SIZE_MAX;\n        }\n        return (size_t)rb;\n    }\n    return 0;\n}\n\nstatic size_t _z_tcp_opencr_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_opencr_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_opencr_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    sock._tcp->write(ptr, len);\n    return len;\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_opencr_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_opencr_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_opencr_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_opencr_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_opencr_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_opencr_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_opencr_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_opencr_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_opencr_write(sock, ptr, len);\n}\n}  // extern \"C\"\n\n#endif /* defined(ZP_PLATFORM_SOCKET_OPENCR) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_posix.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_POSIX)\n\n#include <arpa/inet.h>\n#include <errno.h>\n#include <netdb.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_posix_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_posix_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp == NULL)) {\n        return;\n    }\n\n    freeaddrinfo(ep->_iptcp);\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_tcp_posix_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        z_time_t tv;\n        tv.tv_sec = (time_t)(tout / (uint32_t)1000);\n        tv.tv_usec = (suseconds_t)((tout % (uint32_t)1000) * (uint32_t)1000);\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        int flags = 1;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#if Z_FEATURE_TCP_NODELAY == 1\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n        struct linger ling;\n        ling.l_onoff = 1;\n        ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n#if defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n        int nosigpipe_val = 1;\n        setsockopt(sock->_fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe_val, sizeof(int));\n#endif\n        for (struct addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n            if ((ret == _Z_RES_OK) && (connect(sock->_fd, it->ai_addr, it->ai_addrlen) < 0)) {\n                if (it->ai_next == NULL) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                    break;\n                }\n            } else {\n                break;\n            }\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_posix_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    int value = true;\n    if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n    int flags = 1;\n    if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#if Z_FEATURE_TCP_NODELAY == 1\n    if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#endif\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(sock->_fd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#if defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n    int nosigpipe_val = 1;\n    setsockopt(sock->_fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe_val, sizeof(int));\n#endif\n    if (ret != _Z_RES_OK) {\n        close(sock->_fd);\n        return ret;\n    }\n\n    int addr_count = 0;\n    for (struct addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n        addr_count++;\n        char addr_str[INET6_ADDRSTRLEN];\n        const char *family_str = (it->ai_family == AF_INET) ? \"IPv4\" : (it->ai_family == AF_INET6) ? \"IPv6\" : \"Unknown\";\n\n        if (it->ai_family == AF_INET) {\n            inet_ntop(AF_INET, &((struct sockaddr_in *)it->ai_addr)->sin_addr, addr_str, INET_ADDRSTRLEN);\n        } else if (it->ai_family == AF_INET6) {\n            inet_ntop(AF_INET6, &((struct sockaddr_in6 *)it->ai_addr)->sin6_addr, addr_str, INET6_ADDRSTRLEN);\n        } else {\n            snprintf(addr_str, sizeof(addr_str), \"%s\", \"unknown\");\n        }\n\n        _Z_DEBUG(\"Trying address %d: %s (%s), family=%d\", addr_count, addr_str, family_str, it->ai_family);\n        if (bind(sock->_fd, it->ai_addr, it->ai_addrlen) < 0) {\n            _Z_DEBUG(\"bind() failed for address %s: %s\", addr_str, strerror(errno));\n            if (it->ai_next == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n            }\n            continue;\n        }\n        _Z_DEBUG(\"bind() successful for address %s\", addr_str);\n\n        if (listen(sock->_fd, Z_LISTEN_MAX_CONNECTION_NB) < 0) {\n            _Z_DEBUG(\"listen() failed for address %s: %s\", addr_str, strerror(errno));\n            if (it->ai_next == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n            }\n            continue;\n        }\n        _Z_DEBUG(\"listen() successful for address %s\", addr_str);\n        break;\n    }\n    if (ret != _Z_RES_OK) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n    return ret;\n}\n\nstatic z_result_t _z_tcp_posix_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    struct sockaddr naddr;\n    unsigned int nlen = sizeof(naddr);\n    sock_out->_fd = -1;\n    int con_socket = accept(sock_in->_fd, &naddr, &nlen);\n    if (con_socket < 0) {\n        if (errno == EBADF) {\n            _Z_ERROR_RETURN(_Z_ERR_INVALID);\n        } else {\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n    }\n\n    z_time_t tv;\n    tv.tv_sec = Z_CONFIG_SOCKET_TIMEOUT / (uint32_t)1000;\n    tv.tv_usec = (Z_CONFIG_SOCKET_TIMEOUT % (uint32_t)1000) * (uint32_t)1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    int flags = 1;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#if Z_FEATURE_TCP_NODELAY == 1\n    if (setsockopt(con_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock_out->_fd = con_socket;\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_posix_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        shutdown(sock->_fd, SHUT_RDWR);\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_tcp_posix_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    ssize_t rb = recv(sock._fd, ptr, len, 0);\n    if (rb < (ssize_t)0) {\n        if (errno != EAGAIN) {\n            _Z_DEBUG(\"Errno: %d\\n\", errno);\n        }\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_posix_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_posix_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n += rb;\n        pos = _z_ptr_u8_offset(pos, (ptrdiff_t)rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_posix_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n#if defined(ZENOH_LINUX)\n    return (size_t)send(sock._fd, ptr, len, MSG_NOSIGNAL);\n#else\n    return (size_t)send(sock._fd, ptr, len, 0);\n#endif\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_posix_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_posix_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_posix_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_posix_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_posix_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_posix_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_posix_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_posix_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_posix_write(sock, ptr, len);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_POSIX) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_windows.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_WINDOWS)\n\n#include <string.h>\n#include <winsock2.h>\n#include <ws2tcpip.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic WSADATA _z_tcp_windows_wsa_data;\n\nstatic z_result_t _z_tcp_windows_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n    ep->_ep._iptcp = NULL;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_tcp_windows_wsa_data) == 0) {\n        ADDRINFOA hints;\n        (void)memset(&hints, 0, sizeof(hints));\n        hints.ai_family = AF_UNSPEC;\n        hints.ai_socktype = SOCK_STREAM;\n        hints.ai_flags = 0;\n        hints.ai_protocol = IPPROTO_TCP;\n\n        if (getaddrinfo(s_address, s_port, &hints, &ep->_ep._iptcp) != 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            WSACleanup();\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_windows_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_ep._iptcp == NULL)) {\n        return;\n    }\n\n    freeaddrinfo(ep->_ep._iptcp);\n    ep->_ep._iptcp = NULL;\n    WSACleanup();\n}\n\nstatic z_result_t _z_tcp_windows_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_tcp_windows_wsa_data) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    sock->_sock._fd =\n        socket(endpoint._ep._iptcp->ai_family, endpoint._ep._iptcp->ai_socktype, endpoint._ep._iptcp->ai_protocol);\n    if (sock->_sock._fd != INVALID_SOCKET) {\n        DWORD tv = tout;\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        int flags = 1;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&flags, sizeof(flags)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_sock._fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&flags, sizeof(flags)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n\n        struct linger ling;\n        ling.l_onoff = 1;\n        ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_LINGER, (const char *)&ling, sizeof(ling)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        ADDRINFOA *it = NULL;\n        for (it = endpoint._ep._iptcp; it != NULL; it = it->ai_next) {\n            if ((ret == _Z_RES_OK) && (connect(sock->_sock._fd, it->ai_addr, (int)it->ai_addrlen) < 0)) {\n                if (it->ai_next == NULL) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                    break;\n                }\n            } else {\n                break;\n            }\n        }\n\n        if (ret != _Z_RES_OK) {\n            closesocket(sock->_sock._fd);\n            sock->_sock._fd = INVALID_SOCKET;\n            WSACleanup();\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_windows_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_tcp_windows_wsa_data) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_sock._fd =\n        socket(endpoint._ep._iptcp->ai_family, endpoint._ep._iptcp->ai_socktype, endpoint._ep._iptcp->ai_protocol);\n    if (sock->_sock._fd == INVALID_SOCKET) {\n        WSACleanup();\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    int value = 1;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&value, sizeof(value)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    int flags = 1;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&flags, sizeof(flags)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(sock->_sock._fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&flags, sizeof(flags)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#endif\n\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if ((ret == _Z_RES_OK) &&\n        (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_LINGER, (const char *)&ling, sizeof(ling)) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        closesocket(sock->_sock._fd);\n        WSACleanup();\n        return ret;\n    }\n\n    ADDRINFOA *it = NULL;\n    for (it = endpoint._ep._iptcp; it != NULL; it = it->ai_next) {\n        if (bind(sock->_sock._fd, it->ai_addr, (int)it->ai_addrlen) < 0) {\n            if (it->ai_next == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n            }\n        }\n        if (listen(sock->_sock._fd, Z_LISTEN_MAX_CONNECTION_NB) < 0) {\n            if (it->ai_next == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n            }\n        }\n    }\n\n    if (ret != _Z_RES_OK) {\n        closesocket(sock->_sock._fd);\n        sock->_sock._fd = INVALID_SOCKET;\n    }\n\n    WSACleanup();\n    return ret;\n}\n\nstatic z_result_t _z_tcp_windows_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    struct sockaddr naddr;\n    int nlen = sizeof(naddr);\n    sock_out->_sock._fd = INVALID_SOCKET;\n    SOCKET con_socket = accept(sock_in->_sock._fd, &naddr, &nlen);\n    if (con_socket == INVALID_SOCKET) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    DWORD tv = Z_CONFIG_SOCKET_TIMEOUT;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0) {\n        closesocket(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    int flags = 1;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {\n        closesocket(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#if Z_FEATURE_TCP_NODELAY == 1\n    if (setsockopt(con_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0) {\n        closesocket(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0) {\n        closesocket(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock_out->_sock._fd = con_socket;\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_windows_close(_z_sys_net_socket_t *sock) {\n    if (sock->_sock._fd != INVALID_SOCKET) {\n        shutdown(sock->_sock._fd, SD_BOTH);\n        closesocket(sock->_sock._fd);\n        sock->_sock._fd = INVALID_SOCKET;\n        WSACleanup();\n    }\n}\n\nstatic size_t _z_tcp_windows_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    int rb = recv(sock._sock._fd, (char *)ptr, (int)len, 0);\n    if (rb == SOCKET_ERROR) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_windows_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_windows_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_windows_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    int wb = send(sock._sock._fd, (const char *)ptr, (int)len, 0);\n    if (wb == SOCKET_ERROR) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)wb;\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_windows_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_windows_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_windows_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_windows_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_windows_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_windows_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_windows_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_windows_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_windows_write(sock, ptr, len);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_WINDOWS) */\n"
  },
  {
    "path": "src/link/transport/tcp/tcp_zephyr.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ZEPHYR) && (Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_TLS == 1 || Z_FEATURE_LINK_WS == 1)\n\n#include <netdb.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <unistd.h>\n#include <zephyr/net/socket.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_tcp_zephyr_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct zsock_addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_tcp_zephyr_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    if ((ep == NULL) || (ep->_iptcp == NULL)) {\n        return;\n    }\n\n    freeaddrinfo(ep->_iptcp);\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_tcp_zephyr_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        z_time_t tv;\n        tv.tv_sec = tout / (uint32_t)1000;\n        tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            /* Zephyr may reject this option depending on the network stack configuration. */\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n        int optflag = 1;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&optflag, sizeof(optflag)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n\n#if LWIP_SO_LINGER == 1\n        struct linger ling;\n        ling.l_onoff = 1;\n        ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n#endif\n\n        for (struct zsock_addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n            if ((ret == _Z_RES_OK) && (connect(sock->_fd, it->ai_addr, it->ai_addrlen) < 0)) {\n                if (it->ai_next == NULL) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                    break;\n                }\n            } else {\n                break;\n            }\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_tcp_zephyr_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n    int optflag = 1;\n    if (setsockopt(sock->_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&optflag, sizeof(optflag)) < 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        close(sock->_fd);\n        sock->_fd = -1;\n        return _Z_ERR_GENERIC;\n    }\n#endif\n\n    for (struct zsock_addrinfo *it = endpoint._iptcp; it != NULL; it = it->ai_next) {\n        if (bind(sock->_fd, it->ai_addr, it->ai_addrlen) < 0) {\n            if (it->ai_next != NULL) {\n                continue;\n            }\n\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            break;\n        }\n\n        if (listen(sock->_fd, Z_LISTEN_MAX_CONNECTION_NB) < 0) {\n            if (it->ai_next != NULL) {\n                continue;\n            }\n\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            break;\n        }\n\n        return _Z_RES_OK;\n    }\n\n    close(sock->_fd);\n    sock->_fd = -1;\n    return _Z_ERR_GENERIC;\n}\n\nstatic z_result_t _z_tcp_zephyr_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    struct sockaddr naddr;\n    unsigned int nlen = sizeof(naddr);\n    sock_out->_fd = -1;\n    int con_socket = accept(sock_in->_fd, &naddr, &nlen);\n    if (con_socket < 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n#if Z_FEATURE_TCP_NODELAY == 1\n    int optflag = 1;\n    if (setsockopt(con_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&optflag, sizeof(optflag)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n#if LWIP_SO_LINGER == 1\n    struct linger ling;\n    ling.l_onoff = 1;\n    ling.l_linger = Z_TRANSPORT_LEASE / 1000;\n    if (setsockopt(con_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(struct linger)) < 0) {\n        close(con_socket);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n\n    sock_out->_fd = con_socket;\n    return _Z_RES_OK;\n}\n\nstatic void _z_tcp_zephyr_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_tcp_zephyr_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    ssize_t rb = recv(sock._fd, ptr, len, 0);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_tcp_zephyr_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_tcp_zephyr_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_tcp_zephyr_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return (size_t)send(sock._fd, ptr, len, 0);\n}\n\nz_result_t _z_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_tcp_zephyr_endpoint_init(ep, address, port);\n}\n\nvoid _z_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_zephyr_endpoint_clear(ep); }\n\nz_result_t _z_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_tcp_zephyr_open(sock, endpoint, tout);\n}\n\nz_result_t _z_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint) {\n    return _z_tcp_zephyr_listen(sock, endpoint);\n}\n\nz_result_t _z_tcp_accept(const _z_sys_net_socket_t *sock_in, _z_sys_net_socket_t *sock_out) {\n    return _z_tcp_zephyr_accept(sock_in, sock_out);\n}\n\nvoid _z_tcp_close(_z_sys_net_socket_t *sock) { _z_tcp_zephyr_close(sock); }\n\nsize_t _z_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { return _z_tcp_zephyr_read(sock, ptr, len); }\n\nsize_t _z_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_zephyr_read_exact(sock, ptr, len);\n}\n\nsize_t _z_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_zephyr_write(sock, ptr, len);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/address.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdlib.h>\n\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\nz_result_t _z_udp_unicast_address_valid(const _z_string_t *address) {\n    char *host = _z_endpoint_parse_host(address);\n    char *port = _z_endpoint_parse_port(address);\n    z_result_t ret = ((host != NULL) && (port != NULL)) ? _Z_RES_OK : _Z_ERR_CONFIG_LOCATOR_INVALID;\n\n    z_free(host);\n    z_free(port);\n    return ret;\n}\n\nz_result_t _z_udp_unicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    z_result_t ret = _Z_RES_OK;\n    char *host = _z_endpoint_parse_host(address);\n    char *port = _z_endpoint_parse_port(address);\n\n    if ((host == NULL) || (port == NULL)) {\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n    } else {\n        ret = _z_udp_unicast_endpoint_init(ep, host, port);\n    }\n\n    z_free(host);\n    z_free(port);\n    return ret;\n}\n"
  },
  {
    "path": "src/link/transport/udp/raweth_unix.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/raweth.h\"\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n\n#include <arpa/inet.h>\n#include <errno.h>\n#include <ifaddrs.h>\n#include <net/ethernet.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <netinet/in.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/system/platform/unix.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#if !defined(__linux)\n#error \"Raweth transport only supported on linux systems\"\n#else\n#include <linux/if_packet.h>\n\nvoid _z_raweth_clear_mapping_entry(_zp_raweth_mapping_entry_t *entry) { _z_string_clear(&entry->_keyexpr); }\n\nz_result_t _z_open_raweth(_z_sys_net_socket_t *sock, const char *interface) {\n    z_result_t ret = _Z_RES_OK;\n    // Open a raw network socket in promiscuous mode\n    sock->_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));\n    if (sock->_fd == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    // Get the index of the interface to send on\n    struct ifreq if_idx;\n    memset(&if_idx, 0, sizeof(struct ifreq));\n    strncpy(if_idx.ifr_name, interface, strlen(interface));\n    if (ioctl(sock->_fd, SIOCGIFINDEX, &if_idx) < 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    // Bind the socket\n    struct sockaddr_ll addr;\n    memset(&addr, 0, sizeof(addr));\n    addr.sll_family = AF_PACKET;\n    addr.sll_protocol = htons(ETH_P_ALL);\n    addr.sll_ifindex = if_idx.ifr_ifindex;\n    addr.sll_pkttype = PACKET_HOST | PACKET_BROADCAST | PACKET_MULTICAST;\n\n    if (bind(sock->_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {\n        close(sock->_fd);\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n    return ret;\n}\n\nz_result_t _z_close_raweth(_z_sys_net_socket_t *sock) {\n    z_result_t ret = _Z_RES_OK;\n    if (close(sock->_fd) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n    return ret;\n}\n\nsize_t _z_send_raweth(const _z_sys_net_socket_t *sock, const void *buff, size_t buff_len) {\n    // Send data\n    ssize_t wb = write(sock->_fd, buff, buff_len);\n    if (wb < 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)wb;\n}\n\nsize_t _z_receive_raweth(const _z_sys_net_socket_t *sock, void *buff, size_t buff_len, _z_slice_t *addr,\n                         const _zp_raweth_whitelist_array_t *whitelist) {\n    // Read from socket\n    ssize_t bytesRead = recvfrom(sock->_fd, buff, buff_len, 0, NULL, NULL);\n    if ((bytesRead <= 0) || (bytesRead < (ssize_t)sizeof(_zp_eth_header_t))) {\n        return SIZE_MAX;\n    }\n    bool is_valid = true;\n    // Address filtering (only if there is a whitelist)\n    if (_zp_raweth_whitelist_array_len(whitelist) > 0) {\n        is_valid = false;\n        const _zp_eth_header_t *header = (_zp_eth_header_t *)buff;\n        for (size_t i = 0; i < _zp_raweth_whitelist_array_len(whitelist); i++) {\n            const _zp_raweth_whitelist_entry_t *entry = _zp_raweth_whitelist_array_get(whitelist, i);\n            if (memcmp(&header->smac, entry->_mac, _ZP_MAC_ADDR_LENGTH) == 0) {\n                is_valid = true;\n                break;\n            }\n        }\n    }\n    // Ignore packet from unknown sources\n    if (!is_valid) {\n        return SIZE_MAX;\n    }\n    // Copy sender mac if needed\n    if (addr != NULL) {\n        uint8_t *header_addr = (uint8_t *)buff;\n        addr->len = sizeof(ETH_ALEN);\n        (void)memcpy((uint8_t *)addr->start, (header_addr + ETH_ALEN), sizeof(ETH_ALEN));\n    }\n    return (size_t)bytesRead;\n}\n\nuint16_t _z_raweth_ntohs(uint16_t val) { return ntohs(val); }\n\nuint16_t _z_raweth_htons(uint16_t val) { return htons(val); }\n\n#endif  // defined(__linux)\n#endif  // Z_FEATURE_RAWETH_TRANSPORT == 1\n"
  },
  {
    "path": "src/link/transport/udp/udp_esp32.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ESP32)\n\n#include <netdb.h>\n#include <stddef.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_esp32_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_DGRAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_UDP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_esp32_endpoint_clear(_z_sys_net_endpoint_t *ep) { freeaddrinfo(ep->_iptcp); }\n\nstatic z_result_t _z_udp_esp32_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        z_time_t tv;\n        tv.tv_sec = tout / (uint32_t)1000;\n        tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_esp32_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_udp_esp32_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_udp_esp32_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    struct sockaddr_storage raddr;\n    socklen_t addrlen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = recvfrom(sock._fd, ptr, len, 0, (struct sockaddr *)&raddr, &addrlen);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_esp32_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_esp32_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_esp32_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                 const _z_sys_net_endpoint_t endpoint) {\n    ssize_t wb = sendto(sock._fd, ptr, len, 0, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen);\n    if (wb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)wb;\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_esp32_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_esp32_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_esp32_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_esp32_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_esp32_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_esp32_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_esp32_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_esp32_write(sock, ptr, len, endpoint);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_ESP32) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_freertos_plus_tcp.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_FREERTOS_PLUS_TCP)\n\n#include <stdlib.h>\n\n#include \"FreeRTOS.h\"\n#include \"FreeRTOS_IP.h\"\n#include \"FreeRTOS_Sockets.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_freertos_plus_tcp_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address,\n                                                         const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (FreeRTOS_getaddrinfo(s_address, NULL, NULL, &ep->_iptcp) < 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n        return ret;\n    }\n\n    ep->_iptcp->ai_addr->sin_family = ep->_iptcp->ai_family;\n\n    uint32_t port = strtoul(s_port, NULL, 10);\n    if ((port > (uint32_t)0) && (port <= (uint32_t)65535)) {\n        ep->_iptcp->ai_addr->sin_port = FreeRTOS_htons((uint16_t)port);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_freertos_plus_tcp_endpoint_clear(_z_sys_net_endpoint_t *ep) { FreeRTOS_freeaddrinfo(ep->_iptcp); }\n\nstatic z_result_t _z_udp_freertos_plus_tcp_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint,\n                                                uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_socket = FreeRTOS_socket(endpoint._iptcp->ai_family, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP);\n    if (sock->_socket != FREERTOS_INVALID_SOCKET) {\n        TickType_t receive_timeout = pdMS_TO_TICKS(tout);\n\n        if (FreeRTOS_setsockopt(sock->_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, 0) != 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            FreeRTOS_closesocket(sock->_socket);\n            sock->_socket = FREERTOS_INVALID_SOCKET;\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_freertos_plus_tcp_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint,\n                                                  uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_socket = FreeRTOS_socket(endpoint._iptcp->ai_family, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP);\n    if (sock->_socket != FREERTOS_INVALID_SOCKET) {\n        TickType_t receive_timeout = pdMS_TO_TICKS(tout);\n\n        if (FreeRTOS_setsockopt(sock->_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, 0) != 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        } else if (FreeRTOS_bind(sock->_socket, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen) != 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            FreeRTOS_closesocket(sock->_socket);\n            sock->_socket = FREERTOS_INVALID_SOCKET;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_freertos_plus_tcp_close(_z_sys_net_socket_t *sock) {\n    if (sock->_socket != FREERTOS_INVALID_SOCKET) {\n        FreeRTOS_closesocket(sock->_socket);\n        sock->_socket = FREERTOS_INVALID_SOCKET;\n    }\n}\n\nstatic size_t _z_udp_freertos_plus_tcp_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    struct freertos_sockaddr raddr;\n    uint32_t addrlen = sizeof(struct freertos_sockaddr);\n\n    int32_t rb = FreeRTOS_recvfrom(sock._socket, ptr, len, 0, &raddr, &addrlen);\n    if (rb < 0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_freertos_plus_tcp_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_freertos_plus_tcp_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_freertos_plus_tcp_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                             const _z_sys_net_endpoint_t endpoint) {\n    return (size_t)FreeRTOS_sendto(sock._socket, ptr, len, 0, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_freertos_plus_tcp_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_freertos_plus_tcp_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_freertos_plus_tcp_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_freertos_plus_tcp_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_freertos_plus_tcp_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_freertos_plus_tcp_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_freertos_plus_tcp_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_freertos_plus_tcp_write(sock, ptr, len, endpoint);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_FREERTOS_PLUS_TCP) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_lwip.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP) && (Z_FEATURE_LINK_UDP_UNICAST == 1)\n\n#include <stddef.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"lwip/netdb.h\"\n#include \"lwip/sockets.h\"\n#include \"zenoh-pico/link/transport/lwip_socket.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_lwip_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_DGRAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_UDP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    } else if (ep->_iptcp != NULL && ep->_iptcp->ai_addr != NULL) {\n        ep->_iptcp->ai_addr->sa_family = ep->_iptcp->ai_family;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_lwip_endpoint_clear(_z_sys_net_endpoint_t *ep) { freeaddrinfo(ep->_iptcp); }\n\nstatic z_result_t _z_udp_lwip_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_lwip_socket_set(sock,\n                       socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol));\n    if (_z_lwip_socket_get(*sock) != -1) {\n        z_time_t tv;\n        tv.tv_sec = tout / (uint32_t)1000;\n        tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(_z_lwip_socket_get(*sock));\n            _z_lwip_socket_set(sock, -1);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_lwip_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_udp_lwip_close(_z_sys_net_socket_t *sock) {\n    if (_z_lwip_socket_get(*sock) >= 0) {\n        close(_z_lwip_socket_get(*sock));\n        _z_lwip_socket_set(sock, -1);\n    }\n}\n\nstatic size_t _z_udp_lwip_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    struct sockaddr_storage raddr;\n    unsigned int addrlen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = recvfrom(_z_lwip_socket_get(sock), ptr, len, 0, (struct sockaddr *)&raddr, &addrlen);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_lwip_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_lwip_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, (ptrdiff_t)rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_lwip_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                const _z_sys_net_endpoint_t endpoint) {\n    return (size_t)sendto(_z_lwip_socket_get(sock), ptr, len, 0, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_lwip_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_lwip_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_lwip_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_lwip_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_lwip_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_lwip_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_lwip_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_lwip_write(sock, ptr, len, endpoint);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_LWIP) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_mbed.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_MBED)\n\n#include <NetworkInterface.h>\n#include <mbed.h>\n\nextern \"C\" {\n#include <stddef.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_mbed_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    uint32_t port = strtoul(s_port, NULL, 10);\n    if ((port == 0U) || (port > 65535U)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    ep->_iptcp = new SocketAddress(s_address, port);\n    if (ep->_iptcp == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic void _z_udp_mbed_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    delete ep->_iptcp;\n    ep->_iptcp = NULL;\n}\n\nstatic z_result_t _z_udp_mbed_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(endpoint);\n    NetworkInterface *iface = NetworkInterface::get_default_instance();\n    if (iface == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_udp = new UDPSocket();\n    if (sock->_udp == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    sock->_udp->set_timeout((int)tout);\n    // flawfinder: ignore\n    if (sock->_udp->open(iface) < 0) {\n        delete sock->_udp;\n        sock->_udp = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_udp_mbed_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nstatic void _z_udp_mbed_close(_z_sys_net_socket_t *sock) {\n    if (sock->_udp != NULL) {\n        sock->_udp->close();\n        delete sock->_udp;\n        sock->_udp = NULL;\n    }\n}\n\nstatic size_t _z_udp_mbed_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    SocketAddress raddr;\n    nsapi_size_or_error_t rb = sock._udp->recvfrom(&raddr, ptr, len);\n    if (rb < 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_mbed_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_mbed_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_mbed_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                const _z_sys_net_endpoint_t endpoint) {\n    nsapi_size_or_error_t wb = sock._udp->sendto(*endpoint._iptcp, ptr, len);\n    if (wb < 0) {\n        return SIZE_MAX;\n    }\n    return (size_t)wb;\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_mbed_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_mbed_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_mbed_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_mbed_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_mbed_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_mbed_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_mbed_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_mbed_write(sock, ptr, len, endpoint);\n}\n}  // extern \"C\"\n\n#endif /* defined(ZP_PLATFORM_SOCKET_MBED) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_esp32.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ESP32) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <netdb.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic unsigned int _z_esp32_udp_multicast_ipv6_outbound_ifindex(void) {\n    // TODO: route this through platform/socket support once esp32 multicast iface selection is explicit.\n    return 0U;\n}\n\nstatic unsigned int _z_esp32_udp_multicast_ipv6_membership_ifindex(void) {\n    // TODO: route this through platform/socket support once esp32 multicast iface selection is explicit.\n    return 1U;\n}\n\nstatic z_result_t _z_esp32_udp_multicast_make_local_addr(int family, in_port_t port, struct sockaddr **lsockaddr,\n                                                         socklen_t *addrlen) {\n    z_result_t ret = _Z_RES_OK;\n\n    *lsockaddr = NULL;\n    *addrlen = 0;\n    if (family == AF_INET) {\n        *lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in));\n        if (*lsockaddr != NULL) {\n            (void)memset(*lsockaddr, 0, sizeof(struct sockaddr_in));\n            *addrlen = sizeof(struct sockaddr_in);\n\n            struct sockaddr_in *c_laddr = (struct sockaddr_in *)*lsockaddr;\n            c_laddr->sin_family = AF_INET;\n            c_laddr->sin_addr.s_addr = INADDR_ANY;\n            c_laddr->sin_port = port;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else if (family == AF_INET6) {\n        *lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in6));\n        if (*lsockaddr != NULL) {\n            (void)memset(*lsockaddr, 0, sizeof(struct sockaddr_in6));\n            *addrlen = sizeof(struct sockaddr_in6);\n\n            struct sockaddr_in6 *c_laddr = (struct sockaddr_in6 *)*lsockaddr;\n            c_laddr->sin6_family = AF_INET6;\n            c_laddr->sin6_addr = in6addr_any;\n            c_laddr->sin6_port = port;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_esp32_udp_multicast_configure_outbound_iface(int fd, const struct sockaddr *lsockaddr) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (lsockaddr->sa_family == AF_INET) {\n        if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &((const struct sockaddr_in *)lsockaddr)->sin_addr,\n                       sizeof(struct in_addr)) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else if (lsockaddr->sa_family == AF_INET6) {\n        unsigned int ifindex = _z_esp32_udp_multicast_ipv6_outbound_ifindex();\n        if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_esp32_udp_multicast_apply_membership(int fd, int family, int option, const void *addr_bytes) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (family == AF_INET) {\n        struct ip_mreq mreq;\n        (void)memset(&mreq, 0, sizeof(mreq));\n        // flawfinder: ignore\n        (void)memcpy(&mreq.imr_multiaddr, addr_bytes, sizeof(struct in_addr));\n        mreq.imr_interface.s_addr = htonl(INADDR_ANY);\n        if (setsockopt(fd, IPPROTO_IP, option, &mreq, sizeof(mreq)) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else if (family == AF_INET6) {\n        struct ipv6_mreq mreq;\n        (void)memset(&mreq, 0, sizeof(mreq));\n        // flawfinder: ignore\n        (void)memcpy(&mreq.ipv6mr_multiaddr, addr_bytes, sizeof(struct in6_addr));\n        mreq.ipv6mr_interface = _z_esp32_udp_multicast_ipv6_membership_ifindex();\n        if (setsockopt(fd, IPPROTO_IPV6, option, &mreq, sizeof(mreq)) < 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_esp32_udp_multicast_apply_primary_membership(int fd, const _z_sys_net_endpoint_t rep, int option) {\n    if (rep._iptcp->ai_family == AF_INET) {\n        return _z_esp32_udp_multicast_apply_membership(fd, rep._iptcp->ai_family, option,\n                                                       &((const struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr);\n    }\n    if (rep._iptcp->ai_family == AF_INET6) {\n        return _z_esp32_udp_multicast_apply_membership(fd, rep._iptcp->ai_family, option,\n                                                       &((const struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_addr);\n    }\n\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nz_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    _ZP_UNUSED(iface);\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    socklen_t addrlen = 0;\n    ret = _z_esp32_udp_multicast_make_local_addr(rep._iptcp->ai_family, 0, &lsockaddr, &addrlen);\n    if ((ret == _Z_RES_OK) && (addrlen != 0U)) {\n        sock->_fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n        if (sock->_fd != -1) {\n            z_time_t tv;\n            tv.tv_sec = tout / (uint32_t)1000;\n            tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (bind(sock->_fd, lsockaddr, addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (getsockname(sock->_fd, lsockaddr, &addrlen) == -1)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (ret == _Z_RES_OK) {\n                ret = _z_esp32_udp_multicast_configure_outbound_iface(sock->_fd, lsockaddr);\n            }\n\n            if (ret != _Z_RES_OK) {\n                close(sock->_fd);\n                sock->_fd = -1;\n                z_free(lsockaddr);\n                return ret;\n            }\n\n            struct addrinfo *laddr = (struct addrinfo *)z_malloc(sizeof(struct addrinfo));\n            if (laddr == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                close(sock->_fd);\n                sock->_fd = -1;\n                z_free(lsockaddr);\n                return _Z_ERR_GENERIC;\n            }\n\n            laddr->ai_flags = 0;\n            laddr->ai_family = rep._iptcp->ai_family;\n            laddr->ai_socktype = rep._iptcp->ai_socktype;\n            laddr->ai_protocol = rep._iptcp->ai_protocol;\n            laddr->ai_addrlen = addrlen;\n            laddr->ai_addr = lsockaddr;\n            laddr->ai_canonname = NULL;\n            laddr->ai_next = NULL;\n            lep->_iptcp = laddr;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            z_free(lsockaddr);\n        }\n    } else if (ret == _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    _ZP_UNUSED(iface);\n    (void)join;\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    socklen_t addrlen = 0;\n    if (rep._iptcp->ai_family == AF_INET) {\n        ret = _z_esp32_udp_multicast_make_local_addr(\n            rep._iptcp->ai_family, ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_port, &lsockaddr, &addrlen);\n    } else if (rep._iptcp->ai_family == AF_INET6) {\n        ret = _z_esp32_udp_multicast_make_local_addr(\n            rep._iptcp->ai_family, ((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_port, &lsockaddr, &addrlen);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if ((ret == _Z_RES_OK) && (addrlen != 0U)) {\n        sock->_fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n        if (sock->_fd != -1) {\n            z_time_t tv;\n            tv.tv_sec = tout / (uint32_t)1000;\n            tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            int optflag = 1;\n            if ((ret == _Z_RES_OK) &&\n                (setsockopt(sock->_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optflag, sizeof(optflag)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (bind(sock->_fd, lsockaddr, addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (ret == _Z_RES_OK) {\n                if (rep._iptcp->ai_family == AF_INET) {\n                    ret = _z_esp32_udp_multicast_apply_primary_membership(sock->_fd, rep, IP_ADD_MEMBERSHIP);\n                } else if (rep._iptcp->ai_family == AF_INET6) {\n                    ret = _z_esp32_udp_multicast_apply_primary_membership(sock->_fd, rep, IPV6_JOIN_GROUP);\n                } else {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            }\n\n            if (ret != _Z_RES_OK) {\n                close(sock->_fd);\n                sock->_fd = -1;\n            }\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        z_free(lsockaddr);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nvoid _z_close_udp_multicast(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _ZP_UNUSED(lep);\n    if (sockrecv->_fd >= 0) {\n        if (rep._iptcp->ai_family == AF_INET) {\n            (void)_z_esp32_udp_multicast_apply_primary_membership(sockrecv->_fd, rep, IP_DROP_MEMBERSHIP);\n        } else if (rep._iptcp->ai_family == AF_INET6) {\n            (void)_z_esp32_udp_multicast_apply_primary_membership(sockrecv->_fd, rep, IPV6_LEAVE_GROUP);\n        }\n    }\n\n    if (sockrecv->_fd >= 0) {\n        close(sockrecv->_fd);\n        sockrecv->_fd = -1;\n    }\n    if (socksend->_fd >= 0) {\n        close(socksend->_fd);\n        socksend->_fd = -1;\n    }\n}\n\nsize_t _z_read_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *addr) {\n    struct sockaddr_storage raddr;\n    socklen_t raddrlen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = 0;\n    do {\n        rb = recvfrom(sock._fd, ptr, len, 0, (struct sockaddr *)&raddr, &raddrlen);\n        if (rb < (ssize_t)0) {\n            rb = SIZE_MAX;\n            break;\n        }\n\n        if (lep._iptcp->ai_family == AF_INET) {\n            struct sockaddr_in *a = ((struct sockaddr_in *)lep._iptcp->ai_addr);\n            struct sockaddr_in *b = ((struct sockaddr_in *)&raddr);\n            if (!((a->sin_port == b->sin_port) && (a->sin_addr.s_addr == b->sin_addr.s_addr))) {\n                if (addr != NULL) {\n                    addr->len = sizeof(in_addr_t) + sizeof(in_port_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin_addr.s_addr, sizeof(in_addr_t));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(in_addr_t)), &b->sin_port, sizeof(in_port_t));\n                }\n                break;\n            }\n        } else if (lep._iptcp->ai_family == AF_INET6) {\n            struct sockaddr_in6 *a = ((struct sockaddr_in6 *)lep._iptcp->ai_addr);\n            struct sockaddr_in6 *b = ((struct sockaddr_in6 *)&raddr);\n            if ((a->sin6_port != b->sin6_port) ||\n                (memcmp(&a->sin6_addr, &b->sin6_addr, sizeof(struct in6_addr)) != 0)) {\n                if (addr != NULL) {\n                    addr->len = sizeof(struct in6_addr) + sizeof(in_port_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin6_addr.s6_addr, sizeof(struct in6_addr));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(struct in6_addr)), &b->sin6_port, sizeof(in_port_t));\n                }\n                break;\n            }\n        } else {\n            continue;\n        }\n    } while (1);\n\n    return rb;\n}\n\nsize_t _z_read_exact_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_udp_multicast(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_udp_multicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                             const _z_sys_net_endpoint_t rep) {\n    return sendto(sock._fd, ptr, len, 0, rep._iptcp->ai_addr, rep._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_close_udp_multicast(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_read_exact_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_read_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_send_udp_multicast(sock, ptr, len, rep);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_lwip.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#if defined(ZENOH_FREERTOS_LWIP) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <string.h>\n\n#include \"lwip/ip4_addr.h\"\n#include \"lwip/netdb.h\"\n#include \"lwip/netif.h\"\n#include \"udp_multicast_lwip_common.h\"\n\nstatic unsigned long __get_ip_from_iface(const char *iface, int sa_family, struct sockaddr **lsockaddr) {\n    unsigned int addrlen = 0U;\n    _ZP_UNUSED(sa_family);\n\n    struct netif *netif = netif_find(iface);\n    if (netif == NULL || !netif_is_up(netif)) {\n        return 0;\n    }\n\n    struct sockaddr_in *lsockaddr_in = (struct sockaddr_in *)z_malloc(sizeof(struct sockaddr_in));\n    if (lsockaddr_in == NULL) {\n        return 0;\n    }\n    (void)memset(lsockaddr_in, 0, sizeof(struct sockaddr_in));\n    const ip4_addr_t *ip4_addr = netif_ip4_addr(netif);\n    inet_addr_from_ip4addr(&lsockaddr_in->sin_addr, ip_2_ip4(ip4_addr));\n    lsockaddr_in->sin_family = AF_INET;\n    lsockaddr_in->sin_port = htons(0);\n\n    addrlen = sizeof(struct sockaddr_in);\n    *lsockaddr = (struct sockaddr *)lsockaddr_in;\n\n    return addrlen;\n}\n\nstatic z_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep,\n                                        _z_sys_net_endpoint_t *lep, uint32_t tout, const char *iface) {\n    return _z_lwip_udp_multicast_open(sock, rep, lep, tout, iface, __get_ip_from_iface);\n}\n\nstatic z_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                          const char *iface, const char *join) {\n    return _z_lwip_udp_multicast_listen(sock, rep, tout, iface, join, __get_ip_from_iface);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_lwip_udp_multicast_close(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_lwip_udp_multicast_read_exact(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_lwip_udp_multicast_read(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_lwip_udp_multicast_write(sock, ptr, len, rep);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_lwip_common.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"udp_multicast_lwip_common.h\"\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <string.h>\n\n#include \"lwip/netdb.h\"\n#include \"lwip/sockets.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/link/transport/lwip_socket.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_lwip_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep,\n                                      _z_sys_net_endpoint_t *lep, uint32_t tout, const char *iface,\n                                      _z_lwip_udp_multicast_iface_addr_fn get_ip_from_iface) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    unsigned long addrlen = get_ip_from_iface(iface, rep._iptcp->ai_family, &lsockaddr);\n    if (addrlen != 0U) {\n        _z_lwip_socket_set(sock, socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol));\n        if (_z_lwip_socket_get(*sock) != -1) {\n            z_time_t tv;\n            tv.tv_sec = tout / (uint32_t)1000;\n            tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n            if ((ret == _Z_RES_OK) &&\n                (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (bind(_z_lwip_socket_get(*sock), lsockaddr, addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (getsockname(_z_lwip_socket_get(*sock), lsockaddr, &addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (ret != _Z_RES_OK) {\n                close(_z_lwip_socket_get(*sock));\n                _z_lwip_socket_set(sock, -1);\n                z_free(lsockaddr);\n                return ret;\n            }\n\n            struct addrinfo *laddr = (struct addrinfo *)z_malloc(sizeof(struct addrinfo));\n            if (laddr == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                close(_z_lwip_socket_get(*sock));\n                _z_lwip_socket_set(sock, -1);\n                z_free(lsockaddr);\n                return _Z_ERR_GENERIC;\n            }\n\n            laddr->ai_flags = 0;\n            laddr->ai_family = rep._iptcp->ai_family;\n            laddr->ai_socktype = rep._iptcp->ai_socktype;\n            laddr->ai_protocol = rep._iptcp->ai_protocol;\n            laddr->ai_addrlen = addrlen;\n            laddr->ai_addr = lsockaddr;\n            laddr->ai_canonname = NULL;\n            laddr->ai_next = NULL;\n            lep->_iptcp = laddr;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            z_free(lsockaddr);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nz_result_t _z_lwip_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                        const char *iface, const char *join,\n                                        _z_lwip_udp_multicast_iface_addr_fn get_ip_from_iface) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    unsigned int addrlen = get_ip_from_iface(iface, rep._iptcp->ai_family, &lsockaddr);\n    if (addrlen != 0U) {\n        _z_lwip_socket_set(sock, socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol));\n        if (_z_lwip_socket_get(*sock) != -1) {\n            z_time_t tv;\n            tv.tv_sec = tout / (uint32_t)1000;\n            tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n            if ((ret == _Z_RES_OK) &&\n                (setsockopt(_z_lwip_socket_get(*sock), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._iptcp->ai_family == AF_INET) {\n                struct sockaddr_in address;\n                (void)memset(&address, 0, sizeof(address));\n                address.sin_family = (sa_family_t)rep._iptcp->ai_family;\n                address.sin_port = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_port;\n                inet_pton(address.sin_family, \"0.0.0.0\", &address.sin_addr);\n                if ((ret == _Z_RES_OK) &&\n                    (bind(_z_lwip_socket_get(*sock), (struct sockaddr *)&address, sizeof(address)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._iptcp->ai_family == AF_INET) {\n                struct ip_mreq mreq;\n                (void)memset(&mreq, 0, sizeof(mreq));\n                mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr.s_addr;\n                mreq.imr_interface.s_addr = ((struct sockaddr_in *)lsockaddr)->sin_addr.s_addr;\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(_z_lwip_socket_get(*sock), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (join != NULL) {\n                char *joins = _z_str_clone(join);\n                char *joins_cursor = joins;\n                for (char *ip = strsep(&joins_cursor, \"|\"); ip != NULL; ip = strsep(&joins_cursor, \"|\")) {\n                    if (rep._iptcp->ai_family == AF_INET) {\n                        struct ip_mreq mreq;\n                        (void)memset(&mreq, 0, sizeof(mreq));\n                        inet_pton(rep._iptcp->ai_family, ip, &mreq.imr_multiaddr);\n                        mreq.imr_interface.s_addr = ((struct sockaddr_in *)lsockaddr)->sin_addr.s_addr;\n                        if ((ret == _Z_RES_OK) && (setsockopt(_z_lwip_socket_get(*sock), IPPROTO_IP, IP_ADD_MEMBERSHIP,\n                                                              &mreq, sizeof(mreq)) < 0)) {\n                            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                            ret = _Z_ERR_GENERIC;\n                        }\n                    }\n                }\n                z_free(joins);\n            }\n\n            if (ret != _Z_RES_OK) {\n                close(_z_lwip_socket_get(*sock));\n                _z_lwip_socket_set(sock, -1);\n            }\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        z_free(lsockaddr);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nvoid _z_lwip_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                                 const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    if (_z_lwip_socket_get(*sockrecv) >= 0) {\n        if (rep._iptcp->ai_family == AF_INET) {\n            struct ip_mreq mreq;\n            (void)memset(&mreq, 0, sizeof(mreq));\n            mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr.s_addr;\n            mreq.imr_interface.s_addr = htonl(INADDR_ANY);\n            setsockopt(_z_lwip_socket_get(*sockrecv), IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));\n        }\n    }\n    _ZP_UNUSED(lep);\n\n    if (_z_lwip_socket_get(*sockrecv) >= 0) {\n        close(_z_lwip_socket_get(*sockrecv));\n        _z_lwip_socket_set(sockrecv, -1);\n    }\n    if (_z_lwip_socket_get(*socksend) >= 0) {\n        close(_z_lwip_socket_get(*socksend));\n        _z_lwip_socket_set(socksend, -1);\n    }\n}\n\nsize_t _z_lwip_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                  const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    struct sockaddr_storage raddr;\n    unsigned long replen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = 0;\n    do {\n        rb = recvfrom(_z_lwip_socket_get(sock), ptr, len, 0, (struct sockaddr *)&raddr, &replen);\n        if (rb < (ssize_t)0) {\n            return SIZE_MAX;\n        }\n\n        if (lep._iptcp->ai_family == AF_INET) {\n            struct sockaddr_in *a = ((struct sockaddr_in *)lep._iptcp->ai_addr);\n            struct sockaddr_in *b = ((struct sockaddr_in *)&raddr);\n            if (!((a->sin_port == b->sin_port) && (a->sin_addr.s_addr == b->sin_addr.s_addr))) {\n                if (addr != NULL) {\n                    addr->len = sizeof(in_addr_t) + sizeof(in_port_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin_addr.s_addr, sizeof(in_addr_t));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(in_addr_t)), &b->sin_port, sizeof(in_port_t));\n                }\n                break;\n            }\n        } else {\n            continue;\n        }\n    } while (1);\n\n    return (size_t)rb;\n}\n\nsize_t _z_lwip_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                        const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_lwip_udp_multicast_read(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, (ptrdiff_t)rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_lwip_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t rep) {\n    return (size_t)sendto(_z_lwip_socket_get(sock), ptr, len, 0, rep._iptcp->ai_addr, rep._iptcp->ai_addrlen);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_LWIP) && (Z_FEATURE_LINK_UDP_MULTICAST == 1) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_lwip_common.h",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZENOH_PICO_LINK_TRANSPORT_DATAGRAM_UDP_MULTICAST_LWIP_COMMON_H\n#define ZENOH_PICO_LINK_TRANSPORT_DATAGRAM_UDP_MULTICAST_LWIP_COMMON_H\n\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef unsigned long (*_z_lwip_udp_multicast_iface_addr_fn)(const char *iface, int sa_family,\n                                                             struct sockaddr **lsockaddr);\n\nz_result_t _z_lwip_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep,\n                                      _z_sys_net_endpoint_t *lep, uint32_t tout, const char *iface,\n                                      _z_lwip_udp_multicast_iface_addr_fn get_ip_from_iface);\n\nz_result_t _z_lwip_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                        const char *iface, const char *join,\n                                        _z_lwip_udp_multicast_iface_addr_fn get_ip_from_iface);\n\nvoid _z_lwip_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                                 const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep);\n\nsize_t _z_lwip_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                  const _z_sys_net_endpoint_t lep, _z_slice_t *addr);\n\nsize_t _z_lwip_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                        const _z_sys_net_endpoint_t lep, _z_slice_t *addr);\n\nsize_t _z_lwip_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t rep);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZENOH_PICO_LINK_TRANSPORT_DATAGRAM_UDP_MULTICAST_LWIP_COMMON_H */\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_mbed.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_MBED) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <NetworkInterface.h>\n#include <mbed.h>\n\nextern \"C\" {\n#include <string.h>\n\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    z_result_t ret = _Z_RES_OK;\n    _ZP_UNUSED(rep);\n    (void)(lep);\n    (void)(iface);\n\n    sock->_udp = new UDPSocket();\n    sock->_udp->set_timeout(tout);\n    // flawfinder: ignore\n    if ((ret == _Z_RES_OK) && (sock->_udp->open(NetworkInterface::get_default_instance()) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        delete sock->_udp;\n        sock->_udp = NULL;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    (void)iface;\n    (void)join;\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_udp = new UDPSocket();\n    sock->_udp->set_timeout(tout);\n    // flawfinder: ignore\n    if ((ret == _Z_RES_OK) && (sock->_udp->open(NetworkInterface::get_default_instance()) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if ((ret == _Z_RES_OK) && (sock->_udp->bind(rep._iptcp->get_port()) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if ((ret == _Z_RES_OK) && (sock->_udp->join_multicast_group(*rep._iptcp) < 0)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        sock->_udp->close();\n        delete sock->_udp;\n        sock->_udp = NULL;\n    }\n\n    return ret;\n}\n\nvoid _z_close_udp_multicast(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _ZP_UNUSED(lep);\n    if (sockrecv->_udp != NULL) {\n        sockrecv->_udp->leave_multicast_group(*rep._iptcp);\n        sockrecv->_udp->close();\n        delete sockrecv->_udp;\n        sockrecv->_udp = NULL;\n    }\n\n    if (socksend->_udp != NULL) {\n        socksend->_udp->close();\n        delete socksend->_udp;\n        socksend->_udp = NULL;\n    }\n}\n\nsize_t _z_read_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *addr) {\n    _ZP_UNUSED(lep);\n    SocketAddress raddr;\n    nsapi_size_or_error_t rb = 0;\n\n    do {\n        rb = sock._udp->recvfrom(&raddr, ptr, len);\n        if (rb < (nsapi_size_or_error_t)0) {\n            rb = SIZE_MAX;\n            break;\n        }\n\n        if (raddr.get_ip_version() == NSAPI_IPv4) {\n            addr->len = NSAPI_IPv4_BYTES + sizeof(uint16_t);\n            // flawfinder: ignore\n            (void)memcpy(const_cast<uint8_t *>(addr->start), raddr.get_ip_bytes(), NSAPI_IPv4_BYTES);\n            uint16_t port = raddr.get_port();\n            // flawfinder: ignore\n            (void)memcpy(const_cast<uint8_t *>(addr->start + NSAPI_IPv4_BYTES), &port, sizeof(uint16_t));\n            break;\n        } else if (raddr.get_ip_version() == NSAPI_IPv6) {\n            addr->len = NSAPI_IPv6_BYTES + sizeof(uint16_t);\n            // flawfinder: ignore\n            (void)memcpy(const_cast<uint8_t *>(addr->start), raddr.get_ip_bytes(), NSAPI_IPv6_BYTES);\n            uint16_t port = raddr.get_port();\n            // flawfinder: ignore\n            (void)memcpy(const_cast<uint8_t *>(addr->start + NSAPI_IPv6_BYTES), &port, sizeof(uint16_t));\n            break;\n        } else {\n            continue;\n        }\n    } while (1);\n\n    return rb;\n}\n\nsize_t _z_read_exact_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_udp_multicast(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_udp_multicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                             const _z_sys_net_endpoint_t rep) {\n    return sock._udp->sendto(*rep._iptcp, ptr, len);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_close_udp_multicast(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_read_exact_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_read_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_send_udp_multicast(sock, ptr, len, rep);\n}\n\n}  // extern \"C\"\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_opencr.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_OPENCR) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <Arduino.h>\n#include <WiFiClient.h>\n#include <WiFiUdp.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n\nextern \"C\" {\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    z_result_t ret = _Z_RES_OK;\n    (void)(rep);\n    (void)(tout);\n    (void)(iface);\n\n    sock->_udp = new WiFiUDP();\n    if (!sock->_udp->begin(55555)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    lep->_iptcp._addr = new IPAddress();\n\n    if (ret != _Z_RES_OK) {\n        delete sock->_udp;\n        sock->_udp = NULL;\n        delete lep->_iptcp._addr;\n        lep->_iptcp._addr = NULL;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    (void)tout;\n    (void)iface;\n    (void)join;\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_udp = new WiFiUDP();\n    if (!sock->_udp->beginMulticast(*rep._iptcp._addr, rep._iptcp._port)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        delete sock->_udp;\n        sock->_udp = NULL;\n    }\n\n    return ret;\n}\n\nvoid _z_close_udp_multicast(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _ZP_UNUSED(rep);\n    _ZP_UNUSED(lep);\n\n    if (sockrecv->_udp != NULL) {\n        sockrecv->_udp->stop();\n        delete sockrecv->_udp;\n        sockrecv->_udp = NULL;\n    }\n\n    if (socksend->_udp != NULL) {\n        socksend->_udp->stop();\n        delete socksend->_udp;\n        socksend->_udp = NULL;\n    }\n}\n\nsize_t _z_read_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *addr) {\n    _ZP_UNUSED(lep);\n    ssize_t rb = 0;\n    do {\n        rb = sock._udp->parsePacket();\n    } while (rb == 0);\n\n    if (rb <= (ssize_t)len) {\n        // flawfinder: ignore\n        if (sock._udp->read(ptr, rb) == rb) {\n            if (addr != NULL) {\n                IPAddress rip = sock._udp->remoteIP();\n                uint16_t rport = sock._udp->remotePort();\n                addr->len = 4U + sizeof(uint16_t);\n\n                uint8_t *dst = const_cast<uint8_t *>(addr->start);\n                dst[0] = rip[0];\n                dst[1] = rip[1];\n                dst[2] = rip[2];\n                dst[3] = rip[3];\n\n                const uint8_t *port_bytes = (const uint8_t *)&rport;\n                dst[4] = port_bytes[0];\n                dst[5] = port_bytes[1];\n            }\n        } else {\n            rb = 0;\n        }\n    }\n\n    return rb;\n}\n\nsize_t _z_read_exact_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_udp_multicast(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_udp_multicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                             const _z_sys_net_endpoint_t rep) {\n    sock._udp->beginPacket(*rep._iptcp._addr, rep._iptcp._port);\n    sock._udp->write(ptr, len);\n    sock._udp->endPacket();\n\n    return len;\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_close_udp_multicast(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_read_exact_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_read_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_send_udp_multicast(sock, ptr, len, rep);\n}\n\n}  // extern \"C\"\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_posix.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_POSIX) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <arpa/inet.h>\n#include <assert.h>\n#include <ifaddrs.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <netinet/in.h>\n#include <string.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic unsigned int __get_ip_from_iface(const char *iface, int sa_family, struct sockaddr **lsockaddr) {\n    unsigned int addrlen = 0U;\n\n    struct ifaddrs *l_ifaddr = NULL;\n    if (getifaddrs(&l_ifaddr) != -1) {\n        struct ifaddrs *tmp = NULL;\n        for (tmp = l_ifaddr; tmp != NULL; tmp = tmp->ifa_next) {\n            if (_z_str_eq(tmp->ifa_name, iface) == true) {\n                if (tmp->ifa_addr->sa_family == sa_family) {\n                    if (tmp->ifa_addr->sa_family == AF_INET) {\n                        *lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in));\n                        if (lsockaddr != NULL) {\n                            (void)memset(*lsockaddr, 0, sizeof(struct sockaddr_in));\n                            // flawfinder: ignore\n                            (void)memcpy(*lsockaddr, tmp->ifa_addr, sizeof(struct sockaddr_in));\n                            addrlen = sizeof(struct sockaddr_in);\n                        }\n                    } else if (tmp->ifa_addr->sa_family == AF_INET6) {\n                        *lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in6));\n                        if (lsockaddr != NULL) {\n                            (void)memset(*lsockaddr, 0, sizeof(struct sockaddr_in6));\n                            // flawfinder: ignore\n                            (void)memcpy(*lsockaddr, tmp->ifa_addr, sizeof(struct sockaddr_in6));\n                            addrlen = sizeof(struct sockaddr_in6);\n                        }\n                    } else {\n                        continue;\n                    }\n\n                    break;\n                }\n            }\n        }\n        freeifaddrs(l_ifaddr);\n    }\n\n    return addrlen;\n}\n\nz_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    unsigned int addrlen = __get_ip_from_iface(iface, rep._iptcp->ai_family, &lsockaddr);\n    if (addrlen != 0U) {\n        sock->_fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n        if (sock->_fd != -1) {\n            z_time_t tv;\n            tv.tv_sec = (time_t)(tout / (uint32_t)1000);\n            tv.tv_usec = (suseconds_t)((tout % (uint32_t)1000) * (uint32_t)1000);\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (bind(sock->_fd, lsockaddr, addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (getsockname(sock->_fd, lsockaddr, &addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n#ifndef UNIX_NO_MULTICAST_IF\n            if (lsockaddr->sa_family == AF_INET) {\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(sock->_fd, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in *)lsockaddr)->sin_addr,\n                                sizeof(struct in_addr)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (lsockaddr->sa_family == AF_INET6) {\n                int ifindex = (int)if_nametoindex(iface);\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(sock->_fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n#endif\n\n            if (ret != _Z_RES_OK) {\n                close(sock->_fd);\n                sock->_fd = -1;\n                z_free(lsockaddr);\n                return ret;\n            }\n\n            struct addrinfo *laddr = (struct addrinfo *)z_malloc(sizeof(struct addrinfo));\n            if (laddr == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                close(sock->_fd);\n                sock->_fd = -1;\n                z_free(lsockaddr);\n                return _Z_ERR_GENERIC;\n            }\n\n            laddr->ai_flags = 0;\n            laddr->ai_family = rep._iptcp->ai_family;\n            laddr->ai_socktype = rep._iptcp->ai_socktype;\n            laddr->ai_protocol = rep._iptcp->ai_protocol;\n            laddr->ai_addrlen = addrlen;\n            laddr->ai_addr = lsockaddr;\n            laddr->ai_canonname = NULL;\n            laddr->ai_next = NULL;\n            lep->_iptcp = laddr;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            z_free(lsockaddr);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    unsigned int addrlen = __get_ip_from_iface(iface, rep._iptcp->ai_family, &lsockaddr);\n    if (addrlen != 0U) {\n        sock->_fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n        if (sock->_fd != -1) {\n            z_time_t tv;\n            tv.tv_sec = (time_t)(tout / (uint32_t)1000);\n            tv.tv_usec = (suseconds_t)((tout % (uint32_t)1000) * (uint32_t)1000);\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            int value = true;\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n#ifdef SO_REUSEPORT\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n#endif\n\n            if (rep._iptcp->ai_family == AF_INET) {\n                struct sockaddr_in address;\n                (void)memset(&address, 0, sizeof(address));\n                address.sin_family = (sa_family_t)rep._iptcp->ai_family;\n                address.sin_port = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_port;\n                inet_pton(address.sin_family, \"0.0.0.0\", &address.sin_addr);\n                if ((ret == _Z_RES_OK) && (bind(sock->_fd, (struct sockaddr *)&address, sizeof(address)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (rep._iptcp->ai_family == AF_INET6) {\n                struct sockaddr_in6 address;\n                (void)memset(&address, 0, sizeof(address));\n                address.sin6_family = (sa_family_t)rep._iptcp->ai_family;\n                address.sin6_port = ((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_port;\n                inet_pton(address.sin6_family, \"::\", &address.sin6_addr);\n                if ((ret == _Z_RES_OK) && (bind(sock->_fd, (struct sockaddr *)&address, sizeof(address)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._iptcp->ai_family == AF_INET) {\n                struct ip_mreq mreq;\n                (void)memset(&mreq, 0, sizeof(mreq));\n                mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr.s_addr;\n                mreq.imr_interface.s_addr = ((struct sockaddr_in *)lsockaddr)->sin_addr.s_addr;\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(sock->_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (rep._iptcp->ai_family == AF_INET6) {\n                struct ipv6_mreq mreq;\n                (void)memset(&mreq, 0, sizeof(mreq));\n                // flawfinder: ignore\n                (void)memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_addr,\n                             sizeof(struct in6_addr));\n                mreq.ipv6mr_interface = if_nametoindex(iface);\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(sock->_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (join != NULL) {\n                char *joins = _z_str_clone(join);\n                char *joins_cursor = joins;\n                for (char *ip = strsep(&joins_cursor, \"|\"); ip != NULL; ip = strsep(&joins_cursor, \"|\")) {\n                    if (rep._iptcp->ai_family == AF_INET) {\n                        struct ip_mreq mreq;\n                        (void)memset(&mreq, 0, sizeof(mreq));\n                        inet_pton(rep._iptcp->ai_family, ip, &mreq.imr_multiaddr);\n                        mreq.imr_interface.s_addr = ((struct sockaddr_in *)lsockaddr)->sin_addr.s_addr;\n                        if ((ret == _Z_RES_OK) &&\n                            (setsockopt(sock->_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)) {\n                            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                            ret = _Z_ERR_GENERIC;\n                        }\n                    } else if (rep._iptcp->ai_family == AF_INET6) {\n                        struct ipv6_mreq mreq;\n                        (void)memset(&mreq, 0, sizeof(mreq));\n                        inet_pton(rep._iptcp->ai_family, ip, &mreq.ipv6mr_multiaddr);\n                        mreq.ipv6mr_interface = if_nametoindex(iface);\n                        if ((ret == _Z_RES_OK) &&\n                            (setsockopt(sock->_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)) {\n                            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                            ret = _Z_ERR_GENERIC;\n                        }\n                    }\n                }\n                z_free(joins);\n            }\n\n            if (ret != _Z_RES_OK) {\n                close(sock->_fd);\n                sock->_fd = -1;\n            }\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        z_free(lsockaddr);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nvoid _z_close_udp_multicast(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    if (sockrecv->_fd >= 0) {\n        if (rep._iptcp->ai_family == AF_INET) {\n            struct ip_mreq mreq;\n            (void)memset(&mreq, 0, sizeof(mreq));\n            mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr.s_addr;\n            mreq.imr_interface.s_addr = htonl(INADDR_ANY);\n            setsockopt(sockrecv->_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));\n        } else if (rep._iptcp->ai_family == AF_INET6) {\n            struct ipv6_mreq mreq;\n            (void)memset(&mreq, 0, sizeof(mreq));\n            // flawfinder: ignore\n            (void)memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_addr,\n                         sizeof(struct in6_addr));\n            setsockopt(sockrecv->_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq));\n        } else {\n            /* Do nothing. */\n        }\n    }\n#if defined(ZENOH_LINUX)\n    if (lep._iptcp != NULL) {\n        z_free(lep._iptcp->ai_addr);\n    }\n#else\n    _ZP_UNUSED(lep);\n#endif\n    if (sockrecv->_fd >= 0) {\n        close(sockrecv->_fd);\n        sockrecv->_fd = -1;\n    }\n    if (socksend->_fd >= 0) {\n        close(socksend->_fd);\n        socksend->_fd = -1;\n    }\n}\n\nsize_t _z_read_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *addr) {\n    struct sockaddr_storage raddr;\n    unsigned int replen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = 0;\n    do {\n        rb = recvfrom(sock._fd, ptr, len, 0, (struct sockaddr *)&raddr, &replen);\n        if (rb < (ssize_t)0) {\n            return SIZE_MAX;\n        }\n\n        if (lep._iptcp->ai_family == AF_INET) {\n            struct sockaddr_in *a = ((struct sockaddr_in *)lep._iptcp->ai_addr);\n            struct sockaddr_in *b = ((struct sockaddr_in *)&raddr);\n            if (!((a->sin_port == b->sin_port) && (a->sin_addr.s_addr == b->sin_addr.s_addr))) {\n                if (addr != NULL) {\n                    assert(addr->len >= sizeof(in_addr_t) + sizeof(in_port_t));\n                    addr->len = sizeof(in_addr_t) + sizeof(in_port_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin_addr.s_addr, sizeof(in_addr_t));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(in_addr_t)), &b->sin_port, sizeof(in_port_t));\n                }\n                break;\n            }\n        } else if (lep._iptcp->ai_family == AF_INET6) {\n            struct sockaddr_in6 *a = ((struct sockaddr_in6 *)lep._iptcp->ai_addr);\n            struct sockaddr_in6 *b = ((struct sockaddr_in6 *)&raddr);\n            if (!((a->sin6_port == b->sin6_port) &&\n                  (memcmp(a->sin6_addr.s6_addr, b->sin6_addr.s6_addr, sizeof(struct in6_addr)) == 0))) {\n                if (addr != NULL) {\n                    assert(addr->len >= sizeof(struct in6_addr) + sizeof(in_port_t));\n                    addr->len = sizeof(struct in6_addr) + sizeof(in_port_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin6_addr.s6_addr, sizeof(struct in6_addr));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(struct in6_addr)), &b->sin6_port, sizeof(in_port_t));\n                }\n                break;\n            }\n        } else {\n            continue;\n        }\n    } while (1);\n\n    return (size_t)rb;\n}\n\nsize_t _z_read_exact_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_udp_multicast(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, (ptrdiff_t)rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_udp_multicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                             const _z_sys_net_endpoint_t rep) {\n    return (size_t)sendto(sock._fd, ptr, len, 0, rep._iptcp->ai_addr, rep._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_close_udp_multicast(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_read_exact_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_read_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_send_udp_multicast(sock, ptr, len, rep);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_rpi_pico.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#if defined(ZENOH_RPI_PICO) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <string.h>\n\n#include \"lwip/ip4_addr.h\"\n#include \"lwip/netdb.h\"\n#include \"pico/cyw43_arch.h\"\n#include \"udp_multicast_lwip_common.h\"\n\nstatic unsigned long __get_ip_from_iface(const char *iface, int sa_family, struct sockaddr **lsockaddr) {\n    _ZP_UNUSED(iface);\n    _ZP_UNUSED(sa_family);\n    unsigned int addrlen = 0U;\n\n    struct netif *netif = &cyw43_state.netif[CYW43_ITF_STA];\n    if (!netif_is_up(netif)) {\n        return 0;\n    }\n\n    struct sockaddr_in *lsockaddr_in = (struct sockaddr_in *)z_malloc(sizeof(struct sockaddr_in));\n    if (lsockaddr_in == NULL) {\n        return 0;\n    }\n    (void)memset(lsockaddr_in, 0, sizeof(struct sockaddr_in));\n    const ip4_addr_t *ip4_addr = netif_ip4_addr(netif);\n    inet_addr_from_ip4addr(&lsockaddr_in->sin_addr, ip_2_ip4(ip4_addr));\n    lsockaddr_in->sin_family = AF_INET;\n    lsockaddr_in->sin_port = htons(0);\n\n    addrlen = sizeof(struct sockaddr_in);\n    *lsockaddr = (struct sockaddr *)lsockaddr_in;\n\n    return addrlen;\n}\n\nstatic z_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep,\n                                        _z_sys_net_endpoint_t *lep, uint32_t tout, const char *iface) {\n    return _z_lwip_udp_multicast_open(sock, rep, lep, tout, iface, __get_ip_from_iface);\n}\n\nstatic z_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                          const char *iface, const char *join) {\n    return _z_lwip_udp_multicast_listen(sock, rep, tout, iface, join, __get_ip_from_iface);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_lwip_udp_multicast_close(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_lwip_udp_multicast_read_exact(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_lwip_udp_multicast_read(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_lwip_udp_multicast_write(sock, ptr, len, rep);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_windows.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_WINDOWS) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <iphlpapi.h>\n#include <stdio.h>\n#include <string.h>\n#include <winsock2.h>\n#include <ws2tcpip.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic WSADATA _z_udp_multicast_windows_wsa_data;\n\nstatic unsigned int __get_ip_from_iface(const char *iface, int sa_family, SOCKADDR **lsockaddr) {\n    unsigned int addrlen = 0U;\n\n    unsigned long outBufLen = 15000;\n    IP_ADAPTER_ADDRESSES *l_ifaddr = (IP_ADAPTER_ADDRESSES *)z_malloc(outBufLen);\n    if (l_ifaddr != NULL) {\n        if (GetAdaptersAddresses(sa_family, 0, NULL, l_ifaddr, &outBufLen) != ERROR_BUFFER_OVERFLOW) {\n            for (IP_ADAPTER_ADDRESSES *tmp = l_ifaddr; tmp != NULL; tmp = tmp->Next) {\n                if (_z_str_eq(tmp->AdapterName, iface) == true) {\n                    if (sa_family == AF_INET) {\n                        *lsockaddr = (SOCKADDR *)z_malloc(sizeof(SOCKADDR_IN));\n                        if (lsockaddr != NULL) {\n                            (void)memset(*lsockaddr, 0, sizeof(SOCKADDR_IN));\n                            // flawfinder: ignore\n                            (void)memcpy(*lsockaddr, tmp->FirstUnicastAddress->Address.lpSockaddr, sizeof(SOCKADDR_IN));\n                            addrlen = sizeof(SOCKADDR_IN);\n                        }\n                    } else if (sa_family == AF_INET6) {\n                        *lsockaddr = (SOCKADDR *)z_malloc(sizeof(SOCKADDR_IN6));\n                        if (lsockaddr != NULL) {\n                            (void)memset(*lsockaddr, 0, sizeof(SOCKADDR_IN6));\n                            // flawfinder: ignore\n                            (void)memcpy(*lsockaddr, tmp->FirstUnicastAddress->Address.lpSockaddr,\n                                         sizeof(SOCKADDR_IN6));\n                            addrlen = sizeof(SOCKADDR_IN6);\n                        }\n                    } else {\n                        continue;\n                    }\n\n                    break;\n                }\n            }\n        }\n\n        z_free(l_ifaddr);\n        l_ifaddr = NULL;\n    }\n\n    return addrlen;\n}\n\nz_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_udp_multicast_windows_wsa_data) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    SOCKADDR *lsockaddr = NULL;\n    unsigned int addrlen = __get_ip_from_iface(iface, rep._ep._iptcp->ai_family, &lsockaddr);\n    if (addrlen != 0U) {\n        sock->_sock._fd = socket(rep._ep._iptcp->ai_family, rep._ep._iptcp->ai_socktype, rep._ep._iptcp->ai_protocol);\n        if (sock->_sock._fd != INVALID_SOCKET) {\n            DWORD tv = tout;\n            if ((ret == _Z_RES_OK) &&\n                (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._ep._iptcp->ai_family == AF_INET) {\n                SOCKADDR_IN address = {\n                    .sin_family = AF_INET, .sin_port = htons(0), .sin_addr.s_addr = htonl(INADDR_ANY), .sin_zero = {0}};\n                if ((ret == _Z_RES_OK) &&\n                    (bind(sock->_sock._fd, (SOCKADDR *)&address, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (rep._ep._iptcp->ai_family == AF_INET6) {\n                SOCKADDR_IN6 address = {.sin6_family = AF_INET6, .sin6_port = htons(0), 0, .sin6_addr = {{{0}}}, 0};\n                if ((ret == _Z_RES_OK) &&\n                    (bind(sock->_sock._fd, (SOCKADDR *)&address, sizeof(SOCKADDR_IN6)) == SOCKET_ERROR)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (getsockname(sock->_sock._fd, lsockaddr, (int *)&addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._ep._iptcp->ai_family == AF_INET) {\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(sock->_sock._fd, IPPROTO_IP, IP_MULTICAST_IF,\n                                (const char *)&((SOCKADDR_IN *)lsockaddr)->sin_addr.s_addr, addrlen) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (rep._ep._iptcp->ai_family == AF_INET6) {\n                if ((ret == _Z_RES_OK) &&\n                    (setsockopt(sock->_sock._fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,\n                                (const char *)&((SOCKADDR_IN6 *)lsockaddr)->sin6_scope_id, sizeof(ULONG)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (ret != _Z_RES_OK) {\n                closesocket(sock->_sock._fd);\n                sock->_sock._fd = INVALID_SOCKET;\n                WSACleanup();\n                z_free(lsockaddr);\n                return ret;\n            }\n\n            ADDRINFOA *laddr = (ADDRINFOA *)z_malloc(sizeof(ADDRINFOA));\n            if (laddr == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                closesocket(sock->_sock._fd);\n                sock->_sock._fd = INVALID_SOCKET;\n                WSACleanup();\n                z_free(lsockaddr);\n                return _Z_ERR_GENERIC;\n            }\n\n            laddr->ai_flags = 0;\n            laddr->ai_family = rep._ep._iptcp->ai_family;\n            laddr->ai_socktype = rep._ep._iptcp->ai_socktype;\n            laddr->ai_protocol = rep._ep._iptcp->ai_protocol;\n            laddr->ai_addrlen = addrlen;\n            laddr->ai_addr = lsockaddr;\n            laddr->ai_canonname = NULL;\n            laddr->ai_next = NULL;\n            lep->_ep._iptcp = laddr;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            z_free(lsockaddr);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    (void)join;\n    z_result_t ret = _Z_RES_OK;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_udp_multicast_windows_wsa_data) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    SOCKADDR *lsockaddr = NULL;\n    unsigned int addrlen = __get_ip_from_iface(iface, rep._ep._iptcp->ai_family, &lsockaddr);\n    if (addrlen != 0U) {\n        sock->_sock._fd = socket(rep._ep._iptcp->ai_family, rep._ep._iptcp->ai_socktype, rep._ep._iptcp->ai_protocol);\n        if (sock->_sock._fd != INVALID_SOCKET) {\n            DWORD tv = tout;\n            if ((ret == _Z_RES_OK) &&\n                (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            int optflag = 1;\n            if ((ret == _Z_RES_OK) &&\n                (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optflag, sizeof(optflag)) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._ep._iptcp->ai_family == AF_INET) {\n                SOCKADDR_IN address = {.sin_family = AF_INET,\n                                       .sin_port = ((SOCKADDR_IN *)rep._ep._iptcp->ai_addr)->sin_port,\n                                       .sin_addr = {0},\n                                       .sin_zero = {0}};\n                if ((ret == _Z_RES_OK) && (bind(sock->_sock._fd, (SOCKADDR *)&address, sizeof address) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (rep._ep._iptcp->ai_family == AF_INET6) {\n                SOCKADDR_IN6 address = {.sin6_family = AF_INET6,\n                                        .sin6_port = ((SOCKADDR_IN6 *)rep._ep._iptcp->ai_addr)->sin6_port,\n                                        0,\n                                        .sin6_addr = {{{0}}},\n                                        0};\n                if ((ret == _Z_RES_OK) && (bind(sock->_sock._fd, (SOCKADDR *)&address, sizeof address) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (rep._ep._iptcp->ai_family == AF_INET) {\n                struct ip_mreq mreq;\n                (void)memset(&mreq, 0, sizeof(mreq));\n                mreq.imr_multiaddr.s_addr = ((SOCKADDR_IN *)rep._ep._iptcp->ai_addr)->sin_addr.s_addr;\n                mreq.imr_interface.s_addr = ((SOCKADDR_IN *)lsockaddr)->sin_addr.s_addr;\n                if ((ret == _Z_RES_OK) && (setsockopt(sock->_sock._fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,\n                                                      (const char *)&mreq, sizeof(mreq)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else if (rep._ep._iptcp->ai_family == AF_INET6) {\n                struct ipv6_mreq mreq;\n                (void)memset(&mreq, 0, sizeof(mreq));\n                // flawfinder: ignore\n                (void)memcpy(&mreq.ipv6mr_multiaddr, &((SOCKADDR_IN6 *)rep._ep._iptcp->ai_addr)->sin6_addr,\n                             sizeof(IN6_ADDR));\n                mreq.ipv6mr_interface = if_nametoindex(iface);\n                if ((ret == _Z_RES_OK) && (setsockopt(sock->_sock._fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,\n                                                      (const char *)&mreq, sizeof(mreq)) < 0)) {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (ret != _Z_RES_OK) {\n                closesocket(sock->_sock._fd);\n                sock->_sock._fd = INVALID_SOCKET;\n                WSACleanup();\n            }\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        z_free(lsockaddr);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nvoid _z_close_udp_multicast(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _ZP_UNUSED(lep);\n    if (sockrecv->_sock._fd != INVALID_SOCKET) {\n        if (rep._ep._iptcp->ai_family == AF_INET) {\n            struct ip_mreq mreq;\n            (void)memset(&mreq, 0, sizeof(mreq));\n            mreq.imr_multiaddr.s_addr = ((SOCKADDR_IN *)rep._ep._iptcp->ai_addr)->sin_addr.s_addr;\n            mreq.imr_interface.s_addr = htonl(INADDR_ANY);\n            setsockopt(sockrecv->_sock._fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&mreq, sizeof(mreq));\n        } else if (rep._ep._iptcp->ai_family == AF_INET6) {\n            struct ipv6_mreq mreq;\n            (void)memset(&mreq, 0, sizeof(mreq));\n            // flawfinder: ignore\n            (void)memcpy(&mreq.ipv6mr_multiaddr, &((SOCKADDR_IN6 *)rep._ep._iptcp->ai_addr)->sin6_addr,\n                         sizeof(struct in6_addr));\n            setsockopt(sockrecv->_sock._fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (const char *)&mreq, sizeof(mreq));\n        } else {\n            /* Do nothing. */\n        }\n    }\n\n    if (sockrecv->_sock._fd != INVALID_SOCKET) {\n        closesocket(sockrecv->_sock._fd);\n        sockrecv->_sock._fd = INVALID_SOCKET;\n        WSACleanup();\n    }\n    if (socksend->_sock._fd != INVALID_SOCKET) {\n        closesocket(socksend->_sock._fd);\n        socksend->_sock._fd = INVALID_SOCKET;\n        WSACleanup();\n    }\n}\n\nsize_t _z_read_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *addr) {\n    SOCKADDR_STORAGE raddr;\n    unsigned int replen = sizeof(SOCKADDR_STORAGE);\n\n    size_t rb = 0;\n    do {\n        rb = recvfrom(sock._sock._fd, (char *)ptr, (int)len, 0, (SOCKADDR *)&raddr, (int *)&replen);\n        if (rb < (size_t)0) {\n            rb = SIZE_MAX;\n            break;\n        }\n\n        if (lep._ep._iptcp->ai_family == AF_INET) {\n            SOCKADDR_IN *a = ((SOCKADDR_IN *)lep._ep._iptcp->ai_addr);\n            SOCKADDR_IN *b = ((SOCKADDR_IN *)&raddr);\n            if (!((a->sin_port == b->sin_port) && (a->sin_addr.s_addr == b->sin_addr.s_addr))) {\n                if (addr != NULL) {\n                    addr->len = sizeof(IN_ADDR) + sizeof(USHORT);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin_addr.s_addr, sizeof(IN_ADDR));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(IN_ADDR)), &b->sin_port, sizeof(USHORT));\n                }\n                break;\n            }\n        } else if (lep._ep._iptcp->ai_family == AF_INET6) {\n            SOCKADDR_IN6 *a = ((SOCKADDR_IN6 *)lep._ep._iptcp->ai_addr);\n            SOCKADDR_IN6 *b = ((SOCKADDR_IN6 *)&raddr);\n            if (!((a->sin6_port == b->sin6_port) &&\n                  (memcmp(a->sin6_addr.s6_addr, b->sin6_addr.s6_addr, sizeof(struct in6_addr)) == 0))) {\n                if (addr != NULL) {\n                    addr->len = sizeof(struct in6_addr) + sizeof(USHORT);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin6_addr.s6_addr, sizeof(struct in6_addr));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(struct in6_addr)), &b->sin6_port, sizeof(USHORT));\n                }\n                break;\n            }\n        } else {\n            continue;\n        }\n    } while (1);\n\n    return rb;\n}\n\nsize_t _z_read_exact_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_udp_multicast(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_udp_multicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                             const _z_sys_net_endpoint_t rep) {\n    return sendto(sock._sock._fd, (const char *)ptr, (int)len, 0, rep._ep._iptcp->ai_addr,\n                  (int)rep._ep._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_close_udp_multicast(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_read_exact_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_read_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_send_udp_multicast(sock, ptr, len, rep);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_multicast_zephyr.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/udp_multicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ZEPHYR) && (Z_FEATURE_LINK_UDP_MULTICAST == 1)\n\n#include <netdb.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <unistd.h>\n#include <zephyr/net/net_if.h>\n#include <zephyr/net/socket.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_open_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    _ZP_UNUSED(iface);\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    unsigned int addrlen = 0;\n    if (rep._iptcp->ai_family == AF_INET) {\n        lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in));\n        if (lsockaddr != NULL) {\n            (void)memset(lsockaddr, 0, sizeof(struct sockaddr_in));\n            addrlen = sizeof(struct sockaddr_in);\n\n            struct sockaddr_in *c_laddr = (struct sockaddr_in *)lsockaddr;\n            c_laddr->sin_family = AF_INET;\n            c_laddr->sin_addr.s_addr = INADDR_ANY;\n            c_laddr->sin_port = htons(INADDR_ANY);\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else if (rep._iptcp->ai_family == AF_INET6) {\n        lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in6));\n        if (lsockaddr != NULL) {\n            (void)memset(lsockaddr, 0, sizeof(struct sockaddr_in6));\n            addrlen = sizeof(struct sockaddr_in6);\n\n            struct sockaddr_in6 *c_laddr = (struct sockaddr_in6 *)lsockaddr;\n            c_laddr->sin6_family = AF_INET6;\n            c_laddr->sin6_addr = in6addr_any;\n            c_laddr->sin6_port = htons(INADDR_ANY);\n            //        c_laddr->sin6_scope_id; // Not needed to be defined\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (addrlen != 0U) {\n        sock->_fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n        if (sock->_fd != -1) {\n            z_time_t tv;\n            tv.tv_sec = tout / (uint32_t)1000;\n            tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n            if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n                // FIXME: setting the setsockopt is consistently failing. Commenting it\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                // until further inspection. ret = _Z_ERR_GENERIC;\n            }\n\n            if ((ret == _Z_RES_OK) && (bind(sock->_fd, lsockaddr, addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            // Get the randomly assigned port used to discard loopback messages\n            if ((ret == _Z_RES_OK) && (getsockname(sock->_fd, lsockaddr, &addrlen) < 0)) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n\n            if (ret != _Z_RES_OK) {\n                close(sock->_fd);\n                sock->_fd = -1;\n                z_free(lsockaddr);\n                return ret;\n            }\n\n            // Create lep endpoint\n            struct addrinfo *laddr = (struct addrinfo *)z_malloc(sizeof(struct addrinfo));\n            if (laddr == NULL) {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                close(sock->_fd);\n                sock->_fd = -1;\n                z_free(lsockaddr);\n                return _Z_ERR_GENERIC;\n            }\n\n            laddr->ai_flags = 0;\n            laddr->ai_family = rep._iptcp->ai_family;\n            laddr->ai_socktype = rep._iptcp->ai_socktype;\n            laddr->ai_protocol = rep._iptcp->ai_protocol;\n            laddr->ai_addrlen = addrlen;\n            laddr->ai_addr = lsockaddr;\n            laddr->ai_canonname = NULL;\n            laddr->ai_next = NULL;\n            lep->_iptcp = laddr;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            z_free(lsockaddr);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nz_result_t _z_listen_udp_multicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    (void)iface;\n    (void)join;\n    z_result_t ret = _Z_RES_OK;\n\n    struct sockaddr *lsockaddr = NULL;\n    unsigned int addrlen = 0;\n    if (rep._iptcp->ai_family == AF_INET) {\n        lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in));\n        if (lsockaddr != NULL) {\n            (void)memset(lsockaddr, 0, sizeof(struct sockaddr_in));\n            addrlen = sizeof(struct sockaddr_in);\n\n            struct sockaddr_in *c_laddr = (struct sockaddr_in *)lsockaddr;\n            c_laddr->sin_family = AF_INET;\n            c_laddr->sin_addr.s_addr = INADDR_ANY;\n            c_laddr->sin_port = ((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_port;\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else if (rep._iptcp->ai_family == AF_INET6) {\n        lsockaddr = (struct sockaddr *)z_malloc(sizeof(struct sockaddr_in6));\n        if (lsockaddr != NULL) {\n            (void)memset(lsockaddr, 0, sizeof(struct sockaddr_in6));\n            addrlen = sizeof(struct sockaddr_in6);\n\n            struct sockaddr_in6 *c_laddr = (struct sockaddr_in6 *)lsockaddr;\n            c_laddr->sin6_family = AF_INET6;\n            c_laddr->sin6_addr = in6addr_any;\n            c_laddr->sin6_port = ((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_port;\n            //        c_laddr->sin6_scope_id; // Not needed to be defined\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    sock->_fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        int optflag = 1;\n        if ((ret == _Z_RES_OK) &&\n            (setsockopt(sock->_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optflag, sizeof(optflag)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        z_time_t tv;\n        tv.tv_sec = tout / (uint32_t)1000;\n        tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            // FIXME: setting the setsockopt is consistently failing. Commenting it\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            // until further inspection. ret = _Z_ERR_GENERIC;\n        }\n\n        if ((ret == _Z_RES_OK) && (bind(sock->_fd, lsockaddr, addrlen) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        // FIXME: iface passed into the locator is being ignored\n        //        default if used instead\n        if (ret != _Z_RES_OK) {\n            struct net_if *ifa = NULL;\n            ifa = net_if_get_default();\n            if (ifa != NULL) {\n                // Join the multicast group\n                if (rep._iptcp->ai_family == AF_INET) {\n                    struct net_if_mcast_addr *mcast = NULL;\n                    mcast = net_if_ipv4_maddr_add(ifa, &((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr);\n                    if (!mcast) {\n                        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                        ret = _Z_ERR_GENERIC;\n                    }\n#if KERNEL_VERSION_MAJOR == 3 && KERNEL_VERSION_MINOR > 3 || KERNEL_VERSION_MAJOR >= 4\n                    net_if_ipv4_maddr_join(ifa, mcast);\n#else\n                    net_if_ipv4_maddr_join(mcast);\n#endif\n                } else if (rep._iptcp->ai_family == AF_INET6) {\n                    struct net_if_mcast_addr *mcast = NULL;\n                    mcast = net_if_ipv6_maddr_add(ifa, &((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_addr);\n                    if (!mcast) {\n                        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                        ret = _Z_ERR_GENERIC;\n                    }\n#if KERNEL_VERSION_MAJOR == 3 && KERNEL_VERSION_MINOR > 3 || KERNEL_VERSION_MAJOR >= 4\n                    net_if_ipv6_maddr_join(ifa, mcast);\n#else\n                    net_if_ipv6_maddr_join(mcast);\n#endif\n                } else {\n                    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                    ret = _Z_ERR_GENERIC;\n                }\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n            }\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n\n        z_free(lsockaddr);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nvoid _z_close_udp_multicast(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _ZP_UNUSED(lep);\n    if (sockrecv->_fd >= 0) {\n        // FIXME: iface passed into the locator is being ignored\n        //        default if used instead\n        struct net_if *ifa = NULL;\n        ifa = net_if_get_default();\n        if (ifa != NULL) {\n            struct net_if_mcast_addr *mcast = NULL;\n            if (rep._iptcp->ai_family == AF_INET) {\n                mcast = net_if_ipv4_maddr_add(ifa, &((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr);\n                if (mcast != NULL) {\n#if KERNEL_VERSION_MAJOR == 3 && KERNEL_VERSION_MINOR > 3 || KERNEL_VERSION_MAJOR >= 4\n                    net_if_ipv4_maddr_leave(ifa, mcast);\n#else\n                    net_if_ipv4_maddr_leave(mcast);\n#endif\n                    net_if_ipv4_maddr_rm(ifa, &((struct sockaddr_in *)rep._iptcp->ai_addr)->sin_addr);\n                } else {\n                    // Do nothing. The socket will be closed in any case.\n                }\n            } else if (rep._iptcp->ai_family == AF_INET6) {\n                mcast = net_if_ipv6_maddr_add(ifa, &((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_addr);\n                if (mcast != NULL) {\n#if KERNEL_VERSION_MAJOR == 3 && KERNEL_VERSION_MINOR > 3 || KERNEL_VERSION_MAJOR >= 4\n                    net_if_ipv6_maddr_leave(ifa, mcast);\n#else\n                    net_if_ipv6_maddr_leave(mcast);\n#endif\n                    net_if_ipv6_maddr_rm(ifa, &((struct sockaddr_in6 *)rep._iptcp->ai_addr)->sin6_addr);\n                } else {\n                    // Do nothing. The socket will be closed in any case.\n                }\n            } else {\n                // Do nothing. It must never not enter here.\n                // Required to be compliant with MISRA 15.7 rule\n            }\n        }\n    }\n\n    if (sockrecv->_fd >= 0) {\n        close(sockrecv->_fd);\n        sockrecv->_fd = -1;\n    }\n    if (socksend->_fd >= 0) {\n        close(socksend->_fd);\n        socksend->_fd = -1;\n    }\n}\n\nsize_t _z_read_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *addr) {\n    struct sockaddr_storage raddr;\n    unsigned int raddrlen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = 0;\n    do {\n        rb = recvfrom(sock._fd, ptr, len, 0, (struct sockaddr *)&raddr, &raddrlen);\n        if (rb < (ssize_t)0) {\n            rb = SIZE_MAX;\n            break;\n        }\n\n        if (lep._iptcp->ai_family == AF_INET) {\n            struct sockaddr_in *a = ((struct sockaddr_in *)lep._iptcp->ai_addr);\n            struct sockaddr_in *b = ((struct sockaddr_in *)&raddr);\n            if (!((a->sin_port == b->sin_port) && (a->sin_addr.s_addr == b->sin_addr.s_addr))) {\n                if (addr != NULL) {\n                    addr->len = sizeof(uint32_t) + sizeof(uint16_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin_addr.s_addr, sizeof(uint32_t));\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + sizeof(uint32_t)), &b->sin_port, sizeof(uint16_t));\n                }\n                break;\n            }\n        } else if (lep._iptcp->ai_family == AF_INET6) {\n            struct sockaddr_in6 *a = ((struct sockaddr_in6 *)lep._iptcp->ai_addr);\n            struct sockaddr_in6 *b = ((struct sockaddr_in6 *)&raddr);\n            if (!((a->sin6_port == b->sin6_port) &&\n                  (memcmp(a->sin6_addr.s6_addr, b->sin6_addr.s6_addr, sizeof(uint32_t) * 4UL) == 0))) {\n                // If addr is not NULL, it means that the raddr was requested by the\n                // upper-layers\n                if (addr != NULL) {\n                    addr->len = (sizeof(uint32_t) * 4UL) + sizeof(uint16_t);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)addr->start, &b->sin6_addr.s6_addr, sizeof(uint32_t) * 4UL);\n                    // flawfinder: ignore\n                    (void)memcpy((uint8_t *)(addr->start + (sizeof(uint32_t) * 4UL)), &b->sin6_port, sizeof(uint16_t));\n                }\n                break;\n            }\n        } else {\n            continue;  // FIXME: support error report on invalid packet to the upper\n                       // layer\n        }\n    } while (1);\n\n    return rb;\n}\n\nsize_t _z_read_exact_udp_multicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *addr) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_read_udp_multicast(sock, pos, len - n, lep, addr);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nsize_t _z_send_udp_multicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                             _z_sys_net_endpoint_t rep) {\n    return sendto(sock._fd, ptr, len, 0, rep._iptcp->ai_addr, rep._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_multicast_endpoint_init_from_address(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_udp_multicast_default_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_udp_multicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_multicast_default_endpoint_clear(ep); }\n\nz_result_t _z_udp_multicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, _z_sys_net_endpoint_t *lep,\n                                 uint32_t tout, const char *iface) {\n    return _z_open_udp_multicast(sock, rep, lep, tout, iface);\n}\n\nz_result_t _z_udp_multicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout,\n                                   const char *iface, const char *join) {\n    return _z_listen_udp_multicast(sock, rep, tout, iface, join);\n}\n\nvoid _z_udp_multicast_close(_z_sys_net_socket_t *sockrecv, _z_sys_net_socket_t *socksend,\n                            const _z_sys_net_endpoint_t rep, const _z_sys_net_endpoint_t lep) {\n    _z_close_udp_multicast(sockrecv, socksend, rep, lep);\n}\n\nsize_t _z_udp_multicast_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t lep, _z_slice_t *ep) {\n    return _z_read_exact_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len, const _z_sys_net_endpoint_t lep,\n                             _z_slice_t *ep) {\n    return _z_read_udp_multicast(sock, ptr, len, lep, ep);\n}\n\nsize_t _z_udp_multicast_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                              const _z_sys_net_endpoint_t rep) {\n    return _z_send_udp_multicast(sock, ptr, len, rep);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/udp/udp_opencr.cpp",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_OPENCR)\n\n#include <Arduino.h>\n#include <WiFiUdp.h>\n#include <stddef.h>\n#include <stdlib.h>\n\nextern \"C\" {\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_opencr_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    ep->_iptcp._addr = new IPAddress();\n    if (!ep->_iptcp._addr->fromString(s_address)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    ep->_iptcp._port = strtoul(s_port, NULL, 10);\n    if ((ep->_iptcp._port < (uint32_t)1) ||\n        (ep->_iptcp._port > (uint32_t)65535)) {  // Port numbers should range from 1 to 65535\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        delete ep->_iptcp._addr;\n        ep->_iptcp._addr = NULL;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_opencr_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    delete ep->_iptcp._addr;\n    ep->_iptcp._addr = NULL;\n}\n\nstatic z_result_t _z_udp_opencr_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_udp = new WiFiUDP();\n    if (!sock->_udp->begin(7447)) {  // FIXME: make it random\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    if (ret != _Z_RES_OK) {\n        delete sock->_udp;\n        sock->_udp = NULL;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_opencr_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_udp_opencr_close(_z_sys_net_socket_t *sock) {\n    if (sock->_udp != NULL) {\n        sock->_udp->stop();\n        delete sock->_udp;\n        sock->_udp = NULL;\n    }\n}\n\nstatic size_t _z_udp_opencr_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    ssize_t rb = 0;\n    do {\n        rb = sock._udp->parsePacket();\n    } while (rb == 0);\n\n    if ((rb <= 0) || ((size_t)rb > len)) {\n        return 0;\n    }\n\n    // flawfinder: ignore\n    if (sock._udp->read(ptr, (size_t)rb) != rb) {\n        rb = 0;\n    }\n\n    return rb;\n}\n\nstatic size_t _z_udp_opencr_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_opencr_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_opencr_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                  const _z_sys_net_endpoint_t endpoint) {\n    sock._udp->beginPacket(*endpoint._iptcp._addr, endpoint._iptcp._port);\n    sock._udp->write(ptr, len);\n    sock._udp->endPacket();\n    return len;\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_opencr_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_opencr_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_opencr_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_opencr_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_opencr_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_opencr_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_opencr_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_opencr_write(sock, ptr, len, endpoint);\n}\n}  // extern \"C\"\n\n#endif /* defined(ZP_PLATFORM_SOCKET_OPENCR) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_posix.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_POSIX)\n\n#include <netdb.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_posix_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_DGRAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_UDP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_posix_endpoint_clear(_z_sys_net_endpoint_t *ep) { freeaddrinfo(ep->_iptcp); }\n\nstatic z_result_t _z_udp_posix_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        z_time_t tv;\n        tv.tv_sec = (time_t)(tout / (uint32_t)1000);\n        tv.tv_usec = (suseconds_t)((tout % (uint32_t)1000) * (uint32_t)1000);\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_posix_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_udp_posix_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_udp_posix_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    struct sockaddr_storage raddr;\n    unsigned int addrlen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = recvfrom(sock._fd, ptr, len, 0, (struct sockaddr *)&raddr, &addrlen);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_posix_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_posix_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n += rb;\n        pos = _z_ptr_u8_offset(pos, (ptrdiff_t)rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_posix_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                 const _z_sys_net_endpoint_t endpoint) {\n    return (size_t)sendto(sock._fd, ptr, len, 0, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_posix_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_posix_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_posix_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_posix_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_posix_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_posix_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_posix_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_posix_write(sock, ptr, len, endpoint);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_POSIX) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_windows.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_WINDOWS)\n\n#include <string.h>\n#include <winsock2.h>\n#include <ws2tcpip.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic WSADATA _z_udp_windows_wsa_data;\n\nstatic z_result_t _z_udp_windows_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_udp_windows_wsa_data) == 0) {\n        ADDRINFOA hints;\n        ep->_ep._iptcp = NULL;\n        (void)memset(&hints, 0, sizeof(hints));\n        hints.ai_family = AF_UNSPEC;\n        hints.ai_socktype = SOCK_DGRAM;\n        hints.ai_flags = 0;\n        hints.ai_protocol = IPPROTO_UDP;\n\n        if (getaddrinfo(s_address, s_port, &hints, &ep->_ep._iptcp) != 0) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_windows_endpoint_clear(_z_sys_net_endpoint_t *ep) {\n    freeaddrinfo(ep->_ep._iptcp);\n    WSACleanup();\n}\n\nstatic z_result_t _z_udp_windows_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (WSAStartup(MAKEWORD(2, 2), &_z_udp_windows_wsa_data) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    sock->_sock._fd =\n        socket(endpoint._ep._iptcp->ai_family, endpoint._ep._iptcp->ai_socktype, endpoint._ep._iptcp->ai_protocol);\n    if (sock->_sock._fd != INVALID_SOCKET) {\n        DWORD tv = tout;\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_sock._fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n        }\n        if (ret != _Z_RES_OK) {\n            closesocket(sock->_sock._fd);\n            sock->_sock._fd = INVALID_SOCKET;\n            WSACleanup();\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_windows_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint,\n                                        uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_udp_windows_close(_z_sys_net_socket_t *sock) {\n    if (sock->_sock._fd != INVALID_SOCKET) {\n        closesocket(sock->_sock._fd);\n        sock->_sock._fd = INVALID_SOCKET;\n        WSACleanup();\n    }\n}\n\nstatic size_t _z_udp_windows_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    SOCKADDR_STORAGE raddr;\n    int addrlen = sizeof(raddr);\n    int rb = recvfrom(sock._sock._fd, (char *)ptr, (int)len, 0, (SOCKADDR *)&raddr, &addrlen);\n    if (rb == SOCKET_ERROR) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_windows_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_windows_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_windows_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                   const _z_sys_net_endpoint_t endpoint) {\n    int wb = sendto(sock._sock._fd, (const char *)ptr, (int)len, 0, endpoint._ep._iptcp->ai_addr,\n                    (int)endpoint._ep._iptcp->ai_addrlen);\n    if (wb == SOCKET_ERROR) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)wb;\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_windows_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_windows_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_windows_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_windows_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_windows_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_windows_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_windows_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_windows_write(sock, ptr, len, endpoint);\n}\n\n#endif /* defined(ZP_PLATFORM_SOCKET_WINDOWS) */\n"
  },
  {
    "path": "src/link/transport/udp/udp_zephyr.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ZEPHYR) && (Z_FEATURE_LINK_UDP_UNICAST == 1)\n\n#include <netdb.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <unistd.h>\n#include <zephyr/net/socket.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nstatic z_result_t _z_udp_zephyr_endpoint_init(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct zsock_addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_DGRAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_UDP;\n\n    if (getaddrinfo(s_address, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_udp_zephyr_endpoint_clear(_z_sys_net_endpoint_t *ep) { freeaddrinfo(ep->_iptcp); }\n\nstatic z_result_t _z_udp_zephyr_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_fd = socket(endpoint._iptcp->ai_family, endpoint._iptcp->ai_socktype, endpoint._iptcp->ai_protocol);\n    if (sock->_fd != -1) {\n        z_time_t tv;\n        tv.tv_sec = tout / (uint32_t)1000;\n        tv.tv_usec = (tout % (uint32_t)1000) * (uint32_t)1000;\n        if ((ret == _Z_RES_OK) && (setsockopt(sock->_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0)) {\n            /* Zephyr may reject this option depending on the network stack configuration. */\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        }\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_fd);\n            sock->_fd = -1;\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_udp_zephyr_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(tout);\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    return _Z_ERR_GENERIC;\n}\n\nstatic void _z_udp_zephyr_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nstatic size_t _z_udp_zephyr_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    struct sockaddr_storage raddr;\n    unsigned int addrlen = sizeof(struct sockaddr_storage);\n\n    ssize_t rb = recvfrom(sock._fd, ptr, len, 0, (struct sockaddr *)&raddr, &addrlen);\n    if (rb < (ssize_t)0) {\n        return SIZE_MAX;\n    }\n\n    return (size_t)rb;\n}\n\nstatic size_t _z_udp_zephyr_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_udp_zephyr_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_udp_zephyr_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                                  const _z_sys_net_endpoint_t endpoint) {\n    return (size_t)sendto(sock._fd, ptr, len, 0, endpoint._iptcp->ai_addr, endpoint._iptcp->ai_addrlen);\n}\n\nz_result_t _z_udp_unicast_endpoint_init(_z_sys_net_endpoint_t *ep, const char *address, const char *port) {\n    return _z_udp_zephyr_endpoint_init(ep, address, port);\n}\n\nvoid _z_udp_unicast_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_udp_zephyr_endpoint_clear(ep); }\n\nz_result_t _z_udp_unicast_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_zephyr_open(sock, endpoint, tout);\n}\n\nz_result_t _z_udp_unicast_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t endpoint, uint32_t tout) {\n    return _z_udp_zephyr_listen(sock, endpoint, tout);\n}\n\nvoid _z_udp_unicast_close(_z_sys_net_socket_t *sock) { _z_udp_zephyr_close(sock); }\n\nsize_t _z_udp_unicast_read(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_zephyr_read(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_read_exact(_z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    return _z_udp_zephyr_read_exact(sock, ptr, len);\n}\n\nsize_t _z_udp_unicast_write(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len,\n                            const _z_sys_net_endpoint_t endpoint) {\n    return _z_udp_zephyr_write(sock, ptr, len, endpoint);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/transport/upper/serial_protocol.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/serial_protocol.h\"\n\n#include <errno.h>\n#include <limits.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/link/config/serial.h\"\n#include \"zenoh-pico/link/transport/serial.h\"\n#include \"zenoh-pico/protocol/codec/serial.h\"\n#include \"zenoh-pico/protocol/definitions/serial.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1\n\n#define SERIAL_CONNECT_THROTTLE_TIME_MS 250\n\ntypedef struct {\n    bool _from_pins;\n    uint32_t _baudrate;\n    uint32_t _txpin;\n    uint32_t _rxpin;\n    char *_dev;\n} _z_serial_endpoint_cfg_t;\n\nstatic void _z_serial_endpoint_cfg_clear(_z_serial_endpoint_cfg_t *cfg) {\n    z_free(cfg->_dev);\n    cfg->_dev = NULL;\n}\n\nstatic z_result_t _z_serial_parse_u32(const char *str, uint32_t *value) {\n    char *end = NULL;\n    unsigned long parsed = 0;\n\n    if (str == NULL || str[0] == '\\0') {\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    errno = 0;\n    parsed = strtoul(str, &end, 10);\n    if (errno != 0 || end == str || *end != '\\0' || parsed == 0 || parsed > UINT32_MAX) {\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    *value = (uint32_t)parsed;\n    return _Z_RES_OK;\n}\n\nstatic char *_z_serial_copy_address(const _z_string_t *address) {\n    size_t len = _z_string_len(address);\n    char *copy = (char *)z_malloc(len + 1);\n    if (copy != NULL) {\n        _z_str_n_copy(copy, _z_string_data(address), len + 1);\n    }\n    return copy;\n}\n\nstatic z_result_t _z_serial_endpoint_parse(_z_serial_endpoint_cfg_t *cfg, const _z_endpoint_t *endpoint) {\n    z_result_t ret = _Z_RES_OK;\n    _z_string_t ser_str = _z_string_alias_str(SERIAL_SCHEMA);\n    char *address = NULL;\n    char *dot = NULL;\n    const char *baudrate_str = NULL;\n\n    (void)memset(cfg, 0, sizeof(*cfg));\n\n    if (!_z_string_equals(&endpoint->_locator._protocol, &ser_str)) {\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    baudrate_str = _z_str_intmap_get(&endpoint->_config, SERIAL_CONFIG_BAUDRATE_KEY);\n    ret = _z_serial_parse_u32(baudrate_str, &cfg->_baudrate);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n\n    address = _z_serial_copy_address(&endpoint->_locator._address);\n    if (address == NULL || address[0] == '\\0') {\n        z_free(address);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    dot = strchr(address, '.');\n    if (dot == NULL) {\n        cfg->_dev = address;\n        return _Z_RES_OK;\n    }\n\n    *dot = '\\0';\n    dot++;\n    if (address[0] == '\\0' || dot[0] == '\\0') {\n        z_free(address);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    ret = _z_serial_parse_u32(address, &cfg->_txpin);\n    if (ret != _Z_RES_OK) {\n        z_free(address);\n        return ret;\n    }\n\n    ret = _z_serial_parse_u32(dot, &cfg->_rxpin);\n    z_free(address);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n\n    cfg->_from_pins = true;\n    return _Z_RES_OK;\n}\n\nstatic size_t _z_serial_write_all(_z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    size_t total = 0;\n    while (total != len) {\n        size_t wb = _z_serial_write(sock, _z_ptr_u8_offset((uint8_t *)ptr, (ptrdiff_t)total), len - total);\n        if (wb == SIZE_MAX || wb == 0) {\n            return SIZE_MAX;\n        }\n        total += wb;\n    }\n    return total;\n}\n\nstatic size_t _z_read_serial_internal(const _z_sys_net_socket_t sock, uint8_t *header, uint8_t *ptr, size_t len) {\n    uint8_t *raw_buf = (uint8_t *)z_malloc(_Z_SERIAL_MAX_COBS_BUF_SIZE);\n    if (raw_buf == NULL) {\n        _Z_ERROR(\"Failed to allocate serial COBS buffer\");\n        return SIZE_MAX;\n    }\n\n    size_t rb = 0;\n    while (rb < _Z_SERIAL_MAX_COBS_BUF_SIZE) {\n        size_t chunk = _z_serial_read(sock, &raw_buf[rb], 1);\n        if (chunk != 1) {\n            z_free(raw_buf);\n            return SIZE_MAX;\n        }\n\n        rb++;\n        if (raw_buf[rb - 1] == (uint8_t)0x00) {\n            break;\n        }\n    }\n\n    uint8_t *tmp_buf = (uint8_t *)z_malloc(_Z_SERIAL_MFS_SIZE);\n    if (tmp_buf == NULL) {\n        z_free(raw_buf);\n        _Z_ERROR(\"Failed to allocate serial MFS buffer\");\n        return SIZE_MAX;\n    }\n\n    size_t ret = _z_serial_msg_deserialize(raw_buf, rb, ptr, len, header, tmp_buf, _Z_SERIAL_MFS_SIZE);\n    z_free(raw_buf);\n    z_free(tmp_buf);\n    return ret;\n}\n\nstatic size_t _z_send_serial_internal(const _z_sys_net_socket_t sock, uint8_t header, const uint8_t *ptr, size_t len) {\n    uint8_t *tmp_buf = (uint8_t *)z_malloc(_Z_SERIAL_MFS_SIZE);\n    uint8_t *raw_buf = (uint8_t *)z_malloc(_Z_SERIAL_MAX_COBS_BUF_SIZE);\n    if ((raw_buf == NULL) || (tmp_buf == NULL)) {\n        z_free(raw_buf);\n        z_free(tmp_buf);\n        _Z_ERROR(\"Failed to allocate serial COBS and/or MFS buffer\");\n        return SIZE_MAX;\n    }\n\n    size_t raw_len =\n        _z_serial_msg_serialize(raw_buf, _Z_SERIAL_MAX_COBS_BUF_SIZE, ptr, len, header, tmp_buf, _Z_SERIAL_MFS_SIZE);\n    if (raw_len == SIZE_MAX) {\n        z_free(raw_buf);\n        z_free(tmp_buf);\n        return SIZE_MAX;\n    }\n\n    size_t written = _z_serial_write_all(sock, raw_buf, raw_len);\n    z_free(raw_buf);\n    z_free(tmp_buf);\n    return (written == raw_len) ? len : SIZE_MAX;\n}\n\nz_result_t _z_serial_endpoint_valid(const _z_endpoint_t *endpoint) {\n    _z_serial_endpoint_cfg_t cfg;\n    z_result_t ret = _z_serial_endpoint_parse(&cfg, endpoint);\n    _z_serial_endpoint_cfg_clear(&cfg);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    return ret;\n}\n\nstatic z_result_t _z_serial_open_impl(_z_serial_socket_t *sock, const _z_endpoint_t *endpoint, bool connect) {\n    _z_serial_endpoint_cfg_t cfg;\n    z_result_t ret = _Z_RES_OK;\n\n    ret = _z_serial_endpoint_parse(&cfg, endpoint);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return ret;\n    }\n\n    if (cfg._from_pins) {\n        ret = connect ? _z_serial_open_from_pins(&sock->_sock, cfg._txpin, cfg._rxpin, cfg._baudrate)\n                      : _z_serial_listen_from_pins(&sock->_sock, cfg._txpin, cfg._rxpin, cfg._baudrate);\n    } else {\n        ret = connect ? _z_serial_open_from_dev(&sock->_sock, cfg._dev, cfg._baudrate)\n                      : _z_serial_listen_from_dev(&sock->_sock, cfg._dev, cfg._baudrate);\n    }\n\n    if (ret != _Z_RES_OK || !connect) {\n        _z_serial_endpoint_cfg_clear(&cfg);\n        return ret;\n    }\n\n    ret = _z_connect_serial(sock->_sock);\n    if (ret != _Z_RES_OK) {\n        _z_serial_close(&sock->_sock);\n    }\n\n    _z_serial_endpoint_cfg_clear(&cfg);\n    return ret;\n}\n\nz_result_t _z_serial_protocol_open(_z_serial_socket_t *sock, const _z_endpoint_t *endpoint) {\n    return _z_serial_open_impl(sock, endpoint, true);\n}\n\nz_result_t _z_serial_protocol_listen(_z_serial_socket_t *sock, const _z_endpoint_t *endpoint) {\n    return _z_serial_open_impl(sock, endpoint, false);\n}\n\nvoid _z_serial_protocol_close(_z_serial_socket_t *sock) { _z_serial_close(&sock->_sock); }\n\nz_result_t _z_connect_serial(const _z_sys_net_socket_t sock) {\n    while (true) {\n        uint8_t header = _Z_FLAG_SERIAL_INIT;\n\n        _z_send_serial_internal(sock, header, NULL, 0);\n        uint8_t tmp;\n        size_t ret = _z_read_serial_internal(sock, &header, &tmp, sizeof(tmp));\n        if (ret == SIZE_MAX) {\n            _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_RX_FAILED);\n        }\n\n        if (_Z_HAS_FLAG(header, _Z_FLAG_SERIAL_ACK) && _Z_HAS_FLAG(header, _Z_FLAG_SERIAL_INIT)) {\n            _Z_DEBUG(\"connected\");\n            break;\n        } else if (_Z_HAS_FLAG(header, _Z_FLAG_SERIAL_RESET)) {\n            z_sleep_ms(SERIAL_CONNECT_THROTTLE_TIME_MS);\n            _Z_DEBUG(\"reset\");\n            continue;\n        } else {\n            _Z_ERROR(\"unknown header received: %02X\", header);\n            _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_RX_FAILED);\n        }\n    }\n\n    return _Z_RES_OK;\n}\n\nsize_t _z_read_serial(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    uint8_t header;\n    return _z_read_serial_internal(sock, &header, ptr, len);\n}\n\nsize_t _z_send_serial(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    return _z_send_serial_internal(sock, 0, ptr, len);\n}\n\nsize_t _z_read_exact_serial(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n\n    do {\n        size_t rb = _z_read_serial(sock, ptr, len - n);\n        if (rb == SIZE_MAX) {\n            n = rb;\n            break;\n        }\n\n        n += rb;\n    } while (n != len);\n\n    return n;\n}\n#endif /* Z_FEATURE_LINK_SERIAL == 1 */\n"
  },
  {
    "path": "src/link/transport/upper/tls_stream.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tls_stream.h\"\n\n#if Z_FEATURE_LINK_TLS == 1\n\n#include <errno.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"mbedtls/base64.h\"\n#include \"mbedtls/debug.h\"\n#include \"mbedtls/entropy.h\"\n#include \"mbedtls/error.h\"\n#include \"mbedtls/hmac_drbg.h\"\n#include \"mbedtls/md.h\"\n#include \"mbedtls/net_sockets.h\"\n#include \"mbedtls/pk.h\"\n#include \"mbedtls/ssl.h\"\n#include \"mbedtls/version.h\"\n#include \"mbedtls/x509.h\"\n#include \"mbedtls/x509_crt.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/config/tls.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#define Z_TLS_BASE64_MAX_VALUE_LEN (64 * 1024)\n\n#ifdef ZENOH_LOG_TRACE\nstatic void _z_tls_debug(void *ctx, int level, const char *file, int line, const char *str) {\n    _ZP_UNUSED(ctx);\n    _Z_DEBUG_NONL(\"mbed TLS [%d] %s:%04d: %s\", level, file, line, str);\n}\n#endif\n\nstatic _z_tls_context_t *_z_tls_context_new(void);\nstatic void _z_tls_context_free(_z_tls_context_t **ctx);\n\nstatic z_result_t _z_tls_decode_base64(const char *label, const char *input, unsigned char **output,\n                                       size_t *output_len) {\n    if (input == NULL) {\n        return _Z_ERR_GENERIC;\n    }\n\n    if (label == NULL) {\n        _Z_ERROR(\"TLS base64 value label is NULL\");\n        return _Z_ERR_GENERIC;\n    }\n\n    size_t input_len = strnlen(input, Z_TLS_BASE64_MAX_VALUE_LEN + 1);\n    if (input_len > Z_TLS_BASE64_MAX_VALUE_LEN) {\n        _Z_ERROR(\"%s exceeds maximum supported value length (%zu bytes)\", label, (size_t)Z_TLS_BASE64_MAX_VALUE_LEN);\n        return _Z_ERR_GENERIC;\n    }\n\n    size_t required = 0;\n    int ret = mbedtls_base64_decode(NULL, 0, &required, (const unsigned char *)input, input_len);\n    if (ret != 0 && ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {\n        _Z_ERROR(\"Failed to decode %s from base64: -0x%04x\", label, -ret);\n        return _Z_ERR_GENERIC;\n    }\n\n    size_t buffer_len = (required > 0) ? required : 1;\n    unsigned char *buffer = (unsigned char *)z_malloc(buffer_len + 1);\n    if (buffer == NULL) {\n        _Z_ERROR(\"Failed to allocate buffer for %s base64 (%zu bytes)\", label, buffer_len);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    ret = mbedtls_base64_decode(buffer, buffer_len, &required, (const unsigned char *)input, input_len);\n    if (ret != 0) {\n        _Z_ERROR(\"Failed to decode %s from base64: -0x%04x\", label, -ret);\n        z_free(buffer);\n        return _Z_ERR_GENERIC;\n    }\n\n    buffer[required] = '\\0';\n    *output = buffer;\n    if (output_len != NULL) {\n        *output_len = required;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_tls_parse_cert_from_base64(mbedtls_x509_crt *cert, const char *base64, const char *label) {\n    unsigned char *decoded = NULL;\n    size_t decoded_len = 0;\n    z_result_t res = _z_tls_decode_base64(label, base64, &decoded, &decoded_len);\n    if (res != _Z_RES_OK) {\n        return res;\n    }\n\n    int ret = mbedtls_x509_crt_parse(cert, decoded, decoded_len + 1);\n    z_free(decoded);\n    if (ret != 0) {\n        _Z_ERROR(\"Failed to parse %s from base64: -0x%04x\", label, -ret);\n        return _Z_ERR_GENERIC;\n    }\n\n    _Z_DEBUG(\"Loaded %s from base64\", label);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_tls_parse_key_from_base64(mbedtls_pk_context *key, const char *base64, const char *label,\n                                               mbedtls_hmac_drbg_context *rng) {\n    unsigned char *decoded = NULL;\n    size_t decoded_len = 0;\n    z_result_t res = _z_tls_decode_base64(label, base64, &decoded, &decoded_len);\n    if (res != _Z_RES_OK) {\n        return res;\n    }\n\n#if MBEDTLS_VERSION_MAJOR >= 3\n    int ret = mbedtls_pk_parse_key(key, decoded, decoded_len + 1, NULL, 0, mbedtls_hmac_drbg_random, rng);\n#else\n    _ZP_UNUSED(rng);\n    int ret = mbedtls_pk_parse_key(key, decoded, decoded_len + 1, NULL, 0);\n#endif\n    z_free(decoded);\n    if (ret != 0) {\n        _Z_ERROR(\"Failed to parse %s from base64: -0x%04x\", label, -ret);\n        return _Z_ERR_GENERIC;\n    }\n\n    _Z_DEBUG(\"Loaded %s from base64\", label);\n    return _Z_RES_OK;\n}\n\nstatic bool _z_opt_is_true(const char *val) {\n    if (val == NULL || val[0] == '\\0') {\n        return true;\n    }\n    char c = val[0];\n    return !(c == '0' || c == 'n' || c == 'N' || c == 'f' || c == 'F');\n}\n\nstatic int _z_tls_bio_send(void *ctx, const unsigned char *buf, size_t len) {\n    int fd = *(int *)ctx;\n    ssize_t n = send(fd, buf, len, MSG_NOSIGNAL);\n    if (n < 0) {\n        if (errno == EAGAIN || errno == EWOULDBLOCK) {\n            return MBEDTLS_ERR_SSL_WANT_WRITE;\n        }\n        return MBEDTLS_ERR_NET_SEND_FAILED;\n    }\n    return (int)n;\n}\n\nstatic int _z_tls_bio_recv(void *ctx, unsigned char *buf, size_t len) {\n    int fd = *(int *)ctx;\n    ssize_t n = recv(fd, buf, len, 0);\n    if (n < 0) {\n        if (errno == EAGAIN || errno == EWOULDBLOCK) {\n            return MBEDTLS_ERR_SSL_WANT_READ;\n        }\n        return MBEDTLS_ERR_NET_RECV_FAILED;\n    }\n    if (n == 0) {\n        return 0;\n    }\n    return (int)n;\n}\n\nstatic _z_tls_context_t *_z_tls_context_new(void) {\n    _z_tls_context_t *ctx = (_z_tls_context_t *)z_malloc(sizeof(_z_tls_context_t));\n    if (ctx == NULL) {\n        return NULL;\n    }\n\n    mbedtls_ssl_init(&ctx->_ssl);\n    mbedtls_ssl_config_init(&ctx->_ssl_config);\n    mbedtls_entropy_init(&ctx->_entropy);\n    mbedtls_hmac_drbg_init(&ctx->_hmac_drbg);\n    mbedtls_x509_crt_init(&ctx->_ca_cert);\n    mbedtls_pk_init(&ctx->_listen_key);\n    mbedtls_x509_crt_init(&ctx->_listen_cert);\n    mbedtls_pk_init(&ctx->_client_key);\n    mbedtls_x509_crt_init(&ctx->_client_cert);\n    ctx->_enable_mtls = false;\n#ifdef ZENOH_LOG_TRACE\n    mbedtls_debug_set_threshold(4);\n    mbedtls_ssl_conf_dbg(&ctx->_ssl_config, _z_tls_debug, NULL);\n#endif\n\n    int ret = mbedtls_hmac_drbg_seed(&ctx->_hmac_drbg, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),\n                                     mbedtls_entropy_func, &ctx->_entropy, NULL, 0);\n    if (ret != 0) {\n        _Z_ERROR(\"Failed to seed HMAC_DRBG: -0x%04x\", -ret);\n        _z_tls_context_free(&ctx);\n        return NULL;\n    }\n\n    return ctx;\n}\n\nstatic void _z_tls_context_free(_z_tls_context_t **ctx) {\n    if (ctx != NULL && *ctx != NULL) {\n        mbedtls_ssl_free(&(*ctx)->_ssl);\n        mbedtls_ssl_config_free(&(*ctx)->_ssl_config);\n        mbedtls_entropy_free(&(*ctx)->_entropy);\n        mbedtls_hmac_drbg_free(&(*ctx)->_hmac_drbg);\n        mbedtls_x509_crt_free(&(*ctx)->_ca_cert);\n        mbedtls_pk_free(&(*ctx)->_listen_key);\n        mbedtls_x509_crt_free(&(*ctx)->_listen_cert);\n        mbedtls_pk_free(&(*ctx)->_client_key);\n        mbedtls_x509_crt_free(&(*ctx)->_client_cert);\n        z_free(*ctx);\n        *ctx = NULL;\n    }\n}\n\nstatic z_result_t _z_tls_load_ca_certificate(_z_tls_context_t *ctx, const _z_str_intmap_t *config) {\n    const char *ca_cert_str = _z_str_intmap_get(config, TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY);\n    const char *ca_cert_base64 = _z_str_intmap_get(config, TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_KEY);\n\n    if (ca_cert_str == NULL && ca_cert_base64 == NULL) {\n        _Z_ERROR(\"TLS requires 'root_ca_certificate' to be set\");\n        return _Z_ERR_GENERIC;\n    }\n\n    if (ca_cert_str != NULL) {\n        int ret = mbedtls_x509_crt_parse_file(&ctx->_ca_cert, ca_cert_str);\n        if (ret != 0) {\n            _Z_ERROR(\"Failed to parse CA certificate file %s: -0x%04x\", ca_cert_str, -ret);\n            return _Z_ERR_GENERIC;\n        }\n        _Z_DEBUG(\"Loaded CA certificate from %s\", ca_cert_str);\n    }\n\n    if (ca_cert_base64 != NULL) {\n        z_result_t res = _z_tls_parse_cert_from_base64(&ctx->_ca_cert, ca_cert_base64, \"CA certificate\");\n        if (res != _Z_RES_OK) {\n            return res;\n        }\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_tls_load_listen_cert(_z_tls_context_t *ctx, const _z_str_intmap_t *config) {\n    const char *listen_key_str = _z_str_intmap_get(config, TLS_CONFIG_LISTEN_PRIVATE_KEY_KEY);\n    const char *listen_key_base64 = _z_str_intmap_get(config, TLS_CONFIG_LISTEN_PRIVATE_KEY_BASE64_KEY);\n    const char *listen_cert_str = _z_str_intmap_get(config, TLS_CONFIG_LISTEN_CERTIFICATE_KEY);\n    const char *listen_cert_base64 = _z_str_intmap_get(config, TLS_CONFIG_LISTEN_CERTIFICATE_BASE64_KEY);\n\n    if ((listen_key_str == NULL && listen_key_base64 == NULL) ||\n        (listen_cert_str == NULL && listen_cert_base64 == NULL)) {\n        _Z_ERROR(\"TLS server requires both private key and certificate to be configured\");\n        return _Z_ERR_GENERIC;\n    }\n\n    if (listen_key_base64 != NULL) {\n        z_result_t res = _z_tls_parse_key_from_base64(&ctx->_listen_key, listen_key_base64, \"listening private key\",\n                                                      &ctx->_hmac_drbg);\n        if (res != _Z_RES_OK) {\n            return res;\n        }\n    } else {\n#if MBEDTLS_VERSION_MAJOR >= 3\n        int ret = mbedtls_pk_parse_keyfile(&ctx->_listen_key, listen_key_str, NULL, mbedtls_hmac_drbg_random,\n                                           &ctx->_hmac_drbg);\n#else\n        int ret = mbedtls_pk_parse_keyfile(&ctx->_listen_key, listen_key_str, NULL);\n#endif\n        if (ret != 0) {\n            _Z_ERROR(\"Failed to parse listening side private key file %s: -0x%04x\", listen_key_str, -ret);\n            return _Z_ERR_GENERIC;\n        }\n        _Z_DEBUG(\"Loaded listening private key from %s\", listen_key_str);\n    }\n\n    if (listen_cert_base64 != NULL) {\n        z_result_t res =\n            _z_tls_parse_cert_from_base64(&ctx->_listen_cert, listen_cert_base64, \"listening side certificate\");\n        if (res != _Z_RES_OK) {\n            return res;\n        }\n    } else {\n        int ret = mbedtls_x509_crt_parse_file(&ctx->_listen_cert, listen_cert_str);\n        if (ret != 0) {\n            _Z_ERROR(\"Failed to parse listening side certificate file %s: -0x%04x\", listen_cert_str, -ret);\n            return _Z_ERR_GENERIC;\n        }\n        _Z_DEBUG(\"Loaded listening side certificate from %s\", listen_cert_str);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_tls_load_client_cert(_z_tls_context_t *ctx, const _z_str_intmap_t *config) {\n    const char *key_path = _z_str_intmap_get(config, TLS_CONFIG_CONNECT_PRIVATE_KEY_KEY);\n    const char *key_base64 = _z_str_intmap_get(config, TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_KEY);\n    const char *cert_path = _z_str_intmap_get(config, TLS_CONFIG_CONNECT_CERTIFICATE_KEY);\n    const char *cert_base64 = _z_str_intmap_get(config, TLS_CONFIG_CONNECT_CERTIFICATE_BASE64_KEY);\n\n    if ((key_path == NULL && key_base64 == NULL) || (cert_path == NULL && cert_base64 == NULL)) {\n        _Z_ERROR(\"mTLS requires both client private key and certificate\");\n        return _Z_ERR_GENERIC;\n    }\n\n    if (key_base64 != NULL) {\n        z_result_t res =\n            _z_tls_parse_key_from_base64(&ctx->_client_key, key_base64, \"client private key\", &ctx->_hmac_drbg);\n        if (res != _Z_RES_OK) {\n            return res;\n        }\n    } else {\n#if MBEDTLS_VERSION_MAJOR >= 3\n        int ret =\n            mbedtls_pk_parse_keyfile(&ctx->_client_key, key_path, NULL, mbedtls_hmac_drbg_random, &ctx->_hmac_drbg);\n#else\n        int ret = mbedtls_pk_parse_keyfile(&ctx->_client_key, key_path, NULL);\n#endif\n        if (ret != 0) {\n            _Z_ERROR(\"Failed to parse client private key file %s: -0x%04x\", key_path, -ret);\n            return _Z_ERR_GENERIC;\n        }\n        _Z_DEBUG(\"Loaded client private key from %s\", key_path);\n    }\n\n    if (cert_base64 != NULL) {\n        z_result_t res = _z_tls_parse_cert_from_base64(&ctx->_client_cert, cert_base64, \"client certificate\");\n        if (res != _Z_RES_OK) {\n            return res;\n        }\n    } else {\n        int ret = mbedtls_x509_crt_parse_file(&ctx->_client_cert, cert_path);\n        if (ret != 0) {\n            _Z_ERROR(\"Failed to parse client certificate file %s: -0x%04x\", cert_path, -ret);\n            return _Z_ERR_GENERIC;\n        }\n        _Z_DEBUG(\"Loaded client certificate from %s\", cert_path);\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_open_tls(_z_tls_socket_t *sock, const _z_sys_net_endpoint_t *rep, const char *hostname,\n                       const _z_str_intmap_t *config, bool peer_socket) {\n    if ((rep == NULL) || (rep->_iptcp == NULL)) {\n        _Z_ERROR(\"Invalid TCP endpoint for TLS connection\");\n        return _Z_ERR_GENERIC;\n    }\n\n    sock->_is_peer_socket = peer_socket;\n\n    bool verify_name = true;\n    const char *verify_opt = _z_str_intmap_get(config, TLS_CONFIG_VERIFY_NAME_ON_CONNECT_KEY);\n    if (verify_opt != NULL && !_z_opt_is_true(verify_opt)) {\n        verify_name = false;\n    }\n\n    bool enable_mtls = false;\n    const char *mtls_opt = _z_str_intmap_get(config, TLS_CONFIG_ENABLE_MTLS_KEY);\n    if (mtls_opt != NULL && _z_opt_is_true(mtls_opt)) {\n        enable_mtls = true;\n    }\n    sock->_tls_ctx = _z_tls_context_new();\n    if (sock->_tls_ctx == NULL) {\n        _Z_ERROR(\"Failed to create TLS context\");\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    if (enable_mtls) {\n        z_result_t ret_client = _z_tls_load_client_cert(sock->_tls_ctx, config);\n        if (ret_client != _Z_RES_OK) {\n            _z_tls_context_free(&sock->_tls_ctx);\n            return ret_client;\n        }\n    }\n    sock->_tls_ctx->_enable_mtls = enable_mtls;\n\n    z_result_t ret = _z_tls_load_ca_certificate(sock->_tls_ctx, config);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Failed to load CA certificate\");\n        _z_tls_context_free(&sock->_tls_ctx);\n        return ret;\n    }\n\n    ret = _z_tcp_open(&sock->_sock, *rep, Z_CONFIG_SOCKET_TIMEOUT);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Failed to open lower TCP socket: %d\", ret);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return ret;\n    }\n\n    // Needed for _read_socket_f callback which requires TLS context\n    sock->_sock._tls_sock = (void *)sock;\n\n    int mbedret = mbedtls_ssl_config_defaults(&sock->_tls_ctx->_ssl_config, MBEDTLS_SSL_IS_CLIENT,\n                                              MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);\n    if (mbedret != 0) {\n        _Z_ERROR(\"Failed to set SSL config defaults: -0x%04x\", -mbedret);\n        _z_tcp_close(&sock->_sock);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return _Z_ERR_GENERIC;\n    }\n\n    if (sock->_tls_ctx->_ca_cert.version != 0) {\n        mbedtls_ssl_conf_ca_chain(&sock->_tls_ctx->_ssl_config, &sock->_tls_ctx->_ca_cert, NULL);\n    }\n    mbedtls_ssl_conf_authmode(&sock->_tls_ctx->_ssl_config,\n                              verify_name ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_OPTIONAL);\n    mbedtls_ssl_conf_rng(&sock->_tls_ctx->_ssl_config, mbedtls_hmac_drbg_random, &sock->_tls_ctx->_hmac_drbg);\n\n    if (enable_mtls) {\n        int own_ret = mbedtls_ssl_conf_own_cert(&sock->_tls_ctx->_ssl_config, &sock->_tls_ctx->_client_cert,\n                                                &sock->_tls_ctx->_client_key);\n        if (own_ret != 0) {\n            _Z_ERROR(\"Failed to configure client certificate: -0x%04x\", -own_ret);\n            _z_tcp_close(&sock->_sock);\n            _z_tls_context_free(&sock->_tls_ctx);\n            return _Z_ERR_GENERIC;\n        }\n    }\n\n    mbedret = mbedtls_ssl_setup(&sock->_tls_ctx->_ssl, &sock->_tls_ctx->_ssl_config);\n    if (mbedret != 0) {\n        _Z_ERROR(\"Failed to setup SSL: -0x%04x\", -mbedret);\n        _z_tcp_close(&sock->_sock);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return _Z_ERR_GENERIC;\n    }\n\n    if (!hostname) {\n        _Z_ERROR(\"No hostname is set\");\n        _z_tcp_close(&sock->_sock);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return _Z_ERR_GENERIC;\n    }\n\n    mbedret = mbedtls_ssl_set_hostname(&sock->_tls_ctx->_ssl, hostname);\n    if (mbedret != 0) {\n        _Z_ERROR(\"Failed to set hostname: -0x%04x\", -mbedret);\n        _z_tcp_close(&sock->_sock);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return _Z_ERR_GENERIC;\n    }\n\n    mbedtls_ssl_set_bio(&sock->_tls_ctx->_ssl, &sock->_sock._fd, _z_tls_bio_send, _z_tls_bio_recv, NULL);\n\n    while ((mbedret = mbedtls_ssl_handshake(&sock->_tls_ctx->_ssl)) != 0) {\n        if (mbedret != MBEDTLS_ERR_SSL_WANT_READ && mbedret != MBEDTLS_ERR_SSL_WANT_WRITE) {\n            _Z_ERROR(\"TLS handshake failed: -0x%04x\", -mbedret);\n            _z_tcp_close(&sock->_sock);\n            _z_tls_context_free(&sock->_tls_ctx);\n            return _Z_ERR_GENERIC;\n        }\n    }\n\n    uint32_t ignored_flags = verify_name ? 0u : MBEDTLS_X509_BADCERT_CN_MISMATCH;\n    uint32_t verify_result = mbedtls_ssl_get_verify_result(&sock->_tls_ctx->_ssl);\n    if (verify_result != 0) {\n        if ((verify_result & ~ignored_flags) != 0u) {\n            _Z_ERROR(\"TLS client certificate verification failed: 0x%08x\", verify_result);\n            _z_tcp_close(&sock->_sock);\n            _z_tls_context_free(&sock->_tls_ctx);\n            return _Z_ERR_GENERIC;\n        }\n        if (!verify_name) {\n            _Z_INFO(\"TLS client name verification disabled; ignoring certificate name mismatch\");\n        }\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_listen_tls(_z_tls_socket_t *sock, const _z_sys_net_endpoint_t *rep, const _z_str_intmap_t *config) {\n    if ((rep == NULL) || (rep->_iptcp == NULL)) {\n        _Z_ERROR(\"Invalid lower TCP endpoint for TLS listen\");\n        return _Z_ERR_GENERIC;\n    }\n\n    sock->_is_peer_socket = false;\n    bool enable_mtls = false;\n    const char *mtls_opt = _z_str_intmap_get(config, TLS_CONFIG_ENABLE_MTLS_KEY);\n    if (mtls_opt != NULL && _z_opt_is_true(mtls_opt)) {\n        enable_mtls = true;\n    }\n    sock->_tls_ctx = _z_tls_context_new();\n    if (sock->_tls_ctx == NULL) {\n        _Z_ERROR(\"Failed to create TLS context\");\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    z_result_t ret = _z_tls_load_ca_certificate(sock->_tls_ctx, config);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Failed to load CA certificate\");\n        _z_tls_context_free(&sock->_tls_ctx);\n        return ret;\n    }\n\n    ret = _z_tls_load_listen_cert(sock->_tls_ctx, config);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Failed to load listening side certificate\");\n        _z_tls_context_free(&sock->_tls_ctx);\n        return ret;\n    }\n    sock->_tls_ctx->_enable_mtls = enable_mtls;\n\n    ret = _z_tcp_listen(&sock->_sock, *rep);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Failed to listen on lower TCP socket for TLS, ret=%d\", ret);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return ret;\n    }\n\n    // Needed for _read_socket_f callback which requires TLS context\n    sock->_sock._tls_sock = (void *)sock;\n\n    int mbedret = mbedtls_ssl_config_defaults(&sock->_tls_ctx->_ssl_config, MBEDTLS_SSL_IS_SERVER,\n                                              MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);\n    if (mbedret != 0) {\n        _Z_ERROR(\"Failed to set SSL config defaults for server: -0x%04x\", -mbedret);\n        _z_tcp_close(&sock->_sock);\n        _z_tls_context_free(&sock->_tls_ctx);\n        return _Z_ERR_GENERIC;\n    }\n\n    if (sock->_tls_ctx->_ca_cert.version != 0) {\n        mbedtls_ssl_conf_ca_chain(&sock->_tls_ctx->_ssl_config, &sock->_tls_ctx->_ca_cert, NULL);\n    }\n\n    if (sock->_tls_ctx->_listen_cert.version != 0) {\n        mbedret = mbedtls_ssl_conf_own_cert(&sock->_tls_ctx->_ssl_config, &sock->_tls_ctx->_listen_cert,\n                                            &sock->_tls_ctx->_listen_key);\n        if (mbedret != 0) {\n            _Z_ERROR(\"Failed to configure server certificate: -0x%04x\", -mbedret);\n            _z_tcp_close(&sock->_sock);\n            _z_tls_context_free(&sock->_tls_ctx);\n            return _Z_ERR_GENERIC;\n        }\n    }\n\n    mbedtls_ssl_conf_authmode(&sock->_tls_ctx->_ssl_config,\n                              enable_mtls ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE);\n    mbedtls_ssl_conf_rng(&sock->_tls_ctx->_ssl_config, mbedtls_hmac_drbg_random, &sock->_tls_ctx->_hmac_drbg);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_tls_accept(_z_sys_net_socket_t *socket, const _z_sys_net_socket_t *listen_sock) {\n    socket->_tls_sock = z_malloc(sizeof(_z_tls_socket_t));\n    if (socket->_tls_sock == NULL) {\n        _Z_ERROR(\"Failed to allocate TLS socket structure\");\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    _z_tls_socket_t *tls_sock = (_z_tls_socket_t *)socket->_tls_sock;\n    tls_sock->_tls_ctx = _z_tls_context_new();\n    if (tls_sock->_tls_ctx == NULL) {\n        _Z_ERROR(\"Failed to create TLS context\");\n        z_free(socket->_tls_sock);\n        socket->_tls_sock = NULL;\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    if (listen_sock == NULL) {\n        _Z_ERROR(\"Listening TLS socket is NULL\");\n        _z_tls_context_free(&tls_sock->_tls_ctx);\n        z_free(socket->_tls_sock);\n        socket->_tls_sock = NULL;\n        return _Z_ERR_GENERIC;\n    }\n\n    tls_sock->_sock = *socket;\n\n    mbedtls_ssl_init(&tls_sock->_tls_ctx->_ssl);\n    // Setup SSL context using the listen socket's configuration\n    _z_tls_socket_t *listen_tls_sock = (_z_tls_socket_t *)listen_sock->_tls_sock;\n    if (listen_tls_sock == NULL || listen_tls_sock->_tls_ctx == NULL) {\n        _Z_ERROR(\"Listening TLS socket's TLS context is NULL\");\n        _z_tls_context_free(&tls_sock->_tls_ctx);\n        z_free(socket->_tls_sock);\n        socket->_tls_sock = NULL;\n        return _Z_ERR_GENERIC;\n    }\n\n    tls_sock->_tls_ctx->_enable_mtls = listen_tls_sock->_tls_ctx->_enable_mtls;\n\n    mbedtls_ssl_config *listen_conf = &listen_tls_sock->_tls_ctx->_ssl_config;\n    int mbedret = mbedtls_ssl_setup(&tls_sock->_tls_ctx->_ssl, listen_conf);\n    if (mbedret != 0) {\n        _Z_ERROR(\"Failed to setup SSL: -0x%04x\", -mbedret);\n        _z_tls_context_free(&tls_sock->_tls_ctx);\n        z_free(socket->_tls_sock);\n        socket->_tls_sock = NULL;\n        return _Z_ERR_GENERIC;\n    }\n\n    mbedtls_ssl_set_bio(&tls_sock->_tls_ctx->_ssl, &tls_sock->_sock._fd, _z_tls_bio_send, _z_tls_bio_recv, NULL);\n\n    while ((mbedret = mbedtls_ssl_handshake(&tls_sock->_tls_ctx->_ssl)) != 0) {\n        if (mbedret != MBEDTLS_ERR_SSL_WANT_READ && mbedret != MBEDTLS_ERR_SSL_WANT_WRITE) {\n            _Z_ERROR(\"TLS server handshake failed: -0x%04x\", -mbedret);\n            _z_tls_context_free(&tls_sock->_tls_ctx);\n            z_free(socket->_tls_sock);\n            socket->_tls_sock = NULL;\n            return _Z_ERR_GENERIC;\n        }\n    }\n    uint32_t verify_result = mbedtls_ssl_get_verify_result(&tls_sock->_tls_ctx->_ssl);\n    if (verify_result != 0) {\n        uint32_t allowed_flags = 0u;\n        if (!tls_sock->_tls_ctx->_enable_mtls) {\n            allowed_flags |= MBEDTLS_X509_BADCERT_SKIP_VERIFY;\n        }\n        if ((verify_result & ~allowed_flags) != 0u) {\n            _Z_ERROR(\"TLS client certificate verification failed: 0x%08x\", verify_result);\n            _z_tls_context_free(&tls_sock->_tls_ctx);\n            z_free(socket->_tls_sock);\n            socket->_tls_sock = NULL;\n            return _Z_ERR_GENERIC;\n        }\n    }\n\n    tls_sock->_is_peer_socket = true;\n    tls_sock->_sock._tls_sock = (void *)tls_sock;\n    socket->_fd = tls_sock->_sock._fd;\n    socket->_tls_sock = (void *)tls_sock;\n    return _Z_RES_OK;\n}\n\nvoid _z_close_tls_socket(_z_sys_net_socket_t *socket) {\n    if (socket == NULL) {\n        return;\n    }\n    if (socket->_tls_sock == NULL) {\n        return;\n    }\n\n    _z_tls_socket_t *tls_sock = (_z_tls_socket_t *)socket->_tls_sock;\n    bool peer_socket = tls_sock->_is_peer_socket;\n    _z_close_tls(tls_sock);\n    if (peer_socket) {\n        z_free(tls_sock);\n    }\n\n    socket->_tls_sock = NULL;\n    socket->_fd = -1;\n}\n\nvoid _z_close_tls(_z_tls_socket_t *sock) {\n    if (sock->_tls_ctx != NULL) {\n        mbedtls_ssl_close_notify(&sock->_tls_ctx->_ssl);\n        _z_tls_context_free(&sock->_tls_ctx);\n    }\n    _z_tcp_close(&sock->_sock);\n    sock->_sock._tls_sock = NULL;\n}\n\nsize_t _z_read_tls(const _z_tls_socket_t *sock, uint8_t *ptr, size_t len) {\n    if (sock->_tls_ctx == NULL) {\n        _Z_ERROR(\"TLS context is NULL\");\n        return SIZE_MAX;\n    }\n\n    int ret = mbedtls_ssl_read(&sock->_tls_ctx->_ssl, ptr, len);\n    if (ret > 0) {\n        return (size_t)ret;\n    }\n\n    if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {\n        return 0;\n    }\n\n    if (ret == 0 || ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY || ret == MBEDTLS_ERR_SSL_CONN_EOF) {\n        return SIZE_MAX;\n    }\n\n    _Z_ERROR(\"TLS read error: %d\", ret);\n    return SIZE_MAX;\n}\n\nsize_t _z_write_tls(const _z_tls_socket_t *sock, const uint8_t *ptr, size_t len) {\n    if (sock->_tls_ctx == NULL) {\n        _Z_ERROR(\"TLS context is NULL\");\n        return SIZE_MAX;\n    }\n    int ret = mbedtls_ssl_write(&sock->_tls_ctx->_ssl, ptr, len);\n    if (ret > 0) {\n        return (size_t)ret;\n    }\n\n    if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {\n        return 0;\n    }\n\n    _Z_ERROR(\"TLS write error: -0x%04x\", -ret);\n    return SIZE_MAX;\n}\n\nsize_t _z_write_all_tls(const _z_tls_socket_t *sock, const uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    do {\n        size_t wb = _z_write_tls(sock, &ptr[n], len - n);\n        if (wb == SIZE_MAX) {\n            return wb;\n        }\n        n += wb;\n    } while (n < len);\n    return n;\n}\n\n#endif  // Z_FEATURE_LINK_TLS == 1\n"
  },
  {
    "path": "src/link/transport/upper/ws_emscripten.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_EMSCRIPTEN) && Z_FEATURE_LINK_WS == 1\n\n#include <arpa/inet.h>\n#include <emscripten/websocket.h>\n#include <netdb.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/link/transport/ws.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#define WS_LINK_SLEEP 1\n\nstatic z_result_t _z_ws_emscripten_create_endpoint(_z_sys_net_endpoint_t *ep, const char *s_addr, const char *s_port) {\n    z_result_t ret = _Z_RES_OK;\n\n    struct addrinfo hints;\n    ep->_iptcp = NULL;\n    (void)memset(&hints, 0, sizeof(hints));\n    hints.ai_family = PF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_flags = 0;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    if (getaddrinfo(s_addr, s_port, &hints, &ep->_iptcp) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic void _z_ws_emscripten_free_endpoint(_z_sys_net_endpoint_t *ep) { freeaddrinfo(ep->_iptcp); }\n\nstatic z_result_t _z_ws_emscripten_open(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout) {\n    z_result_t ret = _Z_RES_OK;\n\n    sock->_ws._fd = socket(rep._iptcp->ai_family, rep._iptcp->ai_socktype, rep._iptcp->ai_protocol);\n    if (sock->_ws._fd != -1) {\n        // WARNING: commented because setsockopt is not implemented in emscripten\n        // if ((ret == _Z_RES_OK) && (setsockopt(sock->_ws._fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0))\n        // {\n        //     ret = _Z_ERR_GENERIC;\n        // }\n        sock->_ws._tout = tout;  // We are storing the timeout that we are going to use when sending and receiving\n\n        struct addrinfo *it = NULL;\n        for (it = rep._iptcp; it != NULL; it = it->ai_next) {\n            if ((ret == _Z_RES_OK) && (connect(sock->_ws._fd, it->ai_addr, it->ai_addrlen) < 0)) {\n                break;\n                // WARNING: breaking here because connect returns -1 even if the\n                // underlying socket is actually open.\n\n                // if (it->ai_next == NULL) {\n                //     ret = _Z_ERR_GENERIC;\n                //     break;\n                // }\n            } else {\n                break;\n            }\n        }\n\n        // WARNING: workaround as connect returns before the websocket is\n        // actually open.\n        z_sleep_ms(100);\n\n        if (ret != _Z_RES_OK) {\n            close(sock->_ws._fd);\n        }\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_ws_emscripten_listen(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t lep) {\n    z_result_t ret = _Z_RES_OK;\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(lep);\n\n    // @TODO: To be implemented\n    _Z_ERROR_LOG(_Z_ERR_GENERIC);\n    ret = _Z_ERR_GENERIC;\n\n    return ret;\n}\n\nstatic void _z_ws_emscripten_close(_z_sys_net_socket_t *sock) { close(sock->_ws._fd); }\n\nstatic size_t _z_ws_emscripten_read(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    // WARNING: workaroud implementing here the timeout\n    ssize_t rb = 0;\n    z_time_t start = z_time_now();\n    while ((z_time_elapsed_ms(&start) < sock._ws._tout) && (rb <= 0)) {\n        z_sleep_ms(WS_LINK_SLEEP);\n        rb = recv(sock._ws._fd, ptr, len, 0);\n    }\n    if (rb < 0) {\n        rb = SIZE_MAX;\n    }\n    return (size_t)rb;\n}\n\nstatic size_t _z_ws_emscripten_read_exact(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) {\n    size_t n = 0;\n    uint8_t *pos = &ptr[0];\n\n    do {\n        size_t rb = _z_ws_emscripten_read(sock, pos, len - n);\n        if ((rb == SIZE_MAX) || (rb == 0)) {\n            n = rb;\n            break;\n        }\n\n        n = n + rb;\n        pos = _z_ptr_u8_offset(pos, rb);\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_ws_emscripten_write(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) {\n    // WARNING: workaroud implementing here the timeout\n    ssize_t sb = 0;\n    z_time_t start = z_time_now();\n    while ((z_time_elapsed_ms(&start) < sock._ws._tout) && (sb <= 0)) {\n        z_sleep_ms(WS_LINK_SLEEP);\n        sb = send(sock._ws._fd, ptr, len, 0);\n    }\n    // WARNING: workaround as the recv returns -1 not only in case of errors\n    if (sb < 0) {\n        sb = 0;\n    }\n    return (size_t)sb;\n}\n\nz_result_t _z_ws_endpoint_init(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    z_result_t ret = _Z_RES_OK;\n    char *host = _z_endpoint_parse_host(address);\n    char *port = _z_endpoint_parse_port(address);\n\n    if ((host == NULL) || (port == NULL)) {\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n    } else {\n        ret = _z_ws_emscripten_create_endpoint(ep, host, port);\n    }\n\n    z_free(host);\n    z_free(port);\n    return ret;\n}\n\nvoid _z_ws_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_ws_emscripten_free_endpoint(ep); }\n\nz_result_t _z_ws_transport_open(_z_ws_socket_t *sock, uint32_t tout) {\n    return _z_ws_emscripten_open(&sock->_sock, sock->_rep, tout);\n}\n\nz_result_t _z_ws_transport_listen(_z_ws_socket_t *sock) { return _z_ws_emscripten_listen(&sock->_sock, sock->_rep); }\n\nvoid _z_ws_transport_close(_z_ws_socket_t *sock) { _z_ws_emscripten_close(&sock->_sock); }\n\nsize_t _z_ws_transport_read(const _z_ws_socket_t *sock, uint8_t *ptr, size_t len) {\n    return _z_ws_emscripten_read(sock->_sock, ptr, len);\n}\n\nsize_t _z_ws_transport_read_exact(const _z_ws_socket_t *sock, uint8_t *ptr, size_t len) {\n    return _z_ws_emscripten_read_exact(sock->_sock, ptr, len);\n}\n\nsize_t _z_ws_transport_write(const _z_ws_socket_t *sock, const uint8_t *ptr, size_t len) {\n    return _z_ws_emscripten_write(sock->_sock, ptr, len);\n}\n\nsize_t _z_ws_transport_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    return _z_ws_emscripten_read(socket, ptr, len);\n}\n\n#else\ntypedef int _zp_ws_emscripten_transport_disabled_t;\n#endif\n"
  },
  {
    "path": "src/link/transport/upper/ws_stream.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/tcp.h\"\n#include \"zenoh-pico/link/transport/ws.h\"\n\n#if Z_FEATURE_LINK_WS == 1\n\nz_result_t _z_ws_endpoint_init(_z_sys_net_endpoint_t *ep, const _z_string_t *address) {\n    return _z_tcp_endpoint_init_from_address(ep, address);\n}\n\nvoid _z_ws_endpoint_clear(_z_sys_net_endpoint_t *ep) { _z_tcp_endpoint_clear(ep); }\n\nz_result_t _z_ws_transport_open(_z_ws_socket_t *sock, uint32_t tout) {\n    return _z_tcp_open(&sock->_sock, sock->_rep, tout);\n}\n\nz_result_t _z_ws_transport_listen(_z_ws_socket_t *sock) { return _z_tcp_listen(&sock->_sock, sock->_rep); }\n\nvoid _z_ws_transport_close(_z_ws_socket_t *sock) { _z_tcp_close(&sock->_sock); }\n\nsize_t _z_ws_transport_read(const _z_ws_socket_t *sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_read(sock->_sock, ptr, len);\n}\n\nsize_t _z_ws_transport_read_exact(const _z_ws_socket_t *sock, uint8_t *ptr, size_t len) {\n    return _z_tcp_read_exact(sock->_sock, ptr, len);\n}\n\nsize_t _z_ws_transport_write(const _z_ws_socket_t *sock, const uint8_t *ptr, size_t len) {\n    return _z_tcp_write(sock->_sock, ptr, len);\n}\n\nsize_t _z_ws_transport_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    return _z_tcp_read(socket, ptr, len);\n}\n\n#endif\n"
  },
  {
    "path": "src/link/unicast/serial.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/serial_protocol.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1\n\nz_result_t _z_endpoint_serial_valid(_z_endpoint_t *endpoint) { return _z_serial_endpoint_valid(endpoint); }\n\nz_result_t _z_f_link_open_serial(_z_link_t *self) {\n    return _z_serial_protocol_open(&self->_socket._serial, &self->_endpoint);\n}\n\nz_result_t _z_f_link_listen_serial(_z_link_t *self) {\n    return _z_serial_protocol_listen(&self->_socket._serial, &self->_endpoint);\n}\n\nvoid _z_f_link_close_serial(_z_link_t *self) { _z_serial_protocol_close(&self->_socket._serial); }\n\nvoid _z_f_link_free_serial(_z_link_t *self) { (void)(self); }\n\nsize_t _z_f_link_write_serial(const _z_link_t *self, const uint8_t *ptr, size_t len, _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    return _z_send_serial(self->_socket._serial._sock, ptr, len);\n}\n\nsize_t _z_f_link_write_all_serial(const _z_link_t *self, const uint8_t *ptr, size_t len) {\n    return _z_send_serial(self->_socket._serial._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_serial(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    _ZP_UNUSED(addr);\n    return _z_read_serial(self->_socket._serial._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_exact_serial(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                   _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(addr);\n    _ZP_UNUSED(socket);\n    return _z_read_exact_serial(self->_socket._serial._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_socket_serial(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    return _z_read_serial(socket, ptr, len);\n}\n\nuint16_t _z_get_link_mtu_serial(void) { return _Z_SERIAL_MTU_SIZE; }\n\nz_result_t _z_new_link_serial(_z_link_t *zl, _z_endpoint_t endpoint) {\n    z_result_t ret = _Z_RES_OK;\n    zl->_type = _Z_LINK_TYPE_SERIAL;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_UNICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_DATAGRAM;\n    zl->_cap._is_reliable = false;\n\n    zl->_mtu = _z_get_link_mtu_serial();\n\n    zl->_endpoint = endpoint;\n\n    zl->_open_f = _z_f_link_open_serial;\n    zl->_listen_f = _z_f_link_listen_serial;\n    zl->_close_f = _z_f_link_close_serial;\n    zl->_free_f = _z_f_link_free_serial;\n\n    zl->_write_f = _z_f_link_write_serial;\n    zl->_write_all_f = _z_f_link_write_all_serial;\n    zl->_read_f = _z_f_link_read_serial;\n    zl->_read_exact_f = _z_f_link_read_exact_serial;\n    zl->_read_socket_f = _z_f_link_read_socket_serial;\n\n    return ret;\n}\n#endif\n"
  },
  {
    "path": "src/link/unicast/tcp.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/tcp.h\"\n\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/tcp.h\"\n\n#if Z_FEATURE_LINK_TCP == 1\n\nz_result_t _z_endpoint_tcp_valid(_z_endpoint_t *endpoint) {\n    _z_string_t tcp_str = _z_string_alias_str(TCP_SCHEMA);\n    if (!_z_string_equals(&endpoint->_locator._protocol, &tcp_str)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    z_result_t ret = _z_tcp_address_valid(&endpoint->_locator._address);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    return ret;\n}\n\nz_result_t _z_f_link_open_tcp(_z_link_t *zl) {\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&zl->_endpoint._config, TCP_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    return _z_tcp_open(&zl->_socket._tcp._sock, zl->_socket._tcp._rep, tout);\n}\n\nz_result_t _z_f_link_listen_tcp(_z_link_t *zl) { return _z_tcp_listen(&zl->_socket._tcp._sock, zl->_socket._tcp._rep); }\n\nvoid _z_f_link_close_tcp(_z_link_t *zl) { _z_tcp_close(&zl->_socket._tcp._sock); }\n\nvoid _z_f_link_free_tcp(_z_link_t *zl) { _z_tcp_endpoint_clear(&zl->_socket._tcp._rep); }\n\nsize_t _z_f_link_write_tcp(const _z_link_t *zl, const uint8_t *ptr, size_t len, _z_sys_net_socket_t *socket) {\n    if (socket != NULL) {\n        return _z_tcp_write(*socket, ptr, len);\n    } else {\n        return _z_tcp_write(zl->_socket._tcp._sock, ptr, len);\n    }\n}\n\nsize_t _z_f_link_write_all_tcp(const _z_link_t *zl, const uint8_t *ptr, size_t len) {\n    return _z_tcp_write(zl->_socket._tcp._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_tcp(const _z_link_t *zl, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    _ZP_UNUSED(addr);\n    return _z_tcp_read(zl->_socket._tcp._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_exact_tcp(const _z_link_t *zl, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(addr);\n    if (socket != NULL) {\n        return _z_tcp_read_exact(*socket, ptr, len);\n    } else {\n        return _z_tcp_read_exact(zl->_socket._tcp._sock, ptr, len);\n    }\n}\n\nsize_t _z_f_link_tcp_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    return _z_tcp_read(socket, ptr, len);\n}\n\nuint16_t _z_get_link_mtu_tcp(void) {\n    // Maximum MTU for TCP\n    return 65535;\n}\n\nz_result_t _z_new_peer_tcp(_z_endpoint_t *endpoint, _z_sys_net_socket_t *socket) {\n    _z_sys_net_endpoint_t sys_endpoint = {0};\n    z_result_t ret = _z_tcp_endpoint_init_from_address(&sys_endpoint, &endpoint->_locator._address);\n\n    if (ret != _Z_RES_OK) {\n        _z_tcp_endpoint_clear(&sys_endpoint);\n        return ret;\n    }\n\n    ret = _z_tcp_open(socket, sys_endpoint, Z_CONFIG_SOCKET_TIMEOUT);\n    _z_tcp_endpoint_clear(&sys_endpoint);\n    return ret;\n}\n\nz_result_t _z_new_link_tcp(_z_link_t *zl, _z_endpoint_t *endpoint) {\n    zl->_type = _Z_LINK_TYPE_TCP;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_UNICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_STREAM;\n    zl->_cap._is_reliable = true;\n\n    zl->_mtu = _z_get_link_mtu_tcp();\n\n    zl->_endpoint = *endpoint;\n    z_result_t ret = _z_tcp_endpoint_init_from_address(&zl->_socket._tcp._rep, &endpoint->_locator._address);\n\n    zl->_open_f = _z_f_link_open_tcp;\n    zl->_listen_f = _z_f_link_listen_tcp;\n    zl->_close_f = _z_f_link_close_tcp;\n    zl->_free_f = _z_f_link_free_tcp;\n\n    zl->_write_f = _z_f_link_write_tcp;\n    zl->_write_all_f = _z_f_link_write_all_tcp;\n    zl->_read_f = _z_f_link_read_tcp;\n    zl->_read_exact_f = _z_f_link_read_exact_tcp;\n    zl->_read_socket_f = _z_f_link_tcp_read_socket;\n\n    return ret;\n}\n#else\nz_result_t _z_endpoint_tcp_valid(_z_endpoint_t *endpoint) {\n    _ZP_UNUSED(endpoint);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_new_peer_tcp(_z_endpoint_t *endpoint, _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(endpoint);\n    _ZP_UNUSED(socket);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_new_link_tcp(_z_link_t *zl, _z_endpoint_t *endpoint) {\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(endpoint);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif\n"
  },
  {
    "path": "src/link/unicast/tls.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/tls.h\"\n\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/tcp.h\"\n#include \"zenoh-pico/link/transport/tls_stream.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#if Z_FEATURE_LINK_TLS == 1\n\nuint16_t _z_get_link_mtu_tls(void) { return 65535; }\n\nz_result_t _z_endpoint_tls_valid(_z_endpoint_t *endpoint) {\n    _z_string_t tls_str = _z_string_alias_str(TLS_SCHEMA);\n    if (!_z_string_equals(&endpoint->_locator._protocol, &tls_str)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    z_result_t ret = _z_tcp_address_valid(&endpoint->_locator._address);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    return ret;\n}\n\nstatic _z_config_t _z_tls_merge_config(_z_str_intmap_t *endpoint_cfg, const _z_config_t *session_cfg) {\n    _z_config_t cfg;\n    if (endpoint_cfg != NULL) {\n        _z_str_intmap_move(&cfg, endpoint_cfg);\n    } else {\n        cfg = _z_str_intmap_make();\n    }\n    if (session_cfg == NULL) {\n        return cfg;\n    }\n    static const struct {\n        uint8_t locator_key;\n        uint8_t session_key;\n    } mapping[] = {{TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY, Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY},\n                   {TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_KEY, Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY},\n                   {TLS_CONFIG_LISTEN_PRIVATE_KEY_KEY, Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_KEY},\n                   {TLS_CONFIG_LISTEN_PRIVATE_KEY_BASE64_KEY, Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_BASE64_KEY},\n                   {TLS_CONFIG_LISTEN_CERTIFICATE_KEY, Z_CONFIG_TLS_LISTEN_CERTIFICATE_KEY},\n                   {TLS_CONFIG_LISTEN_CERTIFICATE_BASE64_KEY, Z_CONFIG_TLS_LISTEN_CERTIFICATE_BASE64_KEY},\n                   {TLS_CONFIG_ENABLE_MTLS_KEY, Z_CONFIG_TLS_ENABLE_MTLS_KEY},\n                   {TLS_CONFIG_CONNECT_PRIVATE_KEY_KEY, Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_KEY},\n                   {TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_KEY, Z_CONFIG_TLS_CONNECT_PRIVATE_KEY_BASE64_KEY},\n                   {TLS_CONFIG_CONNECT_CERTIFICATE_KEY, Z_CONFIG_TLS_CONNECT_CERTIFICATE_KEY},\n                   {TLS_CONFIG_CONNECT_CERTIFICATE_BASE64_KEY, Z_CONFIG_TLS_CONNECT_CERTIFICATE_BASE64_KEY},\n                   {TLS_CONFIG_VERIFY_NAME_ON_CONNECT_KEY, Z_CONFIG_TLS_VERIFY_NAME_ON_CONNECT_KEY}};\n\n    for (size_t i = 0; i < sizeof(mapping) / sizeof(mapping[0]); i++) {\n        if (_z_config_get(&cfg, mapping[i].locator_key) != NULL) {\n            continue;\n        }\n        const char *value = _z_config_get(session_cfg, mapping[i].session_key);\n        if (value != NULL) {\n            _zp_config_insert(&cfg, mapping[i].locator_key, value);\n        }\n    }\n    return cfg;\n}\n\nstatic z_result_t _z_f_link_open_tls(_z_link_t *self) {\n    z_result_t ret = _Z_RES_OK;\n\n    char *hostname = _z_tcp_address_parse_host(&self->_endpoint._locator._address);\n    if (hostname == NULL) {\n        _Z_ERROR(\"Failed to parse TLS endpoint address\");\n        z_free(hostname);\n        return _Z_ERR_GENERIC;\n    }\n\n    _z_sys_net_endpoint_t rep = {0};\n    ret = _z_tcp_endpoint_init_from_address(&rep, &self->_endpoint._locator._address);\n    if (ret != _Z_RES_OK) {\n        z_free(hostname);\n        return ret;\n    }\n\n    ret = _z_open_tls(&self->_socket._tls, &rep, hostname, &self->_endpoint._config, false);\n    _z_tcp_endpoint_clear(&rep);\n    z_free(hostname);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"TLS open failed\");\n    }\n    return ret;\n}\n\nstatic z_result_t _z_f_link_listen_tls(_z_link_t *self) {\n    z_result_t ret = _Z_RES_OK;\n\n    char *host = _z_tcp_address_parse_host(&self->_endpoint._locator._address);\n    if (host == NULL) {\n        _Z_ERROR(\"Invalid TLS endpoint\");\n        z_free(host);\n        return _Z_ERR_GENERIC;\n    }\n\n    _z_sys_net_endpoint_t rep = {0};\n    ret = _z_tcp_endpoint_init_from_address(&rep, &self->_endpoint._locator._address);\n    if (ret != _Z_RES_OK) {\n        z_free(host);\n        return ret;\n    }\n\n    ret = _z_listen_tls(&self->_socket._tls, &rep, &self->_endpoint._config);\n    _z_tcp_endpoint_clear(&rep);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"TLS listen failed\");\n    }\n\n    z_free(host);\n    return ret;\n}\n\nstatic void _z_f_link_close_tls(_z_link_t *self) { _z_close_tls(&self->_socket._tls); }\n\nstatic size_t _z_f_link_write_tls(const _z_link_t *self, const uint8_t *ptr, size_t len, _z_sys_net_socket_t *socket) {\n    // Use provided socket if available, otherwise fall back to link socket\n    if (socket != NULL && socket->_tls_sock != NULL) {\n        return _z_write_tls((_z_tls_socket_t *)socket->_tls_sock, ptr, len);\n    } else {\n        return _z_write_tls(&self->_socket._tls, ptr, len);\n    }\n}\n\nstatic size_t _z_f_link_write_all_tls(const _z_link_t *self, const uint8_t *ptr, size_t len) {\n    return _z_write_all_tls(&self->_socket._tls, ptr, len);\n}\n\nstatic size_t _z_f_link_read_tls(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    _ZP_UNUSED(addr);\n    return _z_read_tls(&self->_socket._tls, ptr, len);\n}\n\nstatic size_t _z_f_link_read_exact_tls(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                       _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(addr);\n\n    size_t n = (size_t)0;\n    do {\n        size_t rb;\n        if (socket != NULL && socket->_tls_sock != NULL) {\n            rb = _z_read_tls((_z_tls_socket_t *)socket->_tls_sock, &ptr[n], len - n);\n        } else {\n            rb = _z_read_tls(&self->_socket._tls, &ptr[n], len - n);\n        }\n\n        if (rb == SIZE_MAX) {\n            n = rb;\n            break;\n        }\n        n += rb;\n    } while (n != len);\n\n    return n;\n}\n\nstatic size_t _z_f_link_tls_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    if (socket._tls_sock == NULL) {\n        _Z_ERROR(\"TLS context not found in socket\");\n        return SIZE_MAX;\n    }\n    return _z_read_tls((_z_tls_socket_t *)socket._tls_sock, ptr, len);\n}\n\nstatic void _z_f_link_free_tls(_z_link_t *self) { _ZP_UNUSED(self); }\n\nz_result_t _z_new_link_tls(_z_link_t *zl, _z_endpoint_t *endpoint, const _z_config_t *session_cfg) {\n    zl->_type = _Z_LINK_TYPE_TLS;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_UNICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_STREAM;\n    zl->_cap._is_reliable = true;\n\n    zl->_mtu = _z_get_link_mtu_tls();\n\n    _z_config_t cfg = _z_tls_merge_config(&endpoint->_config, session_cfg);\n    zl->_endpoint = *endpoint;\n    zl->_endpoint._config = cfg;\n    _z_str_intmap_clear(&endpoint->_config);\n    _Z_DEBUG(\"TLS locator: '%.*s'\", (int)_z_string_len(&endpoint->_locator._address),\n             _z_string_data(&endpoint->_locator._address));\n\n    zl->_open_f = _z_f_link_open_tls;\n    zl->_listen_f = _z_f_link_listen_tls;\n    zl->_close_f = _z_f_link_close_tls;\n    zl->_write_f = _z_f_link_write_tls;\n    zl->_write_all_f = _z_f_link_write_all_tls;\n    zl->_read_f = _z_f_link_read_tls;\n    zl->_read_exact_f = _z_f_link_read_exact_tls;\n    zl->_read_socket_f = _z_f_link_tls_read_socket;\n    zl->_free_f = _z_f_link_free_tls;\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_new_peer_tls(_z_endpoint_t *endpoint, _z_sys_net_socket_t *socket, const _z_config_t *session_cfg) {\n    _z_sys_net_endpoint_t sys_endpoint = {0};\n    char *hostname = _z_tcp_address_parse_host(&endpoint->_locator._address);\n    z_result_t ret = _Z_RES_OK;\n    if (hostname == NULL) {\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n        goto cleanup;\n    }\n\n    ret = _z_tcp_endpoint_init_from_address(&sys_endpoint, &endpoint->_locator._address);\n    if (ret != _Z_RES_OK) {\n        goto cleanup;\n    }\n\n    socket->_tls_sock = z_malloc(sizeof(_z_tls_socket_t));\n    if (socket->_tls_sock == NULL) {\n        ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        goto cleanup;\n    }\n\n    _z_config_t cfg = _z_tls_merge_config(&endpoint->_config, session_cfg);\n    ret = _z_open_tls((_z_tls_socket_t *)socket->_tls_sock, &sys_endpoint, hostname, &cfg, true);\n    if (ret != _Z_RES_OK) {\n        z_free(socket->_tls_sock);\n        socket->_tls_sock = NULL;\n        _z_config_clear(&cfg);\n        _z_str_intmap_clear(&endpoint->_config);\n        goto cleanup;\n    }\n\n    socket->_fd = ((_z_tls_socket_t *)socket->_tls_sock)->_sock._fd;\n    _z_config_clear(&cfg);\n    _z_str_intmap_clear(&endpoint->_config);\n\ncleanup:\n    z_free(hostname);\n    _z_tcp_endpoint_clear(&sys_endpoint);\n    return ret;\n}\n\n#endif  // Z_FEATURE_LINK_TLS == 1\n"
  },
  {
    "path": "src/link/unicast/udp.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/udp.h\"\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/udp_unicast.h\"\n\n#if Z_FEATURE_LINK_UDP_UNICAST == 1\n\nz_result_t _z_endpoint_udp_unicast_valid(_z_endpoint_t *endpoint) {\n    _z_string_t udp_str = _z_string_alias_str(UDP_SCHEMA);\n    if (!_z_string_equals(&endpoint->_locator._protocol, &udp_str)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    z_result_t ret = _z_udp_unicast_address_valid(&endpoint->_locator._address);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    return ret;\n}\n\nz_result_t _z_f_link_open_udp_unicast(_z_link_t *self) {\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&self->_endpoint._config, UDP_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    return _z_udp_unicast_open(&self->_socket._udp._sock, self->_socket._udp._rep, tout);\n}\n\nz_result_t _z_f_link_listen_udp_unicast(_z_link_t *self) {\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&self->_endpoint._config, UDP_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    return _z_udp_unicast_listen(&self->_socket._udp._sock, self->_socket._udp._rep, tout);\n}\n\nvoid _z_f_link_close_udp_unicast(_z_link_t *self) { _z_udp_unicast_close(&self->_socket._udp._sock); }\n\nvoid _z_f_link_free_udp_unicast(_z_link_t *self) { _z_udp_unicast_endpoint_clear(&self->_socket._udp._rep); }\n\nsize_t _z_f_link_write_udp_unicast(const _z_link_t *self, const uint8_t *ptr, size_t len, _z_sys_net_socket_t *socket) {\n    if (socket != NULL) {\n        return _z_udp_unicast_write(*socket, ptr, len, self->_socket._udp._rep);\n    } else {\n        return _z_udp_unicast_write(self->_socket._udp._sock, ptr, len, self->_socket._udp._rep);\n    }\n}\n\nsize_t _z_f_link_write_all_udp_unicast(const _z_link_t *self, const uint8_t *ptr, size_t len) {\n    return _z_udp_unicast_write(self->_socket._udp._sock, ptr, len, self->_socket._udp._rep);\n}\n\nsize_t _z_f_link_read_udp_unicast(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    _ZP_UNUSED(addr);\n    return _z_udp_unicast_read(self->_socket._udp._sock, ptr, len);\n}\n\nsize_t _z_f_link_read_exact_udp_unicast(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                        _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(addr);\n    if (socket != NULL) {\n        return _z_udp_unicast_read_exact(*socket, ptr, len);\n    } else {\n        return _z_udp_unicast_read_exact(self->_socket._udp._sock, ptr, len);\n    }\n}\n\nsize_t _z_f_link_udp_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    return _z_udp_unicast_read(socket, ptr, len);\n}\n\nuint16_t _z_get_link_mtu_udp_unicast(void) {\n    // @TODO: the return value should change depending on the target platform.\n    return 1450;\n}\n\nz_result_t _z_new_link_udp_unicast(_z_link_t *zl, _z_endpoint_t endpoint) {\n    zl->_type = _Z_LINK_TYPE_UDP;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_UNICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_DATAGRAM;\n    zl->_cap._is_reliable = false;\n\n    zl->_mtu = _z_get_link_mtu_udp_unicast();\n\n    zl->_endpoint = endpoint;\n    z_result_t ret = _z_udp_unicast_endpoint_init_from_address(&zl->_socket._udp._rep, &endpoint._locator._address);\n\n    zl->_open_f = _z_f_link_open_udp_unicast;\n    zl->_listen_f = _z_f_link_listen_udp_unicast;\n    zl->_close_f = _z_f_link_close_udp_unicast;\n    zl->_free_f = _z_f_link_free_udp_unicast;\n\n    zl->_write_f = _z_f_link_write_udp_unicast;\n    zl->_write_all_f = _z_f_link_write_all_udp_unicast;\n    zl->_read_f = _z_f_link_read_udp_unicast;\n    zl->_read_exact_f = _z_f_link_read_exact_udp_unicast;\n    zl->_read_socket_f = _z_f_link_udp_read_socket;\n\n    return ret;\n}\n#endif\n"
  },
  {
    "path": "src/link/unicast/ws.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/config/ws.h\"\n\n#include <stddef.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/tcp.h\"\n#include \"zenoh-pico/link/transport/ws.h\"\n\n#if Z_FEATURE_LINK_WS == 1\n\nstatic z_result_t _z_ws_address_valid(const _z_string_t *address) { return _z_tcp_address_valid(address); }\n\nz_result_t _z_endpoint_ws_valid(_z_endpoint_t *endpoint) {\n    _z_string_t str = _z_string_alias_str(WS_SCHEMA);\n    if (!_z_string_equals(&endpoint->_locator._protocol, &str)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    z_result_t ret = _z_ws_address_valid(&endpoint->_locator._address);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n    }\n    return ret;\n}\n\nz_result_t _z_f_link_open_ws(_z_link_t *zl) {\n    uint32_t tout = Z_CONFIG_SOCKET_TIMEOUT;\n    char *tout_as_str = _z_str_intmap_get(&zl->_endpoint._config, WS_CONFIG_TOUT_KEY);\n    if (tout_as_str != NULL) {\n        tout = (uint32_t)strtoul(tout_as_str, NULL, 10);\n    }\n\n    return _z_ws_transport_open(&zl->_socket._ws, tout);\n}\n\nz_result_t _z_f_link_listen_ws(_z_link_t *zl) { return _z_ws_transport_listen(&zl->_socket._ws); }\n\nvoid _z_f_link_close_ws(_z_link_t *zl) { _z_ws_transport_close(&zl->_socket._ws); }\n\nvoid _z_f_link_free_ws(_z_link_t *zl) { _z_ws_endpoint_clear(&zl->_socket._ws._rep); }\n\nsize_t _z_f_link_write_ws(const _z_link_t *zl, const uint8_t *ptr, size_t len, _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    return _z_ws_transport_write(&zl->_socket._ws, ptr, len);\n}\n\nsize_t _z_f_link_write_all_ws(const _z_link_t *zl, const uint8_t *ptr, size_t len) {\n    return _z_ws_transport_write(&zl->_socket._ws, ptr, len);\n}\n\nsize_t _z_f_link_read_ws(const _z_link_t *zl, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    _ZP_UNUSED(addr);\n    return _z_ws_transport_read(&zl->_socket._ws, ptr, len);\n}\n\nsize_t _z_f_link_read_exact_ws(const _z_link_t *zl, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                               _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(addr);\n    _ZP_UNUSED(socket);\n    return _z_ws_transport_read_exact(&zl->_socket._ws, ptr, len);\n}\n\nsize_t _z_f_link_ws_read_socket(const _z_sys_net_socket_t socket, uint8_t *ptr, size_t len) {\n    return _z_ws_transport_read_socket(socket, ptr, len);\n}\n\nuint16_t _z_get_link_mtu_ws(void) {\n    // Maximum MTU for TCP\n    return 65535;\n}\n\nz_result_t _z_new_link_ws(_z_link_t *zl, _z_endpoint_t *endpoint) {\n    zl->_type = _Z_LINK_TYPE_WS;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_UNICAST;\n    zl->_cap._flow = Z_LINK_CAP_FLOW_DATAGRAM;\n    zl->_cap._is_reliable = true;\n\n    zl->_mtu = _z_get_link_mtu_ws();\n\n    zl->_endpoint = *endpoint;\n    z_result_t ret = _z_ws_endpoint_init(&zl->_socket._ws._rep, &endpoint->_locator._address);\n\n    zl->_open_f = _z_f_link_open_ws;\n    zl->_listen_f = _z_f_link_listen_ws;\n    zl->_close_f = _z_f_link_close_ws;\n    zl->_free_f = _z_f_link_free_ws;\n\n    zl->_write_f = _z_f_link_write_ws;\n    zl->_write_all_f = _z_f_link_write_all_ws;\n    zl->_read_f = _z_f_link_read_ws;\n    zl->_read_exact_f = _z_f_link_read_exact_ws;\n    zl->_read_socket_f = _z_f_link_ws_read_socket;\n\n    return ret;\n}\n#endif\n"
  },
  {
    "path": "src/net/config.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/config.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/net/config.h\"\n\n_z_config_t _z_config_empty(void) {\n    _z_config_t config;\n    _z_config_init(&config);\n    return config;\n}\n\nz_result_t _z_config_default(_z_config_t *config) { return _z_config_client(config, NULL); }\n\nz_result_t _z_config_client(_z_config_t *ps, const char *locator) {\n    *ps = _z_config_empty();\n    _Z_RETURN_IF_ERR(_zp_config_insert(ps, Z_CONFIG_MODE_KEY, Z_CONFIG_MODE_CLIENT));\n    if (locator != NULL) {\n        // Connect only to the provided locator\n        _Z_CLEAN_RETURN_IF_ERR(_zp_config_insert(ps, Z_CONFIG_CONNECT_KEY, locator), _z_config_clear(ps));\n    } else {\n        // The locator is not provided, we should perform scouting\n        _Z_CLEAN_RETURN_IF_ERR(\n            _zp_config_insert(ps, Z_CONFIG_MULTICAST_SCOUTING_KEY, Z_CONFIG_MULTICAST_SCOUTING_DEFAULT),\n            _z_config_clear(ps));\n        _Z_CLEAN_RETURN_IF_ERR(\n            _zp_config_insert(ps, Z_CONFIG_MULTICAST_LOCATOR_KEY, Z_CONFIG_MULTICAST_LOCATOR_DEFAULT),\n            _z_config_clear(ps));\n        _Z_CLEAN_RETURN_IF_ERR(_zp_config_insert(ps, Z_CONFIG_SCOUTING_TIMEOUT_KEY, Z_CONFIG_SCOUTING_TIMEOUT_DEFAULT),\n                               _z_config_clear(ps));\n    }\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/net/encoding.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/net/encoding.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n_z_encoding_t _z_encoding_wrap(uint16_t id, const char *schema) {\n    return (_z_encoding_t){.id = id,\n                           .schema = (schema == NULL) ? _z_string_null() : _z_string_alias_str((char *)schema)};\n}\n\nz_result_t _z_encoding_make(_z_encoding_t *encoding, uint16_t id, const char *schema, size_t len) {\n    encoding->id = id;\n    // Clone schema\n    if (schema != NULL) {\n        encoding->schema = _z_string_copy_from_substr(schema, len);\n        if (_z_string_len(&encoding->schema) != len) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n    } else {\n        encoding->schema = _z_string_null();\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_encoding_copy(_z_encoding_t *dst, const _z_encoding_t *src) {\n    dst->id = src->id;\n    if (_z_string_check(&src->schema)) {\n        _Z_RETURN_IF_ERR(_z_string_copy(&dst->schema, &src->schema));\n    } else {\n        dst->schema = _z_string_null();\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_encoding_move(_z_encoding_t *dst, _z_encoding_t *src) {\n    dst->id = src->id;\n    src->id = _Z_ENCODING_ID_DEFAULT;\n    dst->schema = _z_string_null();\n    if (_z_string_check(&src->schema)) {\n        _Z_RETURN_IF_ERR(_z_string_move(&dst->schema, &src->schema));\n    }\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/net/filtering.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/net/filtering.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/session/matching.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/locality.h\"\n\n#if Z_FEATURE_INTEREST == 1\n\ntypedef struct _z_write_filter_registration_t {\n    _z_write_filter_ctx_rc_t ctx_rc;\n    struct _z_write_filter_registration_t *next;\n} _z_write_filter_registration_t;\n\nstatic bool _z_filter_target_peer_eq(const void *left, const void *right) {\n    const _z_filter_target_t *left_val = (const _z_filter_target_t *)left;\n    const _z_filter_target_t *right_val = (const _z_filter_target_t *)right;\n    return left_val->peer == right_val->peer;\n}\n\nstatic bool _z_filter_target_eq(const void *left, const void *right) {\n    const _z_filter_target_t *left_val = (const _z_filter_target_t *)left;\n    const _z_filter_target_t *right_val = (const _z_filter_target_t *)right;\n    return (left_val->peer == right_val->peer) && (left_val->decl_id == right_val->decl_id);\n}\n\n#if Z_FEATURE_MULTI_THREAD == 1\nstatic void _z_write_filter_mutex_lock(_z_write_filter_ctx_t *ctx) { _z_mutex_lock(&ctx->mutex); }\nstatic void _z_write_filter_mutex_unlock(_z_write_filter_ctx_t *ctx) { _z_mutex_unlock(&ctx->mutex); }\n#else\nstatic void _z_write_filter_mutex_lock(_z_write_filter_ctx_t *ctx) { _ZP_UNUSED(ctx); }\nstatic void _z_write_filter_mutex_unlock(_z_write_filter_ctx_t *ctx) { _ZP_UNUSED(ctx); }\n#endif\n\nstatic bool _z_write_filter_push_target(_z_write_filter_ctx_t *ctx, _z_transport_peer_common_t *peer, uint32_t id) {\n    _z_filter_target_t target = {.peer = (uintptr_t)peer, .decl_id = id};\n    ctx->targets = _z_filter_target_slist_push(ctx->targets, &target);\n    if (ctx->targets == NULL) {  // Allocation can fail\n        return false;\n    }\n    return true;\n}\n\nstatic inline bool _z_write_filter_peer_allowed(const _z_write_filter_ctx_t *ctx, _z_transport_peer_common_t *peer) {\n    return ((peer == NULL) && ctx->allow_local) || ((peer != NULL) && ctx->allow_remote);\n}\n\nstatic void _z_write_filter_ctx_update_state(_z_write_filter_ctx_t *ctx) {\n    uint8_t prev_state = ctx->state;\n    ctx->state = (ctx->targets == NULL && ctx->local_targets == 0) ? WRITE_FILTER_ACTIVE : WRITE_FILTER_OFF;\n    if (prev_state != ctx->state) {\n        _Z_DEBUG(\"Updated write filter state: %d\", ctx->state);\n#if Z_FEATURE_MATCHING\n        _z_closure_matching_status_intmap_iterator_t it =\n            _z_closure_matching_status_intmap_iterator_make(&ctx->callbacks);\n        _z_matching_status_t s = {.matching = ctx->state != WRITE_FILTER_ACTIVE};\n        while (_z_closure_matching_status_intmap_iterator_next(&it)) {\n            _z_closure_matching_status_t *c = _z_closure_matching_status_intmap_iterator_value(&it);\n            c->call(&s, c->context);\n        }\n#endif\n    }\n}\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 || Z_FEATURE_LOCAL_QUERYABLE == 1\nstatic void _z_write_filter_ctx_add_local_match(_z_write_filter_ctx_t *ctx) {\n    _z_write_filter_mutex_lock(ctx);\n    ctx->local_targets++;\n    _z_write_filter_ctx_update_state(ctx);\n    _z_write_filter_mutex_unlock(ctx);\n}\n\nstatic void _z_write_filter_ctx_remove_local_match(_z_write_filter_ctx_t *ctx) {\n    _z_write_filter_mutex_lock(ctx);\n    if (ctx->local_targets > 0) {\n        ctx->local_targets--;\n    }\n    _z_write_filter_ctx_update_state(ctx);\n    _z_write_filter_mutex_unlock(ctx);\n}\n#endif\n\nstatic z_result_t _z_write_filter_session_register(_z_session_t *session, _z_write_filter_ctx_t *ctx,\n                                                   _z_write_filter_ctx_rc_t *ctx_rc) {\n    _z_write_filter_registration_t *registration =\n        (_z_write_filter_registration_t *)z_malloc(sizeof(_z_write_filter_registration_t));\n    if (registration == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    registration->ctx_rc = _z_write_filter_ctx_rc_clone(ctx_rc);\n    if (_Z_RC_IS_NULL(&registration->ctx_rc)) {\n        z_free(registration);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    if (_z_session_mutex_lock_if_open(session) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to lock session for write filter registration - session may be closing\");\n        _z_write_filter_ctx_rc_drop(&registration->ctx_rc);\n        z_free(registration);\n        return _Z_ERR_SESSION_CLOSED;\n    }\n    registration->next = session->_write_filters;\n    session->_write_filters = registration;\n\n#if (Z_FEATURE_LOCAL_SUBSCRIBER == 1) || (Z_FEATURE_LOCAL_QUERYABLE == 1)\n    if (ctx->allow_local) {\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n        if (ctx->target_type == _Z_WRITE_FILTER_SUBSCRIBER) {\n            _z_subscription_rc_slist_t *node = session->_subscriptions;\n            while (node != NULL) {\n                _z_subscription_t *sub = _Z_RC_IN_VAL(_z_subscription_rc_slist_value(node));\n                if (_z_locality_allows_local(sub->_allowed_origin) &&\n                    _z_keyexpr_intersects(&ctx->key, &sub->_key._inner)) {\n                    _z_write_filter_ctx_add_local_match(ctx);\n                }\n                node = _z_subscription_rc_slist_next(node);\n            }\n        }\n#endif\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n        if (ctx->target_type == _Z_WRITE_FILTER_QUERYABLE) {\n            _z_session_queryable_rc_slist_t *node = session->_local_queryable;\n            while (node != NULL) {\n                _z_session_queryable_t *queryable = _Z_RC_IN_VAL(_z_session_queryable_rc_slist_value(node));\n                if (_z_locality_allows_local(queryable->_allowed_origin)) {\n                    if (ctx->is_complete\n                            ? (queryable->_complete && _z_keyexpr_includes(&queryable->_key._inner, &ctx->key))\n                            : _z_keyexpr_intersects(&ctx->key, &queryable->_key._inner)) {\n                        _z_write_filter_ctx_add_local_match(ctx);\n                    }\n                }\n                node = _z_session_queryable_rc_slist_next(node);\n            }\n        }\n#endif\n    }\n#endif\n    _z_session_mutex_unlock(session);\n\n    ctx->registration = registration;\n    return _Z_RES_OK;\n}\n\nstatic void _z_write_filter_session_unregister(_z_write_filter_ctx_t *ctx) {\n    _z_write_filter_registration_t *registration = ctx->registration;\n    if (registration == NULL) {\n        return;\n    }\n    ctx->registration = NULL;\n\n    _z_session_rc_t session_rc = _z_session_weak_upgrade_if_open(&_Z_RC_IN_VAL(&registration->ctx_rc)->zn);\n    if (_Z_RC_IS_NULL(&session_rc)) {\n        _z_write_filter_ctx_rc_drop(&registration->ctx_rc);\n        z_free(registration);\n        return;\n    }\n    _z_session_t *session = _Z_RC_IN_VAL(&session_rc);\n    _z_session_mutex_lock(session);\n    _z_write_filter_registration_t **iter = &session->_write_filters;\n    while (*iter != NULL && *iter != registration) {\n        iter = &((*iter)->next);\n    }\n    if (*iter != NULL) {\n        *iter = registration->next;\n    }\n    _z_session_mutex_unlock(session);\n    _z_session_rc_drop(&session_rc);\n\n    _z_write_filter_ctx_rc_drop(&registration->ctx_rc);\n    z_free(registration);\n}\n\nstatic void _z_write_filter_callback(const _z_interest_msg_t *msg, _z_transport_peer_common_t *peer, void *arg) {\n    _z_write_filter_ctx_t *ctx = (_z_write_filter_ctx_t *)arg;\n    // Process message\n    _z_write_filter_mutex_lock(ctx);\n    switch (msg->type) {\n        case _Z_INTEREST_MSG_TYPE_DECL_SUBSCRIBER:\n        case _Z_INTEREST_MSG_TYPE_DECL_QUERYABLE: {\n            // the message might be a redeclare - so we need to remove the previous one first\n            _z_filter_target_t target = {.decl_id = msg->id, .peer = (uintptr_t)peer};\n            ctx->targets = _z_filter_target_slist_drop_first_filter(ctx->targets, _z_filter_target_eq, &target);\n            bool peer_allowed = _z_write_filter_peer_allowed(ctx, peer);\n            if (peer_allowed &&\n                (!ctx->is_complete ||\n                 (msg->is_complete && (ctx->is_aggregate || _z_keyexpr_includes(msg->key, &ctx->key))))) {\n                _z_write_filter_push_target(ctx, peer, msg->id);\n            }\n            break;\n        }\n        case _Z_INTEREST_MSG_TYPE_UNDECL_SUBSCRIBER:\n        case _Z_INTEREST_MSG_TYPE_UNDECL_QUERYABLE: {\n            _z_filter_target_t target = {.decl_id = msg->id, .peer = (uintptr_t)peer};\n            ctx->targets = _z_filter_target_slist_drop_first_filter(ctx->targets, _z_filter_target_eq, &target);\n        } break;\n        case _Z_INTEREST_MSG_TYPE_CONNECTION_DROPPED: {\n            _z_filter_target_t target = {.decl_id = 0, .peer = (uintptr_t)peer};\n            ctx->targets = _z_filter_target_slist_drop_all_filter(ctx->targets, _z_filter_target_peer_eq, &target);\n        } break;\n        default:\n            break;\n    }\n    _z_write_filter_ctx_update_state(ctx);\n    _z_write_filter_mutex_unlock(ctx);\n}\n\nz_result_t _z_write_filter_create(const _z_session_rc_t *zn, _z_write_filter_t *filter,\n                                  const _z_declared_keyexpr_t *keyexpr, uint8_t interest_flag, bool complete,\n                                  z_locality_t locality) {\n    uint8_t flags = interest_flag | _Z_INTEREST_FLAG_RESTRICTED | _Z_INTEREST_FLAG_CURRENT;\n    if (_Z_RC_IN_VAL(zn)->_mode == Z_WHATAMI_CLIENT) {\n        // Add client specific flags\n        flags |= _Z_INTEREST_FLAG_KEYEXPRS | _Z_INTEREST_FLAG_AGGREGATE | _Z_INTEREST_FLAG_FUTURE;\n    } else if (_Z_RC_IN_VAL(zn)->_mode == Z_WHATAMI_PEER && _z_session_has_router_peer(_Z_RC_IN_VAL(zn))) {\n        // Add additional flags when in peer mode and connected to a router\n        flags |= _Z_INTEREST_FLAG_KEYEXPRS | _Z_INTEREST_FLAG_FUTURE;\n    }\n    filter->ctx = _z_write_filter_ctx_rc_null();\n    _z_keyexpr_t ke;\n    _Z_RETURN_IF_ERR(_z_keyexpr_copy(&ke, &keyexpr->_inner));\n    _z_write_filter_ctx_t *ctx = (_z_write_filter_ctx_t *)z_malloc(sizeof(_z_write_filter_ctx_t));\n\n    if (ctx == NULL) {\n        _z_keyexpr_clear(&ke);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_CLEAN_RETURN_IF_ERR(_z_mutex_init(&ctx->mutex), _z_keyexpr_clear(&ke); z_free(ctx));\n#endif\n    ctx->state = WRITE_FILTER_ACTIVE;\n    ctx->targets = _z_filter_target_slist_new();\n#if Z_FEATURE_MATCHING\n    _z_closure_matching_status_intmap_init(&ctx->callbacks);\n#endif\n    bool expects_queryable = _Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_QUERYABLES);\n    assert(expects_queryable != _Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_SUBSCRIBERS) &&\n           \"write filter must target exactly one entity type\");\n    ctx->is_complete = complete;\n    ctx->is_aggregate = (flags & _Z_INTEREST_FLAG_AGGREGATE) != 0;\n    ctx->allow_local = _z_locality_allows_local(locality);\n    ctx->allow_remote = _z_locality_allows_remote(locality);\n    ctx->target_type = expects_queryable ? _Z_WRITE_FILTER_QUERYABLE : _Z_WRITE_FILTER_SUBSCRIBER;\n    ctx->key = ke;\n    ctx->zn = _z_session_rc_clone_as_weak(zn);\n    if (_Z_RC_IS_NULL(&ctx->zn)) {\n        _z_write_filter_ctx_clear(ctx);\n        z_free(ctx);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    ctx->local_targets = 0;\n    ctx->registration = NULL;\n    filter->ctx = _z_write_filter_ctx_rc_new(ctx);\n\n    if (_Z_RC_IS_NULL(&filter->ctx)) {\n        _z_write_filter_ctx_clear(ctx);\n        z_free(ctx);\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    _z_write_filter_ctx_rc_t filter_ctx_clone = _z_write_filter_ctx_rc_clone(&filter->ctx);\n    _z_void_rc_t ctx_void = _z_write_filter_ctx_rc_to_void(&filter_ctx_clone);\n    filter->_interest_id = _z_add_interest(_Z_RC_IN_VAL(zn), keyexpr, _z_write_filter_callback, flags, &ctx_void);\n    if (filter->_interest_id == 0) {\n        _z_write_filter_ctx_rc_drop(&filter->ctx);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_write_filter_session_register(_Z_RC_IN_VAL(zn), ctx, &filter->ctx),\n                           _z_remove_interest(_Z_RC_IN_VAL(zn), filter->_interest_id);\n                           _z_write_filter_ctx_rc_drop(&filter->ctx));\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_write_filter_ctx_clear(_z_write_filter_ctx_t *ctx) {\n    z_result_t res = _Z_RES_OK;\n    _z_write_filter_session_unregister(ctx);\n    _z_write_filter_mutex_lock(ctx);\n    _z_filter_target_slist_free(&ctx->targets);\n#if Z_FEATURE_MATCHING\n    _z_closure_matching_status_intmap_clear(&ctx->callbacks);\n#endif\n    _z_keyexpr_clear(&ctx->key);\n    _z_session_weak_drop(&ctx->zn);\n    _z_write_filter_mutex_unlock(ctx);\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_drop(&ctx->mutex);\n#endif\n    return res;\n}\n\nz_result_t _z_write_filter_clear(_z_write_filter_t *filter) {\n    if (_Z_RC_IS_NULL(&filter->ctx)) {\n        return _Z_RES_OK;\n    }\n    _z_write_filter_session_unregister(_Z_RC_IN_VAL(&filter->ctx));\n    _z_session_rc_t s = _z_session_weak_upgrade_if_open(&_Z_RC_IN_VAL(&filter->ctx)->zn);\n    if (!_Z_RC_IS_NULL(&s)) {\n        _z_remove_interest(_Z_RC_IN_VAL(&s), filter->_interest_id);\n        _z_session_rc_drop(&s);\n    }\n    _z_write_filter_ctx_remove_callbacks(_Z_RC_IN_VAL(&filter->ctx));\n    _z_write_filter_ctx_rc_drop(&filter->ctx);\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_MATCHING == 1\nvoid _z_write_filter_ctx_remove_callback(_z_write_filter_ctx_t *ctx, size_t id) {\n    _z_write_filter_mutex_lock(ctx);\n    _z_closure_matching_status_intmap_remove(&ctx->callbacks, id);\n    _z_write_filter_mutex_unlock(ctx);\n}\n\nvoid _z_write_filter_ctx_remove_callbacks(_z_write_filter_ctx_t *ctx) {\n    _z_write_filter_mutex_lock(ctx);\n    _z_closure_matching_status_intmap_clear(&ctx->callbacks);\n    _z_write_filter_mutex_unlock(ctx);\n}\n\nz_result_t _z_write_filter_ctx_add_callback(_z_write_filter_ctx_t *ctx, size_t id, _z_closure_matching_status_t *v) {\n    _z_closure_matching_status_t *ptr = (_z_closure_matching_status_t *)z_malloc(sizeof(_z_closure_matching_status_t));\n    if (ptr == NULL) {\n        _z_closure_matching_status_clear(v);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    *ptr = *v;\n    *v = (_z_closure_matching_status_t){NULL, NULL, NULL};\n    _z_write_filter_mutex_lock(ctx);\n    if (!_z_write_filter_ctx_active(ctx)) {\n        _z_matching_status_t s = (_z_matching_status_t){.matching = true};\n        ptr->call(&s, ptr->context);\n    }\n    _z_closure_matching_status_intmap_insert(&ctx->callbacks, id, ptr);\n    _z_write_filter_mutex_unlock(ctx);\n    return _Z_RES_OK;\n}\n#endif\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 || Z_FEATURE_LOCAL_QUERYABLE == 1\nstatic void _z_write_filter_match_free(void **value) {\n    if (value == NULL || *value == NULL) {\n        return;\n    }\n    _z_write_filter_ctx_rc_t *ctx = (_z_write_filter_ctx_rc_t *)(*value);\n    _z_write_filter_ctx_rc_drop(ctx);\n    z_free(ctx);\n    *value = NULL;\n}\n\nstatic void _z_write_filter_notify_local_entity(_z_session_t *session, const _z_keyexpr_t *key,\n                                                z_locality_t allowed_origin, bool is_complete,\n                                                _z_write_filter_target_type_t source_type, bool add) {\n    if (!_z_locality_allows_local(allowed_origin)) {\n        return;\n    }\n\n    if (_z_session_mutex_lock_if_open(session) != _Z_RES_OK) {\n        return;\n    }\n\n    _z_list_t *matches = NULL;\n    for (_z_write_filter_registration_t *registration = session->_write_filters; registration != NULL;\n         registration = registration->next) {\n        _z_write_filter_ctx_t *registration_ctx = _Z_RC_IN_VAL(&registration->ctx_rc);\n        if (!(registration_ctx->allow_local &&\n              (registration_ctx->is_complete ? (is_complete && _z_keyexpr_includes(key, &registration_ctx->key))\n                                             : _z_keyexpr_intersects(&registration_ctx->key, key)))) {\n            continue;\n        }\n        if (registration_ctx->target_type != source_type) {\n            continue;\n        }\n        _z_write_filter_ctx_rc_t *ctx_clone = (_z_write_filter_ctx_rc_t *)z_malloc(sizeof(_z_write_filter_ctx_rc_t));\n        if (ctx_clone == NULL) {\n            _z_list_free(&matches, _z_write_filter_match_free);\n            _z_session_mutex_unlock(session);\n            return;\n        }\n        *ctx_clone = _z_write_filter_ctx_rc_clone(&registration->ctx_rc);\n        _z_list_t *new_head = _z_list_push(matches, ctx_clone);\n        assert(new_head != matches && \"Failed to allocate write-filter match node\");\n        matches = new_head;\n    }\n\n    _z_session_mutex_unlock(session);\n\n    _z_list_t *it = matches;\n    while (it != NULL) {\n        _z_write_filter_ctx_rc_t *ctx_clone = (_z_write_filter_ctx_rc_t *)_z_list_value(it);\n        _z_write_filter_ctx_t *matched_ctx = _Z_RC_IN_VAL(ctx_clone);\n        if (add) {\n            _z_write_filter_ctx_add_local_match(matched_ctx);\n        } else {\n            _z_write_filter_ctx_remove_local_match(matched_ctx);\n        }\n        it = _z_list_next(it);\n    }\n    _z_list_free(&matches, _z_write_filter_match_free);\n}\n\nvoid _z_write_filter_notify_subscriber(_z_session_t *session, const _z_keyexpr_t *key, z_locality_t allowed_origin,\n                                       bool add) {\n    _z_write_filter_notify_local_entity(session, key, allowed_origin, true, _Z_WRITE_FILTER_SUBSCRIBER, add);\n}\n\nvoid _z_write_filter_notify_queryable(_z_session_t *session, const _z_keyexpr_t *key, z_locality_t allowed_origin,\n                                      bool is_complete, bool add) {\n    _z_write_filter_notify_local_entity(session, key, allowed_origin, is_complete, _Z_WRITE_FILTER_QUERYABLE, add);\n}\n#else\nvoid _z_write_filter_notify_subscriber(_z_session_t *session, const _z_keyexpr_t *key, z_locality_t allowed_origin,\n                                       bool add) {\n    _ZP_UNUSED(session);\n    _ZP_UNUSED(key);\n    _ZP_UNUSED(allowed_origin);\n    _ZP_UNUSED(add);\n}\n\nvoid _z_write_filter_notify_queryable(_z_session_t *session, const _z_keyexpr_t *key, z_locality_t allowed_origin,\n                                      bool is_complete, bool add) {\n    _ZP_UNUSED(session);\n    _ZP_UNUSED(key);\n    _ZP_UNUSED(allowed_origin);\n    _ZP_UNUSED(is_complete);\n    _ZP_UNUSED(add);\n}\n#endif  // Z_FEATURE_LOCAL_SUBSCRIBER == 1 || Z_FEATURE_LOCAL_QUERYABLE == 1\n\n#else  // Z_FEATURE_INTEREST == 0\nz_result_t _z_write_filter_create(const _z_session_rc_t *zn, _z_write_filter_t *filter,\n                                  const _z_declared_keyexpr_t *keyexpr, uint8_t interest_flag, bool complete,\n                                  z_locality_t locality) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(keyexpr);\n    _ZP_UNUSED(filter);\n    _ZP_UNUSED(interest_flag);\n    _ZP_UNUSED(complete);\n    _ZP_UNUSED(locality);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_write_filter_clear(_z_write_filter_t *filter) {\n    _ZP_UNUSED(filter);\n    return _Z_RES_OK;\n}\n\nvoid _z_write_filter_notify_subscriber(_z_session_t *session, const _z_keyexpr_t *key, z_locality_t allowed_origin,\n                                       bool add) {\n    _ZP_UNUSED(session);\n    _ZP_UNUSED(key);\n    _ZP_UNUSED(allowed_origin);\n    _ZP_UNUSED(add);\n}\n\nvoid _z_write_filter_notify_queryable(_z_session_t *session, const _z_keyexpr_t *key, z_locality_t allowed_origin,\n                                      bool is_complete, bool add) {\n    _ZP_UNUSED(session);\n    _ZP_UNUSED(key);\n    _ZP_UNUSED(allowed_origin);\n    _ZP_UNUSED(is_complete);\n    _ZP_UNUSED(add);\n}\n\n#endif\n"
  },
  {
    "path": "src/net/liveliness.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/api/liveliness.h\"\n\n#include \"zenoh-pico/net/liveliness.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_LIVELINESS == 1\n\n/**************** Liveliness Token ****************/\nz_result_t _z_liveliness_send_declare_token(_z_session_t *zn, uint32_t id, const _z_declared_keyexpr_t *keyexpr) {\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, zn);\n    _z_declaration_t declaration = _z_make_decl_token(&wireexpr, id);\n    _z_network_message_t n_msg;\n    _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n    z_result_t ret = _z_send_declare(zn, &n_msg);\n    _z_n_msg_clear(&n_msg);\n    return ret;\n}\n\nz_result_t _z_liveliness_send_undeclare_token(_z_session_t *zn, uint32_t id, const _z_declared_keyexpr_t *keyexpr) {\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, zn);\n    _z_declaration_t declaration = _z_make_undecl_token(id, &wireexpr);\n    _z_network_message_t n_msg;\n    _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n    z_result_t ret = _z_send_undeclare(zn, &n_msg);\n    _z_n_msg_clear(&n_msg);\n    return ret;\n}\n\nz_result_t _z_declare_liveliness_token(const _z_session_rc_t *zn, _z_liveliness_token_t *ret_token,\n                                       const _z_declared_keyexpr_t *keyexpr) {\n    *ret_token = _z_liveliness_token_null();\n    _Z_DEBUG(\"Declare liveliness token (%.*s)\", (int)_z_string_len(&keyexpr->_inner._keyexpr),\n             _z_string_data(&keyexpr->_inner._keyexpr));\n\n    uint32_t id = _z_get_entity_id(_Z_RC_IN_VAL(zn));\n\n    _z_declared_keyexpr_t ke;\n    _Z_RETURN_IF_ERR(_z_declared_keyexpr_declare(zn, &ke, keyexpr));\n    _Z_CLEAN_RETURN_IF_ERR(_z_liveliness_send_declare_token(_Z_RC_IN_VAL(zn), id, &ke), _z_declared_keyexpr_clear(&ke));\n    z_result_t ret = _Z_RES_OK;\n\n    if (_z_session_mutex_lock_if_open(_Z_RC_IN_VAL(zn)) != _Z_RES_OK) {\n        _z_declared_keyexpr_clear(&ke);\n        return _Z_ERR_SESSION_CLOSED;\n    }\n    const _z_declared_keyexpr_t *pkeyexpr = _z_declared_keyexpr_intmap_get(&_Z_RC_IN_VAL(zn)->_local_tokens, id);\n    if (pkeyexpr != NULL) {\n        // Already received this token\n        _Z_ERROR(\"Duplicate token id %i\", (int)id);\n        ret = _Z_ERR_ENTITY_DECLARATION_FAILED;\n    } else {\n        _z_declared_keyexpr_t *ke_on_heap = (_z_declared_keyexpr_t *)z_malloc(sizeof(_z_declared_keyexpr_t));\n        if (ke_on_heap == NULL ||\n            _z_declared_keyexpr_intmap_insert(&_Z_RC_IN_VAL(zn)->_local_tokens, id, ke_on_heap) == NULL) {\n            ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            z_free(ke_on_heap);\n        } else {\n            *ke_on_heap = ke;\n        }\n    }\n    _z_session_mutex_unlock(_Z_RC_IN_VAL(zn));\n\n    if (ret != _Z_RES_OK) {\n        _z_liveliness_send_undeclare_token(_Z_RC_IN_VAL(zn), id, &ke);\n        _z_declared_keyexpr_clear(&ke);\n        return ret;\n    }\n    ret_token->_id = id;\n    ret_token->_zn = _z_session_rc_clone_as_weak(zn);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undeclare_liveliness_token(_z_liveliness_token_t *token) {\n    if (token == NULL || _Z_RC_IS_NULL(&token->_zn)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&token->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        return _Z_ERR_SESSION_CLOSED;\n    }\n    _z_session_t *zn = _Z_RC_IN_VAL(&sess_rc);\n#else\n    _z_session_t *zn = _z_session_weak_as_unsafe_ptr(&token->_zn);\n#endif\n    z_result_t ret;\n    _z_declared_keyexpr_t *ke = NULL;\n    _Z_DEBUG(\"Unregister liveliness token (%i)\", (int)token->_id);\n    _z_session_mutex_lock(zn);\n    ke = _z_declared_keyexpr_intmap_extract(&zn->_local_tokens, token->_id);\n    _z_session_mutex_unlock(zn);\n    if (ke != NULL) {\n        ret = _z_liveliness_send_undeclare_token(zn, token->_id, ke);\n        _z_declared_keyexpr_clear(\n            ke);  // ke needs to be undeclared outside of mutex, since it might trigger resources update\n        z_free(ke);\n    } else {\n        ret = _Z_ERR_ENTITY_UNKNOWN;\n    }\n\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return ret;\n}\n\n/**************** Liveliness Subscriber ****************/\n\nz_result_t _z_liveliness_subscription_trigger_history(_z_session_t *zn, const _z_subscription_t *sub) {\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_DEBUG(\"Retrieve liveliness history for %.*s\", (int)_z_string_len(&sub->_key._inner._keyexpr),\n             _z_string_data(&sub->_key._inner._keyexpr));\n\n    _z_keyexpr_slist_t *tokens_list = _z_keyexpr_slist_new();\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    // TODO: could we call callbacks inside the mutex? - this would allow to avoid extra keyexpr copies, list\n    // allocations, in addition it would also allow to stay consistent with respect to eventual remote undeclarations,\n    // i.e. if they arrive during callback execution - they will only be delivered after initial history calls,\n    // thus preventing potential declare/undeclare order inversion.\n    // TODO: add support for local tokens\n    _z_keyexpr_intmap_iterator_t iter = _z_keyexpr_intmap_iterator_make(&zn->_remote_tokens);\n    while (_z_keyexpr_intmap_iterator_next(&iter)) {\n        if (_z_keyexpr_intersects(&sub->_key._inner, _z_keyexpr_intmap_iterator_value(&iter))) {\n            tokens_list = _z_keyexpr_slist_push(tokens_list, _z_keyexpr_intmap_iterator_value(&iter));\n        }\n    }\n    _z_session_mutex_unlock(zn);\n\n    _z_keyexpr_slist_t *pos = tokens_list;\n    while (pos != NULL) {\n        _z_sample_t s = _z_sample_null();\n        s.kind = Z_SAMPLE_KIND_PUT;\n        s.keyexpr._inner = _z_keyexpr_alias(_z_keyexpr_slist_value(pos));\n        sub->_callback(&s, sub->_arg);\n        _z_sample_clear(&s);\n        pos = _z_keyexpr_slist_next(pos);\n    }\n    _z_keyexpr_slist_free(&tokens_list);\n\n    return ret;\n}\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nz_result_t _z_register_liveliness_subscriber(uint32_t *out_sub_id, const _z_session_rc_t *zn,\n                                             const _z_declared_keyexpr_t *keyexpr,\n                                             _z_closure_sample_callback_t callback, _z_drop_handler_t dropper,\n                                             bool history, void *arg, const _z_sync_group_t *callback_sync_group) {\n    _z_subscription_t s = {0};\n    s._id = _z_get_entity_id(_Z_RC_IN_VAL(zn));\n    s._callback = callback;\n    s._dropper = dropper;\n    s._arg = arg;\n    s._allowed_origin = z_locality_default();\n    _Z_CLEAN_RETURN_IF_ERR(_z_declared_keyexpr_declare(zn, &s._key, keyexpr), _z_subscription_clear(&s));\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_sync_group_create_notifier(&_Z_RC_IN_VAL(zn)->_callback_drop_sync_group, &s._session_callback_drop_notifier),\n        _z_subscription_clear(&s));\n    if (callback_sync_group != NULL) {\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_sync_group_create_notifier(callback_sync_group, &s._subscriber_callback_drop_notifier),\n            _z_subscription_clear(&s));\n    }\n\n    // Register subscription, stored at session-level, do not drop it by the end of this function.\n    _z_subscription_rc_t sp_s =\n        _z_register_subscription(_Z_RC_IN_VAL(zn), _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, &s);\n    if (_Z_RC_IS_NULL(&sp_s)) {\n        _z_subscription_clear(&s);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    if (history) {\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_liveliness_subscription_trigger_history(_Z_RC_IN_VAL(zn), _Z_RC_IN_VAL(&sp_s)),\n            _z_unregister_subscription(_Z_RC_IN_VAL(zn), _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, &sp_s));\n    }\n    // Build the declare message to send on the wire\n    uint8_t mode = history ? (_Z_INTEREST_FLAG_CURRENT | _Z_INTEREST_FLAG_FUTURE) : _Z_INTEREST_FLAG_FUTURE;\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(&_Z_RC_IN_VAL(&sp_s)->_key, _Z_RC_IN_VAL(zn));\n    _z_interest_t interest = _z_make_interest(\n        &wireexpr, s._id, _Z_INTEREST_FLAG_KEYEXPRS | _Z_INTEREST_FLAG_TOKENS | _Z_INTEREST_FLAG_RESTRICTED | mode);\n\n    _z_network_message_t n_msg;\n    _z_n_msg_make_interest(&n_msg, interest);\n    z_result_t res = _z_send_declare(_Z_RC_IN_VAL(zn), &n_msg);\n    _z_n_msg_clear(&n_msg);\n    if (res != _Z_RES_OK) {\n        _z_unregister_subscription(_Z_RC_IN_VAL(zn), _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, &sp_s);\n        res = _Z_ERR_TRANSPORT_TX_FAILED;\n    } else {\n        *out_sub_id = _Z_RC_IN_VAL(&sp_s)->_id;\n        _z_subscription_rc_drop(&sp_s);\n    }\n    return res;\n}\nz_result_t _z_declare_liveliness_subscriber(_z_subscriber_t *subscriber, const _z_session_rc_t *zn,\n                                            const _z_declared_keyexpr_t *keyexpr, _z_closure_sample_callback_t callback,\n                                            _z_drop_handler_t dropper, bool history, void *arg) {\n    *subscriber = _z_subscriber_null();\n    subscriber->_zn = _z_session_rc_clone_as_weak(zn);\n    z_result_t ret = _z_sync_group_create(&subscriber->_callback_drop_sync_group);\n    _Z_SET_IF_OK(ret, _z_register_liveliness_subscriber(&subscriber->_entity_id, zn, keyexpr, callback, dropper,\n                                                        history, arg, &subscriber->_callback_drop_sync_group));\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_subscriber_clear(subscriber));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undeclare_liveliness_subscriber(_z_subscriber_t *sub) {\n    if (sub == NULL || _Z_RC_IS_NULL(&sub->_zn)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n\n    _z_subscription_rc_t s =\n        _z_get_subscription_by_id(_Z_RC_IN_VAL(&sub->_zn), _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, sub->_entity_id);\n    if (_Z_RC_IS_NULL(&s)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n\n    _z_interest_t interest = _z_make_interest_final(_Z_RC_IN_VAL(&s)->_id);\n    _z_network_message_t n_msg;\n    _z_n_msg_make_interest(&n_msg, interest);\n    if (_z_send_undeclare(_Z_RC_IN_VAL(&sub->_zn), &n_msg) != _Z_RES_OK) {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n    }\n    _z_n_msg_clear(&n_msg);\n\n    _z_unregister_subscription(_Z_RC_IN_VAL(&sub->_zn), _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, &s);\n    return _z_sync_group_check(&sub->_callback_drop_sync_group) ? _z_sync_group_wait(&sub->_callback_drop_sync_group)\n                                                                : _Z_RES_OK;\n}\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n/**************** Liveliness Query ****************/\n\n#if Z_FEATURE_QUERY == 1\n#ifdef Z_FEATURE_UNSTABLE_API\n\ntypedef struct _z_cancel_liveliness_pending_query_arg_t {\n    _z_session_weak_t _zn;\n    uint32_t _qid;\n} _z_cancel_liveliness_pending_query_arg_t;\n\nz_result_t _z_cancel_liveliness_pending_query(void *arg) {\n    _z_cancel_liveliness_pending_query_arg_t *a = (_z_cancel_liveliness_pending_query_arg_t *)arg;\n    _z_session_rc_t s_rc = _z_session_weak_upgrade_if_open(&a->_zn);\n    if (!_Z_RC_IS_NULL(&s_rc)) {\n        _z_liveliness_unregister_pending_query(_Z_RC_IN_VAL(&s_rc), a->_qid);\n        _z_session_rc_drop(&s_rc);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_cancel_liveliness_pending_query_arg_drop(void *arg) {\n    _z_cancel_liveliness_pending_query_arg_t *a = (_z_cancel_liveliness_pending_query_arg_t *)arg;\n    _z_session_weak_drop(&a->_zn);\n    z_free(a);\n}\n\nz_result_t _z_liveliness_pending_query_register_cancellation(_z_liveliness_pending_query_t *pq,\n                                                             const _z_cancellation_token_rc_t *opt_cancellation_token,\n                                                             const _z_session_rc_t *zn) {\n    pq->_cancellation_data = _z_pending_query_cancellation_data_null();\n    if (opt_cancellation_token != NULL) {\n        _z_cancel_liveliness_pending_query_arg_t *arg =\n            (_z_cancel_liveliness_pending_query_arg_t *)z_malloc(sizeof(_z_cancel_liveliness_pending_query_arg_t));\n        if (arg == NULL) {\n            return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        }\n        arg->_zn = _z_session_rc_clone_as_weak(zn);\n        arg->_qid = pq->_id;\n\n        size_t handler_id = 0;\n        _z_cancellation_token_on_cancel_handler_t handler;\n        handler._on_cancel = _z_cancel_liveliness_pending_query;\n        handler._on_drop = _z_cancel_liveliness_pending_query_arg_drop;\n        handler._arg = (void *)arg;\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_cancellation_token_add_on_cancel_handler(_Z_RC_IN_VAL(opt_cancellation_token), &handler, &handler_id),\n            _z_cancellation_token_on_cancel_handler_drop(&handler));\n        pq->_cancellation_data._cancellation_token = _z_cancellation_token_rc_clone(opt_cancellation_token);\n        pq->_cancellation_data._handler_id = handler_id;\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_cancellation_token_get_notifier(_Z_RC_IN_VAL(opt_cancellation_token), &pq->_cancellation_data._notifier),\n            _z_pending_query_cancellation_data_clear(&pq->_cancellation_data));\n    }\n    return _Z_RES_OK;\n}\n#endif\n\nz_result_t _z_liveliness_query(const _z_session_rc_t *session, const _z_declared_keyexpr_t *keyexpr,\n                               _z_closure_reply_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                               uint64_t timeout_ms, _z_cancellation_token_rc_t *opt_cancellation_token) {\n    z_result_t ret = _Z_RES_OK;\n    _z_session_t *zn = _Z_RC_IN_VAL(session);\n    _Z_DEBUG(\"Register liveliness query for (%.*s)\", (int)_z_string_len(&keyexpr->_inner._keyexpr),\n             _z_string_data(&keyexpr->_inner._keyexpr));\n\n    _z_keyexpr_t query_ke;\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_copy(&query_ke, &keyexpr->_inner), _z_drop_handler_execute(dropper, arg));\n\n    uint32_t query_id;\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&query_ke);\n                           _z_drop_handler_execute(dropper, arg););\n    _z_liveliness_pending_query_t *pq = _z_unsafe_liveliness_register_pending_query(zn);\n    if (pq == NULL) {\n        _z_session_mutex_unlock(zn);\n        _z_keyexpr_clear(&query_ke);\n        _z_drop_handler_execute(dropper, arg);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    query_id = pq->_id;\n    pq->_key = query_ke;\n    pq->_callback = callback;\n    pq->_dropper = dropper;\n    pq->_arg = arg;\n#ifdef Z_FEATURE_UNSTABLE_API\n    ret = _z_liveliness_pending_query_register_cancellation(pq, opt_cancellation_token, session);\n#else\n    _ZP_UNUSED(opt_cancellation_token);\n#endif\n    _z_session_mutex_unlock(zn);\n\n    if (ret == _Z_RES_OK) {\n        _ZP_UNUSED(timeout_ms);  // Current interest in pico don't support timeout\n        _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, zn);\n        _z_interest_t interest = _z_make_interest(&wireexpr, query_id,\n                                                  _Z_INTEREST_FLAG_KEYEXPRS | _Z_INTEREST_FLAG_TOKENS |\n                                                      _Z_INTEREST_FLAG_RESTRICTED | _Z_INTEREST_FLAG_CURRENT);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_interest(&n_msg, interest);\n        ret = _z_send_declare(zn, &n_msg);\n\n        if (ret != _Z_RES_OK) {\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n            ret = _Z_ERR_TRANSPORT_TX_FAILED;\n        }\n        _z_n_msg_clear(&n_msg);\n    }\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_liveliness_unregister_pending_query(zn, query_id));\n\n    return ret;\n}\n#endif  // Z_FEATURE_QUERY == 1\n\n#endif  // Z_FEATURE_LIVELINESS == 1\n"
  },
  {
    "path": "src/net/logger.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/net/logger.h\"\n\n/*------------------ Init/Config ------------------*/\nvoid _z_init_logger(void) {\n    // @TODO\n}\n"
  },
  {
    "path": "src/net/matching.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/net/matching.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/session/matching.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_MATCHING == 1\nz_result_t _z_matching_listener_register(uint32_t *listener_id, _z_session_t *s, const _z_write_filter_ctx_rc_t *ctx,\n                                         _z_closure_matching_status_t *callback) {\n    *listener_id = _z_get_entity_id(s);\n    _z_closure_matching_status_t c;\n    c = *callback;\n    *callback = (_z_closure_matching_status_t){NULL, NULL, NULL};\n\n    return _z_write_filter_ctx_add_callback(_Z_RC_IN_VAL(ctx), *listener_id, &c);\n}\n\nz_result_t _z_matching_listener_declare(_z_matching_listener_t *listener, _z_session_t *s,\n                                        const _z_write_filter_ctx_rc_t *ctx, _z_closure_matching_status_t *callback) {\n    *listener = _z_matching_listener_null();\n    listener->_write_filter_ctx = _z_write_filter_ctx_rc_clone_as_weak(ctx);\n    _Z_CLEAN_RETURN_IF_ERR(_z_matching_listener_register(&listener->_id, s, ctx, callback),\n                           _z_matching_listener_clear(listener));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_matching_listener_undeclare(_z_matching_listener_t *listener) {\n    _z_write_filter_ctx_rc_t write_filter = _z_write_filter_ctx_weak_upgrade(&listener->_write_filter_ctx);\n    if (!_Z_RC_IS_NULL(&write_filter)) {\n        _z_write_filter_ctx_remove_callback(_Z_RC_IN_VAL(&write_filter), listener->_id);\n        _z_write_filter_ctx_rc_drop(&write_filter);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_matching_listener_clear(_z_matching_listener_t *listener) {\n    _z_write_filter_ctx_weak_drop(&listener->_write_filter_ctx);\n    *listener = _z_matching_listener_null();\n}\n\nvoid _z_matching_listener_free(_z_matching_listener_t **listener) {\n    _z_matching_listener_t *ptr = *listener;\n\n    if (ptr != NULL) {\n        _z_matching_listener_clear(ptr);\n\n        z_free(ptr);\n        *listener = NULL;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/net/memory.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/protocol/core.h\"\n\nvoid _z_hello_clear(_z_hello_t *hello) { _z_string_svec_clear(&hello->_locators); }\n\nvoid _z_hello_free(_z_hello_t **hello) {\n    _z_hello_t *ptr = *hello;\n\n    if (ptr != NULL) {\n        _z_hello_clear(ptr);\n\n        z_free(ptr);\n        *hello = NULL;\n    }\n}\n\nvoid _z_value_clear(_z_value_t *value) {\n    _z_encoding_clear(&value->encoding);\n    _z_bytes_drop(&value->payload);\n}\n\nvoid _z_value_free(_z_value_t **value) {\n    _z_value_t *ptr = *value;\n\n    if (ptr != NULL) {\n        _z_value_clear(ptr);\n\n        z_free(ptr);\n        *value = NULL;\n    }\n}\n\nbool _z_hello_check(const _z_hello_t *hello) { return _z_id_check(hello->_zid); }\n"
  },
  {
    "path": "src/net/primitives.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/net/primitives.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/liveliness.h\"\n#include \"zenoh-pico/net/logger.h\"\n#include \"zenoh-pico/net/matching.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/loopback.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n#include \"zenoh-pico/utils/result.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n/*------------------ Declaration Helpers ------------------*/\nz_result_t _z_send_declare(_z_session_t *zn, const _z_network_message_t *n_msg) {\n    z_result_t ret = _Z_RES_OK;\n    ret = _z_send_n_msg(zn, n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    if (ret == _Z_RES_OK) {\n        _z_cache_declaration(zn, n_msg);\n    }\n#endif\n\n    return ret;\n}\n\nz_result_t _z_send_undeclare(_z_session_t *zn, const _z_network_message_t *n_msg) {\n    z_result_t ret = _Z_RES_OK;\n    ret = _z_send_n_msg(zn, n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    if (ret == _Z_RES_OK) {\n        _z_prune_declaration(zn, n_msg);\n    }\n#endif\n\n    return ret;\n}\n/*------------------ Scouting ------------------*/\n#if Z_FEATURE_SCOUTING == 1\nvoid _z_scout(const z_what_t what, const _z_id_t zid, _z_string_t *locator, const uint32_t timeout,\n              _z_closure_hello_callback_t callback, void *arg_call, _z_drop_handler_t dropper, void *arg_drop) {\n    _z_hello_slist_t *hellos = _z_scout_inner(what, zid, locator, timeout, false);\n\n    while (hellos != NULL) {\n        _z_hello_t *hello = _z_hello_slist_value(hellos);\n        (*callback)(hello, arg_call);\n        hellos = _z_hello_slist_pop(hellos);\n    }\n    if (dropper != NULL) {\n        (*dropper)(arg_drop);\n    }\n    _z_hello_slist_free(&hellos);\n}\n#endif\n\n/*------------------ Resource Declaration ------------------*/\nz_result_t _z_declare_resource(_z_session_t *zn, const _z_string_t *key, uint16_t *out_id) {\n    _z_wireexpr_t expr = _z_wireexpr_null();\n    expr._id = Z_RESOURCE_ID_NONE;\n    expr._suffix = _z_string_alias(*key);\n    z_result_t ret = _z_register_resource(zn, &expr, Z_RESOURCE_ID_NONE, NULL, out_id);\n    if (ret == _Z_RES_OK) {\n        // Build the declare message to send on the wire\n        _z_declaration_t declaration = _z_make_decl_keyexpr(*out_id, &expr);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n        ret = _z_send_declare(zn, &n_msg);\n        if (ret != _Z_RES_OK) {\n            _z_unregister_resource(zn, *out_id, NULL);\n        }\n        _z_n_msg_clear(&n_msg);\n    }\n    return ret;\n}\n\nz_result_t _z_undeclare_resource(_z_session_t *zn, uint16_t rid) {\n    _Z_DEBUG(\"Undeclaring local keyexpr %d\", rid);\n    z_result_t ret = _z_unregister_resource(zn, rid, NULL);\n    if (ret == _Z_RES_OK) {\n        // Build the declare message to send on the wire\n        _z_declaration_t declaration = _z_make_undecl_keyexpr(rid);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n        if (_z_send_undeclare(zn, &n_msg) != _Z_RES_OK) {\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n            ret = _Z_ERR_TRANSPORT_TX_FAILED;\n        }\n        _z_n_msg_clear(&n_msg);\n    } else if (ret > 0) {\n        ret = _Z_RES_OK;\n    } else {\n        _Z_ERROR_LOG(ret);\n    }\n\n    return ret;\n}\n\n#if Z_FEATURE_PUBLICATION == 1\n/*------------------  Publisher Declaration ------------------*/\nz_result_t _z_declare_publisher(_z_publisher_t *publisher, const _z_session_rc_t *zn,\n                                const _z_declared_keyexpr_t *keyexpr, _z_encoding_t *encoding,\n                                z_congestion_control_t congestion_control, z_priority_t priority, bool is_express,\n                                z_reliability_t reliability, z_locality_t allowed_destination) {\n    publisher->_id = _z_get_entity_id(_Z_RC_IN_VAL(zn));\n    publisher->_congestion_control = congestion_control;\n    publisher->_priority = priority;\n    publisher->_is_express = is_express;\n    publisher->reliability = reliability;\n    publisher->_zn = _z_session_rc_clone_as_weak(zn);\n    publisher->_encoding = encoding == NULL ? _z_encoding_null() : _z_encoding_steal(encoding);\n    publisher->_allowed_destination = allowed_destination;\n    publisher->_filter = (_z_write_filter_t){0};\n    _Z_CLEAN_RETURN_IF_ERR(_z_declared_keyexpr_declare(zn, &publisher->_key, keyexpr),\n                           _z_undeclare_publisher(publisher));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undeclare_publisher(_z_publisher_t *pub) {\n    if (pub == NULL || _Z_RC_IS_NULL(&pub->_zn)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n    _z_write_filter_clear(&pub->_filter);\n    _z_declared_keyexpr_clear(&pub->_key);\n    _z_session_weak_drop(&pub->_zn);\n    _z_encoding_clear(&pub->_encoding);\n    *pub = _z_publisher_null();\n    return _Z_RES_OK;\n}\n\n/*------------------ Write ------------------*/\nz_result_t _z_write(_z_session_t *zn, const _z_declared_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                    _z_encoding_t *encoding, z_sample_kind_t kind, z_congestion_control_t cong_ctrl,\n                    z_priority_t priority, bool is_express, const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                    z_reliability_t reliability, const _z_source_info_t *source_info,\n                    z_locality_t allowed_destination) {\n    z_result_t ret = _Z_RES_OK;\n    _z_qos_t qos = _z_n_qos_make(is_express, cong_ctrl == Z_CONGESTION_CONTROL_BLOCK, priority);\n\n    if (_z_locality_allows_remote(allowed_destination)) {\n        _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, zn);\n        _z_network_message_t msg;\n        switch (kind) {\n            case Z_SAMPLE_KIND_PUT:\n                _z_n_msg_make_push_put(&msg, &wireexpr, payload, encoding, qos, timestamp, attachment, reliability,\n                                       source_info);\n                break;\n            case Z_SAMPLE_KIND_DELETE:\n                _z_n_msg_make_push_del(&msg, &wireexpr, qos, timestamp, reliability, source_info);\n                break;\n            default:\n                _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n        if (_z_send_n_msg(zn, &msg, reliability, cong_ctrl, NULL) != _Z_RES_OK) {\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n            ret = _Z_ERR_TRANSPORT_TX_FAILED;\n        }\n    }\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    if (ret == _Z_RES_OK && _z_locality_allows_local(allowed_destination)) {\n        ret = _z_session_deliver_push_locally(zn, &keyexpr->_inner, payload, encoding, kind, qos, timestamp, attachment,\n                                              reliability, source_info);\n    }\n#endif\n    return ret;\n}\n#endif\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n/*------------------ Subscriber Declaration ------------------*/\nz_result_t _z_register_subscriber(uint32_t *sub_id, const _z_session_rc_t *zn, const _z_declared_keyexpr_t *keyexpr,\n                                  _z_closure_sample_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                                  z_locality_t allowed_origin, const _z_sync_group_t *callback_drop_sync_group) {\n    _z_subscription_t s = {0};\n    s._id = _z_get_entity_id(_Z_RC_IN_VAL(zn));\n    s._callback = callback;\n    s._dropper = dropper;\n    s._arg = arg;\n    s._allowed_origin = allowed_origin;\n    _Z_CLEAN_RETURN_IF_ERR(_z_declared_keyexpr_declare_non_wild_prefix(zn, &s._key, keyexpr),\n                           _z_subscription_clear(&s));\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_sync_group_create_notifier(&_Z_RC_IN_VAL(zn)->_callback_drop_sync_group, &s._session_callback_drop_notifier),\n        _z_subscription_clear(&s));\n    if (callback_drop_sync_group != NULL) {\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_sync_group_create_notifier(callback_drop_sync_group, &s._subscriber_callback_drop_notifier),\n            _z_subscription_clear(&s));\n    }\n\n    _z_subscription_rc_t sp_s = _z_register_subscription(_Z_RC_IN_VAL(zn), _Z_SUBSCRIBER_KIND_SUBSCRIBER, &s);\n    if (_Z_RC_IS_NULL(&sp_s)) {\n        _z_subscription_clear(&s);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    if (_z_locality_allows_remote(allowed_origin)) {\n        _z_wireexpr_t wire_expr = _z_declared_keyexpr_alias_to_wire(keyexpr, _Z_RC_IN_VAL(zn));\n        _z_declaration_t declaration = _z_make_decl_subscriber(&wire_expr, s._id);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n        z_result_t res = _z_send_declare(_Z_RC_IN_VAL(zn), &n_msg);\n        _z_n_msg_clear(&n_msg);\n        if (res != _Z_RES_OK) {\n            _z_unregister_subscription(_Z_RC_IN_VAL(zn), _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sp_s);\n            return res;\n        }\n    }\n    *sub_id = s._id;\n    _z_subscription_rc_drop(&sp_s);  // we do not keep this data for the time being inside subscriber, and rc copy is\n                                     // still stored inside the session\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declare_subscriber(_z_subscriber_t *subscriber, const _z_session_rc_t *zn,\n                                 const _z_declared_keyexpr_t *keyexpr, _z_closure_sample_callback_t callback,\n                                 _z_drop_handler_t dropper, void *arg, z_locality_t allowed_origin) {\n    *subscriber = _z_subscriber_null();\n    subscriber->_zn = _z_session_rc_clone_as_weak(zn);\n    z_result_t ret = _z_sync_group_create(&subscriber->_callback_drop_sync_group);\n    _Z_SET_IF_OK(ret, _z_register_subscriber(&subscriber->_entity_id, zn, keyexpr, callback, dropper, arg,\n                                             allowed_origin, &subscriber->_callback_drop_sync_group));\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_subscriber_clear(subscriber));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undeclare_subscriber(_z_subscriber_t *sub) {\n    if (sub == NULL || _Z_RC_IS_NULL(&sub->_zn)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&sub->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        return _Z_ERR_SESSION_CLOSED;\n    }\n    _z_session_t *zn = _Z_RC_IN_VAL(&sess_rc);\n#else\n    _z_session_t *zn = _z_session_weak_as_unsafe_ptr(&sub->_zn);\n#endif\n    // Find subscription entry\n    _z_subscription_rc_t s = _z_get_subscription_by_id(zn, _Z_SUBSCRIBER_KIND_SUBSCRIBER, sub->_entity_id);\n    if (_Z_RC_IS_NULL(&s)) {\n#if Z_FEATURE_LIVELINESS == 1\n#if Z_FEATURE_SESSION_CHECK == 1\n        _z_session_rc_drop(&sess_rc);\n#endif\n        // Not found, treat it as a liveliness subscriber\n        return _z_undeclare_liveliness_subscriber(sub);\n#else\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n#endif\n    }\n    z_result_t ret = _Z_RES_OK;\n    if (_z_locality_allows_remote(_Z_RC_IN_VAL(&s)->_allowed_origin)) {\n        _z_declaration_t declaration;\n        if (zn->_mode == Z_WHATAMI_CLIENT) {\n            declaration = _z_make_undecl_subscriber(sub->_entity_id, NULL);\n        } else {\n            _z_wireexpr_t expr = _z_declared_keyexpr_alias_to_wire(&_Z_RC_IN_VAL(&s)->_key, zn);\n            declaration = _z_make_undecl_subscriber(sub->_entity_id, &expr);\n        }\n        _z_network_message_t n_msg;\n        _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n        if (_z_send_undeclare(zn, &n_msg) != _Z_RES_OK) {\n            ret = _Z_ERR_TRANSPORT_TX_FAILED;\n        }\n        _z_n_msg_clear(&n_msg);\n    }\n    _z_unregister_subscription(zn, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &s);\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    z_result_t wait_ret = _z_sync_group_check(&sub->_callback_drop_sync_group)\n                              ? _z_sync_group_wait(&sub->_callback_drop_sync_group)\n                              : _Z_RES_OK;\n    return ret == _Z_RES_OK ? wait_ret : ret;\n}\n#endif\n\n#if Z_FEATURE_QUERYABLE == 1\n/*------------------ Queryable Declaration ------------------*/\nz_result_t _z_register_queryable(uint32_t *queryable_id, const _z_session_rc_t *zn,\n                                 const _z_declared_keyexpr_t *keyexpr, bool complete,\n                                 _z_closure_query_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                                 z_locality_t allowed_origin, const _z_sync_group_t *callback_drop_sync_group) {\n    _z_session_queryable_t q = {0};\n    q._id = _z_get_entity_id(_Z_RC_IN_VAL(zn));\n    q._complete = complete;\n    q._callback = callback;\n    q._dropper = dropper;\n    q._arg = arg;\n    q._allowed_origin = allowed_origin;\n    _Z_CLEAN_RETURN_IF_ERR(_z_declared_keyexpr_declare_non_wild_prefix(zn, &q._key, keyexpr),\n                           _z_session_queryable_clear(&q));\n    _Z_CLEAN_RETURN_IF_ERR(\n        _z_sync_group_create_notifier(&_Z_RC_IN_VAL(zn)->_callback_drop_sync_group, &q._session_callback_drop_notifier),\n        _z_session_queryable_clear(&q));\n    if (callback_drop_sync_group != NULL) {\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_sync_group_create_notifier(callback_drop_sync_group, &q._queryable_callback_drop_notifier),\n            _z_session_queryable_clear(&q));\n    }\n\n    // Create session_queryable entry, stored at session-level, do not drop it by the end of this function.\n    _z_session_queryable_rc_t sp_q = _z_register_session_queryable(_Z_RC_IN_VAL(zn), &q);\n    if (_Z_RC_IS_NULL(&sp_q)) {\n        _z_session_queryable_clear(&q);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    if (_z_locality_allows_remote(allowed_origin)) {\n        // Build the declare message to send on the wire\n        _z_wireexpr_t wire_expr = _z_declared_keyexpr_alias_to_wire(&q._key, _Z_RC_IN_VAL(zn));\n        _z_declaration_t declaration =\n            _z_make_decl_queryable(&wire_expr, q._id, q._complete, _Z_QUERYABLE_DISTANCE_DEFAULT);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n\n        z_result_t res = _z_send_declare(_Z_RC_IN_VAL(zn), &n_msg);\n        _z_n_msg_clear(&n_msg);\n        if (res != _Z_RES_OK) {\n            _z_unregister_session_queryable(_Z_RC_IN_VAL(zn), &sp_q);\n            return res;\n        }\n    }\n    *queryable_id = q._id;\n    _z_session_queryable_rc_drop(&sp_q);  // we do not keep this data for the time being inside queryable, and rc copy\n                                          // is still stored inside the session\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declare_queryable(_z_queryable_t *queryable, const _z_session_rc_t *zn,\n                                const _z_declared_keyexpr_t *keyexpr, bool complete,\n                                _z_closure_query_callback_t callback, _z_drop_handler_t dropper, void *arg,\n                                z_locality_t allowed_origin) {\n    *queryable = _z_queryable_null();\n    queryable->_zn = _z_session_rc_clone_as_weak(zn);\n    z_result_t ret = _z_sync_group_create(&queryable->_callback_drop_sync_group);\n    _Z_SET_IF_OK(ret, _z_register_queryable(&queryable->_entity_id, zn, keyexpr, complete, callback, dropper, arg,\n                                            allowed_origin, &queryable->_callback_drop_sync_group));\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_queryable_clear(queryable));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undeclare_queryable(_z_queryable_t *qle) {\n    if (qle == NULL || _Z_RC_IS_NULL(&qle->_zn)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&qle->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        return _Z_ERR_SESSION_CLOSED;\n    }\n    _z_session_t *zn = _Z_RC_IN_VAL(&sess_rc);\n#else\n    _z_session_t *zn = _z_session_weak_as_unsafe_ptr(&sub->_zn);\n#endif\n    // Find session_queryable entry\n    _z_session_queryable_rc_t q = _z_get_session_queryable_by_id(zn, qle->_entity_id);\n    z_result_t ret = _Z_RES_OK;\n    if (_Z_RC_IS_NULL(&q)) {\n#if Z_FEATURE_SESSION_CHECK == 1\n        _z_session_rc_drop(&sess_rc);\n#endif\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n    if (_z_locality_allows_remote(_Z_RC_IN_VAL(&q)->_allowed_origin)) {\n        // Build the declare message to send on the wire\n        _z_declaration_t declaration;\n        if (zn->_mode == Z_WHATAMI_CLIENT) {\n            declaration = _z_make_undecl_queryable(qle->_entity_id, NULL);\n        } else {\n            _z_wireexpr_t expr = _z_declared_keyexpr_alias_to_wire(&_Z_RC_IN_VAL(&q)->_key, zn);\n            declaration = _z_make_undecl_queryable(qle->_entity_id, &expr);\n        }\n        _z_network_message_t n_msg;\n        _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_none());\n        ret = _z_send_undeclare(zn, &n_msg);\n        if (ret != _Z_RES_OK) {\n            ret = _Z_ERR_TRANSPORT_TX_FAILED;\n        }\n        _z_n_msg_clear(&n_msg);\n    }\n    _z_unregister_session_queryable(zn, &q);\n    z_result_t wait_ret = _z_sync_group_check(&qle->_callback_drop_sync_group)\n                              ? _z_sync_group_wait(&qle->_callback_drop_sync_group)\n                              : _Z_RES_OK;\n    ret = ret == _Z_RES_OK ? wait_ret : ret;\n#if Z_FEATURE_SESSION_CHECK == 1\n    _z_session_rc_drop(&sess_rc);\n#endif\n    return ret;\n}\n\nz_result_t _z_send_reply(const _z_query_t *query, const _z_session_rc_t *zsrc, const _z_declared_keyexpr_t *keyexpr,\n                         _z_bytes_t *payload, _z_encoding_t *encoding, const z_sample_kind_t kind, bool is_express,\n                         const _z_timestamp_t *timestamp, _z_bytes_t *att, _z_source_info_t *source_info) {\n    _z_session_t *zn = _Z_RC_IN_VAL(zsrc);\n    _Z_DEBUG(\"send_reply: rid=%jd kind=%d\", (intmax_t)query->_request_id, (int)kind);\n    // Check key expression\n    if (!query->_anyke && !_z_declared_keyexpr_intersects(&query->_key, keyexpr)) {\n        _Z_ERROR_RETURN(_Z_ERR_KEYEXPR_NOT_MATCH);\n    }\n    // Build the reply context decorator. This is NOT the final reply.\n    _z_n_qos_t qos =\n        _z_n_qos_create(is_express, _z_n_qos_get_congestion_control(query->_qos), _z_n_qos_get_priority(query->_qos));\n    if (query->_is_local) {\n        return _z_session_deliver_reply_locally(query, zsrc, keyexpr, payload, encoding, kind, qos, timestamp, att,\n                                                source_info);\n    }\n\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, _Z_RC_IN_VAL(zsrc));\n    _z_zenoh_message_t z_msg;\n    switch (kind) {\n        case Z_SAMPLE_KIND_PUT:\n            _z_n_msg_make_reply_ok_put(&z_msg, &zn->_local_zid, query->_request_id, &wireexpr, Z_RELIABILITY_DEFAULT,\n                                       Z_CONSOLIDATION_MODE_DEFAULT, qos, timestamp, source_info, payload, encoding,\n                                       att);\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            _z_n_msg_make_reply_ok_del(&z_msg, &zn->_local_zid, query->_request_id, &wireexpr, Z_RELIABILITY_DEFAULT,\n                                       Z_CONSOLIDATION_MODE_DEFAULT, qos, timestamp, source_info, att);\n            break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    // Send message on network\n    if (_z_send_n_msg(zn, &z_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL) != _Z_RES_OK) {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n    }\n    // Freeing z_msg is unnecessary, as all of its components are aliased\n    return _Z_RES_OK;\n}\n\nz_result_t _z_send_reply_err(const _z_query_t *query, const _z_session_rc_t *zsrc, _z_bytes_t *payload,\n                             _z_encoding_t *encoding) {\n    z_result_t ret = _Z_RES_OK;\n    _z_session_t *zn = _Z_RC_IN_VAL(zsrc);\n\n    // Build the reply context decorator. This is NOT the final reply.\n    _z_n_qos_t qos = _z_n_qos_make(false, true, Z_PRIORITY_DEFAULT);\n    _z_source_info_t source_info = _z_source_info_null();\n    if (query->_is_local) {\n        return _z_session_deliver_reply_err_locally(query, zsrc, payload, encoding, qos);\n    }\n\n    _z_zenoh_message_t msg;\n    _z_n_msg_make_reply_err(&msg, &zn->_local_zid, query->_request_id, Z_RELIABILITY_DEFAULT, qos, payload, encoding,\n                            &source_info);\n    // Send message on network\n    if (_z_send_n_msg(zn, &msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL) != _Z_RES_OK) {\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n        ret = _Z_ERR_TRANSPORT_TX_FAILED;\n    }\n    return ret;\n}\n#endif\n\n#if Z_FEATURE_QUERY == 1\n/*------------------  Querier Declaration ------------------*/\nz_result_t _z_declare_querier(_z_querier_t *querier, const _z_session_rc_t *zn, const _z_declared_keyexpr_t *keyexpr,\n                              z_consolidation_mode_t consolidation_mode, z_congestion_control_t congestion_control,\n                              z_query_target_t target, z_priority_t priority, bool is_express, uint64_t timeout_ms,\n                              _z_encoding_t *encoding, z_reliability_t reliability, z_locality_t allowed_destination,\n                              z_reply_keyexpr_t accept_replies) {\n    *querier = _z_querier_null();\n    querier->_encoding = encoding == NULL ? _z_encoding_null() : _z_encoding_steal(encoding);\n    querier->reliability = reliability;\n    querier->_id = _z_get_entity_id(_Z_RC_IN_VAL(zn));\n    querier->_consolidation_mode = consolidation_mode;\n    querier->_congestion_control = congestion_control;\n    querier->_target = target;\n    querier->_priority = priority;\n    querier->_is_express = is_express;\n    querier->_accept_replies = accept_replies;\n    querier->_timeout_ms = timeout_ms;\n    querier->_allowed_destination = allowed_destination;\n    querier->_zn = _z_session_rc_clone_as_weak(zn);\n    querier->_filter = (_z_write_filter_t){0};\n    _Z_CLEAN_RETURN_IF_ERR(_z_declared_keyexpr_declare(zn, &querier->_key, keyexpr), _z_undeclare_querier(querier));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undeclare_querier(_z_querier_t *querier) {\n    if (querier == NULL || _Z_RC_IS_NULL(&querier->_zn)) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n    _z_session_rc_t s = _z_session_weak_upgrade_if_open(&querier->_zn);\n    if (!_Z_RC_IS_NULL(&s)) {\n        _z_unregister_pending_queries_from_querier(_Z_RC_IN_VAL(&s), querier->_id);\n        _z_session_rc_drop(&s);\n    }\n    _z_write_filter_clear(&querier->_filter);\n    _z_declared_keyexpr_clear(&querier->_key);\n    _z_session_weak_drop(&querier->_zn);\n    _z_encoding_clear(&querier->_encoding);\n    *querier = _z_querier_null();\n    return _Z_RES_OK;\n}\n\n/*------------------ Query ------------------*/\nz_result_t _z_query(const _z_session_rc_t *session, _z_optional_id_t querier_id, const _z_declared_keyexpr_t *keyexpr,\n                    const char *parameters, size_t parameters_len, z_query_target_t target,\n                    z_consolidation_mode_t consolidation, _z_bytes_t *payload, _z_encoding_t *encoding,\n                    _z_closure_reply_callback_t callback, _z_drop_handler_t dropper, void *arg, uint64_t timeout_ms,\n                    _z_bytes_t *attachment, _z_n_qos_t qos, _z_source_info_t *source_info,\n                    z_reply_keyexpr_t accept_replies, z_locality_t allowed_destination,\n                    _z_cancellation_token_rc_t *opt_cancellation_token) {\n    _z_session_t *zn = _Z_RC_IN_VAL(session);\n    if (parameters == NULL && parameters_len > 0) {\n        _Z_ERROR(\"Non-zero length string should not be NULL\");\n        return Z_EINVAL;\n    }\n    bool allow_local = _z_locality_allows_local(allowed_destination);\n    bool allow_remote = _z_locality_allows_remote(allowed_destination);\n    size_t remote_targets = allow_remote ? _z_transport_get_peers_count(&zn->_tp) : 0;\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    size_t remaining_finals = (allow_local ? 1 : 0) + remote_targets;\n#else\n    _ZP_UNUSED(allow_local);\n    size_t remaining_finals = remote_targets;\n#endif\n    if (remaining_finals == 0) {\n        _z_drop_handler_execute(dropper, arg);\n        return _z_session_is_closed(zn) ? _Z_ERR_SESSION_CLOSED : _Z_RES_OK;\n    }\n    _z_keyexpr_t ke_query;\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_copy(&ke_query, &keyexpr->_inner), _z_drop_handler_execute(dropper, arg));\n\n    if (consolidation == Z_CONSOLIDATION_MODE_AUTO) {\n        if (parameters != NULL && _z_strstr(parameters, parameters + parameters_len, Z_SELECTOR_TIME) != NULL) {\n            consolidation = Z_CONSOLIDATION_MODE_NONE;\n        } else {\n            consolidation = Z_CONSOLIDATION_MODE_LATEST;\n        }\n    }\n\n    bool _anyke_in_parameters = _z_parameters_has_anyke(parameters, parameters_len);\n    bool _anyke_option = accept_replies == Z_REPLY_KEYEXPR_ANY;\n    // extra _anyke parameter only if it's not already in the parameters list\n    bool implicit_anyke = _anyke_option && !_anyke_in_parameters;\n\n    // Add the pending query to the current session\n    _z_zint_t qid;\n    z_result_t ret = _Z_RES_OK;\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&ke_query);\n                           _z_drop_handler_execute(dropper, arg));\n    _z_pending_query_t *pq = _z_unsafe_register_pending_query(zn);\n    if (pq == NULL) {\n        _z_session_mutex_unlock(zn);\n        _z_keyexpr_clear(&ke_query);\n        _z_drop_handler_execute(dropper, arg);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    // Fill the pending query object\n    qid = pq->_id;\n    pq->_querier_id = querier_id;\n    pq->_key = ke_query;\n    pq->_target = target;\n    pq->_consolidation = consolidation;\n    pq->_anyke = _anyke_in_parameters || _anyke_option;\n    pq->_callback = callback;\n    pq->_dropper = dropper;\n    pq->_pending_replies = NULL;\n    pq->_allowed_destination = allowed_destination;\n    pq->_arg = arg;\n    pq->_timeout = timeout_ms;\n    pq->_start_time = z_clock_now();\n    pq->_remaining_finals = (uint32_t)remaining_finals;\n#ifdef Z_FEATURE_UNSTABLE_API\n    ret = _z_pending_query_register_cancellation(pq, opt_cancellation_token, session);\n#else\n    _ZP_UNUSED(opt_cancellation_token);\n#endif\n    _z_session_mutex_unlock(zn);\n    // Send query message\n    _z_slice_t params =\n        (parameters == NULL) ? _z_slice_null() : _z_slice_alias_buf((uint8_t *)parameters, parameters_len);\n    if (ret == _Z_RES_OK && remote_targets > 0) {\n        _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, zn);\n        _z_zenoh_message_t z_msg;\n        _z_n_msg_make_query(&z_msg, &wireexpr, &params, qid, Z_RELIABILITY_DEFAULT, consolidation, payload, encoding,\n                            timeout_ms, attachment, qos, source_info, implicit_anyke);\n        ret = _z_send_n_msg(zn, &z_msg, Z_RELIABILITY_RELIABLE, _z_n_qos_get_congestion_control(qos), NULL);\n    }\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    if (ret == _Z_RES_OK && allow_local) {\n        ret = _z_session_deliver_query_locally(zn, &keyexpr->_inner, &params, consolidation, payload, encoding,\n                                               attachment, source_info, qid, timeout_ms, qos, implicit_anyke);\n    }\n#endif\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_unregister_pending_query(zn, qid));\n    return _Z_RES_OK;\n}\n#endif\n\n#if Z_FEATURE_INTEREST == 1\n/*------------------ Interest Declaration ------------------*/\nuint32_t _z_add_interest(_z_session_t *zn, const _z_declared_keyexpr_t *keyexpr, _z_interest_handler_t callback,\n                         uint8_t flags, _z_void_rc_t *arg) {\n    _z_session_interest_t intr;\n    intr._id = _z_get_entity_id(zn);\n    intr._flags = flags;\n    intr._callback = callback;\n    intr._arg = *arg;\n    *arg = _z_void_rc_null();\n    if (_z_keyexpr_copy(&intr._key, &keyexpr->_inner) != _Z_RES_OK) {\n        _z_void_rc_drop(&intr._arg);\n        return 0;\n    }\n\n    // Create interest entry, stored at session-level, do not drop it by the end of this function.\n    _z_session_interest_rc_t *sintr = _z_register_interest(zn, &intr);\n    if (sintr == NULL) {\n        _z_void_rc_drop(&intr._arg);\n        _z_keyexpr_clear(&intr._key);\n        return 0;\n    }\n    // Build the interest message to send on the wire (only needed in client mode or multicast transport or when\n    // connected to a router in peer mode)\n    if (zn->_mode == Z_WHATAMI_CLIENT || _z_session_has_router_peer(zn)\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 1\n        || (zn->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE)\n#endif\n    ) {\n        _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, zn);\n        _z_interest_t interest = _z_make_interest(&wireexpr, intr._id, intr._flags);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_interest(&n_msg, interest);\n        if (_z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL) != _Z_RES_OK) {\n            _z_unregister_interest(zn, sintr);\n            return 0;\n        }\n#if Z_FEATURE_AUTO_RECONNECT == 1\n        _z_cache_declaration(zn, &n_msg);\n#endif\n        _z_n_msg_clear(&n_msg);\n    }\n    // Replay declares\n    _z_interest_replay_declare(zn, &intr);\n    return intr._id;\n}\n\nz_result_t _z_remove_interest(_z_session_t *zn, uint32_t interest_id) {\n    // Find interest entry\n    _z_session_interest_rc_t *sintr = _z_get_interest_by_id(zn, interest_id);\n    if (sintr == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n    // Build the declare message to send on the wire (only needed in client mode or multicast transport)\n    if (zn->_mode == Z_WHATAMI_CLIENT\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 1\n        || (zn->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE)\n#endif\n    ) {\n        _z_interest_t interest = _z_make_interest_final(_Z_RC_IN_VAL(sintr)->_id);\n        _z_network_message_t n_msg;\n        _z_n_msg_make_interest(&n_msg, interest);\n        if (_z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL) != _Z_RES_OK) {\n            _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n        }\n#if Z_FEATURE_AUTO_RECONNECT == 1\n        _z_prune_declaration(zn, &n_msg);\n#endif\n        _z_n_msg_clear(&n_msg);\n    }\n    // Only if message is successfully send, session interest can be removed\n    _z_unregister_interest(zn, sintr);\n    return _Z_RES_OK;\n}\n#endif\n"
  },
  {
    "path": "src/net/query.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/net/query.h\"\n\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/session/loopback.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic void _z_query_clear_inner(_z_query_t *q) {\n    _z_declared_keyexpr_clear(&q->_key);\n    _z_value_clear(&q->_value);\n    _z_bytes_drop(&q->_attachment);\n    _z_string_clear(&q->_parameters);\n    _z_session_weak_drop(&q->_zn);\n}\n\nz_result_t _z_session_send_reply_final(_z_session_t *session, uint32_t query_id, bool is_local) {\n    if (is_local) {\n        return _z_session_deliver_reply_final_locally(session, query_id);\n    } else {\n        _z_zenoh_message_t z_msg;\n        _z_n_msg_make_response_final(&z_msg, query_id);\n        z_result_t ret = _z_send_n_msg(session, &z_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n        _z_msg_clear(&z_msg);\n        return ret;\n    }\n}\n\nz_result_t _z_query_send_reply_final(_z_query_t *q) {\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade_if_open(&q->_zn);\n    if (_Z_RC_IS_NULL(&sess_rc)) {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n    }\n\n    z_result_t ret = _z_session_send_reply_final(_Z_RC_IN_VAL(&sess_rc), q->_request_id, q->_is_local);\n    _z_session_rc_drop(&sess_rc);\n    return ret;\n}\n\nvoid _z_query_clear(_z_query_t *q) {\n    // Send REPLY_FINAL message\n    if (!_Z_RC_IS_NULL(&q->_zn) && _z_query_send_reply_final(q) != _Z_RES_OK) {\n        _Z_ERROR(\"Query send REPLY_FINAL transport failure !\");\n    }\n    // Clean up memory\n    _z_query_clear_inner(q);\n}\n\nvoid _z_query_free(_z_query_t **query) {\n    _z_query_t *ptr = *query;\n    if (ptr != NULL) {\n        _z_query_clear(ptr);\n        z_free(ptr);\n        *query = NULL;\n    }\n}\n\n#if Z_FEATURE_QUERYABLE == 1\nvoid _z_queryable_clear(_z_queryable_t *qbl) {\n    _z_session_weak_drop(&qbl->_zn);\n    _z_sync_group_drop(&qbl->_callback_drop_sync_group);\n    *qbl = _z_queryable_null();\n}\n\nvoid _z_queryable_free(_z_queryable_t **qbl) {\n    _z_queryable_t *ptr = *qbl;\n\n    if (ptr != NULL) {\n        _z_queryable_clear(ptr);\n\n        z_free(ptr);\n        *qbl = NULL;\n    }\n}\n#endif\n"
  },
  {
    "path": "src/net/reply.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/net/reply.h\"\n\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_QUERY == 1\nvoid _z_reply_data_clear(_z_reply_data_t *reply_data) {\n    if (reply_data->_tag == _Z_REPLY_TAG_DATA) {\n        _z_sample_clear(&reply_data->_result.sample);\n    } else if (reply_data->_tag == _Z_REPLY_TAG_ERROR) {\n        _z_value_clear(&reply_data->_result.error);\n    }\n    reply_data->_tag = _Z_REPLY_TAG_NONE;\n    reply_data->replier_id = _z_entity_global_id_null();\n}\n\nvoid _z_reply_data_free(_z_reply_data_t **reply_data) {\n    _z_reply_data_t *ptr = *reply_data;\n\n    if (ptr != NULL) {\n        _z_reply_data_clear(ptr);\n        z_free(ptr);\n        *reply_data = NULL;\n    }\n}\n\nz_result_t _z_reply_data_copy(_z_reply_data_t *dst, const _z_reply_data_t *src) {\n    if (src->_tag == _Z_REPLY_TAG_DATA) {\n        _Z_RETURN_IF_ERR(_z_sample_copy(&dst->_result.sample, &src->_result.sample));\n    } else if (src->_tag == _Z_REPLY_TAG_ERROR) {\n        _Z_RETURN_IF_ERR(_z_value_copy(&dst->_result.error, &src->_result.error));\n    }\n    dst->_tag = src->_tag;\n    dst->replier_id = src->replier_id;\n    return _Z_RES_OK;\n}\n\nvoid _z_reply_steal_data(_z_reply_t *dst, _z_keyexpr_t *keyexpr, _z_entity_global_id_t replier_id, _z_bytes_t *payload,\n                         const _z_timestamp_t *timestamp, _z_encoding_t *encoding, z_sample_kind_t kind,\n                         _z_bytes_t *attachment, _z_source_info_t *source_info) {\n    dst->data.replier_id = replier_id;\n    dst->data._tag = _Z_REPLY_TAG_DATA;\n    _z_sample_steal_data(&dst->data._result.sample, keyexpr, payload, timestamp, encoding, kind, _Z_N_QOS_DEFAULT,\n                         attachment, Z_RELIABILITY_DEFAULT, source_info);\n}\nvoid _z_reply_err_steal_data(_z_reply_t *dst, _z_bytes_t *payload, _z_encoding_t *encoding,\n                             _z_entity_global_id_t replier_id) {\n    dst->data.replier_id = replier_id;\n    dst->data._tag = _Z_REPLY_TAG_ERROR;\n    dst->data._result.error.payload = _z_bytes_steal(payload);\n    dst->data._result.error.encoding = _z_encoding_steal(encoding);\n}\n\nz_result_t _z_reply_move(_z_reply_t *dst, _z_reply_t *src) {\n    dst->data._tag = src->data._tag;\n    dst->data.replier_id = src->data.replier_id;\n    if (src->data._tag == _Z_REPLY_TAG_DATA) {\n        _Z_RETURN_IF_ERR(_z_sample_move(&dst->data._result.sample, &src->data._result.sample));\n    } else if (src->data._tag == _Z_REPLY_TAG_ERROR) {\n        _Z_RETURN_IF_ERR(_z_value_move(&dst->data._result.error, &src->data._result.error));\n    }\n\n    *src = _z_reply_null();\n    return _Z_RES_OK;\n}\n\nvoid _z_reply_clear(_z_reply_t *reply) { _z_reply_data_clear(&reply->data); }\n\nvoid _z_reply_free(_z_reply_t **reply) {\n    _z_reply_t *ptr = *reply;\n\n    if (*reply != NULL) {\n        _z_reply_clear(ptr);\n\n        z_free(ptr);\n        *reply = NULL;\n    }\n}\n\nz_result_t _z_reply_copy(_z_reply_t *dst, const _z_reply_t *src) { return _z_reply_data_copy(&dst->data, &src->data); }\n\nbool _z_pending_reply_eq(const _z_pending_reply_t *one, const _z_pending_reply_t *two) {\n    return one->_tstamp.time == two->_tstamp.time;\n}\n\nvoid _z_pending_reply_clear(_z_pending_reply_t *pr) {\n    // Free reply\n    _z_reply_clear(&pr->_reply);\n\n    // Free the timestamp\n    _z_timestamp_clear(&pr->_tstamp);\n}\n\n#endif  // Z_FEATURE_QUERY == 1\n"
  },
  {
    "path": "src/net/sample.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/net/sample.h\"\n\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nvoid _z_sample_steal_data(_z_sample_t *dst, _z_keyexpr_t *key, _z_bytes_t *payload, const _z_timestamp_t *timestamp,\n                          _z_encoding_t *encoding, z_sample_kind_t kind, _z_qos_t qos, _z_bytes_t *attachment,\n                          z_reliability_t reliability, _z_source_info_t *source_info) {\n    *dst = _z_sample_null();\n    dst->keyexpr._inner = _z_keyexpr_steal(key);\n    dst->payload = _z_bytes_steal(payload);\n    dst->attachment = _z_bytes_steal(attachment);\n    dst->encoding = _z_encoding_steal(encoding);\n    dst->timestamp = *timestamp;\n    dst->kind = kind;\n    dst->qos = qos;\n    dst->reliability = reliability;\n    dst->source_info = *source_info;\n}\n\nz_result_t _z_sample_copy_data(_z_sample_t *dst, const _z_declared_keyexpr_t *key, const _z_bytes_t *payload,\n                               const _z_timestamp_t *timestamp, const _z_encoding_t *encoding, z_sample_kind_t kind,\n                               _z_qos_t qos, const _z_bytes_t *attachment, z_reliability_t reliability,\n                               const _z_source_info_t *source_info) {\n    *dst = _z_sample_null();\n    _Z_RETURN_IF_ERR(_z_declared_keyexpr_copy(&dst->keyexpr, key));\n    _Z_CLEAN_RETURN_IF_ERR(_z_encoding_copy(&dst->encoding, encoding), _z_sample_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_copy(&dst->payload, payload), _z_sample_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_copy(&dst->attachment, attachment), _z_sample_clear(dst));\n    dst->timestamp = _z_timestamp_duplicate(timestamp);\n    dst->source_info = *source_info;\n    dst->qos = qos;\n    dst->reliability = reliability;\n    dst->kind = kind;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_sample_move(_z_sample_t *dst, _z_sample_t *src) {\n    *dst = _z_sample_null();\n    _Z_RETURN_IF_ERR(_z_declared_keyexpr_move(&dst->keyexpr, &src->keyexpr));\n    _Z_CLEAN_RETURN_IF_ERR(_z_encoding_move(&dst->encoding, &src->encoding), _z_sample_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_move(&dst->payload, &src->payload), _z_sample_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_move(&dst->attachment, &src->attachment), _z_sample_clear(dst));\n    _z_timestamp_move(&dst->timestamp, &src->timestamp);\n    dst->source_info = src->source_info;\n    dst->qos = src->qos;\n    dst->reliability = src->reliability;\n    dst->kind = src->kind;\n    return _Z_RES_OK;\n}\n\nvoid _z_sample_clear(_z_sample_t *sample) {\n    _z_declared_keyexpr_clear(&sample->keyexpr);\n    _z_encoding_clear(&sample->encoding);\n    _z_bytes_drop(&sample->payload);\n    _z_bytes_drop(&sample->attachment);\n}\n\nvoid _z_sample_free(_z_sample_t **sample) {\n    _z_sample_t *ptr = *sample;\n    if (ptr != NULL) {\n        _z_sample_clear(ptr);\n        z_free(ptr);\n        *sample = NULL;\n    }\n}\n\nz_result_t _z_sample_copy(_z_sample_t *dst, const _z_sample_t *src) {\n    *dst = _z_sample_null();\n    _Z_RETURN_IF_ERR(_z_declared_keyexpr_copy(&dst->keyexpr, &src->keyexpr));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_copy(&dst->payload, &src->payload), _z_sample_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_encoding_copy(&dst->encoding, &src->encoding), _z_sample_clear(dst));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_copy(&dst->attachment, &src->attachment), _z_sample_clear(dst));\n    dst->kind = src->kind;\n    dst->timestamp = _z_timestamp_duplicate(&src->timestamp);\n    dst->source_info = src->source_info;\n    dst->qos = src->qos;\n    dst->reliability = src->reliability;\n    return _Z_RES_OK;\n}\n\n_z_sample_t _z_sample_duplicate(const _z_sample_t *src) {\n    _z_sample_t dst;\n    _z_sample_copy(&dst, src);\n    return dst;\n}\n"
  },
  {
    "path": "src/net/session.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include \"zenoh-pico/net/session.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/common/lease.h\"\n#include \"zenoh-pico/transport/common/read.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/multicast.h\"\n#include \"zenoh-pico/transport/multicast/lease.h\"\n#include \"zenoh-pico/transport/multicast/read.h\"\n#include \"zenoh-pico/transport/raweth/read.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast.h\"\n#include \"zenoh-pico/transport/unicast/lease.h\"\n#include \"zenoh-pico/transport/unicast/read.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n#include \"zenoh-pico/utils/sleep.h\"\n#include \"zenoh-pico/utils/string.h\"\n#include \"zenoh-pico/utils/uuid.h\"\n\n#if Z_FEATURE_SCOUTING == 1\nstatic z_result_t _z_locators_by_scout(const _z_config_t *config, const _z_id_t *zid, _z_string_svec_t *locators) {\n    z_result_t ret = _Z_RES_OK;\n\n    char *opt_as_str = _z_config_get(config, Z_CONFIG_SCOUTING_WHAT_KEY);\n    if (opt_as_str == NULL) {\n        opt_as_str = (char *)Z_CONFIG_SCOUTING_WHAT_DEFAULT;\n    }\n    z_what_t what = strtol(opt_as_str, NULL, 10);\n\n    opt_as_str = _z_config_get(config, Z_CONFIG_MULTICAST_LOCATOR_KEY);\n    if (opt_as_str == NULL) {\n        opt_as_str = (char *)Z_CONFIG_MULTICAST_LOCATOR_DEFAULT;\n    }\n    _z_string_t mcast_locator = _z_string_alias_str(opt_as_str);\n\n    opt_as_str = _z_config_get(config, Z_CONFIG_SCOUTING_TIMEOUT_KEY);\n    if (opt_as_str == NULL) {\n        opt_as_str = (char *)Z_CONFIG_SCOUTING_TIMEOUT_DEFAULT;\n    }\n    uint32_t timeout = (uint32_t)strtoul(opt_as_str, NULL, 10);\n\n    // Scout and return upon the first result\n    _z_hello_slist_t *hellos = _z_scout_inner(what, *zid, &mcast_locator, timeout, true);\n    if (hellos != NULL) {\n        _z_hello_t *hello = _z_hello_slist_value(hellos);\n        _z_string_svec_copy(locators, &hello->_locators, true);\n    }\n    _z_hello_slist_free(&hellos);\n    return ret;\n}\n#else\nstatic z_result_t _z_locators_by_scout(const _z_config_t *config, const _z_id_t *zid, _z_string_svec_t *locators) {\n    _ZP_UNUSED(config);\n    _ZP_UNUSED(zid);\n    _ZP_UNUSED(locators);\n    _Z_ERROR(\"Cannot scout as Z_FEATURE_SCOUTING was deactivated\");\n    _Z_ERROR_RETURN(_Z_ERR_SCOUT_NO_RESULTS);\n}\n#endif\n\nstatic z_result_t _z_locators_by_config(_z_config_t *config, _z_string_svec_t *listen_locators,\n                                        _z_string_svec_t *connect_locators) {\n    _Z_RETURN_IF_ERR(_z_config_get_all(config, listen_locators, Z_CONFIG_LISTEN_KEY));\n    _Z_RETURN_IF_ERR(_z_config_get_all(config, connect_locators, Z_CONFIG_CONNECT_KEY));\n\n    size_t listen_len = _z_string_svec_len(listen_locators);\n    size_t connect_len = _z_string_svec_len(connect_locators);\n\n    if ((listen_len == 0) && (connect_len == 0)) {\n        return _Z_RES_OK;\n    }\n\n#if Z_FEATURE_UNICAST_PEER == 0\n    if ((listen_len > 0) && (connect_len > 0)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n#endif\n\n    if (listen_len > 0) {\n        _zp_config_insert(config, Z_CONFIG_MODE_KEY, Z_CONFIG_MODE_PEER);\n    }\n\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_config_get_mode(const _z_config_t *config, z_whatami_t *mode) {\n    z_result_t ret = _Z_RES_OK;\n    char *s_mode = _z_config_get(config, Z_CONFIG_MODE_KEY);\n    *mode = Z_WHATAMI_CLIENT;  // By default, zenoh-pico will operate as a client\n    if (s_mode != NULL) {\n        if (_z_str_eq(s_mode, Z_CONFIG_MODE_CLIENT) == true) {\n            *mode = Z_WHATAMI_CLIENT;\n        } else if (_z_str_eq(s_mode, Z_CONFIG_MODE_PEER) == true) {\n            *mode = Z_WHATAMI_PEER;\n        } else {\n            _Z_ERROR(\"Trying to configure an invalid mode: %s\", s_mode);\n            _Z_ERROR_LOG(_Z_ERR_CONFIG_INVALID_MODE);\n            ret = _Z_ERR_CONFIG_INVALID_MODE;\n        }\n    }\n    return ret;\n}\n\nstatic z_result_t _z_open_inner(_z_session_rc_t *zs, _z_string_t *locator, const _z_id_t *zid, int peer_op,\n                                const _z_config_t *config) {\n    z_result_t ret = _Z_RES_OK;\n    _z_session_t *zn = _Z_RC_IN_VAL(zs);\n\n    ret = _z_new_transport(&zn->_tp, zid, locator, zn->_mode, peer_op, config, &_Z_RC_IN_VAL(zs)->_runtime);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    _z_transport_get_common(&zn->_tp)->_session = _z_session_rc_clone_as_weak(zs);\n    _z_transport_get_common(&zn->_tp)->_state = _Z_TRANSPORT_STATE_OPEN;\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 1\n    if (zn->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE) {\n        ret = _z_interest_pull_resource_from_peers(zn);\n    }\n#endif\n    return ret;\n}\n\nstatic int32_t _z_get_remaining_timeout_ms(z_clock_t *start, int32_t timeout_ms) {\n    if (timeout_ms < 0) {\n        return -1;\n    }\n\n    if (timeout_ms == 0) {\n        return 0;\n    }\n\n    unsigned long elapsed = z_clock_elapsed_ms(start);\n    if (elapsed >= (unsigned long)timeout_ms) {\n        return 0;\n    }\n\n    return timeout_ms - (int32_t)elapsed;\n}\n\ntypedef struct {\n    bool transport_opened;\n    int32_t remaining_timeout_ms;\n} _z_open_connect_result_t;\n\n/*\n * Attempt connect locators that are still marked pending.\n *\n * The pending_peers array is both input and output:\n * - PENDING locators may still be attempted;\n * - a locator that succeeds as the primary transport is marked DONE;\n * - a locator that fails with a non-retryable error is marked FAILED;\n * - retryable failures remain PENDING for another attempt or later peer addition.\n * - if exit_on_non_retryable_failure is true, the first non-retryable error is returned immediately;\n * - retryable errors are governed by timeout/backoff and do not fail fast through this flag.\n *\n * On success, out reports that the primary transport is open and how much of the\n * original timeout remains. In peer mode, remaining PENDING locators are used to\n * decide which connect locators still need to be added as peers.\n */\nstatic z_result_t _z_open_connect_locator(_z_session_rc_t *zn, _z_pending_peers_t *pending_peers, const _z_id_t *zid,\n                                          _z_config_t *config, int32_t timeout_ms, bool exit_on_non_retryable_failure,\n                                          _z_open_connect_result_t *out) {\n    size_t connect_len = _z_pending_peer_svec_len(&pending_peers->_peers);\n    z_result_t last_retryable_ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n    z_result_t last_non_retryable_ret = _Z_RES_OK;\n\n    out->transport_opened = false;\n    out->remaining_timeout_ms = timeout_ms;\n\n    if (connect_len == 0) {\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    z_result_t ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n    z_clock_t now = z_clock_now();\n    uint32_t sleep_ms = _Z_SLEEP_BACKOFF_MIN_MS;\n\n    while (!out->transport_opened) {\n        _Z_DEBUG(\"Attempting to open %zu connect locator(s)\", connect_len);\n\n        for (size_t i = 0; i < connect_len; i++) {\n            _z_pending_peer_t *peer = _z_pending_peer_svec_get(&pending_peers->_peers, i);\n            if (peer->_state != _Z_PENDING_PEER_STATE_PENDING) {\n                continue;\n            }\n\n            _z_string_t *locator = &peer->_locator;\n\n            ret = _z_open_inner(zn, locator, zid, _Z_PEER_OP_OPEN, config);\n            if (ret == _Z_RES_OK) {\n                out->transport_opened = true;\n                peer->_state = _Z_PENDING_PEER_STATE_DONE;\n                _Z_DEBUG(\"Successfully opened connect locator [%zu]: %.*s\", i, (int)_z_string_len(locator),\n                         _z_string_data(locator));\n                out->remaining_timeout_ms = _z_get_remaining_timeout_ms(&now, timeout_ms);\n                return _Z_RES_OK;\n            }\n\n            _Z_DEBUG(\"Failed to open connect locator [%zu]: %.*s (ret=%d)\", i, (int)_z_string_len(locator),\n                     _z_string_data(locator), ret);\n\n            if (_z_transport_open_error_is_retryable(ret)) {\n                last_retryable_ret = ret;\n                continue;\n            }\n\n            // Non-retryable error.\n            last_non_retryable_ret = ret;\n            peer->_state = _Z_PENDING_PEER_STATE_FAILED;\n\n            if (exit_on_non_retryable_failure) {\n                out->remaining_timeout_ms = _z_get_remaining_timeout_ms(&now, timeout_ms);\n                return ret;\n            }\n\n            _Z_DEBUG(\"Removing connect locator [%zu] from pending set due to non-retryable error\", i);\n        }\n\n        if (!_z_pending_peers_has_pending(pending_peers)) {\n            break;\n        }\n\n        if (!_z_backoff_sleep(&now, timeout_ms, &sleep_ms)) {\n            break;\n        }\n\n        _Z_DEBUG(\"Retrying connect locators\");\n    }\n\n    out->remaining_timeout_ms = _z_get_remaining_timeout_ms(&now, timeout_ms);\n\n    if (last_non_retryable_ret != _Z_RES_OK) {\n        return last_non_retryable_ret;\n    }\n\n    return last_retryable_ret;\n}\n\nz_result_t _z_open_locators_client(_z_session_rc_t *zn, const _z_string_svec_t *connect_locators, const _z_id_t *zid,\n                                   _z_config_t *config, int32_t timeout_ms) {\n    size_t connect_len = _z_string_svec_len(connect_locators);\n\n    if (connect_len == 0) {\n        _Z_ERROR(\"No connect locators configured in client mode\");\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    _z_pending_peers_t pending_peers = _z_pending_peers_null();\n    _Z_RETURN_IF_ERR(_z_pending_peers_copy_from_locators(&pending_peers, connect_locators));\n    _z_open_connect_result_t connect_result;\n    z_result_t ret = _z_open_connect_locator(zn, &pending_peers, zid, config, timeout_ms, false, &connect_result);\n    _z_pending_peers_clear(&pending_peers);\n    return ret;\n}\n\nz_result_t _z_open_bind_listener(_z_session_rc_t *zn, _z_string_t *locator, const _z_id_t *zid, _z_config_t *config,\n                                 int32_t timeout_ms) {\n    z_result_t ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n    z_clock_t now = z_clock_now();\n    uint32_t sleep_ms = _Z_SLEEP_BACKOFF_MIN_MS;\n\n    while (ret != _Z_RES_OK) {\n        ret = _z_open_inner(zn, locator, zid, _Z_PEER_OP_LISTEN, config);\n        if (ret == _Z_RES_OK) {\n            return _Z_RES_OK;\n        }\n\n        if (!_z_transport_open_error_is_retryable(ret)) {\n            break;\n        }\n\n        if (!_z_backoff_sleep(&now, timeout_ms, &sleep_ms)) {\n            break;\n        }\n    }\n\n    return ret;\n}\n\nz_result_t _z_open_locators_peer(_z_session_rc_t *zn, _z_string_t *listen_locator,\n                                 const _z_string_svec_t *connect_locators, const _z_id_t *zid, _z_config_t *config,\n                                 int32_t listen_timeout_ms, bool listen_exit_on_failure, int32_t connect_timeout_ms,\n                                 bool connect_exit_on_failure) {\n    size_t connect_len = _z_string_svec_len(connect_locators);\n\n    bool transport_opened = false;\n\n#if Z_FEATURE_UNICAST_PEER == 0\n    if ((listen_locator != NULL && connect_len > 0) || (connect_len > 1)) {\n        _Z_ERROR(\"Multiple connect locators, or combined listen and connect locators, require peer support\");\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n#endif\n\n    // First, try to open the optional listen locator.\n    if (listen_locator != NULL) {\n        z_result_t ret = _z_open_bind_listener(zn, listen_locator, zid, config, listen_timeout_ms);\n        if (ret == _Z_RES_OK) {\n            transport_opened = true;\n            _Z_DEBUG(\"Successfully opened listen locator: %.*s\", (int)_z_string_len(listen_locator),\n                     _z_string_data(listen_locator));\n        } else {\n            _Z_DEBUG(\"Failed to open listen locator: %.*s (ret=%d)\", (int)_z_string_len(listen_locator),\n                     _z_string_data(listen_locator), ret);\n\n            if (listen_exit_on_failure) {\n                return ret;\n            }\n        }\n    }\n\n    _z_pending_peers_t pending_peers = _z_pending_peers_null();\n    if (connect_len > 0) {\n        _Z_RETURN_IF_ERR(_z_pending_peers_copy_from_locators(&pending_peers, connect_locators));\n    }\n\n    int32_t remaining_timeout_ms = connect_timeout_ms;\n    if (!transport_opened && (connect_len > 0)) {\n        _z_open_connect_result_t connect_result;\n        _Z_CLEAN_RETURN_IF_ERR(_z_open_connect_locator(zn, &pending_peers, zid, config, connect_timeout_ms,\n                                                       connect_exit_on_failure, &connect_result),\n                               _z_pending_peers_clear(&pending_peers));\n        transport_opened = connect_result.transport_opened;\n        remaining_timeout_ms = connect_result.remaining_timeout_ms;\n    }\n\n    if (!transport_opened) {\n        _Z_ERROR(\"Failed to establish primary transport via listen or connect locators\");\n        _z_pending_peers_clear(&pending_peers);\n        return _Z_ERR_TRANSPORT_OPEN_FAILED;\n    }\n\n#if Z_FEATURE_UNICAST_PEER == 1\n    if (_z_pending_peers_has_pending(&pending_peers)) {\n        pending_peers._timeout_ms = remaining_timeout_ms;\n        pending_peers._start = z_clock_now();\n        pending_peers._sleep_ms = _Z_SLEEP_BACKOFF_MIN_MS;\n\n        // Ownership of pending_peers is transferred to _z_add_peers() if background retries are needed.\n        z_result_t ret = _z_add_peers(&_Z_RC_IN_VAL(zn)->_tp, zid, &pending_peers, config, connect_exit_on_failure);\n        if (connect_exit_on_failure) {\n            if (ret == _Z_ERR_TRANSPORT_OPEN_FAILED) {\n                _z_pending_peers_clear(&pending_peers);\n                return _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY;\n            }\n            _z_pending_peers_clear(&pending_peers);\n            return ret;\n        }\n    }\n#endif\n    _z_pending_peers_clear(&pending_peers);\n    return _Z_RES_OK;\n}\n\nstatic inline z_result_t _z_validate_open_timeout(int32_t timeout_ms) {\n    return (timeout_ms >= -1) ? _Z_RES_OK : _Z_ERR_CONFIG_INVALID_VALUE;\n}\n\nstatic inline const char *_z_open_connect_exit_on_failure_default(z_whatami_t mode) {\n    return (mode == Z_WHATAMI_CLIENT) ? Z_CONFIG_CONNECT_EXIT_ON_FAILURE_CLIENT_DEFAULT\n                                      : Z_CONFIG_CONNECT_EXIT_ON_FAILURE_PEER_DEFAULT;\n}\n\nz_result_t _z_open_locators(_z_session_rc_t *zn, const _z_string_svec_t *listen_locators,\n                            const _z_string_svec_t *connect_locators, const _z_id_t *zid, _z_config_t *config,\n                            z_whatami_t mode) {\n    size_t listen_len = _z_string_svec_len(listen_locators);\n    size_t connect_len = _z_string_svec_len(connect_locators);\n\n    if ((listen_len == 0) && (connect_len == 0)) {\n        _Z_ERROR(\"No listen or connect locators configured\");\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    if (listen_len > 1) {\n        _Z_ERROR(\"Multiple listen locators are not supported in zenoh-pico\");\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    if ((mode == Z_WHATAMI_CLIENT) && (listen_len > 0)) {\n        _Z_ERROR(\"Listen locators are not supported in client mode\");\n        return _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n\n    int32_t listen_timeout_ms;\n    bool listen_exit_on_failure;\n    int32_t connect_timeout_ms;\n    bool connect_exit_on_failure;\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n    _Z_RETURN_IF_ERR(_z_config_get_i32_default(config, Z_CONFIG_LISTEN_TIMEOUT_KEY, Z_CONFIG_LISTEN_TIMEOUT_DEFAULT,\n                                               &listen_timeout_ms));\n    _Z_RETURN_IF_ERR(_z_validate_open_timeout(listen_timeout_ms));\n\n    _Z_RETURN_IF_ERR(_z_config_get_bool_default(config, Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY,\n                                                Z_CONFIG_LISTEN_EXIT_ON_FAILURE_DEFAULT, &listen_exit_on_failure));\n\n    _Z_RETURN_IF_ERR(_z_config_get_i32_default(config, Z_CONFIG_CONNECT_TIMEOUT_KEY, Z_CONFIG_CONNECT_TIMEOUT_DEFAULT,\n                                               &connect_timeout_ms));\n    _Z_RETURN_IF_ERR(_z_validate_open_timeout(connect_timeout_ms));\n\n    const char *connect_exit_default = _z_open_connect_exit_on_failure_default(mode);\n    _Z_RETURN_IF_ERR(_z_config_get_bool_default(config, Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY, connect_exit_default,\n                                                &connect_exit_on_failure));\n#else\n    if (!_z_str_parse_i32(Z_CONFIG_LISTEN_TIMEOUT_DEFAULT, &listen_timeout_ms)) {\n        return _Z_ERR_CONFIG_INVALID_VALUE;\n    }\n    _Z_RETURN_IF_ERR(_z_validate_open_timeout(listen_timeout_ms));\n\n    if (!_z_str_parse_bool(Z_CONFIG_LISTEN_EXIT_ON_FAILURE_DEFAULT, &listen_exit_on_failure)) {\n        return _Z_ERR_CONFIG_INVALID_VALUE;\n    }\n\n    if (!_z_str_parse_i32(Z_CONFIG_CONNECT_TIMEOUT_DEFAULT, &connect_timeout_ms)) {\n        return _Z_ERR_CONFIG_INVALID_VALUE;\n    }\n    _Z_RETURN_IF_ERR(_z_validate_open_timeout(connect_timeout_ms));\n\n    if (!_z_str_parse_bool(_z_open_connect_exit_on_failure_default(mode), &connect_exit_on_failure)) {\n        return _Z_ERR_CONFIG_INVALID_VALUE;\n    }\n#endif\n\n    switch (mode) {\n        case Z_WHATAMI_CLIENT:\n            return _z_open_locators_client(zn, connect_locators, zid, config, connect_timeout_ms);\n\n        case Z_WHATAMI_PEER: {\n            _z_string_t *listen_locator = (listen_len == 1) ? _z_string_svec_get(listen_locators, 0) : NULL;\n            return _z_open_locators_peer(zn, listen_locator, connect_locators, zid, config, listen_timeout_ms,\n                                         listen_exit_on_failure, connect_timeout_ms, connect_exit_on_failure);\n        }\n\n        default:\n            return _Z_ERR_CONFIG_INVALID_MODE;\n    }\n}\n\n/**\n * Open transports based on the configured listen and connect locators.\n *\n * Semantics:\n * - A \"primary transport\" must be established before this function returns.\n *   This is achieved by either:\n *     - successfully binding a listen locator, or\n *     - successfully opening one connect locator.\n *\n * - In peer mode:\n *     - If a listen locator is provided, it is attempted first.\n *       A successful bind satisfies the primary transport requirement.\n *     - If no primary transport is established via listen, connect locators\n *       are attempted in order, with retry/backoff applied to retryable failures.\n *\n * - In client mode:\n *     - Only connect locators are used.\n *     - Connect locators are alternatives and at least one must succeed.\n *\n * - Connect locator behaviour:\n *     - Locators are attempted in sequence.\n *     - Retryable failures are retried with exponential backoff until timeout.\n *     - Non-retryable failures permanently exclude the locator from further attempts.\n *     - If configured, a non-retryable failure may cause immediate exit.\n *\n * - Once a primary transport is established in peer mode:\n *     - Remaining connect locators are treated as additional peers and may be added.\n *     - Peer addition may retry synchronously or be continued by a background task, depending on configuration.\n *     - If not all peers are added:\n *         - either an error is returned, or\n *         - partial connectivity is accepted, depending on configuration.\n *\n * - Timeout semantics:\n *     - A timeout of 0 disables retries.\n *     - A timeout of -1 allows infinite retry.\n *\n * Returns:\n * - _Z_RES_OK on success (primary transport established, and peer policy satisfied).\n * - An error if no primary transport could be established, or if peer policy requires\n *   failure (e.g. exit-on-failure with incomplete connectivity).\n */\nz_result_t _z_open(_z_session_rc_t *zn, _z_config_t *config, const _z_id_t *zid) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_RC_IN_VAL(zn)->_tp._type = _Z_TRANSPORT_NONE;\n\n    _z_string_svec_t listen_locators = _z_string_svec_null();\n    _z_string_svec_t connect_locators = _z_string_svec_null();\n\n    ret = _z_locators_by_config(config, &listen_locators, &connect_locators);\n    if (ret == _Z_RES_OK) {\n        z_whatami_t mode;\n        ret = _z_config_get_mode(config, &mode);\n        if (ret == _Z_RES_OK) {\n            _Z_RC_IN_VAL(zn)->_mode = mode;\n\n            if ((_z_string_svec_len(&listen_locators) > 0) || (_z_string_svec_len(&connect_locators) > 0)) {\n                ret = _z_open_locators(zn, &listen_locators, &connect_locators, zid, config, mode);\n            } else {\n                ret = _z_locators_by_scout(config, zid, &connect_locators);\n                if (ret == _Z_RES_OK) {\n                    if (_z_string_svec_len(&connect_locators) == 0) {\n                        ret = _Z_ERR_SCOUT_NO_RESULTS;\n                    } else {\n                        ret = _z_open_locators(zn, &listen_locators, &connect_locators, zid, config, mode);\n                    }\n                }\n            }\n        }\n    }\n\n    _z_string_svec_clear(&listen_locators);\n    _z_string_svec_clear(&connect_locators);\n    return ret;\n}\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\nvoid _z_client_reopen_task_drop(void *ztc_arg) {\n    _z_transport_common_t *tc = (_z_transport_common_t *)ztc_arg;\n    if (tc->_state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        // Drop the weak session reference as the task is being dropped in the middle of reconnection.\n        _z_session_weak_drop(&tc->_session);\n        tc->_state = _Z_TRANSPORT_STATE_CLOSED;\n    }\n}\n\n_z_fut_fn_result_t _z_client_reopen_task_fn(void *ztc_arg, _z_executor_t *executor) {\n    _z_transport_common_t *tc = (_z_transport_common_t *)ztc_arg;\n    _z_transport_tasks_t tasks_handles = tc->_tasks;\n    _z_session_rc_t zs = _z_session_weak_upgrade(&tc->_session);  // should not fail\n    _z_session_t *s = _Z_RC_IN_VAL(&zs);\n    _z_session_weak_drop(&tc->_session);\n\n    if (_z_config_is_empty(&s->_config)) {\n        _z_session_rc_drop(&zs);\n        return _z_fut_fn_result_ready();\n    }\n    _z_session_transport_mutex_lock(s);\n    z_result_t ret = _z_open(&zs, &s->_config, &s->_local_zid);\n    _z_session_transport_mutex_unlock(s);\n    if (ret != _Z_RES_OK) {\n        if (ret == _Z_ERR_TRANSPORT_OPEN_FAILED || ret == _Z_ERR_SCOUT_NO_RESULTS ||\n            ret == _Z_ERR_TRANSPORT_TX_FAILED || ret == _Z_ERR_TRANSPORT_RX_FAILED ||\n            ret == _Z_ERR_TRANSPORT_RX_DURATION_EXPIRED || ret == _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY) {\n            _Z_DEBUG(\"Reopen failed, next try in 1s\");\n            tc->_session = _z_session_rc_clone_as_weak(&zs);\n            tc->_state = _Z_TRANSPORT_STATE_RECONNECTING;\n            tc->_tasks = tasks_handles;\n            _z_session_rc_drop(&zs);\n            return _z_fut_fn_result_wake_up_after(1000);\n        } else {\n            _Z_ERROR(\"Reopen failed, will not retry\");\n            tc->_state = _Z_TRANSPORT_STATE_CLOSED;\n            _z_session_rc_drop(&zs);\n            return _z_fut_fn_result_ready();\n        }\n    }\n\n    tc->_tasks = tasks_handles;\n    if (!_z_network_message_slist_is_empty(s->_declaration_cache)) {\n        _z_network_message_slist_t *iter = s->_declaration_cache;\n        while (iter != NULL) {\n            _z_network_message_t *n_msg = _z_network_message_slist_value(iter);\n            ret = _z_send_n_msg(s, n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n            if (ret != _Z_RES_OK) {\n                _Z_DEBUG(\"Send message during reopen failed: %i\", ret);\n                _z_transport_clear(&s->_tp);\n                tc->_session = _z_session_rc_clone_as_weak(&zs);\n                tc->_state = _Z_TRANSPORT_STATE_RECONNECTING;\n                _z_session_rc_drop(&zs);\n                return _z_fut_fn_result_continue();\n            }\n\n            iter = _z_network_message_slist_next(iter);\n        }\n    }\n    _z_session_rc_drop(&zs);\n    _Z_DEBUG(\"Reconnected successfully\");\n    // Resume all sibling tasks that suspended themselves while waiting for reconnection.\n    for (size_t i = 0; i < _Z_TRANSPORT_TASK_COUNT; i++) {\n        _z_executor_resume_suspended_fut(executor, &tc->_tasks._task_handles[i]);\n    }\n    return _z_fut_fn_result_ready();\n}\n\nvoid _z_cache_declaration(_z_session_t *zs, const _z_network_message_t *n_msg) {\n    if (_z_config_is_empty(&zs->_config)) {\n        return;\n    }\n    zs->_declaration_cache = _z_network_message_slist_push_back(zs->_declaration_cache, n_msg);\n}\n\n#define _Z_CACHE_DECLARATION_UNDECLARE_FILTER(tp)                                                                     \\\n    static bool _z_cache_declaration_undeclare_filter_##tp(const _z_network_message_t *left,                          \\\n                                                           const _z_network_message_t *right) {                       \\\n        return left->_tag == _Z_N_DECLARE && right->_tag == _Z_N_DECLARE &&                                           \\\n               left->_body._declare._decl._body._undecl_##tp._id == right->_body._declare._decl._body._decl_##tp._id; \\\n    }\n_Z_CACHE_DECLARATION_UNDECLARE_FILTER(kexpr)\n_Z_CACHE_DECLARATION_UNDECLARE_FILTER(subscriber)\n_Z_CACHE_DECLARATION_UNDECLARE_FILTER(queryable)\n_Z_CACHE_DECLARATION_UNDECLARE_FILTER(token)\n\nstatic bool _z_cache_declaration_undeclare_filter_interest(const _z_network_message_t *left,\n                                                           const _z_network_message_t *right) {\n    return left->_tag == _Z_N_INTEREST && right->_tag == _Z_N_INTEREST &&\n           left->_body._interest._interest._id == right->_body._interest._interest._id;\n}\n\nvoid _z_prune_declaration(_z_session_t *zs, const _z_network_message_t *n_msg) {\n#ifdef Z_BUILD_DEBUG\n    size_t cnt_before = _z_network_message_slist_len(zs->_declaration_cache);\n#endif\n    switch (n_msg->_tag) {\n        case _Z_N_DECLARE: {\n            const _z_declaration_t *decl = &n_msg->_body._declare._decl;\n            switch (decl->_tag) {\n                case _Z_UNDECL_KEXPR:\n                    zs->_declaration_cache = _z_network_message_slist_drop_first_filter(\n                        zs->_declaration_cache, _z_cache_declaration_undeclare_filter_kexpr, n_msg);\n                    break;\n                case _Z_UNDECL_SUBSCRIBER:\n                    zs->_declaration_cache = _z_network_message_slist_drop_first_filter(\n                        zs->_declaration_cache, _z_cache_declaration_undeclare_filter_subscriber, n_msg);\n                    break;\n                case _Z_UNDECL_QUERYABLE:\n                    zs->_declaration_cache = _z_network_message_slist_drop_first_filter(\n                        zs->_declaration_cache, _z_cache_declaration_undeclare_filter_queryable, n_msg);\n                    break;\n                case _Z_UNDECL_TOKEN:\n                    zs->_declaration_cache = _z_network_message_slist_drop_first_filter(\n                        zs->_declaration_cache, _z_cache_declaration_undeclare_filter_token, n_msg);\n                    break;\n                default:\n                    _Z_ERROR(\"Invalid decl for _z_prune_declaration: %i\", decl->_tag);\n            };\n            break;\n        }\n        case _Z_N_INTEREST:\n            zs->_declaration_cache = _z_network_message_slist_drop_first_filter(\n                zs->_declaration_cache, _z_cache_declaration_undeclare_filter_interest, n_msg);\n            break;\n        default:\n            _Z_ERROR(\"Invalid net message for _z_prune_declaration: %i\", n_msg->_tag);\n            return;\n    };\n#ifdef Z_BUILD_DEBUG\n    size_t cnt_after = _z_network_message_slist_len(zs->_declaration_cache);\n    assert(cnt_before == cnt_after + 1);\n#endif\n}\n#endif  // Z_FEATURE_AUTO_RECONNECT == 1\n\nbool _z_session_is_closed(const _z_session_t *session) {\n    return _z_atomic_bool_load((_z_atomic_bool_t *)&session->_is_closed, _z_memory_order_acquire);\n}\n\nbool _z_session_has_router_peer(const _z_session_t *session) {\n    if (session->_tp._type == _Z_TRANSPORT_UNICAST_TYPE) {\n        _z_transport_peer_unicast_slist_t *peers = session->_tp._transport._unicast._peers;\n        while (peers != NULL) {\n            _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(peers);\n            if (peer->common._remote_whatami == Z_WHATAMI_ROUTER) {\n                return true;\n            }\n            peers = _z_transport_peer_unicast_slist_next(peers);\n        }\n    } else if (session->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE) {\n        _z_transport_peer_multicast_slist_t *peers = session->_tp._transport._multicast._peers;\n        while (peers != NULL) {\n            _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(peers);\n            if (peer->common._remote_whatami == Z_WHATAMI_ROUTER) {\n                return true;\n            }\n            peers = _z_transport_peer_multicast_slist_next(peers);\n        }\n    }\n    return false;\n}\n\n_z_session_rc_t _z_session_weak_upgrade_if_open(const _z_session_weak_t *weak) {\n    _z_session_rc_t sess_rc = _z_session_weak_upgrade(weak);\n    if (!_Z_RC_IS_NULL(&sess_rc) && _z_session_is_closed(_Z_RC_IN_VAL(&sess_rc))) {\n        _z_session_rc_drop(&sess_rc);\n    }\n    return sess_rc;\n}\n\n_z_config_t *_z_info(const _z_session_t *zn) {\n    _z_config_t *ps = (_z_config_t *)z_malloc(sizeof(_z_config_t));\n    if (ps != NULL) {\n        _z_config_init(ps);\n        _z_string_t s = _z_id_to_string(&zn->_local_zid);\n        _zp_config_insert_string(ps, Z_INFO_PID_KEY, &s);\n        _z_string_clear(&s);\n\n        switch (zn->_tp._type) {\n            case _Z_TRANSPORT_UNICAST_TYPE:\n                _zp_unicast_info_session(&zn->_tp, ps, zn->_mode);\n                break;\n            case _Z_TRANSPORT_MULTICAST_TYPE:\n            case _Z_TRANSPORT_RAWETH_TYPE:\n                _zp_multicast_info_session(&zn->_tp, ps);\n                break;\n            default:\n                break;\n        }\n    }\n\n    return ps;\n}\n\nz_result_t _zp_read(_z_session_t *zn, bool single_read) { return _z_read(&zn->_tp, single_read); }\n\nz_result_t _zp_send_keep_alive(_z_session_t *zn) { return _z_send_keep_alive(&zn->_tp); }\n\nz_result_t _zp_send_join(_z_session_t *zn) { return _z_send_join(&zn->_tp); }\n\nz_result_t _zp_start_transport_tasks(_z_session_t *zn) {\n    switch (zn->_tp._type) {\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_common_t *tc = &zn->_tp._transport._unicast._common;\n            // Order must match _Z_TRANSPORT_TASK_* index constants.\n            _z_fut_fn_t tasks[_Z_TRANSPORT_TASK_COUNT] = {0};\n            tasks[_Z_TRANSPORT_TASK_KEEP_ALIVE] = _zp_unicast_keep_alive_task_fn;\n            tasks[_Z_TRANSPORT_TASK_LEASE] = _zp_unicast_lease_task_fn;\n            tasks[_Z_TRANSPORT_TASK_READ] = _zp_unicast_read_task_fn;\n#if Z_FEATURE_UNICAST_PEER == 1\n            tasks[_Z_TRANSPORT_TASK_ADD_PEERS] = _zp_add_peers_task_fn;\n#endif\n\n            for (size_t i = 0; i < _ZP_ARRAY_SIZE(tasks); i++) {\n                if (tasks[i] == NULL) continue;\n                _z_fut_t f = _z_fut_null();\n                f._fut_arg = &zn->_tp._transport._unicast;\n                f._fut_fn = tasks[i];\n                _z_fut_handle_t h = _z_runtime_spawn(&zn->_runtime, &f);\n                if (_z_fut_handle_is_null(h)) {\n                    _Z_ERROR_RETURN(_Z_ERR_FAILED_TO_SPAWN_TASK);\n                }\n#if Z_FEATURE_AUTO_RECONNECT == 1\n                tc->_tasks._task_handles[i] = h;\n#endif\n            }\n            break;\n        }\n#endif\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_MULTICAST_TYPE: {\n            _z_transport_common_t *tc = &zn->_tp._transport._multicast._common;\n            // Order must match _Z_TRANSPORT_TASK_* index constants.\n            _z_fut_fn_t tasks[_Z_TRANSPORT_TASK_COUNT] = {0};\n            tasks[_Z_TRANSPORT_TASK_KEEP_ALIVE] = _zp_multicast_keep_alive_task_fn;\n            tasks[_Z_TRANSPORT_TASK_LEASE] = _zp_multicast_lease_task_fn;\n            tasks[_Z_TRANSPORT_TASK_READ] = _zp_multicast_read_task_fn;\n            tasks[_Z_TRANSPORT_TASK_SEND_JOIN] = _zp_multicast_send_join_task_fn;\n\n            for (size_t i = 0; i < _ZP_ARRAY_SIZE(tasks); i++) {\n                if (tasks[i] == NULL) continue;\n                _z_fut_t f = _z_fut_null();\n                f._fut_arg = &zn->_tp._transport._multicast;\n                f._fut_fn = tasks[i];\n                _z_fut_handle_t h = _z_runtime_spawn(&zn->_runtime, &f);\n                if (_z_fut_handle_is_null(h)) {\n                    _Z_ERROR_RETURN(_Z_ERR_FAILED_TO_SPAWN_TASK);\n                }\n#if Z_FEATURE_AUTO_RECONNECT == 1\n                tc->_tasks._task_handles[i] = h;\n#endif\n            }\n            break;\n        }\n#endif\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            _z_transport_common_t *tc = &zn->_tp._transport._raweth._common;\n            // Order must match _Z_TRANSPORT_TASK_* index constants.\n            _z_fut_fn_t tasks[_Z_TRANSPORT_TASK_COUNT] = {0};\n            tasks[_Z_TRANSPORT_TASK_KEEP_ALIVE] = _zp_multicast_keep_alive_task_fn;\n            tasks[_Z_TRANSPORT_TASK_LEASE] = _zp_multicast_lease_task_fn;\n            tasks[_Z_TRANSPORT_TASK_READ] = _zp_raweth_read_task_fn;\n            tasks[_Z_TRANSPORT_TASK_SEND_JOIN] = _zp_multicast_send_join_task_fn;\n\n            for (size_t i = 0; i < _ZP_ARRAY_SIZE(tasks); i++) {\n                if (tasks[i] == NULL) continue;\n                _z_fut_t f = _z_fut_null();\n                f._fut_arg = &zn->_tp._transport._raweth;\n                f._fut_fn = tasks[i];\n                _z_fut_handle_t h = _z_runtime_spawn(&zn->_runtime, &f);\n                if (_z_fut_handle_is_null(h)) {\n                    _Z_ERROR_RETURN(_Z_ERR_FAILED_TO_SPAWN_TASK);\n                }\n#if Z_FEATURE_AUTO_RECONNECT == 1\n                tc->_tasks._task_handles[i] = h;\n#endif\n            }\n            break;\n        }\n#endif\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            return _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/net/subscribe.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/net/subscribe.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\nvoid _z_subscriber_clear(_z_subscriber_t *sub) {\n    _z_session_weak_drop(&sub->_zn);\n    _z_sync_group_drop(&sub->_callback_drop_sync_group);\n    *sub = _z_subscriber_null();\n}\n\nvoid _z_subscriber_free(_z_subscriber_t **sub) {\n    _z_subscriber_t *ptr = *sub;\n\n    if (ptr != NULL) {\n        _z_subscriber_clear(ptr);\n\n        z_free(ptr);\n        *sub = NULL;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/protocol/codec/core.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/core.h\"\n\n#include \"zenoh-pico/protocol/iobuf.h\"\n\nz_result_t _z_zbuf_read_exact(_z_zbuf_t *zbf, uint8_t *dest, size_t length) {\n    if (length > _z_zbuf_len(zbf)) {\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    _z_zbuf_read_bytes(zbf, dest, 0, length);\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/protocol/codec/declarations.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/declarations.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico/protocol/codec.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/ext.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n// Placeholder value for extension decode\n#define _Z_KEYEXPR_MAPPING_UNKNOWN_REMOTE (uintptr_t)(&empty_id)\n\nz_result_t _z_decl_ext_keyexpr_encode(_z_wbuf_t *wbf, const _z_wireexpr_t *ke, bool has_next_ext) {\n    uint8_t header = _Z_MSG_EXT_ENC_ZBUF | _Z_MSG_EXT_FLAG_M | 0x0f | (has_next_ext ? _Z_FLAG_Z_Z : 0);\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    uint32_t kelen = (uint32_t)(_z_wireexpr_has_suffix(ke) ? _z_string_len(&ke->_suffix) : 0);\n    header = (uint8_t)((_z_wireexpr_is_local(ke) ? 2 : 0) | (kelen != 0 ? 1 : 0));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, 1 + kelen + _z_zint_len(ke->_id)));\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, ke->_id));\n    if (kelen) {\n        _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, (const uint8_t *)_z_string_data(&ke->_suffix), 0, kelen))\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_decl_kexpr_encode(_z_wbuf_t *wbf, const _z_decl_kexpr_t *decl) {\n    uint8_t header = _Z_DECL_KEXPR_MID;\n    int has_kesuffix = _z_wireexpr_has_suffix(&decl->_keyexpr);\n    if (has_kesuffix) {\n        header |= _Z_DECL_KEXPR_FLAG_N;\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, decl->_id));\n    _Z_RETURN_IF_ERR(_z_wireexpr_encode(wbf, has_kesuffix, &decl->_keyexpr))\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_decl_commons_encode(_z_wbuf_t *wbf, uint8_t header, bool has_extensions, uint32_t id,\n                                  const _z_wireexpr_t *keyexpr) {\n    bool has_kesuffix = _z_wireexpr_has_suffix(keyexpr);\n    if (has_extensions) {\n        header |= _Z_FLAG_Z_Z;\n    }\n    if (has_kesuffix) {\n        header |= _Z_DECL_SUBSCRIBER_FLAG_N;\n    }\n    if (_z_wireexpr_is_local(keyexpr)) {\n        header |= _Z_DECL_SUBSCRIBER_FLAG_M;\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, id));\n    return _z_wireexpr_encode(wbf, has_kesuffix, keyexpr);\n}\nz_result_t _z_decl_subscriber_encode(_z_wbuf_t *wbf, const _z_decl_subscriber_t *decl) {\n    uint8_t header = _Z_DECL_SUBSCRIBER_MID;\n    _Z_RETURN_IF_ERR(_z_decl_commons_encode(wbf, header, false, decl->_id, &decl->_keyexpr));\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_kexpr_encode(_z_wbuf_t *wbf, const _z_undecl_kexpr_t *decl) {\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_UNDECL_KEXPR));\n    return _z_zsize_encode(wbf, decl->_id);\n}\nz_result_t _z_undecl_encode(_z_wbuf_t *wbf, uint8_t header, _z_zint_t decl_id, const _z_wireexpr_t *ke) {\n    bool has_keyexpr_ext = _z_wireexpr_check(ke);\n    if (has_keyexpr_ext) {\n        header |= _Z_FLAG_Z_Z;\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, decl_id));\n    if (has_keyexpr_ext) {\n        _Z_RETURN_IF_ERR(_z_decl_ext_keyexpr_encode(wbf, ke, false));\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_subscriber_encode(_z_wbuf_t *wbf, const _z_undecl_subscriber_t *decl) {\n    return _z_undecl_encode(wbf, _Z_UNDECL_SUBSCRIBER_MID, decl->_id, &decl->_ext_keyexpr);\n}\nz_result_t _z_decl_queryable_encode(_z_wbuf_t *wbf, const _z_decl_queryable_t *decl) {\n    uint8_t header = _Z_DECL_QUERYABLE_MID;\n    bool has_info_ext = decl->_ext_queryable_info._complete || (decl->_ext_queryable_info._distance != 0);\n    _Z_RETURN_IF_ERR(_z_decl_commons_encode(wbf, header, has_info_ext, decl->_id, &decl->_keyexpr));\n    if (has_info_ext) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZINT | 0x01));\n        uint8_t flags = 0;\n        if (decl->_ext_queryable_info._complete) {\n            flags |= 0x01;\n        }\n        uint64_t value = (uint64_t)flags | (uint64_t)decl->_ext_queryable_info._distance << 8;\n        _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, value));\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_queryable_encode(_z_wbuf_t *wbf, const _z_undecl_queryable_t *decl) {\n    return _z_undecl_encode(wbf, _Z_UNDECL_QUERYABLE_MID, decl->_id, &decl->_ext_keyexpr);\n}\nz_result_t _z_decl_token_encode(_z_wbuf_t *wbf, const _z_decl_token_t *decl) {\n    uint8_t header = _Z_DECL_TOKEN_MID;\n    _Z_RETURN_IF_ERR(_z_decl_commons_encode(wbf, header, false, decl->_id, &decl->_keyexpr));\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_token_encode(_z_wbuf_t *wbf, const _z_undecl_token_t *decl) {\n    return _z_undecl_encode(wbf, _Z_UNDECL_TOKEN_MID, decl->_id, &decl->_ext_keyexpr);\n}\nz_result_t _z_decl_final_encode(_z_wbuf_t *wbf) {\n    uint8_t header = _Z_DECL_FINAL_MID;\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declaration_encode(_z_wbuf_t *wbf, const _z_declaration_t *decl) {\n    z_result_t ret = _Z_RES_OK;\n    switch (decl->_tag) {\n        case _Z_DECL_KEXPR: {\n            ret = _z_decl_kexpr_encode(wbf, &decl->_body._decl_kexpr);\n        } break;\n        case _Z_UNDECL_KEXPR: {\n            ret = _z_undecl_kexpr_encode(wbf, &decl->_body._undecl_kexpr);\n        } break;\n#if Z_FEATURE_SUBSCRIPTION == 1\n        case _Z_DECL_SUBSCRIBER: {\n            ret = _z_decl_subscriber_encode(wbf, &decl->_body._decl_subscriber);\n        } break;\n        case _Z_UNDECL_SUBSCRIBER: {\n            ret = _z_undecl_subscriber_encode(wbf, &decl->_body._undecl_subscriber);\n        } break;\n#endif\n#if Z_FEATURE_QUERYABLE == 1\n        case _Z_DECL_QUERYABLE: {\n            ret = _z_decl_queryable_encode(wbf, &decl->_body._decl_queryable);\n        } break;\n        case _Z_UNDECL_QUERYABLE: {\n            ret = _z_undecl_queryable_encode(wbf, &decl->_body._undecl_queryable);\n        } break;\n#endif\n#if Z_FEATURE_LIVELINESS == 1\n        case _Z_DECL_TOKEN: {\n            ret = _z_decl_token_encode(wbf, &decl->_body._decl_token);\n        } break;\n        case _Z_UNDECL_TOKEN: {\n            ret = _z_undecl_token_encode(wbf, &decl->_body._undecl_token);\n        } break;\n#endif\n        case _Z_DECL_FINAL: {\n            ret = _z_decl_final_encode(wbf);\n        } break;\n\n        default:\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_SERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_SERIALIZATION_FAILED;\n            break;\n    }\n    return ret;\n}\nz_result_t _z_decl_kexpr_decode(_z_decl_kexpr_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    *decl = _z_decl_kexpr_null();\n    _Z_RETURN_IF_ERR(_z_zint16_decode(&decl->_id, zbf));\n    _Z_RETURN_IF_ERR(\n        _z_wireexpr_decode(&decl->_keyexpr, zbf, _Z_HAS_FLAG(header, _Z_DECL_KEXPR_FLAG_N), true, mapping));\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, 0x15));\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_kexpr_decode(_z_undecl_kexpr_t *decl, _z_zbuf_t *zbf, uint8_t header) {\n    *decl = _z_undecl_kexpr_null();\n    _Z_RETURN_IF_ERR(_z_zint16_decode(&decl->_id, zbf));\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, 0x10));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_undecl_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_wireexpr_t *ke = (_z_wireexpr_t *)ctx;\n    switch (extension->_header) {\n        case _Z_MSG_EXT_ENC_ZBUF | _Z_MSG_EXT_FLAG_M | 0x0f: {\n            _z_zbuf_t _zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            _z_zbuf_t *zbf = &_zbf;\n            uint8_t header;\n            _Z_RETURN_IF_ERR(_z_uint8_decode(&header, zbf));\n            uintptr_t mapping = _Z_HAS_FLAG(header, 2) ? _Z_KEYEXPR_MAPPING_UNKNOWN_REMOTE : _Z_KEYEXPR_MAPPING_LOCAL;\n            _Z_RETURN_IF_ERR(_z_zint16_decode(&ke->_id, zbf));\n            if (_Z_HAS_FLAG(header, 1)) {\n                size_t len = _z_zbuf_len(zbf);\n                ke->_suffix = _z_string_preallocate(len);\n                if (!_z_wireexpr_has_suffix(ke)) {\n                    _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                }\n                _z_zbuf_read_bytes(zbf, (uint8_t *)_z_string_data(&ke->_suffix), 0, len);\n            }\n            ke->_mapping = mapping;\n        } break;\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                return _z_msg_ext_unknown_error(extension, 0x0e);\n            }\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_trivial_decode(_z_zbuf_t *zbf, _z_wireexpr_t *_ext_keyexpr, uint32_t *decl_id, uint8_t header,\n                                    uintptr_t mapping) {\n    _Z_RETURN_IF_ERR(_z_zint32_decode(decl_id, zbf));\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_undecl_decode_extensions, _ext_keyexpr));\n        if (_ext_keyexpr->_mapping == _Z_KEYEXPR_MAPPING_UNKNOWN_REMOTE) {\n            _ext_keyexpr->_mapping = mapping;\n        }\n    }\n    return _Z_RES_OK;\n}\nstatic z_result_t _z_decl_commons_decode(_z_zbuf_t *zbf, uint8_t header, bool *has_extensions, uint32_t *id,\n                                         _z_wireexpr_t *ke, uintptr_t mapping) {\n    *has_extensions = _Z_HAS_FLAG(header, _Z_FLAG_Z_Z);\n    _Z_RETURN_IF_ERR(_z_zint32_decode(id, zbf));\n    _Z_RETURN_IF_ERR(_z_wireexpr_decode(ke, zbf, _Z_HAS_FLAG(header, _Z_DECL_SUBSCRIBER_FLAG_N),\n                                        _Z_HAS_FLAG(header, _Z_DECL_SUBSCRIBER_FLAG_M), mapping));\n    return _Z_RES_OK;\n}\nz_result_t _z_decl_subscriber_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _ZP_UNUSED(ctx);\n    switch (extension->_header) {\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                return _z_msg_ext_unknown_error(extension, 0x14);\n            }\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_decl_subscriber_decode(_z_decl_subscriber_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    bool has_ext;\n    *decl = _z_decl_subscriber_null();\n    _Z_RETURN_IF_ERR(_z_decl_commons_decode(zbf, header, &has_ext, &decl->_id, &decl->_keyexpr, mapping));\n    if (has_ext) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_decl_subscriber_decode_extensions, decl));\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_subscriber_decode(_z_undecl_subscriber_t *decl, _z_zbuf_t *zbf, uint8_t header,\n                                       uintptr_t mapping) {\n    *decl = _z_undecl_subscriber_null();\n    return _z_undecl_trivial_decode(zbf, &decl->_ext_keyexpr, &decl->_id, header, mapping);\n}\nz_result_t _z_decl_queryable_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_decl_queryable_t *decl = (_z_decl_queryable_t *)ctx;\n    switch (extension->_header) {\n        case _Z_MSG_EXT_ENC_ZINT | 0x01: {\n            uint64_t val = extension->_body._zint._val;\n            decl->_ext_queryable_info._complete = _Z_HAS_FLAG(val, 0x01);\n            decl->_ext_queryable_info._distance = (uint16_t)(val >> 8);\n        } break;\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                return _z_msg_ext_unknown_error(extension, 0x11);\n            }\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_decl_queryable_decode(_z_decl_queryable_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    bool has_ext;\n    *decl = _z_decl_queryable_null();\n    _Z_RETURN_IF_ERR(_z_decl_commons_decode(zbf, header, &has_ext, &decl->_id, &decl->_keyexpr, mapping));\n    if (has_ext) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_decl_queryable_decode_extensions, decl));\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_queryable_decode(_z_undecl_queryable_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    *decl = _z_undecl_queryable_null();\n    return _z_undecl_trivial_decode(zbf, &decl->_ext_keyexpr, &decl->_id, header, mapping);\n}\nz_result_t _z_decl_token_decode(_z_decl_token_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    bool has_ext;\n    *decl = _z_decl_token_null();\n    _Z_RETURN_IF_ERR(_z_decl_commons_decode(zbf, header, &has_ext, &decl->_id, &decl->_keyexpr, mapping));\n    if (has_ext) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, 0x12));\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_undecl_token_decode(_z_undecl_token_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    return _z_undecl_trivial_decode(zbf, &decl->_ext_keyexpr, &decl->_id, header, mapping);\n}\n\nz_result_t _z_decl_final_decode(_z_decl_final_t *decl, _z_zbuf_t *zbf, uint8_t header) {\n    // Nothing to do\n    _ZP_UNUSED(decl);\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, 0x13));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declaration_decode(_z_declaration_t *decl, _z_zbuf_t *zbf, uintptr_t mapping) {\n    uint8_t header;\n    _Z_RETURN_IF_ERR(_z_uint8_decode(&header, zbf));\n    z_result_t ret;\n    switch (_Z_MID(header)) {\n        case _Z_DECL_KEXPR_MID: {\n            decl->_tag = _Z_DECL_KEXPR;\n            ret = _z_decl_kexpr_decode(&decl->_body._decl_kexpr, zbf, header, mapping);\n        } break;\n        case _Z_UNDECL_KEXPR_MID: {\n            decl->_tag = _Z_UNDECL_KEXPR;\n            ret = _z_undecl_kexpr_decode(&decl->_body._undecl_kexpr, zbf, header);\n        } break;\n        case _Z_DECL_SUBSCRIBER_MID: {\n            decl->_tag = _Z_DECL_SUBSCRIBER;\n            ret = _z_decl_subscriber_decode(&decl->_body._decl_subscriber, zbf, header, mapping);\n        } break;\n        case _Z_UNDECL_SUBSCRIBER_MID: {\n            decl->_tag = _Z_UNDECL_SUBSCRIBER;\n            ret = _z_undecl_subscriber_decode(&decl->_body._undecl_subscriber, zbf, header, mapping);\n        } break;\n        case _Z_DECL_QUERYABLE_MID: {\n            decl->_tag = _Z_DECL_QUERYABLE;\n            ret = _z_decl_queryable_decode(&decl->_body._decl_queryable, zbf, header, mapping);\n        } break;\n        case _Z_UNDECL_QUERYABLE_MID: {\n            decl->_tag = _Z_UNDECL_QUERYABLE;\n            ret = _z_undecl_queryable_decode(&decl->_body._undecl_queryable, zbf, header, mapping);\n        } break;\n        case _Z_DECL_TOKEN_MID: {\n            decl->_tag = _Z_DECL_TOKEN;\n            ret = _z_decl_token_decode(&decl->_body._decl_token, zbf, header, mapping);\n        } break;\n        case _Z_UNDECL_TOKEN_MID: {\n            decl->_tag = _Z_UNDECL_TOKEN;\n            ret = _z_undecl_token_decode(&decl->_body._undecl_token, zbf, header, mapping);\n        } break;\n        case _Z_DECL_FINAL_MID: {\n            decl->_tag = _Z_DECL_FINAL;\n            ret = _z_decl_final_decode(&decl->_body._decl_final, zbf, header);\n        } break;\n        default: {\n            _Z_INFO(\"Unknown token type\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n    }\n    return ret;\n}\n"
  },
  {
    "path": "src/protocol/codec/ext.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/ext.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/protocol/codec.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\nz_result_t _z_msg_ext_encode_unit(_z_wbuf_t *wbf, const _z_msg_ext_unit_t *ext) {\n    z_result_t ret = _Z_RES_OK;\n    (void)(wbf);\n    (void)(ext);\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_unit(_z_msg_ext_unit_t *ext, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n    (void)(zbf);\n    (void)(ext);\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_unit_na(_z_msg_ext_unit_t *ext, _z_zbuf_t *zbf) {\n    return _z_msg_ext_decode_unit(ext, zbf);\n}\n\nz_result_t _z_msg_ext_encode_zint(_z_wbuf_t *wbf, const _z_msg_ext_zint_t *ext) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, ext->_val))\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_zint(_z_msg_ext_zint_t *ext, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n    ret |= _z_zint64_decode(&ext->_val, zbf);\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_zint_na(_z_msg_ext_zint_t *ext, _z_zbuf_t *zbf) {\n    return _z_msg_ext_decode_zint(ext, zbf);\n}\n\nz_result_t _z_msg_ext_encode_zbuf(_z_wbuf_t *wbf, const _z_msg_ext_zbuf_t *ext) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &ext->_val))\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_zbuf(_z_msg_ext_zbuf_t *ext, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n    ret |= _z_slice_decode(&ext->_val, zbf);\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_zbuf_na(_z_msg_ext_zbuf_t *ext, _z_zbuf_t *zbf) {\n    return _z_msg_ext_decode_zbuf(ext, zbf);\n}\n\n/*------------------ Message Extension ------------------*/\nz_result_t _z_msg_ext_encode(_z_wbuf_t *wbf, const _z_msg_ext_t *ext, bool has_next) {\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_RETURN_IF_ERR(_z_wbuf_write(wbf, (uint8_t)(_Z_EXT_FULL_ID(ext->_header) | (has_next << 7))))\n\n    uint8_t enc = _Z_EXT_ENC(ext->_header);\n    switch (enc) {\n        case _Z_MSG_EXT_ENC_UNIT: {\n            _z_msg_ext_encode_unit(wbf, &ext->_body._unit);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZINT: {\n            _z_msg_ext_encode_zint(wbf, &ext->_body._zint);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZBUF: {\n            _z_msg_ext_encode_zbuf(wbf, &ext->_body._zbuf);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to copy message extension with unknown encoding(%d)\", enc);\n        } break;\n    }\n\n    return ret;\n}\n\nz_result_t _z_msg_ext_unknown_body_decode(_z_msg_ext_body_t *body, uint8_t enc, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n\n    switch (enc) {\n        case _Z_MSG_EXT_ENC_UNIT: {\n            ret |= _z_msg_ext_decode_unit(&body->_unit, zbf);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZINT: {\n            ret |= _z_msg_ext_decode_zint(&body->_zint, zbf);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZBUF: {\n            ret |= _z_msg_ext_decode_zbuf(&body->_zbuf, zbf);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to copy message extension with unknown encoding(%d)\", enc);\n        } break;\n    }\n\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode(_z_msg_ext_t *ext, _z_zbuf_t *zbf, bool *has_next) {\n    z_result_t ret = _Z_RES_OK;\n\n    ret |= _z_uint8_decode(&ext->_header, zbf);  // Decode the header\n    if (ret == _Z_RES_OK) {\n        // TODO: define behaviour on decode failure, regarding zbuf allocation\n        ret |= _z_msg_ext_unknown_body_decode(&ext->_body, _Z_EXT_ENC(ext->_header), zbf);\n    }\n    *has_next = (ext->_header & _Z_MSG_EXT_FLAG_Z) != 0;\n    ext->_header &= _Z_EXT_FULL_ID_MASK;\n\n    return ret;\n}\n\nz_result_t _z_msg_ext_decode_na(_z_msg_ext_t *ext, _z_zbuf_t *zbf, bool *has_next) {\n    return _z_msg_ext_decode(ext, zbf, has_next);\n}\n\nz_result_t _z_msg_ext_vec_encode(_z_wbuf_t *wbf, const _z_msg_ext_vec_t *extensions) {\n    z_result_t ret = _Z_RES_OK;\n    size_t len = _z_msg_ext_vec_len(extensions);\n    if (len > 0) {\n        size_t i;\n        for (i = 0; ret == _Z_RES_OK && i < len - 1; i++) {\n            ret |= _z_msg_ext_encode(wbf, _z_msg_ext_vec_get(extensions, i), true);\n        }\n        if (ret == _Z_RES_OK) {\n            ret |= _z_msg_ext_encode(wbf, _z_msg_ext_vec_get(extensions, i), true);\n        }\n    }\n    return ret;\n}\nz_result_t _z_msg_ext_vec_push_callback(_z_msg_ext_t *extension, _z_msg_ext_vec_t *extensions) {\n    _z_msg_ext_t *ext = (_z_msg_ext_t *)z_malloc(sizeof(_z_msg_ext_t));\n    if (ext == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    *ext = *extension;\n    *extension = _z_msg_ext_make_unit(0);\n    _z_msg_ext_vec_append(extensions, extension);\n    return 0;\n}\nz_result_t _z_msg_ext_vec_decode(_z_msg_ext_vec_t *extensions, _z_zbuf_t *zbf) {\n    _z_msg_ext_vec_reset(extensions);\n    return _z_msg_ext_decode_iter(zbf, (z_result_t(*)(_z_msg_ext_t *, void *))_z_msg_ext_vec_push_callback,\n                                  (void *)extensions);\n}\n\nz_result_t _z_msg_ext_unknown_error(_z_msg_ext_t *extension, uint8_t trace_id) {\n#ifdef ZENOH_LOG_ERROR\n    uint8_t ext_id = _Z_EXT_ID(extension->_header);\n    switch (_Z_EXT_ENC(extension->_header)) {\n        case _Z_MSG_EXT_ENC_UNIT: {\n            _Z_ERROR(\"Unknown mandatory extension found (extension_id: %02x, trace_id: %02x), UNIT\", ext_id, trace_id);\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZINT: {\n            _Z_ERROR(\"Unknown mandatory extension found (extension_id: %02x, trace_id: %02x), ZINT(%02jx)\", ext_id,\n                     trace_id, (uintmax_t)extension->_body._zint._val);\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF: {\n            _z_slice_t buf = extension->_body._zbuf._val;\n            char *hex = (char *)z_malloc(buf.len * 2 + 1);\n            if (hex == NULL) {\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n            for (size_t i = 0; i < buf.len; ++i) {\n                snprintf(hex + 2 * i, 3, \"%02x\", buf.start[i]);\n            }\n            _Z_ERROR(\"Unknown mandatory extension found (extension_id: %02x, trace_id: %02x), ZBUF(%.*s)\", ext_id,\n                     trace_id, (int)buf.len * 2, hex);\n            z_free(hex);\n            break;\n        }\n        default: {\n            _Z_ERROR(\"Unknown mandatory extension found (extension_id: %02x, trace_id: %02x), UNKOWN_ENCODING\", ext_id,\n                     trace_id);\n        }\n    }\n#else\n    _ZP_UNUSED(extension);\n    _ZP_UNUSED(trace_id);\n#endif\n    _Z_ERROR_RETURN(_Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN);\n}\n\nz_result_t _z_msg_ext_skip_non_mandatory(_z_msg_ext_t *extension, void *ctx) {\n    z_result_t ret = _Z_RES_OK;\n    if ((extension->_header & _Z_MSG_EXT_FLAG_M) != 0) {\n        uint8_t trace_id = *(uint8_t *)ctx;\n        ret = _z_msg_ext_unknown_error(extension, trace_id);\n    }\n\n    return ret;\n}\nz_result_t _z_msg_ext_decode_iter(_z_zbuf_t *zbf, z_result_t (*callback)(_z_msg_ext_t *, void *), void *context) {\n    z_result_t ret = _Z_RES_OK;\n    bool has_next = true;\n    while (has_next && ret == _Z_RES_OK) {\n        _z_msg_ext_t ext = _z_msg_ext_make_unit(0);\n        ret |= _z_msg_ext_decode(&ext, zbf, &has_next);\n        if (ret == _Z_RES_OK) {\n            ret |= callback(&ext, context);\n            _z_msg_ext_clear(&ext);\n        }\n    }\n    return ret;\n}\n\nz_result_t _z_msg_ext_skip_non_mandatories(_z_zbuf_t *zbf, uint8_t trace_id) {\n    return _z_msg_ext_decode_iter(zbf, _z_msg_ext_skip_non_mandatory, &trace_id);\n}\n"
  },
  {
    "path": "src/protocol/codec/interest.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/interest.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico/protocol/codec.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/ext.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/core.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#define _Z_INTEREST_CODEC_FLAG_N 0x20\n#define _Z_INTEREST_CODEC_FLAG_M 0x40\n#define _Z_INTEREST_FLAG_COPY_MASK 0x9f  // N & M flags occupy the place of C & F\n\n#define _Z_INTEREST_TRACE_ID 0x13\n\nz_result_t _z_interest_encode(_z_wbuf_t *wbf, const _z_interest_t *interest, bool is_final) {\n    // Set id\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, interest->_id));\n    if (is_final) {\n        return _Z_RES_OK;\n    }\n    // Copy flags but clear current and future that are already processed.\n    uint8_t flags = interest->flags;\n    _Z_CLEAR_FLAG(flags, _Z_INTEREST_FLAG_CURRENT);\n    _Z_CLEAR_FLAG(flags, _Z_INTEREST_FLAG_FUTURE);\n    // Process restricted flag\n    if (_Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_RESTRICTED)) {\n        // Set Named & Mapping flags\n        bool has_kesuffix = _z_wireexpr_has_suffix(&interest->_keyexpr);\n        if (has_kesuffix) {\n            _Z_SET_FLAG(flags, _Z_INTEREST_CODEC_FLAG_N);\n        }\n        if (_z_wireexpr_is_local(&interest->_keyexpr)) {\n            _Z_SET_FLAG(flags, _Z_INTEREST_CODEC_FLAG_M);\n        }\n        // Set decl flags & keyexpr\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, flags));\n        _Z_RETURN_IF_ERR(_z_wireexpr_encode(wbf, has_kesuffix, &interest->_keyexpr));\n    } else {\n        // Set decl flags\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, flags));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_decode(_z_interest_t *interest, _z_zbuf_t *zbf, bool is_final, bool has_ext, uintptr_t mapping) {\n    // Decode id\n    _Z_RETURN_IF_ERR(_z_zint32_decode(&interest->_id, zbf));\n    if (!is_final) {\n        uint8_t flags = 0;\n        // Decode interest flags\n        _Z_RETURN_IF_ERR(_z_uint8_decode(&flags, zbf));\n        // Process restricted flag\n        if (_Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_RESTRICTED)) {\n            // Decode ke\n            _Z_RETURN_IF_ERR(_z_wireexpr_decode(&interest->_keyexpr, zbf, _Z_HAS_FLAG(flags, _Z_INTEREST_CODEC_FLAG_N),\n                                                _Z_HAS_FLAG(flags, _Z_INTEREST_CODEC_FLAG_M), mapping));\n        }\n        // Store interest flags (current and future already processed)\n        interest->flags = (uint8_t)(interest->flags | (flags & _Z_INTEREST_FLAG_COPY_MASK));\n    }\n    if (has_ext) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, _Z_INTEREST_TRACE_ID));\n    }\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/protocol/codec/message.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/definitions/message.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/protocol/codec.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/ext.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/core.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*=============================*/\n/*           Fields            */\n/*=============================*/\n/*------------------ Payload field ------------------*/\nz_result_t _z_payload_encode(_z_wbuf_t *wbf, const _z_slice_t *pld) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _PAYLOAD\");\n    ret |= _z_slice_encode(wbf, pld);\n\n    return ret;\n}\n\nz_result_t _z_payload_decode_na(_z_slice_t *pld, _z_zbuf_t *zbf) {\n    _Z_DEBUG(\"Decoding _PAYLOAD\");\n    return _z_slice_decode(pld, zbf);\n}\n\nz_result_t _z_payload_decode(_z_slice_t *pld, _z_zbuf_t *zbf) { return _z_payload_decode_na(pld, zbf); }\n\nz_result_t _z_id_encode_as_slice(_z_wbuf_t *wbf, const _z_id_t *id) {\n    z_result_t ret = _Z_RES_OK;\n    uint8_t len = _z_id_len(*id);\n\n    if (len != 0) {\n        _z_slice_t buf = _z_slice_alias_buf(id->id, len);\n        ret = _z_slice_encode(wbf, &buf);\n    } else {\n        _Z_DEBUG(\"Attempted to encode invalid ID 0\");\n        _Z_ERROR_LOG(_Z_ERR_MESSAGE_ZENOH_UNKNOWN);\n        ret = _Z_ERR_MESSAGE_ZENOH_UNKNOWN;\n    }\n    return ret;\n}\n\n/// Decodes a `zid` from the zbf, returning a negative value in case of error.\n///\n/// Note that while `_z_id_t` has an error state (full 0s), this function doesn't\n/// guarantee that this state will be set in case of errors.\nz_result_t _z_id_decode_as_slice(_z_id_t *id, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n    uint8_t len = _z_zbuf_read(zbf);\n    _z_zbuf_read_bytes(zbf, id->id, 0, len);\n    memset(id->id + len, 0, 16 - len);\n    return ret;\n}\n\n/*------------------ Timestamp Field ------------------*/\nz_result_t _z_timestamp_encode(_z_wbuf_t *wbf, const _z_timestamp_t *ts) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _TIMESTAMP\");\n\n    _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, ts->time))\n    ret |= _z_id_encode_as_slice(wbf, &ts->id);\n\n    return ret;\n}\nz_result_t _z_timestamp_encode_ext(_z_wbuf_t *wbf, const _z_timestamp_t *ts) {\n    // Encode extension size then timestamp\n    size_t ext_size = (size_t)(_z_zint_len(ts->time) + 1 + _z_id_len(ts->id));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, ext_size));\n    return _z_timestamp_encode(wbf, ts);\n}\n\nz_result_t _z_timestamp_decode(_z_timestamp_t *ts, _z_zbuf_t *zbf) {\n    _Z_DEBUG(\"Decoding _TIMESTAMP\");\n    z_result_t ret = _Z_RES_OK;\n\n    ret |= _z_zint64_decode(&ts->time, zbf);\n    ret |= _z_id_decode_as_slice(&ts->id, zbf);\n    if (ret == _Z_RES_OK) {\n        ts->valid = true;\n    }\n    return ret;\n}\n\n/*------------------ ResKey Field ------------------*/\nz_result_t _z_wireexpr_encode(_z_wbuf_t *wbf, bool has_suffix, const _z_wireexpr_t *fld) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _RESKEY\");\n\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, fld->_id))\n    if (has_suffix == true) {\n        _Z_RETURN_IF_ERR(_z_string_encode(wbf, &fld->_suffix))\n    }\n\n    return ret;\n}\n\nz_result_t _z_wireexpr_decode(_z_wireexpr_t *ke, _z_zbuf_t *zbf, bool has_suffix, bool remote_mapping,\n                              uintptr_t mapping) {\n    _Z_DEBUG(\"Decoding _RESKEY\");\n    z_result_t ret = _Z_RES_OK;\n\n    ret |= _z_zint16_decode(&ke->_id, zbf);\n    ke->_mapping = (remote_mapping) ? mapping : _Z_KEYEXPR_MAPPING_LOCAL;\n    if (has_suffix) {\n        _z_string_t str = _z_string_null();\n        ret |= _z_string_decode(&str, zbf);\n        if (ret == _Z_RES_OK) {\n            ke->_suffix = str;\n        } else {\n            ke->_suffix = _z_string_null();\n        }\n    } else {\n        ke->_suffix = _z_string_null();\n    }\n    return ret;\n}\n\n/*------------------ Locators Field ------------------*/\nz_result_t _z_locators_encode(_z_wbuf_t *wbf, const _z_locator_array_t *la) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _LOCATORS\");\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, la->_len))\n    for (size_t i = 0; i < la->_len; i++) {\n        _z_string_t s = _z_locator_to_string(&la->_val[i]);\n        _Z_RETURN_IF_ERR(_z_string_encode(wbf, &s))\n        _z_string_clear(&s);\n    }\n\n    return ret;\n}\n\nz_result_t _z_locators_decode_na(_z_locator_array_t *a_loc, _z_zbuf_t *zbf) {\n    _Z_DEBUG(\"Decoding _LOCATORS\");\n    z_result_t ret = _Z_RES_OK;\n\n    _z_zint_t len = 0;  // Number of elements in the array\n    ret |= _z_zsize_decode(&len, zbf);\n    if (ret == _Z_RES_OK) {\n        *a_loc = _z_locator_array_make(len);\n\n        // Decode the elements\n        for (size_t i = 0; i < len; i++) {\n            _z_string_t str = _z_string_null();\n            ret |= _z_string_decode(&str, zbf);\n            if (ret == _Z_RES_OK) {\n                _z_locator_init(&a_loc->_val[i]);\n                ret |= _z_locator_from_string(&a_loc->_val[i], &str);\n                _z_string_clear(&str);\n            } else {\n                a_loc->_len = i;\n            }\n        }\n    } else {\n        *a_loc = _z_locator_array_make(0);\n    }\n\n    return ret;\n}\n\nz_result_t _z_locators_decode(_z_locator_array_t *a_loc, _z_zbuf_t *zbf) { return _z_locators_decode_na(a_loc, zbf); }\n\n/*=============================*/\n/*        Zenoh Messages       */\n/*=============================*/\n\nz_result_t _z_source_info_decode(_z_source_info_t *info, _z_zbuf_t *zbf) {\n    uint8_t zidlen = 0;\n    _z_zint_t intbuf;\n    z_result_t ret = _z_uint8_decode(&zidlen, zbf);\n    if (ret == _Z_RES_OK) {\n        zidlen = (zidlen >> 4) + 1;\n        if (_z_zbuf_len(zbf) >= zidlen) {\n            memset(info->_source_id.zid.id, 0, sizeof(info->_source_id.zid.id) / sizeof(info->_source_id.zid.id[0]));\n            _z_zbuf_read_bytes(zbf, info->_source_id.zid.id, 0, zidlen);\n        } else {\n            _Z_INFO(\"Not enough bytes to read\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n    }\n    if (ret == _Z_RES_OK) {\n        ret = _z_zsize_decode(&intbuf, zbf);\n        if (intbuf <= UINT32_MAX) {\n            info->_source_id.eid = (uint32_t)intbuf;\n        } else {\n            _Z_INFO(\"Invalid value decoded\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n    }\n    if (ret == _Z_RES_OK) {\n        ret = _z_zsize_decode(&intbuf, zbf);\n        if (intbuf <= UINT32_MAX) {\n            info->_source_sn = (uint32_t)intbuf;\n        } else {\n            _Z_INFO(\"Invalid value decoded\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n    }\n    return ret;\n}\nz_result_t _z_source_info_encode(_z_wbuf_t *wbf, const _z_source_info_t *info) {\n    z_result_t ret = 0;\n    uint8_t zidlen = _z_id_len(info->_source_id.zid);\n    ret |= _z_uint8_encode(wbf, (uint8_t)((zidlen - 1) << 4));\n    _z_slice_t zid = _z_slice_alias_buf(info->_source_id.zid.id, zidlen);\n    ret |= _z_slice_val_encode(wbf, &zid);\n    ret |= _z_zsize_encode(wbf, info->_source_id.eid);\n    ret |= _z_zsize_encode(wbf, info->_source_sn);\n    return ret;\n}\nz_result_t _z_source_info_encode_ext(_z_wbuf_t *wbf, const _z_source_info_t *info) {\n    z_result_t ret = 0;\n    uint8_t zidlen = _z_id_len(info->_source_id.zid);\n    size_t ext_size = 1u + zidlen + _z_zint_len(info->_source_id.eid) + _z_zint_len(info->_source_sn);\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, ext_size));\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, (uint8_t)((zidlen - 1) << 4)));\n    _z_slice_t zid = _z_slice_alias_buf(info->_source_id.zid.id, zidlen);\n    _Z_RETURN_IF_ERR(_z_slice_val_encode(wbf, &zid));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, info->_source_id.eid));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, info->_source_sn));\n    return ret;\n}\n\n/*------------------ Push Body Field ------------------*/\nz_result_t _z_push_body_encode(_z_wbuf_t *wbf, const _z_push_body_t *pshb) {\n    uint8_t header = pshb->_is_put ? _Z_MID_Z_PUT : _Z_MID_Z_DEL;\n    bool has_source_info = _z_id_check(pshb->_body._put._commons._source_info._source_id.zid) ||\n                           pshb->_body._put._commons._source_info._source_sn != 0 ||\n                           pshb->_body._put._commons._source_info._source_id.eid != 0;\n\n    bool has_attachment = pshb->_is_put && _z_bytes_check(&pshb->_body._put._attachment);\n    bool has_timestamp = _z_timestamp_check(&pshb->_body._put._commons._timestamp);\n    bool has_encoding = false;\n    if (has_source_info || has_attachment) {\n        header |= _Z_FLAG_Z_Z;\n    }\n    if (pshb->_is_put) {\n        if (has_timestamp) {\n            header |= _Z_FLAG_Z_P_T;\n        }\n        has_encoding = _z_encoding_check(&pshb->_body._put._encoding);\n        if (has_encoding) {\n            header |= _Z_FLAG_Z_P_E;\n        }\n    } else {\n        if (has_timestamp) {\n            header |= _Z_FLAG_Z_D_T;\n        }\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    if (has_timestamp) {\n        _Z_RETURN_IF_ERR(_z_timestamp_encode(wbf, &pshb->_body._put._commons._timestamp));\n    }\n\n    if (has_encoding) {\n        _Z_RETURN_IF_ERR(_z_encoding_encode(wbf, &pshb->_body._put._encoding));\n    }\n\n    if (has_source_info) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x01 | (has_attachment ? _Z_FLAG_Z_Z : 0)));\n        _Z_RETURN_IF_ERR(_z_source_info_encode_ext(wbf, &pshb->_body._put._commons._source_info));\n    }\n    if (has_attachment) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x03));\n        _Z_RETURN_IF_ERR(_z_bytes_encode(wbf, &pshb->_body._put._attachment));\n    }\n    if (pshb->_is_put) {\n        _Z_RETURN_IF_ERR(_z_bytes_encode(wbf, &pshb->_body._put._payload));\n    }\n\n    return _Z_RES_OK;\n}\nz_result_t _z_push_body_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_push_body_t *pshb = (_z_push_body_t *)ctx;\n    z_result_t ret = _Z_RES_OK;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZBUF | 0x01: {\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            ret = _z_source_info_decode(&pshb->_body._put._commons._source_info, &zbf);\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x03: {  // Attachment\n            _z_slice_t s;\n            if (_z_slice_is_alloced(&extension->_body._zbuf._val)) {\n                s = _z_slice_steal(&extension->_body._zbuf._val);\n            } else {\n                _Z_RETURN_IF_ERR(_z_slice_copy(&s, &extension->_body._zbuf._val));\n            }\n            ret = _z_bytes_from_slice(&pshb->_body._put._attachment, &s);\n            break;\n        }\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                ret = _z_msg_ext_unknown_error(extension, 0x08);\n            }\n    }\n    return ret;\n}\n\nz_result_t _z_push_body_decode(_z_push_body_t *pshb, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs) {\n    z_result_t ret = _Z_RES_OK;\n    switch (_Z_MID(header)) {\n        case _Z_MID_Z_PUT: {\n            pshb->_is_put = true;\n            if (_Z_HAS_FLAG(header, _Z_FLAG_Z_P_T)) {\n                _Z_RETURN_IF_ERR(_z_timestamp_decode(&pshb->_body._put._commons._timestamp, zbf));\n            }\n            if ((ret == _Z_RES_OK) && _Z_HAS_FLAG(header, _Z_FLAG_Z_P_E)) {\n                _Z_RETURN_IF_ERR(_z_encoding_decode(&pshb->_body._put._encoding, zbf));\n            }\n            if ((ret == _Z_RES_OK) && _Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n                _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_push_body_decode_extensions, pshb));\n            }\n            if (ret == _Z_RES_OK) {\n                _Z_RETURN_IF_ERR(_z_bytes_decode(&pshb->_body._put._payload, zbf, arcs));\n            }\n            break;\n        }\n        case _Z_MID_Z_DEL: {\n            pshb->_is_put = false;\n            if (_Z_HAS_FLAG(header, _Z_FLAG_Z_D_T)) {\n                _Z_RETURN_IF_ERR(_z_timestamp_decode(&pshb->_body._put._commons._timestamp, zbf));\n            }\n            if ((ret == _Z_RES_OK) && _Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n                _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_push_body_decode_extensions, pshb));\n            }\n            break;\n        }\n        default: {\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_ZENOH_UNKNOWN);\n            ret = _Z_ERR_MESSAGE_ZENOH_UNKNOWN;\n        }\n    }\n    return ret;\n}\n\nz_result_t _z_put_encode(_z_wbuf_t *wbf, const _z_msg_put_t *put) {\n    _z_push_body_t body = {._is_put = true, ._body = {._put = *put}};\n    return _z_push_body_encode(wbf, &body);\n}\nz_result_t _z_put_decode(_z_msg_put_t *put, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs) {\n    assert(_Z_MID(header) == _Z_MID_Z_PUT);\n    _z_push_body_t body = {._is_put = true, ._body = {._put = *put}};\n    z_result_t ret = _z_push_body_decode(&body, zbf, header, arcs);\n    *put = body._body._put;\n    return ret;\n}\n\nz_result_t _z_del_encode(_z_wbuf_t *wbf, const _z_msg_del_t *del) {\n    _z_push_body_t body = {._is_put = false, ._body = {._del = *del}};\n    return _z_push_body_encode(wbf, &body);\n}\nz_result_t _z_del_decode(_z_msg_del_t *del, _z_zbuf_t *zbf, uint8_t header) {\n    assert(_Z_MID(header) == _Z_MID_Z_DEL);\n    _z_push_body_t body = {._is_put = false, ._body = {._del = *del}};\n    z_result_t ret = _z_push_body_decode(&body, zbf, header, NULL);\n    *del = body._body._del;\n    return ret;\n}\n\n/*------------------ Query Message ------------------*/\nz_result_t _z_query_encode(_z_wbuf_t *wbf, const _z_msg_query_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    uint8_t header = _Z_MID_Z_QUERY;\n\n    bool has_params = _z_slice_check(&msg->_parameters) && msg->_parameters.len > 0;\n    if (has_params || msg->_implicit_anyke) {\n        _Z_SET_FLAG(header, _Z_FLAG_Z_Q_P);\n    }\n    bool has_consolidation = (msg->_consolidation != Z_CONSOLIDATION_MODE_DEFAULT);\n    if (has_consolidation) {\n        _Z_SET_FLAG(header, _Z_FLAG_Z_Q_C);\n    }\n    _z_msg_query_reqexts_t required_exts = _z_msg_query_required_extensions(msg);\n    if (required_exts.body || required_exts.info || required_exts.attachment) {\n        header |= _Z_FLAG_Z_Z;\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    if (has_consolidation) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, msg->_consolidation));\n    }\n    if (msg->_implicit_anyke) {\n        if (has_params) {\n            _z_slice_t anykey_slice = _z_slice_from_buf_custom_deleter(\n                (uint8_t *)_Z_QUERY_PARAMS_LIST_SEPARATOR _Z_QUERY_PARAMS_KEY_ANYKE,\n                _Z_QUERY_PARAMS_LIST_SEPARATOR_LEN + _Z_QUERY_PARAMS_KEY_ANYKE_LEN, _z_delete_context_static());\n            _z_slice_t combined[2] = {msg->_parameters, anykey_slice};\n            _Z_RETURN_IF_ERR(_z_slices_encode(wbf, combined, 2));\n        } else {\n            _z_slice_t anykey_slice = _z_slice_from_buf_custom_deleter(\n                (uint8_t *)_Z_QUERY_PARAMS_KEY_ANYKE, _Z_QUERY_PARAMS_KEY_ANYKE_LEN, _z_delete_context_static());\n            _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &anykey_slice));\n        }\n    } else if (has_params) {\n        _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &msg->_parameters));\n    }\n\n    if (required_exts.body) {\n        uint8_t extheader = _Z_MSG_EXT_ENC_ZBUF | 0x03;\n        if (required_exts.info || required_exts.attachment) {\n            extheader |= _Z_FLAG_Z_Z;\n        }\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_value_encode(wbf, &msg->_ext_value));\n    }\n    if (required_exts.info) {\n        uint8_t extheader = _Z_MSG_EXT_ENC_ZBUF | 0x01;\n        if (required_exts.attachment) {\n            extheader |= _Z_FLAG_Z_Z;\n        }\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_source_info_encode_ext(wbf, &msg->_ext_info));\n    }\n    if (required_exts.attachment) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x05));\n        _Z_RETURN_IF_ERR(_z_bytes_encode(wbf, &msg->_ext_attachment));\n    }\n    return ret;\n}\n\nz_result_t _z_query_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_msg_query_t *msg = (_z_msg_query_t *)ctx;\n    z_result_t ret = _Z_RES_OK;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZBUF | 0x01: {  // Source Info\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            ret = _z_source_info_decode(&msg->_ext_info, &zbf);\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x03: {  // Payload\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            ret = _z_value_decode(&msg->_ext_value, &zbf);\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x05: {  // Attachment\n            _z_slice_t s;\n            if (_z_slice_is_alloced(&extension->_body._zbuf._val)) {\n                s = _z_slice_steal(&extension->_body._zbuf._val);\n            } else {\n                _Z_RETURN_IF_ERR(_z_slice_copy(&s, &extension->_body._zbuf._val));\n            }\n            ret = _z_bytes_from_slice(&msg->_ext_attachment, &s);\n            break;\n        }\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                ret = _z_msg_ext_unknown_error(extension, 0x09);\n            }\n    }\n    return ret;\n}\n\nz_result_t _z_query_decode(_z_msg_query_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    _Z_DEBUG(\"Decoding _Z_MID_Z_QUERY\");\n    z_result_t ret = _Z_RES_OK;\n    msg->_implicit_anyke = false;\n    // implicit_anyke is always false on reception, since the presence of the _anyke parameter is signaled by\n    // the presence of the _anyke key in the parameters list, which is parsed later.\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Q_C)) {\n        _Z_RETURN_IF_ERR(_z_uint8_decode((uint8_t *)&msg->_consolidation, zbf));\n    } else {\n        msg->_consolidation = Z_CONSOLIDATION_MODE_DEFAULT;\n    }\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Q_P)) {\n        _Z_RETURN_IF_ERR(_z_slice_decode(&msg->_parameters, zbf));\n    } else {\n        _z_slice_clear(&msg->_parameters);\n    }\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_query_decode_extensions, msg));\n    }\n    return ret;\n}\n\nz_result_t _z_reply_encode(_z_wbuf_t *wbf, const _z_msg_reply_t *reply) {\n    uint8_t header = _Z_MID_Z_REPLY;\n    bool has_consolidation = reply->_consolidation != Z_CONSOLIDATION_MODE_DEFAULT;\n    if (has_consolidation) {\n        _Z_SET_FLAG(header, _Z_FLAG_Z_R_C);\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    if (has_consolidation) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, reply->_consolidation));\n    }\n    _Z_RETURN_IF_ERR(_z_push_body_encode(wbf, &reply->_body));\n    return _Z_RES_OK;\n}\nz_result_t _z_reply_decode_extension(_z_msg_ext_t *extension, void *ctx) {\n    _ZP_UNUSED(ctx);\n    z_result_t ret = _Z_RES_OK;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        default:\n            ret = _z_msg_ext_unknown_error(extension, 0x0a);\n            break;\n    }\n    return ret;\n}\nz_result_t _z_reply_decode(_z_msg_reply_t *reply, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs) {\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_R_C)) {\n        _Z_RETURN_IF_ERR(_z_uint8_decode((uint8_t *)&reply->_consolidation, zbf));\n    } else {\n        reply->_consolidation = Z_CONSOLIDATION_MODE_DEFAULT;\n    }\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_reply_decode_extension, reply));\n    }\n    uint8_t put_header = 0;\n    _Z_RETURN_IF_ERR(_z_uint8_decode(&put_header, zbf));\n    _Z_RETURN_IF_ERR(_z_push_body_decode(&reply->_body, zbf, put_header, arcs));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_err_encode(_z_wbuf_t *wbf, const _z_msg_err_t *err) {\n    z_result_t ret = _Z_RES_OK;\n    uint8_t header = _Z_MID_Z_ERR;\n\n    // Encode header\n    bool has_encoding = _z_encoding_check(&err->_encoding);\n    if (has_encoding) {\n        _Z_SET_FLAG(header, _Z_FLAG_Z_E_E);\n    }\n    bool has_sinfo_ext = _z_id_check(err->_ext_source_info._source_id.zid) ||\n                         err->_ext_source_info._source_id.eid != 0 || err->_ext_source_info._source_sn != 0;\n    if (has_sinfo_ext) {\n        _Z_SET_FLAG(header, _Z_FLAG_Z_Z);\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    // Encode encoding\n    if (has_encoding) {\n        _Z_RETURN_IF_ERR(_z_encoding_encode(wbf, &err->_encoding));\n    }\n    // Encode extensions\n    if (has_sinfo_ext) {\n        uint8_t extheader = _Z_MSG_EXT_ENC_ZBUF | 0x01;\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_source_info_encode_ext(wbf, &err->_ext_source_info));\n    }\n    // Encode payload\n    _Z_RETURN_IF_ERR(_z_bytes_encode(wbf, &err->_payload));\n    return ret;\n}\nz_result_t _z_err_decode_extension(_z_msg_ext_t *extension, void *ctx) {\n    z_result_t ret = _Z_RES_OK;\n    _z_msg_err_t *reply = (_z_msg_err_t *)ctx;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZBUF | 0x01: {\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            ret = _z_source_info_decode(&reply->_ext_source_info, &zbf);\n            break;\n        }\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                ret = _z_msg_ext_unknown_error(extension, 0x0a);\n            }\n    }\n    return ret;\n}\nz_result_t _z_err_decode(_z_msg_err_t *err, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs) {\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_E_E)) {\n        _Z_RETURN_IF_ERR(_z_encoding_decode(&err->_encoding, zbf));\n    }\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_err_decode_extension, err));\n    }\n    _Z_RETURN_IF_ERR(_z_bytes_decode(&err->_payload, zbf, arcs));\n    return _Z_RES_OK;\n}\n\n/*=============================*/\n/*       Scouting Messages     */\n/*=============================*/\n/*------------------ Scout Message ------------------*/\nz_result_t _z_scout_encode(_z_wbuf_t *wbf, uint8_t header, const _z_s_msg_scout_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    (void)(header);\n    _Z_DEBUG(\"Encoding _Z_MID_SCOUT\");\n\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, msg->_version))\n\n    uint8_t cbyte = msg->_what & 0x07;\n    uint8_t zid_len = _z_id_len(msg->_zid);\n    if (zid_len > 0) {\n        _Z_SET_FLAG(cbyte, _Z_FLAG_T_SCOUT_I);\n        cbyte |= (uint8_t)(((zid_len - 1) & 0x0F) << 4);\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, cbyte))\n\n    ret |= _z_wbuf_write_bytes(wbf, msg->_zid.id, 0, zid_len);\n\n    return ret;\n}\n\nz_result_t _z_scout_decode(_z_s_msg_scout_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    z_result_t ret = _Z_RES_OK;\n    (void)(header);\n    _Z_DEBUG(\"Decoding _Z_MID_SCOUT\");\n    *msg = (_z_s_msg_scout_t){0};\n\n    ret |= _z_uint8_decode(&msg->_version, zbf);\n\n    uint8_t cbyte = 0;\n    ret |= _z_uint8_decode(&cbyte, zbf);\n    msg->_what = cbyte & 0x07;\n    msg->_zid = _z_id_empty();\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(cbyte, _Z_FLAG_T_SCOUT_I) == true)) {\n        uint8_t zidlen = ((cbyte & 0xF0) >> 4) + (uint8_t)1;\n        _z_zbuf_read_bytes(zbf, msg->_zid.id, 0, zidlen);\n    }\n\n    return ret;\n}\n\n/*------------------ Hello Message ------------------*/\nz_result_t _z_hello_encode(_z_wbuf_t *wbf, uint8_t header, const _z_s_msg_hello_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_MID_HELLO\");\n\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, msg->_version))\n    uint8_t zidlen = _z_id_len(msg->_zid);\n    uint8_t cbyte = 0;\n    cbyte |= _z_whatami_to_uint8(msg->_whatami);\n    cbyte |= (uint8_t)(((zidlen - 1) & 0x0F) << 4);\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, cbyte))\n    _z_slice_t s = _z_slice_alias_buf(msg->_zid.id, zidlen);\n    _Z_RETURN_IF_ERR(_z_slice_val_encode(wbf, &s));\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_HELLO_L) == true) {\n        _Z_RETURN_IF_ERR(_z_locators_encode(wbf, &msg->_locators))\n    }\n\n    return ret;\n}\n\nz_result_t _z_hello_decode_na(_z_s_msg_hello_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    _Z_DEBUG(\"Decoding _Z_MID_HELLO\");\n    z_result_t ret = _Z_RES_OK;\n    *msg = (_z_s_msg_hello_t){0};\n\n    ret |= _z_uint8_decode(&msg->_version, zbf);\n\n    uint8_t cbyte = 0;\n    ret |= _z_uint8_decode(&cbyte, zbf);\n    msg->_whatami = _z_whatami_from_uint8(cbyte);\n    uint8_t zidlen = ((cbyte & 0xF0) >> 4) + (uint8_t)1;\n\n    if (ret == _Z_RES_OK) {\n        msg->_zid = _z_id_empty();\n        _z_zbuf_read_bytes(zbf, msg->_zid.id, 0, zidlen);\n    } else {\n        msg->_zid = _z_id_empty();\n    }\n\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_HELLO_L) == true)) {\n        ret |= _z_locators_decode(&msg->_locators, zbf);\n        if (ret != _Z_RES_OK) {\n            msg->_locators = _z_locator_array_empty();\n        }\n    } else {\n        msg->_locators = _z_locator_array_empty();\n    }\n\n    return ret;\n}\n\nz_result_t _z_hello_decode(_z_s_msg_hello_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    return _z_hello_decode_na(msg, zbf, header);\n}\n\nz_result_t _z_scouting_message_encode(_z_wbuf_t *wbf, const _z_scouting_message_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n\n    uint8_t header = msg->_header;\n\n    _Z_RETURN_IF_ERR(_z_wbuf_write(wbf, header))\n    switch (_Z_MID(msg->_header)) {\n        case _Z_MID_SCOUT: {\n            ret |= _z_scout_encode(wbf, msg->_header, &msg->_body._scout);\n        } break;\n\n        case _Z_MID_HELLO: {\n            ret |= _z_hello_encode(wbf, msg->_header, &msg->_body._hello);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to encode session message with unknown ID(%d)\", _Z_MID(msg->_header));\n            ret |= _Z_ERR_MESSAGE_TRANSPORT_UNKNOWN;\n        } break;\n    }\n\n    return ret;\n}\nz_result_t _z_scouting_message_decode_na(_z_scouting_message_t *msg, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n    *msg = (_z_scouting_message_t){0};\n\n    bool is_last = false;\n\n    do {\n        ret |= _z_uint8_decode(&msg->_header, zbf);  // Decode the header\n        if (ret == _Z_RES_OK) {\n            uint8_t mid = _Z_MID(msg->_header);\n            switch (mid) {\n                case _Z_MID_SCOUT: {\n                    ret |= _z_scout_decode(&msg->_body._scout, zbf, msg->_header);\n                    is_last = true;\n                } break;\n\n                case _Z_MID_HELLO: {\n                    ret |= _z_hello_decode(&msg->_body._hello, zbf, msg->_header);\n                    is_last = true;\n                } break;\n\n                default: {\n                    _Z_INFO(\"WARNING: Trying to decode scouting message with unknown ID(0x%x)\", mid);\n                    ret |= _Z_ERR_MESSAGE_TRANSPORT_UNKNOWN;\n                    is_last = true;\n                } break;\n            }\n        } else {\n            msg->_header = 0xFF;\n        }\n    } while ((ret == _Z_RES_OK) && (is_last == false));\n\n    if ((ret == _Z_RES_OK) && (msg->_header & _Z_MSG_EXT_FLAG_Z) != 0) {\n        ret |= _z_msg_ext_skip_non_mandatories(zbf, 0x06);\n    }\n\n    return ret;\n}\n\nz_result_t _z_scouting_message_decode(_z_scouting_message_t *s_msg, _z_zbuf_t *zbf) {\n    return _z_scouting_message_decode_na(s_msg, zbf);\n}\n"
  },
  {
    "path": "src/protocol/codec/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/network.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/protocol/codec.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/declarations.h\"\n#include \"zenoh-pico/protocol/codec/ext.h\"\n#include \"zenoh-pico/protocol/codec/interest.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/core.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ Push Message ------------------*/\n\nz_result_t _z_push_encode(_z_wbuf_t *wbf, const _z_n_msg_push_t *msg) {\n    uint8_t header = _Z_MID_N_PUSH | (_z_wireexpr_is_local(&msg->_key) ? _Z_FLAG_N_REQUEST_M : 0);\n    bool has_suffix = _z_wireexpr_has_suffix(&msg->_key);\n    bool has_qos_ext = msg->_qos._val != _Z_N_QOS_DEFAULT._val;\n    bool has_timestamp_ext = _z_timestamp_check(&msg->_timestamp);\n    if (has_suffix) {\n        header |= _Z_FLAG_N_REQUEST_N;\n    }\n    if (has_qos_ext || has_timestamp_ext) {\n        header |= _Z_FLAG_N_Z;\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_wireexpr_encode(wbf, has_suffix, &msg->_key));\n\n    if (has_qos_ext) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, (uint8_t)(_Z_MSG_EXT_ENC_ZINT | 0x01 | (has_timestamp_ext << 7))));\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, msg->_qos._val));\n    }\n\n    if (has_timestamp_ext) {\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x02));\n        _Z_RETURN_IF_ERR(_z_timestamp_encode_ext(wbf, &msg->_timestamp));\n    }\n\n    _Z_RETURN_IF_ERR(_z_push_body_encode(wbf, &msg->_body));\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_push_decode_ext_cb(_z_msg_ext_t *extension, void *ctx) {\n    z_result_t ret = _Z_RES_OK;\n    _z_n_msg_push_t *msg = (_z_n_msg_push_t *)ctx;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZINT | 0x01: {  // QOS ext\n            if (extension->_body._zint._val > UINT32_MAX) {\n                _Z_INFO(\"Invalid value decoded\");\n                _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            }\n            msg->_qos = (_z_n_qos_t){._val = (uint8_t)extension->_body._zint._val};\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x02: {  // Timestamp ext\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            ret = _z_timestamp_decode(&msg->_timestamp, &zbf);\n            break;\n        }\n        default:\n            if ((extension->_header & _Z_MSG_EXT_FLAG_M) != 0) {\n                ret = _z_msg_ext_unknown_error(extension, 0x07);\n            }\n    }\n    return ret;\n}\n\nz_result_t _z_push_decode(_z_n_msg_push_t *msg, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs,\n                          uintptr_t mapping) {\n    z_result_t ret = _Z_RES_OK;\n    msg->_qos = _Z_N_QOS_DEFAULT;\n    ret |= _z_wireexpr_decode(&msg->_key, zbf, _Z_HAS_FLAG(header, _Z_FLAG_N_PUSH_N),\n                              _Z_HAS_FLAG(header, _Z_FLAG_N_PUSH_M), mapping);\n    if ((ret == _Z_RES_OK) && _Z_HAS_FLAG(header, _Z_FLAG_N_Z)) {\n        ret = _z_msg_ext_decode_iter(zbf, _z_push_decode_ext_cb, msg);\n    }\n    if (ret == _Z_RES_OK) {\n        uint8_t msgheader;\n        _Z_RETURN_IF_ERR(_z_uint8_decode(&msgheader, zbf));\n        _Z_RETURN_IF_ERR(_z_push_body_decode(&msg->_body, zbf, msgheader, arcs));\n    }\n\n    return ret;\n}\n\n/*------------------ Request Message ------------------*/\nz_result_t _z_request_encode(_z_wbuf_t *wbf, const _z_n_msg_request_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    uint8_t header = _Z_MID_N_REQUEST | (_z_wireexpr_is_local(&msg->_key) ? _Z_FLAG_N_REQUEST_M : 0);\n    bool has_suffix = _z_wireexpr_has_suffix(&msg->_key);\n    if (has_suffix) {\n        header |= _Z_FLAG_N_REQUEST_N;\n    }\n    _z_n_msg_request_exts_t exts = _z_n_msg_request_needed_exts(msg);\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, (uint8_t)(header | (exts.n != 0 ? _Z_FLAG_Z_Z : 0))));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_rid));\n    _Z_RETURN_IF_ERR(_z_wireexpr_encode(wbf, has_suffix, &msg->_key));\n\n    if (exts.ext_qos) {\n        exts.n -= 1;\n        uint8_t extheader = 0x01 | _Z_MSG_EXT_ENC_ZINT | (exts.n ? _Z_FLAG_Z_Z : 0);\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_ext_qos._val));\n    }\n    if (exts.ext_tstamp) {\n        exts.n -= 1;\n        uint8_t extheader = 0x02 | _Z_MSG_EXT_ENC_ZBUF | (exts.n ? _Z_FLAG_Z_Z : 0);\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_timestamp_encode_ext(wbf, &msg->_ext_timestamp));\n    }\n    if (exts.ext_target) {\n        exts.n -= 1;\n        uint8_t extheader = 0x04 | _Z_MSG_EXT_ENC_ZINT | (exts.n ? _Z_FLAG_Z_Z : 0) | _Z_MSG_EXT_FLAG_M;\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_ext_target));\n    }\n    if (exts.ext_budget) {\n        exts.n -= 1;\n        uint8_t extheader = 0x05 | _Z_MSG_EXT_ENC_ZINT | (exts.n ? _Z_FLAG_Z_Z : 0);\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_ext_budget));\n    }\n    if (exts.ext_timeout_ms) {\n        exts.n -= 1;\n        uint8_t extheader = 0x06 | _Z_MSG_EXT_ENC_ZINT | (exts.n ? _Z_FLAG_Z_Z : 0);\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, msg->_ext_timeout_ms));\n    }\n\n    switch (msg->_tag) {\n        case _Z_REQUEST_QUERY: {\n            _Z_RETURN_IF_ERR(_z_query_encode(wbf, &msg->_body._query));\n        } break;\n        case _Z_REQUEST_PUT: {\n            _Z_RETURN_IF_ERR(_z_put_encode(wbf, &msg->_body._put));\n        } break;\n        case _Z_REQUEST_DEL: {\n            _Z_RETURN_IF_ERR(_z_del_encode(wbf, &msg->_body._del));\n        } break;\n    }\n    return ret;\n}\nz_result_t _z_request_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_n_msg_request_t *msg = (_z_n_msg_request_t *)ctx;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case 0x01 | _Z_MSG_EXT_ENC_ZINT: {  // QOS ext\n            if (extension->_body._zint._val > UINT8_MAX) {\n                _Z_INFO(\"Invalid value decoded\");\n                _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            }\n            msg->_ext_qos = (_z_n_qos_t){._val = (uint8_t)extension->_body._zint._val};\n            break;\n        }\n        case 0x02 | _Z_MSG_EXT_ENC_ZBUF: {  // Timestamp ext\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            _Z_RETURN_IF_ERR(_z_timestamp_decode(&msg->_ext_timestamp, &zbf));\n            break;\n        }\n        case 0x04 | _Z_MSG_EXT_ENC_ZINT | _Z_MSG_EXT_FLAG_M: {\n            msg->_ext_target = (uint8_t)extension->_body._zint._val;\n            if (msg->_ext_target > 2) {\n                _Z_INFO(\"Invalid value decoded\");\n                _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            }\n        } break;\n        case 0x05 | _Z_MSG_EXT_ENC_ZINT: {\n            if (extension->_body._zint._val > UINT32_MAX) {\n                _Z_INFO(\"Request extension budget was truncated to u32.\");\n            }\n            msg->_ext_budget = (uint32_t)extension->_body._zint._val;\n        } break;\n        case 0x06 | _Z_MSG_EXT_ENC_ZINT: {\n            msg->_ext_timeout_ms = extension->_body._zint._val;\n        } break;\n        default:\n            if ((extension->_header & _Z_MSG_EXT_FLAG_M) != 0) {\n                return _z_msg_ext_unknown_error(extension, 0x16);\n            }\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_request_decode(_z_n_msg_request_t *msg, _z_zbuf_t *zbf, const uint8_t header, _z_arc_slice_t *arcs,\n                             uintptr_t mapping) {\n    msg->_ext_qos = _Z_N_QOS_DEFAULT;\n    _Z_RETURN_IF_ERR(_z_zsize_decode(&msg->_rid, zbf));\n    _Z_RETURN_IF_ERR(_z_wireexpr_decode(&msg->_key, zbf, _Z_HAS_FLAG(header, _Z_FLAG_N_REQUEST_N),\n                                        _Z_HAS_FLAG(header, _Z_FLAG_N_REQUEST_M), mapping));\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_request_decode_extensions, msg));\n    }\n    uint8_t zheader;\n    _Z_RETURN_IF_ERR(_z_uint8_decode(&zheader, zbf));\n    switch (_Z_MID(zheader)) {\n        case _Z_MID_Z_QUERY: {\n            msg->_tag = _Z_REQUEST_QUERY;\n            _Z_RETURN_IF_ERR(_z_query_decode(&msg->_body._query, zbf, zheader));\n        } break;\n        case _Z_MID_Z_PUT: {\n            msg->_tag = _Z_REQUEST_PUT;\n            _Z_RETURN_IF_ERR(_z_put_decode(&msg->_body._put, zbf, zheader, arcs));\n        } break;\n        case _Z_MID_Z_DEL: {\n            msg->_tag = _Z_REQUEST_DEL;\n            _Z_RETURN_IF_ERR(_z_del_decode(&msg->_body._del, zbf, zheader));\n        } break;\n        default:\n            _Z_INFO(\"Unknown request type received: %d\", _Z_MID(zheader));\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    return _Z_RES_OK;\n}\n\n/*------------------ Response Message ------------------*/\nz_result_t _z_response_encode(_z_wbuf_t *wbf, const _z_n_msg_response_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    uint8_t header = _Z_MID_N_RESPONSE;\n    _Z_DEBUG(\"Encoding _Z_MID_N_RESPONSE\");\n    bool has_qos_ext = msg->_ext_qos._val != _Z_N_QOS_DEFAULT._val;\n    bool has_ts_ext = _z_timestamp_check(&msg->_ext_timestamp);\n    bool has_responder_ext = _z_id_check(msg->_ext_responder._zid) || msg->_ext_responder._eid != 0;\n    int n_ext = (has_qos_ext ? 1 : 0) + (has_ts_ext ? 1 : 0) + (has_responder_ext ? 1 : 0);\n    bool has_suffix = _z_wireexpr_has_suffix(&msg->_key);\n    if (_z_wireexpr_is_local(&msg->_key)) {\n        _Z_SET_FLAG(header, _Z_FLAG_N_RESPONSE_M);\n    }\n    if (has_suffix) {\n        _Z_SET_FLAG(header, _Z_FLAG_N_RESPONSE_N);\n    }\n    if (n_ext != 0) {\n        _Z_SET_FLAG(header, _Z_FLAG_Z_Z);\n    }\n\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_request_id));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_key._id));\n    if (has_suffix) {\n        _Z_RETURN_IF_ERR(_z_string_encode(wbf, &msg->_key._suffix))\n    }\n    if (has_qos_ext) {\n        n_ext -= 1;\n        uint8_t extheader = _Z_MSG_EXT_ENC_ZINT | 0x01;\n        if (n_ext != 0) {\n            extheader |= _Z_FLAG_Z_Z;\n        }\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_ext_qos._val));\n    }\n    if (has_ts_ext) {\n        n_ext -= 1;\n        uint8_t extheader = _Z_MSG_EXT_ENC_ZBUF | 0x02 | (n_ext != 0 ? _Z_FLAG_Z_Z : 0);\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_timestamp_encode_ext(wbf, &msg->_ext_timestamp));\n    }\n    if (has_responder_ext) {\n        n_ext -= 1;\n        uint8_t extheader = _Z_MSG_EXT_ENC_ZBUF | 0x03 | (n_ext != 0 ? _Z_FLAG_Z_Z : 0);\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        uint8_t zidlen = _z_id_len(msg->_ext_responder._zid);\n        extheader = (uint8_t)((zidlen - 1) << 4);\n        size_t ext_size = (size_t)(zidlen + 1 + _z_zint_len(msg->_ext_responder._eid));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, ext_size));\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader));\n        _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, msg->_ext_responder._zid.id, 0, zidlen));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_ext_responder._eid));\n    }\n    switch (msg->_tag) {\n        case _Z_RESPONSE_BODY_REPLY: {\n            _Z_RETURN_IF_ERR(_z_reply_encode(wbf, &msg->_body._reply));\n            break;\n        }\n        case _Z_RESPONSE_BODY_ERR: {\n            _Z_RETURN_IF_ERR(_z_err_encode(wbf, &msg->_body._err));\n            break;\n        }\n    }\n    return ret;\n}\n\nz_result_t _z_response_decode_extension(_z_msg_ext_t *extension, void *ctx) {\n    z_result_t ret = _Z_RES_OK;\n    _z_n_msg_response_t *msg = (_z_n_msg_response_t *)ctx;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZINT | 0x01: {\n            msg->_ext_qos._val = (uint8_t)extension->_body._zint._val;\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x02: {\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            ret = _z_timestamp_decode(&msg->_ext_timestamp, &zbf);\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x03: {\n            _z_zbuf_t _zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            _z_zbuf_t *zbf = &_zbf;\n            uint8_t header;\n            _Z_RETURN_IF_ERR(_z_uint8_decode(&header, zbf));\n            uint8_t zidlen = (header >> 4) + (uint8_t)1;\n            _Z_RETURN_IF_ERR(_z_zbuf_read_exact(zbf, msg->_ext_responder._zid.id, zidlen));\n            _Z_RETURN_IF_ERR(_z_zint32_decode(&msg->_ext_responder._eid, zbf));\n            break;\n        }\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                ret = _z_msg_ext_unknown_error(extension, 0x0d);\n            }\n    }\n    return ret;\n}\n\nz_result_t _z_response_decode(_z_n_msg_response_t *msg, _z_zbuf_t *zbf, uint8_t header, _z_arc_slice_t *arcs,\n                              uintptr_t mapping) {\n    _Z_DEBUG(\"Decoding _Z_MID_N_RESPONSE\");\n    msg->_ext_qos = _Z_N_QOS_DEFAULT;\n    _Z_RETURN_IF_ERR(_z_zsize_decode(&msg->_request_id, zbf));\n    _Z_RETURN_IF_ERR(_z_wireexpr_decode(&msg->_key, zbf, _Z_HAS_FLAG(header, _Z_FLAG_N_RESPONSE_N),\n                                        _Z_HAS_FLAG(header, _Z_FLAG_N_RESPONSE_M), mapping));\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_response_decode_extension, msg));\n    }\n    uint8_t inner_header;\n    _Z_RETURN_IF_ERR(_z_uint8_decode(&inner_header, zbf));\n    switch (_Z_MID(inner_header)) {\n        case _Z_MID_Z_REPLY: {\n            msg->_tag = _Z_RESPONSE_BODY_REPLY;\n            return _z_reply_decode(&msg->_body._reply, zbf, inner_header, arcs);\n            break;\n        }\n        case _Z_MID_Z_ERR: {\n            msg->_tag = _Z_RESPONSE_BODY_ERR;\n            return _z_err_decode(&msg->_body._err, zbf, inner_header, arcs);\n            break;\n        }\n        default: {\n            _Z_ERROR(\"Unknown N_MID: %d\", _Z_MID(inner_header));\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n        }\n    }\n}\n\n/*------------------ Response Final Message ------------------*/\nz_result_t _z_response_final_encode(_z_wbuf_t *wbf, const _z_n_msg_response_final_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_MID_N_RESPONSE_FINAL\");\n    uint8_t header = _Z_MID_N_RESPONSE_FINAL;\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_request_id));\n\n    return ret;\n}\n\nz_result_t _z_response_final_decode(_z_n_msg_response_final_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    (void)(header);\n    z_result_t ret = _Z_RES_OK;\n    ret |= _z_zsize_decode(&msg->_request_id, zbf);\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, 0x1a));\n    }\n    return ret;\n}\n\nz_result_t _z_declare_encode(_z_wbuf_t *wbf, const _z_n_msg_declare_t *decl) {\n    uint8_t header = _Z_MID_N_DECLARE;\n    bool has_qos_ext = decl->_ext_qos._val != _Z_N_QOS_DEFAULT._val;\n    bool has_timestamp_ext = _z_timestamp_check(&decl->_ext_timestamp);\n    int n_ext = (has_qos_ext ? 1 : 0) + (has_timestamp_ext ? 1 : 0);\n    if (n_ext != 0) {\n        header |= _Z_FLAG_N_Z;\n    }\n    if (decl->_interest_id.has_value) {\n        header |= _Z_FLAG_N_DECLARE_I;\n    }\n    // Encode header\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    // Encode interest id\n    if (decl->_interest_id.has_value) {\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, decl->_interest_id.value));\n    }\n    // Encode extensions\n    if (has_qos_ext) {\n        n_ext -= 1;\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, 0x01 | _Z_MSG_EXT_ENC_ZINT | (n_ext != 0 ? _Z_FLAG_Z_Z : 0)));\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, decl->_ext_qos._val));\n    }\n    if (has_timestamp_ext) {\n        n_ext -= 1;\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, 0x02 | _Z_MSG_EXT_ENC_ZBUF | (n_ext != 0 ? _Z_FLAG_Z_Z : 0)));\n        _Z_RETURN_IF_ERR(_z_timestamp_encode_ext(wbf, &decl->_ext_timestamp));\n    }\n    // Encode declaration\n    return _z_declaration_encode(wbf, &decl->_decl);\n}\nz_result_t _z_declare_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_n_msg_declare_t *decl = (_z_n_msg_declare_t *)ctx;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZINT | 0x01: {\n            decl->_ext_qos._val = (uint8_t)extension->_body._zint._val;\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x02: {\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            return _z_timestamp_decode(&decl->_ext_timestamp, &zbf);\n        }\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                return _z_msg_ext_unknown_error(extension, 0x19);\n            }\n    }\n    return _Z_RES_OK;\n}\nz_result_t _z_declare_decode(_z_n_msg_declare_t *decl, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    decl->_ext_qos = _Z_N_QOS_DEFAULT;\n    // Retrieve interest id\n    if (_Z_HAS_FLAG(header, _Z_FLAG_N_DECLARE_I)) {\n        _Z_RETURN_IF_ERR(_z_zint32_decode(&decl->_interest_id.value, zbf));\n        decl->_interest_id.has_value = true;\n    }\n    // Decode extensions\n    if (_Z_HAS_FLAG(header, _Z_FLAG_N_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_declare_decode_extensions, decl))\n    }\n    // Decode declaration\n    return _z_declaration_decode(&decl->_decl, zbf, mapping);\n}\n\nz_result_t _z_n_interest_encode(_z_wbuf_t *wbf, const _z_n_msg_interest_t *interest) {\n    // Set header\n    uint8_t header = _Z_MID_N_INTEREST;\n    bool is_final = true;\n    if (_Z_HAS_FLAG(interest->_interest.flags, _Z_INTEREST_FLAG_CURRENT)) {\n        is_final = false;\n        _Z_SET_FLAG(header, _Z_FLAG_N_INTEREST_CURRENT);\n    }\n    if (_Z_HAS_FLAG(interest->_interest.flags, _Z_INTEREST_FLAG_FUTURE)) {\n        is_final = false;\n        _Z_SET_FLAG(header, _Z_FLAG_N_INTEREST_FUTURE);\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    return _z_interest_encode(wbf, &interest->_interest, is_final);\n}\n\nz_result_t _z_n_interest_decode(_z_n_msg_interest_t *interest, _z_zbuf_t *zbf, uint8_t header, uintptr_t mapping) {\n    interest->_interest = _z_interest_null();\n    bool is_final = true;\n    bool has_ext = false;\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_N_INTEREST_CURRENT)) {\n        _Z_SET_FLAG(interest->_interest.flags, _Z_INTEREST_FLAG_CURRENT);\n        is_final = false;\n    }\n    if (_Z_HAS_FLAG(header, _Z_FLAG_N_INTEREST_FUTURE)) {\n        _Z_SET_FLAG(interest->_interest.flags, _Z_INTEREST_FLAG_FUTURE);\n        is_final = false;\n    }\n    // Decode extention\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        has_ext = true;\n    }\n    return _z_interest_decode(&interest->_interest, zbf, is_final, has_ext, mapping);\n}\n\nz_result_t _z_oam_encode(_z_wbuf_t *wbf, const _z_n_msg_oam_t *oam) {\n    uint8_t header = _Z_MID_N_OAM;\n    bool has_qos_ext = oam->_ext_qos._val != _Z_N_QOS_DEFAULT._val;\n    bool has_timestamp_ext = _z_timestamp_check(&oam->_ext_timestamp);\n    int n_ext = (has_qos_ext ? 1 : 0) + (has_timestamp_ext ? 1 : 0);\n    if (n_ext != 0) {\n        header |= _Z_FLAG_N_Z;\n    }\n    switch (oam->_enc) {\n        case _Z_OAM_BODY_UNIT: {\n            header |= _Z_MSG_EXT_ENC_UNIT;\n        } break;\n        case _Z_OAM_BODY_ZINT: {\n            header |= _Z_MSG_EXT_ENC_ZINT;\n        } break;\n        case _Z_OAM_BODY_ZBUF: {\n            header |= _Z_MSG_EXT_ENC_ZBUF;\n        } break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, header));\n    _Z_RETURN_IF_ERR(_z_zint16_encode(wbf, oam->_id));\n\n    if (has_qos_ext) {\n        n_ext -= 1;\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, 0x01 | _Z_MSG_EXT_ENC_ZINT | (n_ext != 0 ? _Z_FLAG_Z_Z : 0)));\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, oam->_ext_qos._val));\n    }\n    if (has_timestamp_ext) {\n        n_ext -= 1;\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, 0x02 | _Z_MSG_EXT_ENC_ZBUF | (n_ext != 0 ? _Z_FLAG_Z_Z : 0)));\n        _Z_RETURN_IF_ERR(_z_timestamp_encode_ext(wbf, &oam->_ext_timestamp));\n    }\n\n    switch (oam->_enc) {\n        case _Z_OAM_BODY_UNIT: {\n            // No body to encode\n        } break;\n        case _Z_OAM_BODY_ZINT: {\n            _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, oam->_body._zint._val));\n        } break;\n        case _Z_OAM_BODY_ZBUF: {\n            _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &oam->_body._zbuf._val));\n        } break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_oam_decode_extensions(_z_msg_ext_t *extension, void *ctx) {\n    _z_n_msg_oam_t *oam = (_z_n_msg_oam_t *)ctx;\n    switch (_Z_EXT_FULL_ID(extension->_header)) {\n        case _Z_MSG_EXT_ENC_ZINT | 0x01: {\n            oam->_ext_qos._val = (uint8_t)extension->_body._zint._val;\n            break;\n        }\n        case _Z_MSG_EXT_ENC_ZBUF | 0x02: {\n            _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n            return _z_timestamp_decode(&oam->_ext_timestamp, &zbf);\n        }\n        default:\n            if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) {\n                return _z_msg_ext_unknown_error(extension, 0x20);\n            }\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_oam_decode(_z_n_msg_oam_t *oam, _z_zbuf_t *zbf, uint8_t header) {\n    _Z_DEBUG(\"Decoding _Z_MID_N_OAM\");\n    // Decode ID\n    _Z_RETURN_IF_ERR(_z_zint16_decode(&oam->_id, zbf));\n\n    // Initialize extensions with default values\n    oam->_ext_qos = _Z_N_QOS_DEFAULT;\n    oam->_ext_timestamp = _z_timestamp_null();\n\n    // Decode extensions\n    if (_Z_HAS_FLAG(header, _Z_FLAG_N_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_decode_iter(zbf, _z_oam_decode_extensions, oam))\n    }\n\n    // Decode payload\n    switch (_Z_EXT_ENC(header)) {\n        case _Z_MSG_EXT_ENC_UNIT: {\n            oam->_enc = _Z_OAM_BODY_UNIT;\n            return _Z_RES_OK;\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZINT: {\n            oam->_enc = _Z_OAM_BODY_ZINT;\n            return _z_zint64_decode(&oam->_body._zint._val, zbf);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZBUF: {\n            oam->_enc = _Z_OAM_BODY_ZBUF;\n            return _z_slice_decode(&oam->_body._zbuf._val, zbf);\n        } break;\n        default: {\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n        }\n    }\n}\n\nz_result_t _z_network_message_encode(_z_wbuf_t *wbf, const _z_network_message_t *msg) {\n    switch (msg->_tag) {\n        case _Z_N_DECLARE: {\n            return _z_declare_encode(wbf, &msg->_body._declare);\n        } break;\n#if Z_FEATURE_PUBLICATION == 1\n        case _Z_N_PUSH: {\n            return _z_push_encode(wbf, &msg->_body._push);\n        } break;\n#endif\n#if Z_FEATURE_QUERY == 1\n        case _Z_N_REQUEST: {\n            return _z_request_encode(wbf, &msg->_body._request);\n        } break;\n#endif\n#if Z_FEATURE_QUERYABLE == 1\n        case _Z_N_RESPONSE: {\n            return _z_response_encode(wbf, &msg->_body._response);\n        } break;\n        case _Z_N_RESPONSE_FINAL: {\n            return _z_response_final_encode(wbf, &msg->_body._response_final);\n        } break;\n#endif\n#if Z_FEATURE_INTEREST == 1\n        case _Z_N_INTEREST: {\n            return _z_n_interest_encode(wbf, &msg->_body._interest);\n        } break;\n#endif\n        case _Z_N_OAM: {\n            return _z_oam_encode(wbf, &msg->_body._oam);\n        } break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n}\nz_result_t _z_network_message_decode(_z_network_message_t *msg, _z_zbuf_t *zbf, _z_arc_slice_t *arcs,\n                                     uintptr_t mapping) {\n    uint8_t *header;\n    *msg = (_z_network_message_t){0};\n    _Z_RETURN_IF_ERR(_z_uint8_decode_as_ref(&header, zbf));\n    switch (_Z_MID(*header)) {\n        case _Z_MID_N_DECLARE: {\n            msg->_tag = _Z_N_DECLARE;\n            return _z_declare_decode(&msg->_body._declare, zbf, *header, mapping);\n        } break;\n        case _Z_MID_N_PUSH: {\n            msg->_tag = _Z_N_PUSH;\n            return _z_push_decode(&msg->_body._push, zbf, *header, arcs, mapping);\n        } break;\n        case _Z_MID_N_REQUEST: {\n            msg->_tag = _Z_N_REQUEST;\n            return _z_request_decode(&msg->_body._request, zbf, *header, arcs, mapping);\n        } break;\n        case _Z_MID_N_RESPONSE: {\n            msg->_tag = _Z_N_RESPONSE;\n            return _z_response_decode(&msg->_body._response, zbf, *header, arcs, mapping);\n        } break;\n        case _Z_MID_N_RESPONSE_FINAL: {\n            msg->_tag = _Z_N_RESPONSE_FINAL;\n            return _z_response_final_decode(&msg->_body._response_final, zbf, *header);\n        } break;\n        case _Z_MID_N_INTEREST: {\n            msg->_tag = _Z_N_INTEREST;\n            return _z_n_interest_decode(&msg->_body._interest, zbf, *header, mapping);\n        } break;\n        case _Z_MID_N_OAM: {\n            msg->_tag = _Z_N_OAM;\n            return _z_oam_decode(&msg->_body._oam, zbf, *header);\n        } break;\n        default:\n            _Z_INFO(\"Unknown message type received: %d\", _Z_MID(*header));\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n}\n"
  },
  {
    "path": "src/protocol/codec/serial.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <inttypes.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/checksum.h\"\n#include \"zenoh-pico/utils/encoding.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#define KIND_FIELD_LEN 1u\n#define LEN_FIELD_LEN 2u\n#define CRC32_LEN 4u\n\nsize_t _z_serial_msg_serialize(uint8_t *dest, size_t dest_len, const uint8_t *src, size_t src_len, uint8_t header,\n                               uint8_t *tmp_buf, size_t tmp_buf_len) {\n    size_t expected_size = src_len + KIND_FIELD_LEN + LEN_FIELD_LEN + CRC32_LEN;\n    if (tmp_buf_len < expected_size) {\n        _Z_DEBUG(\"tmp buffer too small: %zu < %zu\", tmp_buf_len, expected_size);\n        return SIZE_MAX;\n    }\n\n    uint32_t crc32 = _z_crc32(src, src_len);\n    uint8_t crc_bytes[CRC32_LEN] = {(uint8_t)(crc32 & 0xFF), (uint8_t)((crc32 >> 8) & 0xFF),\n                                    (uint8_t)((crc32 >> 16) & 0xFF), (uint8_t)((crc32 >> 24) & 0xFF)};\n\n    uint16_t wire_size = (uint16_t)src_len;\n    uint8_t size_bytes[LEN_FIELD_LEN] = {(uint8_t)(wire_size & 0xFF), (uint8_t)((wire_size >> 8) & 0xFF)};\n\n    uint8_t *tmp_buf_ptr = tmp_buf;\n\n    tmp_buf_ptr[0] = header;\n    tmp_buf_ptr += sizeof(header);\n\n    memcpy(tmp_buf_ptr, size_bytes, sizeof(size_bytes));\n    tmp_buf_ptr += sizeof(size_bytes);\n\n    memcpy(tmp_buf_ptr, src, src_len);\n    tmp_buf_ptr += src_len;\n\n    memcpy(tmp_buf_ptr, crc_bytes, sizeof(crc_bytes));\n    tmp_buf_ptr += sizeof(crc_bytes);\n\n    size_t total_len = _z_ptr_u8_diff(tmp_buf_ptr, tmp_buf);\n\n    size_t ret = _z_cobs_encode(tmp_buf, total_len, dest);\n    if (ret + 1 > dest_len) {\n        _Z_DEBUG(\"destination buffer too small\");\n        return SIZE_MAX;\n    }\n\n    dest[ret] = 0x00;\n\n    return ret + 1u;\n}\n\nsize_t _z_serial_msg_deserialize(const uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len, uint8_t *header,\n                                 uint8_t *tmp_buf, size_t tmp_buf_len) {\n    if (tmp_buf_len < src_len) {\n        _Z_DEBUG(\"tmp_buf too small\");\n        return SIZE_MAX;\n    }\n\n    size_t decoded_size = _z_cobs_decode(src, src_len, tmp_buf);\n\n    if (decoded_size < KIND_FIELD_LEN + LEN_FIELD_LEN + CRC32_LEN) {\n        _Z_DEBUG(\"decoded frame too small\");\n        return SIZE_MAX;\n    }\n\n    uint8_t *tmp_buf_ptr = tmp_buf;\n\n    *header = tmp_buf_ptr[0];\n    tmp_buf_ptr += sizeof(uint8_t);\n\n    uint16_t wire_size = (uint16_t)(tmp_buf_ptr[0] | (tmp_buf_ptr[1] << 8));\n    tmp_buf_ptr += sizeof(uint16_t);\n\n    size_t expected_size = wire_size + KIND_FIELD_LEN + LEN_FIELD_LEN + CRC32_LEN;\n    if (expected_size != decoded_size) {\n        _Z_DEBUG(\"wire size mismatch: %zu != %zu\", expected_size, decoded_size);\n        return SIZE_MAX;\n    }\n\n    if (dst_len < wire_size) {\n        _Z_DEBUG(\"destination buffer too small: %zu < %u\", dst_len, wire_size);\n        return SIZE_MAX;\n    }\n\n    if (wire_size != 0) {\n        memcpy(dst, tmp_buf_ptr, wire_size);\n        tmp_buf_ptr += wire_size;\n    }\n\n    uint32_t received_crc =\n        (uint32_t)(tmp_buf_ptr[0] | (tmp_buf_ptr[1] << 8) | (tmp_buf_ptr[2] << 16) | (tmp_buf_ptr[3] << 24));\n\n    uint32_t computed_crc = _z_crc32(dst, wire_size);\n    if (received_crc != computed_crc) {\n        _Z_DEBUG(\"CRC mismatch. Received: 0x%08\" PRIu32 \", Computed: 0x%08\" PRIu32, received_crc, computed_crc);\n        return SIZE_MAX;\n    }\n\n    return wire_size;\n}\n"
  },
  {
    "path": "src/protocol/codec/transport.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/transport.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/ext.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/definitions/core.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\nuint8_t _z_whatami_to_uint8(z_whatami_t whatami) {\n    return (whatami >> 1) & 0x03;  // get set bit index; only first 3 bits can be set\n}\n\nz_whatami_t _z_whatami_from_uint8(uint8_t b) {\n    return 1 << (b & 0x03);  // convert set bit idx into bitmask\n}\n\n/*------------------ Join Message ------------------*/\nz_result_t _z_join_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_join_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_MID_T_JOIN\");\n\n    _Z_RETURN_IF_ERR(_z_wbuf_write(wbf, msg->_version));\n\n    uint8_t cbyte = 0;\n    cbyte |= _z_whatami_to_uint8(msg->_whatami);\n    uint8_t zidlen = _z_id_len(msg->_zid);\n    cbyte |= (uint8_t)(((zidlen - 1) & 0x0F) << 4);\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, cbyte));\n    _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, msg->_zid.id, 0, zidlen));\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_JOIN_S)) {\n        cbyte = msg->_seq_num_res & 0x03;\n        cbyte = (uint8_t)(cbyte | ((msg->_req_id_res & 0x03) << 2));\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, cbyte));\n        _Z_RETURN_IF_ERR(_z_uint16_encode(wbf, msg->_batch_size));\n    }\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_JOIN_T) == true) {\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_lease / 1000));\n    } else {\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_lease));\n    }\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_next_sn._val._plain._reliable));\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_next_sn._val._plain._best_effort));\n#if Z_FEATURE_FRAGMENTATION == 1\n    bool has_patch = msg->_patch != _Z_NO_PATCH;\n#else\n    bool has_patch = false;\n#endif\n    if (msg->_next_sn._is_qos) {\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n            _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ID_JOIN_QOS | _Z_MSG_EXT_MORE(has_patch)));\n            size_t len = 0;\n            for (uint8_t i = 0; (i < Z_PRIORITIES_NUM) && (ret == _Z_RES_OK); i++) {\n                len += _z_zint_len(msg->_next_sn._val._qos[i]._reliable) +\n                       _z_zint_len(msg->_next_sn._val._qos[i]._best_effort);\n            }\n            _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, len));\n            for (uint8_t i = 0; (i < Z_PRIORITIES_NUM) && (ret == _Z_RES_OK); i++) {\n                _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_next_sn._val._qos[i]._reliable));\n                _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_next_sn._val._qos[i]._best_effort));\n            }\n        } else {\n            _Z_DEBUG(\"Attempted to serialize QoS-SN extension, but the header extension flag was unset\");\n            ret |= _Z_ERR_MESSAGE_SERIALIZATION_FAILED;\n        }\n    }\n#if Z_FEATURE_FRAGMENTATION == 1\n    if (has_patch) {\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n            _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ID_JOIN_PATCH));\n            _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, msg->_patch));\n        } else {\n            _Z_DEBUG(\"Attempted to serialize Patch extension, but the header extension flag was unset\");\n            ret |= _Z_ERR_MESSAGE_SERIALIZATION_FAILED;\n        }\n    }\n#endif\n\n    return ret;\n}\n\nz_result_t _z_join_decode_ext(_z_msg_ext_t *extension, void *ctx) {\n    z_result_t ret = _Z_RES_OK;\n    _z_t_msg_join_t *msg = (_z_t_msg_join_t *)ctx;\n    if (_Z_EXT_FULL_ID(extension->_header) == _Z_MSG_EXT_ID_JOIN_QOS) {\n        msg->_next_sn._is_qos = true;\n        _z_zbuf_t zbf = _z_slice_as_zbuf(extension->_body._zbuf._val);\n        for (int i = 0; (ret == _Z_RES_OK) && (i < Z_PRIORITIES_NUM); ++i) {\n            ret |= _z_zsize_decode(&msg->_next_sn._val._qos[i]._reliable, &zbf);\n            ret |= _z_zsize_decode(&msg->_next_sn._val._qos[i]._best_effort, &zbf);\n        }\n#if Z_FEATURE_FRAGMENTATION == 1\n    } else if (_Z_EXT_FULL_ID(extension->_header) == _Z_MSG_EXT_ID_JOIN_PATCH) {\n        msg->_patch = (uint8_t)extension->_body._zint._val;\n#endif\n    } else if (_Z_MSG_EXT_IS_MANDATORY(extension->_header)) {\n        _Z_ERROR_LOG(_Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN);\n        ret = _Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN;\n    }\n    return ret;\n}\n\nz_result_t _z_join_decode(_z_t_msg_join_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    _Z_DEBUG(\"Decoding _Z_MID_T_JOIN\");\n    z_result_t ret = _Z_RES_OK;\n    *msg = (_z_t_msg_join_t){0};\n\n    ret |= _z_uint8_decode(&msg->_version, zbf);\n\n    uint8_t cbyte = 0;\n    ret |= _z_uint8_decode(&cbyte, zbf);\n    msg->_whatami = _z_whatami_from_uint8(cbyte);\n\n    uint8_t zidlen = ((cbyte & 0xF0) >> 4) + (uint8_t)1;\n    msg->_zid = _z_id_empty();\n    if (ret == _Z_RES_OK) {\n        if (_z_zbuf_len(zbf) >= zidlen) {\n            _z_zbuf_read_bytes(zbf, msg->_zid.id, 0, zidlen);\n        } else {\n            _Z_INFO(\"Invalid zid length received\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n    }\n    if (ret == _Z_RES_OK) {\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_JOIN_S) == true) {\n            cbyte = 0;\n            ret |= _z_uint8_decode(&cbyte, zbf);\n            msg->_seq_num_res = (cbyte & 0x03);\n            msg->_req_id_res = ((cbyte >> 2) & 0x03);\n            ret |= _z_uint16_decode(&msg->_batch_size, zbf);\n        } else {\n            msg->_seq_num_res = _Z_DEFAULT_RESOLUTION_SIZE;\n            msg->_req_id_res = _Z_DEFAULT_RESOLUTION_SIZE;\n            msg->_batch_size = _Z_DEFAULT_MULTICAST_BATCH_SIZE;\n        }\n    }\n    if (ret == _Z_RES_OK) {\n        ret |= _z_zsize_decode(&msg->_lease, zbf);\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_JOIN_T) == true) {\n            msg->_lease = msg->_lease * 1000;\n        }\n    }\n    if (ret == _Z_RES_OK) {\n        msg->_next_sn._is_qos = false;\n        ret |= _z_zsize_decode(&msg->_next_sn._val._plain._reliable, zbf);\n        ret |= _z_zsize_decode(&msg->_next_sn._val._plain._best_effort, zbf);\n    }\n#if Z_FEATURE_FRAGMENTATION == 1\n    msg->_patch = _Z_NO_PATCH;\n#endif\n    if ((ret == _Z_RES_OK) && _Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n        ret |= _z_msg_ext_decode_iter(zbf, _z_join_decode_ext, msg);\n    }\n\n    return ret;\n}\n\n/*------------------ Init Message ------------------*/\nz_result_t _z_init_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_init_t *msg) {\n    _Z_DEBUG(\"Encoding _Z_MID_T_INIT\");\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_RETURN_IF_ERR(_z_wbuf_write(wbf, msg->_version))\n\n    uint8_t cbyte = 0;\n    cbyte |= _z_whatami_to_uint8(msg->_whatami);\n    uint8_t zidlen = _z_id_len(msg->_zid);\n    cbyte |= (uint8_t)(((zidlen - 1) & 0x0F) << 4);\n    _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, cbyte))\n    _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, msg->_zid.id, 0, zidlen))\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_INIT_S) == true) {\n        cbyte = msg->_seq_num_res & 0x03;\n        cbyte = (uint8_t)(cbyte | ((msg->_req_id_res & 0x03) << 2));\n        _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, cbyte))\n        _Z_RETURN_IF_ERR(_z_uint16_encode(wbf, msg->_batch_size))\n    }\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_INIT_A) == true) {\n        _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &msg->_cookie))\n    }\n\n#if Z_FEATURE_FRAGMENTATION == 1\n    if (msg->_patch != _Z_NO_PATCH) {\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n            _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ID_JOIN_PATCH));\n            _Z_RETURN_IF_ERR(_z_zint64_encode(wbf, msg->_patch));\n        } else {\n            _Z_DEBUG(\"Attempted to serialize Patch extension, but the header extension flag was unset\");\n            ret |= _Z_ERR_MESSAGE_SERIALIZATION_FAILED;\n        }\n    }\n#endif\n\n    return ret;\n}\n\nz_result_t _z_init_decode_ext(_z_msg_ext_t *extension, void *ctx) {\n    _ZP_UNUSED(ctx);\n    z_result_t ret = _Z_RES_OK;\n    if (false) {\n#if Z_FEATURE_FRAGMENTATION == 1\n    } else if (_Z_EXT_FULL_ID(extension->_header) == _Z_MSG_EXT_ID_INIT_PATCH) {\n        _z_t_msg_init_t *msg = (_z_t_msg_init_t *)ctx;\n        msg->_patch = (uint8_t)extension->_body._zint._val;\n#endif\n    } else if (_Z_MSG_EXT_IS_MANDATORY(extension->_header)) {\n        _Z_ERROR_LOG(_Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN);\n        ret = _Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN;\n    }\n    return ret;\n}\n\nz_result_t _z_init_decode(_z_t_msg_init_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    _Z_DEBUG(\"Decoding _Z_MID_T_INIT\");\n    *msg = (_z_t_msg_init_t){0};\n    z_result_t ret = _Z_RES_OK;\n\n    ret |= _z_uint8_decode(&msg->_version, zbf);\n\n    uint8_t cbyte = 0;\n    ret |= _z_uint8_decode(&cbyte, zbf);\n    msg->_zid = _z_id_empty();\n\n    if (ret == _Z_RES_OK) {\n        msg->_whatami = _z_whatami_from_uint8(cbyte);\n        uint8_t zidlen = ((cbyte & 0xF0) >> 4) + (uint8_t)1;\n        if (_z_zbuf_len(zbf) >= zidlen) {\n            _z_zbuf_read_bytes(zbf, msg->_zid.id, 0, zidlen);\n        } else {\n            _Z_INFO(\"Invalid zid length received\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n    }\n\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_INIT_S) == true)) {\n        cbyte = 0;\n        ret |= _z_uint8_decode(&cbyte, zbf);\n        msg->_seq_num_res = (cbyte & 0x03);\n        msg->_req_id_res = ((cbyte >> 2) & 0x03);\n        ret |= _z_uint16_decode(&msg->_batch_size, zbf);\n    } else {\n        msg->_seq_num_res = _Z_DEFAULT_RESOLUTION_SIZE;\n        msg->_req_id_res = _Z_DEFAULT_RESOLUTION_SIZE;\n        msg->_batch_size = _Z_DEFAULT_UNICAST_BATCH_SIZE;\n    }\n\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_INIT_A) == true)) {\n        ret |= _z_slice_decode(&msg->_cookie, zbf);\n    } else {\n        msg->_cookie = _z_slice_null();\n    }\n#if Z_FEATURE_FRAGMENTATION == 1\n    msg->_patch = _Z_NO_PATCH;\n#endif\n    if ((ret == _Z_RES_OK) && _Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n        ret |= _z_msg_ext_decode_iter(zbf, _z_init_decode_ext, msg);\n    }\n\n    return ret;\n}\n\n/*------------------ Open Message ------------------*/\nz_result_t _z_open_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_open_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_MID_T_OPEN\");\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_OPEN_T) == true) {\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_lease / 1000))\n    } else {\n        _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_lease))\n    }\n\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_initial_sn))\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_OPEN_A) == false) {\n        _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &msg->_cookie))\n    }\n\n    return ret;\n}\n\nz_result_t _z_open_decode(_z_t_msg_open_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    _Z_DEBUG(\"Decoding _Z_MID_T_OPEN\");\n    z_result_t ret = _Z_RES_OK;\n    *msg = (_z_t_msg_open_t){0};\n\n    ret |= _z_zsize_decode(&msg->_lease, zbf);\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_OPEN_T) == true)) {\n        msg->_lease = msg->_lease * 1000;\n    }\n\n    ret |= _z_zsize_decode(&msg->_initial_sn, zbf);\n\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_OPEN_A) == false)) {\n        ret |= _z_slice_decode(&msg->_cookie, zbf);\n        if (ret != _Z_RES_OK) {\n            msg->_cookie = _z_slice_null();\n        }\n    } else {\n        msg->_cookie = _z_slice_null();\n    }\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_Z) == true)) {\n        ret |= _z_msg_ext_skip_non_mandatories(zbf, 0x02);\n    }\n\n    return ret;\n}\n\n/*------------------ Close Message ------------------*/\nz_result_t _z_close_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_close_t *msg) {\n    (void)(header);\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_MID_T_CLOSE\");\n\n    ret |= _z_wbuf_write(wbf, msg->_reason);\n\n    return ret;\n}\n\nz_result_t _z_close_decode(_z_t_msg_close_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    (void)(header);\n    z_result_t ret = _Z_RES_OK;\n    *msg = (_z_t_msg_close_t){0};\n    _Z_DEBUG(\"Decoding _Z_MID_T_CLOSE\");\n\n    ret |= _z_uint8_decode(&msg->_reason, zbf);\n\n    return ret;\n}\n\n/*------------------ Keep Alive Message ------------------*/\nz_result_t _z_keep_alive_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_keep_alive_t *msg) {\n    (void)(wbf);\n    (void)(header);\n    (void)(msg);\n\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_MID_T_KEEP_ALIVE\");\n\n    return ret;\n}\n\nz_result_t _z_keep_alive_decode(_z_t_msg_keep_alive_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    (void)(msg);\n    (void)(zbf);\n    (void)(header);\n    *msg = (_z_t_msg_keep_alive_t){0};\n\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Decoding _Z_MID_T_KEEP_ALIVE\");\n\n    if (_Z_HAS_FLAG(header, _Z_FLAG_Z_Z)) {\n        ret |= _z_msg_ext_skip_non_mandatories(zbf, 0x03);\n    }\n\n    return ret;\n}\n\n/*------------------ Frame Message ------------------*/\n\nz_result_t _z_frame_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_frame_t *msg) {\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_sn))\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_SERIALIZATION_FAILED);\n    }\n    if (msg->_payload != NULL) {\n        _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, _z_zbuf_get_rptr(msg->_payload), 0, _z_zbuf_len(msg->_payload)));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_frame_decode(_z_t_msg_frame_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    *msg = (_z_t_msg_frame_t){0};\n    _Z_RETURN_IF_ERR(_z_zsize_decode(&msg->_sn, zbf));\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z)) {\n        _Z_RETURN_IF_ERR(_z_msg_ext_skip_non_mandatories(zbf, 0x04));\n    }\n    // Note payload\n    msg->_payload = zbf;\n    return _Z_RES_OK;\n}\n\n/*------------------ Fragment Message ------------------*/\nz_result_t _z_fragment_encode(_z_wbuf_t *wbf, uint8_t header, const _z_t_msg_fragment_t *msg) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Encoding _Z_TRANSPORT_FRAGMENT\");\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, msg->_sn))\n    if (msg->first) {\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z) == true) {\n            _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ID_FRAGMENT_FIRST | _Z_MSG_EXT_MORE(msg->drop)));\n        } else {\n            _Z_DEBUG(\"Attempted to serialize Start extension, but the header extension flag was unset\");\n            ret |= _Z_ERR_MESSAGE_SERIALIZATION_FAILED;\n        }\n    }\n    if (msg->drop) {\n        if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z) == true) {\n            _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ID_FRAGMENT_DROP));\n        } else {\n            _Z_DEBUG(\"Attempted to serialize Stop extension, but the header extension flag was unset\");\n            ret |= _Z_ERR_MESSAGE_SERIALIZATION_FAILED;\n        }\n    }\n    if (_z_slice_check(&msg->_payload)) {\n        _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, msg->_payload.start, 0, msg->_payload.len));\n    }\n\n    return ret;\n}\n\nz_result_t _z_fragment_decode_ext(_z_msg_ext_t *extension, void *ctx) {\n    z_result_t ret = _Z_RES_OK;\n    _z_t_msg_fragment_t *msg = (_z_t_msg_fragment_t *)ctx;\n    if (_Z_EXT_FULL_ID(extension->_header) == _Z_MSG_EXT_ID_FRAGMENT_FIRST) {\n        msg->first = true;\n    } else if (_Z_EXT_FULL_ID(extension->_header) == _Z_MSG_EXT_ID_FRAGMENT_DROP) {\n        msg->drop = true;\n    } else if (_Z_MSG_EXT_IS_MANDATORY(extension->_header)) {\n        _Z_ERROR_LOG(_Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN);\n        ret = _Z_ERR_MESSAGE_EXTENSION_MANDATORY_AND_UNKNOWN;\n    }\n    return ret;\n}\n\nz_result_t _z_fragment_decode(_z_t_msg_fragment_t *msg, _z_zbuf_t *zbf, uint8_t header) {\n    z_result_t ret = _Z_RES_OK;\n    *msg = (_z_t_msg_fragment_t){0};\n\n    _Z_DEBUG(\"Decoding _Z_TRANSPORT_FRAGMENT\");\n    ret |= _z_zsize_decode(&msg->_sn, zbf);\n\n    msg->first = false;\n    msg->drop = false;\n    if ((ret == _Z_RES_OK) && (_Z_HAS_FLAG(header, _Z_FLAG_T_Z) == true)) {\n        ret |= _z_msg_ext_decode_iter(zbf, _z_fragment_decode_ext, msg);\n    }\n    msg->_payload = _z_slice_alias_buf((uint8_t *)_z_zbuf_start(zbf), _z_zbuf_len(zbf));\n    zbf->_ios._r_pos = zbf->_ios._w_pos;\n\n    return ret;\n}\n\n/*------------------ Transport Extensions Message ------------------*/\nz_result_t _z_extensions_encode(_z_wbuf_t *wbf, uint8_t header, const _z_msg_ext_vec_t *v_ext) {\n    (void)(header);\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_DEBUG(\"Encoding _Z_TRANSPORT_EXTENSIONS\");\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z) == true) {\n        ret |= _z_msg_ext_vec_encode(wbf, v_ext);\n    }\n\n    return ret;\n}\n\nz_result_t _z_extensions_decode(_z_msg_ext_vec_t *v_ext, _z_zbuf_t *zbf, uint8_t header) {\n    (void)(header);\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_DEBUG(\"Decoding _Z_TRANSPORT_EXTENSIONS\");\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_Z) == true) {\n        ret |= _z_msg_ext_vec_decode(v_ext, zbf);\n    } else {\n        _z_msg_ext_vec_reset(v_ext);\n    }\n\n    return ret;\n}\n\n#if defined Z_TEST_HOOKS\nstatic _z_transport_message_encode_override_fn _z_transport_message_encode_override = NULL;\n\nvoid _z_transport_set_message_encode_override(_z_transport_message_encode_override_fn fn) {\n    _z_transport_message_encode_override = fn;\n}\n#endif\n\n/*------------------ Transport Message ------------------*/\nz_result_t _z_transport_message_encode(_z_wbuf_t *wbf, const _z_transport_message_t *msg) {\n#if defined(Z_TEST_HOOKS)\n    if (_z_transport_message_encode_override != NULL) {\n        bool handled = false;\n        z_result_t override_ret = _z_transport_message_encode_override(wbf, msg, &handled);\n        if (handled) {\n            return override_ret;\n        }\n    }\n#endif\n    _Z_RETURN_IF_ERR(_z_wbuf_write(wbf, msg->_header))\n    switch (_Z_MID(msg->_header)) {\n        case _Z_MID_T_FRAME: {\n            return _z_frame_encode(wbf, msg->_header, &msg->_body._frame);\n        } break;\n        case _Z_MID_T_FRAGMENT: {\n            return _z_fragment_encode(wbf, msg->_header, &msg->_body._fragment);\n        } break;\n        case _Z_MID_T_KEEP_ALIVE: {\n            return _z_keep_alive_encode(wbf, msg->_header, &msg->_body._keep_alive);\n        } break;\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n        case _Z_MID_T_JOIN: {\n            return _z_join_encode(wbf, msg->_header, &msg->_body._join);\n        } break;\n#endif\n        case _Z_MID_T_INIT: {\n            return _z_init_encode(wbf, msg->_header, &msg->_body._init);\n        } break;\n        case _Z_MID_T_OPEN: {\n            return _z_open_encode(wbf, msg->_header, &msg->_body._open);\n        } break;\n        case _Z_MID_T_CLOSE: {\n            return _z_close_encode(wbf, msg->_header, &msg->_body._close);\n        } break;\n        default: {\n            _Z_INFO(\"WARNING: Trying to encode session message with unknown ID(%d)\", _Z_MID(msg->_header));\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_TRANSPORT_UNKNOWN);\n        } break;\n    }\n}\n\nz_result_t _z_transport_message_decode(_z_transport_message_t *msg, _z_zbuf_t *zbf) {\n    _Z_RETURN_IF_ERR(_z_uint8_decode(&msg->_header, zbf));  // Decode the header\n    uint8_t mid = _Z_MID(msg->_header);\n    switch (mid) {\n        case _Z_MID_T_FRAME: {\n            return _z_frame_decode(&msg->_body._frame, zbf, msg->_header);\n        } break;\n        case _Z_MID_T_FRAGMENT: {\n            return _z_fragment_decode(&msg->_body._fragment, zbf, msg->_header);\n        } break;\n        case _Z_MID_T_KEEP_ALIVE: {\n            return _z_keep_alive_decode(&msg->_body._keep_alive, zbf, msg->_header);\n        } break;\n        case _Z_MID_T_JOIN: {\n            return _z_join_decode(&msg->_body._join, zbf, msg->_header);\n        } break;\n        case _Z_MID_T_INIT: {\n            return _z_init_decode(&msg->_body._init, zbf, msg->_header);\n        } break;\n        case _Z_MID_T_OPEN: {\n            return _z_open_decode(&msg->_body._open, zbf, msg->_header);\n        } break;\n        case _Z_MID_T_CLOSE: {\n            return _z_close_decode(&msg->_body._close, zbf, msg->_header);\n        } break;\n        default: {\n            _Z_INFO(\"WARNING: Trying to decode session message with unknown ID(0x%x) (header=0x%x)\", mid, msg->_header);\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_TRANSPORT_UNKNOWN);\n        } break;\n    }\n}\n"
  },
  {
    "path": "src/protocol/codec.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec.h\"\n\n#include <stdint.h>\n\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ uint8 -------------------*/\nz_result_t _z_consolidation_mode_encode(_z_wbuf_t *wbf, z_consolidation_mode_t en) { return _z_zsize_encode(wbf, en); }\n\nz_result_t _z_consolidation_mode_decode(z_consolidation_mode_t *en, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_zint_t tmp;\n    ret |= _z_zsize_decode(&tmp, zbf);\n    *en = tmp;\n\n    return ret;\n}\n\nz_result_t _z_query_target_encode(_z_wbuf_t *wbf, z_query_target_t en) { return _z_zsize_encode(wbf, en); }\n\nz_result_t _z_query_target_decode(z_query_target_t *en, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_zint_t tmp;\n    ret |= _z_zsize_decode(&tmp, zbf);\n    *en = tmp;\n\n    return ret;\n}\n\nz_result_t _z_whatami_encode(_z_wbuf_t *wbf, z_whatami_t en) { return _z_zsize_encode(wbf, _z_whatami_to_uint8(en)); }\n\nz_result_t _z_whatami_decode(z_whatami_t *en, _z_zbuf_t *zbf) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_zint_t tmp;\n    ret |= _z_zsize_decode(&tmp, zbf);\n    *en = _z_whatami_from_uint8((uint8_t)tmp);\n\n    return ret;\n}\n\nz_result_t _z_uint8_encode(_z_wbuf_t *wbf, uint8_t u8) { return _z_wbuf_write(wbf, u8); }\n\nz_result_t _z_uint8_decode(uint8_t *u8, _z_zbuf_t *zbf) {\n    if (!_z_zbuf_can_read(zbf)) {\n        _Z_WARN(\"Not enough bytes to read\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *u8 = _z_zbuf_read(zbf);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_uint8_decode_as_ref(uint8_t **u8, _z_zbuf_t *zbf) {\n    if (!_z_zbuf_can_read(zbf)) {\n        _Z_WARN(\"Not enough bytes to read\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *u8 = _z_zbuf_read_as_ref(zbf);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_uint16_encode(_z_wbuf_t *wbf, uint16_t val) {\n    _Z_RETURN_IF_ERR(_z_wbuf_write(wbf, _z_get_u16_lsb(val)));\n    return _z_wbuf_write(wbf, _z_get_u16_msb(val));\n}\n\nz_result_t _z_uint16_decode(uint16_t *u16, _z_zbuf_t *zbf) {\n    if (_z_zbuf_len(zbf) < sizeof(uint16_t)) {\n        _Z_WARN(\"Not enough bytes to read\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *u16 = _z_zbuf_read(zbf) + (uint16_t)(_z_zbuf_read(zbf) << 8);\n    _z_host_u16_from_le_u16(u16);\n    return _Z_RES_OK;\n}\n\n/*------------------ z_zint ------------------*/\n// Zint is a variable int composed of up to 9 bytes.\n// The msb of the 8 first bytes has meaning: (1: the zint continue, 0: end of the zint)\n#define VLE_LEN 9\n#define VLE_LEN1_MASK (UINT64_MAX << (7 * 1))\n#define VLE_LEN2_MASK (UINT64_MAX << (7 * 2))\n#define VLE_LEN3_MASK (UINT64_MAX << (7 * 3))\n#define VLE_LEN4_MASK (UINT64_MAX << (7 * 4))\n#define VLE_LEN5_MASK (UINT64_MAX << (7 * 5))\n#define VLE_LEN6_MASK (UINT64_MAX << (7 * 6))\n#define VLE_LEN7_MASK (UINT64_MAX << (7 * 7))\n#define VLE_LEN8_MASK (UINT64_MAX << (7 * 8))\n\nuint8_t _z_zint_len(uint64_t v) {\n    if ((v & VLE_LEN1_MASK) == 0) {\n        return 1;\n    } else if ((v & VLE_LEN2_MASK) == 0) {\n        return 2;\n    } else if ((v & VLE_LEN3_MASK) == 0) {\n        return 3;\n    } else if ((v & VLE_LEN4_MASK) == 0) {\n        return 4;\n    } else if ((v & VLE_LEN5_MASK) == 0) {\n        return 5;\n    } else if ((v & VLE_LEN6_MASK) == 0) {\n        return 6;\n    } else if ((v & VLE_LEN7_MASK) == 0) {\n        return 7;\n    } else if ((v & VLE_LEN8_MASK) == 0) {\n        return 8;\n    } else {\n        return 9;\n    }\n}\n\nuint8_t _z_zint64_encode_buf(uint8_t *buf, uint64_t v) {\n    uint64_t lv = v;\n    uint8_t len = 0;\n    size_t start = 0;\n    while ((lv & VLE_LEN1_MASK) != 0) {\n        uint8_t c = (uint8_t)((lv & 0x7f) | 0x80);\n        buf[start++] = c;\n        len++;\n        lv = lv >> (uint64_t)7;\n    }\n    if (len != VLE_LEN) {\n        uint8_t c = (lv & 0xff);\n        buf[start++] = c;\n    }\n    return (uint8_t)start;\n}\n\nz_result_t _z_zint64_encode(_z_wbuf_t *wbf, uint64_t v) {\n    uint8_t buf[VLE_LEN];\n    size_t len = _z_zint64_encode_buf(buf, v);\n    return _z_wbuf_write_bytes(wbf, buf, 0, len);\n}\n\nz_result_t _z_zint64_decode_with_reader(uint64_t *zint, __z_single_byte_reader_t reader, void *context) {\n    *zint = 0;\n\n    uint8_t b = 0;\n    _Z_RETURN_IF_ERR(reader(&b, context));\n\n    uint8_t i = 0;\n    while (((b & 0x80) != 0) && (i != 7 * (VLE_LEN - 1))) {\n        *zint = *zint | ((uint64_t)(b & 0x7f)) << i;\n        _Z_RETURN_IF_ERR(reader(&b, context));\n        i = i + (uint8_t)7;\n    }\n    *zint = *zint | ((uint64_t)b << i);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_zsize_decode_with_reader(_z_zint_t *zint, __z_single_byte_reader_t reader, void *context) {\n    uint64_t i = 0;\n    z_result_t res = _z_zint64_decode_with_reader(&i, reader, context);\n    if (res != _Z_RES_OK || i > SIZE_MAX) {\n        _Z_INFO(\"Reader decode failed\");\n        _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n        res = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n    } else {\n        *zint = (_z_zint_t)i;\n    }\n    return res;\n}\n\nz_result_t _z_uint8_decode_reader(uint8_t *zint, void *context) { return _z_uint8_decode(zint, (_z_zbuf_t *)context); }\n\nz_result_t _z_zint64_decode(uint64_t *zint, _z_zbuf_t *zbf) {\n    *zint = 0;\n    uint8_t b = 0;\n    _Z_RETURN_IF_ERR(_z_uint8_decode(&b, zbf));\n\n    uint8_t i = 0;\n    while (((b & 0x80) != 0) && (i != 7 * (VLE_LEN - 1))) {\n        *zint = *zint | ((uint64_t)(b & 0x7f)) << i;\n        _Z_RETURN_IF_ERR(_z_uint8_decode(&b, zbf));\n        i = i + (uint8_t)7;\n    }\n    *zint = *zint | ((uint64_t)b << i);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_zint16_decode(uint16_t *zint, _z_zbuf_t *zbf) {\n    uint64_t buf;\n    _Z_RETURN_IF_ERR(_z_zint64_decode(&buf, zbf));\n    if (buf > UINT16_MAX) {\n        _Z_WARN(\"Invalid zint16 value decoded\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *zint = (uint16_t)buf;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_zint32_decode(uint32_t *zint, _z_zbuf_t *zbf) {\n    uint64_t buf;\n    _Z_RETURN_IF_ERR(_z_zint64_decode(&buf, zbf));\n    if (buf > UINT32_MAX) {\n        _Z_WARN(\"Invalid zint32 value decoded\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *zint = (uint32_t)buf;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_zsize_decode(_z_zint_t *zint, _z_zbuf_t *zbf) {\n    uint64_t buf;\n    _Z_RETURN_IF_ERR(_z_zint64_decode(&buf, zbf));\n    if (buf > SIZE_MAX) {\n        _Z_WARN(\"Invalid zsize value decoded\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    *zint = (_z_zint_t)buf;\n    return _Z_RES_OK;\n}\n\n/*------------------ uint8_array ------------------*/\nz_result_t _z_buf_encode(_z_wbuf_t *wbf, const uint8_t *buf, size_t len) {\n    z_result_t ret = _Z_RES_OK;\n\n    if ((wbf->_expansion_step != 0) && (len > Z_ZID_LENGTH)) {\n        ret |= _z_wbuf_wrap_bytes(wbf, buf, 0, len);\n    } else {\n        ret |= _z_wbuf_write_bytes(wbf, buf, 0, len);\n    }\n    return ret;\n}\n\nz_result_t _z_slice_encode(_z_wbuf_t *wbf, const _z_slice_t *bs) {\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, bs->len));\n    return _z_slice_val_encode(wbf, bs);\n}\n\nz_result_t _z_slices_encode(_z_wbuf_t *wbf, const _z_slice_t *bs, size_t num_slices) {\n    size_t total_len = 0;\n    for (size_t i = 0; i < num_slices; ++i) {\n        total_len += bs[i].len;\n    }\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, total_len));\n    for (size_t i = 0; i < num_slices; ++i) {\n        _Z_RETURN_IF_ERR(_z_slice_val_encode(wbf, &bs[i]));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_bytes_decode(_z_bytes_t *bs, _z_zbuf_t *zbf, _z_arc_slice_t *arcs) {\n    // Decode slice\n    _z_slice_t s;\n    _Z_RETURN_IF_ERR(_z_slice_decode(&s, zbf));\n    // Calc offset\n    size_t offset = _z_ptr_u8_diff(s.start, _z_slice_simple_rc_value(&zbf->_slice)->start);\n    // Get ownership of subslice\n    *arcs = _z_arc_slice_wrap_slice_rc(&zbf->_slice, offset, s.len);\n    _z_bytes_alias_arc_slice(bs, arcs);\n    return _Z_RES_OK;\n}\n\nstatic inline z_result_t _z_bytes_encode_val(_z_wbuf_t *wbf, const _z_bytes_t *bs) {\n    z_result_t ret = _Z_RES_OK;\n    for (size_t i = 0; i < _z_bytes_num_slices(bs); ++i) {\n        const _z_arc_slice_t *arc_s = _z_bytes_get_slice(bs, i);\n        _Z_RETURN_IF_ERR(_z_buf_encode(wbf, _z_arc_slice_data(arc_s), _z_arc_slice_len(arc_s)))\n    }\n    return ret;\n}\n\nz_result_t _z_bytes_encode(_z_wbuf_t *wbf, const _z_bytes_t *bs) {\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, _z_bytes_len(bs)))\n    return _z_bytes_encode_val(wbf, bs);\n}\n\n/*------------------ string with null terminator ------------------*/\nz_result_t _z_str_encode(_z_wbuf_t *wbf, const char *s) {\n    size_t len = strlen(s);\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, len))\n    // Note that this does not put the string terminator on the wire.\n    return _z_wbuf_write_bytes(wbf, (const uint8_t *)s, 0, len);\n}\n\nz_result_t _z_str_decode(char **str, _z_zbuf_t *zbf) {\n    _z_zint_t len = 0;\n    z_result_t ret = _z_zsize_decode(&len, zbf);\n    if (ret != _Z_RES_OK) {\n        *str = NULL;\n        return ret;\n    }\n    // Check if we have enough bytes to read\n    if (_z_zbuf_len(zbf) < len) {\n        _Z_WARN(\"Not enough bytes to read\");\n        *str = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    // Allocate space for the null terminated string\n    char *tmp = (char *)z_malloc(len + (size_t)1);\n    if (tmp == NULL) {\n        *str = NULL;\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Read and store string\n    tmp[len] = '\\0';\n    _z_zbuf_read_bytes(zbf, (uint8_t *)tmp, 0, len);\n    *str = tmp;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_string_encode(_z_wbuf_t *wbf, const _z_string_t *s) {\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, _z_string_len(s)))\n    // Note that this does not put the string terminator on the wire.\n    return _z_wbuf_write_bytes(wbf, (const uint8_t *)_z_string_data(s), 0, _z_string_len(s));\n}\n\nz_result_t _z_string_decode(_z_string_t *str, _z_zbuf_t *zbf) {\n    _z_zint_t len = 0;\n    // Decode string length\n    _Z_RETURN_IF_ERR(_z_zsize_decode(&len, zbf));\n    // Check if we have enough bytes to read\n    if (_z_zbuf_len(zbf) < len) {\n        _Z_INFO(\"Not enough bytes to read\");\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n    }\n    // Alias string\n    *str = _z_string_alias_substr((const char *)_z_zbuf_get_rptr(zbf), len);\n    _z_zbuf_set_rpos(zbf, _z_zbuf_get_rpos(zbf) + len);\n    return _Z_RES_OK;\n}\n\n/*------------------ encoding ------------------*/\n#define _Z_ENCODING_FLAG_S 0x01\n\nsize_t _z_encoding_len(const _z_encoding_t *en) {\n    size_t en_len = _z_zint_len((uint32_t)(en->id) << 1);\n    if (_z_string_check(&en->schema)) {\n        en_len += _z_zint_len(_z_string_len(&en->schema)) + _z_string_len(&en->schema);\n    }\n    return en_len;\n}\n\nz_result_t _z_encoding_encode(_z_wbuf_t *wbf, const _z_encoding_t *en) {\n    bool has_schema = _z_string_check(&en->schema);\n    uint32_t id = (uint32_t)(en->id) << 1;\n    if (has_schema) {\n        id |= _Z_ENCODING_FLAG_S;\n    }\n    _Z_RETURN_IF_ERR(_z_zint32_encode(wbf, id));\n    if (has_schema) {\n        _Z_RETURN_IF_ERR(_z_string_encode(wbf, &en->schema));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_encoding_decode(_z_encoding_t *en, _z_zbuf_t *zbf) {\n    uint32_t id = 0;\n    bool has_schema = false;\n    _Z_RETURN_IF_ERR(_z_zint32_decode(&id, zbf));\n    if ((id & _Z_ENCODING_FLAG_S) != 0) {\n        has_schema = true;\n    }\n    en->id = (uint16_t)(id >> 1);\n    if (has_schema) {\n        _Z_RETURN_IF_ERR(_z_string_decode(&en->schema, zbf));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_value_encode(_z_wbuf_t *wbf, const _z_value_t *value) {\n    size_t total_len = _z_encoding_len(&value->encoding) + _z_bytes_len(&value->payload);\n    _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, total_len));\n    _Z_RETURN_IF_ERR(_z_encoding_encode(wbf, &value->encoding));\n    return _z_bytes_encode_val(wbf, &value->payload);\n}\n\nz_result_t _z_value_decode(_z_value_t *value, _z_zbuf_t *zbf) {\n    _Z_RETURN_IF_ERR(_z_encoding_decode(&value->encoding, zbf));\n    _Z_RETURN_IF_ERR(_z_bytes_from_buf(&value->payload, (uint8_t *)_z_zbuf_start(zbf), _z_zbuf_len(zbf)));\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/protocol/config.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/config.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/string.h\"\n\nz_result_t _z_config_init(_z_config_t *ps) {\n    _z_str_intmap_init(ps);\n    return 0;\n}\n\nz_result_t _zp_config_insert(_z_config_t *ps, uint8_t key, const char *value) {\n    z_result_t ret = _Z_RES_OK;\n\n    const char *res = \"\";\n    if (key == Z_CONFIG_CONNECT_KEY) {\n        res = _z_str_intmap_insert_push(ps, key, _z_str_clone(value));\n    } else {\n        res = _z_str_intmap_insert(ps, key, _z_str_clone(value));\n    }\n    if (strcmp(res, value) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_FAILED_INSERT);\n        ret = _Z_ERR_CONFIG_FAILED_INSERT;\n    }\n\n    return ret;\n}\n\nz_result_t _zp_config_insert_string(_z_config_t *ps, uint8_t key, const _z_string_t *value) {\n    z_result_t ret = _Z_RES_OK;\n    char *str = _z_str_from_string_clone(value);\n    char *res = _z_str_intmap_insert(ps, key, str);\n    if (strcmp(res, str) != 0) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_FAILED_INSERT);\n        ret = _Z_ERR_CONFIG_FAILED_INSERT;\n    }\n    z_free(str);\n\n    return ret;\n}\n\nchar *_z_config_get(const _z_config_t *ps, uint8_t key) { return _z_str_intmap_get(ps, key); }\n\nz_result_t _z_config_get_all(const _z_config_t *ps, _z_string_svec_t *locators, uint8_t key) {\n    _z_list_t *cfg_list = _z_str_intmap_get_all(ps, key);\n    while (cfg_list != NULL) {\n        _z_int_void_map_entry_t *entry = (_z_int_void_map_entry_t *)_z_list_value(cfg_list);\n        char *val = (char *)entry->_val;\n        _z_string_t s = _z_string_copy_from_str(val);\n        _Z_RETURN_IF_ERR(_z_string_svec_append(locators, &s, true));\n        cfg_list = _z_list_next(cfg_list);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_config_get_i32_default(_z_config_t *config, uint8_t key, const char *default_val, int32_t *out) {\n    const char *s = _z_config_get(config, key);\n    if (s == NULL) {\n        s = default_val;\n    }\n\n    return _z_str_parse_i32(s, out) ? _Z_RES_OK : _Z_ERR_CONFIG_INVALID_VALUE;\n}\n\nz_result_t _z_config_get_bool_default(_z_config_t *config, uint8_t key, const char *default_val, bool *out) {\n    const char *s = _z_config_get(config, key);\n    if (s == NULL) {\n        s = default_val;\n    }\n\n    return _z_str_parse_bool(s, out) ? _Z_RES_OK : _Z_ERR_CONFIG_INVALID_VALUE;\n}\n\n/*------------------ int-string map ------------------*/\nz_result_t _z_str_intmap_from_strn(_z_str_intmap_t *strint, const char *s, uint8_t argc, _z_str_intmapping_t argv[],\n                                   size_t n) {\n    z_result_t ret = _Z_RES_OK;\n    *strint = _z_str_intmap_make();\n\n    // Check the string contains only the right\n    const char *start = s;\n    const char *end = &s[n - 1];\n    size_t curr_len = n;\n    while (curr_len > 0) {\n        const char *p_key_start = start;\n        const char *p_key_end = memchr(p_key_start, INT_STR_MAP_KEYVALUE_SEPARATOR, curr_len);\n\n        if (p_key_end != NULL) {\n            // Verify the key is valid based on the provided mapping\n            size_t p_key_len = _z_ptr_char_diff(p_key_end, p_key_start);\n            bool found = false;\n            uint8_t key = 0;\n            for (uint8_t i = 0; i < argc; i++) {\n                if (p_key_len != strlen(argv[i]._str)) {\n                    continue;\n                }\n                if (strncmp(p_key_start, argv[i]._str, p_key_len) != 0) {\n                    continue;\n                }\n\n                found = true;\n                key = argv[i]._key;\n                break;\n            }\n\n            if (found == false) {\n                break;\n            }\n\n            // Read and populate the value\n            const char *p_value_start = _z_cptr_char_offset(p_key_end, 1);\n            size_t value_max_size = curr_len - _z_ptr_char_diff(p_value_start, start);\n            const char *p_value_end = memchr(p_key_end, INT_STR_MAP_LIST_SEPARATOR, value_max_size);\n\n            size_t p_value_len = 0;\n            if (p_value_end == NULL) {\n                p_value_end = end;\n                p_value_len = value_max_size + 1;\n            } else {\n                p_value_len = _z_ptr_char_diff(p_value_end, p_value_start) + 1;\n            }\n            char *p_value = (char *)z_malloc(p_value_len);\n            if (p_value != NULL) {\n                _z_str_n_copy(p_value, p_value_start, p_value_len);\n                _z_str_intmap_insert(strint, key, p_value);\n\n                // Process next key value\n                start = _z_cptr_char_offset(p_value_end, 1);\n                curr_len = n - _z_ptr_char_diff(start, s);\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            }\n        }\n    }\n\n    return ret;\n}\n\nz_result_t _z_str_intmap_from_str(_z_str_intmap_t *strint, const char *s, uint8_t argc, _z_str_intmapping_t argv[]) {\n    return _z_str_intmap_from_strn(strint, s, argc, argv, strlen(s));\n}\n\nsize_t _z_str_intmap_strlen(const _z_str_intmap_t *s, uint8_t argc, _z_str_intmapping_t argv[]) {\n    // Calculate the string length to allocate\n    size_t len = 0;\n    for (size_t i = 0; i < argc; i++) {\n        char *v = _z_str_intmap_get(s, argv[i]._key);\n        if (v != NULL) {\n            if (len != (size_t)0) {\n                len = len + (size_t)1;  // List separator\n            }\n            len = len + strlen(argv[i]._str);  // Key\n            len = len + (size_t)1;             // KeyValue separator\n            len = len + strlen(v);             // Value\n        }\n    }\n\n    return len;\n}\n\nvoid _z_str_intmap_onto_str(char *dst, size_t dst_len, const _z_str_intmap_t *s, uint8_t argc,\n                            _z_str_intmapping_t argv[]) {\n    if (dst == NULL || dst_len == 0) {\n        return;\n    }\n\n    // Remaining length excluding '\\0'\n    size_t len = dst_len - (size_t)1;\n    dst[0] = '\\0';\n    for (size_t i = 0; i < argc; i++) {\n        char *v = _z_str_intmap_get(s, argv[i]._key);\n        if (v != NULL) {\n            if (len > (size_t)0 && dst[0] != '\\0') {\n                _z_str_append(dst, INT_STR_MAP_LIST_SEPARATOR);  // List separator\n                len = len - (size_t)1;\n            }\n\n            size_t key_len = strnlen(argv[i]._str, len);\n            if (len > (size_t)0) {\n                size_t n = key_len < len ? key_len : len;\n                // Flawfinder: ignore [CWE-120]\n                (void)strncat(dst, argv[i]._str, n);  // Key\n                len = len - n;\n            }\n\n            if (len > (size_t)0) {\n                _z_str_append(dst, INT_STR_MAP_KEYVALUE_SEPARATOR);  // KeyValue separator\n                len = len - (size_t)1;\n            }\n\n            size_t value_len = strnlen(v, len);\n            if (len > (size_t)0) {\n                size_t n = value_len < len ? value_len : len;\n                // Flawfinder: ignore [CWE-120]\n                (void)strncat(dst, v, n);  // Value\n                len = len - n;\n            }\n        }\n    }\n}\n\nchar *_z_str_intmap_to_str(const _z_str_intmap_t *s, uint8_t argc, _z_str_intmapping_t argv[]) {\n    // Calculate the string length to allocate\n    size_t len = _z_str_intmap_strlen(s, argc, argv) + (size_t)1;\n    // Build the string\n    char *dst = (char *)z_malloc(len);\n    if (dst != NULL) {\n        _z_str_intmap_onto_str(dst, len, s, argc, argv);\n    }\n    return dst;\n}\n"
  },
  {
    "path": "src/protocol/core.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/codec/core.h\"\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/net/encoding.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/hash.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#define _Z_ID_LEN (16)\n\nconst _z_id_t empty_id = {0};\n\nuint8_t _z_id_len(_z_id_t id) {\n    uint8_t len = _Z_ID_LEN;\n    while (len > 0) {\n        --len;\n        if (id.id[len] != 0) {\n            ++len;\n            break;\n        }\n    }\n    return len;\n}\n\nsize_t _z_id_hash(const _z_id_t *id) {\n    size_t hash = (size_t)_Z_FNV_OFFSET_BASIS;\n\n    for (size_t i = 0; i < ZENOH_ID_SIZE; ++i) {\n        hash ^= id->id[i];\n        hash *= _Z_FNV_PRIME;\n    }\n\n    return hash;\n}\n\nint _z_id_cmp(const _z_id_t *left, const _z_id_t *right) {\n    for (size_t i = 0; i < ZENOH_ID_SIZE; ++i) {\n        if (left->id[i] < right->id[i]) return -1;\n        if (left->id[i] > right->id[i]) return 1;\n    }\n    return 0;\n}\n\n_z_ntp64_t _z_timestamp_ntp64_from_time(uint32_t seconds, uint32_t nanos) {\n    const uint64_t FRAC_PER_SEC = (uint64_t)1 << 32;\n    const uint64_t NANOS_PER_SEC = 1000000000;\n\n    uint32_t fractions = (uint32_t)((uint64_t)nanos * FRAC_PER_SEC / NANOS_PER_SEC + 1);\n    return ((uint64_t)seconds << 32) | fractions;\n}\n\nint _z_timestamp_cmp(const _z_timestamp_t *left, const _z_timestamp_t *right) {\n    // Compare validity\n    if (!left->valid && right->valid) return -1;\n    if (left->valid && !right->valid) return 1;\n\n    // Compare time\n    if (left->time < right->time) return -1;\n    if (left->time > right->time) return 1;\n\n    // Compare IDs\n    return _z_id_cmp(&left->id, &right->id);\n}\n\n_z_value_t _z_value_steal(_z_value_t *value) {\n    _z_value_t ret = *value;\n    *value = _z_value_null();\n    return ret;\n}\nz_result_t _z_value_copy(_z_value_t *dst, const _z_value_t *src) {\n    *dst = _z_value_null();\n    _Z_RETURN_IF_ERR(_z_encoding_copy(&dst->encoding, &src->encoding));\n    _Z_CLEAN_RETURN_IF_ERR(_z_bytes_copy(&dst->payload, &src->payload), _z_encoding_clear(&dst->encoding));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_hello_copy(_z_hello_t *dst, const _z_hello_t *src) {\n    *dst = _z_hello_null();\n    _Z_RETURN_IF_ERR(_z_string_svec_copy(&dst->_locators, &src->_locators, true));\n    dst->_version = src->_version;\n    dst->_whatami = src->_whatami;\n    memcpy(&dst->_zid.id, &src->_zid.id, _Z_ID_LEN);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_hello_move(_z_hello_t *dst, _z_hello_t *src) {\n    *dst = *src;\n    *src = _z_hello_null();\n    return _Z_RES_OK;\n}\n\nz_result_t _z_value_move(_z_value_t *dst, _z_value_t *src) {\n    *dst = _z_value_null();\n    _Z_RETURN_IF_ERR(_z_bytes_move(&dst->payload, &src->payload));\n    _Z_CLEAN_RETURN_IF_ERR(_z_encoding_move(&dst->encoding, &src->encoding), _z_value_clear(dst));\n    return _Z_RES_OK;\n}\n\nsize_t _z_entity_global_id_hash(const _z_entity_global_id_t *e) {\n    size_t hash = _z_id_hash(&e->zid);\n\n    for (size_t i = 0; i < sizeof(e->eid); ++i) {\n        hash ^= ((uint8_t *)&e->eid)[i];\n        hash *= _Z_FNV_PRIME;\n    }\n\n    return hash;\n}\n\nz_result_t _z_source_info_copy(_z_source_info_t *dst, const _z_source_info_t *src) {\n    dst->_source_id = src->_source_id;\n    dst->_source_sn = src->_source_sn;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_source_info_move(_z_source_info_t *dst, _z_source_info_t *src) {\n    dst->_source_id = src->_source_id;\n    dst->_source_sn = src->_source_sn;\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/protocol/definitions/declarations.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n\nvoid _z_declaration_clear(_z_declaration_t *decl) {\n    switch (decl->_tag) {\n        case _Z_DECL_KEXPR: {\n            _z_wireexpr_clear(&decl->_body._decl_kexpr._keyexpr);\n            break;\n        }\n        case _Z_UNDECL_KEXPR: {\n            break;\n        }\n        case _Z_DECL_SUBSCRIBER: {\n            _z_wireexpr_clear(&decl->_body._decl_subscriber._keyexpr);\n            break;\n        }\n        case _Z_UNDECL_SUBSCRIBER: {\n            _z_wireexpr_clear(&decl->_body._undecl_subscriber._ext_keyexpr);\n            break;\n        }\n        case _Z_DECL_QUERYABLE: {\n            _z_wireexpr_clear(&decl->_body._decl_queryable._keyexpr);\n            break;\n        }\n        case _Z_UNDECL_QUERYABLE: {\n            _z_wireexpr_clear(&decl->_body._undecl_queryable._ext_keyexpr);\n            break;\n        }\n        case _Z_DECL_TOKEN: {\n            _z_wireexpr_clear(&decl->_body._decl_token._keyexpr);\n            break;\n        }\n        case _Z_UNDECL_TOKEN: {\n            _z_wireexpr_clear(&decl->_body._undecl_token._ext_keyexpr);\n            break;\n        }\n        default:\n        case _Z_DECL_FINAL: {\n            break;\n        }\n    }\n}\n_z_declaration_t _z_make_decl_keyexpr(uint16_t id, _Z_MOVE(_z_wireexpr_t) key) {\n    return (_z_declaration_t){._tag = _Z_DECL_KEXPR,\n                              ._body = {._decl_kexpr = {._id = id, ._keyexpr = _z_wireexpr_steal(key)}}};\n}\n_z_declaration_t _z_make_undecl_keyexpr(uint16_t id) {\n    return (_z_declaration_t){._tag = _Z_UNDECL_KEXPR, ._body = {._undecl_kexpr = {._id = id}}};\n}\n_z_declaration_t _z_make_decl_subscriber(_Z_MOVE(_z_wireexpr_t) key, uint32_t id) {\n    return (_z_declaration_t){._tag = _Z_DECL_SUBSCRIBER,\n                              ._body = {._decl_subscriber = {._id = id, ._keyexpr = _z_wireexpr_steal(key)}}};\n}\n\n_z_declaration_t _z_make_undecl_subscriber(uint32_t id, _Z_OPTIONAL _Z_MOVE(_z_wireexpr_t) key) {\n    return (_z_declaration_t){\n        ._tag = _Z_UNDECL_SUBSCRIBER,\n        ._body = {._undecl_subscriber = {._id = id,\n                                         ._ext_keyexpr = (key == NULL) ? _z_wireexpr_null() : _z_wireexpr_steal(key)}}};\n}\n\n_z_declaration_t _z_make_decl_queryable(_Z_MOVE(_z_wireexpr_t) key, uint32_t id, bool complete, uint16_t distance) {\n    return (_z_declaration_t){\n        ._tag = _Z_DECL_QUERYABLE,\n        ._body = {._decl_queryable = {._id = id,\n                                      ._keyexpr = _z_wireexpr_steal(key),\n                                      ._ext_queryable_info = {._complete = complete, ._distance = distance}}}};\n}\n_z_declaration_t _z_make_undecl_queryable(uint32_t id, _Z_OPTIONAL _Z_MOVE(_z_wireexpr_t) key) {\n    return (_z_declaration_t){\n        ._tag = _Z_UNDECL_QUERYABLE,\n        ._body = {._undecl_queryable = {._id = id,\n                                        ._ext_keyexpr = (key == NULL) ? _z_wireexpr_null() : _z_wireexpr_steal(key)}}};\n}\n_z_declaration_t _z_make_decl_token(_Z_MOVE(_z_wireexpr_t) key, uint32_t id) {\n    return (_z_declaration_t){._tag = _Z_DECL_TOKEN,\n                              ._body = {._decl_token = {\n                                            ._id = id,\n                                            ._keyexpr = _z_wireexpr_steal(key),\n                                        }}};\n}\n_z_declaration_t _z_make_undecl_token(uint32_t id, _Z_OPTIONAL _Z_MOVE(_z_wireexpr_t) key) {\n    return (_z_declaration_t){\n        ._tag = _Z_UNDECL_TOKEN,\n        ._body = {\n            ._undecl_token = {._id = id, ._ext_keyexpr = (key == NULL) ? _z_wireexpr_null() : _z_wireexpr_steal(key)}}};\n}\n_z_declaration_t _z_make_decl_final(void) {\n    return (_z_declaration_t){._tag = _Z_DECL_FINAL, ._body = {._decl_final = {0}}};\n}\n"
  },
  {
    "path": "src/protocol/definitions/interest.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n\nvoid _z_interest_clear(_z_interest_t *interest) { _z_wireexpr_clear(&interest->_keyexpr); }\n\n_z_interest_t _z_make_interest(_Z_MOVE(_z_wireexpr_t) key, uint32_t id, uint8_t flags) {\n    return (_z_interest_t){\n        ._id = id,\n        ._keyexpr = (key == NULL) ? _z_wireexpr_null() : _z_wireexpr_steal(key),\n        .flags = flags,\n    };\n}\n\n_z_interest_t _z_make_interest_final(uint32_t id) {\n    return (_z_interest_t){\n        ._id = id,\n        ._keyexpr = _z_wireexpr_null(),\n        .flags = 0,\n    };\n}\n"
  },
  {
    "path": "src/protocol/definitions/message.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/definitions/message.h\"\n\n#include <stdbool.h>\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n\nvoid _z_msg_reply_clear(_z_msg_reply_t *msg) { _z_push_body_clear(&msg->_body); }\n\nvoid _z_msg_put_clear(_z_msg_put_t *msg) {\n    _z_bytes_drop(&msg->_payload);\n    _z_bytes_drop(&msg->_attachment);\n    _z_encoding_clear(&msg->_encoding);\n    _z_timestamp_clear(&msg->_commons._timestamp);\n}\n\n_z_msg_query_reqexts_t _z_msg_query_required_extensions(const _z_msg_query_t *msg) {\n    return (_z_msg_query_reqexts_t){\n        .body = _z_bytes_check(&msg->_ext_value.payload) || _z_encoding_check(&msg->_ext_value.encoding),\n        .info = _z_id_check(msg->_ext_info._source_id.zid) || msg->_ext_info._source_id.eid != 0 ||\n                msg->_ext_info._source_sn != 0,\n        .attachment = _z_bytes_check(&msg->_ext_attachment),\n    };\n}\n\nvoid _z_msg_query_clear(_z_msg_query_t *msg) {\n    _z_slice_clear(&msg->_parameters);\n    _z_bytes_drop(&msg->_ext_attachment);\n    _z_value_clear(&msg->_ext_value);\n    msg->_implicit_anyke = false;\n}\n\nvoid _z_msg_err_clear(_z_msg_err_t *err) {\n    _z_encoding_clear(&err->_encoding);\n    _z_bytes_drop(&err->_payload);\n}\n"
  },
  {
    "path": "src/protocol/definitions/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/definitions/network.h\"\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nconst _z_qos_t _Z_N_QOS_DEFAULT = {._val = 5};\n\n_z_n_msg_request_exts_t _z_n_msg_request_needed_exts(const _z_n_msg_request_t *msg) {\n    _z_n_msg_request_exts_t ret = {.n = 0,\n                                   .ext_budget = msg->_ext_budget != 0,\n                                   .ext_target = msg->_ext_target != Z_QUERY_TARGET_BEST_MATCHING,\n                                   .ext_qos = msg->_ext_qos._val != _Z_N_QOS_DEFAULT._val,\n                                   .ext_timeout_ms = msg->_ext_timeout_ms != 0,\n                                   .ext_tstamp = _z_timestamp_check(&msg->_ext_timestamp)};\n    if (ret.ext_budget) {\n        ret.n += 1;\n    }\n    if (ret.ext_target) {\n        ret.n += 1;\n    }\n    if (ret.ext_qos) {\n        ret.n += 1;\n    }\n    if (ret.ext_timeout_ms) {\n        ret.n += 1;\n    }\n    if (ret.ext_tstamp) {\n        ret.n += 1;\n    }\n    return ret;\n}\n\nvoid _z_n_msg_request_clear(_z_n_msg_request_t *msg) {\n    _z_wireexpr_clear(&msg->_key);\n    switch (msg->_tag) {\n        case _Z_REQUEST_QUERY: {\n            _z_msg_query_clear(&msg->_body._query);\n        } break;\n        case _Z_REQUEST_PUT: {\n            _z_msg_put_clear(&msg->_body._put);\n        } break;\n        case _Z_REQUEST_DEL: {\n            _z_msg_del_clear(&msg->_body._del);\n        } break;\n    }\n}\n\n/*=============================*/\n/*      Network Messages       */\n/*=============================*/\nvoid _z_push_body_clear(_z_push_body_t *msg) {\n    if (msg->_is_put) {\n        _z_msg_put_clear(&msg->_body._put);\n    }\n}\n_z_push_body_t _z_push_body_steal(_z_push_body_t *msg) {\n    _z_push_body_t ret = *msg;\n    *msg = _z_push_body_null();\n    return ret;\n}\n\nstatic z_result_t _z_push_body_copy(_z_push_body_t *dst, const _z_push_body_t *src) {\n    if (src->_is_put) {\n        _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._put._attachment, &src->_body._put._attachment));\n        _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._put._payload, &src->_body._put._payload));\n    } else {\n        _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._del._attachment, &src->_body._del._attachment));\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_n_msg_response_final_clear(_z_n_msg_response_final_t *msg) { (void)(msg); }\n\nvoid _z_n_msg_push_clear(_z_n_msg_push_t *msg) {\n    _z_wireexpr_clear(&msg->_key);\n    _z_push_body_clear(&msg->_body);\n}\n\nvoid _z_n_msg_response_clear(_z_n_msg_response_t *msg) {\n    _z_timestamp_clear(&msg->_ext_timestamp);\n    _z_wireexpr_clear(&msg->_key);\n    switch (msg->_tag) {\n        case _Z_RESPONSE_BODY_REPLY: {\n            _z_msg_reply_clear(&msg->_body._reply);\n            break;\n        }\n        case _Z_RESPONSE_BODY_ERR: {\n            _z_msg_err_clear(&msg->_body._err);\n            break;\n        }\n    }\n}\n\nvoid _z_n_msg_oam_clear(_z_n_msg_oam_t *oam) {\n    _z_timestamp_clear(&oam->_ext_timestamp);\n    switch (oam->_enc) {\n        case _Z_OAM_BODY_UNIT: {\n            _z_msg_ext_clear_unit(&oam->_body._unit);\n            break;\n        }\n        case _Z_OAM_BODY_ZINT: {\n            _z_msg_ext_clear_zint(&oam->_body._zint);\n            break;\n        }\n        case _Z_OAM_BODY_ZBUF: {\n            _z_msg_ext_clear_zbuf(&oam->_body._zbuf);\n            break;\n        }\n    }\n}\n\nvoid _z_n_msg_clear(_z_network_message_t *msg) {\n    switch (msg->_tag) {\n        case _Z_N_PUSH:\n            _z_n_msg_push_clear(&msg->_body._push);\n            break;\n        case _Z_N_REQUEST:\n            _z_n_msg_request_clear(&msg->_body._request);\n            break;\n        case _Z_N_RESPONSE:\n            _z_n_msg_response_clear(&msg->_body._response);\n            break;\n        case _Z_N_RESPONSE_FINAL:\n            _z_n_msg_response_final_clear(&msg->_body._response_final);\n            break;\n        case _Z_N_DECLARE:\n            _z_n_msg_declare_clear(&msg->_body._declare);\n            break;\n        case _Z_N_INTEREST:\n            _z_n_msg_interest_clear(&msg->_body._interest);\n            break;\n        case _Z_N_OAM:\n            _z_n_msg_oam_clear(&msg->_body._oam);\n            break;\n        default:\n            break;\n    }\n}\n\nvoid _z_n_msg_free(_z_network_message_t **msg) {\n    _z_network_message_t *ptr = *msg;\n\n    if (ptr != NULL) {\n        _z_n_msg_clear(ptr);\n\n        z_free(ptr);\n        *msg = NULL;\n    }\n}\n\nvoid _z_n_msg_make_response_final(_z_network_message_t *msg, _z_zint_t rid) {\n    msg->_tag = _Z_N_RESPONSE_FINAL;\n    msg->_reliability = Z_RELIABILITY_DEFAULT;\n    msg->_body._response_final._request_id = rid;\n}\n\nvoid _z_n_msg_make_declare(_z_network_message_t *msg, _z_declaration_t declaration, _z_optional_id_t interest_id) {\n    msg->_tag = _Z_N_DECLARE;\n    msg->_reliability = Z_RELIABILITY_DEFAULT;\n    msg->_body._declare._interest_id = interest_id;\n    msg->_body._declare._decl = declaration;\n    msg->_body._declare._ext_qos = _Z_N_QOS_DEFAULT;\n    msg->_body._declare._ext_timestamp = _z_timestamp_null();\n}\n\nvoid _z_n_msg_make_query(_z_zenoh_message_t *msg, const _z_wireexpr_t *key, const _z_slice_t *parameters, _z_zint_t qid,\n                         z_reliability_t reliability, z_consolidation_mode_t consolidation, const _z_bytes_t *payload,\n                         const _z_encoding_t *encoding, uint64_t timeout_ms, const _z_bytes_t *attachment,\n                         _z_n_qos_t qos, const _z_source_info_t *source_info, bool implicit_anyke) {\n    msg->_tag = _Z_N_REQUEST;\n    msg->_reliability = reliability;\n    msg->_body._request._tag = _Z_REQUEST_QUERY;\n    msg->_body._request._rid = qid;\n    msg->_body._request._key = *key;\n    msg->_body._request._body._query._parameters = *parameters;\n    msg->_body._request._body._query._implicit_anyke = implicit_anyke;\n    msg->_body._request._body._query._consolidation = consolidation;\n    msg->_body._request._body._query._ext_value.payload = (payload == NULL) ? _z_bytes_null() : *payload;\n    msg->_body._request._body._query._ext_value.encoding = (encoding == NULL) ? _z_encoding_null() : *encoding;\n    msg->_body._request._body._query._ext_info = (source_info == NULL) ? _z_source_info_null() : *source_info;\n    msg->_body._request._body._query._ext_attachment = (attachment == NULL) ? _z_bytes_null() : *attachment;\n    msg->_body._request._ext_budget = 0;\n    msg->_body._request._ext_qos = qos;\n    msg->_body._request._ext_target = Z_QUERY_TARGET_BEST_MATCHING;\n    msg->_body._request._ext_timeout_ms = timeout_ms;\n    msg->_body._request._ext_timestamp = _z_timestamp_null();\n}\n\nvoid _z_n_msg_make_push_put(_z_network_message_t *dst, const _z_wireexpr_t *key, const _z_bytes_t *payload,\n                            const _z_encoding_t *encoding, _z_n_qos_t qos, const _z_timestamp_t *timestamp,\n                            const _z_bytes_t *attachment, z_reliability_t reliability,\n                            const _z_source_info_t *source_info) {\n    dst->_tag = _Z_N_PUSH;\n    dst->_reliability = reliability;\n    dst->_body._push._key = *key;\n    dst->_body._push._qos = qos;\n    dst->_body._push._timestamp = _z_timestamp_null();\n    dst->_body._push._body._is_put = true;\n    dst->_body._push._body._body._put._commons._timestamp = (timestamp == NULL) ? _z_timestamp_null() : *timestamp;\n    dst->_body._push._body._body._put._commons._source_info =\n        (source_info == NULL) ? _z_source_info_null() : *source_info;\n    dst->_body._push._body._body._put._payload = (payload == NULL) ? _z_bytes_null() : *payload;\n    dst->_body._push._body._body._put._encoding = (encoding == NULL) ? _z_encoding_null() : *encoding;\n    dst->_body._push._body._body._put._attachment = (attachment == NULL) ? _z_bytes_null() : *attachment;\n}\n\nvoid _z_n_msg_make_push_del(_z_network_message_t *dst, const _z_wireexpr_t *key, _z_n_qos_t qos,\n                            const _z_timestamp_t *timestamp, z_reliability_t reliability,\n                            const _z_source_info_t *source_info) {\n    dst->_tag = _Z_N_PUSH;\n    dst->_reliability = reliability;\n    dst->_body._push._key = *key;\n    dst->_body._push._qos = qos;\n    dst->_body._push._timestamp = _z_timestamp_null();\n    dst->_body._push._body._is_put = false;\n    dst->_body._push._body._body._del._commons._timestamp = (timestamp == NULL) ? _z_timestamp_null() : *timestamp;\n    dst->_body._push._body._body._del._commons._source_info =\n        (source_info == NULL) ? _z_source_info_null() : *source_info;\n    dst->_body._push._body._body._del._attachment = _z_bytes_null();\n}\n\nvoid _z_n_msg_make_reply_ok_put(_z_network_message_t *dst, const _z_id_t *zid, _z_zint_t rid, const _z_wireexpr_t *key,\n                                z_reliability_t reliability, z_consolidation_mode_t consolidation, _z_n_qos_t qos,\n                                const _z_timestamp_t *timestamp, const _z_source_info_t *source_info,\n                                const _z_bytes_t *payload, const _z_encoding_t *encoding,\n                                const _z_bytes_t *attachment) {\n    dst->_tag = _Z_N_RESPONSE;\n    dst->_reliability = reliability;\n    dst->_body._response._tag = _Z_RESPONSE_BODY_REPLY;\n    dst->_body._response._request_id = rid;\n    dst->_body._response._key = *key;\n    dst->_body._response._body._reply._consolidation = consolidation;\n    dst->_body._response._body._reply._body._is_put = true;\n    dst->_body._response._body._reply._body._body._put._commons._timestamp =\n        (timestamp == NULL) ? _z_timestamp_null() : *timestamp;\n    dst->_body._response._body._reply._body._body._put._commons._source_info =\n        (source_info == NULL) ? _z_source_info_null() : *source_info;\n    dst->_body._response._body._reply._body._body._put._payload = (payload == NULL) ? _z_bytes_null() : *payload;\n    dst->_body._response._body._reply._body._body._put._encoding = (encoding == NULL) ? _z_encoding_null() : *encoding;\n    dst->_body._response._body._reply._body._body._put._attachment =\n        (attachment == NULL) ? _z_bytes_null() : *attachment;\n    dst->_body._response._ext_qos = qos;\n    dst->_body._response._ext_timestamp = _z_timestamp_null();\n    dst->_body._response._ext_responder._eid = 0;\n    dst->_body._response._ext_responder._zid = *zid;\n}\n\nvoid _z_n_msg_make_reply_ok_del(_z_network_message_t *dst, const _z_id_t *zid, _z_zint_t rid, const _z_wireexpr_t *key,\n                                z_reliability_t reliability, z_consolidation_mode_t consolidation, _z_n_qos_t qos,\n                                const _z_timestamp_t *timestamp, const _z_source_info_t *source_info,\n                                const _z_bytes_t *attachment) {\n    dst->_tag = _Z_N_RESPONSE;\n    dst->_reliability = reliability;\n    dst->_body._response._tag = _Z_RESPONSE_BODY_REPLY;\n    dst->_body._response._request_id = rid;\n    dst->_body._response._key = *key;\n    dst->_body._response._body._reply._consolidation = consolidation;\n    dst->_body._response._body._reply._body._is_put = false;\n    dst->_body._response._body._reply._body._body._del._commons._timestamp =\n        (timestamp == NULL) ? _z_timestamp_null() : *timestamp;\n    dst->_body._response._body._reply._body._body._del._commons._source_info =\n        (source_info == NULL) ? _z_source_info_null() : *source_info;\n    dst->_body._response._body._reply._body._body._del._attachment =\n        (attachment == NULL) ? _z_bytes_null() : *attachment;\n    dst->_body._response._ext_timestamp = _z_timestamp_null();\n    dst->_body._response._ext_qos = qos;\n    dst->_body._response._ext_responder._eid = 0;\n    dst->_body._response._ext_responder._zid = *zid;\n}\n\nvoid _z_n_msg_make_reply_err(_z_network_message_t *dst, const _z_id_t *zid, _z_zint_t rid, z_reliability_t reliability,\n                             _z_n_qos_t qos, const _z_bytes_t *payload, const _z_encoding_t *encoding,\n                             const _z_source_info_t *source_info) {\n    dst->_tag = _Z_N_RESPONSE;\n    dst->_reliability = reliability;\n    dst->_body._response._tag = _Z_RESPONSE_BODY_ERR;\n    dst->_body._response._request_id = rid;\n    dst->_body._response._key = _z_wireexpr_null();\n    dst->_body._response._body._err._payload = (payload == NULL) ? _z_bytes_null() : *payload;\n    dst->_body._response._body._err._encoding = (encoding == NULL) ? _z_encoding_null() : *encoding;\n    dst->_body._response._body._err._ext_source_info = (source_info == NULL) ? _z_source_info_null() : *source_info;\n    dst->_body._response._ext_timestamp = _z_timestamp_null();\n    dst->_body._response._ext_qos = qos;\n    dst->_body._response._ext_responder._eid = 0;\n    dst->_body._response._ext_responder._zid = *zid;\n}\n\nvoid _z_n_msg_make_interest(_z_network_message_t *msg, _z_interest_t interest) {\n    msg->_tag = _Z_N_INTEREST;\n    msg->_reliability = Z_RELIABILITY_DEFAULT;\n    msg->_body._interest._interest = interest;\n}\n\nstatic z_result_t _z_n_msg_push_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst->_body._push._key, &src->_body._push._key));\n    return _z_push_body_copy(&dst->_body._push._body, &src->_body._push._body);\n}\n\nstatic z_result_t _z_n_msg_request_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst->_body._request._key, &src->_body._request._key));\n    switch (src->_body._request._tag) {\n        case _Z_REQUEST_QUERY:\n            _Z_RETURN_IF_ERR(_z_slice_copy(&dst->_body._request._body._query._parameters,\n                                           &src->_body._request._body._query._parameters));\n            _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._request._body._query._ext_attachment,\n                                           &src->_body._request._body._query._ext_attachment));\n            _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._request._body._query._ext_value.payload,\n                                           &src->_body._request._body._query._ext_value.payload));\n            break;\n        case _Z_REQUEST_PUT:\n            _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._request._body._put._attachment,\n                                           &src->_body._request._body._put._attachment));\n            _Z_RETURN_IF_ERR(\n                _z_bytes_copy(&dst->_body._request._body._put._payload, &src->_body._request._body._put._payload));\n            break;\n        case _Z_REQUEST_DEL:\n            _Z_RETURN_IF_ERR(_z_bytes_copy(&dst->_body._request._body._del._attachment,\n                                           &src->_body._request._body._del._attachment));\n            break;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_n_msg_response_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst->_body._response._key, &src->_body._response._key));\n    switch (src->_body._response._tag) {\n        case _Z_RESPONSE_BODY_REPLY:\n            _Z_RETURN_IF_ERR(\n                _z_push_body_copy(&dst->_body._response._body._reply._body, &src->_body._response._body._reply._body));\n            break;\n        case _Z_RESPONSE_BODY_ERR:\n            _Z_RETURN_IF_ERR(\n                _z_bytes_copy(&dst->_body._response._body._err._payload, &src->_body._response._body._err._payload));\n            break;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_n_msg_response_final_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_n_msg_declare_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    const _z_declaration_t *src_decl = &src->_body._declare._decl;\n    _z_declaration_t *dst_decl = &dst->_body._declare._decl;\n    switch (src_decl->_tag) {\n        case _Z_DECL_KEXPR: {\n            _Z_RETURN_IF_ERR(\n                _z_wireexpr_copy(&dst_decl->_body._decl_kexpr._keyexpr, &src_decl->_body._decl_kexpr._keyexpr));\n        } break;\n        case _Z_DECL_SUBSCRIBER: {\n            _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst_decl->_body._decl_subscriber._keyexpr,\n                                              &src_decl->_body._decl_subscriber._keyexpr));\n        } break;\n        case _Z_UNDECL_SUBSCRIBER: {\n            _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst_decl->_body._undecl_subscriber._ext_keyexpr,\n                                              &src_decl->_body._undecl_subscriber._ext_keyexpr));\n        } break;\n        case _Z_DECL_QUERYABLE: {\n            _Z_RETURN_IF_ERR(\n                _z_wireexpr_copy(&dst_decl->_body._decl_queryable._keyexpr, &src_decl->_body._decl_queryable._keyexpr));\n        } break;\n        case _Z_UNDECL_QUERYABLE: {\n            _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst_decl->_body._undecl_queryable._ext_keyexpr,\n                                              &src_decl->_body._undecl_queryable._ext_keyexpr));\n        } break;\n        case _Z_DECL_TOKEN: {\n            _Z_RETURN_IF_ERR(\n                _z_wireexpr_copy(&dst_decl->_body._decl_token._keyexpr, &src_decl->_body._decl_token._keyexpr));\n        } break;\n        case _Z_UNDECL_TOKEN: {\n            _Z_RETURN_IF_ERR(_z_wireexpr_copy(&dst_decl->_body._undecl_token._ext_keyexpr,\n                                              &src_decl->_body._undecl_token._ext_keyexpr));\n        } break;\n        default:\n            break;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_n_msg_interest_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    _Z_RETURN_IF_ERR(\n        _z_wireexpr_copy(&dst->_body._interest._interest._keyexpr, &src->_body._interest._interest._keyexpr));\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_n_msg_oam_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    memcpy(dst, src, sizeof(_z_network_message_t));\n    switch (src->_body._oam._enc) {\n        case _Z_OAM_BODY_ZBUF:\n            _Z_RETURN_IF_ERR(_z_slice_copy(&dst->_body._oam._body._zbuf._val, &src->_body._oam._body._zbuf._val));\n            break;\n        default:\n            break;\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_n_msg_copy(_z_network_message_t *dst, const _z_network_message_t *src) {\n    switch (src->_tag) {\n        case _Z_N_PUSH:\n            return _z_n_msg_push_copy(dst, src);\n        case _Z_N_REQUEST:\n            return _z_n_msg_request_copy(dst, src);\n        case _Z_N_RESPONSE:\n            return _z_n_msg_response_copy(dst, src);\n        case _Z_N_RESPONSE_FINAL:\n            return _z_n_msg_response_final_copy(dst, src);\n        case _Z_N_DECLARE:\n            return _z_n_msg_declare_copy(dst, src);\n        case _Z_N_INTEREST:\n            return _z_n_msg_interest_copy(dst, src);\n        case _Z_N_OAM:\n            return _z_n_msg_oam_copy(dst, src);\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_ENTITY_UNKNOWN);\n    }\n}\n\n_z_network_message_t *_z_n_msg_clone(const _z_network_message_t *src) {\n    _z_network_message_t *dst = (_z_network_message_t *)z_malloc(sizeof(_z_network_message_t));\n    if (dst != NULL) {\n        _z_n_msg_copy(dst, src);\n    }\n    return dst;\n}\n"
  },
  {
    "path": "src/protocol/definitions/transport.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nvoid _z_s_msg_scout_clear(_z_s_msg_scout_t *msg) {\n    // Nothing to do\n    _ZP_UNUSED(msg);\n}\n\n/*------------------ Locators Field ------------------*/\nvoid _z_locators_clear(_z_locator_array_t *ls) { _z_locator_array_clear(ls); }\n\nvoid _z_s_msg_hello_clear(_z_s_msg_hello_t *msg) { _z_locators_clear(&msg->_locators); }\n\nvoid _z_t_msg_join_clear(_z_t_msg_join_t *msg) {\n    // Nothing to do\n    _ZP_UNUSED(msg);\n}\n\nvoid _z_t_msg_init_clear(_z_t_msg_init_t *msg) { _z_slice_clear(&msg->_cookie); }\n\nvoid _z_t_msg_open_clear(_z_t_msg_open_t *msg) { _z_slice_clear(&msg->_cookie); }\n\nvoid _z_t_msg_close_clear(_z_t_msg_close_t *msg) { _ZP_UNUSED(msg); }\n\nvoid _z_t_msg_keep_alive_clear(_z_t_msg_keep_alive_t *msg) { _ZP_UNUSED(msg); }\n\nvoid _z_t_msg_frame_clear(_z_t_msg_frame_t *msg) {\n    if (msg->_payload != NULL) {\n        _z_zbuf_reset(msg->_payload);\n    }\n}\n\nvoid _z_t_msg_fragment_clear(_z_t_msg_fragment_t *msg) { _z_slice_clear(&msg->_payload); }\n\nvoid _z_t_msg_clear(_z_transport_message_t *msg) {\n    uint8_t mid = _Z_MID(msg->_header);\n    switch (mid) {\n        case _Z_MID_T_JOIN: {\n            _z_t_msg_join_clear(&msg->_body._join);\n        } break;\n\n        case _Z_MID_T_INIT: {\n            _z_t_msg_init_clear(&msg->_body._init);\n        } break;\n\n        case _Z_MID_T_OPEN: {\n            _z_t_msg_open_clear(&msg->_body._open);\n        } break;\n\n        case _Z_MID_T_CLOSE: {\n            _z_t_msg_close_clear(&msg->_body._close);\n        } break;\n\n        case _Z_MID_T_KEEP_ALIVE: {\n            _z_t_msg_keep_alive_clear(&msg->_body._keep_alive);\n        } break;\n\n        case _Z_MID_T_FRAME: {\n            _z_t_msg_frame_clear(&msg->_body._frame);\n        } break;\n\n        case _Z_MID_T_FRAGMENT: {\n            _z_t_msg_fragment_clear(&msg->_body._fragment);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to clear transport message with unknown ID(%d)\", mid);\n        } break;\n    }\n}\n\nz_reliability_t _z_t_msg_get_reliability(_z_transport_message_t *msg) {\n    if (_Z_HAS_FLAG(msg->_header, _Z_FLAG_T_FRAME_R)) {\n        return Z_RELIABILITY_RELIABLE;\n    }\n    return Z_RELIABILITY_BEST_EFFORT;\n}\n\n/*------------------ Join Message ------------------*/\n_z_transport_message_t _z_t_msg_make_join(z_whatami_t whatami, _z_zint_t lease, _z_id_t zid,\n                                          _z_conduit_sn_list_t next_sn) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_JOIN;\n\n    msg._body._join._version = Z_PROTO_VERSION;\n    msg._body._join._whatami = whatami;\n    msg._body._join._lease = lease;\n    msg._body._join._seq_num_res = Z_SN_RESOLUTION;\n    msg._body._join._req_id_res = Z_REQ_RESOLUTION;\n    msg._body._join._batch_size = Z_BATCH_MULTICAST_SIZE;\n    msg._body._join._next_sn = next_sn;\n    msg._body._join._zid = zid;\n#if Z_FEATURE_FRAGMENTATION == 1\n    msg._body._join._patch = _Z_CURRENT_PATCH;\n#endif\n\n    if ((lease % 1000) == 0) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_JOIN_T);\n    }\n\n    if ((Z_BATCH_MULTICAST_SIZE != _Z_DEFAULT_MULTICAST_BATCH_SIZE) ||\n        (Z_SN_RESOLUTION != _Z_DEFAULT_RESOLUTION_SIZE) || (Z_REQ_RESOLUTION != _Z_DEFAULT_RESOLUTION_SIZE)) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_JOIN_S);\n    }\n\n#if Z_FEATURE_FRAGMENTATION == 1\n    bool has_patch = msg._body._join._patch != _Z_NO_PATCH;\n#else\n    bool has_patch = false;\n#endif\n    if (next_sn._is_qos || has_patch) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_Z);\n    }\n\n    return msg;\n}\n\n/*------------------ Init Message ------------------*/\n_z_transport_message_t _z_t_msg_make_init_syn(z_whatami_t whatami, _z_id_t zid) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_INIT;\n\n    msg._body._init._version = Z_PROTO_VERSION;\n    msg._body._init._whatami = whatami;\n    msg._body._init._zid = zid;\n    msg._body._init._seq_num_res = Z_SN_RESOLUTION;\n    msg._body._init._req_id_res = Z_REQ_RESOLUTION;\n    msg._body._init._batch_size = Z_BATCH_UNICAST_SIZE;\n    _z_slice_reset(&msg._body._init._cookie);\n#if Z_FEATURE_FRAGMENTATION == 1\n    msg._body._init._patch = _Z_CURRENT_PATCH;\n#endif\n\n    if ((msg._body._init._batch_size != _Z_DEFAULT_UNICAST_BATCH_SIZE) ||\n        (msg._body._init._seq_num_res != _Z_DEFAULT_RESOLUTION_SIZE) ||\n        (msg._body._init._req_id_res != _Z_DEFAULT_RESOLUTION_SIZE)) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_INIT_S);\n    }\n\n#if Z_FEATURE_FRAGMENTATION == 1\n    if (msg._body._init._patch != _Z_NO_PATCH) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_Z);\n    }\n#endif\n\n    return msg;\n}\n\n_z_transport_message_t _z_t_msg_make_init_ack(z_whatami_t whatami, _z_id_t zid, _z_slice_t cookie) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_INIT;\n    _Z_SET_FLAG(msg._header, _Z_FLAG_T_INIT_A);\n\n    msg._body._init._version = Z_PROTO_VERSION;\n    msg._body._init._whatami = whatami;\n    msg._body._init._zid = zid;\n    msg._body._init._seq_num_res = Z_SN_RESOLUTION;\n    msg._body._init._req_id_res = Z_REQ_RESOLUTION;\n    msg._body._init._batch_size = Z_BATCH_UNICAST_SIZE;\n    msg._body._init._cookie = cookie;\n#if Z_FEATURE_FRAGMENTATION == 1\n    msg._body._init._patch = _Z_CURRENT_PATCH;\n#endif\n\n    if ((msg._body._init._batch_size != _Z_DEFAULT_UNICAST_BATCH_SIZE) ||\n        (msg._body._init._seq_num_res != _Z_DEFAULT_RESOLUTION_SIZE) ||\n        (msg._body._init._req_id_res != _Z_DEFAULT_RESOLUTION_SIZE)) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_INIT_S);\n    }\n\n#if Z_FEATURE_FRAGMENTATION == 1\n    if (msg._body._init._patch != _Z_NO_PATCH) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_Z);\n    }\n#endif\n    return msg;\n}\n\n/*------------------ Open Message ------------------*/\n_z_transport_message_t _z_t_msg_make_open_syn(_z_zint_t lease, _z_zint_t initial_sn, _z_slice_t cookie) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_OPEN;\n\n    msg._body._open._lease = lease;\n    msg._body._open._initial_sn = initial_sn;\n    msg._body._open._cookie = cookie;\n\n    if ((lease % 1000) == 0) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_OPEN_T);\n    }\n\n    return msg;\n}\n\n_z_transport_message_t _z_t_msg_make_open_ack(_z_zint_t lease, _z_zint_t initial_sn) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_OPEN;\n    _Z_SET_FLAG(msg._header, _Z_FLAG_T_OPEN_A);\n\n    msg._body._open._lease = lease;\n    msg._body._open._initial_sn = initial_sn;\n    _z_slice_reset(&msg._body._open._cookie);\n\n    if ((lease % 1000) == 0) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_OPEN_T);\n    }\n\n    return msg;\n}\n\n/*------------------ Close Message ------------------*/\n_z_transport_message_t _z_t_msg_make_close(uint8_t reason, bool link_only) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_CLOSE;\n\n    msg._body._close._reason = reason;\n    if (link_only == false) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_CLOSE_S);\n    }\n\n    return msg;\n}\n\n/*------------------ Keep Alive Message ------------------*/\n_z_transport_message_t _z_t_msg_make_keep_alive(void) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_KEEP_ALIVE;\n\n    return msg;\n}\n\n_z_transport_message_t _z_t_msg_make_frame(_z_zint_t sn, _z_zbuf_t *payload, z_reliability_t reliability) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_FRAME;\n\n    msg._body._frame._sn = sn;\n    if (reliability == Z_RELIABILITY_RELIABLE) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_FRAME_R);\n    }\n    msg._body._frame._payload = payload;\n    return msg;\n}\n\n/*------------------ Frame Message ------------------*/\n_z_transport_message_t _z_t_msg_make_frame_header(_z_zint_t sn, z_reliability_t reliability) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_FRAME;\n\n    msg._body._frame._sn = sn;\n    if (reliability == Z_RELIABILITY_RELIABLE) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_FRAME_R);\n    }\n    msg._body._frame._payload = NULL;\n    return msg;\n}\n\n/*------------------ Fragment Message ------------------*/\n_z_transport_message_t _z_t_msg_make_fragment_header(_z_zint_t sn, z_reliability_t reliability, bool is_last,\n                                                     bool first, bool drop) {\n    return _z_t_msg_make_fragment(sn, _z_slice_null(), reliability, is_last, first, drop);\n}\n_z_transport_message_t _z_t_msg_make_fragment(_z_zint_t sn, _z_slice_t payload, z_reliability_t reliability,\n                                              bool is_last, bool first, bool drop) {\n    _z_transport_message_t msg;\n    msg._header = _Z_MID_T_FRAGMENT;\n    if (is_last == false) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_FRAGMENT_M);\n    }\n    if (reliability == Z_RELIABILITY_RELIABLE) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_FRAGMENT_R);\n    }\n\n    msg._body._fragment._sn = sn;\n    msg._body._fragment._payload = payload;\n    if (first || drop) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_Z);\n    }\n    msg._body._fragment.first = first;\n    msg._body._fragment.drop = drop;\n\n    return msg;\n}\n\nvoid _z_t_msg_copy_fragment(_z_t_msg_fragment_t *clone, _z_t_msg_fragment_t *msg) {\n    clone->_payload = msg->_payload;\n    _z_slice_copy(&clone->_payload, &msg->_payload);\n    clone->first = msg->first;\n    clone->drop = msg->drop;\n}\n\nvoid _z_t_msg_copy_join(_z_t_msg_join_t *clone, _z_t_msg_join_t *msg) {\n    clone->_version = msg->_version;\n    clone->_whatami = msg->_whatami;\n    clone->_lease = msg->_lease;\n    clone->_seq_num_res = msg->_seq_num_res;\n    clone->_req_id_res = msg->_req_id_res;\n    clone->_batch_size = msg->_batch_size;\n    clone->_next_sn = msg->_next_sn;\n#if Z_FEATURE_FRAGMENTATION == 1\n    clone->_patch = msg->_patch;\n#endif\n    memcpy(clone->_zid.id, msg->_zid.id, 16);\n}\n\nvoid _z_t_msg_copy_init(_z_t_msg_init_t *clone, _z_t_msg_init_t *msg) {\n    clone->_version = msg->_version;\n    clone->_whatami = msg->_whatami;\n    clone->_seq_num_res = msg->_seq_num_res;\n    clone->_req_id_res = msg->_req_id_res;\n    clone->_batch_size = msg->_batch_size;\n    memcpy(clone->_zid.id, msg->_zid.id, 16);\n    if (!_z_slice_is_empty(&msg->_cookie)) {\n        _z_slice_copy(&clone->_cookie, &msg->_cookie);\n    }\n#if Z_FEATURE_FRAGMENTATION == 1\n    clone->_patch = msg->_patch;\n#endif\n}\n\nvoid _z_t_msg_copy_open(_z_t_msg_open_t *clone, _z_t_msg_open_t *msg) {\n    clone->_lease = msg->_lease;\n    clone->_initial_sn = msg->_initial_sn;\n    if (!_z_slice_is_empty(&msg->_cookie)) {\n        _z_slice_copy(&clone->_cookie, &msg->_cookie);\n    }\n}\n\nvoid _z_t_msg_copy_close(_z_t_msg_close_t *clone, _z_t_msg_close_t *msg) { clone->_reason = msg->_reason; }\n\nvoid _z_t_msg_copy_keep_alive(_z_t_msg_keep_alive_t *clone, _z_t_msg_keep_alive_t *msg) {\n    (void)(clone);\n    (void)(msg);\n}\n\nvoid _z_t_msg_copy_frame(_z_t_msg_frame_t *clone, _z_t_msg_frame_t *msg) {\n    clone->_sn = msg->_sn;\n    if ((msg->_payload != NULL) && (clone->_payload != NULL)) {\n        _z_zbuf_copy(clone->_payload, msg->_payload);\n    }\n}\n\n/*------------------ Transport Message ------------------*/\nvoid _z_t_msg_copy(_z_transport_message_t *clone, _z_transport_message_t *msg) {\n    clone->_header = msg->_header;\n\n    uint8_t mid = _Z_MID(msg->_header);\n    switch (mid) {\n        case _Z_MID_T_JOIN: {\n            _z_t_msg_copy_join(&clone->_body._join, &msg->_body._join);\n        } break;\n\n        case _Z_MID_T_INIT: {\n            _z_t_msg_copy_init(&clone->_body._init, &msg->_body._init);\n        } break;\n\n        case _Z_MID_T_OPEN: {\n            _z_t_msg_copy_open(&clone->_body._open, &msg->_body._open);\n        } break;\n\n        case _Z_MID_T_CLOSE: {\n            _z_t_msg_copy_close(&clone->_body._close, &msg->_body._close);\n        } break;\n\n        case _Z_MID_T_KEEP_ALIVE: {\n            _z_t_msg_copy_keep_alive(&clone->_body._keep_alive, &msg->_body._keep_alive);\n        } break;\n\n        case _Z_MID_T_FRAME: {\n            _z_t_msg_copy_frame(&clone->_body._frame, &msg->_body._frame);\n        } break;\n\n        case _Z_MID_T_FRAGMENT: {\n            _z_t_msg_copy_fragment(&clone->_body._fragment, &msg->_body._fragment);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to copy transport message with unknown ID(%d)\", mid);\n        } break;\n    }\n}\n\nvoid _z_s_msg_clear(_z_scouting_message_t *msg) {\n    uint8_t mid = _Z_MID(msg->_header);\n    switch (mid) {\n        case _Z_MID_SCOUT: {\n            _z_s_msg_scout_clear(&msg->_body._scout);\n        } break;\n\n        case _Z_MID_HELLO: {\n            _z_s_msg_hello_clear(&msg->_body._hello);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to clear session message with unknown ID(%d)\", mid);\n        } break;\n    }\n}\n\n/*=============================*/\n/*     Transport Messages      */\n/*=============================*/\n/*------------------ Scout Message ------------------*/\n_z_scouting_message_t _z_s_msg_make_scout(z_what_t what, _z_id_t zid) {\n    _z_scouting_message_t msg;\n    msg._header = _Z_MID_SCOUT;\n\n    msg._body._scout._version = Z_PROTO_VERSION;\n    msg._body._scout._what = what;\n    msg._body._scout._zid = zid;\n\n    return msg;\n}\n\n/*------------------ Hello Message ------------------*/\n_z_scouting_message_t _z_s_msg_make_hello(z_whatami_t whatami, _z_id_t zid, _z_locator_array_t locators) {\n    _z_scouting_message_t msg;\n    msg._header = _Z_MID_HELLO;\n\n    msg._body._hello._version = Z_PROTO_VERSION;\n    msg._body._hello._whatami = whatami;\n    msg._body._hello._zid = zid;\n    msg._body._hello._locators = locators;\n\n    if (_z_locator_array_is_empty(&locators) == false) {\n        _Z_SET_FLAG(msg._header, _Z_FLAG_T_HELLO_L);\n    }\n\n    return msg;\n}\n\nvoid _z_s_msg_copy_scout(_z_s_msg_scout_t *clone, _z_s_msg_scout_t *msg) {\n    clone->_what = msg->_what;\n    clone->_version = msg->_version;\n    memcpy(clone->_zid.id, msg->_zid.id, 16);\n}\n\nvoid _z_s_msg_copy_hello(_z_s_msg_hello_t *clone, _z_s_msg_hello_t *msg) {\n    _z_locator_array_copy(&clone->_locators, &msg->_locators);\n    memcpy(clone->_zid.id, msg->_zid.id, 16);\n    clone->_whatami = msg->_whatami;\n}\n\n/*------------------ Scouting Message ------------------*/\nvoid _z_s_msg_copy(_z_scouting_message_t *clone, _z_scouting_message_t *msg) {\n    clone->_header = msg->_header;\n\n    uint8_t mid = _Z_MID(msg->_header);\n    switch (mid) {\n        case _Z_MID_SCOUT: {\n            _z_s_msg_copy_scout(&clone->_body._scout, &msg->_body._scout);\n        } break;\n\n        case _Z_MID_HELLO: {\n            _z_s_msg_copy_hello(&clone->_body._hello, &msg->_body._hello);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to copy session message with unknown ID(%d)\", mid);\n        } break;\n    }\n}\n"
  },
  {
    "path": "src/protocol/ext.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/ext.h\"\n\n#include <stdint.h>\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n_z_msg_ext_t _z_msg_ext_make_unit(uint8_t id) {\n    _z_msg_ext_t ext;\n\n    ext._header = id & _Z_EXT_ID_MASK;\n    ext._header |= _Z_MSG_EXT_ENC_UNIT;\n\n    return ext;\n}\n\nvoid _z_msg_ext_clear_unit(_z_msg_ext_unit_t *ext) { (void)(ext); }\n\nvoid _z_msg_ext_copy_unit(_z_msg_ext_unit_t *clone, const _z_msg_ext_unit_t *ext) {\n    (void)(clone);\n    (void)(ext);\n}\n\n_z_msg_ext_t _z_msg_ext_make_zint(uint8_t id, _z_zint_t zid) {\n    _z_msg_ext_t ext;\n\n    ext._header = id & _Z_EXT_ID_MASK;\n    ext._header |= _Z_MSG_EXT_ENC_ZINT;\n\n    ext._body._zint._val = zid;\n\n    return ext;\n}\n\nvoid _z_msg_ext_clear_zint(_z_msg_ext_zint_t *ext) { (void)(ext); }\n\nvoid _z_msg_ext_copy_zint(_z_msg_ext_zint_t *clone, const _z_msg_ext_zint_t *ext) { clone->_val = ext->_val; }\n\n_z_msg_ext_t _z_msg_ext_make_zbuf(uint8_t id, _z_slice_t zbuf) {\n    _z_msg_ext_t ext;\n\n    ext._header = id & _Z_EXT_ID_MASK;\n    ext._header |= _Z_MSG_EXT_ENC_ZBUF;\n\n    ext._body._zbuf._val = _z_slice_steal(&zbuf);\n\n    return ext;\n}\n\nvoid _z_msg_ext_clear_zbuf(_z_msg_ext_zbuf_t *ext) { _z_slice_clear(&ext->_val); }\n\nvoid _z_msg_ext_copy_zbuf(_z_msg_ext_zbuf_t *clone, const _z_msg_ext_zbuf_t *ext) {\n    _z_slice_copy(&clone->_val, &ext->_val);\n}\n\nvoid _z_msg_ext_copy(_z_msg_ext_t *clone, const _z_msg_ext_t *ext) {\n    clone->_header = ext->_header;\n\n    uint8_t enc = _Z_EXT_ENC(clone->_header);\n    switch (enc) {\n        case _Z_MSG_EXT_ENC_UNIT: {\n            _z_msg_ext_copy_unit(&clone->_body._unit, &ext->_body._unit);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZINT: {\n            _z_msg_ext_copy_zint(&clone->_body._zint, &ext->_body._zint);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZBUF: {\n            _z_msg_ext_copy_zbuf(&clone->_body._zbuf, &ext->_body._zbuf);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to copy message extension with unknown encoding(%d)\", enc);\n        } break;\n    }\n}\n\nvoid _z_msg_ext_clear(_z_msg_ext_t *ext) {\n    uint8_t enc = _Z_EXT_ENC(ext->_header);\n    switch (enc) {\n        case _Z_MSG_EXT_ENC_UNIT: {\n            _z_msg_ext_clear_unit(&ext->_body._unit);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZINT: {\n            _z_msg_ext_clear_zint(&ext->_body._zint);\n        } break;\n\n        case _Z_MSG_EXT_ENC_ZBUF: {\n            _z_msg_ext_clear_zbuf(&ext->_body._zbuf);\n        } break;\n\n        default: {\n            _Z_INFO(\"WARNING: Trying to free message extension with unknown encoding(%d)\", enc);\n        } break;\n    }\n}\n"
  },
  {
    "path": "src/protocol/iobuf.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ IOSli ------------------*/\n_z_iosli_t _z_iosli_wrap(const uint8_t *buf, size_t length, size_t r_pos, size_t w_pos) {\n    assert((r_pos <= w_pos) && (w_pos <= length));\n    _z_iosli_t ios;\n    ios._r_pos = r_pos;\n    ios._w_pos = w_pos;\n    ios._capacity = length;\n    ios._is_alloc = false;\n    ios._buf = (uint8_t *)buf;\n    return ios;\n}\n\n_z_iosli_t _z_iosli_steal(_z_iosli_t *ios) {\n    _z_iosli_t new_ios = *ios;\n    *ios = _z_iosli_null();\n    return new_ios;\n}\n\nvoid __z_iosli_init(_z_iosli_t *ios, size_t capacity) {\n    ios->_r_pos = 0;\n    ios->_w_pos = 0;\n    ios->_capacity = capacity;\n    ios->_is_alloc = true;\n    ios->_buf = (uint8_t *)z_malloc(capacity);\n    if (ios->_buf == NULL) {\n        ios->_capacity = 0;\n        ios->_is_alloc = false;\n    }\n}\n\n_z_iosli_t _z_iosli_make(size_t capacity) {\n    _z_iosli_t ios;\n    __z_iosli_init(&ios, capacity);\n    return ios;\n}\n\n_z_iosli_t *_z_iosli_new(size_t capacity) {\n    _z_iosli_t *pios = (_z_iosli_t *)z_malloc(sizeof(_z_iosli_t));\n    if (pios != NULL) {\n        __z_iosli_init(pios, capacity);\n    }\n    return pios;\n}\n\n_z_slice_t _z_iosli_to_bytes(const _z_iosli_t *ios) {\n    _z_slice_t a;\n    a.len = _z_iosli_readable(ios);\n    a.start = _z_cptr_u8_offset(ios->_buf, (ptrdiff_t)ios->_r_pos);\n    return a;\n}\n\nvoid _z_iosli_clear(_z_iosli_t *ios) {\n    if ((ios->_is_alloc) && (ios->_buf != NULL)) {\n        z_free(ios->_buf);\n        ios->_buf = NULL;\n    }\n}\n\nvoid _z_iosli_free(_z_iosli_t **ios) {\n    _z_iosli_t *ptr = *ios;\n\n    if (ptr != NULL) {\n        _z_iosli_clear(ptr);\n\n        z_free(ptr);\n        *ios = NULL;\n    }\n}\n\nvoid _z_iosli_copy(_z_iosli_t *dst, const _z_iosli_t *src) {\n    dst->_r_pos = src->_r_pos;\n    dst->_w_pos = src->_w_pos;\n    dst->_capacity = src->_capacity;\n    dst->_is_alloc = src->_is_alloc;\n    if (dst->_is_alloc) {\n        dst->_buf = (uint8_t *)z_malloc(src->_capacity);\n        if (dst->_buf != NULL) {\n            (void)memcpy(dst->_buf, src->_buf, src->_capacity);\n        }\n    } else {\n        dst->_buf = src->_buf;\n    }\n}\n\n_z_iosli_t *_z_iosli_clone(const _z_iosli_t *src) {\n    _z_iosli_t *dst = (_z_iosli_t *)z_malloc(_z_iosli_size(src));\n    if (dst != NULL) {\n        _z_iosli_copy(dst, src);\n    }\n    return dst;\n}\n\n/*------------------ ZBuf ------------------*/\n_z_zbuf_t _z_zbuf_make(size_t capacity) {\n    _z_zbuf_t zbf = _z_zbuf_null();\n    zbf._ios = _z_iosli_make(capacity);\n    if (_z_zbuf_capacity(&zbf) == 0) {\n        return zbf;\n    }\n    _z_slice_t s = _z_slice_from_buf_custom_deleter(zbf._ios._buf, zbf._ios._capacity, _z_delete_context_default());\n    zbf._slice = _z_slice_simple_rc_new_from_val(&s);\n    if (_z_slice_simple_rc_is_null(&zbf._slice)) {\n        _Z_ERROR(\"slice rc creation failed\");\n        _z_iosli_clear(&zbf._ios);\n    }\n    zbf._ios._is_alloc = false;\n    return zbf;\n}\n\n_z_zbuf_t _z_zbuf_view(_z_zbuf_t *zbf, size_t length) {\n    assert(_z_iosli_readable(&zbf->_ios) >= length);\n    _z_zbuf_t v;\n    v._ios = _z_iosli_wrap(_z_zbuf_get_rptr(zbf), length, 0, length);\n    v._slice = zbf->_slice;\n    return v;\n}\n\n_z_zbuf_t _z_slice_as_zbuf(_z_slice_t slice) {\n    return (_z_zbuf_t){\n        ._ios = {._buf = (uint8_t *)slice.start,  // Safety: `_z_zbuf_t` is an immutable buffer\n                 ._is_alloc = false,\n                 ._capacity = slice.len,\n                 ._r_pos = 0,\n                 ._w_pos = slice.len},\n        ._slice = _z_slice_simple_rc_null(),\n    };\n}\n\nvoid _z_zbuf_copy_bytes(_z_zbuf_t *dst, const _z_zbuf_t *src) { _z_iosli_copy_bytes(&dst->_ios, &src->_ios); }\n\nvoid _z_zbuf_copy(_z_zbuf_t *dst, const _z_zbuf_t *src) {\n    dst->_slice = _z_slice_simple_rc_clone(&src->_slice);\n    _z_iosli_copy_bytes(&dst->_ios, &src->_ios);\n}\n\nvoid _z_zbuf_read_bytes(_z_zbuf_t *zbf, uint8_t *dest, size_t offset, size_t length) {\n    _z_iosli_read_bytes(&zbf->_ios, dest, offset, length);\n}\n\nvoid _z_zbuf_clear(_z_zbuf_t *zbf) {\n    _z_iosli_clear(&zbf->_ios);\n    _z_slice_simple_rc_drop(&zbf->_slice);\n}\n\nvoid _z_zbuf_compact(_z_zbuf_t *zbf) {\n    if ((zbf->_ios._r_pos != 0) || (zbf->_ios._w_pos != 0)) {\n        size_t len = _z_iosli_readable(&zbf->_ios);\n        (void)memmove(zbf->_ios._buf, _z_zbuf_get_rptr(zbf), len);\n        _z_zbuf_set_rpos(zbf, 0);\n        _z_zbuf_set_wpos(zbf, len);\n    }\n}\n\nvoid _z_zbuf_free(_z_zbuf_t **zbf) {\n    _z_zbuf_t *ptr = *zbf;\n\n    if (ptr != NULL) {\n        _z_iosli_clear(&ptr->_ios);\n\n        z_free(ptr);\n        *zbf = NULL;\n    }\n}\n\n/*------------------ WBuf ------------------*/\nstatic z_result_t _z_wbuf_add_iosli(_z_wbuf_t *wbf, _z_iosli_t *ios) {\n    z_result_t res = _z_iosli_svec_append(&wbf->_ioss, ios, false);\n    if (res == _Z_RES_OK) {\n        wbf->_w_idx++;\n    }\n    return res;\n}\n\nsize_t _z_wbuf_len_iosli(const _z_wbuf_t *wbf) { return _z_iosli_svec_len(&wbf->_ioss); }\n\n_z_wbuf_t _z_wbuf_make(size_t capacity, bool is_expandable) {\n    _z_wbuf_t wbf;\n    if (is_expandable) {\n        wbf._ioss = _z_iosli_svec_make(5);  // Dfrag buffer layout: misc, attachment, misc, payload, misc\n        wbf._expansion_step = capacity;\n    } else {\n        wbf._ioss = _z_iosli_svec_make(1);\n        wbf._expansion_step = 0;\n    }\n    _z_iosli_t ios = _z_iosli_make(capacity);\n    z_result_t res = _z_iosli_svec_append(&wbf._ioss, &ios, false);\n    if (res != _Z_RES_OK) {\n        _z_iosli_clear(&ios);\n    }\n    wbf._w_idx = 0;\n    wbf._r_idx = 0;\n    return wbf;\n}\n\nsize_t _z_wbuf_capacity(const _z_wbuf_t *wbf) {\n    size_t cap = 0;\n    for (size_t i = 0; i < _z_wbuf_len_iosli(wbf); i++) {\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, i);\n        cap = cap + ios->_capacity;\n    }\n    return cap;\n}\n\nsize_t _z_wbuf_len(const _z_wbuf_t *wbf) {\n    size_t len = 0;\n    for (size_t i = wbf->_r_idx; (i < _z_wbuf_len_iosli(wbf)) && (i <= wbf->_w_idx); i++) {\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, i);\n        len = len + _z_iosli_readable(ios);\n    }\n    return len;\n}\n\nsize_t _z_wbuf_space_left(const _z_wbuf_t *wbf) {\n    _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n    return _z_iosli_writable(ios);\n}\n\nuint8_t _z_wbuf_read(_z_wbuf_t *wbf) {\n    uint8_t ret = 0;\n\n    do {\n        assert(wbf->_r_idx <= wbf->_w_idx);\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, wbf->_r_idx);\n        size_t readable = _z_iosli_readable(ios);\n        if (readable > (size_t)0) {\n            ret = _z_iosli_read(ios);\n            break;\n        } else {\n            wbf->_r_idx = wbf->_r_idx + (size_t)1;\n        }\n    } while (1);\n\n    return ret;\n}\n\nvoid _z_wbuf_read_bytes(_z_wbuf_t *wbf, uint8_t *dest, size_t offset, size_t length) {\n    size_t loffset = offset;\n    size_t llength = length;\n\n    do {\n        assert(wbf->_r_idx <= wbf->_w_idx);\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, wbf->_r_idx);\n        size_t readable = _z_iosli_readable(ios);\n        if (readable > (size_t)0) {\n            size_t to_read = (readable <= llength) ? readable : llength;\n            _z_iosli_read_bytes(ios, dest, loffset, to_read);\n            loffset = loffset + to_read;\n            llength = llength - to_read;\n        } else {\n            wbf->_r_idx = wbf->_r_idx + 1;\n        }\n    } while (llength > (size_t)0);\n}\n\nuint8_t _z_wbuf_get(const _z_wbuf_t *wbf, size_t pos) {\n    size_t current = pos;\n    size_t i = 0;\n\n    _z_iosli_t *ios;\n    do {\n        assert(i < _z_iosli_svec_len(&wbf->_ioss));\n        ios = _z_wbuf_get_iosli(wbf, i);\n        if (current < ios->_capacity) {\n            break;\n        } else {\n            current = current - ios->_capacity;\n        }\n\n        i = i + (size_t)1;\n    } while (1);\n\n    return _z_iosli_get(ios, current);\n}\n\nz_result_t _z_wbuf_write(_z_wbuf_t *wbf, uint8_t b) {\n    _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n    if (!_z_iosli_can_write(ios)) {\n        // Check if we need to allocate new buffer\n        if (wbf->_ioss._len <= wbf->_w_idx + 1) {\n            if (wbf->_expansion_step == 0) {\n                _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NO_SPACE);\n            }\n            _z_iosli_t tmp = _z_iosli_make(wbf->_expansion_step);\n            _Z_CLEAN_RETURN_IF_ERR(_z_wbuf_add_iosli(wbf, &tmp), _z_iosli_clear(&tmp));\n        } else {\n            wbf->_w_idx++;\n        }\n        ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n    }\n    _z_iosli_write(ios, b);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_wbuf_write_bytes(_z_wbuf_t *wbf, const uint8_t *bs, size_t offset, size_t length) {\n    _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n    size_t writable = _z_iosli_writable(ios);\n    if (writable >= length) {\n        _z_iosli_write_bytes(ios, bs, offset, length);\n    } else if (wbf->_expansion_step != 0) {\n        // Expand buffer to write all the data\n        size_t llength = length;\n        size_t loffset = offset;\n        _z_iosli_write_bytes(ios, bs, loffset, writable);\n        llength -= writable;\n        loffset += writable;\n        while (llength > (size_t)0) {\n            _z_iosli_t tmp = _z_iosli_make(wbf->_expansion_step);\n            _Z_CLEAN_RETURN_IF_ERR(_z_wbuf_add_iosli(wbf, &tmp), _z_iosli_clear(&tmp));\n            ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n\n            writable = _z_iosli_writable(ios);\n            if (llength < writable) {\n                writable = llength;\n            }\n            _z_iosli_write_bytes(ios, bs, loffset, writable);\n            llength -= writable;\n            loffset += writable;\n        }\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NO_SPACE);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_wbuf_wrap_bytes(_z_wbuf_t *wbf, const uint8_t *bs, size_t offset, size_t length) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n    size_t curr_space = _z_iosli_writable(ios);\n    // Block writing on this ioslice\n    ios->_capacity = ios->_w_pos;\n    // Wrap data\n    _z_iosli_t wios = _z_iosli_wrap(bs, length, offset, offset + length);\n    _Z_CLEAN_RETURN_IF_ERR(_z_wbuf_add_iosli(wbf, &wios), _z_iosli_clear(&wios));\n    // If svec expanded, ios is invalid, refresh pointer.\n    ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx - 1);\n    // Set remaining space as a new ioslice\n    wios = _z_iosli_wrap(_z_ptr_u8_offset(ios->_buf, (ptrdiff_t)ios->_w_pos), curr_space, 0, 0);\n    _Z_CLEAN_RETURN_IF_ERR(_z_wbuf_add_iosli(wbf, &wios), _z_iosli_clear(&wios));\n    return ret;\n}\n\nvoid _z_wbuf_put(_z_wbuf_t *wbf, uint8_t b, size_t pos) {\n    size_t current = pos;\n    size_t i = 0;\n    _z_iosli_t *ios;\n    do {\n        assert(i < _z_iosli_svec_len(&wbf->_ioss));\n        ios = _z_wbuf_get_iosli(wbf, i);\n        if (current < ios->_capacity) {\n            break;\n        } else {\n            current = current - ios->_capacity;\n        }\n\n        i = i + (size_t)1;\n    } while (1);\n\n    _z_iosli_put(ios, b, current);\n}\n\nsize_t _z_wbuf_get_rpos(const _z_wbuf_t *wbf) {\n    size_t pos = 0;\n    _z_iosli_t *ios;\n    for (size_t i = 0; i < wbf->_r_idx; i++) {\n        ios = _z_wbuf_get_iosli(wbf, i);\n        pos = pos + ios->_capacity;\n    }\n    ios = _z_wbuf_get_iosli(wbf, wbf->_r_idx);\n    pos = pos + ios->_r_pos;\n    return pos;\n}\n\nsize_t _z_wbuf_get_wpos(const _z_wbuf_t *wbf) {\n    size_t pos = 0;\n    _z_iosli_t *ios;\n    for (size_t i = 0; i < wbf->_w_idx; i++) {\n        ios = _z_wbuf_get_iosli(wbf, i);\n        pos = pos + ios->_capacity;\n    }\n    ios = _z_wbuf_get_iosli(wbf, wbf->_w_idx);\n    pos = pos + ios->_w_pos;\n    return pos;\n}\n\nvoid _z_wbuf_set_rpos(_z_wbuf_t *wbf, size_t pos) {\n    size_t current = pos;\n    size_t i = 0;\n    do {\n        assert(i <= wbf->_w_idx);\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, i);\n        if (current <= ios->_w_pos) {\n            wbf->_r_idx = i;\n            ios->_r_pos = current;\n            break;\n        }\n\n        ios->_r_pos = ios->_w_pos;\n        current = current - ios->_capacity;\n\n        i = i + (size_t)1;\n    } while (1);\n}\n\nvoid _z_wbuf_set_wpos(_z_wbuf_t *wbf, size_t pos) {\n    size_t current = pos;\n    size_t i = 0;\n    do {\n        assert(i <= _z_iosli_svec_len(&wbf->_ioss));\n\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, i);\n        if ((current <= ios->_capacity) && (current >= ios->_r_pos)) {\n            wbf->_w_idx = i;\n            ios->_w_pos = current;\n            break;\n        }\n\n        ios->_w_pos = ios->_capacity;\n        current = current - ios->_capacity;\n\n        i = i + (size_t)1;\n    } while (1);\n}\n\n_z_zbuf_t _z_wbuf_to_zbuf(const _z_wbuf_t *wbf) {\n    size_t len = _z_wbuf_len(wbf);\n    _z_zbuf_t zbf = _z_zbuf_make(len);\n    for (size_t i = wbf->_r_idx; i <= wbf->_w_idx; i++) {\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, i);\n        _z_iosli_write_bytes(&zbf._ios, ios->_buf, ios->_r_pos, _z_iosli_readable(ios));\n    }\n    return zbf;\n}\n\n_z_zbuf_t _z_wbuf_moved_as_zbuf(_z_wbuf_t *wbf) {\n    // Can only move single buffer wbuf\n    assert(_z_iosli_svec_len(&wbf->_ioss) == 1);\n\n    _z_zbuf_t zbf = _z_zbuf_null();\n    _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, 0);\n    zbf._ios = _z_iosli_steal(ios);\n    _z_slice_t s = _z_slice_from_buf_custom_deleter(zbf._ios._buf, zbf._ios._capacity, _z_delete_context_default());\n    zbf._slice = _z_slice_simple_rc_new_from_val(&s);\n    if (_z_slice_simple_rc_is_null(&zbf._slice)) {\n        _Z_ERROR(\"slice rc creation failed\");\n    }\n    zbf._ios._is_alloc = false;\n    _z_wbuf_clear(wbf);\n    return zbf;\n}\n\nz_result_t _z_wbuf_siphon(_z_wbuf_t *dst, _z_wbuf_t *src, size_t length) {\n    z_result_t ret = _Z_RES_OK;\n    size_t llength = length;\n    _z_iosli_t *wios = _z_wbuf_get_iosli(dst, dst->_w_idx);\n    size_t writable = _z_iosli_writable(wios);\n\n    // Siphon does not work (as of now) on expandable dst buffers\n    if (writable >= length) {\n        do {\n            assert(src->_r_idx <= src->_w_idx);\n            _z_iosli_t *rios = _z_wbuf_get_iosli(src, src->_r_idx);\n            size_t readable = _z_iosli_readable(rios);\n            if (readable > (size_t)0) {\n                size_t to_read = (readable <= llength) ? readable : llength;\n                uint8_t *w_pos = _z_ptr_u8_offset(wios->_buf, (ptrdiff_t)wios->_w_pos);\n                (void)memcpy(w_pos, rios->_buf + rios->_r_pos, to_read);\n                rios->_r_pos = rios->_r_pos + to_read;\n                llength -= to_read;\n                wios->_w_pos += to_read;\n            } else {\n                src->_r_idx++;\n            }\n        } while (llength > (size_t)0);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NO_SPACE);\n        ret = _Z_ERR_TRANSPORT_NO_SPACE;\n    }\n    return ret;\n}\n\nvoid _z_wbuf_copy(_z_wbuf_t *dst, const _z_wbuf_t *src) {\n    dst->_r_idx = src->_r_idx;\n    dst->_w_idx = src->_w_idx;\n    dst->_expansion_step = src->_expansion_step;\n    _z_iosli_svec_copy(&dst->_ioss, &src->_ioss, false);\n}\n\nvoid _z_wbuf_reset(_z_wbuf_t *wbf) {\n    wbf->_r_idx = 0;\n    wbf->_w_idx = 0;\n\n    // Reset to default iosli allocation\n    for (size_t i = 0; i < _z_iosli_svec_len(&wbf->_ioss); i++) {\n        _z_iosli_t *ios = _z_wbuf_get_iosli(wbf, i);\n        if (!ios->_is_alloc) {\n            _z_iosli_svec_remove(&wbf->_ioss, i, false);\n        } else {\n            _z_iosli_reset(ios);\n        }\n    }\n}\n\nvoid _z_wbuf_clear(_z_wbuf_t *wbf) {\n    _z_iosli_svec_clear(&wbf->_ioss);\n    *wbf = _z_wbuf_null();\n}\n\nvoid _z_wbuf_free(_z_wbuf_t **wbf) {\n    _z_wbuf_t *ptr = *wbf;\n\n    if (ptr != NULL) {\n        _z_wbuf_clear(ptr);\n\n        z_free(ptr);\n        *wbf = NULL;\n    }\n}\n"
  },
  {
    "path": "src/runtime/background_executor.c",
    "content": "#include \"zenoh-pico/runtime/background_executor.h\"\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct _z_background_executor_inner_t {\n    _z_executor_t _executor;\n    _z_mutex_t _mutex;\n    _z_condvar_t _condvar;\n    _z_atomic_size_t _waiters;\n    size_t _thread_idx;\n    _z_atomic_bool_t _started;\n    _z_atomic_size_t _thread_checkers;\n    _z_task_t _task;\n} _z_background_executor_inner_t;\n\nstatic inline bool _is_called_from_executor(_z_background_executor_inner_t *be) {\n    bool res = false;\n    _z_atomic_size_fetch_add(&be->_thread_checkers, 1, _z_memory_order_acq_rel);\n    if (_z_atomic_bool_load(&be->_started, _z_memory_order_acquire)) {  // only check task id if executor is started\n        _z_task_id_t current_task_id = _z_task_current_id();\n        _z_task_id_t executor_task_id = _z_task_get_id(&be->_task);\n        res = _z_task_id_equal(&current_task_id, &executor_task_id);\n    }\n    _z_atomic_size_fetch_sub(&be->_thread_checkers, 1, _z_memory_order_acq_rel);\n    return res;\n}\n\nz_result_t _z_background_executor_inner_suspend_and_lock(_z_background_executor_inner_t *be,\n                                                         bool check_executor_thread) {\n    if (check_executor_thread && _is_called_from_executor(be)) {\n        return _Z_ERR_INVALID;  // suspend cannot be called from executor thread\n    }\n    _z_atomic_size_fetch_add(&be->_waiters, 1, _z_memory_order_acq_rel);\n    return _z_mutex_lock(&be->_mutex);\n}\n\nz_result_t _z_background_executor_inner_suspend(_z_background_executor_inner_t *be) {\n    _Z_RETURN_IF_ERR(_z_background_executor_inner_suspend_and_lock(be, true));\n    return _z_mutex_unlock(&be->_mutex);\n}\n\nz_result_t _z_background_executor_inner_unlock_and_resume(_z_background_executor_inner_t *be) {\n    _z_atomic_size_fetch_sub(&be->_waiters, 1, _z_memory_order_acq_rel);\n    _Z_CLEAN_RETURN_IF_ERR(_z_condvar_signal_all(&be->_condvar), _z_mutex_unlock(&be->_mutex));\n    return _z_mutex_unlock(&be->_mutex);\n}\n\nz_result_t _z_background_executor_inner_resume(_z_background_executor_inner_t *be) {\n    if (_is_called_from_executor(be)) {\n        return _Z_ERR_INVALID;  // resume cannot be called from executor thread\n    }\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&be->_mutex));\n    return _z_background_executor_inner_unlock_and_resume(be);\n}\n\nz_result_t _z_background_executor_inner_run_forever(_z_background_executor_inner_t *be, size_t thread_idx) {\n    _Z_RETURN_IF_ERR(_z_mutex_lock(&be->_mutex));\n    while (true) {\n        while (_z_atomic_size_load(&be->_waiters, _z_memory_order_acquire) > 0) {\n            if (thread_idx <\n                be->_thread_idx) {  // extra check to allow to stop executor thread even if there are waiters\n                break;              // stop requested, exit the loop and end the thread\n            }\n            // if there are waiters, sleep until they are resumed\n            _Z_CLEAN_RETURN_IF_ERR(_z_condvar_wait(&be->_condvar, &be->_mutex), _z_mutex_unlock(&be->_mutex));\n        }\n        if (thread_idx < be->_thread_idx) {\n            break;  // stop requested, exit the loop and end the thread\n        }\n        _z_executor_spin_result_t res = _z_executor_spin(&be->_executor);\n        if (res.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS) {  // no pending tasks, sleep until next task is added\n            _Z_CLEAN_RETURN_IF_ERR(_z_condvar_wait(&be->_condvar, &be->_mutex), _z_mutex_unlock(&be->_mutex));\n        } else if (res.status == _Z_EXECUTOR_SPIN_RESULT_SHOULD_WAIT) {  // we have pending timed tasks but they are not\n                                                                         // ready yet, sleep until the next one is ready\n            z_clock_t now = z_clock_now();\n            if (zp_clock_elapsed_ms_since(&res.next_wake_up_time, &now) > 1) {  // sleep until next task is ready\n                z_result_t wait_result = _z_condvar_wait_until(&be->_condvar, &be->_mutex, &res.next_wake_up_time);\n                if (wait_result != Z_ETIMEDOUT && wait_result != _Z_RES_OK) {\n                    return _z_mutex_unlock(&be->_mutex);\n                }\n            }\n        }\n    }\n    return _z_mutex_unlock(&be->_mutex);\n}\n\nz_result_t _z_background_executor_inner_spawn(_z_background_executor_inner_t *be, _z_fut_t *fut,\n                                              _z_fut_handle_t *handle) {\n    z_result_t ret = _Z_RES_OK;\n    if (_is_called_from_executor(be)) {\n        *handle = _z_executor_spawn(&be->_executor, fut);\n    } else {\n        _Z_RETURN_IF_ERR(_z_background_executor_inner_suspend_and_lock(be, false));\n        *handle = _z_executor_spawn(&be->_executor, fut);\n        ret = _z_background_executor_inner_unlock_and_resume(be);\n    }\n    return _z_fut_handle_is_null(*handle) ? _Z_ERR_SYSTEM_OUT_OF_MEMORY : ret;\n}\n\nz_result_t _z_background_executor_inner_get_fut_status(_z_background_executor_inner_t *be,\n                                                       const _z_fut_handle_t *handle, _z_fut_status_t *status_out) {\n    if (_is_called_from_executor(be)) {\n        *status_out = _z_executor_get_fut_status(&be->_executor, handle);\n        return _Z_RES_OK;\n    } else {\n        _Z_RETURN_IF_ERR(_z_background_executor_inner_suspend_and_lock(be, false));\n        *status_out = _z_executor_get_fut_status(&be->_executor, handle);\n        return _z_background_executor_inner_unlock_and_resume(be);\n    }\n}\n\nz_result_t _z_background_executor_inner_cancel_fut(_z_background_executor_inner_t *be, const _z_fut_handle_t *handle) {\n    if (_is_called_from_executor(be)) {\n        return _z_executor_cancel_fut(&be->_executor, handle) ? _Z_RES_OK : _Z_ERR_INVALID;\n    } else {\n        _Z_RETURN_IF_ERR(_z_background_executor_inner_suspend_and_lock(be, false));\n        _z_executor_cancel_fut(&be->_executor, handle);\n        return _z_background_executor_inner_unlock_and_resume(be);\n    }\n}\n\nz_result_t _z_background_executor_inner_stop(_z_background_executor_inner_t *be) {\n    _Z_RETURN_IF_ERR(_z_background_executor_inner_suspend_and_lock(be, true));\n    // executor is now suspended, so no API can be called from its thread\n    // in addition we are holding the mutex, so no other thread can request to stop or start the executor\n    if (!_z_atomic_bool_load(&be->_started, _z_memory_order_acquire)) {\n        return _z_background_executor_inner_unlock_and_resume(be);\n    }\n    while (_z_atomic_size_load(&be->_thread_checkers, _z_memory_order_acquire) > 0) {\n        z_sleep_us(10);\n    }\n    be->_thread_idx++;\n    _z_atomic_bool_store(&be->_started, false, _z_memory_order_release);\n    _z_task_t task_to_join = be->_task;\n    z_result_t ret = _z_background_executor_inner_unlock_and_resume(be);\n    // after resume the executor thread will proceed to stop directly without trying to execute any tasks\n    _Z_SET_IF_OK(ret, _z_task_join(&task_to_join));\n    return ret;\n}\n\nvoid _z_background_executor_inner_clear(_z_background_executor_inner_t *be) {\n    _z_background_executor_inner_stop(be);\n    _z_executor_destroy(&be->_executor);\n    _z_condvar_drop(&be->_condvar);\n    _z_mutex_drop(&be->_mutex);\n}\n\nvoid *_z_background_executor_inner_task_fn(void *arg) {\n    _z_background_executor_inner_t *be = (_z_background_executor_inner_t *)arg;\n    size_t thread_idx = be->_thread_idx;  // this is safe since _z_background_executor_inner_start holds the mutex until\n                                          // be->_started is set to true.\n    _z_atomic_bool_store(&be->_started, true, _z_memory_order_release);\n    _z_background_executor_inner_run_forever(be, thread_idx);\n    return NULL;\n}\n\nz_result_t _z_background_executor_inner_init_deferred(_z_background_executor_inner_t *be) {\n    _Z_RETURN_IF_ERR(_z_mutex_init(&be->_mutex));\n    _Z_CLEAN_RETURN_IF_ERR(_z_condvar_init(&be->_condvar), _z_mutex_drop(&be->_mutex));\n    _z_executor_init(&be->_executor);\n    _z_atomic_size_init(&be->_waiters, 0);\n    _z_atomic_size_init(&be->_thread_checkers, 0);\n    be->_thread_idx = 0;\n    _z_atomic_bool_init(&be->_started, false);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_background_executor_inner_start(_z_background_executor_inner_t *be, z_task_attr_t *task_attr) {\n    _Z_RETURN_IF_ERR(_z_background_executor_inner_suspend_and_lock(be, true));\n    if (_z_atomic_bool_load(&be->_started, _z_memory_order_acquire)) {\n        // already started, just return\n        return _z_background_executor_inner_unlock_and_resume(be);\n    }\n    z_result_t ret = _z_task_init(&be->_task, task_attr, _z_background_executor_inner_task_fn, be);\n    if (ret == _Z_RES_OK) {\n        while (!_z_atomic_bool_load(&be->_started, _z_memory_order_acquire)) {\n            z_sleep_us(10);  // wait until the executor thread sets the state to started\n        }\n    }\n    // resume the executor thread to let it proceed to run\n    z_result_t ret2 = _z_background_executor_inner_unlock_and_resume(be);\n    _Z_SET_IF_OK(ret, ret2);\n    return ret;\n}\n\nz_result_t _z_background_executor_init_deferred(_z_background_executor_t *be) {\n    be->_inner = _z_background_executor_inner_rc_null();\n    _z_background_executor_inner_t *inner =\n        (_z_background_executor_inner_t *)z_malloc(sizeof(_z_background_executor_inner_t));\n    if (!inner) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    if (_z_background_executor_inner_init_deferred(inner) != _Z_RES_OK) {\n        z_free(inner);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    be->_inner = _z_background_executor_inner_rc_new(inner);\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        _z_background_executor_inner_clear(inner);\n        z_free(inner);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_background_executor_start(_z_background_executor_t *be, z_task_attr_t *task_attr) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_start(_Z_RC_IN_VAL(&be->_inner), task_attr);\n}\n\nz_result_t _z_background_executor_stop(_z_background_executor_t *be) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_stop(_Z_RC_IN_VAL(&be->_inner));\n}\n\nz_result_t _z_background_executor_init(_z_background_executor_t *be, z_task_attr_t *task_attr) {\n    _Z_RETURN_IF_ERR(_z_background_executor_init_deferred(be));\n    _Z_CLEAN_RETURN_IF_ERR(_z_background_executor_start(be, task_attr), _z_background_executor_destroy(be));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_background_executor_spawn(_z_background_executor_t *be, _z_fut_t *fut, _z_fut_handle_t *handle_out) {\n    _z_fut_handle_t dummy_handle;\n    if (handle_out == NULL) {\n        handle_out = &dummy_handle;\n    }\n    *handle_out = _z_fut_handle_null();\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_spawn(_Z_RC_IN_VAL(&be->_inner), fut, handle_out);\n}\n\nz_result_t _z_background_executor_suspend(_z_background_executor_t *be) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_suspend(_Z_RC_IN_VAL(&be->_inner));\n}\n\nz_result_t _z_background_executor_resume(_z_background_executor_t *be) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_resume(_Z_RC_IN_VAL(&be->_inner));\n}\n\nvoid _z_background_executor_destroy(_z_background_executor_t *be) { _z_background_executor_inner_rc_drop(&be->_inner); }\n\nz_result_t _z_background_executor_get_fut_status(_z_background_executor_t *be, const _z_fut_handle_t *handle,\n                                                 _z_fut_status_t *status_out) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_get_fut_status(_Z_RC_IN_VAL(&be->_inner), handle, status_out);\n}\n\nz_result_t _z_background_executor_cancel_fut(_z_background_executor_t *be, const _z_fut_handle_t *handle) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_background_executor_inner_cancel_fut(_Z_RC_IN_VAL(&be->_inner), handle);\n}\n\nz_result_t _z_background_executor_clone(_z_background_executor_t *dst, const _z_background_executor_t *src) {\n    if (_Z_RC_IS_NULL(&src->_inner)) {\n        dst->_inner = _z_background_executor_inner_rc_null();\n        return _Z_RES_OK;\n    }\n    dst->_inner = _z_background_executor_inner_rc_clone(&src->_inner);\n    if (_Z_RC_IS_NULL(&dst->_inner)) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    return _Z_RES_OK;\n}\n\nbool _z_background_executor_is_running(const _z_background_executor_t *be) {\n    if (_Z_RC_IS_NULL(&be->_inner)) {\n        return false;\n    }\n    return _z_atomic_bool_load(&_Z_RC_IN_VAL(&be->_inner)->_started, _z_memory_order_acquire);\n}\n#else\n// to prevent \"empty compilation unit\" warning when multi-threading is disabled\ntypedef int _z_background_executor_inner_t;\n#endif\n"
  },
  {
    "path": "src/runtime/executor.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/runtime/executor.h\"\n\n_z_fut_handle_t _z_executor_spawn(_z_executor_t *executor, _z_fut_t *fut) {\n    _z_fut_data_t fut_data;\n    _z_fut_move(&fut_data._fut, fut);\n    fut_data._schedule = _z_fut_schedule_running();\n    if (executor->_next_fut_id == 0) {\n        executor->_next_fut_id++;  // Skip 0 since it's reserved for null handle\n    }\n    _z_fut_data_hmap_index_t idx = _z_fut_data_hmap_insert(&executor->_tasks, &executor->_next_fut_id, &fut_data);\n    _z_fut_handle_t handle = _z_fut_handle_null();\n    if (!_z_fut_data_hmap_index_valid(idx)) {\n        return handle;\n    }\n    handle._id = executor->_next_fut_id;\n    executor->_next_fut_id++;\n    // can't fail since we have enough capacity for all tasks in the hashmap\n    _z_fut_data_hmap_index_deque_push_back(&executor->_ready_tasks, &idx);\n    return handle;\n}\n\n_z_executor_spin_result_t _z_executor_get_next_fut(_z_executor_t *executor, _z_fut_data_hmap_index_t *task_idx) {\n    _z_executor_spin_result_t result;\n    result.status = _Z_EXECUTOR_SPIN_RESULT_NO_TASKS;\n    _z_fut_data_hmap_index_t *sleeping_idx_ptr = _z_sleeping_fut_pqueue_peek(&executor->_sleeping_tasks);\n    if (sleeping_idx_ptr != NULL) {\n        z_clock_t now = z_clock_now();\n        uint64_t wake_up_time_ms = _z_fut_schedule_get_wake_up_time_ms(\n            _z_fut_data_hmap_node_at(&executor->_tasks, *sleeping_idx_ptr)->val._schedule);\n        z_clock_t wake_up_time = executor->_epoch;\n        z_clock_advance_ms(&wake_up_time, (unsigned long)wake_up_time_ms);\n        if (zp_clock_elapsed_ms_since(&now, &wake_up_time) > 0) {\n            // The sleeping task is ready to execute\n            _z_fut_data_hmap_index_t sleeping_idx;\n            _z_sleeping_fut_pqueue_pop(&executor->_sleeping_tasks, &sleeping_idx);\n            if (_z_fut_data_hmap_index_deque_pop_front(&executor->_ready_tasks, task_idx)) {\n                // We have a non-sleeping task to execute, we should re-enqueue the ready sleeping task as non-sleeping\n                // one and execute the non-sleeping task first.\n                _z_fut_data_hmap_index_deque_push_back(&executor->_ready_tasks, &sleeping_idx);\n                // Mark the sleeping task as ready since it's now\n                // re-enqueued to the ready task queue and can be executed.\n                _z_fut_data_hmap_node_at(&executor->_tasks, sleeping_idx)->val._schedule = _z_fut_schedule_ready();\n            } else {\n                // No non-sleeping task, execute the ready sleeping task directly.\n                *task_idx = sleeping_idx;\n            }\n            result.status = _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK;\n        } else if (_z_fut_data_hmap_index_deque_pop_front(&executor->_ready_tasks, task_idx)) {\n            // We have a non-sleeping task to execute\n            result.status = _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK;\n        } else {\n            // No non-sleeping task, we should wait for the sleeping task to be ready.\n            result.status = _Z_EXECUTOR_SPIN_RESULT_SHOULD_WAIT;\n            result.next_wake_up_time = wake_up_time;\n        }\n    } else if (_z_fut_data_hmap_index_deque_pop_front(&executor->_ready_tasks, task_idx)) {\n        // We have a non-sleeping task to execute\n        result.status = _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK;\n    }\n    return result;\n}\n\n_z_executor_spin_result_t _z_executor_spin(_z_executor_t *executor) {\n    _z_fut_data_hmap_index_t fut_idx;\n    _z_fut_data_t *fut_data = NULL;\n    _z_executor_spin_result_t result;\n    // Set context before spinning to make sure the sleeping task queue can access the task pool to compare the wake-up\n    // time, in case executor was moved.\n    _z_sleeping_fut_pqueue_set_ctx(&executor->_sleeping_tasks, &executor->_tasks);\n    while (true) {  // Loop until we find non-null task to execute\n        result = _z_executor_get_next_fut(executor, &fut_idx);\n        if (result.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS ||\n            result.status == _Z_EXECUTOR_SPIN_RESULT_SHOULD_WAIT) {  // No tasks to execute\n            return result;\n        }\n        fut_data = &_z_fut_data_hmap_node_at(&executor->_tasks, fut_idx)->val;\n        if (fut_data->_fut._fut_fn == NULL) {  // idle task, just skip it and check the next task.\n            _z_fut_data_hmap_remove_at(&executor->_tasks, fut_idx, NULL);  // Remove the idle task from the task pool\n            continue;\n        } else if (_z_fut_schedule_get_status(fut_data->_schedule) != _Z_FUT_STATUS_SUSPENDED) {\n            break;\n        }\n    }\n\n    _z_fut_fn_result_t fn_result = fut_data->_fut._fut_fn(fut_data->_fut._fut_arg, executor);\n    if (fn_result._status == _Z_FUT_STATUS_RUNNING) {\n        // The task is still running, we should re-enqueue it to the executor.\n        fut_data->_schedule = _z_fut_schedule_running();\n        // can't fail since we have enough capacity for all tasks in the hashmap\n        _z_fut_data_hmap_index_deque_push_back(&executor->_ready_tasks, &fut_idx);\n    } else if (fn_result._status == _Z_FUT_STATUS_SLEEPING) {\n        // The task is sleeping, we should move it to the sleeping task queue with the wake-up time.\n        fut_data->_schedule =\n            _z_fut_schedule_sleeping((uint64_t)zp_clock_elapsed_ms_since(&fn_result._wake_up_time, &executor->_epoch));\n        // can't fail since we have enough capacity for all tasks in the hashmap\n        _z_sleeping_fut_pqueue_push(&executor->_sleeping_tasks, &fut_idx);\n    } else if (fn_result._status == _Z_FUT_STATUS_READY) {\n        // The task is ready, we should destroy it to free the resource.\n        _z_fut_data_hmap_remove_at(&executor->_tasks, fut_idx, NULL);\n    } else if (fn_result._status == _Z_FUT_STATUS_SUSPENDED) {\n        // The task is suspended, we should keep it in the task pool with the suspended status, and it will be skipped\n        // in the next spin until it's resumed by external events.\n        fut_data->_schedule = _z_fut_schedule_suspended();\n    }\n    return result;\n}\n\n_z_fut_status_t _z_executor_get_fut_status(const _z_executor_t *executor, const _z_fut_handle_t *handle) {\n    if (_z_fut_handle_is_null(*handle)) {\n        return _Z_FUT_STATUS_READY;  // Invalid handle is considered as ready (i.e., not running or sleeping)\n    }\n    _z_fut_data_t *fut_data = _z_fut_data_hmap_get((_z_fut_data_hmap_t *)&executor->_tasks, &handle->_id);\n    if (fut_data == NULL) {\n        return _Z_FUT_STATUS_READY;  // If the task is not found in the task pool, it means it's already completed and\n                                     // removed, we consider it as ready (i.e., not running or sleeping)\n    }\n    return _z_fut_schedule_get_status(fut_data->_schedule);\n}\n\nbool _z_executor_cancel_fut(_z_executor_t *executor, const _z_fut_handle_t *handle) {\n    if (_z_fut_handle_is_null(*handle)) {\n        return false;\n    }\n    _z_fut_data_t *fut = _z_fut_data_hmap_get(&executor->_tasks, &handle->_id);\n    if (fut == NULL) {\n        return false;\n    }\n    // We leave the cancelled task in the NULL state, to let executor remove it while spinning,\n    // since we don't want to break the sleeping/ready task queue order by removing the cancelled task immediately.\n    _z_fut_data_destroy(fut);\n\n    return true;\n}\n\nbool _z_executor_resume_suspended_fut(_z_executor_t *executor, const _z_fut_handle_t *handle) {\n    if (_z_fut_handle_is_null(*handle)) {\n        return false;\n    }\n    _z_fut_data_hmap_index_t fut_idx = _z_fut_data_hmap_get_idx(&executor->_tasks, &handle->_id);\n    if (!_z_fut_data_hmap_index_valid(fut_idx)) {\n        return false;\n    }\n    _z_fut_data_t *fut = &_z_fut_data_hmap_node_at(&executor->_tasks, fut_idx)->val;\n    if (_z_fut_schedule_get_status(fut->_schedule) != _Z_FUT_STATUS_SUSPENDED) {\n        return false;\n    }\n    // Mark the suspended task as ready, and re-enqueue it to the ready task queue.\n    fut->_schedule = _z_fut_schedule_ready();\n    // can't fail since we have enough capacity for all tasks in the hashmap\n    _z_fut_data_hmap_index_deque_push_back(&executor->_ready_tasks, &fut_idx);\n\n    return true;\n}\n"
  },
  {
    "path": "src/session/cancellation.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/cancellation.h\"\n\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/query.h\"\n\nstatic inline void _z_cancellation_handlers_storage_clear(_z_cancellation_handlers_storage_t *storage) {\n    _z_cancellation_token_on_cancel_handler_intmap_clear(&storage->_handlers);\n    _z_sync_group_notifier_drop(&storage->_cancel_sync_notifier);\n}\n\nstatic inline void _z_cancellation_handlers_storage_remove(_z_cancellation_handlers_storage_t *storage,\n                                                           size_t handler_id) {\n    _z_cancellation_token_on_cancel_handler_intmap_remove(&storage->_handlers, handler_id);\n}\n\nvoid _z_cancellation_token_clear_all_except_mutex(_z_cancellation_token_t *ct) {\n    _z_cancellation_handlers_storage_clear(&ct->_handlers);\n    _z_sync_group_drop(&ct->_sync_group);\n}\n\nz_result_t _z_cancellation_token_on_cancel_handler_call(_z_cancellation_token_on_cancel_handler_t *handler) {\n    z_result_t ret = handler->_on_cancel != NULL ? handler->_on_cancel(handler->_arg) : _Z_RES_OK;\n    _z_cancellation_token_on_cancel_handler_drop(handler);\n    return ret;\n}\n\nstatic inline _z_cancellation_handlers_storage_t _z_cancellation_handlers_storage_null(void) {\n    _z_cancellation_handlers_storage_t storage;\n    _z_cancellation_token_on_cancel_handler_intmap_init(&storage._handlers);\n    storage._next_handler_id = 0;\n    storage._cancel_sync_notifier = _z_sync_group_notifier_null();\n    return storage;\n}\n\nz_result_t _z_cancellation_handlers_storage_add(_z_cancellation_handlers_storage_t *storage,\n                                                _z_cancellation_token_on_cancel_handler_t *handler,\n                                                size_t *out_handler_id) {\n    _z_cancellation_token_on_cancel_handler_t *handler_on_heap =\n        (_z_cancellation_token_on_cancel_handler_t *)z_malloc(sizeof(_z_cancellation_token_on_cancel_handler_t));\n    if (handler_on_heap == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    _z_cancellation_token_on_cancel_handler_t *ret = _z_cancellation_token_on_cancel_handler_intmap_insert(\n        &storage->_handlers, storage->_next_handler_id, handler_on_heap);\n    if (ret == NULL) {\n        z_free(handler_on_heap);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    _z_cancellation_token_on_cancel_handler_move(ret, handler);\n    *out_handler_id = storage->_next_handler_id++;\n    return _Z_RES_OK;\n}\n\nvoid _z_cancellation_handlers_storage_cancel(_z_cancellation_handlers_storage_t *storage, z_result_t *ret) {\n    *ret = _Z_RES_OK;\n    _z_cancellation_token_on_cancel_handler_intmap_iterator_t it =\n        _z_cancellation_token_on_cancel_handler_intmap_iterator_make(&storage->_handlers);\n    while (*ret == _Z_RES_OK && _z_cancellation_token_on_cancel_handler_intmap_iterator_next(&it)) {\n        _z_cancellation_token_on_cancel_handler_t *h =\n            _z_cancellation_token_on_cancel_handler_intmap_iterator_value(&it);\n        *ret = _z_cancellation_token_on_cancel_handler_call(h);\n    }\n    // drop sync handler in the end to ensure that all concurrent cancel calls return only once all work is done\n    _z_cancellation_handlers_storage_clear(storage);\n}\n\nz_result_t _z_cancellation_token_drop_cancel_sync_notifier(void *arg) {\n    _z_sync_group_notifier_t *n = (_z_sync_group_notifier_t *)arg;\n    _z_sync_group_notifier_drop(n);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_cancellation_token_create(_z_cancellation_token_t *ct) {\n    z_result_t ret = _Z_RES_OK;\n    ct->_cancel_result = _Z_RES_OK;\n    ct->_handlers = _z_cancellation_handlers_storage_null();\n    ret = _z_sync_group_create(&ct->_sync_group);\n    // add notifier to synchronize cancel operation\n    _Z_SET_IF_OK(ret, _z_sync_group_create_notifier(&ct->_sync_group, &ct->_handlers._cancel_sync_notifier));\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_cancellation_token_clear_all_except_mutex(ct));\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_CLEAN_RETURN_IF_ERR(_z_mutex_init(&ct->_mutex), _z_sync_group_drop(&ct->_sync_group);\n                           _z_cancellation_token_clear_all_except_mutex(ct));\n#endif\n    return _Z_RES_OK;\n}\n\nstatic inline z_result_t _z_cancellation_token_lock(const _z_cancellation_token_t *ct) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    return _z_mutex_lock((_z_mutex_t *)&ct->_mutex);\n#else\n    _ZP_UNUSED(ct);\n    return _Z_RES_OK;\n#endif\n}\n\nstatic inline z_result_t _z_cancellation_token_unlock(const _z_cancellation_token_t *ct) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    return _z_mutex_unlock((_z_mutex_t *)&ct->_mutex);\n#else\n    _ZP_UNUSED(ct);\n    return _Z_RES_OK;\n#endif\n}\n\nstatic inline bool _z_unsafe_cancellation_token_has_started_cancel(const _z_cancellation_token_t *ct) {\n    return !_z_sync_group_notifier_check(&ct->_handlers._cancel_sync_notifier);\n}\n\nbool _z_cancellation_token_is_cancelled(const _z_cancellation_token_t *ct) {\n    return _z_sync_group_is_closed(&ct->_sync_group);\n}\n\nz_result_t _z_cancellation_token_call_handlers(_z_cancellation_token_t *ct) {\n    bool set_cancel_result = false;\n    if (_z_cancellation_token_lock(ct) != _Z_RES_OK) {\n        return _Z_ERR_SYSTEM_GENERIC;\n    }\n    set_cancel_result = _z_sync_group_notifier_check(&ct->_handlers._cancel_sync_notifier);\n    _z_cancellation_handlers_storage_t s = ct->_handlers;\n    ct->_handlers = _z_cancellation_handlers_storage_null();\n    _z_cancellation_token_unlock(ct);\n    if (set_cancel_result) {\n        _z_cancellation_handlers_storage_cancel(&s, &ct->_cancel_result);\n        if (ct->_cancel_result != _Z_RES_OK) {\n            _z_sync_group_close(&ct->_sync_group);\n        }\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_cancellation_token_cancel(_z_cancellation_token_t *ct) {\n    _Z_RETURN_IF_ERR(_z_cancellation_token_call_handlers(ct));\n    _z_sync_group_wait(&ct->_sync_group);\n    return ct->_cancel_result;\n}\n\nz_result_t _z_cancellation_token_cancel_with_timeout(_z_cancellation_token_t *ct, uint32_t timeout_ms) {\n    z_clock_t deadline = z_clock_now();\n    z_clock_advance_ms(&deadline, timeout_ms);\n\n    _Z_RETURN_IF_ERR(_z_cancellation_token_call_handlers(ct));\n    if (_z_sync_group_wait_deadline(&ct->_sync_group, &deadline) == Z_ETIMEDOUT) {\n        return Z_ETIMEDOUT;\n    } else {\n        return ct->_cancel_result;\n    }\n}\n\nvoid _z_cancellation_token_clear(_z_cancellation_token_t *ct) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    _z_mutex_drop(&ct->_mutex);\n#endif\n    _z_cancellation_token_clear_all_except_mutex(ct);\n}\n\nz_result_t _z_cancellation_token_add_on_cancel_handler(_z_cancellation_token_t *ct,\n                                                       _z_cancellation_token_on_cancel_handler_t *handler,\n                                                       size_t *out_handler_id) {\n    _Z_RETURN_IF_ERR(_z_cancellation_token_lock(ct));\n    z_result_t ret = _z_unsafe_cancellation_token_has_started_cancel(ct)\n                         ? Z_ERR_CANCELLED\n                         : _z_cancellation_handlers_storage_add(&ct->_handlers, handler, out_handler_id);\n    _z_cancellation_token_unlock(ct);\n    return ret;\n}\n\nz_result_t _z_cancellation_token_remove_on_cancel_handler(_z_cancellation_token_t *ct, size_t handler_id) {\n    _Z_RETURN_IF_ERR(_z_cancellation_token_lock(ct));\n    _z_cancellation_handlers_storage_remove(&ct->_handlers, handler_id);\n    _z_cancellation_token_unlock(ct);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_cancellation_token_get_notifier(_z_cancellation_token_t *ct, _z_sync_group_notifier_t *notifier) {\n    z_result_t ret = _z_sync_group_create_notifier(&ct->_sync_group, notifier);\n    return ret == Z_SYNC_GROUP_CLOSED ? Z_ERR_CANCELLED : ret;\n}\n"
  },
  {
    "path": "src/session/interest.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/multicast/lease.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nstatic z_result_t _z_interest_send_decl_resource(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                                 const _z_keyexpr_t *restr_key) {\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_resource_slist_t *res_list = _z_resource_slist_clone(zn->_local_resources);\n    _z_session_mutex_unlock(zn);\n    _z_resource_slist_t *xs = res_list;\n    while (xs != NULL) {\n        _z_resource_t *res = _z_resource_slist_value(xs);\n        // Check if key is concerned\n        if (restr_key == NULL || _z_keyexpr_intersects(restr_key, &res->_key)) {\n            // Build the declare message to send on the wire\n            _z_wireexpr_t wireexpr = _z_keyexpr_alias_to_wire(&res->_key);\n            _z_declaration_t declaration = _z_make_decl_keyexpr(res->_id, &wireexpr);\n            _z_network_message_t n_msg;\n            _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_some(interest_id));\n            z_result_t ret = _z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, peer);\n            _z_n_msg_clear(&n_msg);\n            if (ret != _Z_RES_OK) {\n                _z_resource_slist_free(&res_list);\n                _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n            }\n        }\n        xs = _z_resource_slist_next(xs);\n    }\n    _z_resource_slist_free(&res_list);\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nstatic z_result_t _z_interest_send_decl_subscriber(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                                   const _z_keyexpr_t *restr_key) {\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_subscription_rc_slist_t *sub_list = _z_subscription_rc_slist_clone(zn->_subscriptions);\n    _z_session_mutex_unlock(zn);\n    _z_subscription_rc_slist_t *xs = sub_list;\n    while (xs != NULL) {\n        _z_subscription_rc_t *sub = _z_subscription_rc_slist_value(xs);\n        // Check if key is concerned\n        if (restr_key == NULL || _z_keyexpr_intersects(restr_key, &_Z_RC_IN_VAL(sub)->_key._inner)) {\n            // Build the declare message to send on the wire\n            _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(&_Z_RC_IN_VAL(sub)->_key, zn);\n            _z_declaration_t declaration = _z_make_decl_subscriber(&wireexpr, _Z_RC_IN_VAL(sub)->_id);\n            _z_network_message_t n_msg;\n            _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_some(interest_id));\n            z_result_t ret = _z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, peer);\n            _z_n_msg_clear(&n_msg);\n            if (ret != _Z_RES_OK) {\n                _z_subscription_rc_slist_free(&sub_list);\n                _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n            }\n        }\n        xs = _z_subscription_rc_slist_next(xs);\n    }\n    _z_subscription_rc_slist_free(&sub_list);\n    return _Z_RES_OK;\n}\n#else\nstatic z_result_t _z_interest_send_decl_subscriber(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                                   const _z_keyexpr_t *restr_key) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(interest_id);\n    _ZP_UNUSED(peer);\n    _ZP_UNUSED(restr_key);\n    return _Z_RES_OK;\n}\n#endif\n\n#if Z_FEATURE_QUERYABLE == 1\nstatic z_result_t _z_interest_send_decl_queryable(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                                  const _z_keyexpr_t *restr_key) {\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_session_queryable_rc_slist_t *qle_list = _z_session_queryable_rc_slist_clone(zn->_local_queryable);\n    _z_session_mutex_unlock(zn);\n    _z_session_queryable_rc_slist_t *xs = qle_list;\n    while (xs != NULL) {\n        _z_session_queryable_rc_t *qle = _z_session_queryable_rc_slist_value(xs);\n        // Check if key is concerned\n        if (restr_key == NULL || _z_keyexpr_intersects(restr_key, &_Z_RC_IN_VAL(qle)->_key._inner)) {\n            // Build the declare message to send on the wire\n            _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(&_Z_RC_IN_VAL(qle)->_key, zn);\n            _z_declaration_t declaration = _z_make_decl_queryable(\n                &wireexpr, _Z_RC_IN_VAL(qle)->_id, _Z_RC_IN_VAL(qle)->_complete, _Z_QUERYABLE_DISTANCE_DEFAULT);\n            _z_network_message_t n_msg;\n            _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_some(interest_id));\n            z_result_t ret = _z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, peer);\n            _z_n_msg_clear(&n_msg);\n            if (ret != _Z_RES_OK) {\n                _z_session_queryable_rc_slist_free(&qle_list);\n                _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n            }\n        }\n        xs = _z_session_queryable_rc_slist_next(xs);\n    }\n    _z_session_queryable_rc_slist_free(&qle_list);\n    return _Z_RES_OK;\n}\n#else\nstatic z_result_t _z_interest_send_decl_queryable(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                                  const _z_keyexpr_t *restr_key) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(interest_id);\n    _ZP_UNUSED(peer);\n    _ZP_UNUSED(restr_key);\n    return _Z_RES_OK;\n}\n#endif\n\n#if Z_FEATURE_LIVELINESS == 1\nstatic z_result_t _z_interest_send_decl_token(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                              const _z_keyexpr_t *restr_key) {\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_declared_keyexpr_intmap_t token_list = _z_declared_keyexpr_intmap_clone(&zn->_local_tokens);\n    _z_session_mutex_unlock(zn);\n    _z_declared_keyexpr_intmap_iterator_t iter = _z_declared_keyexpr_intmap_iterator_make(&token_list);\n    while (_z_declared_keyexpr_intmap_iterator_next(&iter)) {\n        uint32_t id = (uint32_t)_z_declared_keyexpr_intmap_iterator_key(&iter);\n        // Check if key is concerned\n        if (restr_key == NULL ||\n            _z_keyexpr_intersects(restr_key, &_z_declared_keyexpr_intmap_iterator_value(&iter)->_inner)) {\n            // Build the declare message to send on the wire\n            _z_wireexpr_t wireexpr =\n                _z_declared_keyexpr_alias_to_wire(_z_declared_keyexpr_intmap_iterator_value(&iter), zn);\n            _z_declaration_t declaration = _z_make_decl_token(&wireexpr, id);\n            _z_network_message_t n_msg;\n            _z_n_msg_make_declare(&n_msg, declaration, _z_optional_id_make_some(interest_id));\n            z_result_t ret = _z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, peer);\n            _z_n_msg_clear(&n_msg);\n            if (ret != _Z_RES_OK) {\n                _z_declared_keyexpr_intmap_clear(&token_list);\n                _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n            }\n        }\n    }\n    _z_declared_keyexpr_intmap_clear(&token_list);\n    return _Z_RES_OK;\n}\n#else\nstatic z_result_t _z_interest_send_decl_token(_z_session_t *zn, uint32_t interest_id, void *peer,\n                                              const _z_keyexpr_t *restr_key) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(interest_id);\n    _ZP_UNUSED(peer);\n    _ZP_UNUSED(restr_key);\n    return _Z_RES_OK;\n}\n#endif\n\nstatic z_result_t _z_interest_send_declare_final(_z_session_t *zn, uint32_t interest_id, void *peer) {\n    _z_declaration_t decl = _z_make_decl_final();\n    _z_network_message_t n_msg;\n    _z_n_msg_make_declare(&n_msg, decl, _z_optional_id_make_some(interest_id));\n    z_result_t ret = _z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, peer);\n    _z_n_msg_clear(&n_msg);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_push_declarations_to_peer(_z_session_t *zn, void *peer) {\n    _Z_RETURN_IF_ERR(_z_interest_send_decl_resource(zn, 0, peer, NULL));\n    _Z_RETURN_IF_ERR(_z_interest_send_decl_subscriber(zn, 0, peer, NULL));\n    _Z_RETURN_IF_ERR(_z_interest_send_decl_queryable(zn, 0, peer, NULL));\n    _Z_RETURN_IF_ERR(_z_interest_send_decl_token(zn, 0, peer, NULL));\n    _Z_RETURN_IF_ERR(_z_interest_send_declare_final(zn, 0, peer));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_pull_resource_from_peers(_z_session_t *zn) {\n    // Retrieve all current resource declarations\n    uint32_t eid = _z_get_entity_id(zn);\n    uint8_t flags = _Z_INTEREST_FLAG_KEYEXPRS | _Z_INTEREST_FLAG_CURRENT;\n    // Send message on the network\n    _z_interest_t interest = _z_make_interest(NULL, eid, flags);\n    _z_network_message_t n_msg;\n    _z_n_msg_make_interest(&n_msg, interest);\n    z_result_t ret = _z_send_n_msg(zn, &n_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n    _z_n_msg_clear(&n_msg);\n    return ret;\n}\n\n#if Z_FEATURE_INTEREST == 1\nvoid _z_declare_data_clear(_z_declare_data_t *data) { _z_keyexpr_clear(&data->_key); }\nsize_t _z_declare_data_size(_z_declare_data_t *data) {\n    _ZP_UNUSED(data);\n    return sizeof(_z_declare_data_t);\n}\nvoid _z_declare_data_copy(_z_declare_data_t *dst, const _z_declare_data_t *src) {\n    dst->_id = src->_id;\n    dst->_type = src->_type;\n    dst->_peer = src->_peer;\n    _z_keyexpr_copy(&dst->_key, &src->_key);\n}\n\nbool _z_declare_data_eq(const _z_declare_data_t *left, const _z_declare_data_t *right) {\n    return ((left->_id == right->_id) && (left->_type == right->_type));\n}\n\nbool _z_session_interest_eq(const _z_session_interest_t *one, const _z_session_interest_t *two) {\n    return one->_id == two->_id;\n}\n\nvoid _z_session_interest_clear(_z_session_interest_t *intr) {\n    _z_keyexpr_clear(&intr->_key);\n    _z_void_rc_drop(&intr->_arg);\n}\n\n/*------------------ interest ------------------*/\nstatic _z_session_interest_rc_t *__z_get_interest_by_id(_z_session_interest_rc_slist_t *intrs, const _z_zint_t id) {\n    _z_session_interest_rc_t *ret = NULL;\n    _z_session_interest_rc_slist_t *xs = intrs;\n    while (xs != NULL) {\n        _z_session_interest_rc_t *intr = _z_session_interest_rc_slist_value(xs);\n        if (id == _Z_RC_IN_VAL(intr)->_id) {\n            ret = intr;\n            break;\n        }\n        xs = _z_session_interest_rc_slist_next(xs);\n    }\n    return ret;\n}\n\nstatic _z_session_interest_rc_slist_t *__z_get_interest_by_key_and_flags(_z_session_interest_rc_slist_t *intrs,\n                                                                         uint8_t flags, const _z_keyexpr_t *key,\n                                                                         _z_optional_id_t interest_id) {\n    _z_session_interest_rc_slist_t *ret = NULL;\n    _z_session_interest_rc_slist_t *xs = intrs;\n    while (xs != NULL) {\n        _z_session_interest_rc_t *intr = _z_session_interest_rc_slist_value(xs);\n        if ((_Z_RC_IN_VAL(intr)->_flags & flags) == 0) {\n            xs = _z_session_interest_rc_slist_next(xs);\n            continue;\n        }\n        // consider only interests with matching id if specified (which corresponds to CURRENT interest response)\n        // ignore 0 id, since it is the one initially used by peers for declarations propagation\n        if (interest_id.has_value && interest_id.value != 0 && interest_id.value != _Z_RC_IN_VAL(intr)->_id) {\n            xs = _z_session_interest_rc_slist_next(xs);\n            continue;\n        }\n        bool is_matching = _z_session_interest_is_aggregate(_Z_RC_IN_VAL(intr))\n                               ? _z_keyexpr_equals(&_Z_RC_IN_VAL(intr)->_key, key)\n                               : _z_keyexpr_intersects(&_Z_RC_IN_VAL(intr)->_key, key);\n\n        if (is_matching) {\n            ret = _z_session_interest_rc_slist_push_empty(ret);\n            _z_session_interest_rc_t *new_intr = _z_session_interest_rc_slist_value(ret);\n            *new_intr = _z_session_interest_rc_clone(intr);\n        }\n        xs = _z_session_interest_rc_slist_next(xs);\n    }\n    return ret;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic _z_session_interest_rc_t *__unsafe_z_get_interest_by_id(_z_session_t *zn, const _z_zint_t id) {\n    _z_session_interest_rc_slist_t *intrs = zn->_local_interests;\n    return __z_get_interest_by_id(intrs, id);\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic _z_session_interest_rc_slist_t *__unsafe_z_get_interest_by_key_and_flags(_z_session_t *zn, uint8_t flags,\n                                                                                const _z_keyexpr_t *key,\n                                                                                _z_optional_id_t interest_id) {\n    _z_session_interest_rc_slist_t *intrs = zn->_local_interests;\n    return __z_get_interest_by_key_and_flags(intrs, flags, key, interest_id);\n}\n\n_z_session_interest_rc_t *_z_get_interest_by_id(_z_session_t *zn, const _z_zint_t id) {\n    _z_session_mutex_lock(zn);\n    _z_session_interest_rc_t *intr = __unsafe_z_get_interest_by_id(zn, id);\n    _z_session_mutex_unlock(zn);\n    return intr;\n}\n\n_z_session_interest_rc_t *_z_register_interest(_z_session_t *zn, _z_session_interest_t *intr) {\n    _Z_DEBUG(\">>> Allocating interest for (%.*s)\", (int)_z_string_len(&intr->_key._keyexpr),\n             _z_string_data(&intr->_key._keyexpr));\n    _z_session_interest_rc_t *ret = NULL;\n\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to acquire session mutex for registering interest for (%.*s) - session is closed\",\n                (int)_z_string_len(&intr->_key._keyexpr), _z_string_data(&intr->_key._keyexpr));\n        return ret;\n    }\n    zn->_local_interests = _z_session_interest_rc_slist_push_empty(zn->_local_interests);\n    ret = _z_session_interest_rc_slist_value(zn->_local_interests);\n    *ret = _z_session_interest_rc_new_from_val(intr);\n    _z_session_mutex_unlock(zn);\n    return ret;\n}\n\nstatic z_result_t _unsafe_z_register_declare(_z_session_t *zn, const _z_keyexpr_t *key, uint32_t id, uint8_t type,\n                                             bool complete, _z_transport_peer_common_t *peer) {\n    zn->_remote_declares = _z_declare_data_slist_push_empty(zn->_remote_declares);\n    _z_declare_data_t *decl = _z_declare_data_slist_value(zn->_remote_declares);\n    _z_keyexpr_copy(&decl->_key, key);\n    decl->_id = id;\n    decl->_type = type;\n    decl->_complete = complete;\n    decl->_peer = peer;\n    return _Z_RES_OK;\n}\n\nstatic _z_declare_data_t *_unsafe_z_get_declare(_z_session_t *zn, uint32_t id, uint8_t type) {\n    _z_declare_data_slist_t *xs = zn->_remote_declares;\n    _z_declare_data_t comp = {._key = _z_keyexpr_null(), ._id = id, ._type = type, ._complete = false};\n    while (xs != NULL) {\n        _z_declare_data_t *decl = _z_declare_data_slist_value(xs);\n        if (_z_declare_data_eq(&comp, decl)) {\n            return decl;\n        }\n        xs = _z_declare_data_slist_next(xs);\n    }\n    return NULL;\n}\n\nstatic z_result_t _unsafe_z_unregister_declare(_z_session_t *zn, uint32_t id, uint8_t type) {\n    _z_declare_data_t decl = {._key = _z_keyexpr_null(), ._id = id, ._type = type, ._complete = false};\n    zn->_remote_declares = _z_declare_data_slist_drop_first_filter(zn->_remote_declares, _z_declare_data_eq, &decl);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_declares(_z_session_t *zn, const _z_n_msg_declare_t *decl,\n                                        _z_transport_peer_common_t *peer) {\n    const _z_wireexpr_t *decl_key = NULL;\n    _z_interest_msg_t msg;\n    uint8_t flags = 0;\n    uint8_t decl_type = 0;\n    msg.is_complete = false;\n\n    switch (decl->_decl._tag) {\n        case _Z_DECL_SUBSCRIBER:\n            msg.type = _Z_INTEREST_MSG_TYPE_DECL_SUBSCRIBER;\n            msg.id = decl->_decl._body._decl_subscriber._id;\n            decl_key = &decl->_decl._body._decl_subscriber._keyexpr;\n            decl_type = _Z_DECLARE_TYPE_SUBSCRIBER;\n            flags = _Z_INTEREST_FLAG_SUBSCRIBERS;\n            break;\n        case _Z_DECL_QUERYABLE:\n            msg.type = _Z_INTEREST_MSG_TYPE_DECL_QUERYABLE;\n            msg.id = decl->_decl._body._decl_queryable._id;\n            decl_key = &decl->_decl._body._decl_queryable._keyexpr;\n            decl_type = _Z_DECLARE_TYPE_QUERYABLE;\n            flags = _Z_INTEREST_FLAG_QUERYABLES;\n            msg.is_complete = decl->_decl._body._decl_queryable._ext_queryable_info._complete;\n            break;\n        case _Z_DECL_TOKEN:\n            msg.type = _Z_INTEREST_MSG_TYPE_DECL_TOKEN;\n            msg.id = decl->_decl._body._decl_token._id;\n            decl_key = &decl->_decl._body._decl_token._keyexpr;\n            decl_type = _Z_DECLARE_TYPE_TOKEN;\n            flags = _Z_INTEREST_FLAG_TOKENS;\n            break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_ZENOH_DECLARATION_UNKNOWN);\n    }\n    // Retrieve key\n    _z_keyexpr_t key;\n    if (_z_get_keyexpr_from_wireexpr(zn, &key, decl_key, peer, true) != _Z_RES_OK) {\n        _Z_ERROR_RETURN(_Z_ERR_KEYEXPR_UNKNOWN);\n    }\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&key));\n    msg.key = &key;\n    // NOTE: it is possible that it is a redeclare of an existing entity - so we might need to update it\n    _z_declare_data_t *prev_decl = _unsafe_z_get_declare(zn, msg.id, decl_type);\n    if (prev_decl != NULL) {  // possible change in queryable completness\n        prev_decl->_complete = msg.is_complete;\n    } else {\n        // register new declare\n        _unsafe_z_register_declare(zn, &key, msg.id, decl_type, msg.is_complete, peer);\n    }\n    // Retrieve interests\n    _z_session_interest_rc_slist_t *intrs =\n        __unsafe_z_get_interest_by_key_and_flags(zn, flags, &key, decl->_interest_id);\n    _z_session_mutex_unlock(zn);\n    // update interests with new value\n    _z_session_interest_rc_slist_t *xs = intrs;\n    while (xs != NULL) {\n        _z_session_interest_rc_t *intr = _z_session_interest_rc_slist_value(xs);\n        if (_Z_RC_IN_VAL(intr)->_callback != NULL) {\n            _Z_RC_IN_VAL(intr)->_callback(&msg, peer, _Z_RC_IN_VAL(&_Z_RC_IN_VAL(intr)->_arg));\n        }\n        xs = _z_session_interest_rc_slist_next(xs);\n    }\n    // Clean up\n    _z_keyexpr_clear(&key);\n    _z_session_interest_rc_slist_free(&intrs);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_undeclares(_z_session_t *zn, const _z_declaration_t *decl,\n                                          _z_transport_peer_common_t *peer) {\n    _z_interest_msg_t msg = {0};\n    uint8_t flags = 0;\n    uint8_t decl_type = 0;\n    switch (decl->_tag) {\n        case _Z_UNDECL_SUBSCRIBER:\n            msg.type = _Z_INTEREST_MSG_TYPE_UNDECL_SUBSCRIBER;\n            msg.id = decl->_body._undecl_subscriber._id;\n            decl_type = _Z_DECLARE_TYPE_SUBSCRIBER;\n            flags = _Z_INTEREST_FLAG_SUBSCRIBERS;\n            break;\n        case _Z_UNDECL_QUERYABLE:\n            msg.type = _Z_INTEREST_MSG_TYPE_UNDECL_QUERYABLE;\n            msg.id = decl->_body._undecl_queryable._id;\n            decl_type = _Z_DECLARE_TYPE_QUERYABLE;\n            flags = _Z_INTEREST_FLAG_QUERYABLES;\n            break;\n        case _Z_UNDECL_TOKEN:\n            msg.type = _Z_INTEREST_MSG_TYPE_UNDECL_TOKEN;\n            msg.id = decl->_body._undecl_token._id;\n            decl_type = _Z_DECLARE_TYPE_TOKEN;\n            flags = _Z_INTEREST_FLAG_TOKENS;\n            break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_MESSAGE_ZENOH_DECLARATION_UNKNOWN);\n    }\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    // Retrieve declare data\n    _z_declare_data_t *prev_decl = _unsafe_z_get_declare(zn, msg.id, decl_type);\n    if (prev_decl == NULL) {\n        _z_session_mutex_unlock(zn);\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_ZENOH_DECLARATION_UNKNOWN);\n    }\n    _z_session_interest_rc_slist_t *intrs =\n        __unsafe_z_get_interest_by_key_and_flags(zn, flags, &prev_decl->_key, _z_optional_id_make_none());\n    // Remove declare\n    _unsafe_z_unregister_declare(zn, msg.id, decl_type);\n    _z_session_mutex_unlock(zn);\n\n    // Parse session_interest list\n    _z_session_interest_rc_slist_t *xs = intrs;\n    while (xs != NULL) {\n        _z_session_interest_rc_t *intr = _z_session_interest_rc_slist_value(xs);\n        if (_Z_RC_IN_VAL(intr)->_callback != NULL) {\n            _Z_RC_IN_VAL(intr)->_callback(&msg, peer, _Z_RC_IN_VAL(&_Z_RC_IN_VAL(intr)->_arg));\n        }\n        xs = _z_session_interest_rc_slist_next(xs);\n    }\n    // Clean up\n    _z_session_interest_rc_slist_free(&intrs);\n    return _Z_RES_OK;\n}\n\nvoid _z_unregister_interest(_z_session_t *zn, _z_session_interest_rc_t *intr) {\n    _z_session_mutex_lock(zn);\n    zn->_local_interests =\n        _z_session_interest_rc_slist_drop_first_filter(zn->_local_interests, _z_session_interest_rc_eq, intr);\n    _z_session_mutex_unlock(zn);\n}\n\nvoid _z_interest_init(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n    zn->_local_interests = NULL;\n    zn->_remote_declares = NULL;\n    _z_session_mutex_unlock(zn);\n}\n\nvoid _z_flush_interest(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n    _z_session_interest_rc_slist_free(&zn->_local_interests);\n    _z_declare_data_slist_free(&zn->_remote_declares);\n    _z_session_mutex_unlock(zn);\n}\n\nz_result_t _z_interest_process_declare_final(_z_session_t *zn, uint32_t id, _z_transport_peer_common_t *peer) {\n    _z_interest_msg_t msg = {.type = _Z_INTEREST_MSG_TYPE_FINAL, .id = id};\n    // Retrieve interest\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_session_interest_rc_t *intr = __unsafe_z_get_interest_by_id(zn, id);\n    _z_session_mutex_unlock(zn);\n    if (intr == NULL) {\n        return _Z_RES_OK;\n    }\n    // Trigger callback\n    if (_Z_RC_IN_VAL(intr)->_callback != NULL) {\n        _Z_RC_IN_VAL(intr)->_callback(&msg, peer, _Z_RC_IN_VAL(&_Z_RC_IN_VAL(intr)->_arg));\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_interest_final(_z_session_t *zn, uint32_t id) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(id);\n    // TODO: Update future masks\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_interest(_z_session_t *zn, const _z_wireexpr_t *wireexpr, uint32_t id, uint8_t flags,\n                                        _z_transport_peer_common_t *peer) {\n    // Check transport type\n    if (zn->_tp._type == _Z_TRANSPORT_UNICAST_TYPE) {\n        return _Z_RES_OK;  // Nothing to do on unicast\n    }\n    // Push a join in case it's a new node\n    _Z_RETURN_IF_ERR(_zp_multicast_send_join(&zn->_tp._transport._multicast));\n    _z_keyexpr_t restr_key = _z_keyexpr_null();\n    if (_Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_RESTRICTED)) {\n        _Z_RETURN_IF_ERR(_z_get_keyexpr_from_wireexpr(zn, &restr_key, wireexpr, peer, true));\n    }\n    _z_keyexpr_t *restr_key_opt = _z_keyexpr_check(&restr_key) ? &restr_key : NULL;\n    z_result_t ret = _Z_RES_OK;\n    // Current flags process\n    if (_Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_CURRENT)) {\n        // Send all declare\n        if (ret == _Z_RES_OK && _Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_KEYEXPRS)) {\n            _Z_DEBUG(\"Sending declare resources\");\n            ret = _z_interest_send_decl_resource(zn, id, NULL, restr_key_opt);\n        }\n        if (ret == _Z_RES_OK && _Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_SUBSCRIBERS)) {\n            _Z_DEBUG(\"Sending declare subscribers\");\n            ret = _z_interest_send_decl_subscriber(zn, id, NULL, restr_key_opt);\n        }\n        if (ret == _Z_RES_OK && _Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_QUERYABLES)) {\n            _Z_DEBUG(\"Sending declare queryables\");\n            ret = _z_interest_send_decl_queryable(zn, id, NULL, restr_key_opt);\n        }\n        if (ret == _Z_RES_OK && _Z_HAS_FLAG(flags, _Z_INTEREST_FLAG_TOKENS)) {\n            _Z_DEBUG(\"Sending declare tokens\");\n            ret = _z_interest_send_decl_token(zn, id, NULL, restr_key_opt);\n        }\n        // Send final declare\n        _Z_SET_IF_OK(ret, _z_interest_send_declare_final(zn, id, NULL));\n    }\n    _z_keyexpr_clear(&restr_key);\n    return ret;\n}\n\nvoid _z_interest_peer_disconnected(_z_session_t *zn, _z_transport_peer_common_t *peer) {\n    // Clone session interest list\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        return;\n    }\n    _z_session_interest_rc_slist_t *intrs = _z_session_interest_rc_slist_clone(zn->_local_interests);\n    _z_session_mutex_unlock(zn);\n\n    // Parse session_interest list\n    _z_interest_msg_t msg = {.id = 0, .type = _Z_INTEREST_MSG_TYPE_CONNECTION_DROPPED};\n    _z_session_interest_rc_slist_t *xs = intrs;\n    while (xs != NULL) {\n        _z_session_interest_rc_t *intr = _z_session_interest_rc_slist_value(xs);\n        if (_Z_RC_IN_VAL(intr)->_callback != NULL) {\n            _Z_RC_IN_VAL(intr)->_callback(&msg, peer, _Z_RC_IN_VAL(&_Z_RC_IN_VAL(intr)->_arg));\n        }\n        xs = _z_session_interest_rc_slist_next(xs);\n    }\n    // Clean up\n    _z_session_interest_rc_slist_free(&intrs);\n}\n\nvoid _z_interest_replay_declare(_z_session_t *zn, _z_session_interest_t *interest) {\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        return;\n    }\n    _z_declare_data_slist_t *res_list = _z_declare_data_slist_clone(zn->_remote_declares);\n    _z_session_mutex_unlock(zn);\n\n    _z_declare_data_slist_t *xs = res_list;\n    while (xs != NULL) {\n        _z_declare_data_t *res = _z_declare_data_slist_value(xs);\n        bool is_matching = _z_session_interest_is_aggregate(interest)\n                               ? _z_keyexpr_equals(&interest->_key, &res->_key)\n                               : _z_keyexpr_intersects(&interest->_key, &res->_key);\n        if (is_matching) {\n            _z_interest_msg_t msg = {0};\n            msg.key = &res->_key;\n            msg.is_complete = res->_complete;\n            msg.id = res->_id;\n            switch (res->_type) {\n                default:\n                    break;\n                case _Z_DECLARE_TYPE_QUERYABLE:\n                    msg.type = _Z_INTEREST_MSG_TYPE_DECL_QUERYABLE;\n                    break;\n                case _Z_DECLARE_TYPE_SUBSCRIBER:\n                    msg.type = _Z_INTEREST_MSG_TYPE_DECL_SUBSCRIBER;\n                    break;\n                case _Z_DECLARE_TYPE_TOKEN:\n                    msg.type = _Z_INTEREST_MSG_TYPE_DECL_TOKEN;\n                    break;\n            }\n            interest->_callback(&msg, res->_peer, _Z_RC_IN_VAL(&interest->_arg));\n        }\n        xs = _z_declare_data_slist_next(xs);\n    }\n    _z_declare_data_slist_free(&res_list);\n}\n\n#else\nvoid _z_interest_init(_z_session_t *zn) { _ZP_UNUSED(zn); }\n\nvoid _z_flush_interest(_z_session_t *zn) { _ZP_UNUSED(zn); }\n\nz_result_t _z_interest_process_declares(_z_session_t *zn, const _z_n_msg_declare_t *decl,\n                                        _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_undeclares(_z_session_t *zn, const _z_declaration_t *decl,\n                                          _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_declare_final(_z_session_t *zn, uint32_t id, _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(id);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_interest_final(_z_session_t *zn, uint32_t id) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(id);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_interest_process_interest(_z_session_t *zn, _z_wireexpr_t *wireexpr, uint32_t id, uint8_t flags,\n                                        _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(wireexpr);\n    _ZP_UNUSED(id);\n    _ZP_UNUSED(flags);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nvoid _z_interest_peer_disconnected(_z_session_t *zn, _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(peer);\n}\n#endif\n"
  },
  {
    "path": "src/session/keyexpr.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/session/keyexpr.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/string.h\"\n\nz_result_t _z_keyexpr_wire_declaration_new(_z_keyexpr_wire_declaration_t *declaration, const _z_string_t *keyexpr,\n                                           const _z_session_rc_t *session) {\n    *declaration = _z_keyexpr_wire_declaration_null();\n    z_result_t ret = _z_declare_resource(_Z_RC_IN_VAL(session), keyexpr, &declaration->_id);\n    if (ret == _Z_RES_OK) {\n        declaration->_prefix_len = (uint16_t)_z_string_len(keyexpr);\n        declaration->_session = _z_session_rc_clone_as_weak(session);\n    }\n    return ret;\n}\n\nz_result_t _z_keyexpr_wire_declaration_undeclare(_z_keyexpr_wire_declaration_t *declaration) {\n    z_result_t ret = _Z_RES_OK;\n    if (_Z_RC_IS_NULL(&declaration->_session)) {\n        return ret;\n    }\n\n    _z_session_rc_t session_rc = _z_session_weak_upgrade_if_open(&declaration->_session);\n\n    if (!_Z_RC_IS_NULL(&session_rc)) {\n        ret = _z_undeclare_resource(_Z_RC_IN_VAL(&session_rc), declaration->_id);\n        _z_session_rc_drop(&session_rc);\n    }\n    declaration->_id = Z_RESOURCE_ID_NONE;\n    declaration->_prefix_len = 0;\n    _z_session_weak_drop(&declaration->_session);\n    return ret;\n}\n\nvoid _z_keyexpr_wire_declaration_clear(_z_keyexpr_wire_declaration_t *declaration) {\n    _z_keyexpr_wire_declaration_undeclare(declaration);\n}\n\n_z_keyexpr_t _z_keyexpr_alias_from_string(const _z_string_t *str) {\n    _z_keyexpr_t ke = _z_keyexpr_null();\n    ke._keyexpr = _z_string_alias(*str);\n    return ke;\n}\n\n_z_keyexpr_t _z_keyexpr_alias_from_substr(const char *str, size_t len) {\n    _z_keyexpr_t ke = _z_keyexpr_null();\n    ke._keyexpr = _z_string_alias_substr(str, len);\n    return ke;\n}\n\n_z_declared_keyexpr_t _z_declared_keyexpr_alias_from_string(const _z_string_t *str) {\n    _z_declared_keyexpr_t ke = _z_declared_keyexpr_null();\n    ke._inner = _z_keyexpr_alias_from_string(str);\n    return ke;\n}\n\n_z_declared_keyexpr_t _z_declared_keyexpr_alias_from_substr(const char *str, size_t len) {\n    _z_declared_keyexpr_t ke = _z_declared_keyexpr_null();\n    ke._inner = _z_keyexpr_alias_from_substr(str, len);\n    return ke;\n}\n\nz_result_t _z_keyexpr_from_string(_z_keyexpr_t *dst, const _z_string_t *str) {\n    return _z_keyexpr_from_substr(dst, _z_string_data(str), _z_string_len(str));\n}\n\nz_result_t _z_keyexpr_from_substr(_z_keyexpr_t *dst, const char *str, size_t len) {\n    *dst = _z_keyexpr_null();\n    dst->_keyexpr = _z_string_copy_from_substr(str, len);\n    return _z_string_check(&dst->_keyexpr) ? _Z_RES_OK : _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n}\n\nz_result_t _z_declared_keyexpr_copy(_z_declared_keyexpr_t *dst, const _z_declared_keyexpr_t *src) {\n    *dst = _z_declared_keyexpr_null();\n    _Z_RETURN_IF_ERR(_z_keyexpr_copy(&dst->_inner, &src->_inner));\n    if (!_Z_RC_IS_NULL(&src->_declaration)) {\n        dst->_declaration = _z_keyexpr_wire_declaration_rc_clone(&src->_declaration);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declared_keyexpr_move(_z_declared_keyexpr_t *dst, _z_declared_keyexpr_t *src) {\n    *dst = _z_declared_keyexpr_null();\n    _Z_RETURN_IF_ERR(_z_keyexpr_move(&dst->_inner, &src->_inner));\n    dst->_declaration = src->_declaration;\n    src->_declaration = _z_keyexpr_wire_declaration_rc_null();\n    return _Z_RES_OK;\n}\n\n/*------------------ Canonize helpers ------------------*/\nzp_keyexpr_canon_status_t __zp_canon_prefix(const char *start, size_t *len) {\n    zp_keyexpr_canon_status_t ret = Z_KEYEXPR_CANON_SUCCESS;\n\n    bool in_big_wild = false;\n    char const *chunk_start = start;\n    const char *end = _z_cptr_char_offset(start, (ptrdiff_t)(*len));\n    char const *next_slash;\n\n    do {\n        next_slash = memchr(chunk_start, '/', _z_ptr_char_diff(end, chunk_start));\n        const char *chunk_end = next_slash ? next_slash : end;\n        size_t chunk_len = _z_ptr_char_diff(chunk_end, chunk_start);\n        switch (chunk_len) {\n            case 0: {\n                ret = Z_KEYEXPR_CANON_EMPTY_CHUNK;\n            } break;\n\n            case 1: {\n                if (in_big_wild && (chunk_start[0] == '*')) {\n                    *len = _z_ptr_char_diff(chunk_start, start) - (size_t)3;\n                    ret = Z_KEYEXPR_CANON_SINGLE_STAR_AFTER_DOUBLE_STAR;\n                } else {\n                    chunk_start = _z_cptr_char_offset(chunk_end, 1);\n                    continue;\n                }\n            } break;\n\n            case 2:\n                if (chunk_start[1] == '*') {\n                    if (chunk_start[0] == '$') {\n                        *len = _z_ptr_char_diff(chunk_start, start);\n                        ret = Z_KEYEXPR_CANON_LONE_DOLLAR_STAR;\n                    } else if (chunk_start[0] == '*') {\n                        if (in_big_wild) {\n                            *len = _z_ptr_char_diff(chunk_start, start) - (size_t)3;\n                            ret = Z_KEYEXPR_CANON_DOUBLE_STAR_AFTER_DOUBLE_STAR;\n                        } else {\n                            chunk_start = _z_cptr_char_offset(chunk_end, 1);\n                            in_big_wild = true;\n                            continue;\n                        }\n                    } else {\n                        // Do nothing. Required to be compliant with MISRA 15.7 rule\n                    }\n                } else {\n                    // Do nothing. Required to be compliant with MISRA 15.7 rule\n                }\n                break;\n\n            default:\n                break;\n        }\n\n        unsigned char in_dollar = 0;\n        for (char const *c = chunk_start; (c < chunk_end) && (ret == Z_KEYEXPR_CANON_SUCCESS);\n             c = _z_cptr_char_offset(c, 1)) {\n            switch (c[0]) {\n                case '#':\n                case '?': {\n                    ret = Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK;\n                } break;\n\n                case '$': {\n                    if (in_dollar != (unsigned char)0) {\n                        ret = Z_KEYEXPR_CANON_DOLLAR_AFTER_DOLLAR_OR_STAR;\n                    } else {\n                        in_dollar = in_dollar + (unsigned char)1;\n                    }\n                } break;\n\n                case '*': {\n                    if (in_dollar != (unsigned char)1) {\n                        ret = Z_KEYEXPR_CANON_STARS_IN_CHUNK;\n                    } else {\n                        in_dollar = in_dollar + (unsigned char)2;\n                    }\n                } break;\n\n                default: {\n                    if (in_dollar == (unsigned char)1) {\n                        ret = Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR;\n                    } else {\n                        in_dollar = 0;\n                    }\n                } break;\n            }\n        }\n\n        if (ret == Z_KEYEXPR_CANON_SUCCESS) {\n            if (in_dollar == (unsigned char)1) {\n                ret = Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR;\n            } else {\n                chunk_start = _z_cptr_char_offset(chunk_end, 1);\n                in_big_wild = false;\n            }\n        }\n    } while ((chunk_start < end) && (ret == Z_KEYEXPR_CANON_SUCCESS));\n\n    if (ret == Z_KEYEXPR_CANON_SUCCESS) {\n        if (chunk_start <= end) {\n            ret = Z_KEYEXPR_CANON_EMPTY_CHUNK;\n        }\n    }\n\n    return ret;\n}\n\nvoid __zp_singleify(char *start, size_t *len, const char *needle) {\n    const char *end = _z_cptr_char_offset(start, (ptrdiff_t)(*len));\n    bool right_after_needle = false;\n    char *reader = start;\n\n    while (reader < end) {\n        size_t pos = _z_str_startswith(reader, needle);\n        if (pos != (size_t)0) {\n            if (right_after_needle == true) {\n                break;\n            }\n            right_after_needle = true;\n            reader = _z_ptr_char_offset(reader, (ptrdiff_t)pos);\n        } else {\n            right_after_needle = false;\n            reader = _z_ptr_char_offset(reader, 1);\n        }\n    }\n\n    char *writer = reader;\n    while (reader < end) {\n        size_t pos = _z_str_startswith(reader, needle);\n        if (pos != (size_t)0) {\n            if (right_after_needle == false) {\n                for (size_t i = 0; i < pos; i++) {\n                    writer[i] = reader[i];\n                }\n                writer = _z_ptr_char_offset(writer, (ptrdiff_t)pos);\n            }\n            right_after_needle = true;\n            reader = _z_ptr_char_offset(reader, (ptrdiff_t)pos);\n        } else {\n            right_after_needle = false;\n            *writer = *reader;\n            writer = _z_ptr_char_offset(writer, 1);\n            reader = _z_ptr_char_offset(reader, 1);\n        }\n    }\n    *len = _z_ptr_char_diff(writer, start);\n}\n\nvoid __zp_ke_write_chunk(char **writer, const char *chunk, size_t len, const char *write_start) {\n    if (writer[0] != write_start) {\n        writer[0][0] = '/';\n        writer[0] = _z_ptr_char_offset(writer[0], 1);\n    }\n\n    (void)memmove(writer[0], chunk, len);\n    writer[0] = _z_ptr_char_offset(writer[0], (ptrdiff_t)len);\n}\n\n/*------------------ Common helpers ------------------*/\ntypedef bool (*_z_ke_chunk_matcher)(_z_str_se_t l, _z_str_se_t r);\n\nenum _zp_wildness_t { _ZP_WILDNESS_ANY = 1, _ZP_WILDNESS_SUPERCHUNKS = 2, _ZP_WILDNESS_SUBCHUNK_DSL = 4 };\nint8_t _zp_ke_wildness(_z_str_se_t ke, size_t *n_segments, size_t *n_verbatims) {\n    const char *start = ke.start;\n    const char *end = ke.end;\n    int8_t result = 0;\n    char prev_char = 0;\n    for (char const *c = start; c < end; c = _z_cptr_char_offset(c, 1)) {\n        switch (c[0]) {\n            case '*': {\n                result = result | (int8_t)_ZP_WILDNESS_ANY;\n                if (prev_char == '*') {\n                    result = result | (int8_t)_ZP_WILDNESS_SUPERCHUNKS;\n                }\n            } break;\n\n            case '$': {\n                result = result | (int8_t)_ZP_WILDNESS_SUBCHUNK_DSL;\n            } break;\n\n            case '/': {\n                *n_segments = *n_segments + (size_t)1;\n            } break;\n            case '@': {\n                *n_verbatims = *n_verbatims + (size_t)1;\n            }\n            default: {\n                // Do nothing\n            } break;\n        }\n\n        prev_char = *c;\n    }\n\n    return result;\n}\n\nconst char *_Z_DOUBLE_STAR = \"**\";\nconst char *_Z_DOLLAR_STAR = \"$*\";\n\nzp_keyexpr_canon_status_t _z_keyexpr_canonize(char *start, size_t *len) {\n    __zp_singleify(start, len, \"$*\");\n    size_t canon_len = *len;\n    zp_keyexpr_canon_status_t ret = __zp_canon_prefix(start, &canon_len);\n\n    if ((ret == Z_KEYEXPR_CANON_LONE_DOLLAR_STAR) || (ret == Z_KEYEXPR_CANON_SINGLE_STAR_AFTER_DOUBLE_STAR) ||\n        (ret == Z_KEYEXPR_CANON_DOUBLE_STAR_AFTER_DOUBLE_STAR)) {\n        ret = Z_KEYEXPR_CANON_SUCCESS;\n\n        const char *end = _z_cptr_char_offset(start, (ptrdiff_t)(*len));\n        char *reader = _z_ptr_char_offset(start, (ptrdiff_t)canon_len);\n        const char *write_start = reader;\n        char *writer = reader;\n        char *next_slash = strchr(reader, '/');\n        char const *chunk_end = (next_slash != NULL) ? next_slash : end;\n\n        bool in_big_wild = false;\n        if ((_z_ptr_char_diff(chunk_end, reader) == 2) && (reader[1] == '*')) {\n            if (reader[0] == '*') {\n                in_big_wild = true;\n            } else if (reader[0] == '$') {\n                writer[0] = '*';\n                writer = _z_ptr_char_offset(writer, 1);\n            } else {\n                assert(false);  // anything before \"$*\" or \"**\" must be part of the canon prefix\n            }\n        } else {\n            assert(false);  // anything before \"$*\" or \"**\" must be part of the canon prefix\n        }\n        while (next_slash != NULL) {\n            reader = _z_ptr_char_offset(next_slash, 1);\n            next_slash = memchr(reader, '/', _z_ptr_char_diff(end, reader));\n            chunk_end = next_slash ? next_slash : end;\n            switch (_z_ptr_char_diff(chunk_end, reader)) {\n                case 0: {\n                    ret = Z_KEYEXPR_CANON_EMPTY_CHUNK;\n                } break;\n\n                case 1: {\n                    if (reader[0] == '*') {\n                        __zp_ke_write_chunk(&writer, \"*\", 1, write_start);\n                        continue;\n                    }\n                } break;\n\n                case 2: {\n                    if (reader[1] == '*') {\n                        if (reader[0] == '$') {\n                            __zp_ke_write_chunk(&writer, \"*\", 1, write_start);\n                            continue;\n                        } else if (reader[0] == '*') {\n                            in_big_wild = true;\n                            continue;\n                        } else {\n                            // Do nothing. Required to be compliant with MISRA 15.7 rule\n                        }\n                    }\n                } break;\n\n                default:\n                    break;\n            }\n\n            unsigned char in_dollar = 0;\n            for (char const *c = reader; (c < end) && (ret == Z_KEYEXPR_CANON_SUCCESS); c = _z_cptr_char_offset(c, 1)) {\n                switch (*c) {\n                    case '#':\n                    case '?': {\n                        ret = Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK;\n                    } break;\n\n                    case '$': {\n                        if (in_dollar != (unsigned char)0) {\n                            ret = Z_KEYEXPR_CANON_DOLLAR_AFTER_DOLLAR_OR_STAR;\n                        } else {\n                            in_dollar = in_dollar + (unsigned char)1;\n                        }\n                    } break;\n\n                    case '*': {\n                        if (in_dollar != (unsigned char)1) {\n                            ret = Z_KEYEXPR_CANON_STARS_IN_CHUNK;\n                        } else {\n                            in_dollar = in_dollar + (unsigned char)2;\n                        }\n                    } break;\n\n                    default: {\n                        if (in_dollar == (unsigned char)1) {\n                            ret = Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR;\n                        } else {\n                            in_dollar = 0;\n                        }\n                    } break;\n                }\n            }\n\n            if ((ret == Z_KEYEXPR_CANON_SUCCESS) && (in_dollar == (unsigned char)1)) {\n                ret = Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR;\n            }\n\n            if (ret == Z_KEYEXPR_CANON_SUCCESS) {\n                if (in_big_wild) {\n                    __zp_ke_write_chunk(&writer, _Z_DOUBLE_STAR, 2, write_start);\n                }\n\n                __zp_ke_write_chunk(&writer, reader, _z_ptr_char_diff(chunk_end, reader), write_start);\n                in_big_wild = false;\n            }\n        }\n\n        if (ret == Z_KEYEXPR_CANON_SUCCESS) {\n            if (in_big_wild) {\n                __zp_ke_write_chunk(&writer, _Z_DOUBLE_STAR, 2, write_start);\n            }\n            *len = _z_ptr_char_diff(writer, start);\n        }\n    }\n\n    return ret;\n}\n\nzp_keyexpr_canon_status_t _z_keyexpr_is_canon(const char *start, size_t len) { return __zp_canon_prefix(start, &len); }\n\nz_result_t _z_keyexpr_concat(_z_keyexpr_t *key, const _z_keyexpr_t *left, const char *right, size_t len) {\n    *key = _z_keyexpr_null();\n    size_t left_len = _z_string_len(&left->_keyexpr);\n    if (left_len == 0) {\n        return _z_keyexpr_from_substr(key, right, len);\n    }\n    const char *left_data = _z_string_data(&left->_keyexpr);\n\n    if (left_data[left_len - 1] == '*' && len > 0 && right[0] == '*') {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    _Z_RETURN_IF_ERR(_z_string_concat_substr(&key->_keyexpr, &left->_keyexpr, right, len, NULL, 0));\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declared_keyexpr_concat(_z_declared_keyexpr_t *key, const _z_declared_keyexpr_t *left, const char *right,\n                                      size_t len) {\n    *key = _z_declared_keyexpr_null();\n    _Z_RETURN_IF_ERR(_z_keyexpr_concat(&key->_inner, &left->_inner, right, len));\n    if (!_Z_RC_IS_NULL(&left->_declaration)) {\n        key->_declaration = _z_keyexpr_wire_declaration_rc_clone(&left->_declaration);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_keyexpr_join(_z_keyexpr_t *key, const _z_keyexpr_t *left, const _z_keyexpr_t *right) {\n    *key = _z_keyexpr_null();\n\n    _Z_RETURN_IF_ERR(_z_string_concat_substr(&key->_keyexpr, &left->_keyexpr, _z_string_data(&right->_keyexpr),\n                                             _z_string_len(&right->_keyexpr), \"/\", 1));\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_canonize((char *)key->_keyexpr._slice.start, &key->_keyexpr._slice.len),\n                           _z_keyexpr_clear(key));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declared_keyexpr_join(_z_declared_keyexpr_t *key, const _z_declared_keyexpr_t *left,\n                                    const _z_declared_keyexpr_t *right) {\n    *key = _z_declared_keyexpr_null();\n    _Z_RETURN_IF_ERR(_z_keyexpr_join(&key->_inner, &left->_inner, &right->_inner));\n    if (!_Z_RC_IS_NULL(&left->_declaration)) {\n        key->_declaration = _z_keyexpr_wire_declaration_rc_clone(&left->_declaration);\n    }\n    return _Z_RES_OK;\n}\n\n_z_wireexpr_t _z_declared_keyexpr_alias_to_wire(const _z_declared_keyexpr_t *key, const _z_session_t *session) {\n    _z_wireexpr_t expr = _z_wireexpr_null();\n    const char *suffix_str = _z_string_data(&key->_inner._keyexpr);\n    size_t suffix_len = _z_string_len(&key->_inner._keyexpr);\n    if (!_Z_RC_IS_NULL(&key->_declaration) &&\n        _z_keyexpr_wire_declaration_is_declared_on_session(_Z_RC_IN_VAL(&key->_declaration), session)) {\n        expr._id = _Z_RC_IN_VAL(&key->_declaration)->_id;\n        expr._mapping = _Z_KEYEXPR_MAPPING_LOCAL;\n        suffix_str = suffix_str + _Z_RC_IN_VAL(&key->_declaration)->_prefix_len;\n        suffix_len -= _Z_RC_IN_VAL(&key->_declaration)->_prefix_len;\n    }\n    if (suffix_len > 0) {\n        expr._suffix = _z_string_alias_substr(suffix_str, suffix_len);\n    }\n    return expr;\n}\n\n_z_wireexpr_t _z_keyexpr_alias_to_wire(const _z_keyexpr_t *key) {\n    _z_wireexpr_t expr = _z_wireexpr_null();\n    expr._suffix = _z_string_alias(key->_keyexpr);\n    return expr;\n}\n\nz_result_t _z_keyexpr_declare_prefix(const _z_session_rc_t *zs, _z_declared_keyexpr_t *out, const _z_keyexpr_t *keyexpr,\n                                     size_t prefix_len) {\n    assert(prefix_len <= _z_string_len(&keyexpr->_keyexpr));\n    *out = _z_declared_keyexpr_null();\n    _Z_RETURN_IF_ERR(_z_string_copy(&out->_inner._keyexpr, &keyexpr->_keyexpr));\n    if (prefix_len == 0) {\n        return _Z_RES_OK;\n    }\n#if Z_FEATURE_MULTICAST_DECLARATIONS == 0\n    if (_Z_RC_IN_VAL(zs)->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE) {\n        // Skip declaration since declaring a keyexpr without Z_FEATURE_MULTICAST_DECLARATIONS might generate unknown\n        // key expression errors.\n        return _Z_RES_OK;\n    }\n#endif\n    _z_keyexpr_wire_declaration_t declaration = _z_keyexpr_wire_declaration_null();\n    out->_declaration = _z_keyexpr_wire_declaration_rc_new_from_val(&declaration);\n    if (_Z_RC_IS_NULL(&out->_declaration)) {\n        _z_declared_keyexpr_clear(out);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    _z_string_t prefix = _z_string_alias_substr(_z_string_data(&out->_inner._keyexpr), prefix_len);\n    _Z_CLEAN_RETURN_IF_ERR(_z_keyexpr_wire_declaration_new(_Z_RC_IN_VAL(&out->_declaration), &prefix, zs),\n                           _z_declared_keyexpr_clear(out));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_declared_keyexpr_declare(const _z_session_rc_t *zs, _z_declared_keyexpr_t *out,\n                                       const _z_declared_keyexpr_t *keyexpr) {\n    if (_z_declared_keyexpr_is_fully_optimized(keyexpr, _Z_RC_IN_VAL(zs))) {\n        return _z_declared_keyexpr_copy(out, keyexpr);\n    } else {\n        return _z_keyexpr_declare_prefix(zs, out, &keyexpr->_inner, _z_string_len(&keyexpr->_inner._keyexpr));\n    }\n}\n\nsize_t _z_keyexpr_non_wild_prefix_len(const _z_keyexpr_t *key) {\n    const char *data = _z_string_data(&key->_keyexpr);\n    size_t len = _z_string_len(&key->_keyexpr);\n    char *pos = (char *)memchr(data, '*', len);\n    if (pos == NULL) {\n        return len;\n    }\n    while (pos != data && *pos != '/') {\n        pos--;\n    }\n\n    return _z_ptr_char_diff(pos, data);\n}\n\nz_result_t _z_declared_keyexpr_declare_non_wild_prefix(const _z_session_rc_t *zs, _z_declared_keyexpr_t *out,\n                                                       const _z_declared_keyexpr_t *keyexpr) {\n    if (_z_declared_keyexpr_is_non_wild_prefix_optimized(keyexpr, _Z_RC_IN_VAL(zs))) {\n        return _z_declared_keyexpr_copy(out, keyexpr);\n    } else {\n        return _z_keyexpr_declare_prefix(zs, out, &keyexpr->_inner, _z_keyexpr_non_wild_prefix_len(&keyexpr->_inner));\n    }\n}\n\n#define _ZP_KE_MATCH_TEMPLATE_INTERSECTS 1\n#include \"zenoh-pico/session/keyexpr_match_template.h\"\n#define _ZP_KE_MATCH_TEMPLATE_INTERSECTS 0\n#include \"zenoh-pico/session/keyexpr_match_template.h\"\n\nbool _z_keyexpr_intersects(const _z_keyexpr_t *left, const _z_keyexpr_t *right) {\n    size_t left_len = _z_string_len(&left->_keyexpr);\n    size_t right_len = _z_string_len(&right->_keyexpr);\n    const char *left_start = _z_string_data(&left->_keyexpr);\n    const char *right_start = _z_string_data(&right->_keyexpr);\n\n    // fast path for identical key expressions, do we really need it ?\n    if ((left_len == right_len) && (strncmp(left_start, right_start, left_len) == 0)) {\n        return true;\n    }\n\n    return _z_keyexpr_forward_intersects(left_start, left_start + left_len, right_start, right_start + right_len, true);\n}\n\nbool _z_keyexpr_includes(const _z_keyexpr_t *left, const _z_keyexpr_t *right) {\n    size_t left_len = _z_string_len(&left->_keyexpr);\n    size_t right_len = _z_string_len(&right->_keyexpr);\n    const char *left_start = _z_string_data(&left->_keyexpr);\n    const char *right_start = _z_string_data(&right->_keyexpr);\n\n    // fast path for identical key expressions, do we really need it ?\n    if ((left_len == right_len) && (strncmp(left_start, right_start, left_len) == 0)) {\n        return true;\n    }\n\n    return _z_keyexpr_forward_includes(left_start, left_start + left_len, right_start, right_start + right_len, true);\n}\n"
  },
  {
    "path": "src/session/liveliness.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/api/liveliness.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/reply.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_LIVELINESS == 1\n/**************** Liveliness Subscriber ****************/\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nz_result_t _z_liveliness_process_remote_token_declare(_z_session_t *zn, uint32_t id, const _z_wireexpr_t *wireexpr,\n                                                      const _z_timestamp_t *timestamp,\n                                                      _z_transport_peer_common_t *peer) {\n    _z_keyexpr_t ke;\n    _Z_RETURN_IF_ERR(_z_get_keyexpr_from_wireexpr(zn, &ke, wireexpr, peer, false));\n    z_result_t ret = _Z_RES_OK;\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&ke));\n\n    const _z_keyexpr_t *pkeyexpr = _z_keyexpr_intmap_get(&zn->_remote_tokens, id);\n    if (pkeyexpr != NULL) {\n        // Already received this token\n        _Z_DEBUG(\"Duplicate token id %i\", (int)id);\n        ret = _z_keyexpr_equals(pkeyexpr, &ke) ? _Z_RES_OK : _Z_ERR_KEYEXPR_NOT_MATCH;\n        _z_session_mutex_unlock(zn);\n        _z_keyexpr_clear(&ke);\n        return ret;\n    } else {\n        _z_keyexpr_t *ke_on_heap = (_z_keyexpr_t *)z_malloc(sizeof(_z_keyexpr_t));\n        if (ke_on_heap == NULL || _z_keyexpr_intmap_insert(&zn->_remote_tokens, id, ke_on_heap) == NULL) {\n            ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            z_free(ke_on_heap);\n        } else {\n            *ke_on_heap = _z_keyexpr_steal(&ke);\n        }\n    }\n\n    _z_session_mutex_unlock(zn);\n    _z_wireexpr_t wireexpr2 = _z_wireexpr_alias(wireexpr);\n    _Z_SET_IF_OK(ret, _z_trigger_liveliness_subscriptions_declare(zn, &wireexpr2, timestamp, peer));\n    if (ret != _Z_RES_OK) {\n        _z_session_mutex_lock(zn);\n        // remote tokens kes do not reference any declaration, so it is safe to remove them under session mutex\n        _z_keyexpr_intmap_remove(&zn->_remote_tokens, id);\n        _z_session_mutex_unlock(zn);\n        _z_keyexpr_clear(&ke);\n    }\n    return ret;\n}\n\nz_result_t _z_liveliness_process_remote_token_undeclare(_z_session_t *zn, uint32_t id,\n                                                        const _z_timestamp_t *timestamp) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_keyexpr_t key = _z_keyexpr_null();\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_keyexpr_t *keyexpr = (_z_keyexpr_t *)_z_keyexpr_intmap_get(&zn->_remote_tokens, id);\n    if (keyexpr != NULL) {\n        key = _z_keyexpr_steal(keyexpr);\n        _z_keyexpr_intmap_remove(&zn->_remote_tokens, id);\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_ENTITY_UNKNOWN);\n        ret = _Z_ERR_ENTITY_UNKNOWN;\n    }\n    _z_session_mutex_unlock(zn);\n\n    if (_z_keyexpr_check(&key)) {\n        ret = _z_trigger_liveliness_subscriptions_undeclare(zn, &key, timestamp);\n        _z_keyexpr_clear(&key);\n    }\n    return ret;\n}\n\nz_result_t _z_liveliness_subscription_undeclare_all(_z_session_t *zn) {\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    // NOTE: it is safe to just move the data, since remote tokens store full copies of ke.\n    _z_keyexpr_intmap_t token_list = zn->_remote_tokens;\n    _z_keyexpr_intmap_init(&zn->_remote_tokens);\n    _z_session_mutex_unlock(zn);\n\n    _z_keyexpr_intmap_iterator_t iter = _z_keyexpr_intmap_iterator_make(&token_list);\n    _z_timestamp_t tm = _z_timestamp_null();\n    while (_z_keyexpr_intmap_iterator_next(&iter)) {\n        _z_keyexpr_t *key = _z_keyexpr_intmap_iterator_value(&iter);\n        ret = _z_trigger_liveliness_subscriptions_undeclare(zn, key, &tm);\n        if (ret != _Z_RES_OK) {\n            break;\n        }\n    }\n    _z_keyexpr_intmap_clear(&token_list);\n\n    return ret;\n}\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n/**************** Liveliness Query ****************/\n\n#if Z_FEATURE_QUERY == 1\n\nvoid _z_liveliness_pending_query_clear(_z_liveliness_pending_query_t *pen_qry) {\n    if (pen_qry->_dropper != NULL) {\n        pen_qry->_dropper(pen_qry->_arg);\n        pen_qry->_dropper = NULL;\n    }\n    _z_keyexpr_clear(&pen_qry->_key);\n#ifdef Z_FEATURE_UNSTABLE_API\n    _z_pending_query_cancellation_data_clear(&pen_qry->_cancellation_data);\n#endif\n}\n\n_z_liveliness_pending_query_t *_z_unsafe_liveliness_register_pending_query(_z_session_t *zn) {\n    _z_liveliness_pending_query_t *q = (_z_liveliness_pending_query_t *)z_malloc(sizeof(_z_liveliness_pending_query_t));\n    if (q == NULL) {\n        return NULL;\n    }\n    uint32_t id = zn->_liveliness_query_id++;\n    q->_id = id;\n    if (_z_liveliness_pending_query_intmap_insert(&zn->_liveliness_pending_queries, id, q) == NULL) {\n        z_free(q);\n        return NULL;\n    }\n    return q;\n}\n\nstatic z_result_t _z_liveliness_pending_query_reply(_z_session_t *zn, uint32_t interest_id,\n                                                    const _z_wireexpr_t *wireexpr, const _z_timestamp_t *timestamp,\n                                                    _z_transport_peer_common_t *peer) {\n    _Z_DEBUG(\"Resolving %d - %.*s on mapping 0x%x\", wireexpr->_id, (int)_z_string_len(&wireexpr->_suffix),\n             _z_string_data(&wireexpr->_suffix), (unsigned int)wireexpr->_mapping);\n    _z_keyexpr_t ke;\n    _Z_RETURN_IF_ERR(_z_get_keyexpr_from_wireexpr(zn, &ke, wireexpr, peer, true));\n    z_result_t ret = _Z_RES_OK;\n\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&ke));\n\n    const _z_liveliness_pending_query_t *pq =\n        _z_liveliness_pending_query_intmap_get(&zn->_liveliness_pending_queries, interest_id);\n    if (pq == NULL) {\n        _Z_ERROR_LOG(_Z_ERR_ENTITY_UNKNOWN);\n        ret = _Z_ERR_ENTITY_UNKNOWN;\n    }\n\n    _Z_DEBUG(\"Liveliness pending query reply %i resolve result %i\", (int)interest_id, ret);\n\n    if (ret == _Z_RES_OK) {\n        _Z_DEBUG(\"Reply liveliness query for %.*s\", (int)_z_string_len(&ke._keyexpr), _z_string_data(&ke._keyexpr));\n\n        if (!_z_keyexpr_intersects(&pq->_key, &ke)) {\n            _Z_ERROR_LOG(_Z_ERR_QUERY_NOT_MATCH);\n            ret = _Z_ERR_QUERY_NOT_MATCH;\n        }\n\n        if (ret == _Z_RES_OK) {\n            _z_encoding_t encoding = _z_encoding_null();\n            _z_bytes_t payload = _z_bytes_null();\n            _z_bytes_t attachment = _z_bytes_null();\n            _z_source_info_t source_info = _z_source_info_null();\n            _z_reply_t reply;\n            _z_reply_steal_data(&reply, &ke, _z_entity_global_id_null(), &payload, timestamp, &encoding,\n                                Z_SAMPLE_KIND_PUT, &attachment, &source_info);\n\n            pq->_callback(&reply, pq->_arg);\n            _z_reply_clear(&reply);\n        }\n    }\n\n    _z_session_mutex_unlock(zn);\n    _z_keyexpr_clear(&ke);\n\n    return ret;\n}\n\nz_result_t _z_liveliness_unregister_pending_query(_z_session_t *zn, uint32_t id) {\n    z_result_t ret = _Z_ERR_ENTITY_UNKNOWN;\n    _z_session_mutex_lock(zn);\n    _z_liveliness_pending_query_t *pq =\n        _z_liveliness_pending_query_intmap_extract(&zn->_liveliness_pending_queries, id);\n    if (pq != NULL) {\n        _z_liveliness_pending_query_clear(pq);\n        z_free(pq);\n        ret = _Z_RES_OK;\n    }\n    _z_session_mutex_unlock(zn);\n    return ret;\n}\n\n#endif  // Z_FEATURE_QUERY == 1\n\n/**************** Interest processing ****************/\n\nz_result_t _z_liveliness_process_token_declare(_z_session_t *zn, const _z_n_msg_declare_t *decl,\n                                               _z_transport_peer_common_t *peer) {\n#if Z_FEATURE_QUERY == 1\n    if (decl->_interest_id.has_value) {\n        _z_liveliness_pending_query_reply(zn, decl->_interest_id.value, &decl->_decl._body._decl_token._keyexpr,\n                                          &decl->_ext_timestamp, peer);\n    }\n#endif\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n    return _z_liveliness_process_remote_token_declare(\n        zn, decl->_decl._body._decl_token._id, &decl->_decl._body._decl_token._keyexpr, &decl->_ext_timestamp, peer);\n#else\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n#endif\n}\n\nz_result_t _z_liveliness_process_token_undeclare(_z_session_t *zn, const _z_n_msg_declare_t *decl) {\n#if Z_FEATURE_SUBSCRIPTION == 1\n    return _z_liveliness_process_remote_token_undeclare(zn, decl->_decl._body._undecl_token._id, &decl->_ext_timestamp);\n#else\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    return _Z_RES_OK;\n#endif\n}\n\nz_result_t _z_liveliness_process_declare_final(_z_session_t *zn, const _z_n_msg_declare_t *decl) {\n    z_result_t ret = _Z_RES_OK;\n#if Z_FEATURE_QUERY == 1\n    if (decl->_interest_id.has_value) {\n        ret = _z_liveliness_unregister_pending_query(zn, decl->_interest_id.value);\n        if (ret != _Z_RES_OK) {\n            _Z_ERROR_LOG(ret);\n        } else {\n            _Z_DEBUG(\"Liveliness pending query drop %zu\", (size_t)decl->_interest_id.value);\n        }\n    }\n#else\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n#endif\n    return _Z_RES_OK;\n}\n\n/**************** Init/Clear ****************/\n\nvoid _z_liveliness_init(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n\n    zn->_remote_tokens = _z_keyexpr_intmap_make();\n    zn->_local_tokens = _z_declared_keyexpr_intmap_make();\n#if Z_FEATURE_QUERY == 1\n    zn->_liveliness_query_id = 1;\n    zn->_liveliness_pending_queries = _z_liveliness_pending_query_intmap_make();\n#endif\n\n    _z_session_mutex_unlock(zn);\n}\n\nvoid _z_liveliness_clear(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n#if Z_FEATURE_QUERY == 1\n    _z_liveliness_pending_query_intmap_clear(&zn->_liveliness_pending_queries);\n#endif\n    _z_declared_keyexpr_intmap_t local_tokens = zn->_local_tokens;\n    zn->_local_tokens = _z_declared_keyexpr_intmap_make();\n    _z_keyexpr_intmap_t remote_tokens = zn->_remote_tokens;\n    zn->_remote_tokens = _z_keyexpr_intmap_make();\n    _z_session_mutex_unlock(zn);\n    // drop maps outside of session mutex to avoid deadlock\n    _z_declared_keyexpr_intmap_clear(&local_tokens);\n    _z_keyexpr_intmap_clear(&remote_tokens);\n}\n\n#else  // Z_FEATURE_LIVELINESS == 0\n\nz_result_t _z_liveliness_process_token_declare(_z_session_t *zn, const _z_n_msg_declare_t *decl,\n                                               _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_liveliness_process_token_undeclare(_z_session_t *zn, const _z_n_msg_declare_t *decl) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_liveliness_process_declare_final(_z_session_t *zn, const _z_n_msg_declare_t *decl) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(decl);\n    return _Z_RES_OK;\n}\n\n#endif  // Z_FEATURE_LIVELINESS == 1\n"
  },
  {
    "path": "src/session/loopback.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/loopback.h\"\n\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/reply.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/utils/locality.h\"\n\n#if defined(Z_TEST_HOOKS)\nstatic _z_session_transport_override_fn _z_transport_common_override = NULL;\n\nvoid _z_session_set_transport_common_override(_z_session_transport_override_fn fn) {\n    _z_transport_common_override = fn;\n}\n#endif\n\n#if Z_FEATURE_SUBSCRIPTION == 1 || Z_FEATURE_QUERYABLE == 1\nstatic _z_transport_common_t *_z_session_get_transport_common(_z_session_t *zn) {\n#if defined(Z_TEST_HOOKS)\n    if (_z_transport_common_override != NULL) {\n        _z_transport_common_t *override = _z_transport_common_override(zn);\n        if (override != NULL) {\n            return override;\n        }\n    }\n#endif\n    switch (zn->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            return &zn->_tp._transport._unicast._common;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            return &zn->_tp._transport._multicast._common;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            return &zn->_tp._transport._raweth._common;\n        default:\n            break;\n    }\n    return NULL;\n}\n\n#else\nstatic _z_transport_common_t *_z_session_get_transport_common(_z_session_t *zn) {\n    _ZP_UNUSED(zn);\n    return NULL;\n}\n#endif  // Z_FEATURE_SUBSCRIPTION == 1 || Z_FEATURE_QUERYABLE == 1\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_LOCAL_SUBSCRIBER == 1\nz_result_t _z_session_deliver_push_locally(_z_session_t *zn, const _z_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                                           _z_encoding_t *encoding, z_sample_kind_t kind, _z_n_qos_t qos,\n                                           const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                                           z_reliability_t reliability, const _z_source_info_t *source_info) {\n    _z_transport_common_t *transport = _z_session_get_transport_common(zn);\n    if (transport == NULL) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_wireexpr_t wireexpr = _z_keyexpr_alias_to_wire(keyexpr);\n    _z_bytes_t payload2 = payload == NULL ? _z_bytes_null() : _z_bytes_steal(payload);\n    _z_bytes_t attachment2 = attachment == NULL ? _z_bytes_null() : _z_bytes_steal(attachment);\n    _z_encoding_t encoding2 = encoding == NULL ? _z_encoding_null() : _z_encoding_steal(encoding);\n\n    _z_network_message_t msg;\n    switch (kind) {\n        case Z_SAMPLE_KIND_PUT: {\n            _z_n_msg_make_push_put(&msg, &wireexpr, &payload2, &encoding2, qos, timestamp, &attachment2, reliability,\n                                   source_info);\n            break;\n        }\n        case Z_SAMPLE_KIND_DELETE: {\n            _z_n_msg_make_push_del(&msg, &wireexpr, qos, timestamp, reliability, source_info);\n            break;\n        }\n        default:\n            return _Z_ERR_INVALID;\n    }\n\n    return _z_handle_network_message(transport, &msg, NULL);\n}\n#else\nz_result_t _z_session_deliver_push_locally(_z_session_t *zn, const _z_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                                           _z_encoding_t *encoding, z_sample_kind_t kind, _z_n_qos_t qos,\n                                           const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                                           z_reliability_t reliability, const _z_source_info_t *source_info) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(keyexpr);\n    _ZP_UNUSED(payload);\n    _ZP_UNUSED(encoding);\n    _ZP_UNUSED(kind);\n    _ZP_UNUSED(qos);\n    _ZP_UNUSED(timestamp);\n    _ZP_UNUSED(attachment);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(source_info);\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n\n#if Z_FEATURE_QUERYABLE == 1 && Z_FEATURE_LOCAL_QUERYABLE == 1\nz_result_t _z_session_deliver_query_locally(_z_session_t *zn, const _z_keyexpr_t *keyexpr, const _z_slice_t *parameters,\n                                            z_consolidation_mode_t consolidation, _z_bytes_t *payload,\n                                            _z_encoding_t *encoding, _z_bytes_t *attachment,\n                                            const _z_source_info_t *source_info, _z_zint_t qid, uint64_t timeout_ms,\n                                            _z_n_qos_t qos, bool implicit_anyke) {\n    _z_transport_common_t *transport = _z_session_get_transport_common(zn);\n    if (transport == NULL) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_wireexpr_t wireexpr = _z_keyexpr_alias_to_wire(keyexpr);\n    _z_slice_t parameters2 = parameters == NULL ? _z_slice_null() : _z_slice_alias(*parameters);\n    _z_bytes_t payload2 = payload == NULL ? _z_bytes_null() : _z_bytes_steal(payload);\n    _z_bytes_t attachment2 = attachment == NULL ? _z_bytes_null() : _z_bytes_steal(attachment);\n    _z_encoding_t encoding2 = encoding == NULL ? _z_encoding_null() : _z_encoding_steal(encoding);\n\n    _z_zenoh_message_t msg;\n    _z_n_msg_make_query(&msg, &wireexpr, &parameters2, qid, Z_RELIABILITY_DEFAULT, consolidation, &payload2, &encoding2,\n                        timeout_ms, &attachment2, qos, source_info, implicit_anyke);\n\n    return _z_handle_network_message(transport, &msg, NULL);\n}\n#else\nz_result_t _z_session_deliver_query_locally(_z_session_t *zn, const _z_keyexpr_t *keyexpr, const _z_slice_t *parameters,\n                                            z_consolidation_mode_t consolidation, _z_bytes_t *payload,\n                                            _z_encoding_t *encoding, _z_bytes_t *attachment,\n                                            const _z_source_info_t *source_info, _z_zint_t qid, uint64_t timeout_ms,\n                                            _z_n_qos_t qos, bool implicit_anyke) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(keyexpr);\n    _ZP_UNUSED(parameters);\n    _ZP_UNUSED(consolidation);\n    _ZP_UNUSED(payload);\n    _ZP_UNUSED(encoding);\n    _ZP_UNUSED(attachment);\n    _ZP_UNUSED(source_info);\n    _ZP_UNUSED(qid);\n    _ZP_UNUSED(timeout_ms);\n    _ZP_UNUSED(qos);\n    _ZP_UNUSED(implicit_anyke);\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_QUERYABLE == 1\n\n#if Z_FEATURE_QUERY == 1\nz_result_t _z_session_deliver_reply_locally(const _z_query_t *query, const _z_session_rc_t *zn,\n                                            const _z_declared_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                                            _z_encoding_t *encoding, z_sample_kind_t kind, _z_n_qos_t qos,\n                                            const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                                            const _z_source_info_t *source_info) {\n    _z_transport_common_t *transport = _z_session_get_transport_common(_Z_RC_IN_VAL(zn));\n    if (transport == NULL) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(keyexpr, _Z_RC_IN_VAL(zn));\n    _z_bytes_t payload2 = payload == NULL ? _z_bytes_null() : _z_bytes_steal(payload);\n    _z_bytes_t attachment2 = attachment == NULL ? _z_bytes_null() : _z_bytes_steal(attachment);\n    _z_encoding_t encoding2 = encoding == NULL ? _z_encoding_null() : _z_encoding_steal(encoding);\n\n    _z_network_message_t msg;\n    switch (kind) {\n        case Z_SAMPLE_KIND_PUT:\n            _z_n_msg_make_reply_ok_put(&msg, &_Z_RC_IN_VAL(zn)->_local_zid, query->_request_id, &wireexpr,\n                                       Z_RELIABILITY_DEFAULT, Z_CONSOLIDATION_MODE_DEFAULT, qos, timestamp, source_info,\n                                       &payload2, &encoding2, &attachment2);\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            _z_n_msg_make_reply_ok_del(&msg, &_Z_RC_IN_VAL(zn)->_local_zid, query->_request_id, &wireexpr,\n                                       Z_RELIABILITY_DEFAULT, Z_CONSOLIDATION_MODE_DEFAULT, qos, timestamp, source_info,\n                                       &attachment2);\n            break;\n        default:\n            return _Z_ERR_INVALID;\n    }\n\n    return _z_handle_network_message(transport, &msg, NULL);\n}\n\nz_result_t _z_session_deliver_reply_err_locally(const _z_query_t *query, const _z_session_rc_t *zn, _z_bytes_t *payload,\n                                                _z_encoding_t *encoding, _z_n_qos_t qos) {\n    _z_transport_common_t *transport = _z_session_get_transport_common(_Z_RC_IN_VAL(zn));\n    if (transport == NULL) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_bytes_t payload2 = payload == NULL ? _z_bytes_null() : _z_bytes_steal(payload);\n    _z_encoding_t encoding2 = encoding == NULL ? _z_encoding_null() : _z_encoding_steal(encoding);\n\n    _z_network_message_t msg;\n    _z_n_msg_make_reply_err(&msg, &_Z_RC_IN_VAL(zn)->_local_zid, query->_request_id, Z_RELIABILITY_DEFAULT, qos,\n                            &payload2, &encoding2, NULL);\n    return _z_handle_network_message(transport, &msg, NULL);\n}\n\nz_result_t _z_session_deliver_reply_final_locally(_z_session_t *zn, _z_zint_t rid) {\n    if (zn == NULL) {\n        return _Z_ERR_INVALID;\n    }\n    return _z_trigger_query_reply_final(zn, rid);\n}\n#else\nz_result_t _z_session_deliver_reply_locally(const _z_query_t *query, const _z_session_rc_t *responder,\n                                            const _z_declared_keyexpr_t *keyexpr, _z_bytes_t *payload,\n                                            _z_encoding_t *encoding, z_sample_kind_t kind, _z_n_qos_t qos,\n                                            const _z_timestamp_t *timestamp, _z_bytes_t *attachment,\n                                            const _z_source_info_t *source_info) {\n    _ZP_UNUSED(query);\n    _ZP_UNUSED(responder);\n    _ZP_UNUSED(keyexpr);\n    _ZP_UNUSED(payload);\n    _ZP_UNUSED(encoding);\n    _ZP_UNUSED(kind);\n    _ZP_UNUSED(qos);\n    _ZP_UNUSED(timestamp);\n    _ZP_UNUSED(attachment);\n    _ZP_UNUSED(source_info);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_session_deliver_reply_err_locally(const _z_query_t *query, const _z_session_rc_t *zn, _z_bytes_t *payload,\n                                                _z_encoding_t *encoding, _z_n_qos_t qos) {\n    _ZP_UNUSED(query);\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(payload);\n    _ZP_UNUSED(encoding);\n    _ZP_UNUSED(qos);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_session_deliver_reply_final_locally(_z_session_t *zn, _z_zint_t rid) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(rid);\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_QUERY == 1\n"
  },
  {
    "path": "src/session/push.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/push.h\"\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nz_result_t _z_trigger_push(_z_session_t *zn, _z_n_msg_push_t *push, z_reliability_t reliability,\n                           _z_transport_peer_common_t *peer) {\n    z_result_t ret = _Z_RES_OK;\n\n    // Memory cleaning must be done in the feature layer\n    if (push->_body._is_put) {\n        _z_msg_put_t *put = &push->_body._body._put;\n        ret =\n            _z_trigger_subscriptions_put(zn, &push->_key, &put->_payload, &put->_encoding, &put->_commons._timestamp,\n                                         push->_qos, &put->_attachment, reliability, &put->_commons._source_info, peer);\n    } else {\n        _z_msg_del_t *del = &push->_body._body._del;\n        ret = _z_trigger_subscriptions_del(zn, &push->_key, &del->_commons._timestamp, push->_qos, &del->_attachment,\n                                           reliability, &del->_commons._source_info, peer);\n    }\n    return ret;\n}\n#else\nz_result_t _z_trigger_push(_z_session_t *zn, _z_n_msg_push_t *push, z_reliability_t reliability,\n                           _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(push);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n#endif\n"
  },
  {
    "path": "src/session/query.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/query.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/reply.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_QUERY == 1\nvoid _z_pending_query_clear(_z_pending_query_t *pen_qry) {\n    if (pen_qry->_dropper != NULL) {\n        pen_qry->_dropper(pen_qry->_arg);\n        pen_qry->_dropper = NULL;\n    }\n    _z_keyexpr_clear(&pen_qry->_key);\n    _z_pending_reply_slist_free(&pen_qry->_pending_replies);\n    pen_qry->_allowed_destination = z_locality_default();\n    pen_qry->_remaining_finals = 0;\n#ifdef Z_FEATURE_UNSTABLE_API\n    _z_pending_query_cancellation_data_clear(&pen_qry->_cancellation_data);\n#endif\n}\n\nbool _z_pending_query_eq(const _z_pending_query_t *one, const _z_pending_query_t *two) { return one->_id == two->_id; }\nbool _z_pending_query_querier_eq(const _z_pending_query_t *one, const _z_pending_query_t *two) {\n    return one->_querier_id.has_value == two->_querier_id.has_value && one->_querier_id.value == two->_querier_id.value;\n}\n\nstatic bool _z_pending_query_timeout(const _z_pending_query_t *foo, const _z_pending_query_t *pq) {\n    _ZP_UNUSED(foo);\n    bool result = z_clock_elapsed_ms((z_clock_t *)&pq->_start_time) >= pq->_timeout;\n    if (result) {\n        _Z_INFO(\"Dropping query because of timeout\");\n    }\n    return result;\n}\n\nvoid _z_pending_query_process_timeout(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n    // Extract all queries with timeout elapsed\n    zn->_pending_queries = _z_pending_query_slist_drop_all_filter(zn->_pending_queries, _z_pending_query_timeout, NULL);\n    _z_session_mutex_unlock(zn);\n}\n\n_z_fut_fn_result_t _z_pending_query_process_timeout_task_fn(void *session_arg, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n    _z_session_t *zn = (_z_session_t *)session_arg;\n    _z_pending_query_process_timeout(zn);\n    return _z_fut_fn_result_wake_up_after(1000);\n}\n\n/*------------------ Query ------------------*/\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\n_z_pending_query_t *_z_unsafe_get_pending_query_by_id(_z_session_t *zn, const _z_zint_t id) {\n    _z_pending_query_t *ret = NULL;\n\n    _z_pending_query_slist_t *xs = zn->_pending_queries;\n    while (xs != NULL) {\n        _z_pending_query_t *pql = _z_pending_query_slist_value(xs);\n        if (pql->_id == id) {\n            ret = pql;\n            break;\n        }\n\n        xs = _z_pending_query_slist_next(xs);\n    }\n    return ret;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\n_z_pending_query_t *_z_unsafe_register_pending_query(_z_session_t *zn) {\n    _z_zint_t qid = zn->_query_id++;\n    zn->_pending_queries = _z_pending_query_slist_push_empty(zn->_pending_queries);\n    _z_pending_query_t *pq = _z_pending_query_slist_value(zn->_pending_queries);\n    pq->_id = qid;\n    return pq;\n}\n\nstatic z_result_t _z_trigger_query_reply_partial_inner(_z_session_t *zn, const _z_zint_t id, _z_keyexpr_t *keyexpr,\n                                                       _z_msg_put_t *msg, z_sample_kind_t kind,\n                                                       _z_entity_global_id_t *replier_id) {\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(keyexpr); _z_msg_put_clear(msg));\n\n    // Get query infos\n    _z_pending_query_t *pen_qry = _z_unsafe_get_pending_query_by_id(zn, id);\n    if (pen_qry == NULL) {\n        _z_session_mutex_unlock(zn);\n        _z_keyexpr_clear(keyexpr);\n        _z_msg_put_clear(msg);\n        // Not concerned by the reply\n        return _Z_RES_OK;\n    }\n\n    if (!pen_qry->_anyke && !_z_keyexpr_intersects(&pen_qry->_key, keyexpr)) {\n        _z_session_mutex_unlock(zn);\n        _z_keyexpr_clear(keyexpr);\n        _z_msg_put_clear(msg);\n        // Not concerned by the reply\n        return _Z_RES_OK;\n    }\n    // Build the reply\n    _z_reply_t reply;\n    _z_reply_steal_data(&reply, keyexpr, *replier_id, &msg->_payload, &msg->_commons._timestamp, &msg->_encoding, kind,\n                        &msg->_attachment, &msg->_commons._source_info);\n    // Process monotonic & latest consolidation mode\n    if ((pen_qry->_consolidation == Z_CONSOLIDATION_MODE_LATEST) ||\n        (pen_qry->_consolidation == Z_CONSOLIDATION_MODE_MONOTONIC)) {\n        bool drop = false;\n        _z_pending_reply_slist_t *curr_node = pen_qry->_pending_replies;\n        _z_pending_reply_t *pen_rep = NULL;\n\n        // Verify if this is a newer reply, free the old one in case it is\n        while (curr_node != NULL) {\n            pen_rep = _z_pending_reply_slist_value(curr_node);\n            // Check if this is the same resource key\n            if (_z_declared_keyexpr_equals(&pen_rep->_reply.data._result.sample.keyexpr,\n                                           &reply.data._result.sample.keyexpr)) {\n                if (msg->_commons._timestamp.time <= pen_rep->_tstamp.time) {\n                    drop = true;\n                } else {\n                    pen_qry->_pending_replies = _z_pending_reply_slist_drop_first_filter(pen_qry->_pending_replies,\n                                                                                         _z_pending_reply_eq, pen_rep);\n                }\n                break;\n            }\n            curr_node = _z_pending_reply_slist_next(curr_node);\n        }\n        if (!drop) {\n            // Cache most recent reply\n            _z_pending_reply_t tmp_rep;\n            if (pen_qry->_consolidation == Z_CONSOLIDATION_MODE_MONOTONIC) {\n                // No need to store the whole reply in the monotonic mode.\n                tmp_rep._reply = _z_reply_null();\n                tmp_rep._reply.data._tag = _Z_REPLY_TAG_DATA;\n                _Z_CLEAN_RETURN_IF_ERR(_z_declared_keyexpr_copy(&tmp_rep._reply.data._result.sample.keyexpr,\n                                                                &reply.data._result.sample.keyexpr),\n                                       _z_reply_clear(&reply);\n                                       _z_session_mutex_unlock(zn));\n            } else {\n                // Copy the reply to store it out of context\n                _Z_CLEAN_RETURN_IF_ERR(_z_reply_move(&tmp_rep._reply, &reply), _z_reply_clear(&reply);\n                                       _z_session_mutex_unlock(zn));\n            }\n            tmp_rep._tstamp = _z_timestamp_duplicate(&msg->_commons._timestamp);\n            pen_qry->_pending_replies = _z_pending_reply_slist_push(pen_qry->_pending_replies, &tmp_rep);\n            _Z_DEBUG(\"stored reply for id=%jd consolidation=%d\", (intmax_t)id, pen_qry->_consolidation);\n        }\n    }\n    _z_session_mutex_unlock(zn);\n\n    // Trigger callback if applicable\n    if (pen_qry->_consolidation != Z_CONSOLIDATION_MODE_LATEST) {\n        _Z_DEBUG(\"immediate callback for id=%jd\", (intmax_t)id);\n        pen_qry->_callback(&reply, pen_qry->_arg);\n    }\n    _z_reply_clear(&reply);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_trigger_query_reply_partial(_z_session_t *zn, const _z_zint_t id, _z_wireexpr_t *wireexpr,\n                                          _z_msg_put_t *msg, z_sample_kind_t kind, _z_entity_global_id_t *replier_id,\n                                          _z_transport_peer_common_t *peer) {\n    _z_keyexpr_t keyexpr;\n    z_result_t ret = _z_get_keyexpr_from_wireexpr(zn, &keyexpr, wireexpr, peer, true);\n\n    _Z_SET_IF_OK(ret, _z_trigger_query_reply_partial_inner(zn, id, &keyexpr, msg, kind, replier_id));\n    // Clean up\n    _z_keyexpr_clear(&keyexpr);\n    _z_wireexpr_clear(wireexpr);\n    _z_msg_put_clear(msg);\n    return ret;\n}\n\nz_result_t _z_trigger_query_reply_err(_z_session_t *zn, _z_zint_t id, _z_msg_err_t *msg,\n                                      _z_entity_global_id_t *replier_id) {\n    // Retrieve query\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_bytes_drop(&msg->_payload);\n                           _z_encoding_clear(&msg->_encoding));\n    _z_pending_query_t *pen_qry = _z_unsafe_get_pending_query_by_id(zn, id);\n    _z_session_mutex_unlock(zn);\n    if (pen_qry == NULL) {\n        // Not concerned by the reply\n        _z_bytes_drop(&msg->_payload);\n        _z_encoding_clear(&msg->_encoding);\n        return _Z_RES_OK;\n    }\n    // Trigger the user callback\n    _z_reply_t reply;\n    _z_reply_err_steal_data(&reply, &msg->_payload, &msg->_encoding, *replier_id);\n    pen_qry->_callback(&reply, pen_qry->_arg);\n    _z_reply_clear(&reply);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_trigger_query_reply_final(_z_session_t *zn, _z_zint_t id) {\n    // Retrieve query\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    _z_pending_query_t *pen_qry = _z_unsafe_get_pending_query_by_id(zn, id);\n    if (pen_qry == NULL) {\n        _z_session_mutex_unlock(zn);\n        // Not concerned by the reply\n        return _Z_RES_OK;\n    }\n    _Z_DEBUG(\"trigger_reply_final id=%jd\", (intmax_t)id);\n\n    if (pen_qry->_remaining_finals > 0) {\n        pen_qry->_remaining_finals--;\n    }\n\n    bool do_finalize = (pen_qry->_remaining_finals == 0);\n\n    if (pen_qry->_consolidation == Z_CONSOLIDATION_MODE_LATEST && do_finalize) {\n        while (pen_qry->_pending_replies != NULL) {\n            _z_pending_reply_t *pen_rep = _z_pending_reply_slist_value(pen_qry->_pending_replies);\n\n            // Trigger the query handler\n            _Z_DEBUG(\"deliver pending reply in final id=%jd\", (intmax_t)id);\n            pen_qry->_callback(&pen_rep->_reply, pen_qry->_arg);\n            pen_qry->_pending_replies = _z_pending_reply_slist_pop(pen_qry->_pending_replies);\n        }\n    }\n    // Finalize query if requested: drop pending query and trigger dropper callback,\n    // which is equivalent to a reply with FINAL.\n    if (do_finalize) {\n        zn->_pending_queries =\n            _z_pending_query_slist_drop_first_filter(zn->_pending_queries, _z_pending_query_eq, pen_qry);\n    }\n    _z_session_mutex_unlock(zn);\n    return _Z_RES_OK;\n}\n\nvoid _z_unregister_pending_query(_z_session_t *zn, _z_zint_t qid) {\n    _z_pending_query_t target = {0};\n    target._id = qid;\n    _z_session_mutex_lock(zn);\n    zn->_pending_queries = _z_pending_query_slist_drop_first_filter(zn->_pending_queries, _z_pending_query_eq, &target);\n    _z_session_mutex_unlock(zn);\n}\n\nvoid _z_unregister_pending_queries_from_querier(_z_session_t *zn, uint32_t querier_id) {\n    _z_pending_query_t target = {0};\n    target._querier_id = _z_optional_id_make_some(querier_id);\n    _z_session_mutex_lock(zn);\n    zn->_pending_queries =\n        _z_pending_query_slist_drop_all_filter(zn->_pending_queries, _z_pending_query_querier_eq, &target);\n    _z_session_mutex_unlock(zn);\n}\n\nvoid _z_flush_pending_queries(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n    _z_pending_query_slist_t *queries = zn->_pending_queries;\n    zn->_pending_queries = _z_pending_query_slist_new();\n    _z_session_mutex_unlock(zn);\n    _z_pending_query_slist_free(&queries);\n}\n#ifdef Z_FEATURE_UNSTABLE_API\n\ntypedef struct _z_cancel_pending_query_arg_t {\n    _z_session_weak_t _zn;\n    _z_zint_t _qid;\n} _z_cancel_pending_query_arg_t;\n\nz_result_t _z_cancel_pending_query(void *arg) {\n    _z_cancel_pending_query_arg_t *a = (_z_cancel_pending_query_arg_t *)arg;\n    _z_session_rc_t s_rc = _z_session_weak_upgrade_if_open(&a->_zn);\n    if (!_Z_RC_IS_NULL(&s_rc)) {\n        _z_unregister_pending_query(_Z_RC_IN_VAL(&s_rc), a->_qid);\n    }\n    _z_session_rc_drop(&s_rc);\n    return _Z_RES_OK;\n}\n\nvoid _z_cancel_pending_query_arg_drop(void *arg) {\n    _z_cancel_pending_query_arg_t *a = (_z_cancel_pending_query_arg_t *)arg;\n    _z_session_weak_drop(&a->_zn);\n    z_free(a);\n}\n\nz_result_t _z_pending_query_register_cancellation(_z_pending_query_t *pq,\n                                                  const _z_cancellation_token_rc_t *opt_cancellation_token,\n                                                  const _z_session_rc_t *zn) {\n    pq->_cancellation_data = _z_pending_query_cancellation_data_null();\n    if (opt_cancellation_token != NULL) {\n        _z_cancel_pending_query_arg_t *arg =\n            (_z_cancel_pending_query_arg_t *)z_malloc(sizeof(_z_cancel_pending_query_arg_t));\n        if (arg == NULL) {\n            return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        }\n        arg->_zn = _z_session_rc_clone_as_weak(zn);\n        arg->_qid = pq->_id;\n\n        size_t handler_id = 0;\n        _z_cancellation_token_on_cancel_handler_t handler;\n        handler._on_cancel = _z_cancel_pending_query;\n        handler._on_drop = _z_cancel_pending_query_arg_drop;\n        handler._arg = (void *)arg;\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_cancellation_token_add_on_cancel_handler(_Z_RC_IN_VAL(opt_cancellation_token), &handler, &handler_id),\n            _z_cancellation_token_on_cancel_handler_drop(&handler));\n        pq->_cancellation_data._cancellation_token = _z_cancellation_token_rc_clone(opt_cancellation_token);\n        pq->_cancellation_data._handler_id = handler_id;\n        _Z_CLEAN_RETURN_IF_ERR(\n            _z_cancellation_token_get_notifier(_Z_RC_IN_VAL(opt_cancellation_token), &pq->_cancellation_data._notifier),\n            _z_pending_query_cancellation_data_clear(&pq->_cancellation_data));\n    }\n    return _Z_RES_OK;\n}\n#endif\n\n#else\n\nvoid _z_pending_query_process_timeout(_z_session_t* zn) {\n    _ZP_UNUSED(zn);\n    return;\n}\n\n#endif\n"
  },
  {
    "path": "src/session/queryable.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/query.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#if Z_FEATURE_QUERYABLE == 1\n\n#define _Z_QLEINFOS_VEC_SIZE 4  // Arbitrary initial size\n\nstatic inline _z_queryable_cache_data_t _z_queryable_cache_data_null(void) {\n    _z_queryable_cache_data_t ret = {0};\n    return ret;\n}\n\nvoid _z_unsafe_queryable_cache_invalidate(_z_session_t *zn) {\n#if Z_FEATURE_RX_CACHE == 1\n    _z_queryable_lru_cache_clear(&zn->_queryable_cache);\n#else\n    _ZP_UNUSED(zn);\n#endif\n}\n\n#if Z_FEATURE_RX_CACHE == 1\nint _z_queryable_cache_data_compare(const void *first, const void *second) {\n    const _z_queryable_cache_data_t *first_data = (const _z_queryable_cache_data_t *)first;\n    const _z_queryable_cache_data_t *second_data = (const _z_queryable_cache_data_t *)second;\n    if (first_data->is_remote != second_data->is_remote) {\n        return (int)first_data->is_remote - (int)second_data->is_remote;\n    }\n    return _z_keyexpr_compare(&first_data->ke, &second_data->ke);\n}\n#endif  // Z_FEATURE_RX_CACHE == 1\n\nvoid _z_queryable_cache_data_clear(_z_queryable_cache_data_t *val) {\n    _z_session_queryable_rc_svec_rc_drop(&val->infos);\n    _z_keyexpr_clear(&val->ke);\n}\n\nbool _z_session_queryable_eq(const _z_session_queryable_t *one, const _z_session_queryable_t *two) {\n    return one->_id == two->_id;\n}\n\nvoid _z_session_queryable_clear(_z_session_queryable_t *qle) {\n    if (qle->_dropper != NULL) {\n        qle->_dropper(qle->_arg);\n        qle->_dropper = NULL;\n    }\n    _z_declared_keyexpr_clear(&qle->_key);\n    _z_sync_group_notifier_drop(&qle->_session_callback_drop_notifier);\n    _z_sync_group_notifier_drop(&qle->_queryable_callback_drop_notifier);\n}\n\n/*------------------ Queryable ------------------*/\nstatic _z_session_queryable_rc_t *__z_get_session_queryable_by_id(_z_session_queryable_rc_slist_t *qles,\n                                                                  const _z_zint_t id) {\n    _z_session_queryable_rc_t *ret = NULL;\n\n    _z_session_queryable_rc_slist_t *xs = qles;\n    while (xs != NULL) {\n        _z_session_queryable_rc_t *qle = _z_session_queryable_rc_slist_value(xs);\n        if (id == _Z_RC_IN_VAL(qle)->_id) {\n            ret = qle;\n            break;\n        }\n        xs = _z_session_queryable_rc_slist_next(xs);\n    }\n\n    return ret;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic _z_session_queryable_rc_t *__unsafe_z_get_session_queryable_by_id(_z_session_t *zn, const _z_zint_t id) {\n    _z_session_queryable_rc_slist_t *qles = zn->_local_queryable;\n    return __z_get_session_queryable_by_id(qles, id);\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic z_result_t __unsafe_z_get_session_queryables_by_key(_z_session_t *zn, const _z_keyexpr_t *key, bool is_remote,\n                                                           _z_session_queryable_rc_svec_t *qle_infos) {\n    _z_session_queryable_rc_slist_t *qles = zn->_local_queryable;\n\n    *qle_infos = _z_session_queryable_rc_svec_make(_Z_QLEINFOS_VEC_SIZE);\n    _Z_RETURN_ERR_OOM_IF_TRUE(qle_infos->_val == NULL);\n    _z_session_queryable_rc_slist_t *xs = qles;\n    while (xs != NULL) {\n        // Parse queryable list\n        _z_session_queryable_rc_t *qle = _z_session_queryable_rc_slist_value(xs);\n        const _z_session_queryable_t *qle_val = _Z_RC_IN_VAL(qle);\n        bool origin_allowed = is_remote ? _z_locality_allows_remote(qle_val->_allowed_origin)\n                                        : _z_locality_allows_local(qle_val->_allowed_origin);\n        if (origin_allowed && _z_keyexpr_intersects(&qle_val->_key._inner, key)) {\n            _z_session_queryable_rc_t qle_clone = _z_session_queryable_rc_clone(qle);\n            _Z_CLEAN_RETURN_IF_ERR(_z_session_queryable_rc_svec_append(qle_infos, &qle_clone, false),\n                                   _z_session_queryable_rc_svec_clear(qle_infos));\n        }\n        xs = _z_session_queryable_rc_slist_next(xs);\n    }\n    return _Z_RES_OK;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic z_result_t __unsafe_z_get_session_queryables_rc_by_key(_z_session_t *zn, const _z_keyexpr_t *key, bool is_remote,\n                                                              _z_session_queryable_rc_svec_rc_t *qle_infos) {\n    *qle_infos = _z_session_queryable_rc_svec_rc_new_undefined();\n    z_result_t ret = !_Z_RC_IS_NULL(qle_infos) ? _Z_RES_OK : _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    _Z_SET_IF_OK(ret, __unsafe_z_get_session_queryables_by_key(zn, key, is_remote, _Z_RC_IN_VAL(qle_infos)));\n    if (ret != _Z_RES_OK) {\n        _z_session_queryable_rc_svec_rc_drop(qle_infos);\n    }\n    return _Z_RES_OK;\n}\n\n_z_session_queryable_rc_t _z_get_session_queryable_by_id(_z_session_t *zn, const _z_zint_t id) {\n    _z_session_queryable_rc_t out = _z_session_queryable_rc_null();\n    _z_session_mutex_lock(zn);\n\n    _z_session_queryable_rc_t *qle = __unsafe_z_get_session_queryable_by_id(zn, id);\n    if (qle != NULL) {\n        out = _z_session_queryable_rc_clone(qle);\n    }\n    _z_session_mutex_unlock(zn);\n\n    return out;\n}\n\n_z_session_queryable_rc_t _z_register_session_queryable(_z_session_t *zn, _z_session_queryable_t *q) {\n    _Z_DEBUG(\">>> Allocating queryable for (%.*s)\", (int)_z_string_len(&q->_key._inner._keyexpr),\n             _z_string_data(&q->_key._inner._keyexpr));\n\n    _z_session_queryable_rc_t out = _z_session_queryable_rc_new_from_val(q);\n    if (_Z_RC_IS_NULL(&out)) {\n        return out;\n    }\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        _Z_WARN(\"Failed to acquire session mutex for registering queryable - session is closed\");\n        _z_session_queryable_rc_drop(&out);\n        *q = _z_session_queryable_null();\n        return out;\n    }\n    _z_unsafe_queryable_cache_invalidate(zn);\n    zn->_local_queryable = _z_session_queryable_rc_slist_push_empty(zn->_local_queryable);\n    _z_session_queryable_rc_t *ret = _z_session_queryable_rc_slist_value(zn->_local_queryable);\n    *ret = _z_session_queryable_rc_clone(\n        &out);  // immediately increase reference count to prevent eventual drop by concurrent session close\n    _z_session_mutex_unlock(zn);\n\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    if (!_Z_RC_IS_NULL(&out) && _z_locality_allows_local(q->_allowed_origin)) {\n        _z_session_queryable_t *qle_val = _Z_RC_IN_VAL(&out);\n        _z_write_filter_notify_queryable(zn, &qle_val->_key._inner, qle_val->_allowed_origin, qle_val->_complete, true);\n    }\n#endif\n\n    return out;\n}\n\nstatic z_result_t _z_session_queryable_get_infos(_z_session_t *zn, _z_queryable_cache_data_t *out,\n                                                 const _z_wireexpr_t *wireexpr, _z_transport_peer_common_t *peer) {\n    out->is_remote = (peer != NULL);\n    _Z_RETURN_IF_ERR(_z_get_keyexpr_from_wireexpr(zn, &out->ke, wireexpr, peer, true));\n    _z_queryable_cache_data_t *cache_entry = NULL;\n    z_result_t ret = _Z_RES_OK;\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&out->ke));\n#if Z_FEATURE_RX_CACHE == 1\n    cache_entry = _z_queryable_lru_cache_get(&zn->_queryable_cache, out);\n    if (cache_entry != NULL && cache_entry->is_remote != out->is_remote) {\n        cache_entry = NULL;\n    }\n#endif\n    if (cache_entry != NULL) {  // Copy cache entry\n        out->infos = _z_session_queryable_rc_svec_rc_clone(&cache_entry->infos);\n    } else {  // Build queryable data\n        _Z_SET_IF_OK(ret, __unsafe_z_get_session_queryables_rc_by_key(zn, &out->ke, out->is_remote, &out->infos));\n#if Z_FEATURE_RX_CACHE == 1\n        // Update cache\n        _z_queryable_cache_data_t cache_storage = _z_queryable_cache_data_null();\n        cache_storage.infos = _z_session_queryable_rc_svec_rc_clone(&out->infos);\n        cache_storage.is_remote = out->is_remote;\n        _Z_SET_IF_OK(ret, _z_keyexpr_copy(&cache_storage.ke, &out->ke));\n        _Z_SET_IF_OK(ret, _z_queryable_lru_cache_insert(&zn->_queryable_cache, &cache_storage));\n        if (ret != _Z_RES_OK) {\n            _z_queryable_cache_data_clear(&cache_storage);\n        }\n#endif\n    }\n    _z_session_mutex_unlock(zn);\n    if (ret != _Z_RES_OK) {\n        _z_queryable_cache_data_clear(out);\n    }\n    return ret;\n}\n\nz_result_t _z_trigger_queryables(_z_transport_common_t *transport, _z_msg_query_t *msgq, _z_wireexpr_t *q_key,\n                                 uint32_t qid, _z_n_qos_t qos, _z_transport_peer_common_t *peer) {\n    bool is_local = peer == NULL;\n    _z_session_t *zn = _z_transport_common_get_session(transport);\n    _z_queryable_cache_data_t qle_infos = _z_queryable_cache_data_null();\n    // Retrieve sub infos\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_queryable_get_infos(zn, &qle_infos, q_key, peer), _z_wireexpr_clear(q_key);\n                           _z_msg_query_clear(msgq));\n    // Check if there are queryables\n    const _z_session_queryable_rc_svec_t *qles = _Z_RC_IN_VAL(&qle_infos.infos);\n    size_t qle_nb = _z_session_queryable_rc_svec_len(qles);\n    _Z_DEBUG(\"Triggering %ju queryables for key %.*s\", (uintmax_t)qle_nb, (int)_z_string_len(&qle_infos.ke._keyexpr),\n             _z_string_data(&qle_infos.ke._keyexpr));\n\n    if (qle_nb == 0) {  // optimization for local queries, since moves can imply extra copy if aliased\n        _z_wireexpr_clear(q_key);\n        _z_queryable_cache_data_clear(&qle_infos);\n        _z_msg_query_clear(msgq);\n        _z_session_send_reply_final(zn, qid, is_local);\n        return _Z_RES_OK;\n    }\n    // Build the z_query\n    _z_query_rc_t query = _z_query_rc_new_undefined();\n    z_result_t ret = _Z_RC_IS_NULL(&query) ? _Z_ERR_SYSTEM_OUT_OF_MEMORY : _Z_RES_OK;\n    // Note: _z_query_move_data will make copies of all aliased fields, since query is under ref count\n    // and thus it is impossible to detect when user moves it out of callback\n    _Z_SET_IF_OK(ret, _z_query_move_data(_Z_RC_IN_VAL(&query), &msgq->_ext_value, &qle_infos.ke, &msgq->_parameters,\n                                         &transport->_session, qid, &msgq->_ext_attachment, msgq->_implicit_anyke,\n                                         &msgq->_ext_info));\n    _Z_CLEAN_RETURN_IF_ERR(ret, _z_wireexpr_clear(q_key); _z_msg_query_clear(msgq);\n                           _z_queryable_cache_data_clear(&qle_infos); _z_query_rc_drop(&query))\n\n    _Z_RC_IN_VAL(&query)->_qos = qos;\n    _Z_RC_IN_VAL(&query)->_is_local = is_local;\n    // Parse session_queryable svec\n    for (size_t i = 0; i < qle_nb; i++) {\n        _z_session_queryable_t *qle_info = _Z_RC_IN_VAL(_z_session_queryable_rc_svec_get(qles, i));\n        if (i + 1 == qle_nb) {\n            qle_info->_callback(&query, qle_info->_arg);\n        } else {\n            _z_query_rc_t query_copy = _z_query_rc_clone(&query);\n            qle_info->_callback(&query_copy, qle_info->_arg);\n            _z_query_rc_drop(&query_copy);\n        }\n    }\n    _z_wireexpr_clear(q_key);\n    _z_query_rc_drop(&query);\n    _z_queryable_cache_data_clear(&qle_infos);\n    return _Z_RES_OK;\n}\n\nvoid _z_unregister_session_queryable(_z_session_t *zn, _z_session_queryable_rc_t *qle) {\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    _z_session_queryable_t *qle_val = _Z_RC_IN_VAL(qle);\n    _z_write_filter_notify_queryable(zn, &qle_val->_key._inner, qle_val->_allowed_origin, qle_val->_complete, false);\n#endif\n    _z_session_mutex_lock(zn);\n    _z_unsafe_queryable_cache_invalidate(zn);\n    zn->_local_queryable =\n        _z_session_queryable_rc_slist_drop_first_filter(zn->_local_queryable, _z_session_queryable_rc_eq, qle);\n    _z_session_mutex_unlock(zn);\n    _z_session_queryable_rc_drop(qle);\n}\n\nvoid _z_flush_session_queryable(_z_session_t *zn) {\n    _z_session_queryable_rc_slist_t *queryables;\n    _z_session_mutex_lock(zn);\n    _z_unsafe_queryable_cache_invalidate(zn);\n    queryables = zn->_local_queryable;\n    zn->_local_queryable = _z_session_queryable_rc_slist_new();\n    _z_session_mutex_unlock(zn);\n    _z_session_queryable_rc_slist_free(&queryables);\n}\n#else  //  Z_FEATURE_QUERYABLE == 0\n\nvoid _z_unsafe_queryable_cache_invalidate(_z_session_t *zn) { _ZP_UNUSED(zn); }\n\n#endif  // Z_FEATURE_QUERYABLE == 1\n"
  },
  {
    "path": "src/session/reply.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/reply.h\"\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nz_result_t _z_trigger_reply_partial(_z_session_t *zn, _z_zint_t id, _z_wireexpr_t *key, _z_msg_reply_t *reply,\n                                    _z_entity_global_id_t *replier_id, _z_transport_peer_common_t *peer) {\n    z_result_t ret = _Z_RES_OK;\n\n#if Z_FEATURE_QUERY == 1\n    ret = _z_trigger_query_reply_partial(zn, id, key, &reply->_body._body._put,\n                                         (reply->_body._is_put ? Z_SAMPLE_KIND_PUT : Z_SAMPLE_KIND_DELETE), replier_id,\n                                         peer);\n#else\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(id);\n    _ZP_UNUSED(key);\n    _ZP_UNUSED(reply);\n    _ZP_UNUSED(replier_id);\n    _ZP_UNUSED(peer);\n#endif\n    return ret;\n}\n\nz_result_t _z_trigger_reply_err(_z_session_t *zn, _z_zint_t id, _z_msg_err_t *error,\n                                _z_entity_global_id_t *replier_id) {\n    z_result_t ret = _Z_RES_OK;\n\n#if Z_FEATURE_QUERY == 1\n    ret = _z_trigger_query_reply_err(zn, id, error, replier_id);\n#else\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(id);\n    _ZP_UNUSED(error);\n    _ZP_UNUSED(replier_id);\n#endif\n    return ret;\n}\n\nz_result_t _z_trigger_reply_final(_z_session_t *zn, _z_n_msg_response_final_t *final) {\n    z_result_t ret = _Z_RES_OK;\n\n#if Z_FEATURE_QUERY == 1\n    // TODO check id to know where to dispatch\n    _z_zint_t id = final->_request_id;\n    _z_trigger_query_reply_final(zn, id);\n#else\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(final);\n#endif\n    return ret;\n}\n"
  },
  {
    "path": "src/session/resource.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/resource.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nbool _z_resource_eq(const _z_resource_t *other, const _z_resource_t *this_) { return this_->_id == other->_id; }\n\nvoid _z_resource_clear(_z_resource_t *res) { _z_keyexpr_clear(&res->_key); }\n\nsize_t _z_resource_size(_z_resource_t *p) {\n    _ZP_UNUSED(p);\n    return sizeof(_z_resource_t);\n}\n\nvoid _z_resource_copy(_z_resource_t *dst, const _z_resource_t *src) {\n    _z_keyexpr_copy(&dst->_key, &src->_key);\n    dst->_id = src->_id;\n}\n\nvoid _z_resource_free(_z_resource_t **res) {\n    _z_resource_t *ptr = *res;\n\n    if (ptr != NULL) {\n        _z_resource_clear(ptr);\n\n        z_free(ptr);\n        *res = NULL;\n    }\n}\n\n/*------------------ Entity ------------------*/\nuint32_t _z_get_entity_id(_z_session_t *zn) { return zn->_entity_id++; }\n\nuint16_t _z_get_resource_id(_z_session_t *zn) { return zn->_resource_id++; }\n\n/*------------------ Resource ------------------*/\n_z_resource_t *_z_get_resource_by_id_inner(_z_resource_slist_t *rl, const _z_zint_t id) {\n    _z_resource_t *ret = NULL;\n\n    _z_resource_slist_t *xs = rl;\n    while (xs != NULL) {\n        _z_resource_t *r = _z_resource_slist_value(xs);\n        if (r->_id == id) {\n            ret = r;\n            break;\n        }\n\n        xs = _z_resource_slist_next(xs);\n    }\n\n    return ret;\n}\n\n_z_resource_t *_z_get_resource_by_key_inner(_z_resource_slist_t *rl, const _z_keyexpr_t *keyexpr) {\n    _z_resource_t *ret = NULL;\n    _z_resource_slist_t *xs = rl;\n    while (xs != NULL) {\n        _z_resource_t *r = _z_resource_slist_value(xs);\n        if (_z_keyexpr_equals(&r->_key, keyexpr)) {\n            ret = r;\n            break;\n        }\n\n        xs = _z_resource_slist_next(xs);\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_get_keyexpr_from_wireexpr_inner(_z_keyexpr_t *ret, _z_resource_slist_t *xs,\n                                                     const _z_wireexpr_t *expr, bool alias_wireexpr_if_possible) {\n    *ret = _z_keyexpr_null();\n    _z_zint_t id = expr->_id;\n\n    if (id == Z_RESOURCE_ID_NONE) {  // Check if ke is already expanded\n        if (alias_wireexpr_if_possible) {\n            ret->_keyexpr = _z_string_alias(expr->_suffix);\n            return _Z_RES_OK;\n        } else {\n            return _z_string_copy(&ret->_keyexpr, &expr->_suffix);\n        }\n    } else {\n        _z_resource_t *res = _z_get_resource_by_id_inner(xs, id);\n        if (res == NULL) {\n            return _Z_ERR_KEYEXPR_UNKNOWN;\n        }\n        _z_keyexpr_t ke_prefix = _z_keyexpr_alias(&res->_key);\n        return _z_string_concat(&ret->_keyexpr, &ke_prefix._keyexpr, &expr->_suffix, NULL, 0);\n    }\n}\n\nz_result_t _z_get_keyexpr_from_wireexpr(_z_session_t *zn, _z_keyexpr_t *out, const _z_wireexpr_t *expr,\n                                        _z_transport_peer_common_t *peer, bool alias_wireexpr_if_possible) {\n    *out = _z_keyexpr_null();\n    z_result_t ret = _Z_ERR_NULL;\n    if (expr != NULL && _z_wireexpr_check(expr)) {\n        _z_session_mutex_lock(zn);\n        _z_resource_slist_t *decls =\n            (_z_wireexpr_is_local(expr) || (peer == NULL)) ? zn->_local_resources : peer->_remote_resources;\n        ret = _z_get_keyexpr_from_wireexpr_inner(out, decls, expr, alias_wireexpr_if_possible);\n        _z_session_mutex_unlock(zn);\n    }\n    return ret;\n}\n\nz_result_t _z_register_resource_inner(_z_session_t *zn, const _z_wireexpr_t *expr, uint16_t id,\n                                      _z_transport_peer_common_t *peer, uint16_t *out_id) {\n    _z_resource_slist_t **resources = (peer == NULL) ? &zn->_local_resources : &peer->_remote_resources;\n    _z_resource_slist_t *parent_resources =\n        (expr->_mapping == _Z_KEYEXPR_MAPPING_LOCAL) ? zn->_local_resources : peer->_remote_resources;\n\n    _z_keyexpr_t new_key = _z_keyexpr_null();\n    if (expr->_id != Z_RESOURCE_ID_NONE) {\n        _z_resource_t *res = _z_get_resource_by_id_inner(parent_resources, expr->_id);\n        if (res == NULL) {\n            _Z_ERROR(\"Unknown scope: %d, for mapping: %zu\", (unsigned int)expr->_id, (size_t)expr->_mapping);\n            return _Z_ERR_ENTITY_DECLARATION_FAILED;\n        }\n        if (_z_wireexpr_has_suffix(expr)) {\n            if (_z_string_concat(&new_key._keyexpr, &res->_key._keyexpr, &expr->_suffix, NULL, 0) != _Z_RES_OK) {\n                _Z_ERROR(\"Failed to allocate memory for new string\");\n                return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            }\n        } else if (id == Z_RESOURCE_ID_NONE && *resources == parent_resources) {\n            // declaration of already declared resource\n            res->_refcount++;\n            *out_id = res->_id;\n            return _Z_RES_OK;\n        } else {  // redeclaration of exisiting resource\n            new_key = _z_keyexpr_alias(&res->_key);\n        }\n    } else {\n        new_key = _z_keyexpr_alias_from_string(&expr->_suffix);\n    }\n\n    if (id == Z_RESOURCE_ID_NONE) {\n        _z_resource_t *res = _z_get_resource_by_key_inner(*resources, &new_key);\n        if (res != NULL) {  // declaration of already declared resource\n            res->_refcount++;\n            _z_keyexpr_clear(&new_key);\n            *out_id = res->_id;\n            return _Z_RES_OK;\n        }\n    }\n    _z_keyexpr_t ke;\n    _Z_RETURN_IF_ERR(_z_keyexpr_move(&ke, &new_key));\n\n    *resources = _z_resource_slist_push_empty(*resources);\n    _z_resource_t *res = _z_resource_slist_value(*resources);\n    res->_refcount = 1;\n    res->_key = ke;\n    res->_id = id == Z_RESOURCE_ID_NONE ? _z_get_resource_id(zn) : id;\n    *out_id = res->_id;\n    return _Z_RES_OK;\n}\n\nz_result_t _z_register_resource(_z_session_t *zn, const _z_wireexpr_t *expr, uint16_t id,\n                                _z_transport_peer_common_t *peer, uint16_t *out_id) {\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn));\n    z_result_t ret = _z_register_resource_inner(zn, expr, id, peer, out_id);\n    _z_session_mutex_unlock(zn);\n\n    return ret;\n}\n\nz_result_t _z_unregister_resource(_z_session_t *zn, uint16_t id, _z_transport_peer_common_t *peer) {\n    bool is_local = true;\n    uintptr_t mapping = _Z_KEYEXPR_MAPPING_LOCAL;\n    if (peer != NULL) {\n        is_local = false;\n        mapping = (uintptr_t)peer;\n    }\n    _Z_DEBUG(\"unregistering: id %d, mapping: %d\", id, (unsigned int)mapping);\n    _z_session_mutex_lock(zn);\n    _z_resource_slist_t **resources = is_local ? &zn->_local_resources : &peer->_remote_resources;\n    _z_resource_t res = {0};\n    res._id = id;\n    _z_resource_slist_t *res_ptr = _z_resource_slist_find(*resources, _z_resource_eq, &res);\n    z_result_t ret = _Z_RESOURCE_POSITIVE_REF_COUNT;\n    if (res_ptr == NULL) {\n        ret = _Z_ERR_KEYEXPR_UNKNOWN;\n    } else {\n        _z_resource_slist_value(res_ptr)->_refcount--;\n        if (_z_resource_slist_value(res_ptr)->_refcount == 0) {\n            ret = _Z_RES_OK;\n            *resources = _z_resource_slist_drop_first_filter(*resources, _z_resource_eq, &res);\n        }\n    }\n    _z_session_mutex_unlock(zn);\n    return ret;\n}\n\nvoid _z_flush_local_resources(_z_session_t *zn) {\n    _z_session_mutex_lock(zn);\n    _z_resource_slist_free(&zn->_local_resources);\n    _z_session_mutex_unlock(zn);\n}\n"
  },
  {
    "path": "src/session/rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/push.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/reply.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/*------------------ Handle message ------------------*/\n\nstatic z_result_t _z_handle_declare_inner(_z_session_t *zn, _z_n_msg_declare_t *decl,\n                                          _z_transport_peer_common_t *peer) {\n    switch (decl->_decl._tag) {\n        case _Z_DECL_KEXPR: {\n            uint16_t _res_id;\n            return _z_register_resource(zn, &decl->_decl._body._decl_kexpr._keyexpr, decl->_decl._body._decl_kexpr._id,\n                                        peer, &_res_id);\n        }\n\n        case _Z_UNDECL_KEXPR:\n            _z_unregister_resource(zn, decl->_decl._body._undecl_kexpr._id, peer);\n            break;\n\n        case _Z_DECL_SUBSCRIBER:\n            return _z_interest_process_declares(zn, decl, peer);\n\n        case _Z_DECL_QUERYABLE:\n            return _z_interest_process_declares(zn, decl, peer);\n\n        case _Z_DECL_TOKEN:\n            _Z_RETURN_IF_ERR(_z_liveliness_process_token_declare(zn, decl, peer));\n            return _z_interest_process_declares(zn, decl, peer);\n\n        case _Z_UNDECL_SUBSCRIBER:\n            return _z_interest_process_undeclares(zn, &decl->_decl, peer);\n\n        case _Z_UNDECL_QUERYABLE:\n            return _z_interest_process_undeclares(zn, &decl->_decl, peer);\n\n        case _Z_UNDECL_TOKEN:\n            _Z_RETURN_IF_ERR(_z_liveliness_process_token_undeclare(zn, decl));\n            return _z_interest_process_undeclares(zn, &decl->_decl, peer);\n\n        case _Z_DECL_FINAL:\n            _Z_RETURN_IF_ERR(_z_liveliness_process_declare_final(zn, decl));\n            // Check that interest id is valid\n            if (!decl->_interest_id.has_value) {\n                _Z_ERROR_RETURN(_Z_ERR_MESSAGE_ZENOH_DECLARATION_UNKNOWN);\n            }\n            return _z_interest_process_declare_final(zn, decl->_interest_id.value, peer);\n\n        default:\n            _Z_INFO(\"Received unknown declare tag: %d\\n\", decl->_decl._tag);\n            break;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_handle_declare(_z_session_t *zn, _z_n_msg_declare_t *decl, _z_transport_peer_common_t *peer) {\n    z_result_t ret = _z_handle_declare_inner(zn, decl, peer);\n    _z_n_msg_declare_clear(decl);\n    return ret;\n}\n\nstatic z_result_t _z_handle_request(_z_transport_common_t *transport, _z_n_msg_request_t *req,\n                                    z_reliability_t reliability, _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(transport);\n    _ZP_UNUSED(peer);\n    _z_session_t *zn = _z_transport_common_get_session(transport);\n    _ZP_UNUSED(zn);\n    switch (req->_tag) {\n        case _Z_REQUEST_QUERY: {\n#if Z_FEATURE_QUERYABLE == 1\n            // Memory cleaning must be done in the feature layer\n            return _z_trigger_queryables(transport, &req->_body._query, &req->_key, (uint32_t)req->_rid, req->_ext_qos,\n                                         peer);\n#else\n            _Z_DEBUG(\"_Z_REQUEST_QUERY dropped, queryables not supported\");\n            _z_n_msg_request_clear(req);\n            break;\n#endif\n        }\n\n        case _Z_REQUEST_PUT: {\n#if Z_FEATURE_SUBSCRIPTION == 1\n            _z_msg_put_t put = req->_body._put;\n            // Memory cleaning must be done in the feature layer\n            _Z_RETURN_IF_ERR(_z_trigger_subscriptions_put(zn, &req->_key, &put._payload, &put._encoding,\n                                                          &put._commons._timestamp, req->_ext_qos, &put._attachment,\n                                                          reliability, &put._commons._source_info, peer));\n#endif\n            _z_network_message_t final;\n            _z_n_msg_make_response_final(&final, req->_rid);\n            z_result_t ret = _z_send_n_msg(zn, &final, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n#if Z_FEATURE_SUBSCRIPTION == 0\n            _z_n_msg_request_clear(req);\n#endif\n            return ret;\n        }\n        case _Z_REQUEST_DEL: {\n#if Z_FEATURE_SUBSCRIPTION == 1\n            _z_msg_del_t del = req->_body._del;\n            // Memory cleaning must be done in the feature layer\n            _Z_RETURN_IF_ERR(_z_trigger_subscriptions_del(zn, &req->_key, &del._commons._timestamp, req->_ext_qos,\n                                                          &del._attachment, reliability, &del._commons._source_info,\n                                                          peer));\n#endif\n            _z_network_message_t final;\n            _z_n_msg_make_response_final(&final, req->_rid);\n            z_result_t ret = _z_send_n_msg(zn, &final, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK, NULL);\n#if Z_FEATURE_SUBSCRIPTION == 0\n            _z_n_msg_request_clear(req);\n#endif\n            return ret;\n        }\n\n        default:\n            _Z_INFO(\"Received unknown request tag: %d\\n\", req->_tag);\n            _z_n_msg_request_clear(req);\n            break;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_handle_response(_z_session_t *zn, _z_n_msg_response_t *resp, _z_transport_peer_common_t *peer) {\n#if Z_FEATURE_QUERY == 1\n    _z_entity_global_id_t replier_id = {.zid = resp->_ext_responder._zid, .eid = resp->_ext_responder._eid};\n    switch (resp->_tag) {\n        case _Z_RESPONSE_BODY_REPLY:\n            // Memory cleaning must be done in the feature layer\n            return _z_trigger_reply_partial(zn, resp->_request_id, &resp->_key, &resp->_body._reply, &replier_id, peer);\n        case _Z_RESPONSE_BODY_ERR:\n            // Memory cleaning must be done in the feature layer\n            return _z_trigger_reply_err(zn, resp->_request_id, &resp->_body._err, &replier_id);\n        default:\n            _Z_INFO(\"Received unknown response tag: %d\\n\", resp->_tag);\n            _z_n_msg_response_clear(resp);\n            break;\n    }\n#else\n    _z_n_msg_response_clear(resp);\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(peer);\n#endif\n    return _Z_RES_OK;\n}\n\nz_result_t _z_handle_network_message(_z_transport_common_t *transport, _z_zenoh_message_t *msg,\n                                     _z_transport_peer_common_t *peer) {\n    z_result_t ret = _Z_RES_OK;\n    _z_session_t *zn = _z_transport_common_get_session(transport);\n\n    switch (msg->_tag) {\n        case _Z_N_DECLARE:\n            _Z_DEBUG(\"Handling _Z_N_DECLARE: %i\", msg->_body._declare._decl._tag);\n            ret = _z_handle_declare(zn, &msg->_body._declare, peer);\n            break;\n\n        case _Z_N_PUSH:\n            _Z_DEBUG(\"Handling _Z_N_PUSH\");\n            ret = _z_trigger_push(zn, &msg->_body._push, msg->_reliability, peer);\n            break;\n\n        case _Z_N_REQUEST:\n            _Z_DEBUG(\"Handling _Z_N_REQUEST\");\n            ret = _z_handle_request(transport, &msg->_body._request, msg->_reliability, peer);\n            break;\n\n        case _Z_N_RESPONSE:\n            _Z_DEBUG(\"Handling _Z_N_RESPONSE\");\n            ret = _z_handle_response(zn, &msg->_body._response, peer);\n            break;\n\n        case _Z_N_RESPONSE_FINAL:\n            _Z_DEBUG(\"Handling _Z_N_RESPONSE_FINAL\");\n            ret = _z_trigger_reply_final(zn, &msg->_body._response_final);\n            _z_n_msg_response_final_clear(&msg->_body._response_final);\n            break;\n\n        case _Z_N_INTEREST: {\n            _Z_DEBUG(\"Handling _Z_N_INTEREST\");\n            _z_n_msg_interest_t *interest = &msg->_body._interest;\n            if ((interest->_interest.flags & _Z_INTEREST_NOT_FINAL_MASK) != 0) {\n                _z_interest_process_interest(zn, &interest->_interest._keyexpr, interest->_interest._id,\n                                             interest->_interest.flags, peer);\n            } else {\n                _z_interest_process_interest_final(zn, interest->_interest._id);\n            }\n            _z_n_msg_interest_clear(&msg->_body._interest);\n        } break;\n\n        case _Z_N_OAM: {\n            _Z_DEBUG(\"Ignoring _Z_N_OAM\");\n            _z_n_msg_oam_clear(&msg->_body._oam);\n        } break;\n\n        default:\n            _Z_ERROR(\"Unknown network message ID\");\n            _z_n_msg_clear(msg);\n            break;\n    }\n    return ret;\n}\n"
  },
  {
    "path": "src/session/scout.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/transport/multicast.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_SCOUTING == 1\n\n#define SCOUT_BUFFER_SIZE 32\n\nstatic _z_hello_slist_t *__z_scout_loop(const _z_wbuf_t *wbf, _z_string_t *locator, unsigned long period,\n                                        bool exit_on_first) {\n    // Define an empty array\n    _z_hello_slist_t *ret = NULL;\n    z_result_t err = _Z_RES_OK;\n\n    _z_endpoint_t ep;\n    err = _z_endpoint_from_string(&ep, locator);\n\n#if Z_FEATURE_SCOUTING == 1\n    _z_string_t cmp_str = _z_string_alias_str(UDP_SCHEMA);\n    if ((err == _Z_RES_OK) && _z_string_equals(&ep._locator._protocol, &cmp_str)) {\n        _z_endpoint_clear(&ep);\n    } else\n#endif\n        if (err == _Z_RES_OK) {\n        _z_endpoint_clear(&ep);\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n        err = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n    }\n\n    if (err == _Z_RES_OK) {\n        _z_link_t zl;\n        memset(&zl, 0, sizeof(_z_link_t));\n\n        err = _z_open_link(&zl, locator, NULL);\n        if (err == _Z_RES_OK) {\n            // Send the scout message\n            err = _z_link_send_wbuf(&zl, wbf, NULL);\n            if (err == _Z_RES_OK) {\n                // The receiving buffer\n                _z_zbuf_t zbf = _z_zbuf_make(Z_BATCH_UNICAST_SIZE);\n\n                z_clock_t start = z_clock_now();\n                while (z_clock_elapsed_ms(&start) < period) {\n                    // Eventually read hello messages\n                    _z_zbuf_reset(&zbf);\n\n                    // Read bytes from the socket\n                    size_t len = _z_link_recv_zbuf(&zl, &zbf, NULL);\n                    if (len == SIZE_MAX) {\n                        continue;\n                    }\n\n                    _z_scouting_message_t s_msg;\n                    err = _z_scouting_message_decode(&s_msg, &zbf);\n                    if (err != _Z_RES_OK) {\n                        _Z_ERROR(\"Scouting loop received malformed message\");\n                        continue;\n                    }\n\n                    switch (_Z_MID(s_msg._header)) {\n                        case _Z_MID_HELLO: {\n                            _Z_DEBUG(\"Received _Z_HELLO message\");\n                            ret = _z_hello_slist_push_empty(ret);\n                            if (ret == NULL) {\n                                _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n                                err = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n                                break;\n                            }\n                            _z_hello_t *hello = _z_hello_slist_value(ret);\n                            hello->_version = s_msg._body._hello._version;\n                            hello->_whatami = s_msg._body._hello._whatami;\n                            memcpy(hello->_zid.id, s_msg._body._hello._zid.id, 16);\n\n                            size_t n_loc = _z_locator_array_len(&s_msg._body._hello._locators);\n                            if (n_loc > 0) {\n                                hello->_locators = _z_string_svec_make(n_loc);\n\n                                for (size_t i = 0; i < n_loc; i++) {\n                                    _z_string_t s = _z_locator_to_string(&s_msg._body._hello._locators._val[i]);\n                                    err = _z_string_svec_append(&hello->_locators, &s, true);\n                                    if (err != _Z_RES_OK) {\n                                        _Z_ERROR_LOG(err);\n                                        break;  // bail out of locator loop; case-level break follows below\n                                    }\n                                }\n                            } else {\n                                // @TODO: construct the locator departing from the sock address\n                                _z_string_svec_clear(&hello->_locators);\n                            }\n                            break;\n                        }\n                        default: {\n                            _Z_ERROR_LOG(_Z_ERR_MESSAGE_UNEXPECTED);\n                            err = _Z_ERR_MESSAGE_UNEXPECTED;\n                            _Z_ERROR(\"Scouting loop received unexpected message\");\n                            break;\n                        }\n                    }\n                    _z_s_msg_clear(&s_msg);\n\n                    if (!_z_hello_slist_is_empty(ret) && exit_on_first) {\n                        break;\n                    }\n                }\n\n                _z_link_clear(&zl);\n                _z_zbuf_clear(&zbf);\n            } else {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n                err = _Z_ERR_TRANSPORT_TX_FAILED;\n                _z_link_clear(&zl);\n            }\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_FAILED);\n            err = _Z_ERR_TRANSPORT_OPEN_FAILED;\n        }\n    }\n    _ZP_UNUSED(err);\n    return ret;\n}\n\n_z_hello_slist_t *_z_scout_inner(const z_what_t what, _z_id_t zid, _z_string_t *locator, const uint32_t timeout,\n                                 const bool exit_on_first) {\n    _z_hello_slist_t *ret = NULL;\n\n    // Create the buffer to serialize the scout message on\n    _z_wbuf_t wbf = _z_wbuf_make(SCOUT_BUFFER_SIZE, false);\n\n    // Create and encode the scout message\n    _z_scouting_message_t scout = _z_s_msg_make_scout(what, zid);\n\n    z_result_t res = _z_scouting_message_encode(&wbf, &scout);\n    if (res != _Z_RES_OK) {\n        _Z_ERROR(\"Scout message encoding failed with err %d\", res);\n        _z_wbuf_clear(&wbf);\n        return NULL;\n    }\n\n    // Scout on multicast\n    ret = __z_scout_loop(&wbf, locator, timeout, exit_on_first);\n\n    _z_wbuf_clear(&wbf);\n\n    return ret;\n}\n#else\n\n_z_hello_slist_t *_z_scout_inner(const z_what_t what, _z_id_t zid, _z_string_t *locator, const uint32_t timeout,\n                                 const bool exit_on_first) {\n    _ZP_UNUSED(what);\n    _ZP_UNUSED(zid);\n    _ZP_UNUSED(locator);\n    _ZP_UNUSED(timeout);\n    _ZP_UNUSED(exit_on_first);\n    return NULL;\n}\n\n#endif  // Z_FEATURE_SCOUTING == 1\n"
  },
  {
    "path": "src/session/subscription.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/subscription.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/net/filtering.h\"\n#include \"zenoh-pico/net/sample.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/utils/locality.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1\n\n#define _Z_SUBINFOS_VEC_SIZE 4  // Arbitrary initial size\n\nvoid _z_unsafe_subscription_cache_invalidate(_z_session_t *zn) {\n#if Z_FEATURE_RX_CACHE == 1\n    _z_subscription_lru_cache_clear(&zn->_subscription_cache);\n#else\n    _ZP_UNUSED(zn);\n#endif\n}\n\n#if Z_FEATURE_RX_CACHE == 1\nint _z_subscription_cache_data_compare(const void *first, const void *second) {\n    const _z_subscription_cache_data_t *first_data = (const _z_subscription_cache_data_t *)first;\n    const _z_subscription_cache_data_t *second_data = (const _z_subscription_cache_data_t *)second;\n    if (first_data->is_remote != second_data->is_remote) {\n        return (int)first_data->is_remote - (int)second_data->is_remote;\n    }\n    return _z_keyexpr_compare(&first_data->ke, &second_data->ke);\n}\n#endif  // Z_FEATURE_RX_CACHE == 1\n\nvoid _z_subscription_cache_data_clear(_z_subscription_cache_data_t *val) {\n    _z_subscription_rc_svec_rc_drop(&val->infos);\n    _z_keyexpr_clear(&val->ke);\n}\n\nbool _z_subscription_eq(const _z_subscription_t *other, const _z_subscription_t *this_) {\n    return this_->_id == other->_id;\n}\n\nvoid _z_subscription_clear(_z_subscription_t *sub) {\n    if (sub->_dropper != NULL) {\n        sub->_dropper(sub->_arg);\n        sub->_dropper = NULL;\n    }\n    _z_declared_keyexpr_clear(&sub->_key);\n    _z_sync_group_notifier_drop(&sub->_session_callback_drop_notifier);\n    _z_sync_group_notifier_drop(&sub->_subscriber_callback_drop_notifier);\n}\n\n_z_subscription_rc_t *__z_get_subscription_by_id(_z_subscription_rc_slist_t *subs, const _z_zint_t id) {\n    _z_subscription_rc_t *ret = NULL;\n\n    _z_subscription_rc_slist_t *xs = subs;\n    while (xs != NULL) {\n        _z_subscription_rc_t *sub = _z_subscription_rc_slist_value(xs);\n        if (id == _Z_RC_IN_VAL(sub)->_id) {\n            ret = sub;\n            break;\n        }\n        xs = _z_subscription_rc_slist_next(xs);\n    }\n\n    return ret;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\n_z_subscription_rc_t *__unsafe_z_get_subscription_by_id(_z_session_t *zn, _z_subscriber_kind_t kind,\n                                                        const _z_zint_t id) {\n    _z_subscription_rc_slist_t *subs =\n        (kind == _Z_SUBSCRIBER_KIND_SUBSCRIBER) ? zn->_subscriptions : zn->_liveliness_subscriptions;\n    return __z_get_subscription_by_id(subs, id);\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic z_result_t __unsafe_z_get_subscriptions_by_key(_z_session_t *zn, _z_subscriber_kind_t kind,\n                                                      const _z_keyexpr_t *key, bool is_remote,\n                                                      _z_subscription_rc_svec_t *sub_infos) {\n    _z_subscription_rc_slist_t *subs =\n        (kind == _Z_SUBSCRIBER_KIND_SUBSCRIBER) ? zn->_subscriptions : zn->_liveliness_subscriptions;\n\n    *sub_infos = _z_subscription_rc_svec_make(_Z_SUBINFOS_VEC_SIZE);\n    _Z_RETURN_ERR_OOM_IF_TRUE(sub_infos->_val == NULL);\n    _z_subscription_rc_slist_t *xs = subs;\n    while (xs != NULL) {\n        // Parse subscription list\n        _z_subscription_rc_t *sub = _z_subscription_rc_slist_value(xs);\n        const _z_subscription_t *sub_val = _Z_RC_IN_VAL(sub);\n        bool origin_allowed = is_remote ? _z_locality_allows_remote(sub_val->_allowed_origin)\n                                        : _z_locality_allows_local(sub_val->_allowed_origin);\n        if (origin_allowed && _z_keyexpr_intersects(&sub_val->_key._inner, key)) {\n            _z_subscription_rc_t sub_clone = _z_subscription_rc_clone(sub);\n            _Z_CLEAN_RETURN_IF_ERR(_z_subscription_rc_svec_append(sub_infos, &sub_clone, false),\n                                   _z_subscription_rc_svec_clear(sub_infos));\n        }\n        xs = _z_subscription_rc_slist_next(xs);\n    }\n    return _Z_RES_OK;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - zn->_mutex_inner\n */\nstatic z_result_t __unsafe_z_get_subscriptions_rc_by_key(_z_session_t *zn, _z_subscriber_kind_t kind,\n                                                         const _z_keyexpr_t *key, bool is_remote,\n                                                         _z_subscription_rc_svec_rc_t *sub_infos) {\n    *sub_infos = _z_subscription_rc_svec_rc_new_undefined();\n    z_result_t ret = !_Z_RC_IS_NULL(sub_infos) ? _Z_RES_OK : _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    _Z_SET_IF_OK(ret, __unsafe_z_get_subscriptions_by_key(zn, kind, key, is_remote, _Z_RC_IN_VAL(sub_infos)));\n    if (ret != _Z_RES_OK) {\n        _z_subscription_rc_svec_rc_drop(sub_infos);\n    }\n    return _Z_RES_OK;\n}\n\n_z_subscription_rc_t _z_get_subscription_by_id(_z_session_t *zn, _z_subscriber_kind_t kind, const _z_zint_t id) {\n    _z_subscription_rc_t out = _z_subscription_rc_null();\n    _z_session_mutex_lock(zn);\n\n    _z_subscription_rc_t *sub = __unsafe_z_get_subscription_by_id(zn, kind, id);\n    if (sub != NULL) {\n        out = _z_subscription_rc_clone(sub);\n    }\n    _z_session_mutex_unlock(zn);\n\n    return out;\n}\n\n_z_subscription_rc_t _z_register_subscription(_z_session_t *zn, _z_subscriber_kind_t kind, _z_subscription_t *s) {\n    _Z_DEBUG(\">>> Allocating sub decl for (%.*s)\", (int)_z_string_len(&s->_key._inner._keyexpr),\n             _z_string_data(&s->_key._inner._keyexpr));\n\n    _z_subscription_rc_t *ret = NULL;\n    _z_subscription_rc_t out = _z_subscription_rc_new_from_val(s);\n    if (_Z_RC_IS_NULL(&out)) {\n        return out;\n    }\n    if (_z_session_mutex_lock_if_open(zn) != _Z_RES_OK) {\n        _z_subscription_rc_drop(&out);\n        *s = _z_subscription_null();\n        return _z_subscription_rc_null();\n    }\n    if (kind == _Z_SUBSCRIBER_KIND_SUBSCRIBER) {\n        zn->_subscriptions = _z_subscription_rc_slist_push_empty(zn->_subscriptions);\n        ret = _z_subscription_rc_slist_value(zn->_subscriptions);\n    } else {\n        zn->_liveliness_subscriptions = _z_subscription_rc_slist_push_empty(zn->_liveliness_subscriptions);\n        ret = _z_subscription_rc_slist_value(zn->_liveliness_subscriptions);\n    }\n    if (ret == NULL) {\n        _z_subscription_rc_drop(&out);\n    } else {\n        // immediately increase reference count to prevent eventual drop by concurrent session close\n        *ret = _z_subscription_rc_clone(&out);\n    }\n    _z_session_mutex_unlock(zn);\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    if (!_Z_RC_IS_NULL(&out) && kind == _Z_SUBSCRIBER_KIND_SUBSCRIBER) {\n        _z_subscription_t *sub_val = _Z_RC_IN_VAL(&out);\n        if (_z_locality_allows_local(sub_val->_allowed_origin)) {\n            _z_write_filter_notify_subscriber(zn, &sub_val->_key._inner, sub_val->_allowed_origin, true);\n        }\n    }\n#endif\n\n    return out;\n}\n\nz_result_t _z_trigger_liveliness_subscriptions_declare(_z_session_t *zn, const _z_wireexpr_t *wireexpr,\n                                                       const _z_timestamp_t *timestamp,\n                                                       _z_transport_peer_common_t *peer) {\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_bytes_t payload = _z_bytes_null();\n    _z_bytes_t attachment = _z_bytes_null();\n    _z_source_info_t source_info = _z_source_info_null();\n    _z_wireexpr_t wireexpr2 = _z_wireexpr_alias(wireexpr);\n    return _z_trigger_subscriptions_impl(zn, _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, &wireexpr2, &payload, &encoding,\n                                         Z_SAMPLE_KIND_PUT, timestamp, _Z_N_QOS_DEFAULT, &attachment,\n                                         Z_RELIABILITY_RELIABLE, &source_info, peer);\n}\n\nz_result_t _z_trigger_liveliness_subscriptions_undeclare(_z_session_t *zn, const _z_keyexpr_t *keyexpr,\n                                                         const _z_timestamp_t *timestamp) {\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_bytes_t payload = _z_bytes_null();\n    _z_bytes_t attachment = _z_bytes_null();\n    _z_wireexpr_t wireexpr = _z_keyexpr_alias_to_wire(keyexpr);\n    _z_source_info_t source_info = _z_source_info_null();\n    return _z_trigger_subscriptions_impl(zn, _Z_SUBSCRIBER_KIND_LIVELINESS_SUBSCRIBER, &wireexpr, &payload, &encoding,\n                                         Z_SAMPLE_KIND_DELETE, timestamp, _Z_N_QOS_DEFAULT, &attachment,\n                                         Z_RELIABILITY_RELIABLE, &source_info, NULL);\n}\n\nstatic z_result_t _z_subscription_get_infos(_z_session_t *zn, _z_subscriber_kind_t kind,\n                                            _z_subscription_cache_data_t *out, const _z_wireexpr_t *wireexpr,\n                                            _z_transport_peer_common_t *peer) {\n    out->is_remote = (peer != NULL);\n    _Z_RETURN_IF_ERR(_z_get_keyexpr_from_wireexpr(zn, &out->ke, wireexpr, peer, true));\n    _Z_CLEAN_RETURN_IF_ERR(_z_session_mutex_lock_if_open(zn), _z_keyexpr_clear(&out->ke));\n    _z_subscription_cache_data_t *cache_entry = NULL;\n    z_result_t ret = _Z_RES_OK;\n#if Z_FEATURE_RX_CACHE == 1\n    cache_entry = _z_subscription_lru_cache_get(&zn->_subscription_cache, out);\n    if (cache_entry != NULL && cache_entry->is_remote != out->is_remote) {\n        cache_entry = NULL;\n    }\n#endif\n    if (cache_entry != NULL) {  // Copy cache entry\n        out->infos = _z_subscription_rc_svec_rc_clone(&cache_entry->infos);\n    } else {  // Construct data and add to cache\n        _Z_SET_IF_OK(ret, __unsafe_z_get_subscriptions_rc_by_key(zn, kind, &out->ke, out->is_remote, &out->infos));\n#if Z_FEATURE_RX_CACHE == 1\n        _z_subscription_cache_data_t cache_storage = _z_subscription_cache_data_null();\n        cache_storage.infos = _z_subscription_rc_svec_rc_clone(&out->infos);\n        cache_storage.is_remote = out->is_remote;\n        _Z_SET_IF_OK(ret, _z_keyexpr_copy(&cache_storage.ke, &out->ke));\n        _Z_SET_IF_OK(ret, _z_subscription_lru_cache_insert(&zn->_subscription_cache, &cache_storage));\n        if (ret != _Z_RES_OK) {\n            _z_subscription_cache_data_clear(&cache_storage);\n        }\n#endif\n    }\n    _z_session_mutex_unlock(zn);\n    if (ret != _Z_RES_OK) {\n        _z_subscription_cache_data_clear(out);\n    }\n    return ret;\n}\n\nz_result_t _z_trigger_subscriptions_impl(_z_session_t *zn, _z_subscriber_kind_t sub_kind, _z_wireexpr_t *wireexpr,\n                                         _z_bytes_t *payload, _z_encoding_t *encoding, const _z_zint_t sample_kind,\n                                         const _z_timestamp_t *timestamp, const _z_n_qos_t qos, _z_bytes_t *attachment,\n                                         z_reliability_t reliability, _z_source_info_t *source_info,\n                                         _z_transport_peer_common_t *peer) {\n    _z_subscription_cache_data_t sub_infos = _z_subscription_cache_data_null();\n    _Z_CLEAN_RETURN_IF_ERR(_z_subscription_get_infos(zn, sub_kind, &sub_infos, wireexpr, peer),\n                           _z_wireexpr_clear(wireexpr);\n                           _z_encoding_clear(encoding); _z_bytes_drop(payload); _z_bytes_drop(attachment););\n    const _z_subscription_rc_svec_t *subs = _Z_RC_IN_VAL(&sub_infos.infos);\n    size_t sub_nb = _z_subscription_rc_svec_len(subs);\n    _Z_DEBUG(\"Triggering %ju subs for key %.*s\", (uintmax_t)sub_nb, (int)_z_string_len(&sub_infos.ke._keyexpr),\n             _z_string_data(&sub_infos.ke._keyexpr));\n    // Create sample\n    z_result_t ret = _Z_RES_OK;\n    _z_sample_t sample;\n    _z_sample_steal_data(&sample, &sub_infos.ke, payload, timestamp, encoding, sample_kind, qos, attachment,\n                         reliability, source_info);\n    // Parse subscription infos svec\n    if (sub_nb == 1) {\n        _z_subscription_t *sub_info = _Z_RC_IN_VAL(_z_subscription_rc_svec_get(subs, 0));\n        sub_info->_callback(&sample, sub_info->_arg);\n    } else {\n        for (size_t i = 0; i < sub_nb; i++) {\n            _z_subscription_t *sub_info = _Z_RC_IN_VAL(_z_subscription_rc_svec_get(subs, i));\n            if (i + 1 == sub_nb) {\n                sub_info->_callback(&sample, sub_info->_arg);\n            } else {\n                _z_sample_t sample_copy;\n                ret = _z_sample_copy(&sample_copy, &sample);\n                if (ret != _Z_RES_OK) {\n                    break;\n                }\n                sub_info->_callback(&sample_copy, sub_info->_arg);\n                _z_sample_clear(&sample_copy);\n            }\n        }\n    }\n    _z_wireexpr_clear(wireexpr);\n    _z_sample_clear(&sample);\n    _z_subscription_cache_data_clear(&sub_infos);\n    return ret;\n}\n\nvoid _z_unregister_subscription(_z_session_t *zn, _z_subscriber_kind_t kind, _z_subscription_rc_t *sub) {\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    if (kind == _Z_SUBSCRIBER_KIND_SUBSCRIBER) {\n        _z_subscription_t *sub_val = _Z_RC_IN_VAL(sub);\n        _z_write_filter_notify_subscriber(zn, &sub_val->_key._inner, sub_val->_allowed_origin, false);\n    }\n#endif\n    _z_session_mutex_lock(zn);\n    _z_unsafe_subscription_cache_invalidate(zn);\n    if (kind == _Z_SUBSCRIBER_KIND_SUBSCRIBER) {\n        zn->_subscriptions = _z_subscription_rc_slist_drop_first_filter(zn->_subscriptions, _z_subscription_rc_eq, sub);\n    } else {\n        zn->_liveliness_subscriptions =\n            _z_subscription_rc_slist_drop_first_filter(zn->_liveliness_subscriptions, _z_subscription_rc_eq, sub);\n    }\n    _z_session_mutex_unlock(zn);\n    _z_subscription_rc_drop(sub);\n}\n\nvoid _z_flush_subscriptions(_z_session_t *zn) {\n    _z_subscription_rc_slist_t *subscriptions, *liveliness_subscriptions;\n    _z_session_mutex_lock(zn);\n    _z_unsafe_subscription_cache_invalidate(zn);\n    subscriptions = zn->_subscriptions;\n    liveliness_subscriptions = zn->_liveliness_subscriptions;\n    zn->_subscriptions = _z_subscription_rc_slist_new();\n    zn->_liveliness_subscriptions = _z_subscription_rc_slist_new();\n    _z_session_mutex_unlock(zn);\n    _z_subscription_rc_slist_free(&subscriptions);\n    _z_subscription_rc_slist_free(&liveliness_subscriptions);\n}\n#else  // Z_FEATURE_SUBSCRIPTION == 0\nz_result_t _z_trigger_liveliness_subscriptions_declare(_z_session_t *zn, const _z_wireexpr_t *wireexpr,\n                                                       const _z_timestamp_t *timestamp,\n                                                       _z_transport_peer_common_t *peer) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(wireexpr);\n    _ZP_UNUSED(timestamp);\n    _ZP_UNUSED(peer);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_trigger_liveliness_subscriptions_undeclare(_z_session_t *zn, const _z_keyexpr_t *keyexpr,\n                                                         const _z_timestamp_t *timestamp) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(keyexpr);\n    _ZP_UNUSED(timestamp);\n    return _Z_RES_OK;\n}\n\nvoid _z_unsafe_subscription_cache_invalidate(_z_session_t *zn) { _ZP_UNUSED(zn); }\n\n#endif  // Z_FEATURE_SUBSCRIPTION == 1\n"
  },
  {
    "path": "src/session/utils.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/session/utils.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/matching.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ clone helpers ------------------*/\nvoid _z_timestamp_copy(_z_timestamp_t *dst, const _z_timestamp_t *src) { *dst = *src; }\n\n_z_timestamp_t _z_timestamp_duplicate(const _z_timestamp_t *tstamp) { return *tstamp; }\n\nvoid _z_timestamp_move(_z_timestamp_t *dst, _z_timestamp_t *src) {\n    *dst = *src;\n    _z_timestamp_clear(src);\n}\n\nvoid _z_timestamp_clear(_z_timestamp_t *tstamp) {\n    tstamp->valid = false;\n    tstamp->time = 0;\n}\n\nz_result_t _z_session_generate_zid(_z_id_t *bs, uint8_t size) {\n    z_result_t ret = _Z_RES_OK;\n    z_random_fill((uint8_t *)bs->id, size);\n    return ret;\n}\n\n/*------------------ Init/Free/Close session ------------------*/\nz_result_t _z_session_init(_z_session_t *zn, const _z_id_t *zid) {\n    z_result_t ret = _Z_RES_OK;\n    _z_atomic_bool_init(&zn->_is_closed, true);\n    _z_runtime_null(&zn->_runtime);\n#if Z_FEATURE_MULTI_THREAD == 1\n    _Z_RETURN_IF_ERR(_z_mutex_init(&zn->_mutex_inner));\n    ret = _z_mutex_rec_init(&zn->_mutex_transport);\n    if (ret != _Z_RES_OK) {\n        _z_mutex_drop(&zn->_mutex_inner);\n        _Z_ERROR_RETURN(ret);\n    }\n#if Z_FEATURE_ADMIN_SPACE == 1\n    ret = _z_mutex_init(&zn->_mutex_admin_space);\n    if (ret != _Z_RES_OK) {\n        _z_mutex_rec_drop(&zn->_mutex_transport);\n        _z_mutex_drop(&zn->_mutex_inner);\n        _Z_ERROR_RETURN(ret);\n    }\n#endif\n#endif\n    zn->_mode = Z_WHATAMI_CLIENT;\n    zn->_tp._type = _Z_TRANSPORT_NONE;\n    // Initialize the counters to 1\n    zn->_entity_id = 1;\n    zn->_resource_id = 1;\n    zn->_query_id = 1;\n\n    _z_config_init(&zn->_config);\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    zn->_declaration_cache = NULL;\n#endif\n\n    // Initialize the data structs\n    zn->_local_resources = NULL;\n#if Z_FEATURE_SUBSCRIPTION == 1\n    zn->_subscriptions = NULL;\n    zn->_liveliness_subscriptions = NULL;\n#if Z_FEATURE_RX_CACHE == 1\n    zn->_subscription_cache = _z_subscription_lru_cache_init(Z_RX_CACHE_SIZE);\n#endif\n#endif\n#if Z_FEATURE_QUERYABLE == 1\n    zn->_local_queryable = NULL;\n#if Z_FEATURE_RX_CACHE == 1\n    zn->_queryable_cache = _z_queryable_lru_cache_init(Z_RX_CACHE_SIZE);\n#endif\n#endif\n#if Z_FEATURE_QUERY == 1\n    zn->_pending_queries = NULL;\n#endif\n\n#if Z_FEATURE_LIVELINESS == 1\n    _z_liveliness_init(zn);\n#endif\n\n#if Z_FEATURE_INTEREST == 1\n    zn->_write_filters = NULL;\n#endif\n\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_ADMIN_SPACE == 1\n    zn->_admin_space_queryable_id = 0;\n#if Z_FEATURE_CONNECTIVITY == 1\n#if Z_FEATURE_QUERYABLE == 1\n    zn->_admin_space_session_queryable_id = 0;\n#endif\n#if Z_FEATURE_PUBLICATION == 1\n    zn->_admin_space_transport_listener_id = 0;\n    zn->_admin_space_link_listener_id = 0;\n#endif\n#endif\n#endif\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    zn->_connectivity_next_listener_id = 1;\n    _z_connectivity_transport_listener_intmap_init(&zn->_connectivity_transport_event_listeners);\n    _z_connectivity_link_listener_intmap_init(&zn->_connectivity_link_event_listeners);\n#endif\n#endif\n    zn->_callback_drop_sync_group = _z_sync_group_null();\n    _Z_SET_IF_OK(ret, _z_sync_group_create(&zn->_callback_drop_sync_group));\n    _Z_SET_IF_OK(ret, _z_runtime_init(&zn->_runtime));\n#if Z_FEATURE_QUERY\n    if (ret == _Z_RES_OK) {\n        _z_fut_t fut = _z_fut_null();\n        fut._fut_fn = _z_pending_query_process_timeout_task_fn;\n        fut._fut_arg = zn;\n        ret = _z_fut_handle_is_null(_z_runtime_spawn(&zn->_runtime, &fut)) ? _Z_ERR_FAILED_TO_SPAWN_TASK : _Z_RES_OK;\n    }\n#endif\n    if (ret != _Z_RES_OK) {\n#if Z_FEATURE_MULTI_THREAD == 1\n#if Z_FEATURE_ADMIN_SPACE == 1\n        _z_mutex_drop(&zn->_mutex_admin_space);\n#endif\n        _z_mutex_rec_drop(&zn->_mutex_transport);\n        _z_mutex_drop(&zn->_mutex_inner);\n#endif\n        _z_sync_group_drop(&zn->_callback_drop_sync_group);\n        _z_runtime_clear(&zn->_runtime);\n        _Z_ERROR_RETURN(ret);\n    }\n\n    _z_interest_init(zn);\n\n    zn->_local_zid = *zid;\n    _z_atomic_bool_store(&zn->_is_closed, false, _z_memory_order_release);\n    return ret;\n}\n\nz_result_t _z_session_close(_z_session_t *zn) {\n    // Need to run close sequence unconditionally, since\n    // this is the only way to guarantee that after _z_session_close returns,\n    // no more callbacks will be running\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock(zn));\n    _z_atomic_bool_store(&zn->_is_closed, true, _z_memory_order_release);\n    _z_session_mutex_unlock(zn);\n    // stop the runtime to prevent spawning new tasks\n    // this will also ensure that no callbacks can be called in response to message reception inside read task,\n    // session sync group at the end of the call might still be needed in case there are any historical\n    // callbacks currently executing, like in the case of liveliness subscribers/ matching listeners / connectivity\n    // events\n    _Z_RETURN_IF_ERR(_z_runtime_stop(&zn->_runtime));\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock(zn));\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    _z_network_message_slist_free(&zn->_declaration_cache);\n#endif\n    _z_session_mutex_unlock(zn);\n    _z_flush_local_resources(zn);\n#if Z_FEATURE_SUBSCRIPTION == 1\n    _z_flush_subscriptions(zn);\n#endif\n#if Z_FEATURE_QUERYABLE == 1\n    // Admin space querable cleanup will occur as part of queryable cleanup\n    _z_flush_session_queryable(zn);\n#endif\n#if Z_FEATURE_QUERY == 1\n    _z_flush_pending_queries(zn);\n#endif\n#if Z_FEATURE_LIVELINESS == 1\n    _z_liveliness_clear(zn);\n#endif\n    _z_flush_interest(zn);\n#ifdef Z_FEATURE_UNSTABLE_API\n#if Z_FEATURE_CONNECTIVITY == 1\n    _Z_RETURN_IF_ERR(_z_session_mutex_lock(zn));\n    _z_connectivity_transport_listener_intmap_clear(&zn->_connectivity_transport_event_listeners);\n    _z_connectivity_link_listener_intmap_clear(&zn->_connectivity_link_event_listeners);\n    zn->_connectivity_next_listener_id = 1;\n    _z_session_mutex_unlock(zn);\n#endif\n#if Z_FEATURE_ADMIN_SPACE == 1\n    _z_session_admin_space_mutex_lock(zn);\n    zn->_admin_space_queryable_id = 0;\n#if Z_FEATURE_CONNECTIVITY == 1\n#if Z_FEATURE_QUERYABLE == 1\n    zn->_admin_space_session_queryable_id = 0;\n#endif\n#if Z_FEATURE_PUBLICATION == 1\n    zn->_admin_space_transport_listener_id = 0;\n    zn->_admin_space_link_listener_id = 0;\n#endif\n#endif\n    _z_session_admin_space_mutex_unlock(zn);\n#endif\n#endif\n    // Despite stopping runtime at the very beginning, we still need to wait for possible historical callbacks\n    // from liveliness subscribers, matching listeners, connectivity events listeners, etc\n    // to finish\n    _z_sync_group_wait(&zn->_callback_drop_sync_group);\n    return _Z_RES_OK;\n}\n\nvoid _z_session_clear(_z_session_t *zn) {\n    _z_session_close(zn);\n    _z_runtime_clear(&zn->_runtime);\n    _z_config_clear(&zn->_config);\n    _z_session_transport_mutex_lock(zn);\n    _z_transport_clear(&zn->_tp);\n    _z_session_transport_mutex_unlock(zn);\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#if Z_FEATURE_ADMIN_SPACE == 1\n    _z_mutex_drop(&zn->_mutex_admin_space);\n#endif\n    _z_mutex_rec_drop(&zn->_mutex_transport);\n    _z_mutex_drop(&zn->_mutex_inner);\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n    _z_sync_group_drop(&zn->_callback_drop_sync_group);\n}\n"
  },
  {
    "path": "src/system/arduino/esp32/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ARDUINO_ESP32)\n\n#include <Arduino.h>\n#include <errno.h>\n#include <esp_heap_caps.h>\n#include <esp_random.h>\n#include <stddef.h>\n#include <sys/time.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/common/system_error.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return z_random_u32(); }\n\nuint16_t z_random_u16(void) { return z_random_u32(); }\n\nuint32_t z_random_u32(void) { return esp_random(); }\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) { esp_fill_random(buf, len); }\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) { return heap_caps_malloc(size, MALLOC_CAP_8BIT); }\n\nvoid *z_realloc(void *ptr, size_t size) { return heap_caps_realloc(ptr, size, MALLOC_CAP_8BIT); }\n\nvoid z_free(void *ptr) { heap_caps_free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n// This wrapper is only used for ESP32.\n// In FreeRTOS, tasks created using xTaskCreate must end with vTaskDelete.\n// A task function should __not__ simply return.\ntypedef struct {\n    void *(*_fun)(void *);\n    void *_arg;\n    EventGroupHandle_t join_event;\n} z_task_arg;\n\nvoid z_task_wrapper(z_task_arg *targ) {\n    targ->_fun(targ->_arg);\n    // Notify the deleter task that this task is done\n    xEventGroupSetBits(targ->join_event, 1);\n    // No one else uses this task argument after this\n    z_free(targ);\n    // Put the task in a safe state to be culled by another task\n    vTaskSuspend(NULL);\n}\n\nstatic z_task_attr_t z_default_task_attr = {\n    .name = \"\",\n    .priority = configMAX_PRIORITIES / 2,\n    .stack_depth = 5120,\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    .static_allocation = false,\n    .stack_buffer = NULL,\n    .task_buffer = NULL,\n#endif /* SUPPORT_STATIC_ALLOCATION */\n};\n\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    if (attr == NULL) {\n        attr = &z_default_task_attr;\n    }\n\n    z_task_arg *z_arg = (z_task_arg *)z_malloc(sizeof(z_task_arg));\n\n    if (z_arg == NULL) {\n        return -1;\n    }\n\n    z_arg->_fun = fun;\n    z_arg->_arg = arg;\n    task->join_event = xEventGroupCreate();\n    z_arg->join_event = task->join_event;\n\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    if (attr->static_allocation) {\n        task->handle = xTaskCreateStatic((void *)z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority,\n                                         attr->stack_buffer, attr->task_buffer);\n        if (task->handle == NULL) {\n            z_free(z_arg);\n            return -1;\n        }\n    } else {\n#endif /* SUPPORT_STATIC_ALLOCATION */\n        if (xTaskCreate((void *)z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority, &task->handle) !=\n            pdPASS) {\n            z_free(z_arg);\n            return -1;\n        }\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    }\n#endif /* SUPPORT_STATIC_ALLOCATION */\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    xEventGroupWaitBits(task->join_event, 1, pdFALSE, pdFALSE, portMAX_DELAY);\n    return _z_task_cancel(task);\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    // Note: task/thread detach not supported on FreeRTOS API, so we force its deletion instead.\n    return _z_task_cancel(task);\n}\n\nz_result_t _z_task_cancel(_z_task_t *task) {\n    vTaskDelete(task->handle);\n    task->handle = NULL;\n    return _Z_RES_OK;\n}\n\nvoid _z_task_exit(void) { vTaskDelete(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    vEventGroupDelete(ptr->join_event);\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return task->handle; }\n_z_task_id_t _z_task_current_id(void) { return xTaskGetCurrentTaskHandle(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_init(m, NULL)); }\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) {\n    pthread_mutexattr_t attr;\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_init(&attr));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutex_init(m, &attr));\n    _Z_CHECK_SYS_ERR(pthread_mutexattr_destroy(&attr));\n}\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    pthread_condattr_t attr;\n    pthread_condattr_init(&attr);\n    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);\n    _Z_CHECK_SYS_ERR(pthread_cond_init(cv, &attr));\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_destroy(cv)); }\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_signal(cv)); }\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_broadcast(cv)); }\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_cond_wait(cv, m)); }\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    int error = pthread_cond_timedwait(cv, m, abstime);\n\n    if (error == ETIMEDOUT) {\n        return Z_ETIMEDOUT;\n    }\n\n    _Z_CHECK_SYS_ERR(error);\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) { _Z_CHECK_SYS_ERR(usleep(time)); }\n\nz_result_t z_sleep_ms(size_t time) {\n    z_time_t start = z_time_now();\n\n    // Most sleep APIs promise to sleep at least whatever you asked them to.\n    // This may compound, so this approach may make sleeps longer than expected.\n    // This extra check tries to minimize the amount of extra time it might sleep.\n    while (z_time_elapsed_ms(&start) < time) {\n        z_result_t ret = z_sleep_us(1000);\n        if (ret < 0) {\n            return ret;\n        }\n    }\n\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) { _Z_CHECK_SYS_ERR(sleep(time)); }\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = now.tv_sec - time->tv_sec;\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = now.tv_sec;\n    t->nanos = now.tv_usec * 1000;\n    return 0;\n}\n\n#endif /* defined(ZENOH_ARDUINO_ESP32) */\n"
  },
  {
    "path": "src/system/arduino/opencr/network.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ARDUINO_OPENCR)\n\n#include <Arduino.h>\n#include <WiFiClient.h>\n#include <WiFiUdp.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n\nextern \"C\" {\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(blocking);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    _ZP_UNUSED(iter);\n    _ZP_UNUSED(timeout_ms);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on OpenCR port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#error \"Serial not supported yet on OpenCR port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on OpenCR port of Zenoh-Pico\"\n#endif\n}  // extern \"C\"\n\n#endif /* defined(ZENOH_ARDUINO_OPENCR) */\n"
  },
  {
    "path": "src/system/arduino/opencr/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <FreeRTOS.h>\n#include <hw/driver/delay.h>\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return random(0xFF); }\n\nuint16_t z_random_u16(void) { return random(0xFFFF); }\n\nuint32_t z_random_u32(void) { return random(0xFFFFFFFF); }\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        ((uint8_t *)buf)[i] = z_random_u8();\n    }\n}\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) {\n    // return pvPortMalloc(size); // FIXME: Further investigation is required to understand\n    //        why pvPortMalloc or pvPortMallocAligned are failing\n    return malloc(size);\n}\n\nvoid *z_realloc(void *ptr, size_t size) {\n    // Not implemented by the platform\n    return NULL;\n}\n\nvoid z_free(void *ptr) {\n    // vPortFree(ptr); // FIXME: Further investigation is required to understand\n    //        why vPortFree or vPortFreeAligned are failing\n    return free(ptr);\n}\n\n#if Z_FEATURE_MULTI_THREAD == 1\n#error \"Multi-threading not supported yet on OpenCR port. Disable it by defining Z_FEATURE_MULTI_THREAD=0\"\n\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) { return -1; }\n\nz_result_t _z_task_join(_z_task_t *task) { return -1; }\n\nz_result_t _z_task_detach(_z_task_t *task) { return -1; }\n\nz_result_t _z_task_cancel(_z_task_t *task) { return -1; }\n\nvoid _z_task_exit(void) {}\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return NULL; }\n_z_task_id_t _z_task_current_id(void) { return NULL; }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return true; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) { return -1; }\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) { return -1; }\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { return -1; }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { return -1; }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { return -1; }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) { return -1; }\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { return -1; }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { return -1; }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { return -1; }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { return -1; }\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) { return -1; }\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) { return -1; }\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) { return -1; }\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) { return -1; }\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { return -1; }\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) { return -1; }\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    delay_us(time);\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    delay_ms(time);\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    z_time_t start = z_time_now();\n\n    // Most sleep APIs promise to sleep at least whatever you asked them to.\n    // This may compound, so this approach may make sleeps longer than expected.\n    // This extra check tries to minimize the amount of extra time it might sleep.\n    while (z_time_elapsed_s(&start) < time) {\n        z_sleep_ms(1000);\n    }\n\n    return 0;\n}\n\n/*------------------ Instant ------------------*/\nvoid __z_clock_gettime(z_clock_t *ts) {\n    uint64_t m = millis();\n    ts->tv_sec = m / (uint64_t)1000000;\n    ts->tv_nsec = (m % (uint64_t)1000000) * (uint64_t)1000;\n}\n\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = now.tv_sec - time->tv_sec;\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = now.tv_sec;\n    t->nanos = now.tv_usec * 1000;\n    return 0;\n}\n"
  },
  {
    "path": "src/system/common/platform.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/system/common/platform.h\"\n\n#include \"zenoh-pico/api/olv_macros.h\"\n\n#if Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Thread ------------------*/\n_Z_OWNED_FUNCTIONS_SYSTEM_IMPL(_z_task_t, task)\n\nz_result_t z_task_init(z_owned_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    return _z_task_init(&task->_val, attr, fun, arg);\n}\n\nz_result_t z_task_join(z_moved_task_t *task) {\n    _z_task_t *ptr = &task->_this._val;\n    z_result_t ret = _z_task_join(ptr);\n    return ret;\n}\n\nz_result_t z_task_detach(z_moved_task_t *task) {\n    _z_task_t *ptr = &task->_this._val;\n    z_result_t ret = _z_task_detach(ptr);\n    return ret;\n}\n\nz_result_t z_task_drop(z_moved_task_t *task) { return z_task_detach(task); }\n\n/*------------------ Mutex ------------------*/\n_Z_OWNED_FUNCTIONS_SYSTEM_IMPL(_z_mutex_t, mutex)\n\nz_result_t z_mutex_init(z_owned_mutex_t *m) { return _z_mutex_init(&m->_val); }\nz_result_t z_mutex_drop(z_moved_mutex_t *m) { return _z_mutex_drop(&m->_this._val); }\n\nz_result_t z_mutex_lock(z_loaned_mutex_t *m) { return _z_mutex_lock(m); }\nz_result_t z_mutex_try_lock(z_loaned_mutex_t *m) { return _z_mutex_try_lock(m); }\nz_result_t z_mutex_unlock(z_loaned_mutex_t *m) { return _z_mutex_unlock(m); }\n\n/*------------------ CondVar ------------------*/\n_Z_OWNED_FUNCTIONS_SYSTEM_IMPL(_z_condvar_t, condvar)\n\nz_result_t z_condvar_init(z_owned_condvar_t *cv) { return _z_condvar_init(&cv->_val); }\nz_result_t z_condvar_drop(z_moved_condvar_t *cv) { return _z_condvar_drop(&cv->_this._val); }\n\nz_result_t z_condvar_signal(z_loaned_condvar_t *cv) { return _z_condvar_signal(cv); }\nz_result_t z_condvar_wait(z_loaned_condvar_t *cv, z_loaned_mutex_t *m) { return _z_condvar_wait(cv, m); }\nz_result_t z_condvar_wait_until(z_loaned_condvar_t *cv, z_loaned_mutex_t *m, const z_clock_t *abstime) {\n    return _z_condvar_wait_until(cv, m, abstime);\n}\n\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n"
  },
  {
    "path": "src/system/emscripten/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(blocking);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    _ZP_UNUSED(iter);\n    _ZP_UNUSED(timeout_ms);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\n#if Z_FEATURE_LINK_TCP == 1\n#error \"TCP not supported yet on Emscripten port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n#error \"UDP not supported yet on Emscripten port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on Emscripten port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#error \"Serial not supported yet on Emscripten port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on Emscripten port of Zenoh-Pico\"\n#endif\n"
  },
  {
    "path": "src/system/emscripten/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <emscripten/html5.h>\n#include <errno.h>\n#include <pthread.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/common/system_error.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return (emscripten_random() * 255.0); }\n\nuint16_t z_random_u16(void) { return (emscripten_random() * 65535.0); }\n\nuint32_t z_random_u32(void) { return (emscripten_random() * 4294967295.0); }\n\nuint64_t z_random_u64(void) { return (emscripten_random() * 18446744073709551615.0); }\n\nvoid z_random_fill(void *buf, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        *((uint8_t *)buf) = z_random_u8();\n    }\n}\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) { return malloc(size); }\n\nvoid *z_realloc(void *ptr, size_t size) { return realloc(ptr, size); }\n\nvoid z_free(void *ptr) { free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, pthread_attr_t *attr, void *(*fun)(void *), void *arg) {\n    _Z_CHECK_SYS_ERR(pthread_create(task, attr, fun, arg));\n}\n\nz_result_t _z_task_join(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_join(*task, NULL)); }\n\nz_result_t _z_task_detach(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_detach(*task)); }\n\nz_result_t _z_task_cancel(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_cancel(*task)); }\n\nvoid _z_task_exit(void) { pthread_exit(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return *task; }\n_z_task_id_t _z_task_current_id(void) { return pthread_self(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return pthread_equal(*l, *r) != 0; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_init(m, NULL)); }\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) {\n    pthread_mutexattr_t attr;\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_init(&attr));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutex_init(m, &attr));\n    _Z_CHECK_SYS_ERR(pthread_mutexattr_destroy(&attr));\n}\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    pthread_condattr_t attr;\n    pthread_condattr_init(&attr);\n    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);\n    _Z_CHECK_SYS_ERR(pthread_cond_init(cv, &attr));\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_destroy(cv)); }\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_signal(cv)); }\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_broadcast(cv)); }\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_cond_wait(cv, m)); }\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    struct timespec ts;\n    ts.tv_sec = (time_t)(*abstime / 1000);\n    ts.tv_nsec = (long)((*abstime - (ts.tv_sec * 1000)) * 1000000);\n\n    int error = pthread_cond_timedwait(cv, m, &ts);\n\n    if (error == ETIMEDOUT) {\n        return Z_ETIMEDOUT;\n    }\n\n    _Z_CHECK_SYS_ERR(error);\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    emscripten_sleep((time / 1000) + (time % 1000 == 0 ? 0 : 1));\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    emscripten_sleep(time);\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    z_time_t start = z_time_now();\n\n    // Most sleep APIs promise to sleep at least whatever you asked them to.\n    // This may compound, so this approach may make sleeps longer than expected.\n    // This extra check tries to minimize the amount of extra time it might sleep.\n    while (z_time_elapsed_s(&start) < time) {\n        z_sleep_ms(1000);\n    }\n\n    return 0;\n}\n\nunsigned long z_time_elapsed_ms_since(z_time_t *time, z_time_t *epoch) {\n    unsigned long elapsed = *time > *epoch ? *time - *epoch : 0;\n    return elapsed;\n}\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) { return z_time_now(); }\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    return z_time_elapsed_ms_since(instant, epoch) * 1000;\n}\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    return z_time_elapsed_ms_since(instant, epoch);\n}\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    return z_time_elapsed_ms_since(instant, epoch) / 1000;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) { return z_clock_elapsed_ms(instant) * 1000; }\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) { return z_time_elapsed_ms(instant); }\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) { return z_time_elapsed_ms(instant) / 1000; }\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) { *clock += (double)(duration / 1000); }\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) { *clock += (double)duration; }\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { *clock += (double)(duration * 1000); }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) { return emscripten_get_now(); }\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    snprintf(buf, buflen, \"%f\", z_time_now());\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) { return z_time_elapsed_ms(time) * 1000; }\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now = emscripten_get_now();\n    return z_time_elapsed_ms_since(&now, time);\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) { return z_time_elapsed_ms(time) / 1000; }\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    double date = emscripten_date_now();\n    t->secs = (uint32_t)(date / 1000);\n    t->nanos = (uint32_t)((date - t->secs * 1000) * 1000000);\n    return 0;\n}\n"
  },
  {
    "path": "src/system/espidf/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ESPIDF)\n\n#include <errno.h>\n#include <esp_heap_caps.h>\n#include <esp_random.h>\n#include <stddef.h>\n#include <sys/time.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/common/system_error.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return z_random_u32(); }\n\nuint16_t z_random_u16(void) { return z_random_u32(); }\n\nuint32_t z_random_u32(void) { return esp_random(); }\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) { esp_fill_random(buf, len); }\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) { return heap_caps_malloc(size, MALLOC_CAP_8BIT); }\n\nvoid *z_realloc(void *ptr, size_t size) { return heap_caps_realloc(ptr, size, MALLOC_CAP_8BIT); }\n\nvoid z_free(void *ptr) { heap_caps_free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n// This wrapper is only used for ESP32.\n// In FreeRTOS, tasks created using xTaskCreate must end with vTaskDelete.\n// A task function should __not__ simply return.\ntypedef struct {\n    void *(*fun)(void *);\n    void *arg;\n    EventGroupHandle_t join_event;\n} z_task_arg;\n\nstatic void z_task_wrapper(void *arg) {\n    z_task_arg *targ = (z_task_arg *)arg;\n    targ->fun(targ->arg);\n    xEventGroupSetBits(targ->join_event, 1);\n    vTaskDelete(NULL);\n}\n\nstatic z_task_attr_t z_default_task_attr = {\n    .name = \"\",\n    .priority = configMAX_PRIORITIES / 2,\n    .stack_depth = 5120,\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    .static_allocation = false,\n    .stack_buffer = NULL,\n    .task_buffer = NULL,\n#endif /* SUPPORT_STATIC_ALLOCATION */\n};\n\n/*------------------ Thread ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *arg_attr, void *(*fun)(void *), void *arg) {\n    z_task_attr_t *attr = arg_attr;\n    z_task_arg *z_arg = (z_task_arg *)z_malloc(sizeof(z_task_arg));\n    if (z_arg == NULL) {\n        return -1;\n    }\n\n    z_arg->fun = fun;\n    z_arg->arg = arg;\n    task->join_event = xEventGroupCreate();\n    z_arg->join_event = task->join_event;\n\n    if (attr == NULL) {\n        attr = &z_default_task_attr;\n    }\n\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    if (attr->static_allocation) {\n        task->handle = xTaskCreateStatic(z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority,\n                                         attr->stack_buffer, attr->task_buffer);\n        if (task->handle == NULL) {\n            return -1;\n        }\n    } else {\n#endif /* SUPPORT_STATIC_ALLOCATION */\n        if (xTaskCreate(z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority, &task->handle) !=\n            pdPASS) {\n            return -1;\n        }\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    }\n#endif /* SUPPORT_STATIC_ALLOCATION */\n\n    return 0;\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    xEventGroupWaitBits(task->join_event, 1, pdFALSE, pdFALSE, portMAX_DELAY);\n    return 0;\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    // Not implemented\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nz_result_t z_task_cancel(_z_task_t *task) {\n    vTaskDelete(task->handle);\n    return 0;\n}\n\nvoid _z_task_exit(void) { vTaskDelete(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr->join_event);\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return task->handle; }\n_z_task_id_t _z_task_current_id(void) { return xTaskGetCurrentTaskHandle(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_init(m, NULL)); }\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) {\n    pthread_mutexattr_t attr;\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_init(&attr));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutex_init(m, &attr));\n    _Z_CHECK_SYS_ERR(pthread_mutexattr_destroy(&attr));\n}\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    pthread_condattr_t attr;\n    pthread_condattr_init(&attr);\n    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);\n    _Z_CHECK_SYS_ERR(pthread_cond_init(cv, &attr));\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_destroy(cv)); }\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_signal(cv)); }\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_broadcast(cv)); }\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_cond_wait(cv, m)); }\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    int error = pthread_cond_timedwait(cv, m, abstime);\n\n    if (error == ETIMEDOUT) {\n        return Z_ETIMEDOUT;\n    }\n\n    _Z_CHECK_SYS_ERR(error);\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time / 1000));\n    return _Z_RES_OK;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time));\n    return _Z_RES_OK;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time * 1000));\n    return _Z_RES_OK;\n}\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = now.tv_sec - time->tv_sec;\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = now.tv_sec;\n    t->nanos = now.tv_usec * 1000;\n    return 0;\n}\n\n#endif /* defined(ZENOH_ESPIDF) */\n"
  },
  {
    "path": "src/system/flipper/network.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(blocking);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\n#if Z_FEATURE_LINK_TCP == 1\n#error \"TCP is not supported on Flipper port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1\n#error \"UDP is not supported on Flipper port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported on Flipper port of Zenoh-Pico\"\n#endif\n"
  },
  {
    "path": "src/system/flipper/system.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <furi.h>\n#include <stddef.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return random(); }\n\nuint16_t z_random_u16(void) { return random(); }\n\nuint32_t z_random_u32(void) { return random(); }\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n\n    return ret;\n}\n\nvoid z_random_fill(void* buf, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        ((uint8_t*)buf)[i] = z_random_u8();\n    }\n}\n\n/*------------------ Memory ------------------*/\nvoid* z_malloc(size_t size) {\n    if (!size) {\n        return NULL;\n    }\n    return malloc(size);\n}\n\nvoid* z_realloc(void* ptr, size_t size) {\n    if (!size) {\n        free(ptr);\n        return NULL;\n    }\n    return realloc(ptr, size);\n}\n\nvoid z_free(void* ptr) { return free(ptr); }\n\n/*------------------ Task ------------------*/\n\nz_result_t _z_task_init(_z_task_t* task, z_task_attr_t* attr, void* (*fun)(void*), void* arg) {\n    if (task == NULL) {\n        return -1;\n    }\n\n    uint32_t stack_size = FLIPPER_DEFAULT_THREAD_STACK_SIZE;\n    if (attr) {\n        stack_size = *attr;\n    }\n\n    *task = furi_thread_alloc_ex(NULL, stack_size, (FuriThreadCallback)fun, arg);\n    if (*task == NULL) {\n        return -1;\n    }\n    furi_thread_start(*task);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_task_join(_z_task_t* task) {\n    if (task == NULL) {\n        return -1;\n    }\n    return furi_thread_join(*task);\n}\n\nz_result_t _z_task_detach(_z_task_t* task) { return -1; }\n\nz_result_t _z_task_cancel(_z_task_t* task) { return -1; }\n\nvoid _z_task_exit(void) {}\n\nvoid _z_task_free(_z_task_t** task) {\n    if (task == NULL || *task == NULL) {\n        return;\n    }\n    furi_thread_free(**task);\n    z_free(*task);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t* task) { return furi_thread_get_id(*task); }\n_z_task_id_t _z_task_current_id(void) { return furi_thread_get_current_id(); }\nbool _z_task_id_equal(const _z_task_id_t* l, const _z_task_id_t* r) { return *l == *r; }\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t* m) {\n    if (m == NULL) {\n        return -1;\n    }\n    *m = furi_mutex_alloc(FuriMutexTypeRecursive);\n    return (*m != 0) ? _Z_RES_OK : _Z_ERR_SYSTEM_TASK_FAILED;\n}\n\nz_result_t _z_mutex_drop(_z_mutex_t* m) {\n    if (m == NULL) {\n        return -1;\n    }\n    if (*m == 0) {\n        return 0;\n    }\n    furi_mutex_free(*m);\n    *m = NULL;\n    return 0;\n}\n\nz_result_t _z_mutex_lock(_z_mutex_t* m) {\n    if (m == NULL) {\n        return -1;\n    }\n    if (*m == 0) {\n        return 0;\n    }\n    return furi_mutex_acquire(*m, FuriWaitForever);\n}\n\nz_result_t _z_mutex_try_lock(_z_mutex_t* m) { return -1; }\n\nz_result_t _z_mutex_unlock(_z_mutex_t* m) {\n    if (m == NULL) {\n        return -1;\n    }\n    if (*m == 0) {\n        return 0;\n    }\n    return furi_mutex_release(*m);\n}\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t* cv) { return -1; }\n\nz_result_t _z_condvar_drop(_z_condvar_t* cv) { return -1; }\n\nz_result_t _z_condvar_signal(_z_condvar_t* cv) { return -1; }\n\nz_result_t _z_condvar_signal_all(_z_condvar_t* cv) { return -1; }\n\nz_result_t _z_condvar_wait(_z_condvar_t* cv, _z_mutex_t* m) { return -1; }\n\nz_result_t _z_condvar_wait_until(_z_condvar_t* cv, _z_mutex_t* m, const z_clock_t* abstime) { return -1; }\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    furi_delay_us(time);\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    furi_delay_ms(time);\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    z_time_t start = z_time_now();\n\n    // Most sleep APIs promise to sleep at least whatever you asked them to.\n    // This may compound, so this approach may make sleeps longer than expected.\n    // This extra check tries to minimize the amount of extra time it might sleep.\n    while (z_time_elapsed_s(&start) < time) {\n        z_sleep_ms(1000);\n    }\n\n    return 0;\n}\n\n/*------------------ Instant ------------------*/\nvoid __z_clock_gettime(z_clock_t* ts) {\n    uint64_t m = millis();\n    ts->tv_sec = m / (uint64_t)1000000;\n    ts->tv_nsec = (m % (uint64_t)1000000) * (uint64_t)1000;\n}\n\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t* instant, z_clock_t* epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t* instant, z_clock_t* epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t* instant, z_clock_t* epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t* instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t* instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t* instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t* clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t* clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t* clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char* z_time_now_as_str(char* const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t* time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t* time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t* time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = now.tv_sec - time->tv_sec;\n    return elapsed;\n}\n\nchar* strncat(char* dest, const char* src, size_t dest_size) {\n    size_t dest_len = strlen(dest);\n    size_t i;\n\n    for (i = 0; i < dest_size && src[i] != '\\0'; i++) {\n        dest[dest_len + i] = src[i];\n    }\n    dest[dest_len + i] = '\\0';\n\n    return dest;\n}\n\nchar* strpbrk(const char* str, const char* charset) {\n    while (*str != '\\0') {\n        const char* c = charset;\n        while (*c != '\\0') {\n            if (*str == *c) {\n                return (char*)str;\n            }\n            c++;\n        }\n        str++;\n    }\n    return NULL;\n}\n\nsize_t strftime(char* s, size_t max, const char* format, const struct tm* tm) {\n    // not supported\n    s[0] = 0;\n    return 0;\n}\n\nint gettimeofday(struct timeval* __restrict __p, void* __restrict __tz) {\n    // not supported\n    __p->tv_sec = 0;\n    __p->tv_usec = 0;\n    return 0;\n}\n\nstruct tm* localtime(const time_t* timep) {\n    // not supported\n    static struct tm t;\n    return &t;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch* t) { return -1; }\n"
  },
  {
    "path": "src/system/freertos/freertos_plus_tcp/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n// FreeRTOS includes\n#include \"FreeRTOS.h\"\n#include \"FreeRTOS_IP.h\"\n#include \"FreeRTOS_Sockets.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    TickType_t option_value = blocking ? pdMS_TO_TICKS(Z_CONFIG_SOCKET_TIMEOUT) : 0;\n    BaseType_t result =\n        FreeRTOS_setsockopt(sock->_socket, 0, FREERTOS_SO_RCVTIMEO, &option_value, sizeof(option_value));\n\n    if (result != pdPASS) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { FreeRTOS_closesocket(sock->_socket); }\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_socket_wait_iter_reset(iter);\n    if (!_z_socket_wait_iter_next(iter)) {\n        return _Z_RES_OK;\n    }\n\n    SocketSet_t socketSet = FreeRTOS_CreateSocketSet();\n    if (socketSet == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n\n    do {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, false);\n        FreeRTOS_FD_SET(sock->_socket, socketSet, eSELECT_READ);\n    } while (_z_socket_wait_iter_next(iter));\n\n    BaseType_t result = FreeRTOS_select(socketSet, pdMS_TO_TICKS(timeout_ms));\n    if (result != 0) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, FreeRTOS_FD_ISSET(sock->_socket, socketSet) != 0);\n    }\n\n    FreeRTOS_DeleteSocketSet(socketSet);\n    return ret;\n}\n\n#if Z_FEATURE_LINK_UDP_MULTICAST == 1\n#error \"UDP Multicast not supported yet on FreeRTOS-Plus-TCP port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on FreeRTOS-Plus-TCP port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#error \"Serial not supported yet on FreeRTOS-Plus-TCP port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on FreeRTOS-Plus-TCP port of Zenoh-Pico\"\n#endif\n"
  },
  {
    "path": "src/system/freertos/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n// Copyright (c) 2023 Fictionlab sp. z o.o.\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//   Błażej Sowa, <blazej@fictionlab.pl>\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/time.h>\n\n#if defined(ZENOH_FREERTOS_PLUS_TCP)\n#include \"FreeRTOS_IP.h\"\n#elif defined(ZENOH_FREERTOS_LWIP)\n#include \"lwip/arch.h\"\n#else\n#error \"FreeRTOS System Implementation was used but no compatible network stack was selected\"\n#endif\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return z_random_u32(); }\n\nuint16_t z_random_u16(void) { return z_random_u32(); }\n\nuint32_t z_random_u32(void) {\n#if defined(ZENOH_FREERTOS_PLUS_TCP)\n    uint32_t ret = 0;\n    xApplicationGetRandomNumber(&ret);\n    return ret;\n#elif defined(ZENOH_FREERTOS_LWIP)\n    return LWIP_RAND();\n#else\n#error \"FreeRTOS System Implementation was used but no compatible network stack was selected\"\n#endif\n}\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) {\n    uint8_t *p = (uint8_t *)buf;\n    for (size_t i = 0; i < len; i++) {\n        p[i] = z_random_u8();\n    }\n}\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) {\n    if (size == 0) {\n        return NULL;\n    }\n    return pvPortMalloc(size);\n}\n\nvoid *z_realloc(void *ptr, size_t size) {\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(size);\n    // realloc not implemented in FreeRTOS\n    return NULL;\n}\n\nvoid z_free(void *ptr) { vPortFree(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n/*------------------ Thread ------------------*/\nstatic void z_task_wrapper(void *arg) {\n    _z_task_t *task = (_z_task_t *)arg;\n\n    // Run the task function\n    task->fun(task->arg);\n\n    // Notify the joiner that the task has finished\n    xEventGroupSetBits(task->join_event, 1);\n\n    // In FreeRTOS, when a task deletes itself, it adds itself to a list of tasks awaiting to be terminated by the idle\n    // task. There is no guarantee when exactly that will happen, which could lead to race conditions on freeing the\n    // task resources. To avoid this, we suspend the task indefinitely and delete this task from another task running\n    // z_task_join or z_task_detach.\n    vTaskSuspend(NULL);\n}\n\nstatic z_task_attr_t z_default_task_attr = {\n    .name = \"\",\n    .priority = configMAX_PRIORITIES / 2,\n    .stack_depth = 5120,\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    .static_allocation = false,\n    .stack_buffer = NULL,\n    .task_buffer = NULL,\n#endif /* SUPPORT_STATIC_ALLOCATION */\n};\n\n/*------------------ Thread ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    task->fun = fun;\n    task->arg = arg;\n\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    task->join_event = xEventGroupCreateStatic(&task->join_event_buffer);\n#else\n    task->join_event = xEventGroupCreate();\n#endif /* SUPPORT_STATIC_ALLOCATION */\n\n    if (attr == NULL) {\n        attr = &z_default_task_attr;\n    }\n\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    if (attr->static_allocation) {\n        task->handle = xTaskCreateStatic(z_task_wrapper, attr->name, attr->stack_depth, task, attr->priority,\n                                         attr->stack_buffer, attr->task_buffer);\n        if (task->handle == NULL) {\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n    } else {\n#endif /* SUPPORT_STATIC_ALLOCATION */\n        if (xTaskCreate(z_task_wrapper, attr->name, attr->stack_depth, task, attr->priority, &task->handle) != pdPASS) {\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    }\n#endif /* SUPPORT_STATIC_ALLOCATION */\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    xEventGroupWaitBits(task->join_event, 1, pdFALSE, pdFALSE, portMAX_DELAY);\n\n    taskENTER_CRITICAL();\n    if (task->handle != NULL) {\n        vTaskDelete(task->handle);\n        task->handle = NULL;\n    }\n    taskEXIT_CRITICAL();\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    _ZP_UNUSED(task);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nz_result_t _z_task_cancel(_z_task_t *task) {\n    taskENTER_CRITICAL();\n    if (task->handle != NULL) {\n        vTaskDelete(task->handle);\n        task->handle = NULL;\n    }\n    taskEXIT_CRITICAL();\n\n    xEventGroupSetBits(task->join_event, 1);\n\n    return _Z_RES_OK;\n}\n\nvoid _z_task_exit(void) { vTaskDelete(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    vEventGroupDelete(ptr->join_event);\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return task->handle; }\n_z_task_id_t _z_task_current_id(void) { return xTaskGetCurrentTaskHandle(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) {\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    m->handle = xSemaphoreCreateRecursiveMutexStatic(&m->buffer);\n#else\n    m->handle = xSemaphoreCreateRecursiveMutex();\n#endif /* SUPPORT_STATIC_ALLOCATION */\n    return m->handle == NULL ? _Z_ERR_GENERIC : _Z_RES_OK;\n}\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) {\n    vSemaphoreDelete(m->handle);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) {\n    return xSemaphoreTakeRecursive(m->handle, portMAX_DELAY) == pdTRUE ? _Z_RES_OK : _Z_ERR_GENERIC;\n}\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) {\n    return xSemaphoreTakeRecursive(m->handle, 0) == pdTRUE ? _Z_RES_OK : _Z_ERR_GENERIC;\n}\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) {\n    return xSemaphoreGiveRecursive(m->handle) == pdTRUE ? _Z_RES_OK : _Z_ERR_GENERIC;\n}\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) { return _z_mutex_init(m); }\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { return _z_mutex_drop(m); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { return _z_mutex_lock(m); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { return _z_mutex_try_lock(m); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { return _z_mutex_unlock(m); }\n\n/*------------------ CondVar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n#if (configSUPPORT_STATIC_ALLOCATION == 1)\n    cv->mutex = xSemaphoreCreateMutexStatic(&cv->mutex_buffer);\n    cv->sem = xSemaphoreCreateCountingStatic((UBaseType_t)(~0), 0, &cv->sem_buffer);\n#else\n    cv->mutex = xSemaphoreCreateMutex();\n    cv->sem = xSemaphoreCreateCounting((UBaseType_t)(~0), 0);\n#endif /* SUPPORT_STATIC_ALLOCATION */\n    cv->waiters = 0;\n\n    if (!cv->mutex || !cv->sem) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    vSemaphoreDelete(cv->sem);\n    vSemaphoreDelete(cv->mutex);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    if (cv->waiters > 0) {\n        xSemaphoreGive(cv->sem);\n        cv->waiters--;\n    }\n    xSemaphoreGive(cv->mutex);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    while (cv->waiters > 0) {\n        xSemaphoreGive(cv->sem);\n        cv->waiters--;\n    }\n    xSemaphoreGive(cv->mutex);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    cv->waiters++;\n    xSemaphoreGive(cv->mutex);\n\n    _z_mutex_unlock(m);\n\n    xSemaphoreTake(cv->sem, portMAX_DELAY);\n\n    _z_mutex_lock(m);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    TickType_t now = xTaskGetTickCount();\n    TickType_t target_time = *abstime;\n    TickType_t block_duration = (target_time > now) ? (target_time - now) : 0;\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    cv->waiters++;\n    xSemaphoreGive(cv->mutex);\n\n    _z_mutex_unlock(m);\n\n    bool timed_out = xSemaphoreTake(cv->sem, block_duration) == pdFALSE;\n\n    _z_mutex_lock(m);\n\n    if (timed_out) {\n        xSemaphoreTake(cv->mutex, portMAX_DELAY);\n        cv->waiters--;\n        xSemaphoreGive(cv->mutex);\n        return Z_ETIMEDOUT;\n    }\n\n    return _Z_RES_OK;\n}\n#endif  // Z_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time / 1000));\n    return _Z_RES_OK;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time));\n    return _Z_RES_OK;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time * 1000));\n    return _Z_RES_OK;\n}\n\n/*------------------ Clock ------------------*/\nz_clock_t z_clock_now(void) { return xTaskGetTickCount(); }\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    return zp_clock_elapsed_ms_since(instant, epoch) * 1000;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    return *instant > *epoch ? (*instant - *epoch) * portTICK_PERIOD_MS : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    return zp_clock_elapsed_ms_since(instant, epoch) / 1000;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) { return z_clock_elapsed_ms(instant) * 1000; }\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now = z_clock_now();\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) { return z_clock_elapsed_ms(instant) / 1000; }\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) { z_clock_advance_ms(clock, duration / 1000); }\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    unsigned long ticks = pdMS_TO_TICKS(duration);\n    *clock += ticks;\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { z_clock_advance_ms(clock, duration * 1000); }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(now.tv_sec - time->tv_sec);\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = (uint32_t)now.tv_sec;\n    t->nanos = (uint32_t)now.tv_usec * 1000;\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/system/mbed/network.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_MBED)\n\n#include <NetworkInterface.h>\n#include <USBSerial.h>\n#include <mbed.h>\n\nextern \"C\" {\n#include <netdb.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(blocking);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    _ZP_UNUSED(iter);\n    _ZP_UNUSED(timeout_ms);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on MBED port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on MBED port of Zenoh-Pico\"\n#endif\n\n}  // extern \"C\"\n\n#endif /* defined(ZENOH_MBED) */\n"
  },
  {
    "path": "src/system/mbed/system.cpp",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_MBED)\n\n#include <mbed.h>\n#include <randLIB.h>\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n\nextern \"C\" {\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return randLIB_get_8bit(); }\n\nuint16_t z_random_u16(void) { return randLIB_get_16bit(); }\n\nuint32_t z_random_u32(void) { return randLIB_get_32bit(); }\n\nuint64_t z_random_u64(void) { return randLIB_get_64bit(); }\n\nvoid z_random_fill(void *buf, size_t len) { randLIB_get_n_bytes_random(buf, len); }\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) { return malloc(size); }\n\nvoid *z_realloc(void *ptr, size_t size) { return realloc(ptr, size); }\n\nvoid z_free(void *ptr) { free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    *task = new Thread();\n    mbed::Callback<void()> c = mbed::Callback<void()>(fun, arg);\n    return ((Thread *)*task)->start(c);\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    int res = ((Thread *)*task)->join();\n    delete ((Thread *)*task);\n    return res;\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    // Not implemented\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nz_result_t _z_task_cancel(_z_task_t *task) {\n    int res = ((Thread *)*task)->terminate();\n    delete ((Thread *)*task);\n    return res;\n}\n\nvoid _z_task_exit(void) {}\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return ((Thread *)*task)->get_id(); }\n_z_task_id_t _z_task_current_id(void) { return ThisThread::get_id(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) {\n    *m = new Mutex();\n    return 0;\n}\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) {\n    delete ((Mutex *)*m);\n    return 0;\n}\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) {\n    ((Mutex *)*m)->lock();\n    return 0;\n}\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { return (((Mutex *)*m)->trylock() == true) ? 0 : -1; }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) {\n    ((Mutex *)*m)->unlock();\n    return 0;\n}\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) { return _z_mutex_init(m); }\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { return _z_mutex_drop(m); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { return _z_mutex_lock(m); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { return _z_mutex_try_lock(m); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { return _z_mutex_unlock(m); }\n\n/*------------------ Condvar ------------------*/\nstruct condvar {\n    Mutex mutex;\n    Semaphore sem{0};\n    int waiters{0};\n};\n\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    *cv = new condvar();\n    return 0;\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    delete ((condvar *)*cv);\n    return 0;\n}\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    auto &cond_var = *(condvar *)*cv;\n\n    cond_var.mutex.lock();\n    if (cond_var.waiters > 0) {\n        cond_var.sem.release();\n        cond_var.waiters--;\n    }\n    cond_var.mutex.unlock();\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    auto &cond_var = *(condvar *)*cv;\n\n    cond_var.mutex.lock();\n    while (cond_var.waiters > 0) {\n        cond_var.sem.release();\n        cond_var.waiters--;\n    }\n    cond_var.mutex.unlock();\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    auto &cond_var = *(condvar *)*cv;\n\n    cond_var.mutex.lock();\n    cond_var.waiters++;\n    cond_var.mutex.unlock();\n\n    _z_mutex_unlock(m);\n\n    cond_var.sem.acquire();\n\n    _z_mutex_lock(m);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    auto &cond_var = *(condvar *)*cv;\n\n    auto target_time =\n        Kernel::Clock::time_point(Kernel::Clock::duration(abstime->tv_sec * 1000LL + abstime->tv_nsec / 1000000));\n\n    cond_var.mutex.lock();\n    cond_var.waiters++;\n    cond_var.mutex.unlock();\n\n    _z_mutex_unlock(m);\n\n    bool timed_out = cond_var.sem.try_acquire_until(target_time) == false;\n\n    _z_mutex_lock(m);\n\n    if (timed_out) {\n        cond_var.mutex.lock();\n        cond_var.waiters--;\n        cond_var.mutex.unlock();\n        return Z_ETIMEDOUT;\n    }\n\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    ThisThread::sleep_for(chrono::milliseconds(((time / 1000) + (time % 1000 == 0 ? 0 : 1))));\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    ThisThread::sleep_for(chrono::milliseconds(time));\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    ThisThread::sleep_for(chrono::seconds(time));\n    return 0;\n}\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) {\n    auto now = Kernel::Clock::now();\n    auto duration = now.time_since_epoch();\n    auto secs = std::chrono::duration_cast<std::chrono::seconds>(duration);\n    auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(duration - secs);\n\n    z_clock_t ts;\n    ts.tv_sec = secs.count();\n    ts.tv_nsec = nanos.count();\n    return ts;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t* epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t* epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t* epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now = z_clock_now();\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now = z_clock_now();\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now = z_clock_now();\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = now.tv_sec - time->tv_sec;\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = now.tv_sec;\n    t->nanos = now.tv_usec * 1000;\n    return 0;\n}\n\n}  // extern \"C\"\n\n#endif /* defined(ZENOH_MBED) */\n"
  },
  {
    "path": "src/system/rpi_pico/system.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <limits.h>\n#include <pico/rand.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/time.h>\n\n#include \"FreeRTOS.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return (uint8_t)get_rand_32(); }\n\nuint16_t z_random_u16(void) { return (uint16_t)get_rand_32(); }\n\nuint32_t z_random_u32(void) { return get_rand_32(); }\n\nuint64_t z_random_u64(void) { return get_rand_64(); }\n\nvoid z_random_fill(void *buf, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        *((uint8_t *)buf) = z_random_u8();\n    }\n}\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) {\n    if (size == 0) {\n        return NULL;\n    }\n    return pvPortMalloc(size);\n}\n\nvoid *z_realloc(void *ptr, size_t size) {\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(size);\n    // realloc not implemented in FreeRTOS\n    assert(false);\n    return NULL;\n}\n\nvoid z_free(void *ptr) { vPortFree(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n// In FreeRTOS, tasks created using xTaskCreate must end with vTaskDelete.\n// A task function should __not__ simply return.\ntypedef struct {\n    void *(*fun)(void *);\n    void *arg;\n    EventGroupHandle_t join_event;\n} z_task_arg;\n\nstatic void z_task_wrapper(void *arg) {\n    z_task_arg *targ = (z_task_arg *)arg;\n    targ->fun(targ->arg);\n    xEventGroupSetBits(targ->join_event, 1);\n    vTaskDelete(NULL);\n}\n\nstatic z_task_attr_t z_default_task_attr = {\n    .name = \"\",\n    .priority = configMAX_PRIORITIES / 2,\n    .stack_depth = 1024,\n};\n\n/*------------------ Thread ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    z_task_arg *z_arg = (z_task_arg *)z_malloc(sizeof(z_task_arg));\n    if (z_arg == NULL) {\n        return -1;\n    }\n\n    z_arg->fun = fun;\n    z_arg->arg = arg;\n    z_arg->join_event = task->join_event = xEventGroupCreate();\n\n    if (attr == NULL) {\n        attr = &z_default_task_attr;\n    }\n\n    if (xTaskCreate(z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority, &task->handle) != pdPASS) {\n        return -1;\n    }\n\n    return 0;\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    xEventGroupWaitBits(task->join_event, 1, pdFALSE, pdFALSE, portMAX_DELAY);\n    return 0;\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    _ZP_UNUSED(task);\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nz_result_t _z_task_cancel(_z_task_t *task) {\n    vTaskDelete(task->handle);\n    return 0;\n}\n\nvoid _z_task_exit(void) { vTaskDelete(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr->join_event);\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return task->handle; }\n_z_task_id_t _z_task_current_id(void) { return xTaskGetCurrentTaskHandle(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) {\n    *m = xSemaphoreCreateRecursiveMutex();\n    return *m == NULL ? -1 : 0;\n}\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) {\n    z_free(*m);\n    return 0;\n}\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { return xSemaphoreTakeRecursive(*m, portMAX_DELAY) == pdTRUE ? 0 : -1; }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { return xSemaphoreTakeRecursive(*m, 0) == pdTRUE ? 0 : -1; }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { return xSemaphoreGiveRecursive(*m) == pdTRUE ? 0 : -1; }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) { return _z_mutex_init(m); }\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { return _z_mutex_drop(m); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { return _z_mutex_lock(m); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { return _z_mutex_try_lock(m); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { return _z_mutex_unlock(m); }\n\n/*------------------ CondVar ------------------*/\nstatic UBaseType_t CONDVAR_MAX_WAITERS_COUNT = UINT_MAX;\n\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    cv->mutex = xSemaphoreCreateMutex();\n    cv->sem = xSemaphoreCreateCounting(CONDVAR_MAX_WAITERS_COUNT, 0);\n    cv->waiters = 0;\n\n    if (!cv->mutex || !cv->sem) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    vSemaphoreDelete(cv->sem);\n    vSemaphoreDelete(cv->mutex);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    if (cv->waiters > 0) {\n        xSemaphoreGive(cv->sem);\n        cv->waiters--;\n    }\n    xSemaphoreGive(cv->mutex);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    while (cv->waiters > 0) {\n        xSemaphoreGive(cv->sem);\n        cv->waiters--;\n    }\n    xSemaphoreGive(cv->mutex);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    cv->waiters++;\n    xSemaphoreGive(cv->mutex);\n\n    _z_mutex_unlock(m);\n\n    xSemaphoreTake(cv->sem, portMAX_DELAY);\n\n    return _z_mutex_lock(m);\n}\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    TickType_t now = xTaskGetTickCount();\n    TickType_t target_time = pdMS_TO_TICKS(abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000);\n    TickType_t block_duration = (target_time > now) ? (target_time - now) : 0;\n\n    xSemaphoreTake(cv->mutex, portMAX_DELAY);\n    cv->waiters++;\n    xSemaphoreGive(cv->mutex);\n\n    _z_mutex_unlock(m);\n\n    bool timed_out = xSemaphoreTake(cv->sem, block_duration) == pdFALSE;\n\n    _z_mutex_lock(m);\n\n    if (timed_out) {\n        xSemaphoreTake(cv->mutex, portMAX_DELAY);\n        cv->waiters--;\n        xSemaphoreGive(cv->mutex);\n        return Z_ETIMEDOUT;\n    }\n\n    return _Z_RES_OK;\n}\n#endif  // Z_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time / 1000));\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time));\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    vTaskDelay(pdMS_TO_TICKS(time * 1000));\n    return 0;\n}\n\n/*------------------ Clock ------------------*/\nvoid __z_clock_gettime(z_clock_t *ts) {\n    uint64_t m = xTaskGetTickCount() / portTICK_PERIOD_MS;\n    ts->tv_sec = m / (uint64_t)1000;\n    ts->tv_nsec = (m % (uint64_t)1000) * (uint64_t)1000000;\n}\n\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(now.tv_sec - time->tv_sec);\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = (uint32_t)now.tv_sec;\n    t->nanos = (uint32_t)now.tv_usec * 1000;\n    return 0;\n}\n"
  },
  {
    "path": "src/system/rpi_pico/usb_uart.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_LINK_SERIAL == 1 && Z_FEATURE_LINK_SERIAL_USB == 1\n\n#include \"pico/unique_id.h\"\n#include \"tusb.h\"\n\n// ===== USB descriptors =====\n// Copied from\n// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c\n//\n#ifndef USBD_VID\n#define USBD_VID (0x2E8A)  // Raspberry Pi\n#endif\n\n#ifndef USBD_PID\n#if PICO_RP2040\n#define USBD_PID (0x000a)  // Raspberry Pi Pico SDK CDC for RP2040\n#else\n#define USBD_PID (0x0009)  // Raspberry Pi Pico SDK CDC\n#endif\n#endif\n\n#ifndef USBD_MANUFACTURER\n#define USBD_MANUFACTURER \"Raspberry Pi\"\n#endif\n\n#ifndef USBD_PRODUCT\n#define USBD_PRODUCT \"Pico\"\n#endif\n\n#define TUD_RPI_RESET_DESC_LEN 9\n#if !PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE\n#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)\n#else\n#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_RPI_RESET_DESC_LEN)\n#endif\n#if !PICO_STDIO_USB_DEVICE_SELF_POWERED\n#define USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE (0)\n#define USBD_MAX_POWER_MA (250)\n#else\n#define USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE TUSB_DESC_CONFIG_ATT_SELF_POWERED\n#define USBD_MAX_POWER_MA (1)\n#endif\n\n#define USBD_ITF_CDC (0)  // needs 2 interfaces\n#if !PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE\n#define USBD_ITF_MAX (2)\n#else\n#define USBD_ITF_RPI_RESET (2)\n#define USBD_ITF_MAX (3)\n#endif\n\n#define USBD_CDC_EP_CMD (0x81)\n#define USBD_CDC_EP_OUT (0x02)\n#define USBD_CDC_EP_IN (0x82)\n#define USBD_CDC_CMD_MAX_SIZE (8)\n#define USBD_CDC_IN_OUT_MAX_SIZE (64)\n\n#define USBD_STR_0 (0x00)\n#define USBD_STR_MANUF (0x01)\n#define USBD_STR_PRODUCT (0x02)\n#define USBD_STR_SERIAL (0x03)\n#define USBD_STR_CDC (0x04)\n#define USBD_STR_RPI_RESET (0x05)\n\n// Note: descriptors returned from callbacks must exist long enough for transfer to complete\n\nstatic const tusb_desc_device_t usbd_desc_device = {\n    .bLength = sizeof(tusb_desc_device_t),\n    .bDescriptorType = TUSB_DESC_DEVICE,\n// On Windows, if bcdUSB = 0x210 then a Microsoft OS 2.0 descriptor is required, else the device won't be detected\n// This is only needed for driverless access to the reset interface - the CDC interface doesn't require these\n// descriptors for driverless access, but will still not work if bcdUSB = 0x210 and no descriptor is provided. Therefore\n// always use bcdUSB = 0x200 if the Microsoft OS 2.0 descriptor isn't enabled\n#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR\n    .bcdUSB = 0x0210,\n#else\n    .bcdUSB = 0x0200,\n#endif\n    .bDeviceClass = TUSB_CLASS_MISC,\n    .bDeviceSubClass = MISC_SUBCLASS_COMMON,\n    .bDeviceProtocol = MISC_PROTOCOL_IAD,\n    .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,\n    .idVendor = USBD_VID,\n    .idProduct = USBD_PID,\n    .bcdDevice = 0x0100,\n    .iManufacturer = USBD_STR_MANUF,\n    .iProduct = USBD_STR_PRODUCT,\n    .iSerialNumber = USBD_STR_SERIAL,\n    .bNumConfigurations = 1,\n};\n\n#define TUD_RPI_RESET_DESCRIPTOR(_itfnum, _stridx)                                               \\\n    /* Interface */                                                                              \\\n    9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, \\\n        RESET_INTERFACE_PROTOCOL, _stridx,\n\nstatic const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {\n    TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE,\n                          USBD_MAX_POWER_MA),\n\n    TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT,\n                       USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),\n\n#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE\n    TUD_RPI_RESET_DESCRIPTOR(USBD_ITF_RPI_RESET, USBD_STR_RPI_RESET)\n#endif\n};\n\nstatic char usbd_serial_str[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];\n\nstatic const char *const usbd_desc_str[] = {\n    [USBD_STR_MANUF] = USBD_MANUFACTURER, [USBD_STR_PRODUCT] = USBD_PRODUCT,\n    [USBD_STR_SERIAL] = usbd_serial_str,  [USBD_STR_CDC] = \"Board CDC\",\n#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE\n    [USBD_STR_RPI_RESET] = \"Reset\",\n#endif\n};\n\nconst uint8_t *tud_descriptor_device_cb(void) { return (const uint8_t *)&usbd_desc_device; }\n\nconst uint8_t *tud_descriptor_configuration_cb(__unused uint8_t index) { return usbd_desc_cfg; }\n\nconst uint16_t *tud_descriptor_string_cb(uint8_t index, __unused uint16_t langid) {\n#ifndef USBD_DESC_STR_MAX\n#define USBD_DESC_STR_MAX (20)\n#elif USBD_DESC_STR_MAX > 127\n#error USBD_DESC_STR_MAX too high (max is 127).\n#elif USBD_DESC_STR_MAX < 17\n#error USBD_DESC_STR_MAX too low (min is 17).\n#endif\n    static uint16_t desc_str[USBD_DESC_STR_MAX];\n\n    // Assign the SN using the unique flash id\n    if (!usbd_serial_str[0]) {\n        pico_get_unique_board_id_string(usbd_serial_str, sizeof(usbd_serial_str));\n    }\n\n    uint8_t len;\n    if (index == 0) {\n        desc_str[1] = 0x0409;  // supported language is English\n        len = 1;\n    } else {\n        if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {\n            return NULL;\n        }\n        const char *str = usbd_desc_str[index];\n        for (len = 0; len < USBD_DESC_STR_MAX - 1 && str[len]; ++len) {\n            desc_str[1 + len] = str[len];\n        }\n    }\n\n    // first byte is length (including header), second byte is string type\n    desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * len + 2));\n\n    return desc_str;\n}\n\n// ===== USB UART methods =====\nstatic _z_mutex_t _z_usb_uart_mutex;\nstatic _z_task_t _z_usb_uart_task;\nstatic volatile bool _z_usb_uart_task_run;\n\nstatic void *_z_usb_uart_task_proc(void *) {\n    while (_z_usb_uart_task_run) {\n        _z_mutex_lock(&_z_usb_uart_mutex);\n        tud_task();\n        _z_mutex_unlock(&_z_usb_uart_mutex);\n        z_sleep_ms(1);\n    }\n    return NULL;\n}\n\nvoid _z_usb_uart_init() {\n    tud_init(BOARD_TUD_RHPORT);\n    _z_mutex_init(&_z_usb_uart_mutex);\n    _z_usb_uart_task_run = true;\n    _z_task_init(&_z_usb_uart_task, NULL, &_z_usb_uart_task_proc, NULL);\n    _Z_DEBUG(\"whating for host...\");\n    while (!tud_cdc_connected()) {\n        z_sleep_ms(100);\n    }\n}\n\nvoid _z_usb_uart_deinit() {\n    _z_usb_uart_task_run = false;\n    _z_task_join(&_z_usb_uart_task);\n    _z_mutex_drop(&_z_usb_uart_mutex);\n    tud_deinit(BOARD_TUD_RHPORT);\n}\n\nvoid _z_usb_uart_write(const uint8_t *buf, int length) {\n    _z_mutex_lock(&_z_usb_uart_mutex);\n    for (int i = 0; i < length;) {\n        int n = length - i;\n        int avail = (int)tud_cdc_write_available();\n        if (n > avail) {\n            n = avail;\n        }\n        if (n != 0) {\n            int n2 = (int)tud_cdc_write(buf + i, (uint32_t)n);\n            tud_task();\n            tud_cdc_write_flush();\n            i += n2;\n        } else {\n            tud_task();\n            tud_cdc_write_flush();\n        }\n    }\n    _z_mutex_unlock(&_z_usb_uart_mutex);\n}\n\nuint8_t _z_usb_uart_getc() {\n    uint8_t ret = 0;\n    bool ready = false;\n    while (true) {\n        _z_mutex_lock(&_z_usb_uart_mutex);\n        ready = tud_cdc_available();\n        if (ready) {\n            ret = tud_cdc_read_char();\n        }\n        _z_mutex_unlock(&_z_usb_uart_mutex);\n        if (ready) {\n            break;\n        } else {\n            z_sleep_ms(1);\n        }\n    }\n    return ret;\n}\n#endif\n"
  },
  {
    "path": "src/system/socket/esp32.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_ESP32)\n\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n#include <fcntl.h>\n#include <netdb.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n#include <unistd.h>\n#endif\n\n#include \"zenoh-pico/utils/logging.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    int flags = fcntl(sock->_fd, F_GETFL, 0);\n    if (flags == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (fcntl(sock->_fd, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK)) == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        shutdown(sock->_fd, SHUT_RDWR);\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    fd_set read_fds;\n    int max_fd = 0;\n    bool has_sockets = false;\n\n    FD_ZERO(&read_fds);\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, false);\n        FD_SET(sock->_fd, &read_fds);\n        if (sock->_fd > max_fd) {\n            max_fd = sock->_fd;\n        }\n        has_sockets = true;\n    }\n\n    if (!has_sockets) {\n        return _Z_RES_OK;\n    }\n\n    struct timeval timeout = {\n        .tv_sec = (time_t)(timeout_ms / 1000U),\n        .tv_usec = (suseconds_t)((timeout_ms % 1000U) * 1000U),\n    };\n    if (select(max_fd + 1, &read_fds, NULL, NULL, &timeout) <= 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, FD_ISSET(sock->_fd, &read_fds));\n    }\n\n    return _Z_RES_OK;\n}\n#else\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(blocking);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    _ZP_UNUSED(iter);\n    _ZP_UNUSED(timeout_ms);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n#endif\n\n#endif /* defined(ZP_PLATFORM_SOCKET_ESP32) */\n"
  },
  {
    "path": "src/system/socket/lwip.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/socket.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_LWIP)\n\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED)\n#include <unistd.h>\n\n#include \"lwip/sockets.h\"\n#include \"zenoh-pico/link/transport/lwip_socket.h\"\n#endif\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if defined(ZP_PLATFORM_SOCKET_LINKS_ENABLED) && Z_FEATURE_LINK_TCP == 1\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    int fd = _z_lwip_socket_get(*sock);\n    int flags = lwip_fcntl(fd, F_GETFL, 0);\n    if (flags == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (lwip_fcntl(fd, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK)) == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) {\n    int fd = _z_lwip_socket_get(*sock);\n    if (fd >= 0) {\n        shutdown(fd, SHUT_RDWR);\n        lwip_close(fd);\n        _z_lwip_socket_set(sock, -1);\n    }\n}\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    fd_set read_fds;\n    int max_fd = 0;\n    bool has_sockets = false;\n\n    FD_ZERO(&read_fds);\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        int fd = _z_lwip_socket_get(*sock);\n        _z_socket_wait_iter_set_ready(iter, false);\n        FD_SET(fd, &read_fds);\n        if (fd > max_fd) {\n            max_fd = fd;\n        }\n        has_sockets = true;\n    }\n\n    if (!has_sockets) {\n        return _Z_RES_OK;\n    }\n\n    struct timeval timeout = {\n        .tv_sec = (time_t)(timeout_ms / 1000U),\n        .tv_usec = (suseconds_t)((timeout_ms % 1000U) * 1000U),\n    };\n    if (lwip_select(max_fd + 1, &read_fds, NULL, NULL, &timeout) <= 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, FD_ISSET(_z_lwip_socket_get(*sock), &read_fds));\n    }\n\n    return _Z_RES_OK;\n}\n\n#else\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    _ZP_UNUSED(sock);\n    _ZP_UNUSED(blocking);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    _ZP_UNUSED(iter);\n    _ZP_UNUSED(timeout_ms);\n    _Z_ERROR(\"Function not yet supported on this system\");\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n#endif\n\n#endif /* defined(ZP_PLATFORM_SOCKET_LWIP) */\n"
  },
  {
    "path": "src/system/threadx/stm32/network.c",
    "content": "/* Ubiquity robotics\n * ======================================================================\n * Zenoh-pico stm32 threadx\n * Network implementation for serial device running in circular DMA mode.\n * ======================================================================\n */\n#if defined(ZENOH_THREADX_STM32)\n#include \"hal.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#if Z_FEATURE_LINK_TCP == 1\n#error \"Z_FEATURE_LINK_TCP is not supported\"\n#endif\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Z_FEATURE_LINK_BLUETOOTH is not supported\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Z_FEATURE_RAWETH_TRANSPORT is not supported\"\n#endif\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) { _ZP_UNUSED(sock); }\n\n#endif  // ZENOH_THREADX_STM32\n"
  },
  {
    "path": "src/system/threadx/stm32/system.c",
    "content": "/* Ubiquity robotics\n * =============================================================\n * Zenoh-pico stm32 threadx\n * System implementation for threadx.\n * =============================================================\n */\n#if defined(ZENOH_THREADX_STM32)\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"tx_api.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/* pointer to threadx byte pool, should be provided by application */\nextern TX_BYTE_POOL *pthreadx_byte_pool;\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return z_random_u32(); }\n\nuint16_t z_random_u16(void) { return z_random_u32(); }\n\nuint32_t z_random_u32(void) { return random(); }\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) {\n    for (size_t i = 0; i < len; i++) {\n        ((uint8_t *)buf)[i] = z_random_u8();\n    }\n}\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) {\n    void *ptr = NULL;\n\n    uint8_t r = tx_byte_allocate(pthreadx_byte_pool, &ptr, size, TX_WAIT_FOREVER);\n    if (r != TX_SUCCESS) {\n        ptr = NULL;\n    }\n    return ptr;\n}\n\nvoid *z_realloc(void *ptr, size_t size) {\n    // realloc not implemented\n    return NULL;\n}\n\nvoid z_free(void *ptr) { tx_byte_release(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Thread ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    _Z_DEBUG(\"Creating a new task!\");\n\n    UINT status = tx_thread_create(&(task->threadx_thread), \"ztask\", (VOID(*)(ULONG))fun, (ULONG)arg,\n                                   task->threadx_stack, Z_TASK_STACK_SIZE, Z_TASK_PRIORITY, Z_TASK_PREEMPT_THRESHOLD,\n                                   Z_TASK_TIME_SLICE, TX_AUTO_START);\n\n    if (status != TX_SUCCESS) _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    while (1) {\n        UINT state;\n        UINT status = tx_thread_info_get(&(task->threadx_thread), NULL, &state, NULL, NULL, NULL, NULL, NULL, NULL);\n        if (status != TX_SUCCESS) _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n\n        if ((state == TX_COMPLETED) || (state == TX_TERMINATED)) break;\n\n        tx_thread_sleep(1);\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    // Not implemented\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nz_result_t _z_task_cancel(_z_task_t *task) {\n    // Not implemented\n    _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n}\n\nvoid _z_task_exit(void) {  // NEW with new vesion\n    // Not implemented\n}\n\nvoid _z_task_free(_z_task_t **task) {\n    z_free(*task);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return (TX_THREAD *)&(task->threadx_thread); }\n_z_task_id_t _z_task_current_id(void) { return tx_thread_identify(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) {\n    UINT status = tx_mutex_create(m, TX_NULL, TX_INHERIT);\n    if (status == TX_MUTEX_ERROR) {\n        // zenoh-pico reuses mutex if zenoh_init() fails.\n        status = tx_mutex_delete(m);\n        if (status == TX_SUCCESS) {\n            status = tx_mutex_create(m, TX_NULL, TX_INHERIT);\n        }\n    }\n    return (status == TX_SUCCESS) ? 0 : -1;\n}\nz_result_t _z_mutex_drop(_z_mutex_t *m) {\n    UINT status = tx_mutex_delete(m);\n    return (status == TX_SUCCESS) ? 0 : -1;\n}\nz_result_t _z_mutex_lock(_z_mutex_t *m) {\n    UINT status = tx_mutex_get(m, TX_WAIT_FOREVER);\n    return (status == TX_SUCCESS) ? 0 : -1;\n}\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) {\n    UINT status = tx_mutex_get(m, TX_NO_WAIT);  // Return immediately even if the mutex was not available\n    return (status == TX_SUCCESS) ? 0 : -1;\n}\nz_result_t _z_mutex_unlock(_z_mutex_t *m) {\n    UINT status = tx_mutex_put(m);\n    return (status == TX_SUCCESS) ? 0 : -1;\n}\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) { return _z_mutex_init(m); }\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { return _z_mutex_drop(m); }\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { return _z_mutex_lock(m); }\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { return _z_mutex_unlock(m); }\n\n/*------------------ CondVar ------------------*/\n#define CONDVAR_MAX_WAITERS_COUNT 0xff;\n\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    UINT m_status = tx_mutex_create(&cv->mutex, TX_NULL, TX_INHERIT);\n    UINT s_status = tx_semaphore_create(&cv->sem, TX_NULL, 0);\n    cv->waiters = 0;\n\n    if (m_status != TX_SUCCESS || s_status != TX_SUCCESS) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    tx_mutex_delete(&cv->mutex);\n    tx_semaphore_delete(&cv->sem);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    tx_mutex_get(&cv->mutex, TX_WAIT_FOREVER);\n    if (cv->waiters > 0) {\n        tx_semaphore_put(&cv->sem);\n        cv->waiters--;\n    }\n    tx_mutex_put(&cv->mutex);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) {\n    if (!cv) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    tx_mutex_get(&cv->mutex, TX_WAIT_FOREVER);\n    while (cv->waiters > 0) {\n        tx_semaphore_put(&cv->sem);\n        cv->waiters--;\n    }\n    tx_mutex_put(&cv->mutex);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    tx_mutex_get(&cv->mutex, TX_WAIT_FOREVER);\n    cv->waiters++;\n    tx_mutex_put(&cv->mutex);\n\n    _z_mutex_unlock(m);\n    tx_semaphore_get(&cv->sem, TX_WAIT_FOREVER);\n\n    _z_mutex_lock(m);\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    if (!cv || !m) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    ULONG now = tx_time_get();\n    ULONG target_time = (abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000) * (TX_TIMER_TICKS_PER_SECOND / 1000);\n    ULONG block_duration = (target_time > now) ? (target_time - now) : 0;\n\n    tx_mutex_get(&cv->mutex, TX_WAIT_FOREVER);\n    cv->waiters++;\n    tx_mutex_put(&cv->mutex);\n\n    _z_mutex_unlock(m);\n\n    bool timed_out = tx_semaphore_get(&cv->sem, block_duration) != TX_SUCCESS;\n\n    _z_mutex_lock(m);\n\n    if (timed_out) {\n        tx_mutex_get(&cv->mutex, TX_WAIT_FOREVER);\n        cv->waiters--;\n        tx_mutex_put(&cv->mutex);\n        return Z_ETIMEDOUT;\n    }\n\n    return _Z_RES_OK;\n}\n#endif  // Z_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    tx_thread_sleep(time * TX_TIMER_TICKS_PER_SECOND / 1000000);\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    tx_thread_sleep(time * TX_TIMER_TICKS_PER_SECOND / 1000);\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    tx_thread_sleep(time * TX_TIMER_TICKS_PER_SECOND);\n    return 0;\n}\n\n/*------------------ Clock ------------------*/\n\nvoid __z_clock_gettime(z_clock_t *ts) {\n    uint64_t ms = tx_time_get() * (TX_TIMER_TICKS_PER_SECOND / 1000);\n    ts->tv_sec = ms / (uint64_t)1000;\n    ts->tv_nsec = (ms % (uint64_t)1000) * (uint64_t)1000;\n}\n\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    __z_clock_gettime(&now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) { return tx_time_get(); }\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    snprintf(buf, buflen, \"%lu\", z_time_now());\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    return (tx_time_get() - *time) * 1000000ULL / TX_TIMER_TICKS_PER_SECOND;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    return (tx_time_get() - *time) * 1000ULL / TX_TIMER_TICKS_PER_SECOND;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) { return (tx_time_get() - *time) * TX_TIMER_TICKS_PER_SECOND; }\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    ULONG64 time_ns = tx_time_get() * 1000000000ULL / TX_TIMER_TICKS_PER_SECOND;\n\n    t->secs = time_ns / 1000000000ULL;\n    t->nanos = time_ns % 1000000000ULL;\n\n    return _Z_RES_OK;\n}\n#endif  // ZENOH_THREADX_STM32\n"
  },
  {
    "path": "src/system/unix/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <arpa/inet.h>\n#include <assert.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <ifaddrs.h>\n#include <net/if.h>\n#include <netdb.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <poll.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    int flags = fcntl(sock->_fd, F_GETFL, 0);\n    if (flags == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (fcntl(sock->_fd, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK)) == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        shutdown(sock->_fd, SHUT_RDWR);\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    fd_set read_fds;\n    int max_fd = 0;\n    bool has_sockets = false;\n\n    FD_ZERO(&read_fds);\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, false);\n        FD_SET(sock->_fd, &read_fds);\n        if (sock->_fd > max_fd) {\n            max_fd = sock->_fd;\n        }\n        has_sockets = true;\n    }\n\n    if (!has_sockets) {\n        return _Z_RES_OK;\n    }\n\n    struct timeval timeout = {\n        .tv_sec = (time_t)(timeout_ms / 1000U),\n        .tv_usec = (suseconds_t)((timeout_ms % 1000U) * 1000U),\n    };\n    int result = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);\n    if (result < 0) {\n        _Z_DEBUG(\"Errno: %d\\n\", errno);\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, FD_ISSET(sock->_fd, &read_fds));\n    }\n\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on Unix port of Zenoh-Pico\"\n#endif\n"
  },
  {
    "path": "src/system/unix/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <errno.h>\n#include <pthread.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"zenoh-pico/utils/result.h\"\n\n#if defined(ZENOH_LINUX)\n#include <sys/random.h>\n#include <sys/time.h>\n#endif\n\n#include <unistd.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/common/system_error.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) {\n    uint8_t ret = 0;\n#if defined(ZENOH_LINUX)\n    while (getrandom(&ret, sizeof(uint8_t), 0) <= 0) {\n        ZP_ASM_NOP;\n    }\n#elif defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n    ret = z_random_u32();\n#endif\n\n    return ret;\n}\n\nuint16_t z_random_u16(void) {\n    uint16_t ret = 0;\n#if defined(ZENOH_LINUX)\n    while (getrandom(&ret, sizeof(uint16_t), 0) <= 0) {\n        ZP_ASM_NOP;\n    }\n#elif defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n    ret = z_random_u32();\n#endif\n\n    return ret;\n}\n\nuint32_t z_random_u32(void) {\n    uint32_t ret = 0;\n#if defined(ZENOH_LINUX)\n    while (getrandom(&ret, sizeof(uint32_t), 0) <= 0) {\n        ZP_ASM_NOP;\n    }\n#elif defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n    ret = arc4random();\n#endif\n\n    return ret;\n}\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n#if defined(ZENOH_LINUX)\n    while (getrandom(&ret, sizeof(uint64_t), 0) <= 0) {\n        ZP_ASM_NOP;\n    }\n#elif defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n#endif\n\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) {\n#if defined(ZENOH_LINUX)\n    while (getrandom(buf, len, 0) <= 0) {\n        ZP_ASM_NOP;\n    }\n#elif defined(ZENOH_MACOS) || defined(ZENOH_BSD)\n    arc4random_buf(buf, len);\n#endif\n}\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) { return malloc(size); }\n\nvoid *z_realloc(void *ptr, size_t size) { return realloc(ptr, size); }\n\nvoid z_free(void *ptr) { free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    _Z_CHECK_SYS_ERR(pthread_create(task, attr, fun, arg));\n}\n\nz_result_t _z_task_join(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_join(*task, NULL)); }\n\nz_result_t _z_task_detach(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_detach(*task)); }\n\nz_result_t _z_task_cancel(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_cancel(*task)); }\n\nvoid _z_task_exit(void) { pthread_exit(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return *task; }\n_z_task_id_t _z_task_current_id(void) { return pthread_self(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return pthread_equal(*l, *r) != 0; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_init(m, NULL)); }\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) {\n    pthread_mutexattr_t attr;\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_init(&attr));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutex_init(m, &attr));\n    _Z_CHECK_SYS_ERR(pthread_mutexattr_destroy(&attr));\n}\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m)); }\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    pthread_condattr_t attr;\n    pthread_condattr_init(&attr);\n#ifndef ZENOH_MACOS\n    // macos does not have pthread_condattr_setclock function\n    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);\n#endif\n    _Z_CHECK_SYS_ERR(pthread_cond_init(cv, &attr));\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_destroy(cv)); }\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_signal(cv)); }\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_broadcast(cv)); }\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_cond_wait(cv, m)); }\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n#ifndef ZENOH_MACOS\n    int error = pthread_cond_timedwait(cv, m, abstime);\n#else\n    // pthread_cond_timedwait does not work for macos since it assumes REALTIME_CLOCK\n    // while z_clock_t corresponds to MONOTONIC_CLOCK.\n    z_clock_t deadline = {0};\n    z_clock_t now = z_clock_now();\n    if (now.tv_sec < abstime->tv_sec) {\n        deadline.tv_sec = abstime->tv_sec - now.tv_sec;\n        if (now.tv_nsec <= abstime->tv_nsec) {\n            deadline.tv_nsec = abstime->tv_nsec - now.tv_nsec;\n        } else {\n            deadline.tv_sec--;\n            deadline.tv_nsec += 1000000000 + abstime->tv_nsec - now.tv_nsec;\n        }\n    } else if (now.tv_sec == abstime->tv_sec && now.tv_nsec < abstime->tv_nsec) {\n        deadline.tv_nsec = abstime->tv_nsec - now.tv_nsec;\n    }\n    int error = pthread_cond_timedwait_relative_np(cv, m, &deadline);\n#endif\n\n    if (error == ETIMEDOUT) {\n        return Z_ETIMEDOUT;\n    }\n\n    _Z_CHECK_SYS_ERR(error);\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) { _Z_CHECK_SYS_ERR(usleep((unsigned int)time)); }\n\nz_result_t z_sleep_ms(size_t time) {\n    z_time_t start = z_time_now();\n\n    // Most sleep APIs promise to sleep at least whatever you asked them to.\n    // This may compound, so this approach may make sleeps longer than expected.\n    // This extra check tries to minimize the amount of extra time it might sleep.\n    while (z_time_elapsed_ms(&start) < time) {\n        z_result_t ret = z_sleep_us(1000);\n        if (ret != _Z_RES_OK) {\n            return ret;\n        }\n    }\n\n    return _Z_RES_OK;\n}\n\nz_result_t z_sleep_s(size_t time) { _Z_CHECK_SYS_ERR((int)sleep((unsigned int)time)); }\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += (time_t)(duration / 1000000);\n    clock->tv_nsec += (long int)((duration % 1000000) * 1000);\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += (time_t)(duration / 1000);\n    clock->tv_nsec += (long int)((duration % 1000) * 1000000);\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += (time_t)duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (unsigned long)(now.tv_sec - time->tv_sec);\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = (uint32_t)now.tv_sec;\n    t->nanos = (uint32_t)now.tv_usec * 1000;\n    return 0;\n}\n"
  },
  {
    "path": "src/system/windows/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <winsock2.h>\n// The following includes must come after winsock2\n#include <iphlpapi.h>\n#include <stdio.h>\n#include <ws2tcpip.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nWSADATA wsaData;\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    u_long mode = blocking ? 0 : 1;\n    if (ioctlsocket(sock->_sock._fd, FIONBIO, &mode) != 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) {\n    if (sock->_sock._fd != INVALID_SOCKET) {\n        shutdown(sock->_sock._fd, SD_BOTH);\n        closesocket(sock->_sock._fd);\n        sock->_sock._fd = INVALID_SOCKET;\n    }\n}\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    fd_set read_fds;\n    bool has_sockets = false;\n\n    FD_ZERO(&read_fds);\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, false);\n        FD_SET(sock->_sock._fd, &read_fds);\n        has_sockets = true;\n    }\n\n    if (!has_sockets) {\n        return _Z_RES_OK;\n    }\n\n    struct timeval timeout = {\n        .tv_sec = (long)(timeout_ms / 1000U),\n        .tv_usec = (long)((timeout_ms % 1000U) * 1000U),\n    };\n    int result = select(0, &read_fds, NULL, NULL, &timeout);\n    if (result <= 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, FD_ISSET(sock->_sock._fd, &read_fds));\n    }\n\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on Windows port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_LINK_SERIAL == 1\n#error \"Serial not supported yet on Windows port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on Windows port of Zenoh-Pico\"\n#endif\n"
  },
  {
    "path": "src/system/windows/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n\n#include <stdlib.h>\n#include <sys/types.h>\n#include <time.h>\n#include <windows.h>\n\n// The following includes must come after windows\n#include <ntsecapi.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) {\n    uint8_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\nuint16_t z_random_u16(void) {\n    uint16_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\nuint32_t z_random_u32(void) {\n    uint32_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) { RtlGenRandom(buf, (unsigned long)len); }\n\n/*------------------ Memory ------------------*/\n// #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))\n// #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))\nvoid *z_malloc(size_t size) { return malloc(size); }\n\nvoid *z_realloc(void *ptr, size_t size) { return realloc(ptr, size); }\n\nvoid z_free(void *ptr) { free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    (void)(attr);\n    z_result_t ret = _Z_RES_OK;\n    *task = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fun, arg, 0, NULL);\n    if (*task == NULL) {\n        _Z_ERROR_LOG(_Z_ERR_SYSTEM_TASK_FAILED);\n        ret = _Z_ERR_SYSTEM_TASK_FAILED;\n    }\n    return ret;\n}\n\nz_result_t _z_task_join(_z_task_t *task) {\n    z_result_t ret = _Z_RES_OK;\n    WaitForSingleObject(*task, INFINITE);\n    return ret;\n}\n\nz_result_t _z_task_detach(_z_task_t *task) {\n    z_result_t ret = _Z_RES_OK;\n    CloseHandle(*task);\n    *task = 0;\n    return ret;\n}\n\nz_result_t _z_task_cancel(_z_task_t *task) {\n    z_result_t ret = _Z_RES_OK;\n    TerminateThread(*task, 0);\n    return ret;\n}\n\nvoid _z_task_exit(void) { ExitThread(0); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    if (*ptr != 0) {\n        CloseHandle(*ptr);\n    }\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return GetThreadId(*task); }\n_z_task_id_t _z_task_current_id(void) { return GetCurrentThreadId(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return *l == *r; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) {\n    z_result_t ret = _Z_RES_OK;\n    InitializeSRWLock(m);\n    return ret;\n}\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) {\n    (void)(m);\n    z_result_t ret = _Z_RES_OK;\n    return ret;\n}\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) {\n    z_result_t ret = _Z_RES_OK;\n    AcquireSRWLockExclusive(m);\n    return ret;\n}\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) {\n    z_result_t ret = _Z_RES_OK;\n    if (!TryAcquireSRWLockExclusive(m)) {\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n    return ret;\n}\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) {\n    z_result_t ret = _Z_RES_OK;\n    ReleaseSRWLockExclusive(m);\n    return ret;\n}\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) {\n    InitializeCriticalSection(m);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) {\n    DeleteCriticalSection(m);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) {\n    EnterCriticalSection(m);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) {\n    if (!TryEnterCriticalSection(m)) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) {\n    LeaveCriticalSection(m);\n    return _Z_RES_OK;\n}\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    z_result_t ret = _Z_RES_OK;\n    InitializeConditionVariable(cv);\n    return ret;\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) {\n    (void)(cv);\n    z_result_t ret = _Z_RES_OK;\n    return ret;\n}\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) {\n    z_result_t ret = _Z_RES_OK;\n    WakeConditionVariable(cv);\n    return ret;\n}\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) {\n    z_result_t ret = _Z_RES_OK;\n    WakeAllConditionVariable(cv);\n    return ret;\n}\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) {\n    z_result_t ret = _Z_RES_OK;\n    SleepConditionVariableSRW(cv, m, INFINITE, 0);\n    return ret;\n}\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    z_clock_t now = z_clock_now();\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    double remaining = (double)(abstime->QuadPart - now.QuadPart) / frequency.QuadPart * 1000.0;\n    DWORD block_duration = remaining > 0.0 ? (DWORD)remaining : 0;\n\n    if (SleepConditionVariableSRW(cv, m, block_duration, 0) == 0) {\n        if (GetLastError() == ERROR_TIMEOUT) {\n            return Z_ETIMEDOUT;\n        } else {\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n        }\n    }\n\n    return _Z_RES_OK;\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) { return z_sleep_ms((time / 1000) + (time % 1000 == 0 ? 0 : 1)); }\n\nz_result_t z_sleep_ms(size_t time) {\n    // Guarantees that size_t is split into DWORD segments for Sleep\n    uint8_t ratio = sizeof(size_t) / sizeof(DWORD);\n    DWORD ratio_time = (DWORD)((time / ratio) + (time % ratio == 0 ? 0 : 1));\n    for (uint8_t i = 0; i < ratio; i++) {\n        Sleep(ratio_time);\n    }\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    z_time_t start = z_time_now();\n\n    // Most sleep APIs promise to sleep at least whatever you asked them to.\n    // This may compound, so this approach may make sleeps longer than expected.\n    // This extra check tries to minimize the amount of extra time it might sleep.\n    while (z_time_elapsed_s(&start) < time) {\n        z_sleep_ms(1000);\n    }\n\n    return 0;\n}\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    QueryPerformanceCounter(&now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        return 0;\n    }\n    double elapsed = (double)(instant->QuadPart - epoch->QuadPart) * 1000000.0;\n    elapsed /= frequency.QuadPart;\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        return 0;\n    }\n    double elapsed = (double)(instant->QuadPart - epoch->QuadPart) * 1000.0;\n    elapsed /= frequency.QuadPart;\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        return 0;\n    }\n    double elapsed = (double)(instant->QuadPart - epoch->QuadPart) / frequency.QuadPart;\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    QueryPerformanceCounter(&now);\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    QueryPerformanceCounter(&now);\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    QueryPerformanceCounter(&now);\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        return;\n    }\n    double ticks = (double)duration * frequency.QuadPart / 1000000.0;\n    clock->QuadPart += (LONGLONG)ticks;\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        return;\n    }\n    double ticks = (double)duration * frequency.QuadPart / 1000.0;\n    clock->QuadPart += (LONGLONG)ticks;\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) {\n    LARGE_INTEGER frequency;\n    QueryPerformanceFrequency(&frequency);  // ticks per second\n\n    // Hardware not supporting QueryPerformanceFrequency\n    if (frequency.QuadPart == 0) {\n        return;\n    }\n    double ticks = (double)duration * frequency.QuadPart;\n    clock->QuadPart += (LONGLONG)ticks;\n}\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    ftime(&now);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.time);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) { return z_time_elapsed_ms(time) * 1000; }\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    ftime(&now);\n\n    unsigned long elapsed = ((unsigned long)(now.time - time->time) * 1000) + (now.millitm - time->millitm);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    ftime(&now);\n\n    unsigned long elapsed = (unsigned long)(now.time - time->time);\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    ftime(&now);\n    t->secs = (uint32_t)now.time;\n    t->nanos = (uint32_t)(now.millitm * 1000000);\n    return 0;\n}\n"
  },
  {
    "path": "src/system/zephyr/network.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ZEPHYR)\n\n#include <fcntl.h>\n#include <netdb.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <sys/socket.h>\n#include <unistd.h>\n#include <zephyr/net/net_if.h>\n#include <zephyr/net/socket.h>\n#include <zephyr/posix/sys/select.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\nz_result_t _z_socket_set_blocking(const _z_sys_net_socket_t *sock, bool blocking) {\n    int flags = fcntl(sock->_fd, F_GETFL, 0);\n    if (flags == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (fcntl(sock->_fd, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK)) == -1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    return _Z_RES_OK;\n}\n\nvoid _z_socket_close(_z_sys_net_socket_t *sock) {\n    if (sock->_fd >= 0) {\n        close(sock->_fd);\n        sock->_fd = -1;\n    }\n}\n\nz_result_t _z_socket_wait_readable(_z_socket_wait_iter_t *iter, uint32_t timeout_ms) {\n    fd_set read_fds;\n    int max_fd = 0;\n    bool has_sockets = false;\n\n    FD_ZERO(&read_fds);\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, false);\n        FD_SET(sock->_fd, &read_fds);\n        if (sock->_fd > max_fd) {\n            max_fd = sock->_fd;\n        }\n        has_sockets = true;\n    }\n\n    if (!has_sockets) {\n        return _Z_RES_OK;\n    }\n\n    struct timeval timeout = {\n        .tv_sec = (time_t)(timeout_ms / 1000U),\n        .tv_usec = (suseconds_t)((timeout_ms % 1000U) * 1000U),\n    };\n    int result = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);\n    if (result <= 0) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    _z_socket_wait_iter_reset(iter);\n    while (_z_socket_wait_iter_next(iter)) {\n        const _z_sys_net_socket_t *sock = _z_socket_wait_iter_get_socket(iter);\n        _z_socket_wait_iter_set_ready(iter, FD_ISSET(sock->_fd, &read_fds));\n    }\n\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_LINK_BLUETOOTH == 1\n#error \"Bluetooth not supported yet on Zephyr port of Zenoh-Pico\"\n#endif\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n#error \"Raw ethernet transport not supported yet on Zephyr port of Zenoh-Pico\"\n#endif\n\n#endif /* defined(ZENOH_ZEPHYR) */\n"
  },
  {
    "path": "src/system/zephyr/system.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/config.h\"\n\n#if defined(ZENOH_ZEPHYR)\n\n#include <version.h>\n\n#if KERNEL_VERSION_MAJOR == 2\n#include <random/rand32.h>\n#else\n#include <zephyr/random/random.h>\n#endif\n\n#include <errno.h>\n#include <stddef.h>\n#include <sys/time.h>\n#include <unistd.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/system/common/system_error.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n/*------------------ Random ------------------*/\nuint8_t z_random_u8(void) { return z_random_u32(); }\n\nuint16_t z_random_u16(void) { return z_random_u32(); }\n\nuint32_t z_random_u32(void) { return sys_rand32_get(); }\n\nuint64_t z_random_u64(void) {\n    uint64_t ret = 0;\n    ret |= z_random_u32();\n    ret = ret << 32;\n    ret |= z_random_u32();\n\n    return ret;\n}\n\nvoid z_random_fill(void *buf, size_t len) { sys_rand_get(buf, len); }\n\n/*------------------ Memory ------------------*/\nvoid *z_malloc(size_t size) { return k_malloc(size); }\n\nvoid *z_realloc(void *ptr, size_t size) {\n    // k_realloc not implemented in Zephyr\n    return NULL;\n}\n\nvoid z_free(void *ptr) { k_free(ptr); }\n\n#if Z_FEATURE_MULTI_THREAD == 1\n\n#define Z_THREADS_NUM 4\n\n#ifdef CONFIG_TEST_EXTRA_STACK_SIZE\n#define Z_PTHREAD_STACK_SIZE_DEFAULT CONFIG_MAIN_STACK_SIZE + CONFIG_TEST_EXTRA_STACK_SIZE\n#elif CONFIG_TEST_EXTRA_STACKSIZE\n#define Z_PTHREAD_STACK_SIZE_DEFAULT CONFIG_MAIN_STACK_SIZE + CONFIG_TEST_EXTRA_STACKSIZE\n#else\n#define Z_PTHREAD_STACK_SIZE_DEFAULT CONFIG_MAIN_STACK_SIZE\n#endif\n\nK_THREAD_STACK_ARRAY_DEFINE(thread_stack_area, Z_THREADS_NUM, Z_PTHREAD_STACK_SIZE_DEFAULT);\nstatic int thread_index = 0;\n\n/*------------------ Task ------------------*/\nz_result_t _z_task_init(_z_task_t *task, z_task_attr_t *attr, void *(*fun)(void *), void *arg) {\n    z_task_attr_t *lattr = NULL;\n    z_task_attr_t tmp;\n    if (attr == NULL) {\n        (void)pthread_attr_init(&tmp);\n        (void)pthread_attr_setstack(&tmp, &thread_stack_area[thread_index++], Z_PTHREAD_STACK_SIZE_DEFAULT);\n        lattr = &tmp;\n    }\n\n    _Z_CHECK_SYS_ERR(pthread_create(task, lattr, fun, arg));\n}\n\nz_result_t _z_task_join(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_join(*task, NULL)); }\n\nz_result_t _z_task_detach(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_detach(*task)); }\n\nz_result_t _z_task_cancel(_z_task_t *task) { _Z_CHECK_SYS_ERR(pthread_cancel(*task)); }\n\nvoid _z_task_exit(void) { pthread_exit(NULL); }\n\nvoid _z_task_free(_z_task_t **task) {\n    _z_task_t *ptr = *task;\n    z_free(ptr);\n    *task = NULL;\n}\n\n_z_task_id_t _z_task_get_id(const _z_task_t *task) { return *task; }\n_z_task_id_t _z_task_current_id(void) { return pthread_self(); }\nbool _z_task_id_equal(const _z_task_id_t *l, const _z_task_id_t *r) { return pthread_equal(*l, *r) != 0; }\n\n/*------------------ Mutex ------------------*/\nz_result_t _z_mutex_init(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_init(m, NULL)); }\n\nz_result_t _z_mutex_drop(_z_mutex_t *m) {\n    if (m == NULL) {\n        return 0;\n    }\n    _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m));\n}\n\nz_result_t _z_mutex_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_try_lock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_unlock(_z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\nz_result_t _z_mutex_rec_init(_z_mutex_rec_t *m) {\n    pthread_mutexattr_t attr;\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_init(&attr));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));\n    _Z_RETURN_IF_SYS_ERR(pthread_mutex_init(m, &attr));\n    _Z_CHECK_SYS_ERR(pthread_mutexattr_destroy(&attr));\n}\n\nz_result_t _z_mutex_rec_drop(_z_mutex_rec_t *m) {\n    if (m == NULL) {\n        return 0;\n    }\n    _Z_CHECK_SYS_ERR(pthread_mutex_destroy(m));\n}\n\nz_result_t _z_mutex_rec_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_lock(m)); }\n\nz_result_t _z_mutex_rec_try_lock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_trylock(m)); }\n\nz_result_t _z_mutex_rec_unlock(_z_mutex_rec_t *m) { _Z_CHECK_SYS_ERR(pthread_mutex_unlock(m)); }\n\n/*------------------ Condvar ------------------*/\nz_result_t _z_condvar_init(_z_condvar_t *cv) {\n    pthread_condattr_t attr;\n    pthread_condattr_init(&attr);\n    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);\n    _Z_CHECK_SYS_ERR(pthread_cond_init(cv, &attr));\n}\n\nz_result_t _z_condvar_drop(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_destroy(cv)); }\n\nz_result_t _z_condvar_signal(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_signal(cv)); }\n\nz_result_t _z_condvar_signal_all(_z_condvar_t *cv) { _Z_CHECK_SYS_ERR(pthread_cond_broadcast(cv)); }\n\nz_result_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { _Z_CHECK_SYS_ERR(pthread_cond_wait(cv, m)); }\n\nz_result_t _z_condvar_wait_until(_z_condvar_t *cv, _z_mutex_t *m, const z_clock_t *abstime) {\n    int error = pthread_cond_timedwait(cv, m, abstime);\n\n    if (error == ETIMEDOUT) {\n        return Z_ETIMEDOUT;\n    }\n\n    _Z_CHECK_SYS_ERR(error);\n}\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n/*------------------ Sleep ------------------*/\nz_result_t z_sleep_us(size_t time) {\n    int32_t rem = time;\n    while (rem > 0) {\n        rem = k_usleep(rem);  // This function is unlikely to work as expected without kernel tuning.\n                              // In particular, because the lower bound on the duration of a sleep is the\n                              // duration of a tick, CONFIG_SYS_CLOCK_TICKS_PER_SEC must be adjusted to\n                              // achieve the resolution desired. The implications of doing this must be\n                              // understood before attempting to use k_usleep(). Use with caution.\n                              // From: https://docs.zephyrproject.org/apidoc/latest/group__thread__apis.html\n    }\n\n    return 0;\n}\n\nz_result_t z_sleep_ms(size_t time) {\n    int32_t rem = time;\n    while (rem > 0) {\n        rem = k_msleep(rem);\n    }\n\n    return 0;\n}\n\nz_result_t z_sleep_s(size_t time) {\n    int32_t rem = time;\n    while (rem > 0) {\n        rem = k_sleep(K_SECONDS(rem));\n    }\n\n    return 0;\n}\n\n/*------------------ Instant ------------------*/\nz_clock_t z_clock_now(void) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return now;\n}\n\nunsigned long zp_clock_elapsed_us_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_ms_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (1000 * (instant->tv_sec - epoch->tv_sec) + (instant->tv_nsec - epoch->tv_nsec) / 1000000);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long zp_clock_elapsed_s_since(z_clock_t *instant, z_clock_t *epoch) {\n    long elapsed = (instant->tv_sec - epoch->tv_sec);\n    return elapsed > 0 ? (unsigned long)elapsed : 0;\n}\n\nunsigned long z_clock_elapsed_us(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n    return zp_clock_elapsed_us_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_ms(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_ms_since(&now, instant);\n}\n\nunsigned long z_clock_elapsed_s(z_clock_t *instant) {\n    z_clock_t now;\n    clock_gettime(CLOCK_MONOTONIC, &now);\n\n    return zp_clock_elapsed_s_since(&now, instant);\n}\n\nvoid z_clock_advance_us(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000000;\n    clock->tv_nsec += (duration % 1000000) * 1000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_ms(z_clock_t *clock, unsigned long duration) {\n    clock->tv_sec += duration / 1000;\n    clock->tv_nsec += (duration % 1000) * 1000000;\n\n    if (clock->tv_nsec >= 1000000000) {\n        clock->tv_sec += 1;\n        clock->tv_nsec -= 1000000000;\n    }\n}\n\nvoid z_clock_advance_s(z_clock_t *clock, unsigned long duration) { clock->tv_sec += duration; }\n\n/*------------------ Time ------------------*/\nz_time_t z_time_now(void) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    return now;\n}\n\nconst char *z_time_now_as_str(char *const buf, unsigned long buflen) {\n    z_time_t tv = z_time_now();\n    struct tm ts;\n    ts = *localtime(&tv.tv_sec);\n    strftime(buf, buflen, \"%Y-%m-%dT%H:%M:%SZ\", &ts);\n    return buf;\n}\n\nunsigned long z_time_elapsed_us(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec));\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_ms(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = (1000 * (now.tv_sec - time->tv_sec) + (now.tv_usec - time->tv_usec) / 1000);\n    return elapsed;\n}\n\nunsigned long z_time_elapsed_s(z_time_t *time) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n\n    unsigned long elapsed = now.tv_sec - time->tv_sec;\n    return elapsed;\n}\n\nz_result_t _z_get_time_since_epoch(_z_time_since_epoch *t) {\n    z_time_t now;\n    gettimeofday(&now, NULL);\n    t->secs = now.tv_sec;\n    t->nanos = now.tv_usec * 1000;\n    return 0;\n}\n\n#endif /* defined(ZENOH_ZEPHYR) */\n"
  },
  {
    "path": "src/transport/common/lease.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/lease.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/transport/multicast/lease.h\"\n#include \"zenoh-pico/transport/unicast/lease.h\"\n\nz_result_t _z_send_keep_alive(_z_transport_t *zt) {\n    z_result_t ret = _Z_RES_OK;\n    switch (zt->_type) {\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            ret = _zp_unicast_send_keep_alive(&zt->_transport._unicast);\n            break;\n#endif\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            ret = _zp_multicast_send_keep_alive(&zt->_transport._multicast);\n            break;\n#endif\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            ret = _zp_multicast_send_keep_alive(&zt->_transport._raweth);\n            break;\n#endif\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n\nz_result_t _z_send_join(_z_transport_t *zt) {\n    z_result_t ret = _Z_RES_OK;\n    // Join task only applies to multicast transports\n    switch (zt->_type) {\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            ret = _zp_multicast_send_join(&zt->_transport._multicast);\n            break;\n#endif\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            ret = _zp_multicast_send_join(&zt->_transport._raweth);\n            break;\n#endif\n        default:\n            _ZP_UNUSED(zt);\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n"
  },
  {
    "path": "src/transport/common/read.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/read.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/transport/multicast/read.h\"\n#include \"zenoh-pico/transport/raweth/read.h\"\n#include \"zenoh-pico/transport/unicast/read.h\"\n\nz_result_t _z_read(_z_transport_t *zt, bool single_read) {\n    z_result_t ret = _Z_RES_OK;\n    switch (zt->_type) {\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            ret = _zp_unicast_read(&zt->_transport._unicast, single_read);\n            break;\n#endif\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            ret = _zp_multicast_read(&zt->_transport._multicast, single_read);\n            break;\n#endif\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            ret = _zp_raweth_read(&zt->_transport._raweth, single_read);\n            break;\n#endif\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n"
  },
  {
    "path": "src/transport/common/rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/rx.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/transport/multicast/rx.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n/*------------------ Reception helper ------------------*/\nsize_t _z_read_stream_size(_z_zbuf_t *zbuf) {\n    uint8_t stream_size[_Z_MSG_LEN_ENC_SIZE];\n    // Read the bytes from stream\n    for (uint8_t i = 0; i < _Z_MSG_LEN_ENC_SIZE; i++) {\n        stream_size[i] = _z_zbuf_read(zbuf);\n    }\n    return _z_host_le_load16(stream_size);\n}\n\nz_result_t _z_link_recv_t_msg_cap_flow_stream(const _z_link_t *zl, _z_zbuf_t *zbf, _z_sys_net_socket_t *socket) {\n    // Read the message length\n    size_t read = _z_link_recv_exact_zbuf(zl, zbf, _Z_MSG_LEN_ENC_SIZE, NULL, socket);\n    if (read == _Z_MSG_LEN_ENC_SIZE) {\n        size_t len = 0;\n        for (uint8_t i = 0; i < _Z_MSG_LEN_ENC_SIZE; i++) {\n            len |= (size_t)(_z_zbuf_read(zbf) << (i * (uint8_t)8));\n        }\n\n        size_t writable = _z_zbuf_capacity(zbf) - _z_zbuf_len(zbf);\n        if (writable >= len) {\n            // Read enough bytes to decode the message\n            if (_z_link_recv_exact_zbuf(zl, zbf, len, NULL, socket) != len) {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_RX_FAILED);\n                return _Z_ERR_TRANSPORT_RX_FAILED;\n            }\n        } else {\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NO_SPACE);\n            return _Z_ERR_TRANSPORT_NO_SPACE;\n        }\n    } else if (read == SIZE_MAX) {\n        return Z_ETIMEDOUT;\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_RX_FAILED);\n        return _Z_ERR_TRANSPORT_RX_FAILED;\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_link_recv_t_msg_cap_flow_datagram(const _z_link_t *zl, _z_zbuf_t *zbf, _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(socket);\n    if (_z_link_recv_zbuf(zl, zbf, NULL) == SIZE_MAX) {\n        return Z_ETIMEDOUT;\n    } else {\n        return _Z_RES_OK;\n    }\n}\n\nz_result_t _z_link_recv_t_msg(_z_transport_message_t *t_msg, const _z_link_t *zl, _z_sys_net_socket_t *socket,\n                              z_clock_t recv_deadline) {\n    // Create and prepare the buffer\n    _z_zbuf_t zbf = _z_zbuf_make(Z_BATCH_UNICAST_SIZE);\n    _z_zbuf_reset(&zbf);\n\n    z_result_t ret = Z_ETIMEDOUT;\n    while (ret == Z_ETIMEDOUT) {\n        switch (zl->_cap._flow) {\n            case Z_LINK_CAP_FLOW_STREAM:\n                ret = _z_link_recv_t_msg_cap_flow_stream(zl, &zbf, socket);\n                break;\n            case Z_LINK_CAP_FLOW_DATAGRAM:\n                ret = _z_link_recv_t_msg_cap_flow_datagram(zl, &zbf, socket);\n                break;\n            default:\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n        }\n        if (ret == Z_ETIMEDOUT) {\n            z_clock_t now = z_clock_now();\n            if (zp_clock_elapsed_ms_since(&recv_deadline, &now) == 0) {\n                ret = _Z_ERR_TRANSPORT_RX_DURATION_EXPIRED;\n            }\n        }\n    }\n\n    if (ret == _Z_RES_OK) {\n        _z_transport_message_t l_t_msg;\n        ret = _z_transport_message_decode(&l_t_msg, &zbf);\n        if (ret == _Z_RES_OK) {\n            _z_t_msg_copy(t_msg, &l_t_msg);\n        }\n    } else {\n        _Z_ERROR_LOG(ret);\n    }\n    _z_zbuf_clear(&zbf);\n\n    return ret;\n}\n"
  },
  {
    "path": "src/transport/common/transport.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/transport/transport.h\"\n\n#include <stdbool.h>\n\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/unicast/accept.h\"\n#include \"zenoh-pico/utils/result.h\"\n\nvoid _z_transport_common_clear(_z_transport_common_t *ztc) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    // Clean up the mutexes\n    _z_mutex_drop(&ztc->_mutex_tx);\n    _z_mutex_rec_drop(&ztc->_mutex_peer);\n#endif\n    // Clean up the buffers\n    _z_wbuf_clear(&ztc->_wbuf);\n    _z_zbuf_clear(&ztc->_zbuf);\n\n    _z_link_free(&ztc->_link);\n    _z_session_weak_drop(&ztc->_session);\n}\n"
  },
  {
    "path": "src/transport/common/tx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/tx.h\"\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/transport/raweth/tx.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/endianness.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if defined(Z_TEST_HOOKS)\n#include \"zenoh-pico/session/loopback.h\"\n\nstatic _z_session_send_override_fn _z_send_n_msg_override = NULL;\n\nvoid _z_transport_set_send_n_msg_override(_z_session_send_override_fn fn) { _z_send_n_msg_override = fn; }\n#endif\n\n/*------------------ Transmission helper ------------------*/\n\nstatic inline bool _z_transport_tx_get_express_status(const _z_network_message_t *msg) {\n    switch (msg->_tag) {\n        case _Z_N_DECLARE:\n            return _Z_HAS_FLAG(msg->_body._declare._ext_qos._val, _Z_N_QOS_IS_EXPRESS_FLAG);\n        case _Z_N_PUSH:\n            return _Z_HAS_FLAG(msg->_body._push._qos._val, _Z_N_QOS_IS_EXPRESS_FLAG);\n        case _Z_N_REQUEST:\n            return _Z_HAS_FLAG(msg->_body._request._ext_qos._val, _Z_N_QOS_IS_EXPRESS_FLAG);\n        case _Z_N_RESPONSE:\n            return _Z_HAS_FLAG(msg->_body._response._ext_qos._val, _Z_N_QOS_IS_EXPRESS_FLAG);\n        default:\n            return false;\n    }\n}\nstatic _z_zint_t _z_transport_tx_get_sn(_z_transport_common_t *ztc, z_reliability_t reliability) {\n    _z_zint_t sn;\n    if (reliability == Z_RELIABILITY_RELIABLE) {\n        sn = ztc->_sn_tx_reliable;\n        ztc->_sn_tx_reliable = _z_sn_increment(ztc->_sn_res, ztc->_sn_tx_reliable);\n    } else {\n        sn = ztc->_sn_tx_best_effort;\n        ztc->_sn_tx_best_effort = _z_sn_increment(ztc->_sn_res, ztc->_sn_tx_best_effort);\n    }\n    return sn;\n}\n\n#if Z_FEATURE_FRAGMENTATION == 1\nstatic z_result_t _z_transport_tx_send_fragment_inner(_z_transport_common_t *ztc, _z_wbuf_t *frag_buff,\n                                                      const _z_network_message_t *n_msg, z_reliability_t reliability,\n                                                      _z_zint_t first_sn, _z_transport_peer_unicast_slist_t *peers) {\n    bool is_first = true;\n    _z_zint_t sn = first_sn;\n    // Encode message on temp buffer\n    _Z_RETURN_IF_ERR(_z_network_message_encode(frag_buff, n_msg));\n    // Fragment message\n    while (_z_wbuf_len(frag_buff) > 0) {\n        // Get fragment sequence number\n        if (!is_first) {\n            sn = _z_transport_tx_get_sn(ztc, reliability);\n        }\n        // Serialize fragment\n        __unsafe_z_prepare_wbuf(&ztc->_wbuf, ztc->_link->_cap._flow);\n        z_result_t ret = __unsafe_z_serialize_zenoh_fragment(&ztc->_wbuf, frag_buff, reliability, sn, is_first);\n        if (ret != _Z_RES_OK) {\n            _Z_ERROR(\"Fragment serialization failed with err %d\", ret);\n            return ret;\n        }\n        // Send fragment\n        __unsafe_z_finalize_wbuf(&ztc->_wbuf, ztc->_link->_cap._flow);\n        if (peers == NULL) {\n            _Z_RETURN_IF_ERR(_z_link_send_wbuf(ztc->_link, &ztc->_wbuf, NULL));\n        } else {\n            _z_transport_peer_unicast_slist_t *curr_list = peers;\n            while (curr_list != NULL) {\n                _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(curr_list);\n                // Send on peer socket\n                _z_link_send_wbuf(ztc->_link, &ztc->_wbuf, &curr_peer->_socket);\n                curr_list = _z_transport_peer_unicast_slist_next(curr_list);\n            }\n        }\n        ztc->_transmitted = true;  // Tell session we transmitted data\n        is_first = false;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_transport_tx_send_fragment(_z_transport_common_t *ztc, const _z_network_message_t *n_msg,\n                                                z_reliability_t reliability, _z_zint_t first_sn,\n                                                _z_transport_peer_unicast_slist_t *peers) {\n    // Create an expandable wbuf for fragmentation\n    _z_wbuf_t frag_buff = _z_wbuf_make(_Z_FRAG_BUFF_BASE_SIZE, true);\n    // Send message as fragments\n    z_result_t ret = _z_transport_tx_send_fragment_inner(ztc, &frag_buff, n_msg, reliability, first_sn, peers);\n    // Clear the buffer as it's no longer required\n    _z_wbuf_clear(&frag_buff);\n    return ret;\n}\n\n#else\nstatic z_result_t _z_transport_tx_send_fragment(_z_transport_common_t *ztc, const _z_network_message_t *n_msg,\n                                                z_reliability_t reliability, _z_zint_t first_sn,\n                                                _z_transport_peer_unicast_slist_t *peers) {\n    _ZP_UNUSED(ztc);\n    _ZP_UNUSED(n_msg);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(first_sn);\n    _ZP_UNUSED(peers);\n    _Z_INFO(\"Sending the message required fragmentation feature that is deactivated.\");\n    return _Z_RES_OK;\n}\n#endif\n\nstatic inline bool _z_transport_tx_batch_has_data(_z_transport_common_t *ztc) {\n#if Z_FEATURE_BATCHING == 1\n    return (ztc->_batch_state == _Z_BATCHING_ACTIVE) && (ztc->_batch_count > 0);\n#else\n    _ZP_UNUSED(ztc);\n    return false;\n#endif\n}\n\nstatic z_result_t _z_transport_tx_flush_buffer(_z_transport_common_t *ztc, _z_transport_peer_unicast_slist_t *peers) {\n    __unsafe_z_finalize_wbuf(&ztc->_wbuf, ztc->_link->_cap._flow);\n    // Send network message\n    if (peers == NULL) {\n        _Z_RETURN_IF_ERR(_z_link_send_wbuf(ztc->_link, &ztc->_wbuf, NULL));\n    } else {\n        _z_transport_peer_unicast_slist_t *curr_list = peers;\n        while (curr_list != NULL) {\n            _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(curr_list);\n            // Send on peer socket\n            _z_link_send_wbuf(ztc->_link, &ztc->_wbuf, &curr_peer->_socket);\n            curr_list = _z_transport_peer_unicast_slist_next(curr_list);\n        }\n    }\n    ztc->_transmitted = true;  // Tell session we transmitted data\n#if Z_FEATURE_BATCHING == 1\n    ztc->_batch_count = 0;\n#endif\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_transport_tx_flush_or_incr_batch(_z_transport_common_t *ztc,\n                                                      _z_transport_peer_unicast_slist_t *peers) {\n#if Z_FEATURE_BATCHING == 1\n    if (ztc->_batch_state == _Z_BATCHING_ACTIVE) {\n        // Increment batch count\n        ztc->_batch_count++;\n        return _Z_RES_OK;\n    } else {\n        return _z_transport_tx_flush_buffer(ztc, peers);\n    }\n#else\n    return _z_transport_tx_flush_buffer(ztc, peers);\n#endif\n}\n\nstatic z_result_t _z_transport_tx_batch_overflow(_z_transport_common_t *ztc, const _z_network_message_t *n_msg,\n                                                 z_reliability_t reliability, _z_zint_t sn, size_t prev_wpos,\n                                                 _z_transport_peer_unicast_slist_t *peers) {\n#if Z_FEATURE_BATCHING == 1\n    // Remove partially encoded data\n    _z_wbuf_set_wpos(&ztc->_wbuf, prev_wpos);\n    // Send batch\n    _Z_RETURN_IF_ERR(_z_transport_tx_flush_buffer(ztc, peers));\n    // Init buffer\n    __unsafe_z_prepare_wbuf(&ztc->_wbuf, ztc->_link->_cap._flow);\n    sn = _z_transport_tx_get_sn(ztc, reliability);\n    _z_transport_message_t t_msg = _z_t_msg_make_frame_header(sn, reliability);\n    _Z_RETURN_IF_ERR(_z_transport_message_encode(&ztc->_wbuf, &t_msg));\n    // Retry encode\n    z_result_t ret = _z_network_message_encode(&ztc->_wbuf, n_msg);\n    if (ret != _Z_RES_OK) {\n        // Message still doesn't fit in buffer, send as fragments\n        return _z_transport_tx_send_fragment(ztc, n_msg, reliability, sn, peers);\n    } else {\n        if (_z_transport_tx_get_express_status(n_msg)) {\n            // Send immediately\n            return _z_transport_tx_flush_buffer(ztc, peers);\n        } else {\n            // Increment batch\n            ztc->_batch_count++;\n        }\n    }\n    return _Z_RES_OK;\n#else\n    _ZP_UNUSED(ztc);\n    _ZP_UNUSED(n_msg);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(sn);\n    _ZP_UNUSED(prev_wpos);\n    _ZP_UNUSED(peers);\n    return _Z_RES_OK;\n#endif\n}\n\nstatic inline size_t _z_transport_tx_save_wpos(_z_wbuf_t *wbuf) {\n#if Z_FEATURE_BATCHING == 1\n    return _z_wbuf_get_wpos(wbuf);\n#else\n    _ZP_UNUSED(wbuf);\n    return 0;\n#endif\n}\n\nstatic z_result_t _z_transport_tx_send_n_msg_inner(_z_transport_common_t *ztc, const _z_network_message_t *n_msg,\n                                                   z_reliability_t reliability,\n                                                   _z_transport_peer_unicast_slist_t *peers) {\n    // Init buffer\n    _z_zint_t sn = 0;\n    bool batch_has_data = _z_transport_tx_batch_has_data(ztc);\n    if (!batch_has_data) {\n        __unsafe_z_prepare_wbuf(&ztc->_wbuf, ztc->_link->_cap._flow);\n        sn = _z_transport_tx_get_sn(ztc, reliability);\n        _z_transport_message_t t_msg = _z_t_msg_make_frame_header(sn, reliability);\n        _Z_RETURN_IF_ERR(_z_transport_message_encode(&ztc->_wbuf, &t_msg));\n    }\n    // Try encoding the network message\n    size_t prev_wpos = _z_transport_tx_save_wpos(&ztc->_wbuf);\n    z_result_t ret = _z_network_message_encode(&ztc->_wbuf, n_msg);\n    if (ret == _Z_RES_OK) {\n        if (_z_transport_tx_get_express_status(n_msg)) {\n            // Send immediately\n            return _z_transport_tx_flush_buffer(ztc, peers);\n        } else {\n            // Flush buffer or increase batch\n            return _z_transport_tx_flush_or_incr_batch(ztc, peers);\n        }\n    } else if (!batch_has_data) {\n        // Message doesn't fit in buffer, send as fragments\n        return _z_transport_tx_send_fragment(ztc, n_msg, reliability, sn, peers);\n    } else {\n        // Buffer is too full for message\n        return _z_transport_tx_batch_overflow(ztc, n_msg, reliability, sn, prev_wpos, peers);\n    }\n}\n\nstatic z_result_t _z_transport_tx_send_t_msg_inner(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg,\n                                                   _z_transport_peer_unicast_slist_t *peers) {\n    // Send batch if needed\n    bool batch_has_data = _z_transport_tx_batch_has_data(ztc);\n    if (batch_has_data) {\n        _Z_RETURN_IF_ERR(_z_transport_tx_flush_buffer(ztc, peers));\n    }\n    // Encode transport message\n    __unsafe_z_prepare_wbuf(&ztc->_wbuf, ztc->_link->_cap._flow);\n    _Z_RETURN_IF_ERR(_z_transport_message_encode(&ztc->_wbuf, t_msg));\n    // Send message\n    return _z_transport_tx_flush_buffer(ztc, peers);\n}\n\nz_result_t _z_transport_tx_send_t_msg(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg,\n                                      _z_transport_peer_unicast_slist_t *peers) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Send session message\");\n    // If sending to a peer list, make sure the peer mutex is locked\n    _z_transport_tx_mutex_lock(ztc, true);\n\n    ret = _z_transport_tx_send_t_msg_inner(ztc, t_msg, peers);\n\n    _z_transport_tx_mutex_unlock(ztc);\n    return ret;\n}\n\nz_result_t _z_transport_tx_send_t_msg_wrapper(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg) {\n    return _z_transport_tx_send_t_msg(ztc, t_msg, NULL);\n}\n\nstatic z_result_t _z_transport_tx_send_n_msg(_z_transport_common_t *ztc, const _z_network_message_t *n_msg,\n                                             z_reliability_t reliability, z_congestion_control_t cong_ctrl,\n                                             _z_transport_peer_unicast_slist_t *peers) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\"Send network message\");\n\n    // Acquire the lock and drop the message if needed\n    if (!_z_transport_batch_hold_tx_mutex()) {\n        ret = _z_transport_tx_mutex_lock(ztc, cong_ctrl == Z_CONGESTION_CONTROL_BLOCK);\n    }\n    if (ret != _Z_RES_OK) {\n        _Z_INFO(\"Dropping zenoh message because of congestion control\");\n        return ret;\n    }\n    // Process message\n    ret = _z_transport_tx_send_n_msg_inner(ztc, n_msg, reliability, peers);\n    if (!_z_transport_batch_hold_tx_mutex()) {\n        _z_transport_tx_mutex_unlock(ztc);\n    }\n    return ret;\n}\n\nstatic z_result_t _z_transport_tx_send_n_batch(_z_transport_common_t *ztc, z_congestion_control_t cong_ctrl,\n                                               _z_transport_peer_unicast_slist_t *peers) {\n#if Z_FEATURE_BATCHING == 1\n    z_result_t ret = _Z_RES_OK;\n    // Check batch size\n    if (ztc->_batch_count > 0) {\n        // Acquire the lock and drop the message if needed\n        if (!_z_transport_batch_hold_tx_mutex()) {\n            ret = _z_transport_tx_mutex_lock(ztc, cong_ctrl == Z_CONGESTION_CONTROL_BLOCK);\n        }\n        if (ret != _Z_RES_OK) {\n            _Z_INFO(\"Dropping zenoh batch because of congestion control\");\n            return ret;\n        }\n        // Send batch\n        _Z_DEBUG(\"Send network batch\");\n        ret = _z_transport_tx_flush_buffer(ztc, peers);\n        if (!_z_transport_batch_hold_tx_mutex()) {\n            _z_transport_tx_mutex_unlock(ztc);\n        }\n        return ret;\n    }\n    return _Z_RES_OK;\n#else\n    _ZP_UNUSED(ztc);\n    _ZP_UNUSED(cong_ctrl);\n    _ZP_UNUSED(peers);\n    return _Z_RES_OK;\n#endif\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - ztu->mutex_tx\n */\nvoid __unsafe_z_prepare_wbuf(_z_wbuf_t *buf, uint8_t link_flow_capability) {\n    _z_wbuf_reset(buf);\n\n    switch (link_flow_capability) {\n        // Stream capable links\n        case Z_LINK_CAP_FLOW_STREAM:\n            for (uint8_t i = 0; i < _Z_MSG_LEN_ENC_SIZE; i++) {\n                _z_wbuf_put(buf, 0, i);\n            }\n            _z_wbuf_set_wpos(buf, _Z_MSG_LEN_ENC_SIZE);\n            break;\n        // Datagram capable links\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n        default:\n            break;\n    }\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - ztu->mutex_tx\n */\nvoid __unsafe_z_finalize_wbuf(_z_wbuf_t *buf, uint8_t link_flow_capability) {\n    switch (link_flow_capability) {\n        // Stream capable links\n        case Z_LINK_CAP_FLOW_STREAM: {\n            size_t len = _z_wbuf_len(buf) - _Z_MSG_LEN_ENC_SIZE;\n            // Encode the u16 size as little endian\n            _z_wbuf_put(buf, _z_get_u16_lsb((uint_fast16_t)len), 0);\n            _z_wbuf_put(buf, _z_get_u16_msb((uint_fast16_t)len), 1);\n            break;\n        }\n        // Datagram capable links\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n        default:\n            break;\n    }\n}\n\nz_result_t _z_send_t_msg(_z_transport_t *zt, const _z_transport_message_t *t_msg) {\n    z_result_t ret = _Z_RES_OK;\n    switch (zt->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            ret = _z_transport_tx_send_t_msg(&zt->_transport._unicast._common, t_msg, NULL);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            ret = _z_transport_tx_send_t_msg(&zt->_transport._multicast._common, t_msg, NULL);\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            ret = _z_raweth_send_t_msg(&zt->_transport._raweth._common, t_msg);\n            break;\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n\nz_result_t _z_link_send_t_msg(const _z_link_t *zl, const _z_transport_message_t *t_msg, _z_sys_net_socket_t *socket) {\n    z_result_t ret = _Z_RES_OK;\n\n    // Create and prepare the buffer to serialize the message on\n    uint16_t mtu = (zl->_mtu < Z_BATCH_UNICAST_SIZE) ? zl->_mtu : Z_BATCH_UNICAST_SIZE;\n    _z_wbuf_t wbf = _z_wbuf_make(mtu, false);\n    if (_z_wbuf_capacity(&wbf) != mtu) {\n        _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    switch (zl->_cap._flow) {\n        case Z_LINK_CAP_FLOW_STREAM:\n            for (uint8_t i = 0; i < _Z_MSG_LEN_ENC_SIZE; i++) {\n                _z_wbuf_put(&wbf, 0, i);\n            }\n            _z_wbuf_set_wpos(&wbf, _Z_MSG_LEN_ENC_SIZE);\n            break;\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n            break;\n        default:\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n            break;\n    }\n    // Encode the session message\n    ret = _z_transport_message_encode(&wbf, t_msg);\n    if (ret == _Z_RES_OK) {\n        switch (zl->_cap._flow) {\n            case Z_LINK_CAP_FLOW_STREAM: {\n                // Write the message length in the reserved space if needed\n                size_t len = _z_wbuf_len(&wbf) - _Z_MSG_LEN_ENC_SIZE;\n                for (uint8_t i = 0; i < _Z_MSG_LEN_ENC_SIZE; i++) {\n                    _z_wbuf_put(&wbf, (uint8_t)((len >> (uint8_t)8 * i) & (uint8_t)0xFF), i);\n                }\n                break;\n            }\n            case Z_LINK_CAP_FLOW_DATAGRAM:\n                break;\n            default:\n                _Z_ERROR_LOG(_Z_ERR_GENERIC);\n                ret = _Z_ERR_GENERIC;\n                break;\n        }\n        // Send the wbuf on the socket\n        ret = _z_link_send_wbuf(zl, &wbf, socket);\n    }\n    _z_wbuf_clear(&wbf);\n\n    return ret;\n}\n\nz_result_t __unsafe_z_serialize_zenoh_fragment(_z_wbuf_t *dst, _z_wbuf_t *src, z_reliability_t reliability, size_t sn,\n                                               bool first) {\n    z_result_t ret = _Z_RES_OK;\n\n    // Assume first that this is not the final fragment\n    bool is_final = false;\n    do {\n        size_t w_pos = _z_wbuf_get_wpos(dst);  // Mark the buffer for the writing operation\n\n        _z_transport_message_t f_hdr =\n            _z_t_msg_make_fragment_header(sn, reliability == Z_RELIABILITY_RELIABLE, is_final, first, false);\n        ret = _z_transport_message_encode(dst, &f_hdr);  // Encode the frame header\n        if (ret == _Z_RES_OK) {\n            size_t space_left = _z_wbuf_space_left(dst);\n            size_t bytes_left = _z_wbuf_len(src);\n\n            if ((is_final == false) && (bytes_left <= space_left)) {  // Check if it is really the final fragment\n                _z_wbuf_set_wpos(dst, w_pos);                         // Revert the buffer\n                is_final = true;  // It is really the finally fragment, reserialize the header\n                continue;\n            }\n\n            size_t to_copy = (bytes_left <= space_left) ? bytes_left : space_left;  // Compute bytes to write\n            ret = _z_wbuf_siphon(dst, src, to_copy);                                // Write the fragment\n        }\n        break;\n    } while (1);\n\n    return ret;\n}\n\nz_result_t _z_send_n_msg(_z_session_t *zn, const _z_network_message_t *z_msg, z_reliability_t reliability,\n                         z_congestion_control_t cong_ctrl, void *peer) {\n#if defined(Z_TEST_HOOKS)\n    if (_z_send_n_msg_override != NULL) {\n        bool handled = false;\n        z_result_t override_ret = _z_send_n_msg_override(zn, z_msg, reliability, cong_ctrl, peer, &handled);\n        if (handled) {\n            return override_ret;\n        }\n    }\n#endif\n    z_result_t ret = _Z_RES_OK;\n    // Call transport function\n    switch (zn->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_transport_common_t *ztc = &zn->_tp._transport._unicast._common;\n            if (zn->_mode == Z_WHATAMI_CLIENT) {\n                ret = _z_transport_tx_send_n_msg(ztc, z_msg, reliability, cong_ctrl, NULL);\n            } else if (!_z_transport_peer_unicast_slist_is_empty(zn->_tp._transport._unicast._peers)) {\n                if (!_z_transport_batch_hold_peer_mutex()) {\n                    _z_transport_peer_mutex_lock(ztc);\n                }\n                if (peer == NULL) {\n                    ret = _z_transport_tx_send_n_msg(ztc, z_msg, reliability, cong_ctrl,\n                                                     zn->_tp._transport._unicast._peers);\n                } else {\n                    // Send to a single peer, convert to peer list\n                    _z_transport_peer_unicast_slist_t *dst_list = _z_transport_peer_unicast_slist_push_empty(NULL);\n                    if (dst_list != NULL) {\n                        memcpy(_z_transport_peer_unicast_slist_value(dst_list), (_z_transport_peer_unicast_t *)peer,\n                               sizeof(_z_transport_peer_unicast_t));\n                        // Send message\n                        ret = _z_transport_tx_send_n_msg(ztc, z_msg, reliability, cong_ctrl, dst_list);\n                        z_free(dst_list);\n                    }\n                }\n                if (!_z_transport_batch_hold_peer_mutex()) {\n                    _z_transport_peer_mutex_unlock(ztc);\n                }\n            }\n        } break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            ret =\n                _z_transport_tx_send_n_msg(&zn->_tp._transport._multicast._common, z_msg, reliability, cong_ctrl, NULL);\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            ret = _z_raweth_send_n_msg(zn, z_msg, reliability, cong_ctrl);\n            break;\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n\nz_result_t _z_send_n_batch(_z_session_t *zn, z_congestion_control_t cong_ctrl) {\n    z_result_t ret = _Z_RES_OK;\n    // Call transport function\n    switch (zn->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            if (zn->_mode == Z_WHATAMI_CLIENT) {\n                ret = _z_transport_tx_send_n_batch(&zn->_tp._transport._unicast._common, cong_ctrl, NULL);\n            } else if (!_z_transport_peer_unicast_slist_is_empty(zn->_tp._transport._unicast._peers)) {\n                _z_transport_peer_mutex_lock(&zn->_tp._transport._unicast._common);\n                ret = _z_transport_tx_send_n_batch(&zn->_tp._transport._unicast._common, cong_ctrl,\n                                                   zn->_tp._transport._unicast._peers);\n                _z_transport_peer_mutex_unlock(&zn->_tp._transport._unicast._common);\n            }\n\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            ret = _z_transport_tx_send_n_batch(&zn->_tp._transport._multicast._common, cong_ctrl, NULL);\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            _Z_INFO(\"Batching not yet supported on raweth transport\");\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_TX_FAILED);\n            ret = _Z_ERR_TRANSPORT_TX_FAILED;\n            break;\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n"
  },
  {
    "path": "src/transport/manager.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/manager.h\"\n\n#include <stddef.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#if Z_FEATURE_LINK_TLS == 1\n#include \"zenoh-pico/link/transport/tls_stream.h\"\n#endif\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/transport/unicast/accept.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/utils/sleep.h\"\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic void _z_new_peer_dispatch_connected_event(_z_transport_unicast_t *ztu, const _z_transport_peer_unicast_t *peer) {\n    if (ztu == NULL || peer == NULL) {\n        return;\n    }\n\n    _z_connectivity_peer_event_data_t connected_peer = {0};\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    bool has_event_data = false;\n\n    _z_transport_peer_mutex_lock(&ztu->_common);\n    _z_transport_peer_unicast_slist_t *it = ztu->_peers;\n    while (it != NULL) {\n        _z_transport_peer_unicast_t *current_peer = _z_transport_peer_unicast_slist_value(it);\n        if (current_peer == peer) {\n            _z_transport_get_link_properties(&ztu->_common, &mtu, &is_streamed, &is_reliable);\n            _z_connectivity_peer_event_data_copy_from_common(&connected_peer, &current_peer->common);\n            has_event_data = true;\n            break;\n        }\n        it = _z_transport_peer_unicast_slist_next(it);\n    }\n    _z_transport_peer_mutex_unlock(&ztu->_common);\n\n    if (has_event_data) {\n        _z_connectivity_peer_connected(_z_transport_common_get_session(&ztu->_common), &connected_peer, false, mtu,\n                                       is_streamed, is_reliable);\n        _z_connectivity_peer_event_data_clear(&connected_peer);\n    }\n}\n#endif\n\nstatic z_result_t _z_new_transport_client(_z_transport_t *zt, const _z_string_t *locator, const _z_id_t *local_zid,\n                                          const _z_config_t *session_cfg) {\n    z_result_t ret = _Z_RES_OK;\n    // Init link\n    _z_link_t *zl = (_z_link_t *)z_malloc(sizeof(_z_link_t));\n    if (zl == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    memset(zl, 0, sizeof(_z_link_t));\n    // Open link\n    ret = _z_open_link(zl, locator, session_cfg);\n    if (ret != _Z_RES_OK) {\n        z_free(zl);\n        return ret;\n    }\n    // Open transport\n    switch (zl->_cap._transport) {\n        // Unicast transport\n        case Z_LINK_CAP_TRANSPORT_UNICAST: {\n            _z_transport_unicast_establish_param_t tp_param;\n            ret = _z_unicast_open_client(&tp_param, zl, local_zid);\n            if (ret != _Z_RES_OK) {\n                _z_link_free(&zl);\n                return ret;\n            }\n            ret = _z_unicast_transport_create(zt, zl, &tp_param);\n            // Fill peer list\n            if (ret == _Z_RES_OK) {\n                ret = _z_transport_peer_unicast_add(&zt->_transport._unicast, &tp_param, *_z_link_get_socket(zl), false,\n                                                    NULL);\n            }\n            break;\n        }\n        // Multicast transport\n        case Z_LINK_CAP_TRANSPORT_RAWETH:\n        case Z_LINK_CAP_TRANSPORT_MULTICAST: {\n            _z_transport_multicast_establish_param_t tp_param = {0};\n            ret = _z_multicast_open_client(&tp_param, zl, local_zid);\n            if (ret != _Z_RES_OK) {\n                _z_link_free(&zl);\n                return ret;\n            }\n            ret = _z_multicast_transport_create(zt, zl, &tp_param);\n            break;\n        }\n        default:\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            _z_link_free(&zl);\n            ret = _Z_ERR_GENERIC;\n            break;\n    }\n    return ret;\n}\n\nstatic z_result_t _z_new_transport_peer(_z_transport_t *zt, const _z_string_t *locator, const _z_id_t *local_zid,\n                                        int peer_op, const _z_config_t *session_cfg, _z_runtime_t *runtime) {\n    z_result_t ret = _Z_RES_OK;\n#if Z_FEATURE_LINK_TCP != 1 && Z_FEATURE_LINK_TLS != 1\n    _ZP_UNUSED(runtime);\n#endif\n    // Init link\n    _z_link_t *zl = (_z_link_t *)z_malloc(sizeof(_z_link_t));\n    if (zl == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n    memset(zl, 0, sizeof(_z_link_t));\n    // Listen link\n    if (peer_op == _Z_PEER_OP_OPEN) {\n        ret = _z_open_link(zl, locator, session_cfg);\n    } else {\n        ret = _z_listen_link(zl, locator, session_cfg);\n    }\n    if (ret != _Z_RES_OK) {\n        z_free(zl);\n        return ret;\n    }\n    switch (zl->_cap._transport) {\n        case Z_LINK_CAP_TRANSPORT_UNICAST: {\n#if Z_FEATURE_UNICAST_PEER == 1\n            _z_transport_unicast_establish_param_t tp_param = {0};\n            ret = _z_unicast_open_peer(&tp_param, zl, local_zid, peer_op, NULL);\n            if (ret != _Z_RES_OK) {\n                _z_link_free(&zl);\n                return ret;\n            }\n            ret = _z_unicast_transport_create(zt, zl, &tp_param);\n            _Z_SET_IF_OK(ret, _z_socket_set_blocking(_z_link_get_socket(zl), false));\n            if (ret == _Z_RES_OK) {\n                if (peer_op == _Z_PEER_OP_OPEN) {\n                    ret = _z_transport_peer_unicast_add(&zt->_transport._unicast, &tp_param, *_z_link_get_socket(zl),\n                                                        false, NULL);\n                } else {\n#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_TLS == 1\n                    _z_fut_t f = _z_fut_null();\n                    f._fut_arg = &zt->_transport._unicast;\n                    f._fut_fn = _zp_unicast_accept_task_fn;\n                    if (_z_fut_handle_is_null(_z_runtime_spawn(runtime, &f))) {\n                        _Z_ERROR(\"Failed to spawn unicast accept task after transport creation.\");\n                        ret = _Z_ERR_FAILED_TO_SPAWN_TASK;\n                    }\n#else\n                    _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_FAILED);\n                    ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n#endif\n                }\n            }\n#else\n            _ZP_UNUSED(runtime);\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_FAILED);\n            ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n#endif\n            break;\n        }\n        case Z_LINK_CAP_TRANSPORT_RAWETH:\n        case Z_LINK_CAP_TRANSPORT_MULTICAST: {\n            _z_transport_multicast_establish_param_t tp_param;\n            ret = _z_multicast_open_peer(&tp_param, zl, local_zid);\n            if (ret != _Z_RES_OK) {\n                _z_link_free(&zl);\n                return ret;\n            }\n            ret = _z_multicast_transport_create(zt, zl, &tp_param);\n            break;\n        }\n        default:\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            _z_link_free(&zl);\n            ret = _Z_ERR_GENERIC;\n            break;\n    }\n    return ret;\n}\n\nz_result_t _z_new_transport(_z_transport_t *zt, const _z_id_t *bs, const _z_string_t *locator, z_whatami_t mode,\n                            int peer_op, const _z_config_t *session_cfg, _z_runtime_t *runtime) {\n    z_result_t ret;\n\n    if (mode == Z_WHATAMI_CLIENT) {\n        ret = _z_new_transport_client(zt, locator, bs, session_cfg);\n    } else {\n        ret = _z_new_transport_peer(zt, locator, bs, peer_op, session_cfg, runtime);\n    }\n\n    return ret;\n}\n\nz_result_t _z_new_peer(_z_transport_t *zt, const _z_id_t *session_id, const _z_string_t *locator,\n                       const _z_config_t *session_cfg) {\n    z_result_t ret = _Z_RES_OK;\n    switch (zt->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            _z_sys_net_socket_t socket = {0};\n            ret = _z_open_socket(locator, session_cfg, &socket);\n            if (ret == _Z_ERR_GENERIC) {\n                ret = _Z_ERR_TRANSPORT_OPEN_FAILED;\n            }\n            _Z_RETURN_IF_ERR(ret);\n            _z_transport_unicast_establish_param_t tp_param = {0};\n            ret = _z_unicast_open_peer(&tp_param, zt->_transport._unicast._common._link, session_id, _Z_PEER_OP_OPEN,\n                                       &socket);\n            if (ret != _Z_RES_OK) {\n#if Z_FEATURE_LINK_TLS == 1\n                _z_close_tls_socket(&socket);\n#endif\n                _z_socket_close(&socket);\n                return ret;\n            }\n            ret = _z_socket_set_blocking(&socket, false);\n            if (ret != _Z_RES_OK) {\n#if Z_FEATURE_LINK_TLS == 1\n                _z_close_tls_socket(&socket);\n#endif\n                _z_socket_close(&socket);\n                return ret;\n            }\n            _z_transport_peer_unicast_t *peer = NULL;\n            ret = _z_transport_peer_unicast_add(&zt->_transport._unicast, &tp_param, socket, true, &peer);\n            if ((ret == _Z_RES_OK) && (peer != NULL)) {\n                (void)_z_interest_push_declarations_to_peer(\n                    _z_transport_common_get_session(&zt->_transport._unicast._common), &peer->common);\n            }\n#if Z_FEATURE_CONNECTIVITY == 1\n            if ((ret == _Z_RES_OK) && (peer != NULL)) {\n                _z_new_peer_dispatch_connected_event(&zt->_transport._unicast, peer);\n            }\n#endif\n        } break;\n\n        default:\n            break;\n    }\n    return ret;\n}\n\nbool _z_transport_open_error_is_retryable(z_result_t ret) {\n    switch (ret) {\n        case _Z_ERR_TRANSPORT_OPEN_FAILED:\n        case _Z_ERR_TRANSPORT_TX_FAILED:\n        case _Z_ERR_TRANSPORT_RX_FAILED:\n        case _Z_ERR_TRANSPORT_RX_DURATION_EXPIRED:\n            return true;\n\n        default:\n            return false;\n    }\n}\n\n#if Z_FEATURE_UNICAST_PEER == 1\n/*\n * Attempt to add all peers currently marked as pending.\n *\n * Behaviour:\n * - Each locator is attempted once per call.\n * - On success, the locator is marked done.\n * - On non-retryable error, the locator is marked failed.\n * - On retryable error, the locator remains pending for future attempts.\n *\n * Return values:\n * - _Z_RES_OK:\n *     All pending peers were added, or there were no pending peers.\n *\n * - _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY:\n *     At least one peer was successfully added during this call, but\n *     retryable peers remain.\n *\n * - _Z_ERR_TRANSPORT_OPEN_FAILED:\n *     No peer was successfully added during this call, and retryable\n *     peers remain.\n *\n * - Any other error:\n *     A non-retryable error occurred; the returned value is the last\n *     such error encountered.\n */\nstatic z_result_t _z_add_peers_impl(_z_transport_t *zt, const _z_id_t *session_id, _z_pending_peers_t *pending_peers,\n                                    const _z_config_t *config) {\n    if (!_z_pending_peers_has_pending(pending_peers)) {\n        return _Z_RES_OK;\n    }\n\n    z_result_t last_non_retryable_ret = _Z_RES_OK;\n    bool peer_added = false;\n\n    size_t len = _z_pending_peer_svec_len(&pending_peers->_peers);\n    for (size_t i = 0; i < len; i++) {\n        _z_pending_peer_t *peer = _z_pending_peer_svec_get(&pending_peers->_peers, i);\n        if (peer->_state != _Z_PENDING_PEER_STATE_PENDING) {\n            continue;\n        }\n\n        _z_string_t *locator = &peer->_locator;\n        z_result_t peer_ret = _z_new_peer(zt, session_id, locator, config);\n\n        if (peer_ret == _Z_RES_OK) {\n            peer->_state = _Z_PENDING_PEER_STATE_DONE;\n            peer_added = true;\n            _Z_DEBUG(\"Successfully added peer locator [%zu]: %.*s\", i, (int)_z_string_len(locator),\n                     _z_string_data(locator));\n            continue;\n        }\n\n        _Z_DEBUG(\"Could not add peer locator [%zu]: %.*s (%d)\", i, (int)_z_string_len(locator), _z_string_data(locator),\n                 peer_ret);\n\n        if (!_z_transport_open_error_is_retryable(peer_ret)) {\n            peer->_state = _Z_PENDING_PEER_STATE_FAILED;\n            last_non_retryable_ret = peer_ret;\n\n            _Z_WARN(\"Peer locator [%zu] (%.*s) removed from pending set due to non-retryable error\", i,\n                    (int)_z_string_len(locator), _z_string_data(locator));\n        }\n    }\n\n    if (last_non_retryable_ret != _Z_RES_OK) {\n        return last_non_retryable_ret;\n    }\n    if (_z_pending_peers_has_pending(pending_peers)) {\n        return peer_added ? _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY : _Z_ERR_TRANSPORT_OPEN_FAILED;\n    }\n    return _Z_RES_OK;\n}\n\nstatic _z_fut_fn_result_t _z_add_peers_task_ready(_z_pending_peers_t *pending_peers) {\n    _z_pending_peers_clear(pending_peers);\n    return _z_fut_fn_result_ready();\n}\n\n/*\n * Add peers for a transport according to the configured failure policy.\n *\n * This function operates only on unicast transports. For other transport\n * types it is a no-op and returns _Z_RES_OK.\n *\n * Behaviour:\n * - Performs at least one attempt to add pending peers.\n * - If all peers are added, returns _Z_RES_OK.\n *\n * Non-retryable errors:\n * - If exit_on_failure is true, returns immediately with the error.\n * - Otherwise, tolerates the error and continues if retryable peers remain.\n *\n * Retryable peers remaining:\n * - If timeout_ms == 0:\n *     - exit_on_failure == true:\n *         returns:\n *           _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY if any peer was added\n *           _Z_ERR_TRANSPORT_OPEN_FAILED otherwise\n *     - exit_on_failure == false:\n *         returns _Z_RES_OK\n *\n * - If timeout_ms != 0:\n *     - exit_on_failure == true:\n *         retries synchronously with backoff until:\n *           * all peers are added, or\n *           * timeout expires, or\n *           * a non-retryable error occurs\n *\n *     - exit_on_failure == false:\n *         returns _Z_RES_OK and leaves pending_peers populated for\n *         background retry handling.\n *\n * Timeout result (exit_on_failure == true):\n * - If at least one peer was added before timeout:\n *     returns _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY\n * - Otherwise:\n *     returns _Z_ERR_TRANSPORT_OPEN_FAILED\n */\nz_result_t _z_add_peers(_z_transport_t *zt, const _z_id_t *session_id, _z_pending_peers_t *pending_peers,\n                        const _z_config_t *session_cfg, bool exit_on_failure) {\n    if (zt->_type != _Z_TRANSPORT_UNICAST_TYPE) {\n        _z_pending_peers_clear(pending_peers);\n        return _Z_RES_OK;\n    }\n\n    bool peer_added = false;\n\n    while (true) {\n        z_result_t ret = _z_add_peers_impl(zt, session_id, pending_peers, session_cfg);\n\n        if (ret == _Z_RES_OK) {\n            assert(!_z_pending_peers_has_pending(pending_peers));\n            _z_pending_peers_clear(pending_peers);\n            return _Z_RES_OK;\n        }\n\n        if (ret == _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY) {\n            peer_added = true;\n        } else if (ret != _Z_ERR_TRANSPORT_OPEN_FAILED) {\n            // Non-retryable error\n            if (exit_on_failure) {\n                _z_pending_peers_clear(pending_peers);\n                return ret;\n            }\n\n            if (!_z_pending_peers_has_pending(pending_peers)) {\n                _z_pending_peers_clear(pending_peers);\n                return _Z_RES_OK;\n            }\n        }\n\n        // Retryable peers remain\n        if (pending_peers->_timeout_ms == 0) {\n            if (!exit_on_failure) {\n                _z_pending_peers_clear(pending_peers);\n                return _Z_RES_OK;\n            }\n            _z_pending_peers_clear(pending_peers);\n            return peer_added ? _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY : _Z_ERR_TRANSPORT_OPEN_FAILED;\n        }\n\n        if (!exit_on_failure) {\n            _z_pending_peers_move(&zt->_transport._unicast._pending_peers, pending_peers);\n            return _Z_RES_OK;  // Let the background task handle retries until success or timeout\n        }\n\n        if (!_z_backoff_sleep(&pending_peers->_start, pending_peers->_timeout_ms, &pending_peers->_sleep_ms)) {\n            _z_pending_peers_clear(pending_peers);\n            return peer_added ? _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY : _Z_ERR_TRANSPORT_OPEN_FAILED;\n        }\n    }\n}\n\n/*\n * Continue peer addition after z_open() accepted partial connectivity.\n *\n * The task owns ztu->_pending_peers while pending locators remain. It clears\n * that state when the transport/session can no longer accept peers, when all\n * pending peers have been added, or when the configured timeout expires. During\n * transport reconnection it suspends so reconnection can re-establish the base\n * transport before peer addition resumes.\n */\n_z_fut_fn_result_t _zp_add_peers_task_fn(void *ztu_arg, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n\n    _z_transport_unicast_t *ztu = (_z_transport_unicast_t *)ztu_arg;\n    _z_pending_peers_t *pending_peers = &ztu->_pending_peers;\n\n    if (ztu->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_add_peers_task_ready(pending_peers);\n    } else if (ztu->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    if (!_z_pending_peers_has_pending(pending_peers)) {\n        return _z_add_peers_task_ready(pending_peers);\n    }\n\n    _z_session_rc_t session_rc = _z_session_weak_upgrade_if_open(&ztu->_common._session);\n    if (_Z_RC_IS_NULL(&session_rc)) {\n        return _z_add_peers_task_ready(pending_peers);\n    }\n\n    (void)_z_add_peers_impl(&_Z_RC_IN_VAL(&session_rc)->_tp, &_Z_RC_IN_VAL(&session_rc)->_local_zid, pending_peers,\n                            &_Z_RC_IN_VAL(&session_rc)->_config);\n\n    _z_session_rc_drop(&session_rc);\n\n    if (!_z_pending_peers_has_pending(pending_peers)) {\n        return _z_add_peers_task_ready(pending_peers);\n    }\n\n    // Check timeout and reschedule if needed\n    unsigned long delay_ms = pending_peers->_sleep_ms;\n\n    if (pending_peers->_timeout_ms > 0) {\n        unsigned long elapsed = z_clock_elapsed_ms(&pending_peers->_start);\n        if (elapsed >= (unsigned long)pending_peers->_timeout_ms) {\n            return _z_add_peers_task_ready(pending_peers);\n        }\n\n        unsigned long remaining_ms = (unsigned long)pending_peers->_timeout_ms - elapsed;\n        if (delay_ms > remaining_ms) {\n            delay_ms = remaining_ms;\n        }\n    }\n    _z_backoff_advance(&pending_peers->_sleep_ms);\n    return _z_fut_fn_result_wake_up_after(delay_ms);\n}\n#endif\n"
  },
  {
    "path": "src/transport/multicast/lease.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/lease.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/multicast/lease.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n\nz_result_t _zp_multicast_send_join(_z_transport_multicast_t *ztm) {\n    _z_conduit_sn_list_t next_sn;\n    next_sn._is_qos = false;\n    next_sn._val._plain._best_effort = ztm->_common._sn_tx_best_effort;\n    next_sn._val._plain._reliable = ztm->_common._sn_tx_reliable;\n\n    _z_id_t zid = _z_transport_common_get_session(&ztm->_common)->_local_zid;\n    _z_transport_message_t jsm = _z_t_msg_make_join(Z_WHATAMI_PEER, Z_TRANSPORT_LEASE, zid, next_sn);\n\n    return ztm->_send_f(&ztm->_common, &jsm);\n}\n\nz_result_t _zp_multicast_send_keep_alive(_z_transport_multicast_t *ztm) {\n    _z_transport_message_t t_msg = _z_t_msg_make_keep_alive();\n    return ztm->_send_f(&ztm->_common, &t_msg);\n}\n\n_z_fut_fn_result_t _zp_multicast_failed_result(_z_transport_multicast_t *ztm, _z_executor_t *executor) {\n    _z_session_t *session = _z_transport_common_get_session(&ztm->_common);\n\n#if Z_FEATURE_LIVELINESS == 1 && Z_FEATURE_SUBSCRIPTION == 1\n    _z_liveliness_subscription_undeclare_all(session);\n#endif\n    _z_session_transport_mutex_lock(session);\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    // Store weak session, to reuse for reconnection\n    _z_session_weak_t zs = _z_session_weak_clone(&ztm->_common._session);\n#endif\n    _z_transport_clear(&session->_tp);\n    _z_session_transport_mutex_unlock(session);\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    // Store weak session, to reuse for reconnection\n    ztm->_common._state = _Z_TRANSPORT_STATE_RECONNECTING;\n    ztm->_common._session = zs;\n    _z_fut_t f = _z_fut_null();\n    f._fut_arg = &ztm->_common;\n    f._fut_fn = _z_client_reopen_task_fn;\n    f._destroy_fn = _z_client_reopen_task_drop;\n    if (_z_fut_handle_is_null(_z_executor_spawn(executor, &f))) {\n        _Z_ERROR(\"Failed to spawn client reopen task after transport failure.\");\n        ztm->_common._state = _Z_TRANSPORT_STATE_CLOSED;\n        _z_session_weak_drop(&ztm->_common._session);\n        return _z_fut_fn_result_ready();\n    } else {\n        return _z_fut_fn_result_suspend();\n    }\n#else\n    _ZP_UNUSED(executor);\n    return _z_fut_fn_result_ready();\n#endif\n}\n\nstatic _z_zint_t _z_get_minimum_lease(_z_transport_peer_multicast_slist_t *peers, _z_zint_t local_lease) {\n    _z_zint_t ret = local_lease;\n\n    _z_transport_peer_multicast_slist_t *it = peers;\n    while (it != NULL) {\n        _z_transport_peer_multicast_t *val = _z_transport_peer_multicast_slist_value(it);\n        _z_zint_t lease = val->_lease;\n        if (lease < ret) {\n            ret = lease;\n        }\n\n        it = _z_transport_peer_multicast_slist_next(it);\n    }\n\n    return ret;\n}\n\nstatic bool _zp_multicast_peer_is_expired(const _z_transport_peer_multicast_t *target,\n                                          const _z_transport_peer_multicast_t *peer) {\n    _ZP_UNUSED(target);\n    return !peer->common._received;\n}\n\nstatic void _zp_multicast_report_disconnected_events(_z_transport_multicast_t *ztm,\n                                                     _z_transport_peer_multicast_slist_t **dropped_peers) {\n    if (dropped_peers == NULL || *dropped_peers == NULL) {\n        return;\n    }\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    _z_transport_get_link_properties(&ztm->_common, &mtu, &is_streamed, &is_reliable);\n#endif\n\n    _z_session_t *s = _z_transport_common_get_session(&ztm->_common);\n    _z_transport_peer_multicast_slist_t *it = *dropped_peers;\n    while (it != NULL) {\n        _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(it);\n        _Z_INFO(\"Deleting peer because it has expired after %zums\", peer->_lease);\n        _z_interest_peer_disconnected(s, &peer->common);\n#if Z_FEATURE_CONNECTIVITY == 1\n        _z_connectivity_peer_event_data_t disconnected_peer = {0};\n        _z_connectivity_peer_event_data_alias_from_common(&disconnected_peer, &peer->common);\n        _z_connectivity_peer_disconnected(s, &disconnected_peer, true, mtu, is_streamed, is_reliable);\n#endif\n        it = _z_transport_peer_multicast_slist_next(it);\n    }\n    _z_transport_peer_multicast_slist_free(dropped_peers);\n}\n\n_z_fut_fn_result_t _zp_multicast_lease_task_fn(void *ztm_arg, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n    _z_transport_multicast_t *ztm = (_z_transport_multicast_t *)ztm_arg;\n\n    if (ztm->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztm->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    _z_transport_peer_multicast_slist_t *dropped_peers = _z_transport_peer_multicast_slist_new();\n    _z_transport_peer_mutex_lock(&ztm->_common);\n    ztm->_peers = _z_transport_peer_multicast_slist_extract_all_filter(ztm->_peers, &dropped_peers,\n                                                                       _zp_multicast_peer_is_expired, NULL);\n    _z_transport_peer_multicast_slist_t *curr_list = ztm->_peers;\n    while (curr_list != NULL) {\n        _z_transport_peer_multicast_t *curr_peer = _z_transport_peer_multicast_slist_value(curr_list);\n        curr_peer->common._received = false;\n        curr_list = _z_transport_peer_multicast_slist_next(curr_list);\n    }\n    unsigned long min_lease = (unsigned long)_z_get_minimum_lease(ztm->_peers, ztm->_common._lease);\n    _z_transport_peer_mutex_unlock(&ztm->_common);\n    _zp_multicast_report_disconnected_events(ztm, &dropped_peers);\n    return _z_fut_fn_result_wake_up_after(min_lease);\n}\n\n_z_fut_fn_result_t _zp_multicast_keep_alive_task_fn(void *ztm_arg, _z_executor_t *executor) {\n    _z_transport_multicast_t *ztm = (_z_transport_multicast_t *)ztm_arg;\n\n    if (ztm->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztm->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    if (ztm->_common._transmitted == false) {\n        if (_zp_multicast_send_keep_alive(ztm) < 0) {\n            _Z_INFO(\"Send keep alive failed.\");\n            return _zp_multicast_failed_result(ztm, executor);\n        }\n    }\n    ztm->_common._transmitted = false;\n    _z_transport_peer_mutex_lock(&ztm->_common);\n    unsigned long min_lease = (unsigned long)_z_get_minimum_lease(ztm->_peers, ztm->_common._lease);\n    _z_transport_peer_mutex_unlock(&ztm->_common);\n    return _z_fut_fn_result_wake_up_after(min_lease / Z_TRANSPORT_LEASE_EXPIRE_FACTOR);\n}\n\n_z_fut_fn_result_t _zp_multicast_send_join_task_fn(void *ztm_arg, _z_executor_t *executor) {\n    _z_transport_multicast_t *ztm = (_z_transport_multicast_t *)ztm_arg;\n\n    if (ztm->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztm->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n    if (_zp_multicast_send_join(ztm) < 0) {\n        _Z_INFO(\"Send join failed.\");\n        return _zp_multicast_failed_result(ztm, executor);\n    } else {\n        ztm->_common._transmitted = true;\n        return _z_fut_fn_result_wake_up_after(Z_JOIN_INTERVAL);\n    }\n}\n#endif  // Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/multicast/read.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/multicast/read.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/common/rx.h\"\n#include \"zenoh-pico/transport/multicast/lease.h\"\n#include \"zenoh-pico/transport/multicast/rx.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\n\nstatic z_result_t _zp_multicast_process_messages(_z_transport_multicast_t *ztm) {\n    size_t to_read = 0;\n\n    z_result_t ret = _z_multicast_recv_zbuf(ztm, &to_read);\n    if (ret == _Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES || ret == _Z_ERR_TRANSPORT_RX_FAILED) {\n        return _Z_NO_DATA_PROCESSED;\n    } else if (ret != _Z_RES_OK) {\n        return ret;\n    }\n\n    // Wrap the main buffer to_read bytes\n    _z_zbuf_t zbuf = _z_zbuf_view(&ztm->_common._zbuf, to_read);\n    while (_z_zbuf_len(&zbuf) > 0) {\n        // Decode one session message\n        _z_transport_message_t t_msg;\n        ret = _z_transport_message_decode(&t_msg, &zbuf);\n        if (ret != _Z_RES_OK) {\n            _Z_ERROR(\"Connection closed due to malformed message: %d\", ret);\n            break;\n        }\n\n        ret = _z_multicast_handle_transport_message(ztm, &t_msg, &ztm->_zbuf_addr);\n        if (ret != _Z_RES_OK) {\n            _Z_ERROR(\"Dropping message due to processing error: %d\", ret);\n            break;\n        }\n    }\n    // Move the read position of the read buffer\n    _z_zbuf_set_rpos(&ztm->_common._zbuf, _z_zbuf_get_rpos(&ztm->_common._zbuf) + to_read);\n    if (_z_multicast_update_rx_buffer(ztm) != _Z_RES_OK) {\n        _Z_ERROR(\"Connection closed due to lack of memory to allocate rx buffer\");\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return ret;\n}\n\nz_result_t _zp_multicast_read(_z_transport_multicast_t *ztm, bool single_read) {\n    // Read & process a single message\n    if (single_read) {\n        _z_transport_message_t t_msg;\n        _Z_RETURN_IF_ERR(_z_multicast_recv_t_msg(ztm, &t_msg));\n        _Z_CLEAN_RETURN_IF_ERR(_z_multicast_handle_transport_message(ztm, &t_msg, &ztm->_zbuf_addr),\n                               _z_t_msg_clear(&t_msg));\n        _z_t_msg_clear(&t_msg);\n        return _z_multicast_update_rx_buffer(ztm);\n    } else {\n        return _zp_multicast_process_messages(ztm);\n    }\n}\n\n_z_fut_fn_result_t _zp_multicast_read_task_fn(void *ztm_arg, _z_executor_t *executor) {\n    _z_transport_multicast_t *ztm = (_z_transport_multicast_t *)ztm_arg;\n    if (ztm->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztm->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n    if (_zp_multicast_process_messages(ztm) < _Z_RES_OK) {\n        // TODO: report failure and disconnect ?\n        _Z_WARN(\"Multicast read task failed\");\n        return _zp_multicast_failed_result(ztm, executor);\n    } else {\n        return _z_fut_fn_result_continue();\n    }\n}\n#endif\n"
  },
  {
    "path": "src/transport/multicast/rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/rx.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/multicast/rx.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\nz_result_t _z_multicast_recv_zbuf(_z_transport_multicast_t *ztm, size_t *to_read) {\n    z_result_t ret = _Z_RES_OK;\n\n    do {\n        // Read bytes from socket to the main buffer\n        switch (ztm->_common._link->_cap._flow) {\n            case Z_LINK_CAP_FLOW_STREAM:\n                if (_z_zbuf_len(&ztm->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                    _z_link_recv_zbuf(ztm->_common._link, &ztm->_common._zbuf, &ztm->_zbuf_addr);\n                    if (_z_zbuf_len(&ztm->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                        _z_zbuf_compact(&ztm->_common._zbuf);\n                        ret = _Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES;\n                        break;\n                    }\n                }\n                // Get stream size\n                *to_read = _z_read_stream_size(&ztm->_common._zbuf);\n                // Read data\n                if (_z_zbuf_len(&ztm->_common._zbuf) < *to_read) {\n                    _z_link_recv_zbuf(ztm->_common._link, &ztm->_common._zbuf, NULL);\n                    if (_z_zbuf_len(&ztm->_common._zbuf) < *to_read) {\n                        _z_zbuf_set_rpos(&ztm->_common._zbuf,\n                                         _z_zbuf_get_rpos(&ztm->_common._zbuf) - _Z_MSG_LEN_ENC_SIZE);\n                        _z_zbuf_compact(&ztm->_common._zbuf);\n                        ret = _Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES;\n                        break;\n                    }\n                }\n                break;\n            // Datagram capable links\n            case Z_LINK_CAP_FLOW_DATAGRAM:\n                if (_z_zbuf_len(&ztm->_common._zbuf) == 0) {\n                    _z_zbuf_compact(&ztm->_common._zbuf);\n                    *to_read = _z_link_recv_zbuf(ztm->_common._link, &ztm->_common._zbuf, &ztm->_zbuf_addr);\n                    if (*to_read == SIZE_MAX) {\n                        ret = _Z_ERR_TRANSPORT_RX_FAILED;\n                    }\n                } else {\n                    *to_read = _z_zbuf_len(&ztm->_common._zbuf);\n                }\n                break;\n            default:\n                break;\n        }\n    } while (false);  // The 1-iteration loop to use continue to break the entire loop on error\n\n    return ret;\n}\n\nz_result_t _z_multicast_recv_t_msg(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg) {\n    _Z_DEBUG(\">> recv session msg\");\n    size_t to_read = 0;\n\n    z_result_t ret = _z_multicast_recv_zbuf(ztm, &to_read);\n\n    if (ret == _Z_RES_OK) {\n        _Z_DEBUG(\">> \\t transport_message_decode: %ju\", (uintmax_t)_z_zbuf_len(&ztm->_common._zbuf));\n\n        // Wrap the main buffer to_read bytes\n        _z_zbuf_t zbuf = _z_zbuf_view(&ztm->_common._zbuf, to_read);\n        ret = _z_transport_message_decode(t_msg, &zbuf);\n        if (ret == _Z_RES_OK) {\n            _z_zbuf_set_rpos(&ztm->_common._zbuf, _z_zbuf_get_rpos(&ztm->_common._zbuf) + _z_zbuf_get_rpos(&zbuf));\n        } else {\n            _Z_ERROR(\"Malformed transport message: %d\", ret);\n            _z_zbuf_set_rpos(&ztm->_common._zbuf, _z_zbuf_get_rpos(&ztm->_common._zbuf) + to_read);\n        }\n    }\n\n    return ret;\n}\n#else\nz_result_t _z_multicast_recv_t_msg(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg) {\n    _ZP_UNUSED(ztm);\n    _ZP_UNUSED(t_msg);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif  // Z_FEATURE_MULTICAST_TRANSPORT == 1\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic z_result_t _z_multicast_remote_addr_to_endpoint(const _z_transport_multicast_t *ztm,\n                                                       const _z_slice_t *remote_addr, _z_string_t *endpoint) {\n    char addr[96] = {0};\n    _z_locator_t locator;\n    const uint8_t *bytes = remote_addr->start;\n    size_t address_len = 0;\n    uint16_t port = 0;\n\n    *endpoint = _z_string_null();\n    if (ztm == NULL || ztm->_common._link == NULL || remote_addr == NULL || bytes == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    if (remote_addr->len == sizeof(uint32_t) + sizeof(uint16_t)) {\n        address_len = sizeof(uint32_t);\n        port = ((uint16_t)bytes[4] << 8) | (uint16_t)bytes[5];\n    } else if (remote_addr->len == 16 + sizeof(uint16_t)) {\n        address_len = 16;\n        port = ((uint16_t)bytes[16] << 8) | (uint16_t)bytes[17];\n    } else {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n    _Z_RETURN_IF_ERR(_z_ip_port_to_endpoint(bytes, address_len, port, addr, sizeof(addr)));\n\n    _z_locator_init(&locator);\n    if (_z_string_check(&ztm->_common._link->_endpoint._locator._protocol)) {\n        locator._protocol = _z_string_alias(ztm->_common._link->_endpoint._locator._protocol);\n    } else {\n        locator._protocol = _z_string_alias_str(\"udp\");\n    }\n    locator._address = _z_string_alias_str(addr);\n\n    *endpoint = _z_locator_to_string(&locator);\n    _z_locator_clear(&locator);\n    if (!_z_string_check(endpoint)) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n#endif\n\nstatic _z_transport_peer_multicast_t *_z_find_peer_entry(_z_transport_peer_multicast_slist_t *l,\n                                                         _z_slice_t *remote_addr) {\n    _z_transport_peer_multicast_t *ret = NULL;\n\n    _z_transport_peer_multicast_slist_t *xs = l;\n    for (; xs != NULL; xs = _z_transport_peer_multicast_slist_next(xs)) {\n        _z_transport_peer_multicast_t *val = _z_transport_peer_multicast_slist_value(xs);\n        if (val->_remote_addr.len != remote_addr->len) {\n            continue;\n        }\n        if (memcmp(val->_remote_addr.start, remote_addr->start, remote_addr->len) == 0) {\n            ret = val;\n        }\n    }\n\n    return ret;\n}\n\nstatic z_result_t _z_multicast_handle_frame(_z_transport_multicast_t *ztm, uint8_t header, _z_t_msg_frame_t *msg,\n                                            _z_transport_peer_multicast_t *entry) {\n    // Check peer\n    if (entry == NULL) {\n        _Z_INFO(\"Dropping _Z_FRAME from unknown peer\");\n        _z_t_msg_frame_clear(msg);\n        return _Z_RES_OK;\n    }\n    // Note that we receive data from peer\n    entry->common._received = true;\n\n    z_reliability_t tmsg_reliability;\n    // Check if the SN is correct\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_FRAME_R)) {\n        tmsg_reliability = Z_RELIABILITY_RELIABLE;\n        // @TODO: amend once reliability is in place. For the time being only\n        //        monotonic SNs are ensured\n        if (_z_sn_precedes(entry->_sn_res, entry->_sn_rx_sns._val._plain._reliable, msg->_sn)) {\n            entry->_sn_rx_sns._val._plain._reliable = msg->_sn;\n        } else {\n#if Z_FEATURE_FRAGMENTATION == 1\n            entry->common._state_reliable = _Z_DBUF_STATE_NULL;\n            _z_wbuf_clear(&entry->common._dbuf_reliable);\n#endif\n            _Z_INFO(\"Reliable message dropped because it is out of order\");\n            _z_t_msg_frame_clear(msg);\n            return _Z_RES_OK;\n        }\n    } else {\n        tmsg_reliability = Z_RELIABILITY_BEST_EFFORT;\n        if (_z_sn_precedes(entry->_sn_res, entry->_sn_rx_sns._val._plain._best_effort, msg->_sn)) {\n            entry->_sn_rx_sns._val._plain._best_effort = msg->_sn;\n        } else {\n#if Z_FEATURE_FRAGMENTATION == 1\n            entry->common._state_best_effort = _Z_DBUF_STATE_NULL;\n            _z_wbuf_clear(&entry->common._dbuf_best_effort);\n#endif\n            _Z_INFO(\"Best effort message dropped because it is out of order\");\n            _z_t_msg_frame_clear(msg);\n            return _Z_RES_OK;\n        }\n    }\n    // Handle all the zenoh message, one by one\n    // From this point, memory cleaning must be handled by the network message layer\n    _z_network_message_t curr_nmsg = {0};\n    _z_arc_slice_t arcs = _z_arc_slice_empty();\n    while (_z_zbuf_len(msg->_payload) > 0) {\n        _Z_RETURN_IF_ERR(_z_network_message_decode(&curr_nmsg, msg->_payload, &arcs, (uintptr_t)&entry->common));\n        curr_nmsg._reliability = tmsg_reliability;\n        _Z_RETURN_IF_ERR(_z_handle_network_message(&ztm->_common, &curr_nmsg, &entry->common));\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_multicast_handle_fragment_inner(_z_transport_multicast_t *ztm, uint8_t header,\n                                                     _z_t_msg_fragment_t *msg, _z_transport_peer_multicast_t *entry) {\n    z_result_t ret = _Z_RES_OK;\n#if Z_FEATURE_FRAGMENTATION == 1\n    // Check peer\n    if (entry == NULL) {\n        _Z_INFO(\"Dropping Z_FRAGMENT from unknown peer\");\n        return _Z_RES_OK;\n    }\n    // Note that we receive data from the peer\n    entry->common._received = true;\n\n    _z_wbuf_t *dbuf;\n    uint8_t *dbuf_state;\n    z_reliability_t tmsg_reliability;\n    bool consecutive;\n\n    // Select the right defragmentation buffer\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_FRAME_R)) {\n        tmsg_reliability = Z_RELIABILITY_RELIABLE;\n        // Check SN\n        // @TODO: amend once reliability is in place. For the time being only\n        //        monotonic SNs are ensured\n        if (_z_sn_precedes(entry->_sn_res, entry->_sn_rx_sns._val._plain._reliable, msg->_sn)) {\n            consecutive = _z_sn_consecutive(entry->_sn_res, entry->_sn_rx_sns._val._plain._reliable, msg->_sn);\n            entry->_sn_rx_sns._val._plain._reliable = msg->_sn;\n            dbuf = &entry->common._dbuf_reliable;\n            dbuf_state = &entry->common._state_reliable;\n        } else {\n            _z_wbuf_clear(&entry->common._dbuf_reliable);\n            entry->common._state_reliable = _Z_DBUF_STATE_NULL;\n            _Z_INFO(\"Reliable message dropped because it is out of order\");\n            return _Z_RES_OK;\n        }\n    } else {\n        tmsg_reliability = Z_RELIABILITY_BEST_EFFORT;\n        // Check SN\n        if (_z_sn_precedes(entry->_sn_res, entry->_sn_rx_sns._val._plain._best_effort, msg->_sn)) {\n            consecutive = _z_sn_consecutive(entry->_sn_res, entry->_sn_rx_sns._val._plain._best_effort, msg->_sn);\n            entry->_sn_rx_sns._val._plain._best_effort = msg->_sn;\n            dbuf = &entry->common._dbuf_best_effort;\n            dbuf_state = &entry->common._state_best_effort;\n        } else {\n            _z_wbuf_clear(&entry->common._dbuf_best_effort);\n            entry->common._state_best_effort = _Z_DBUF_STATE_NULL;\n            _Z_INFO(\"Best effort message dropped because it is out of order\");\n            return _Z_RES_OK;\n        }\n    }\n    if (!consecutive && (_z_wbuf_len(dbuf) > 0)) {\n        _z_wbuf_clear(dbuf);\n        *dbuf_state = _Z_DBUF_STATE_NULL;\n        _Z_INFO(\"Defragmentation buffer dropped because non-consecutive fragments received\");\n        return _Z_RES_OK;\n    }\n    // Handle fragment markers\n    if (_Z_PATCH_HAS_FRAGMENT_MARKERS(entry->common._patch)) {\n        if (msg->first) {\n            _z_wbuf_reset(dbuf);\n        } else if (_z_wbuf_len(dbuf) == 0) {\n            _Z_INFO(\"First fragment received without the first marker\");\n            return _Z_RES_OK;\n        }\n        if (msg->drop) {\n            _z_wbuf_reset(dbuf);\n            return _Z_RES_OK;\n        }\n    }\n    // Allocate buffer if needed\n    if (*dbuf_state == _Z_DBUF_STATE_NULL) {\n        *dbuf = _z_wbuf_make(Z_FRAG_MAX_SIZE, false);\n        if (_z_wbuf_capacity(dbuf) != Z_FRAG_MAX_SIZE) {\n            _Z_ERROR(\"Not enough memory to allocate peer defragmentation buffer\");\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        *dbuf_state = _Z_DBUF_STATE_INIT;\n    }\n    // Process fragment data\n    if (*dbuf_state == _Z_DBUF_STATE_INIT) {\n        // Check overflow\n        if ((_z_wbuf_len(dbuf) + msg->_payload.len) > Z_FRAG_MAX_SIZE) {\n            *dbuf_state = _Z_DBUF_STATE_OVERFLOW;\n        } else {\n            // Fill buffer\n            _z_wbuf_write_bytes(dbuf, msg->_payload.start, 0, msg->_payload.len);\n        }\n    }\n    // Process final fragment\n    if (!_Z_HAS_FLAG(header, _Z_FLAG_T_FRAGMENT_M)) {\n        // Drop message if it exceeds the fragmentation size\n        if (*dbuf_state == _Z_DBUF_STATE_OVERFLOW) {\n            _Z_INFO(\"Fragment dropped because defragmentation buffer has overflown\");\n            _z_wbuf_clear(dbuf);\n            *dbuf_state = _Z_DBUF_STATE_NULL;\n            return _Z_RES_OK;\n        }\n        // Convert the defragmentation buffer into a decoding buffer\n        _z_zbuf_t zbf = _z_wbuf_moved_as_zbuf(dbuf);\n        if (_z_zbuf_capacity(&zbf) == 0) {\n            _Z_ERROR(\"Failed to convert defragmentation buffer into a decoding buffer!\");\n            _z_wbuf_clear(dbuf);\n            *dbuf_state = _Z_DBUF_STATE_NULL;\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        // Decode message\n        _z_zenoh_message_t zm = {0};\n        _z_arc_slice_t arcs = _z_arc_slice_empty();\n        ret = _z_network_message_decode(&zm, &zbf, &arcs, (uintptr_t)&entry->common);\n        zm._reliability = tmsg_reliability;\n        if (ret == _Z_RES_OK) {\n            // Memory clear of the network message data must be handled by the network message layer\n            _z_handle_network_message(&ztm->_common, &zm, &entry->common);\n        } else {\n            _Z_INFO(\"Failed to decode defragmented message\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n        // Free the decoding buffer\n        _z_zbuf_clear(&zbf);\n        *dbuf_state = _Z_DBUF_STATE_NULL;\n    }\n#else\n    _ZP_UNUSED(ztm);\n    _ZP_UNUSED(header);\n    _ZP_UNUSED(msg);\n    _ZP_UNUSED(entry);\n    _Z_INFO(\"Fragment dropped because fragmentation feature is deactivated\");\n#endif\n    return ret;\n}\n\nstatic z_result_t _z_multicast_handle_fragment(_z_transport_multicast_t *ztm, uint8_t header, _z_t_msg_fragment_t *msg,\n                                               _z_transport_peer_multicast_t *entry) {\n    z_result_t ret = _z_multicast_handle_fragment_inner(ztm, header, msg, entry);\n    _z_t_msg_fragment_clear(msg);\n    return ret;\n}\n\nstatic z_result_t _z_multicast_handle_join_inner(_z_transport_multicast_t *ztm, _z_slice_t *addr, _z_t_msg_join_t *msg,\n                                                 _z_transport_peer_multicast_t *entry) {\n    // Check proto version\n    if (msg->_version != Z_PROTO_VERSION) {\n        return _Z_RES_OK;\n    }\n    // Check peer\n    if (entry == NULL) {  // New peer\n        // If the new node has less representing capabilities then we can't communicate\n        if ((msg->_seq_num_res != Z_SN_RESOLUTION) || (msg->_req_id_res != Z_REQ_RESOLUTION) ||\n            (msg->_batch_size != Z_BATCH_MULTICAST_SIZE)) {\n            _Z_INFO(\"Couldn't accept peer because distant node is incompatible config wise.\");\n            _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION);\n        }\n        // Initialize entry\n        ztm->_peers = _z_transport_peer_multicast_slist_push_empty(ztm->_peers);\n        entry = _z_transport_peer_multicast_slist_value(ztm->_peers);\n        entry->_sn_res = _z_sn_max(msg->_seq_num_res);\n        entry->_remote_addr = _z_slice_duplicate(addr);\n        _z_conduit_sn_list_copy(&entry->_sn_rx_sns, &msg->_next_sn);\n        _z_conduit_sn_list_decrement(entry->_sn_res, &entry->_sn_rx_sns);\n        // Update lease time (set as ms during)\n        entry->_lease = msg->_lease;\n        entry->common._remote_zid = msg->_zid;\n        entry->common._remote_whatami = msg->_whatami;\n        entry->common._received = true;\n        entry->common._remote_resources = NULL;\n#if Z_FEATURE_CONNECTIVITY == 1\n        entry->common._link_src = _z_string_null();\n        entry->common._link_dst = _z_string_null();\n        if (ztm->_common._link != NULL) {\n            entry->common._link_src = _z_endpoint_to_string(&ztm->_common._link->_endpoint);\n            (void)_z_multicast_remote_addr_to_endpoint(ztm, addr, &entry->common._link_dst);\n        }\n#endif\n#if Z_FEATURE_FRAGMENTATION == 1\n        entry->common._patch = msg->_patch < _Z_CURRENT_PATCH ? msg->_patch : _Z_CURRENT_PATCH;\n        entry->common._state_reliable = _Z_DBUF_STATE_NULL;\n        entry->common._state_best_effort = _Z_DBUF_STATE_NULL;\n        entry->common._dbuf_reliable = _z_wbuf_null();\n        entry->common._dbuf_best_effort = _z_wbuf_null();\n#endif\n#if Z_FEATURE_CONNECTIVITY == 1\n        _z_connectivity_peer_event_data_t connected_peer = {0};\n        uint16_t mtu = 0;\n        bool is_streamed = false;\n        bool is_reliable = false;\n        _z_transport_get_link_properties(&ztm->_common, &mtu, &is_streamed, &is_reliable);\n        _z_connectivity_peer_event_data_copy_from_common(&connected_peer, &entry->common);\n        _z_transport_peer_mutex_unlock(&ztm->_common);\n        _z_connectivity_peer_connected(_z_transport_common_get_session(&ztm->_common), &connected_peer, true, mtu,\n                                       is_streamed, is_reliable);\n        _z_connectivity_peer_event_data_clear(&connected_peer);\n        _z_transport_peer_mutex_lock(&ztm->_common);\n#endif\n    } else {  // Existing peer\n        // Note that we receive data from the peer\n        entry->common._received = true;\n\n        // Check representing capabilities\n        if ((msg->_seq_num_res != Z_SN_RESOLUTION) || (msg->_req_id_res != Z_REQ_RESOLUTION) ||\n            (msg->_batch_size != Z_BATCH_MULTICAST_SIZE)) {\n#if Z_FEATURE_CONNECTIVITY == 1\n            _z_connectivity_peer_event_data_t disconnected_peer = {0};\n            uint16_t mtu = 0;\n            bool is_streamed = false;\n            bool is_reliable = false;\n            _z_transport_get_link_properties(&ztm->_common, &mtu, &is_streamed, &is_reliable);\n            _z_connectivity_peer_event_data_copy_from_common(&disconnected_peer, &entry->common);\n#endif\n            // TODO: cleanup here should also be done on mappings/subs/etc...\n            _z_transport_peer_multicast_slist_drop_first_filter(ztm->_peers, _z_transport_peer_multicast_eq, entry);\n#if Z_FEATURE_CONNECTIVITY == 1\n            _z_transport_peer_mutex_unlock(&ztm->_common);\n            _z_connectivity_peer_disconnected(_z_transport_common_get_session(&ztm->_common), &disconnected_peer, true,\n                                              mtu, is_streamed, is_reliable);\n            _z_connectivity_peer_event_data_clear(&disconnected_peer);\n            _z_transport_peer_mutex_lock(&ztm->_common);\n#endif\n            return _Z_RES_OK;\n        }\n        // Update SNs\n        _z_conduit_sn_list_copy(&entry->_sn_rx_sns, &msg->_next_sn);\n        _z_conduit_sn_list_decrement(entry->_sn_res, &entry->_sn_rx_sns);\n        // Update lease time (set as ms during)\n        entry->_lease = msg->_lease;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_multicast_handle_join(_z_transport_multicast_t *ztm, _z_slice_t *addr, _z_t_msg_join_t *msg,\n                                           _z_transport_peer_multicast_t *entry) {\n    z_result_t ret = _z_multicast_handle_join_inner(ztm, addr, msg, entry);\n    _z_t_msg_join_clear(msg);\n    return ret;\n}\n\nz_result_t _z_multicast_handle_transport_message(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg,\n                                                 _z_slice_t *addr) {\n    z_result_t ret = _Z_RES_OK;\n    _z_transport_peer_mutex_lock(&ztm->_common);\n    // Mark the session that we have received data from this peer\n    _z_transport_peer_multicast_t *entry = _z_find_peer_entry(ztm->_peers, addr);\n    switch (_Z_MID(t_msg->_header)) {\n        case _Z_MID_T_FRAME: {\n            _Z_DEBUG(\"Received _Z_FRAME message\");\n            ret = _z_multicast_handle_frame(ztm, t_msg->_header, &t_msg->_body._frame, entry);\n            break;\n        }\n\n        case _Z_MID_T_FRAGMENT:\n            _Z_DEBUG(\"Received Z_FRAGMENT message\");\n            ret = _z_multicast_handle_fragment(ztm, t_msg->_header, &t_msg->_body._fragment, entry);\n            break;\n\n        case _Z_MID_T_KEEP_ALIVE: {\n            _Z_DEBUG(\"Received _Z_KEEP_ALIVE message\");\n            if (entry != NULL) {\n                entry->common._received = true;\n            }\n            _z_t_msg_keep_alive_clear(&t_msg->_body._keep_alive);\n            break;\n        }\n\n        case _Z_MID_T_INIT: {\n            // Do nothing, multicast transports are not expected to handle INIT messages\n            _z_t_msg_init_clear(&t_msg->_body._init);\n            break;\n        }\n\n        case _Z_MID_T_OPEN: {\n            // Do nothing, multicast transports are not expected to handle OPEN messages\n            _z_t_msg_open_clear(&t_msg->_body._open);\n            break;\n        }\n\n        case _Z_MID_T_JOIN: {\n            _Z_DEBUG(\"Received _Z_JOIN message\");\n            ret = _z_multicast_handle_join(ztm, addr, &t_msg->_body._join, entry);\n            break;\n        }\n\n        case _Z_MID_T_CLOSE: {\n            _Z_INFO(\"Closing connection as requested by the remote peer\");\n            if (entry != NULL) {\n#if Z_FEATURE_CONNECTIVITY == 1\n                _z_connectivity_peer_event_data_t disconnected_peer = {0};\n                uint16_t mtu = 0;\n                bool is_streamed = false;\n                bool is_reliable = false;\n                _z_transport_get_link_properties(&ztm->_common, &mtu, &is_streamed, &is_reliable);\n                _z_connectivity_peer_event_data_copy_from_common(&disconnected_peer, &entry->common);\n#endif\n                ztm->_peers = _z_transport_peer_multicast_slist_drop_first_filter(\n                    ztm->_peers, _z_transport_peer_multicast_eq, entry);\n#if Z_FEATURE_CONNECTIVITY == 1\n                _z_transport_peer_mutex_unlock(&ztm->_common);\n                _z_connectivity_peer_disconnected(_z_transport_common_get_session(&ztm->_common), &disconnected_peer,\n                                                  true, mtu, is_streamed, is_reliable);\n                _z_connectivity_peer_event_data_clear(&disconnected_peer);\n                _z_transport_peer_mutex_lock(&ztm->_common);\n#endif\n            }\n            _z_t_msg_close_clear(&t_msg->_body._close);\n            break;\n        }\n\n        default: {\n            _Z_ERROR(\"Unknown session message ID\");\n            _z_t_msg_clear(t_msg);\n            break;\n        }\n    }\n    _z_transport_peer_mutex_unlock(&ztm->_common);\n    return ret;\n}\n\nz_result_t _z_multicast_update_rx_buffer(_z_transport_multicast_t *ztm) {\n    // Check if user or defragment buffer took ownership of buffer\n    if (_z_zbuf_get_ref_count(&ztm->_common._zbuf) != 1) {\n        // Allocate a new buffer\n        _z_zbuf_t new_zbuf = _z_zbuf_make(Z_BATCH_MULTICAST_SIZE);\n        if (_z_zbuf_capacity(&new_zbuf) != Z_BATCH_MULTICAST_SIZE) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        // Recopy leftover bytes\n        size_t leftovers = _z_zbuf_len(&ztm->_common._zbuf);\n        if (leftovers > 0) {\n            _z_zbuf_copy_bytes(&new_zbuf, &ztm->_common._zbuf);\n        }\n        // Drop buffer & update\n        _z_zbuf_clear(&ztm->_common._zbuf);\n        ztm->_common._zbuf = new_zbuf;\n    }\n    return _Z_RES_OK;\n}\n\n#else\nz_result_t _z_multicast_handle_transport_message(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg,\n                                                 _z_slice_t *addr) {\n    _ZP_UNUSED(ztm);\n    _ZP_UNUSED(t_msg);\n    _ZP_UNUSED(addr);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif  // Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/multicast/transport.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/transport/common/transport.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/transport/raweth/tx.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n\nz_result_t _z_multicast_transport_create(_z_transport_t *zt, _z_link_t *zl,\n                                         _z_transport_multicast_establish_param_t *param) {\n    z_result_t ret = _Z_RES_OK;\n    // Transport specific information\n    _z_transport_multicast_t *ztm = NULL;\n    switch (zl->_cap._transport) {\n        case Z_LINK_CAP_TRANSPORT_MULTICAST:\n            zt->_type = _Z_TRANSPORT_MULTICAST_TYPE;\n            ztm = &zt->_transport._multicast;\n            ztm->_send_f = _z_transport_tx_send_t_msg_wrapper;\n            break;\n        case Z_LINK_CAP_TRANSPORT_RAWETH:\n            zt->_type = _Z_TRANSPORT_RAWETH_TYPE;\n            ztm = &zt->_transport._raweth;\n            ztm->_send_f = _z_raweth_send_t_msg;\n            break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n\n    // Initialize persistent address buffer\n    ztm->_zbuf_addr = _z_slice_alias_buf(ztm->_zbuf_addr_buf, sizeof(ztm->_zbuf_addr_buf));\n\n// Initialize batching data\n#if Z_FEATURE_BATCHING == 1\n    ztm->_common._batch_state = _Z_BATCHING_IDLE;\n    ztm->_common._batch_count = 0;\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    // Initialize the mutexes\n    ret = _z_mutex_init(&ztm->_common._mutex_tx);\n    if (ret == _Z_RES_OK) {\n        ret = _z_mutex_rec_init(&ztm->_common._mutex_peer);\n        if (ret != _Z_RES_OK) {\n            _z_mutex_drop(&ztm->_common._mutex_tx);\n        }\n    }\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    // Initialize the read and write buffers\n    if (ret == _Z_RES_OK) {\n        uint16_t mtu = (zl->_mtu < Z_BATCH_MULTICAST_SIZE) ? zl->_mtu : Z_BATCH_MULTICAST_SIZE;\n        ztm->_common._wbuf = _z_wbuf_make(mtu, false);\n        ztm->_common._zbuf = _z_zbuf_make(Z_BATCH_MULTICAST_SIZE);\n\n        // Clean up the buffers if one of them failed to be allocated\n        if ((_z_wbuf_capacity(&ztm->_common._wbuf) != mtu) ||\n            (_z_zbuf_capacity(&ztm->_common._zbuf) != Z_BATCH_MULTICAST_SIZE)) {\n            _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            ret = _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n            _Z_ERROR(\"Not enough memory to allocate transport tx rx buffers!\");\n\n#if Z_FEATURE_MULTI_THREAD == 1\n            _z_mutex_drop(&ztm->_common._mutex_tx);\n            _z_mutex_rec_drop(&ztm->_common._mutex_peer);\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n            _z_wbuf_clear(&ztm->_common._wbuf);\n            _z_zbuf_clear(&ztm->_common._zbuf);\n        }\n    }\n\n    if (ret == _Z_RES_OK) {\n        // Set default SN resolution\n        ztm->_common._sn_res = _z_sn_max(param->_seq_num_res);\n\n        // The initial SN at TX side\n        ztm->_common._sn_tx_reliable = param->_initial_sn_tx._val._plain._reliable;\n        ztm->_common._sn_tx_best_effort = param->_initial_sn_tx._val._plain._best_effort;\n\n        // Initialize peer list\n        ztm->_peers = _z_transport_peer_multicast_slist_new();\n\n        ztm->_common._lease = Z_TRANSPORT_LEASE;\n\n        // Notifiers\n        ztm->_common._transmitted = false;\n\n        // Transport link for multicast\n        ztm->_common._link = zl;\n    }\n    return ret;\n}\n\nz_result_t _z_multicast_open_peer(_z_transport_multicast_establish_param_t *param, const _z_link_t *zl,\n                                  const _z_id_t *local_zid) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_zint_t initial_sn_tx = 0;\n    z_random_fill(&initial_sn_tx, sizeof(initial_sn_tx));\n    initial_sn_tx = initial_sn_tx & !_z_sn_modulo_mask(Z_SN_RESOLUTION);\n\n    _z_conduit_sn_list_t next_sn;\n    next_sn._is_qos = false;\n    next_sn._val._plain._best_effort = initial_sn_tx;\n    next_sn._val._plain._reliable = initial_sn_tx;\n\n    _z_id_t zid = *local_zid;\n    _z_transport_message_t jsm = _z_t_msg_make_join(Z_WHATAMI_PEER, Z_TRANSPORT_LEASE, zid, next_sn);\n\n    // Encode and send the message\n    _Z_DEBUG(\"Sending Z_JOIN message\");\n    switch (zl->_cap._transport) {\n        case Z_LINK_CAP_TRANSPORT_MULTICAST:\n            ret = _z_link_send_t_msg(zl, &jsm, NULL);\n            break;\n        case Z_LINK_CAP_TRANSPORT_RAWETH:\n            ret = _z_raweth_link_send_t_msg(zl, &jsm);\n            break;\n        default:\n            _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    _z_t_msg_clear(&jsm);\n\n    if (ret == _Z_RES_OK) {\n        param->_seq_num_res = jsm._body._join._seq_num_res;\n        param->_initial_sn_tx = next_sn;\n    }\n    return ret;\n}\n\nz_result_t _z_multicast_open_client(_z_transport_multicast_establish_param_t *param, const _z_link_t *zl,\n                                    const _z_id_t *local_zid) {\n    _ZP_UNUSED(param);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(local_zid);\n    _Z_ERROR_LOG(_Z_ERR_CONFIG_UNSUPPORTED_CLIENT_MULTICAST);\n    z_result_t ret = _Z_ERR_CONFIG_UNSUPPORTED_CLIENT_MULTICAST;\n    // @TODO: not implemented\n    return ret;\n}\n\nz_result_t _z_multicast_send_close(_z_transport_multicast_t *ztm, uint8_t reason, bool link_only) {\n    z_result_t ret = _Z_RES_OK;\n    // Send and clear message\n    _z_transport_message_t cm = _z_t_msg_make_close(reason, link_only);\n    ret = ztm->_send_f(&ztm->_common, &cm);\n    _z_t_msg_clear(&cm);\n    return ret;\n}\n\nz_result_t _z_multicast_transport_close(_z_transport_multicast_t *ztm, uint8_t reason) {\n    return _z_multicast_send_close(ztm, reason, false);\n}\n\nvoid _z_multicast_transport_clear(_z_transport_multicast_t *ztm) {\n    _z_transport_peer_multicast_slist_free(&ztm->_peers);\n    _z_transport_common_clear(\n        &ztm->_common);  // free common in the very end, as peers might access the link data in common while being freed\n    _z_slice_clear(&ztm->_zbuf_addr);\n}\n\n#else\n\nz_result_t _z_multicast_transport_create(_z_transport_t *zt, _z_link_t *zl,\n                                         _z_transport_multicast_establish_param_t *param) {\n    _ZP_UNUSED(zt);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(param);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_multicast_open_peer(_z_transport_multicast_establish_param_t *param, const _z_link_t *zl,\n                                  const _z_id_t *local_zid) {\n    _ZP_UNUSED(param);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(local_zid);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_multicast_open_client(_z_transport_multicast_establish_param_t *param, const _z_link_t *zl,\n                                    const _z_id_t *local_zid) {\n    _ZP_UNUSED(param);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(local_zid);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_multicast_send_close(_z_transport_multicast_t *ztm, uint8_t reason, bool link_only) {\n    _ZP_UNUSED(ztm);\n    _ZP_UNUSED(reason);\n    _ZP_UNUSED(link_only);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_multicast_transport_close(_z_transport_multicast_t *ztm, uint8_t reason) {\n    _ZP_UNUSED(ztm);\n    _ZP_UNUSED(reason);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nvoid _z_multicast_transport_clear(_z_transport_multicast_t *ztm) { _ZP_UNUSED(ztm); }\n#endif  // Z_FEATURE_MULTICAST_TRANSPORT == 1 || Z_FEATURE_RAWETH_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/multicast.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/transport/multicast.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/transport/common/lease.h\"\n#include \"zenoh-pico/transport/common/read.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/multicast/rx.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/uuid.h\"\n\n#if Z_FEATURE_MULTICAST_TRANSPORT == 1\nvoid _zp_multicast_fetch_zid(const _z_transport_t *zt, _z_closure_zid_t *callback) {\n    void *ctx = callback->context;\n    _z_transport_peer_multicast_slist_t *l = zt->_transport._multicast._peers;\n    for (; l != NULL; l = _z_transport_peer_multicast_slist_next(l)) {\n        _z_transport_peer_multicast_t *val = _z_transport_peer_multicast_slist_value(l);\n        z_id_t id = val->common._remote_zid;\n\n        callback->call(&id, ctx);\n    }\n}\n\nvoid _zp_multicast_info_session(const _z_transport_t *zt, _z_config_t *ps) {\n    _z_transport_peer_multicast_slist_t *xs = zt->_transport._multicast._peers;\n    while (xs != NULL) {\n        _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(xs);\n        _z_string_t remote_zid_str = _z_id_to_string(&peer->common._remote_zid);\n        _zp_config_insert_string(ps, Z_INFO_PEER_PID_KEY, &remote_zid_str);\n        _z_string_clear(&remote_zid_str);\n\n        xs = _z_transport_peer_multicast_slist_next(xs);\n    }\n}\n\n#else\nvoid _zp_multicast_fetch_zid(const _z_transport_t *zt, _z_closure_zid_t *callback) {\n    _ZP_UNUSED(zt);\n    _ZP_UNUSED(callback);\n}\n\nvoid _zp_multicast_info_session(const _z_transport_t *zt, _z_config_t *ps) {\n    _ZP_UNUSED(zt);\n    _ZP_UNUSED(ps);\n}\n#endif  // Z_FEATURE_MULTICAST_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/peer.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#if Z_FEATURE_LINK_TLS == 1\n#include \"zenoh-pico/link/transport/tls_stream.h\"\n#endif\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic z_result_t _z_transport_make_endpoint(const _z_string_t *protocol, const char *address, _z_string_t *out) {\n    _z_locator_t locator;\n\n    *out = _z_string_null();\n    if (address == NULL || address[0] == '\\0') {\n        _Z_ERROR_RETURN(_Z_ERR_INVALID);\n    }\n\n    _z_locator_init(&locator);\n    if (protocol != NULL && _z_string_check(protocol)) {\n        locator._protocol = _z_string_alias(*protocol);\n    } else {\n        locator._protocol = _z_string_alias_str(\"tcp\");\n    }\n    locator._address = _z_string_alias_str(address);\n\n    *out = _z_locator_to_string(&locator);\n    _z_locator_clear(&locator);\n    if (!_z_string_check(out)) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n#endif\n\nvoid _z_transport_peer_common_clear(_z_transport_peer_common_t *src) {\n#if Z_FEATURE_CONNECTIVITY == 1\n    _z_string_clear(&src->_link_src);\n    _z_string_clear(&src->_link_dst);\n#endif\n#if Z_FEATURE_FRAGMENTATION == 1\n    _z_wbuf_clear(&src->_dbuf_reliable);\n    _z_wbuf_clear(&src->_dbuf_best_effort);\n#endif\n    src->_remote_zid = _z_id_empty();\n    _z_resource_slist_free(&src->_remote_resources);\n}\nvoid _z_transport_peer_common_copy(_z_transport_peer_common_t *dst, const _z_transport_peer_common_t *src) {\n#if Z_FEATURE_CONNECTIVITY == 1\n    dst->_link_src = _z_string_null();\n    dst->_link_dst = _z_string_null();\n    (void)_z_string_copy(&dst->_link_src, &src->_link_src);\n    if (_z_string_copy(&dst->_link_dst, &src->_link_dst) != _Z_RES_OK) {\n        _z_string_clear(&dst->_link_src);\n    }\n#endif\n#if Z_FEATURE_FRAGMENTATION == 1\n    dst->_state_reliable = src->_state_reliable;\n    dst->_state_best_effort = src->_state_best_effort;\n    _z_wbuf_copy(&dst->_dbuf_reliable, &src->_dbuf_reliable);\n    _z_wbuf_copy(&dst->_dbuf_best_effort, &src->_dbuf_best_effort);\n    dst->_patch = src->_patch;\n#endif\n    dst->_remote_resources = NULL;\n    dst->_received = src->_received;\n    dst->_remote_zid = src->_remote_zid;\n    dst->_remote_whatami = src->_remote_whatami;\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1\nvoid _z_connectivity_peer_event_data_clear(_z_connectivity_peer_event_data_t *event_data) {\n    if (event_data == NULL) {\n        return;\n    }\n    if (event_data->_owns_endpoints) {\n        _z_string_clear(&event_data->_link_src);\n        _z_string_clear(&event_data->_link_dst);\n    }\n    *event_data = (_z_connectivity_peer_event_data_t){0};\n}\n\nvoid _z_connectivity_peer_event_data_copy_from_common(_z_connectivity_peer_event_data_t *dst,\n                                                      const _z_transport_peer_common_t *src) {\n    *dst = (_z_connectivity_peer_event_data_t){0};\n    dst->_link_src = _z_string_null();\n    dst->_link_dst = _z_string_null();\n    dst->_remote_zid = src->_remote_zid;\n    dst->_remote_whatami = src->_remote_whatami;\n    dst->_owns_endpoints = true;\n\n    (void)_z_string_copy(&dst->_link_src, &src->_link_src);\n    if (_z_string_copy(&dst->_link_dst, &src->_link_dst) != _Z_RES_OK) {\n        _z_string_clear(&dst->_link_src);\n    }\n}\n\nvoid _z_connectivity_peer_event_data_alias_from_common(_z_connectivity_peer_event_data_t *dst,\n                                                       const _z_transport_peer_common_t *src) {\n    *dst = (_z_connectivity_peer_event_data_t){\n        ._remote_zid = src->_remote_zid,\n        ._remote_whatami = src->_remote_whatami,\n        ._link_src = src->_link_src,\n        ._link_dst = src->_link_dst,\n        ._owns_endpoints = false,\n    };\n}\n#endif\n\nbool _z_transport_peer_common_eq(const _z_transport_peer_common_t *left, const _z_transport_peer_common_t *right) {\n    return _z_id_eq(&left->_remote_zid, &right->_remote_zid);\n}\n\nvoid _z_transport_peer_multicast_clear(_z_transport_peer_multicast_t *src) {\n    _z_slice_clear(&src->_remote_addr);\n    _z_transport_peer_common_clear(&src->common);\n}\n\nvoid _z_transport_peer_multicast_copy(_z_transport_peer_multicast_t *dst, const _z_transport_peer_multicast_t *src) {\n    dst->_sn_res = src->_sn_res;\n    _z_conduit_sn_list_copy(&dst->_sn_rx_sns, &src->_sn_rx_sns);\n    dst->_lease = src->_lease;\n    _z_slice_copy(&dst->_remote_addr, &src->_remote_addr);\n    _z_transport_peer_common_copy(&dst->common, &src->common);\n}\n\nsize_t _z_transport_peer_multicast_size(const _z_transport_peer_multicast_t *src) {\n    _ZP_UNUSED(src);\n    return sizeof(_z_transport_peer_multicast_t);\n}\n\nbool _z_transport_peer_multicast_eq(const _z_transport_peer_multicast_t *left,\n                                    const _z_transport_peer_multicast_t *right) {\n    return _z_transport_peer_common_eq(&left->common, &right->common);\n}\n\nvoid _z_transport_peer_unicast_clear(_z_transport_peer_unicast_t *src) {\n    _z_zbuf_clear(&src->flow_buff);\n    if (src->_owns_socket) {\n#if Z_FEATURE_LINK_TLS == 1\n        _z_close_tls_socket(&src->_socket);\n#endif\n        _z_socket_close(&src->_socket);\n    }\n    _z_transport_peer_common_clear(&src->common);\n}\n\nvoid _z_transport_peer_unicast_copy(_z_transport_peer_unicast_t *dst, const _z_transport_peer_unicast_t *src) {\n    dst->_sn_rx_reliable = src->_sn_rx_reliable;\n    dst->_sn_rx_best_effort = src->_sn_rx_best_effort;\n    dst->_socket = src->_socket;\n    dst->_owns_socket = false;  // Ownership is not copied\n    dst->_pending = false;\n    dst->flow_state = _Z_FLOW_STATE_INACTIVE;\n    dst->flow_curr_size = 0;\n    dst->flow_buff = _z_zbuf_null();\n    _z_transport_peer_common_copy(&dst->common, &src->common);\n}\n\nsize_t _z_transport_peer_unicast_size(const _z_transport_peer_unicast_t *src) {\n    _ZP_UNUSED(src);\n    return sizeof(_z_transport_peer_unicast_t);\n}\n\nbool _z_transport_peer_unicast_eq(const _z_transport_peer_unicast_t *left, const _z_transport_peer_unicast_t *right) {\n    return _z_transport_peer_common_eq(&left->common, &right->common);\n}\n\nz_result_t _z_transport_peer_unicast_add(_z_transport_unicast_t *ztu, _z_transport_unicast_establish_param_t *param,\n                                         _z_sys_net_socket_t socket, bool owns_socket,\n                                         _z_transport_peer_unicast_t **output_peer) {\n#if Z_FEATURE_CONNECTIVITY == 1\n    bool dispatch_connected_event = output_peer == NULL;\n    _z_session_t *session = _z_transport_common_get_session(&ztu->_common);\n    _z_connectivity_peer_event_data_t peer_event_data = {0};\n    char local_addr[160] = {0};\n    char remote_addr[160] = {0};\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n#endif\n\n    _z_transport_peer_mutex_lock(&ztu->_common);\n    // Create peer\n    ztu->_peers = _z_transport_peer_unicast_slist_push_empty(ztu->_peers);\n    if (ztu->_peers == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Fill peer data\n    _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(ztu->_peers);\n    peer->flow_state = _Z_FLOW_STATE_INACTIVE;\n    peer->flow_curr_size = 0;\n    peer->flow_buff = _z_zbuf_null();\n    peer->_pending = false;\n    peer->_socket = socket;\n    peer->_owns_socket = owns_socket;\n    _z_zint_t initial_sn_rx = _z_sn_decrement(ztu->_common._sn_res, param->_initial_sn_rx);\n    peer->_sn_rx_reliable = initial_sn_rx;\n    peer->_sn_rx_best_effort = initial_sn_rx;\n\n    peer->common._remote_zid = param->_remote_zid;\n    peer->common._remote_whatami = param->_remote_whatami;\n    peer->common._received = true;\n    peer->common._remote_resources = NULL;\n#if Z_FEATURE_CONNECTIVITY == 1\n    peer->common._link_src = _z_string_null();\n    peer->common._link_dst = _z_string_null();\n#endif\n#if Z_FEATURE_FRAGMENTATION == 1\n    peer->common._patch = param->_patch < _Z_CURRENT_PATCH ? param->_patch : _Z_CURRENT_PATCH;\n    peer->common._state_reliable = _Z_DBUF_STATE_NULL;\n    peer->common._state_best_effort = _Z_DBUF_STATE_NULL;\n    peer->common._dbuf_reliable = _z_wbuf_null();\n    peer->common._dbuf_best_effort = _z_wbuf_null();\n#endif\n#if Z_FEATURE_CONNECTIVITY == 1\n    if (ztu->_common._link != NULL) {\n        mtu = ztu->_common._link->_mtu;\n        is_streamed = ztu->_common._link->_cap._flow == Z_LINK_CAP_FLOW_STREAM;\n        is_reliable = ztu->_common._link->_cap._is_reliable;\n        if (_z_socket_get_endpoints(&peer->_socket, local_addr, sizeof(local_addr), remote_addr, sizeof(remote_addr)) ==\n            _Z_RES_OK) {\n            (void)_z_transport_make_endpoint(&ztu->_common._link->_endpoint._locator._protocol, local_addr,\n                                             &peer->common._link_src);\n            (void)_z_transport_make_endpoint(&ztu->_common._link->_endpoint._locator._protocol, remote_addr,\n                                             &peer->common._link_dst);\n        }\n    }\n    if (dispatch_connected_event) {\n        _z_connectivity_peer_event_data_copy_from_common(&peer_event_data, &peer->common);\n    }\n#endif\n    _z_transport_peer_mutex_unlock(&ztu->_common);\n\n    if (output_peer != NULL) {\n        *output_peer = peer;\n    }\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    if (dispatch_connected_event) {\n        _z_connectivity_peer_connected(session, &peer_event_data, false, mtu, is_streamed, is_reliable);\n    }\n    _z_connectivity_peer_event_data_clear(&peer_event_data);\n#endif\n\n    return _Z_RES_OK;\n}\n"
  },
  {
    "path": "src/transport/raweth/link.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/config/raweth.h\"\n#include \"zenoh-pico/link/manager.h\"\n#include \"zenoh-pico/link/transport/raweth.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/system/platform.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n\n#define RAWETH_CFG_TUPLE_SEPARATOR '#'\n#define RAWETH_CFG_LIST_SEPARATOR \",\"\n\n#define RAWETH_CONFIG_ARGC 4\n\n#define RAWETH_CONFIG_IFACE_KEY 0x01\n#define RAWETH_CONFIG_IFACE_STR \"iface\"\n\n#define RAWETH_CONFIG_ETHTYPE_KEY 0x02\n#define RAWETH_CONFIG_ETHTYPE_STR \"ethtype\"\n\n#define RAWETH_CONFIG_MAPPING_KEY 0x03\n#define RAWETH_CONFIG_MAPPING_STR \"mapping\"\n\n#define RAWETH_CONFIG_WHITELIST_KEY 0x04\n#define RAWETH_CONFIG_WHITELIST_STR \"whitelist\"\n\n// Ethtype must be at least 0x600 in network order\n#define RAWETH_ETHTYPE_MIN_VALUE 0x600U\n\n#define RAWETH_CONFIG_MAPPING_BUILD               \\\n    _z_str_intmapping_t args[RAWETH_CONFIG_ARGC]; \\\n    args[0]._key = RAWETH_CONFIG_IFACE_KEY;       \\\n    args[0]._str = RAWETH_CONFIG_IFACE_STR;       \\\n    args[1]._key = RAWETH_CONFIG_ETHTYPE_KEY;     \\\n    args[1]._str = RAWETH_CONFIG_ETHTYPE_STR;     \\\n    args[2]._key = RAWETH_CONFIG_MAPPING_KEY;     \\\n    args[2]._str = RAWETH_CONFIG_MAPPING_STR;     \\\n    args[3]._key = RAWETH_CONFIG_WHITELIST_KEY;   \\\n    args[3]._str = RAWETH_CONFIG_WHITELIST_STR;\n\nconst uint16_t _ZP_RAWETH_DEFAULT_ETHTYPE = 0x72e0;\nconst char *_ZP_RAWETH_DEFAULT_INTERFACE = \"lo\";\nconst uint8_t _ZP_RAWETH_DEFAULT_SMAC[_ZP_MAC_ADDR_LENGTH] = {0x30, 0x03, 0xc8, 0x37, 0x25, 0xa1};\nconst _zp_raweth_mapping_entry_t _ZP_RAWETH_DEFAULT_MAPPING = {\n    ._keyexpr = {0}, ._vlan = 0x0000, ._dmac = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, ._has_vlan = false};\n\nstatic bool _z_valid_iface_raweth(_z_str_intmap_t *config);\nstatic const char *_z_get_iface_raweth(_z_str_intmap_t *config);\nstatic bool _z_valid_ethtype_raweth(_z_str_intmap_t *config);\nstatic long _z_get_ethtype_raweth(_z_str_intmap_t *config);\nstatic size_t _z_valid_mapping_raweth(_z_str_intmap_t *config);\nstatic z_result_t _z_get_mapping_raweth(_z_str_intmap_t *config, _zp_raweth_mapping_array_t *array, size_t size);\nstatic size_t _z_valid_whitelist_raweth(_z_str_intmap_t *config);\nstatic z_result_t _z_get_whitelist_raweth(_z_str_intmap_t *config, _zp_raweth_whitelist_array_t *array, size_t size);\nstatic z_result_t _z_get_mapping_entry(char *entry, _zp_raweth_mapping_entry_t *storage);\nstatic bool _z_valid_mapping_entry(char *entry);\nstatic bool _z_valid_address_raweth_inner(const _z_string_t *address);\nstatic bool _z_valid_address_raweth(const char *address);\nstatic uint8_t *_z_parse_address_raweth(const char *address);\nstatic z_result_t _z_f_link_open_raweth(_z_link_t *self);\nstatic z_result_t _z_f_link_listen_raweth(_z_link_t *self);\nstatic void _z_f_link_close_raweth(_z_link_t *self);\nstatic void _z_f_link_free_raweth(_z_link_t *self);\nstatic size_t _z_f_link_write_raweth(const _z_link_t *self, const uint8_t *ptr, size_t len,\n                                     _z_sys_net_socket_t *socket);\nstatic size_t _z_f_link_write_all_raweth(const _z_link_t *self, const uint8_t *ptr, size_t len);\nstatic size_t _z_f_link_read_raweth(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr);\nstatic size_t _z_f_link_read_exact_raweth(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                          _z_sys_net_socket_t *socket);\nstatic uint16_t _z_get_link_mtu_raweth(void);\n\nstatic bool _z_valid_iface_raweth(_z_str_intmap_t *config) {\n    const char *iface = _z_str_intmap_get(config, RAWETH_CONFIG_IFACE_KEY);\n    return (iface != NULL);\n}\n\nstatic const char *_z_get_iface_raweth(_z_str_intmap_t *config) {\n    return _z_str_intmap_get(config, RAWETH_CONFIG_IFACE_KEY);\n}\n\nstatic bool _z_valid_ethtype_raweth(_z_str_intmap_t *config) {\n    const char *s_ethtype = _z_str_intmap_get(config, RAWETH_CONFIG_ETHTYPE_KEY);\n    if (s_ethtype == NULL) {\n        return false;\n    }\n    long ethtype = strtol(s_ethtype, NULL, 16);\n    return (_z_raweth_htons((uint16_t)ethtype) > RAWETH_ETHTYPE_MIN_VALUE);\n}\n\nstatic long _z_get_ethtype_raweth(_z_str_intmap_t *config) {\n    const char *s_ethtype = _z_str_intmap_get(config, RAWETH_CONFIG_ETHTYPE_KEY);\n    return strtol(s_ethtype, NULL, 16);\n}\n\nstatic size_t _z_valid_mapping_raweth(_z_str_intmap_t *config) {\n    // Retrieve list\n    const char *cfg_str = _z_str_intmap_get(config, RAWETH_CONFIG_MAPPING_KEY);\n    if (cfg_str == NULL) {\n        return 0;\n    }\n    char *s_mapping = _z_str_clone(cfg_str);\n    if (s_mapping == NULL) {\n        return 0;\n    }\n    size_t size = 0;\n    // Parse list\n    const char *delim = RAWETH_CFG_LIST_SEPARATOR;\n    char *entry = strtok(s_mapping, delim);\n    while (entry != NULL) {\n        // Check entry\n        if (!_z_valid_mapping_entry(entry)) {\n            z_free(s_mapping);\n            return 0;\n        }\n        size++;\n        entry = strtok(NULL, delim);\n    }\n    // Clean up\n    z_free(s_mapping);\n    return size;\n}\n\nstatic z_result_t _z_get_mapping_raweth(_z_str_intmap_t *config, _zp_raweth_mapping_array_t *array, size_t size) {\n    // Retrieve data\n    const char *cfg_str = _z_str_intmap_get(config, RAWETH_CONFIG_MAPPING_KEY);\n    if (cfg_str == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    // Copy data\n    char *s_mapping = _z_str_clone(cfg_str);\n    if (s_mapping == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Allocate array\n    *array = _zp_raweth_mapping_array_make(size);\n    if (_zp_raweth_mapping_array_len(array) == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    size_t idx = 0;\n    // Parse list\n    const char *delim = RAWETH_CFG_LIST_SEPARATOR;\n    char *entry = strtok(s_mapping, delim);\n    while ((entry != NULL) && (idx < _zp_raweth_mapping_array_len(array))) {\n        // Copy data into array\n        _Z_CLEAN_RETURN_IF_ERR(_z_get_mapping_entry(entry, _zp_raweth_mapping_array_get(array, idx)),\n                               z_free(s_mapping));\n        // Next iteration\n        idx++;\n        entry = strtok(NULL, delim);\n    }\n    // Clean up\n    z_free(s_mapping);\n    return _Z_RES_OK;\n}\n\nstatic size_t _z_valid_whitelist_raweth(_z_str_intmap_t *config) {\n    // Retrieve data\n    const char *cfg_str = _z_str_intmap_get(config, RAWETH_CONFIG_WHITELIST_KEY);\n    if (cfg_str == NULL) {\n        return 0;\n    }\n    // Copy data\n    char *s_whitelist = _z_str_clone(cfg_str);\n    if (s_whitelist == NULL) {\n        return 0;\n    }\n    // Parse list\n    size_t size = 0;\n    const char *delim = RAWETH_CFG_LIST_SEPARATOR;\n    char *entry = strtok(s_whitelist, delim);\n    while (entry != NULL) {\n        // Check entry\n        if (!_z_valid_address_raweth(entry)) {\n            z_free(s_whitelist);\n            return 0;\n        }\n        size++;\n        entry = strtok(NULL, delim);\n    }\n    // Parse last entry\n\n    // Clean up\n    z_free(s_whitelist);\n    return size;\n}\n\nstatic z_result_t _z_get_whitelist_raweth(_z_str_intmap_t *config, _zp_raweth_whitelist_array_t *array, size_t size) {\n    // Retrieve data\n    const char *cfg_str = _z_str_intmap_get(config, RAWETH_CONFIG_WHITELIST_KEY);\n    if (cfg_str == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    // Copy data\n    char *s_whitelist = _z_str_clone(cfg_str);\n    if (s_whitelist == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Allocate array\n    *array = _zp_raweth_whitelist_array_make(size);\n    if (_zp_raweth_whitelist_array_len(array) == 0) {\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    size_t idx = 0;\n    // Parse list\n    const char *delim = RAWETH_CFG_LIST_SEPARATOR;\n    char *entry = strtok(s_whitelist, delim);\n    while ((entry != NULL) && (idx < _zp_raweth_whitelist_array_len(array))) {\n        // Convert address from string to int array\n        uint8_t *addr = _z_parse_address_raweth(entry);\n        if (addr == NULL) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        // Copy address to entry\n        _zp_raweth_whitelist_entry_t *elem = _zp_raweth_whitelist_array_get(array, idx);\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(elem->_mac, addr, _ZP_MAC_ADDR_LENGTH);\n        z_free(addr);\n        // Next iteration\n        idx++;\n        entry = strtok(NULL, delim);\n    }\n    // Clean up\n    z_free(s_whitelist);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_get_mapping_entry(char *entry, _zp_raweth_mapping_entry_t *storage) {\n    // Flawfinder: ignore [CWE-126] - entry is a '\\0'-terminated token produced from a cloned config string.\n    size_t len = strlen(entry);\n    const char *entry_end = &entry[len - (size_t)1];\n\n    // Get first tuple member (keyexpr)\n    char *p_start = &entry[0];\n    char *p_end = strchr(p_start, RAWETH_CFG_TUPLE_SEPARATOR);\n    size_t ke_len = (uintptr_t)p_end - (uintptr_t)p_start;\n    storage->_keyexpr = _z_string_copy_from_substr(p_start, ke_len);\n    if (!_z_string_check(&storage->_keyexpr)) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    // Check second entry (address)\n    p_start = p_end;\n    p_start++;\n    p_end = strchr(p_start, RAWETH_CFG_TUPLE_SEPARATOR);\n    *p_end = '\\0';\n    uint8_t *addr = _z_parse_address_raweth(p_start);\n    // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n    memcpy(storage->_dmac, addr, _ZP_MAC_ADDR_LENGTH);\n    z_free(addr);\n    *p_end = RAWETH_CFG_TUPLE_SEPARATOR;\n\n    // Check optional third entry (vlan id)\n    p_start = p_end;\n    p_start++;\n    if (p_start >= entry_end) {  // No entry\n        storage->_has_vlan = false;\n    } else {\n        storage->_has_vlan = true;\n        storage->_vlan = (uint16_t)strtol(p_start, NULL, 16);\n    }\n    return _Z_RES_OK;\n}\nstatic bool _z_valid_mapping_entry(char *entry) {\n    // Flawfinder: ignore [CWE-126] - entry is a '\\0'-terminated token produced from a cloned config string.\n    size_t len = strlen(entry);\n    const char *entry_end = &entry[len - (size_t)1];\n\n    // Check first tuple member (keyexpr)\n    char *p_start = &entry[0];\n    char *p_end = strchr(p_start, RAWETH_CFG_TUPLE_SEPARATOR);\n    if (p_end == NULL) {\n        return false;\n    }\n    // Check second entry (address)\n    p_start = p_end;\n    p_start++;\n    if (p_start > entry_end) {\n        return false;\n    }\n    p_end = strchr(p_start, RAWETH_CFG_TUPLE_SEPARATOR);\n    if (p_end == NULL) {\n        return false;\n    }\n    *p_end = '\\0';\n    if (!_z_valid_address_raweth(p_start)) {\n        *p_end = RAWETH_CFG_TUPLE_SEPARATOR;\n        return false;\n    }\n    *p_end = RAWETH_CFG_TUPLE_SEPARATOR;\n    return true;\n}\n\nstatic bool _z_valid_address_raweth_inner(const _z_string_t *address) {\n    // Check if the string has the correct length\n    size_t len = _z_string_len(address);\n    const char *str_data = _z_string_data(address);\n    if (len != 17) {  // 6 pairs of hexadecimal digits and 5 colons\n        return false;\n    }\n    // Check if the colons are at the correct positions\n    for (size_t i = 2; i < len; i += 3) {\n        if (str_data[i] != ':') {\n            return false;\n        }\n    }\n    // Check if each character is a valid hexadecimal digit\n    for (size_t i = 0; i < len; ++i) {\n        if (i % 3 != 2) {\n            char c = str_data[i];\n            if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\nstatic bool _z_valid_address_raweth(const char *address) {\n    _z_string_t addr_str = _z_string_alias_str(address);\n    return _z_valid_address_raweth_inner(&addr_str);\n}\n\nstatic uint8_t *_z_parse_address_raweth(const char *address) {\n    // Allocate data\n    uint8_t *ret = (uint8_t *)z_malloc(_ZP_MAC_ADDR_LENGTH);\n    if (ret == NULL) {\n        return ret;\n    }\n    for (size_t i = 0; i < _ZP_MAC_ADDR_LENGTH; ++i) {\n        // Flawfinder: ignore [CWE-120] - fixed 2-digit hex byte plus explicit terminator.\n        char byte_string[3] = {address[i * 3], address[(i * 3) + 1], '\\0'};\n        ret[i] = (uint8_t)strtol(byte_string, NULL, 16);\n    }\n    return ret;\n}\n\nstatic z_result_t _z_f_link_open_raweth(_z_link_t *self) {\n    // Init arrays\n    self->_socket._raweth._mapping = _zp_raweth_mapping_array_empty();\n    self->_socket._raweth._whitelist = _zp_raweth_whitelist_array_empty();\n    // Init socket smac\n    if (_z_valid_address_raweth_inner(&self->_endpoint._locator._address)) {\n        uint8_t *addr = _z_parse_address_raweth(_z_string_data(&self->_endpoint._locator._address));\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(self->_socket._raweth._smac, addr, _ZP_MAC_ADDR_LENGTH);\n        z_free(addr);\n    } else {\n        _Z_DEBUG(\"Invalid locator source mac addr, using default value.\");\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(self->_socket._raweth._smac, _ZP_RAWETH_DEFAULT_SMAC, _ZP_MAC_ADDR_LENGTH);\n    }\n    // Init socket interface\n    if (_z_valid_iface_raweth(&self->_endpoint._config)) {\n        self->_socket._raweth._interface = _z_get_iface_raweth(&self->_endpoint._config);\n    } else {\n        _Z_DEBUG(\"Invalid locator interface, using default value %s\", _ZP_RAWETH_DEFAULT_INTERFACE);\n        self->_socket._raweth._interface = _ZP_RAWETH_DEFAULT_INTERFACE;\n    }\n    // Init socket ethtype\n    if (_z_valid_ethtype_raweth(&self->_endpoint._config)) {\n        self->_socket._raweth._ethtype = (uint16_t)_z_get_ethtype_raweth(&self->_endpoint._config);\n    } else {\n        _Z_DEBUG(\"Invalid locator ethtype, using default value 0x%04x\", _ZP_RAWETH_DEFAULT_ETHTYPE);\n        self->_socket._raweth._ethtype = _ZP_RAWETH_DEFAULT_ETHTYPE;\n    }\n    // Init socket mapping\n    size_t size = _z_valid_mapping_raweth(&self->_endpoint._config);\n    if (size != (size_t)0) {\n        _Z_RETURN_IF_ERR(_z_get_mapping_raweth(&self->_endpoint._config, &self->_socket._raweth._mapping, size));\n    } else {\n        _Z_DEBUG(\"Invalid locator mapping, using default value.\");\n        self->_socket._raweth._mapping = _zp_raweth_mapping_array_make(1);\n        if (_zp_raweth_mapping_array_len(&self->_socket._raweth._mapping) == 0) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        _zp_raweth_mapping_entry_t *entry = _zp_raweth_mapping_array_get(&self->_socket._raweth._mapping, 0);\n        *entry = _ZP_RAWETH_DEFAULT_MAPPING;\n    }\n    // Init socket whitelist\n    size = _z_valid_whitelist_raweth(&self->_endpoint._config);\n    if (size != (size_t)0) {\n        _Z_RETURN_IF_ERR(_z_get_whitelist_raweth(&self->_endpoint._config, &self->_socket._raweth._whitelist, size));\n    } else {\n        _Z_DEBUG(\"Invalid locator whitelist, filtering deactivated.\");\n    }\n    // Open raweth link\n    return _z_open_raweth(&self->_socket._raweth._sock, self->_socket._raweth._interface);\n}\n\nstatic z_result_t _z_f_link_listen_raweth(_z_link_t *self) { return _z_f_link_open_raweth(self); }\n\nstatic void _z_f_link_close_raweth(_z_link_t *self) {\n    // Close connection\n    _z_close_raweth(&self->_socket._raweth._sock);\n    // Clear config\n    _zp_raweth_mapping_array_clear(&self->_socket._raweth._mapping);\n    if (_zp_raweth_whitelist_array_len(&self->_socket._raweth._whitelist) != 0) {\n        _zp_raweth_whitelist_array_clear(&self->_socket._raweth._whitelist);\n    }\n}\n\nstatic void _z_f_link_free_raweth(_z_link_t *self) { _ZP_UNUSED(self); }\n\nstatic size_t _z_f_link_write_raweth(const _z_link_t *self, const uint8_t *ptr, size_t len,\n                                     _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(self);\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(len);\n    _ZP_UNUSED(socket);\n    return SIZE_MAX;\n}\n\nstatic size_t _z_f_link_write_all_raweth(const _z_link_t *self, const uint8_t *ptr, size_t len) {\n    _ZP_UNUSED(self);\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(len);\n    return SIZE_MAX;\n}\n\nstatic size_t _z_f_link_read_raweth(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr) {\n    _ZP_UNUSED(self);\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(len);\n    _ZP_UNUSED(addr);\n    return SIZE_MAX;\n}\n\nstatic size_t _z_f_link_read_exact_raweth(const _z_link_t *self, uint8_t *ptr, size_t len, _z_slice_t *addr,\n                                          _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(self);\n    _ZP_UNUSED(ptr);\n    _ZP_UNUSED(len);\n    _ZP_UNUSED(addr);\n    _ZP_UNUSED(socket);\n    return SIZE_MAX;\n}\n\nstatic uint16_t _z_get_link_mtu_raweth(void) { return _ZP_MAX_ETH_FRAME_SIZE; }\n\nz_result_t _z_endpoint_raweth_valid(_z_endpoint_t *endpoint) {\n    z_result_t ret = _Z_RES_OK;\n\n    // Check the root\n    _z_string_t str_cmp = _z_string_alias_str(RAWETH_SCHEMA);\n    if (!_z_string_equals(&endpoint->_locator._protocol, &str_cmp)) {\n        _Z_ERROR_LOG(_Z_ERR_CONFIG_LOCATOR_INVALID);\n        ret = _Z_ERR_CONFIG_LOCATOR_INVALID;\n    }\n    return ret;\n}\n\nz_result_t _z_new_link_raweth(_z_link_t *zl, _z_endpoint_t endpoint) {\n    z_result_t ret = _Z_RES_OK;\n    zl->_type = _Z_LINK_TYPE_RAWETH;\n    zl->_cap._transport = Z_LINK_CAP_TRANSPORT_RAWETH;\n    zl->_cap._is_reliable = false;\n    zl->_mtu = _z_get_link_mtu_raweth();\n\n    zl->_endpoint = endpoint;\n\n    // Init socket\n    memset(&zl->_socket._raweth, 0, sizeof(zl->_socket._raweth));\n\n    zl->_open_f = _z_f_link_open_raweth;\n    zl->_listen_f = _z_f_link_listen_raweth;\n    zl->_close_f = _z_f_link_close_raweth;\n    zl->_free_f = _z_f_link_free_raweth;\n\n    zl->_write_f = _z_f_link_write_raweth;\n    zl->_write_all_f = _z_f_link_write_all_raweth;\n    zl->_read_f = _z_f_link_read_raweth;\n    zl->_read_exact_f = _z_f_link_read_exact_raweth;\n    zl->_read_socket_f = _z_noop_link_read_socket;\n\n    return ret;\n}\n\nsize_t _z_raweth_config_strlen(const _z_str_intmap_t *s) {\n    RAWETH_CONFIG_MAPPING_BUILD\n    return _z_str_intmap_strlen(s, RAWETH_CONFIG_ARGC, args);\n}\nchar *_z_raweth_config_to_str(const _z_str_intmap_t *s) {\n    RAWETH_CONFIG_MAPPING_BUILD\n    return _z_str_intmap_to_str(s, RAWETH_CONFIG_ARGC, args);\n}\n\nz_result_t _z_raweth_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    RAWETH_CONFIG_MAPPING_BUILD\n    return _z_str_intmap_from_strn(strint, s, RAWETH_CONFIG_ARGC, args, n);\n}\n\nz_result_t _z_raweth_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    // Flawfinder: ignore [CWE-126] - public from_str() expects a conventional '\\0'-terminated C string.\n    return _z_raweth_config_from_strn(strint, s, strlen(s));\n}\n\n#else\nz_result_t _z_endpoint_raweth_valid(_z_endpoint_t *endpoint) {\n    _ZP_UNUSED(endpoint);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_new_link_raweth(_z_link_t *zl, _z_endpoint_t endpoint) {\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(endpoint);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nsize_t _z_raweth_config_strlen(const _z_str_intmap_t *s) {\n    _ZP_UNUSED(s);\n    return 0;\n}\n\nchar *_z_raweth_config_to_str(const _z_str_intmap_t *s) {\n    _ZP_UNUSED(s);\n    return NULL;\n}\n\nz_result_t _z_raweth_config_from_strn(_z_str_intmap_t *strint, const char *s, size_t n) {\n    _ZP_UNUSED(strint);\n    _ZP_UNUSED(s);\n    _ZP_UNUSED(n);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_raweth_config_from_str(_z_str_intmap_t *strint, const char *s) {\n    _ZP_UNUSED(strint);\n    _ZP_UNUSED(s);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif\n"
  },
  {
    "path": "src/transport/raweth/read.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/raweth/read.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/transport/multicast/rx.h\"\n#include \"zenoh-pico/transport/raweth/rx.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n\nz_result_t _zp_raweth_read(_z_transport_multicast_t *ztm, bool single_read) {\n    z_result_t ret = _Z_RES_OK;\n    _ZP_UNUSED(single_read);\n\n    _z_slice_t addr;\n    _z_transport_message_t t_msg;\n    ret = _z_raweth_recv_t_msg(ztm, &t_msg, &addr);\n    if (ret == _Z_RES_OK) {\n        ret = _z_multicast_handle_transport_message(ztm, &t_msg, &addr);\n        _z_t_msg_clear(&t_msg);\n    }\n    _z_slice_clear(&addr);\n    ret = _z_raweth_update_rx_buff(ztm);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Failed to allocate rx buffer\");\n    }\n    return ret;\n}\n\n_z_fut_fn_result_t _zp_raweth_read_task_fn(void *ztm_arg, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n    _z_transport_multicast_t *ztm = (_z_transport_multicast_t *)ztm_arg;\n\n    if (ztm->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztm->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    _z_transport_message_t t_msg;\n    _z_slice_t addr = _z_slice_alias_buf(NULL, 0);\n\n    // Read message from link\n    z_result_t ret = _z_raweth_recv_t_msg(ztm, &t_msg, &addr);\n    switch (ret) {\n        case _Z_RES_OK:\n            // Process message\n            break;\n        case _Z_ERR_TRANSPORT_RX_FAILED:\n            // Drop message\n            _z_slice_clear(&addr);\n            return _z_fut_fn_result_continue();\n        default:\n            // Drop message & stop task\n            _Z_ERROR(\"Connection closed due to malformed message: %d\", ret);\n            _z_slice_clear(&addr);\n            return _z_fut_fn_result_ready();\n    }\n    // Process message\n    ret = _z_multicast_handle_transport_message(ztm, &t_msg, &addr);\n    if (ret != _Z_RES_OK) {\n        _Z_ERROR(\"Connection closed due to message processing error: %d\", ret);\n        _z_slice_clear(&addr);\n        return _z_fut_fn_result_ready();\n    }\n    _z_t_msg_clear(&t_msg);\n    _z_slice_clear(&addr);\n    if (_z_raweth_update_rx_buff(ztm) != _Z_RES_OK) {\n        _Z_ERROR(\"Connection closed due to lack of memory to allocate rx buffer\");\n        return _z_fut_fn_result_ready();\n    }\n    return _z_fut_fn_result_continue();\n}\n#endif\n"
  },
  {
    "path": "src/transport/raweth/rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// #include \"zenoh-pico/transport/link/rx.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n\nstatic size_t _z_raweth_link_recv_zbuf(const _z_link_t *link, _z_zbuf_t *zbf, _z_slice_t *addr) {\n    uint8_t *buff = _z_zbuf_get_wptr(zbf);\n    size_t rb = _z_receive_raweth(&link->_socket._raweth._sock, buff, _z_zbuf_space_left(zbf), addr,\n                                  &link->_socket._raweth._whitelist);\n    // Check validity\n    if ((rb == SIZE_MAX) || (rb < sizeof(_zp_eth_header_t))) {\n        return SIZE_MAX;\n    }\n    // Check if header has vlan\n    bool has_vlan = false;\n    _zp_eth_header_t *header = (_zp_eth_header_t *)buff;\n    if (header->ethtype == _ZP_ETH_TYPE_VLAN) {\n        has_vlan = true;\n    }\n    // Check validity\n    if (has_vlan && (rb < sizeof(_zp_eth_vlan_header_t))) {\n        return SIZE_MAX;\n    }\n    size_t data_length = 0;\n    if (has_vlan) {\n        _zp_eth_vlan_header_t *vlan_header = (_zp_eth_vlan_header_t *)buff;\n        // Retrieve data length\n        data_length = _z_raweth_ntohs(vlan_header->data_length);\n        if (rb < (data_length + sizeof(_zp_eth_vlan_header_t))) {\n            // Invalid data_length\n            return SIZE_MAX;\n        }\n        // Skip header\n        _z_zbuf_set_wpos(zbf, _z_zbuf_get_wpos(zbf) + sizeof(_zp_eth_vlan_header_t) + data_length);\n        _z_zbuf_set_rpos(zbf, _z_zbuf_get_rpos(zbf) + sizeof(_zp_eth_vlan_header_t));\n    } else {\n        header = (_zp_eth_header_t *)buff;\n        // Retrieve data length\n        data_length = _z_raweth_ntohs(header->data_length);\n        if (rb < (data_length + sizeof(_zp_eth_header_t))) {\n            // Invalid data_length\n            return SIZE_MAX;\n        }\n        // Skip header\n        _z_zbuf_set_wpos(zbf, _z_zbuf_get_wpos(zbf) + sizeof(_zp_eth_header_t) + data_length);\n        _z_zbuf_set_rpos(zbf, _z_zbuf_get_rpos(zbf) + sizeof(_zp_eth_header_t));\n    }\n    return data_length;\n}\n\n/*------------------ Reception helper ------------------*/\nz_result_t _z_raweth_recv_t_msg_na(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg, _z_slice_t *addr) {\n    _Z_DEBUG(\">> recv session msg\");\n    z_result_t ret = _Z_RES_OK;\n\n    // Prepare the buffer\n    _z_zbuf_reset(&ztm->_common._zbuf);\n\n    switch (ztm->_common._link->_cap._flow) {\n        // Datagram capable links\n        case Z_LINK_CAP_FLOW_DATAGRAM: {\n            _z_zbuf_compact(&ztm->_common._zbuf);\n            // Read from link\n            size_t to_read = _z_raweth_link_recv_zbuf(ztm->_common._link, &ztm->_common._zbuf, addr);\n            if (to_read == SIZE_MAX) {\n                _Z_ERROR_LOG(_Z_ERR_TRANSPORT_RX_FAILED);\n                ret = _Z_ERR_TRANSPORT_RX_FAILED;\n            }\n            break;\n        }\n        default:\n            _Z_ERROR_LOG(_Z_ERR_GENERIC);\n            ret = _Z_ERR_GENERIC;\n            break;\n    }\n    // Decode message\n    if (ret == _Z_RES_OK) {\n        _Z_DEBUG(\">> \\t transport_message_decode: %ju\", (uintmax_t)_z_zbuf_len(&ztm->_common._zbuf));\n        ret = _z_transport_message_decode(t_msg, &ztm->_common._zbuf);\n    }\n    return ret;\n}\n\nz_result_t _z_raweth_recv_t_msg(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg, _z_slice_t *addr) {\n    return _z_raweth_recv_t_msg_na(ztm, t_msg, addr);\n}\n\nz_result_t _z_raweth_update_rx_buff(_z_transport_multicast_t *ztm) {\n    // Check if user or defragment buffer took ownership of buffer\n    if (_z_zbuf_get_ref_count(&ztm->_common._zbuf) != 1) {\n        // Allocate a new buffer\n        _z_zbuf_t new_zbuf = _z_zbuf_make(Z_BATCH_MULTICAST_SIZE);\n        if (_z_zbuf_capacity(&new_zbuf) != Z_BATCH_MULTICAST_SIZE) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        // Recopy leftover bytes\n        size_t leftovers = _z_zbuf_len(&ztm->_common._zbuf);\n        if (leftovers > 0) {\n            _z_zbuf_copy_bytes(&new_zbuf, &ztm->_common._zbuf);\n        }\n        // Drop buffer & update\n        _z_zbuf_clear(&ztm->_common._zbuf);\n        ztm->_common._zbuf = new_zbuf;\n    }\n    return _Z_RES_OK;\n}\n\n#else\nz_result_t _z_raweth_recv_t_msg(_z_transport_multicast_t *ztm, _z_transport_message_t *t_msg, _z_slice_t *addr) {\n    _ZP_UNUSED(ztm);\n    _ZP_UNUSED(t_msg);\n    _ZP_UNUSED(addr);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif  // Z_FEATURE_RAWETH_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/raweth/tx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n// #include \"zenoh-pico/transport/link/tx.h\"\n\n#include \"zenoh-pico/transport/common/tx.h\"\n\n#include <string.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/transport/raweth.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/transport/multicast/transport.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_RAWETH_TRANSPORT == 1\n\nstatic int _zp_raweth_find_map_entry(const _z_keyexpr_t *keyexpr, _z_raweth_socket_t *sock) {\n    for (size_t i = 0; i < _zp_raweth_mapping_array_len(&sock->_mapping); i++) {\n        // Find matching keyexpr\n        const _zp_raweth_mapping_entry_t *entry = _zp_raweth_mapping_array_get(&sock->_mapping, i);\n        _z_keyexpr_t entry_ke = _z_keyexpr_alias_from_string(&entry->_keyexpr);\n        if (!z_keyexpr_intersects(keyexpr, &entry_ke)) {\n            continue;\n        }\n        return (int)i;\n    }\n    return -1;\n}\n\nstatic z_result_t _zp_raweth_set_socket(const _z_keyexpr_t *keyexpr, _z_raweth_socket_t *sock) {\n    z_result_t ret = _Z_RES_OK;\n\n    if (_zp_raweth_mapping_array_len(&sock->_mapping) < 1) {\n        _Z_ERROR_RETURN(_Z_ERR_GENERIC);\n    }\n    if (keyexpr == NULL) {\n        // Store default value into socket\n        const _zp_raweth_mapping_entry_t *entry = _zp_raweth_mapping_array_get(&sock->_mapping, 0);\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(sock->_dmac, entry->_dmac, _ZP_MAC_ADDR_LENGTH);\n        sock->_has_vlan = entry->_has_vlan;\n        if (sock->_has_vlan) {\n            sock->_vlan = entry->_vlan;\n        }\n    } else {\n        // Find config entry (linear)\n        int idx = _zp_raweth_find_map_entry(keyexpr, sock);\n        // Key not found case\n        if (idx < 0) {\n            idx = 0;  // Set to default entry\n            _Z_DEBUG(\"Key '%.*s' wasn't found in config mapping, sending to default address\",\n                     (int)_z_string_len(&keyexpr), _z_string_data(&keyexpr));\n        }\n        // Store data into socket\n        const _zp_raweth_mapping_entry_t *entry = _zp_raweth_mapping_array_get(&sock->_mapping, (size_t)idx);\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(sock->_dmac, entry->_dmac, _ZP_MAC_ADDR_LENGTH);\n        sock->_has_vlan = entry->_has_vlan;\n        if (sock->_has_vlan) {\n            sock->_vlan = entry->_vlan;\n        }\n    }\n    return ret;\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - ztm->_mutex_inner\n */\nstatic _z_zint_t __unsafe_z_raweth_get_sn(_z_transport_multicast_t *ztm, z_reliability_t reliability) {\n    _z_zint_t sn;\n    if (reliability == Z_RELIABILITY_RELIABLE) {\n        sn = ztm->_common._sn_tx_reliable;\n        ztm->_common._sn_tx_reliable = _z_sn_increment(ztm->_common._sn_res, ztm->_common._sn_tx_reliable);\n    } else {\n        sn = ztm->_common._sn_tx_best_effort;\n        ztm->_common._sn_tx_best_effort = _z_sn_increment(ztm->_common._sn_res, ztm->_common._sn_tx_best_effort);\n    }\n    return sn;\n}\n\nstatic void __unsafe_z_raweth_prepare_header(_z_link_t *zl, _z_wbuf_t *wbf) {\n    _z_raweth_socket_t *resocket = &zl->_socket._raweth;\n    // Reserve eth header in buffer\n    if (resocket->_has_vlan) {\n        _z_wbuf_set_wpos(wbf, sizeof(_zp_eth_vlan_header_t));\n    } else {\n        _z_wbuf_set_wpos(wbf, sizeof(_zp_eth_header_t));\n    }\n}\n\n/**\n * This function is unsafe because it operates in potentially concurrent data.\n * Make sure that the following mutexes are locked before calling this function:\n *  - ztm->_mutex_inner\n */\nstatic z_result_t __unsafe_z_raweth_write_header(_z_link_t *zl, _z_wbuf_t *wbf) {\n    _z_raweth_socket_t *resocket = &zl->_socket._raweth;\n    // Save and reset buffer position\n    size_t wpos = _z_wbuf_len(wbf);\n    _z_wbuf_set_wpos(wbf, 0);\n    // Write eth header in buffer\n    if (resocket->_has_vlan) {\n        _zp_eth_vlan_header_t header;\n        // Set header\n        memset(&header, 0, sizeof(header));\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(header.dmac, resocket->_dmac, _ZP_MAC_ADDR_LENGTH);\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(header.smac, resocket->_smac, _ZP_MAC_ADDR_LENGTH);\n        header.vlan_type = _ZP_ETH_TYPE_VLAN;\n        header.tag = resocket->_vlan;\n        header.ethtype = resocket->_ethtype;\n        header.data_length = _z_raweth_htons((uint16_t)(wpos - sizeof(header)));\n        // Write header\n        _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, (uint8_t *)&header, 0, sizeof(header)));\n    } else {\n        _zp_eth_header_t header;\n        // Set header\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(header.dmac, resocket->_dmac, _ZP_MAC_ADDR_LENGTH);\n        // Flawfinder: ignore [CWE-120] - fixed-size MAC copy, both operands are _ZP_MAC_ADDR_LENGTH bytes.\n        memcpy(header.smac, resocket->_smac, _ZP_MAC_ADDR_LENGTH);\n        header.ethtype = resocket->_ethtype;\n        header.data_length = _z_raweth_htons((uint16_t)(wpos - sizeof(header)));\n        // Write header\n        _Z_RETURN_IF_ERR(_z_wbuf_write_bytes(wbf, (uint8_t *)&header, 0, sizeof(header)));\n    }\n    // Restore wpos\n    _z_wbuf_set_wpos(wbf, wpos);\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_raweth_link_send_wbuf(const _z_link_t *zl, const _z_wbuf_t *wbf) {\n    z_result_t ret = _Z_RES_OK;\n    for (size_t i = 0; (i < _z_wbuf_len_iosli(wbf)) && (ret == _Z_RES_OK); i++) {\n        _z_slice_t bs = _z_iosli_to_bytes(_z_wbuf_get_iosli(wbf, i));\n        size_t n = bs.len;\n\n        do {\n            // Retrieve addr from config + vlan tag above (locator)\n            size_t wb = _z_send_raweth(&zl->_socket._raweth._sock, bs.start, n);  // Unix\n            if (wb == SIZE_MAX) {\n                _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_TX_FAILED);\n            }\n            n = n - wb;\n            bs.start = bs.start + (bs.len - n);\n        } while (n > (size_t)0);\n    }\n    return ret;\n}\n\nz_result_t _z_raweth_link_send_t_msg(const _z_link_t *zl, const _z_transport_message_t *t_msg) {\n    z_result_t ret = _Z_RES_OK;\n\n    // Create and prepare the buffer to serialize the message on\n    uint16_t mtu = (zl->_mtu < Z_BATCH_UNICAST_SIZE) ? zl->_mtu : Z_BATCH_UNICAST_SIZE;\n    _z_wbuf_t wbf = _z_wbuf_make(mtu, false);\n    if (_z_wbuf_capacity(&wbf) != mtu) {\n        _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    // Discard const qualifier\n    _z_link_t *mzl = (_z_link_t *)zl;\n    // Set socket info\n    _Z_RETURN_IF_ERR(_zp_raweth_set_socket(NULL, &mzl->_socket._raweth));\n    // Prepare buff\n    __unsafe_z_raweth_prepare_header(mzl, &wbf);\n    // Encode the session message\n    _Z_RETURN_IF_ERR(_z_transport_message_encode(&wbf, t_msg));\n    // Write the message header\n    _Z_RETURN_IF_ERR(__unsafe_z_raweth_write_header(mzl, &wbf));\n    // Send the wbuf on the socket\n    ret = _z_raweth_link_send_wbuf(zl, &wbf);\n    _z_wbuf_clear(&wbf);\n\n    return ret;\n}\n\nz_result_t _z_raweth_send_t_msg(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg) {\n    z_result_t ret = _Z_RES_OK;\n    _Z_DEBUG(\">> send session message\");\n\n    _z_transport_tx_mutex_lock(ztc, true);\n    // Reset wbuf\n    _z_wbuf_reset(&ztc->_wbuf);\n    // Set socket info\n    _Z_CLEAN_RETURN_IF_ERR(_zp_raweth_set_socket(NULL, &ztc->_link->_socket._raweth),\n                           _z_transport_tx_mutex_unlock(ztc));\n    // Prepare buff\n    __unsafe_z_raweth_prepare_header(ztc->_link, &ztc->_wbuf);\n    // Encode the session message\n    _Z_CLEAN_RETURN_IF_ERR(_z_transport_message_encode(&ztc->_wbuf, t_msg), _z_transport_tx_mutex_unlock(ztc));\n    // Write the message header\n    _Z_CLEAN_RETURN_IF_ERR(__unsafe_z_raweth_write_header(ztc->_link, &ztc->_wbuf), _z_transport_tx_mutex_unlock(ztc));\n    // Send the wbuf on the socket\n    _Z_CLEAN_RETURN_IF_ERR(_z_raweth_link_send_wbuf(ztc->_link, &ztc->_wbuf), _z_transport_tx_mutex_unlock(ztc));\n    // Mark the session that we have transmitted data\n    ztc->_transmitted = true;\n    _z_transport_tx_mutex_unlock(ztc);\n    return ret;\n}\n\nz_result_t _z_raweth_send_n_msg(_z_session_t *zn, const _z_network_message_t *n_msg, z_reliability_t reliability,\n                                z_congestion_control_t cong_ctrl) {\n    z_result_t ret = _Z_RES_OK;\n    _z_transport_multicast_t *ztm = &zn->_tp._transport._raweth;\n    _Z_DEBUG(\">> send network message\");\n\n    // Acquire the lock and drop the message if needed\n    ret = _z_transport_tx_mutex_lock(&ztm->_common, cong_ctrl == Z_CONGESTION_CONTROL_BLOCK);\n    if (ret != _Z_RES_OK) {\n        _Z_INFO(\"Dropping zenoh message because of congestion control\");\n        return ret;\n    }\n    const _z_keyexpr_t *keyexpr = NULL;\n    switch (n_msg->_tag) {\n        case _Z_N_PUSH:\n            keyexpr = &n_msg->_body._push._key;\n            break;\n        case _Z_N_REQUEST:\n            keyexpr = &n_msg->_body._request._key;\n            break;\n        case _Z_N_RESPONSE:\n            keyexpr = &n_msg->_body._response._key;\n            break;\n        case _Z_N_RESPONSE_FINAL:\n        case _Z_N_DECLARE:\n        default:\n            break;\n    }\n    // Reset wbuf\n    _z_wbuf_reset(&ztm->_common._wbuf);\n    // Set socket info\n    _Z_CLEAN_RETURN_IF_ERR(_zp_raweth_set_socket(keyexpr, &ztm->_common._link->_socket._raweth),\n                           _z_transport_tx_mutex_unlock(&ztm->_common));\n    // Prepare buff\n    __unsafe_z_raweth_prepare_header(ztm->_common._link, &ztm->_common._wbuf);\n    // Set the frame header\n    _z_zint_t sn = __unsafe_z_raweth_get_sn(ztm, reliability);\n    _z_transport_message_t t_msg = _z_t_msg_make_frame_header(sn, reliability);\n    // Encode the frame header\n    _Z_CLEAN_RETURN_IF_ERR(_z_transport_message_encode(&ztm->_common._wbuf, &t_msg),\n                           _z_transport_tx_mutex_unlock(&ztm->_common));\n    // Encode the network message\n    if (_z_network_message_encode(&ztm->_common._wbuf, n_msg) == _Z_RES_OK) {\n        // Write the eth header\n        _Z_CLEAN_RETURN_IF_ERR(__unsafe_z_raweth_write_header(ztm->_common._link, &ztm->_common._wbuf),\n                               _z_transport_tx_mutex_unlock(&ztm->_common));\n        // Send the wbuf on the socket\n        _Z_CLEAN_RETURN_IF_ERR(_z_raweth_link_send_wbuf(ztm->_common._link, &ztm->_common._wbuf),\n                               _z_transport_tx_mutex_unlock(&ztm->_common));\n        // Mark the session that we have transmitted data\n        ztm->_common._transmitted = true;\n    } else {  // The message does not fit in the current batch, let's fragment it\n#if Z_FEATURE_FRAGMENTATION == 1\n        // Create an expandable wbuf for fragmentation\n        _z_wbuf_t fbf = _z_wbuf_make(_Z_FRAG_BUFF_BASE_SIZE, true);\n        if (_z_wbuf_capacity(&fbf) != _Z_FRAG_BUFF_BASE_SIZE) {\n            _Z_ERROR_LOG(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            _z_transport_tx_mutex_unlock(&ztm->_common);\n            return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n        }\n        // Encode the message on the expandable wbuf\n        _Z_CLEAN_RETURN_IF_ERR(_z_network_message_encode(&fbf, n_msg), _z_transport_tx_mutex_unlock(&ztm->_common));\n        // Fragment and send the message\n        bool is_first = true;\n        while (_z_wbuf_len(&fbf) > 0) {\n            if (is_first) {\n                // Get the fragment sequence number\n                sn = __unsafe_z_raweth_get_sn(ztm, reliability);\n            }\n            // Reset wbuf\n            _z_wbuf_reset(&ztm->_common._wbuf);\n            // Prepare buff\n            __unsafe_z_raweth_prepare_header(ztm->_common._link, &ztm->_common._wbuf);\n            // Serialize one fragment\n            _Z_CLEAN_RETURN_IF_ERR(\n                __unsafe_z_serialize_zenoh_fragment(&ztm->_common._wbuf, &fbf, reliability, sn, is_first),\n                _z_transport_tx_mutex_unlock(&ztm->_common));\n            // Write the eth header\n            _Z_CLEAN_RETURN_IF_ERR(__unsafe_z_raweth_write_header(ztm->_common._link, &ztm->_common._wbuf),\n                                   _z_transport_tx_mutex_unlock(&ztm->_common));\n            // Send the wbuf on the socket\n            _Z_CLEAN_RETURN_IF_ERR(_z_raweth_link_send_wbuf(ztm->_common._link, &ztm->_common._wbuf),\n                                   _z_transport_tx_mutex_unlock(&ztm->_common));\n            // Mark the session that we have transmitted data\n            ztm->_common._transmitted = true;\n            is_first = false;\n        }\n        // Clear the expandable buffer\n        _z_wbuf_clear(&fbf);\n#else\n        _Z_INFO(\"Sending the message required fragmentation feature that is deactivated.\");\n#endif\n    }\n    _z_transport_tx_mutex_unlock(&ztm->_common);\n    return ret;\n}\n\n#else\nz_result_t _z_raweth_link_send_t_msg(const _z_link_t *zl, const _z_transport_message_t *t_msg) {\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(t_msg);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\nz_result_t _z_raweth_send_t_msg(_z_transport_common_t *ztc, const _z_transport_message_t *t_msg) {\n    _ZP_UNUSED(ztc);\n    _ZP_UNUSED(t_msg);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_raweth_send_n_msg(_z_session_t *zn, const _z_network_message_t *n_msg, z_reliability_t reliability,\n                                z_congestion_control_t cong_ctrl) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(n_msg);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(cong_ctrl);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif  // Z_FEATURE_RAWETH_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/transport.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/multicast/transport.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/sleep.h\"\n\nsize_t _z_transport_get_peers_count(_z_transport_t *zt) {\n    size_t count = 0;\n    switch (zt->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            _z_transport_peer_mutex_lock(&zt->_transport._unicast._common);\n            count = _z_transport_peer_unicast_slist_len(zt->_transport._unicast._peers);\n            _z_transport_peer_mutex_unlock(&zt->_transport._unicast._common);\n            return count;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            _z_transport_peer_mutex_lock(&zt->_transport._multicast._common);\n            count = _z_transport_peer_multicast_slist_len(zt->_transport._multicast._peers);\n            _z_transport_peer_mutex_unlock(&zt->_transport._multicast._common);\n            return count;\n        default:\n            return 0;\n    }\n}\n\n_z_transport_common_t *_z_transport_get_common(_z_transport_t *zt) {\n    switch (zt->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            return &zt->_transport._unicast._common;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            return &zt->_transport._multicast._common;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            return &zt->_transport._raweth._common;\n        default:\n            _Z_DEBUG(\"None transport, it should never happens\");\n            return NULL;\n    }\n}\n\nz_result_t _z_send_close(_z_transport_t *zt, uint8_t reason, bool link_only) {\n    z_result_t ret = _Z_RES_OK;\n    // Call transport function\n    switch (zt->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            ret = _z_unicast_send_close(&zt->_transport._unicast, reason, link_only);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            ret = _z_multicast_send_close(&zt->_transport._multicast, reason, link_only);\n            break;\n        default:\n            _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n            ret = _Z_ERR_TRANSPORT_NOT_AVAILABLE;\n            break;\n    }\n    return ret;\n}\n\nz_result_t _z_transport_close(_z_transport_t *zt, uint8_t reason) { return _z_send_close(zt, reason, false); }\n\nvoid _z_transport_clear(_z_transport_t *zt) {\n    switch (zt->_type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            _z_unicast_transport_clear(&zt->_transport._unicast);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            _z_multicast_transport_clear(&zt->_transport._multicast);\n            break;\n        default:\n            return;\n    }\n    _z_transport_get_common(zt)->_state = _Z_TRANSPORT_STATE_CLOSED;\n    zt->_type = _Z_TRANSPORT_NONE;\n}\n\nvoid _z_transport_free(_z_transport_t **zt) {\n    _z_transport_t *ptr = *zt;\n    if (ptr == NULL) {\n        return;\n    }\n    // Clear and free transport\n    _z_transport_clear(ptr);\n    z_free(ptr);\n    *zt = NULL;\n}\n\n#if Z_FEATURE_BATCHING == 1\nz_result_t _z_transport_start_batching(_z_transport_t *zt) {\n    _z_transport_common_t *ztc = _z_transport_get_common(zt);\n    if (ztc == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n    }\n    if (ztc->_batch_state == _Z_BATCHING_ACTIVE) {\n        return _Z_ERR_GENERIC;\n    }\n    ztc->_batch_count = 0;\n    ztc->_batch_state = _Z_BATCHING_ACTIVE;\n\n#if Z_FEATURE_BATCH_TX_MUTEX == 1\n    _z_transport_tx_mutex_lock(ztc, true);\n#endif\n#if Z_FEATURE_BATCH_PEER_MUTEX == 1\n    _z_transport_peer_mutex_lock(ztc);\n#endif\n    return _Z_RES_OK;\n}\n\nz_result_t _z_transport_stop_batching(_z_transport_t *zt) {\n    _z_transport_common_t *ztc = _z_transport_get_common(zt);\n    if (ztc == NULL) {\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n    }\n\n#if Z_FEATURE_BATCH_TX_MUTEX == 1\n    _z_transport_tx_mutex_unlock(ztc);\n#endif\n#if Z_FEATURE_BATCH_PEER_MUTEX == 1\n    _z_transport_peer_mutex_unlock(ztc);\n#endif\n    ztc->_batch_state = _Z_BATCHING_IDLE;\n    return _Z_RES_OK;\n}\n#endif\n\n_z_pending_peers_t _z_pending_peers_null(void) {\n    _z_pending_peers_t pending_peers;\n\n    pending_peers._peers = _z_pending_peer_svec_null();\n    pending_peers._timeout_ms = 0;\n    pending_peers._start = (z_clock_t){0};\n    pending_peers._sleep_ms = _Z_SLEEP_BACKOFF_MIN_MS;\n\n    return pending_peers;\n}\n\nz_result_t _z_pending_peers_copy_from_locators(_z_pending_peers_t *pending_peers, const _z_string_svec_t *locators) {\n    if ((pending_peers == NULL) || (locators == NULL)) {\n        return _Z_ERR_GENERIC;\n    }\n\n    _z_pending_peers_clear(pending_peers);\n\n    size_t len = _z_string_svec_len(locators);\n    if (len == 0) {\n        return _Z_RES_OK;\n    }\n\n    pending_peers->_peers = _z_pending_peer_svec_make(len);\n    if (pending_peers->_peers._val == NULL) {\n        return _Z_ERR_SYSTEM_OUT_OF_MEMORY;\n    }\n\n    for (size_t i = 0; i < len; i++) {\n        _z_pending_peer_t peer = {0};\n        peer._state = _Z_PENDING_PEER_STATE_PENDING;\n        _z_string_t *locator = _z_string_svec_get(locators, i);\n        z_result_t ret = _z_string_copy(&peer._locator, locator);\n        if (ret == _Z_RES_OK) {\n            ret = _z_pending_peer_svec_append(&pending_peers->_peers, &peer, false);\n        }\n        if (ret != _Z_RES_OK) {\n            _z_pending_peer_clear(&peer);\n            _z_pending_peers_clear(pending_peers);\n            return ret;\n        }\n    }\n\n    return _Z_RES_OK;\n}\n\nbool _z_pending_peers_has_pending(const _z_pending_peers_t *pending_peers) {\n    if (pending_peers == NULL) {\n        return false;\n    }\n\n    size_t len = _z_pending_peer_svec_len(&pending_peers->_peers);\n    for (size_t i = 0; i < len; i++) {\n        const _z_pending_peer_t *peer = _z_pending_peer_svec_get(&pending_peers->_peers, i);\n        if (peer->_state == _Z_PENDING_PEER_STATE_PENDING) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid _z_pending_peers_clear(_z_pending_peers_t *pending_peers) {\n    if (pending_peers == NULL) {\n        return;\n    }\n\n    _z_pending_peer_svec_clear(&pending_peers->_peers);\n    *pending_peers = _z_pending_peers_null();\n}\n\nvoid _z_pending_peers_move(_z_pending_peers_t *dst, _z_pending_peers_t *src) {\n    if ((dst == NULL) || (src == NULL) || (dst == src)) {\n        return;\n    }\n\n    _z_pending_peers_clear(dst);\n\n    *dst = *src;\n    *src = _z_pending_peers_null();\n}\n"
  },
  {
    "path": "src/transport/unicast/accept.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/link/transport/socket.h\"\n#if Z_FEATURE_LINK_TLS == 1\n#include \"zenoh-pico/link/transport/tls_stream.h\"\n#endif\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast/lease.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1 && Z_FEATURE_UNICAST_PEER == 1 && \\\n    (Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_TLS == 1)\n#if Z_FEATURE_CONNECTIVITY == 1\nstatic void _zp_unicast_dispatch_connected_event(_z_transport_unicast_t *ztu, const _z_transport_peer_unicast_t *peer) {\n    if (ztu == NULL || peer == NULL) {\n        return;\n    }\n\n    _z_connectivity_peer_event_data_t connected_peer = {0};\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    bool has_event_data = false;\n\n    _z_transport_peer_mutex_lock(&ztu->_common);\n    _z_transport_peer_unicast_slist_t *it = ztu->_peers;\n    while (it != NULL) {\n        _z_transport_peer_unicast_t *current_peer = _z_transport_peer_unicast_slist_value(it);\n        if (current_peer == peer) {\n            _z_transport_get_link_properties(&ztu->_common, &mtu, &is_streamed, &is_reliable);\n            _z_connectivity_peer_event_data_copy_from_common(&connected_peer, &current_peer->common);\n            has_event_data = true;\n            break;\n        }\n        it = _z_transport_peer_unicast_slist_next(it);\n    }\n    _z_transport_peer_mutex_unlock(&ztu->_common);\n\n    if (has_event_data) {\n        _z_connectivity_peer_connected(_z_transport_common_get_session(&ztu->_common), &connected_peer, false, mtu,\n                                       is_streamed, is_reliable);\n        _z_connectivity_peer_event_data_clear(&connected_peer);\n    }\n}\n#endif\n\n_z_fut_fn_result_t _zp_unicast_accept_task_fn(void *ctx, _z_executor_t *executor) {\n    _ZP_UNUSED(executor);\n    _z_transport_unicast_t *ztu = (_z_transport_unicast_t *)ctx;\n    const _z_sys_net_socket_t *socket_ptr = _z_link_get_socket(ztu->_common._link);\n    if (socket_ptr == NULL) {\n        _Z_ERROR_LOG(_Z_ERR_INVALID);\n        return _z_fut_fn_result_ready();\n    }\n\n    _z_sys_net_socket_t listen_socket = *socket_ptr;\n    _z_sys_net_socket_t con_socket = {0};\n    z_result_t ret = _z_tcp_accept(&listen_socket, &con_socket);\n    if (ret != _Z_RES_OK) {\n        if (ret == _Z_ERR_INVALID) {\n            _Z_INFO(\"Accept socket was closed\");\n            return _z_fut_fn_result_ready();\n        }\n        return _z_fut_fn_result_wake_up_after(1000);\n    }\n\n    if (_z_transport_peer_unicast_slist_len(ztu->_peers) >= Z_LISTEN_MAX_CONNECTION_NB) {\n        _Z_INFO(\"Refusing connection as max connections currently reached\");\n#if Z_FEATURE_LINK_TLS == 1\n        _z_close_tls_socket(&con_socket);\n#endif\n        _z_socket_close(&con_socket);\n        return _z_fut_fn_result_wake_up_after(1000);\n    }\n\n    ret = _z_socket_set_blocking(&con_socket, true);\n    if (ret != _Z_RES_OK) {\n        _Z_INFO(\"Failed to set socket blocking with error %d\", ret);\n#if Z_FEATURE_LINK_TLS == 1\n        _z_close_tls_socket(&con_socket);\n#endif\n        _z_socket_close(&con_socket);\n        return _z_fut_fn_result_continue();\n    }\n\n#if Z_FEATURE_LINK_TLS == 1\n    if (ztu->_common._link->_type == _Z_LINK_TYPE_TLS) {\n        ret = _z_tls_accept(&con_socket, &listen_socket);\n        if (ret != _Z_RES_OK) {\n            _Z_INFO(\"TLS handshake failed with error %d\", ret);\n            _z_close_tls_socket(&con_socket);\n            _z_socket_close(&con_socket);\n            return _z_fut_fn_result_continue();\n        }\n    }\n#endif\n\n    _z_transport_unicast_establish_param_t param = {0};\n    ret = _z_unicast_handshake_listen(&param, ztu->_common._link,\n                                      &_z_transport_common_get_session(&ztu->_common)->_local_zid, Z_WHATAMI_PEER,\n                                      &con_socket);\n    if (ret != _Z_RES_OK) {\n        _Z_INFO(\"Connection accept handshake failed with error %d\", ret);\n#if Z_FEATURE_LINK_TLS == 1\n        _z_close_tls_socket(&con_socket);\n#endif\n        _z_socket_close(&con_socket);\n        return _z_fut_fn_result_continue();\n    }\n\n    if (_z_socket_set_blocking(&con_socket, false) != _Z_RES_OK) {\n        _Z_INFO(\"Failed to set socket non blocking\");\n#if Z_FEATURE_LINK_TLS == 1\n        _z_close_tls_socket(&con_socket);\n#endif\n        _z_socket_close(&con_socket);\n        return _z_fut_fn_result_continue();\n    }\n\n    _z_transport_peer_unicast_t *new_peer = NULL;\n    ret = _z_transport_peer_unicast_add(ztu, &param, con_socket, true, &new_peer);\n    if (ret != _Z_RES_OK) {\n#if Z_FEATURE_LINK_TLS == 1\n        _z_close_tls_socket(&con_socket);\n#endif\n        _z_socket_close(&con_socket);\n        return _z_fut_fn_result_continue();\n    }\n\n    if (new_peer != NULL) {\n        (void)_z_interest_push_declarations_to_peer(_z_transport_common_get_session(&ztu->_common), (void *)new_peer);\n#if Z_FEATURE_CONNECTIVITY == 1\n        _zp_unicast_dispatch_connected_event(ztu, new_peer);\n#endif\n    }\n\n    return _z_fut_fn_result_continue();\n}\n#endif\n"
  },
  {
    "path": "src/transport/unicast/lease.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/unicast/lease.h\"\n\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/session/liveliness.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\n#if Z_FEATURE_UNICAST_PEER == 1\nstatic bool _zp_unicast_peer_is_expired(const _z_transport_peer_unicast_t *target,\n                                        const _z_transport_peer_unicast_t *peer) {\n    _ZP_UNUSED(target);\n    return !peer->common._received;\n}\n\nstatic void _zp_unicast_report_disconnected_peers(_z_transport_unicast_t *ztu,\n                                                  _z_transport_peer_unicast_slist_t **dropped_peers) {\n    if (dropped_peers == NULL || *dropped_peers == NULL) {\n        return;\n    }\n\n#if Z_FEATURE_CONNECTIVITY == 1\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    _z_transport_get_link_properties(&ztu->_common, &mtu, &is_streamed, &is_reliable);\n#endif\n\n    _z_session_t *zs = _z_transport_common_get_session(&ztu->_common);\n    _z_transport_peer_unicast_slist_t *it = *dropped_peers;\n    while (it != NULL) {\n        _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(it);\n        _Z_INFO(\"Deleting peer because it has expired after %zums\", ztu->_common._lease);\n        _z_interest_peer_disconnected(zs, &peer->common);\n#if Z_FEATURE_CONNECTIVITY == 1\n        _z_connectivity_peer_event_data_t disconnected_peer = {0};\n        _z_connectivity_peer_event_data_alias_from_common(&disconnected_peer, &peer->common);\n        _z_connectivity_peer_disconnected(zs, &disconnected_peer, false, mtu, is_streamed, is_reliable);\n#endif\n        it = _z_transport_peer_unicast_slist_next(it);\n    }\n    _z_transport_peer_unicast_slist_free(dropped_peers);\n}\n#endif\n\nz_result_t _zp_unicast_send_keep_alive(_z_transport_unicast_t *ztu) {\n    z_result_t ret = _Z_RES_OK;\n\n    _z_transport_message_t t_msg = _z_t_msg_make_keep_alive();\n    ret = _z_transport_tx_send_t_msg(&ztu->_common, &t_msg, NULL);\n\n    return ret;\n}\n\n_z_fut_fn_result_t _zp_unicast_failed_result(_z_transport_unicast_t *ztu, _z_executor_t *executor) {\n    _z_session_t *zs = _z_transport_common_get_session(&ztu->_common);\n#if Z_FEATURE_LIVELINESS == 1 && Z_FEATURE_SUBSCRIPTION == 1\n    _z_liveliness_subscription_undeclare_all(zs);\n#endif\n#if Z_FEATURE_CONNECTIVITY == 1\n    _z_connectivity_peer_event_data_t disconnected_peer = {0};\n    uint16_t mtu = 0;\n    bool is_streamed = false;\n    bool is_reliable = false;\n    bool has_disconnected_peer = false;\n    _z_transport_peer_mutex_lock(&ztu->_common);\n    if (!_z_transport_peer_unicast_slist_is_empty(ztu->_peers)) {\n        _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(ztu->_peers);\n        _z_transport_get_link_properties(&ztu->_common, &mtu, &is_streamed, &is_reliable);\n        _z_connectivity_peer_event_data_copy_from_common(&disconnected_peer, &curr_peer->common);\n        has_disconnected_peer = true;\n    }\n    _z_transport_peer_mutex_unlock(&ztu->_common);\n    if (has_disconnected_peer) {\n        _z_connectivity_peer_disconnected(zs, &disconnected_peer, false, mtu, is_streamed, is_reliable);\n        _z_connectivity_peer_event_data_clear(&disconnected_peer);\n    }\n#endif\n    _z_unicast_transport_close(ztu, _Z_CLOSE_EXPIRED);\n    _z_session_transport_mutex_lock(zs);\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    // Store weak session to reuse for reconnection.\n    _z_session_weak_t weak_session_clone = _z_session_weak_clone(&ztu->_common._session);\n#endif\n    _z_transport_clear(&zs->_tp);\n    _z_session_transport_mutex_unlock(zs);\n\n#if Z_FEATURE_AUTO_RECONNECT == 1\n    ztu->_common._state = _Z_TRANSPORT_STATE_RECONNECTING;\n    ztu->_common._session = weak_session_clone;\n    _z_fut_t f = _z_fut_null();\n    f._fut_arg = &ztu->_common;\n    f._fut_fn = _z_client_reopen_task_fn;\n    f._destroy_fn = _z_client_reopen_task_drop;\n    if (_z_fut_handle_is_null(_z_executor_spawn(executor, &f))) {\n        _Z_ERROR(\"Failed to spawn client reopen task after transport failure.\");\n        ztu->_common._state = _Z_TRANSPORT_STATE_CLOSED;\n        _z_session_weak_drop(&ztu->_common._session);\n        return _z_fut_fn_result_ready();\n    } else {\n        return _z_fut_fn_result_suspend();\n    }\n#else\n    return _z_fut_fn_result_ready();\n#endif\n}\n\n_z_fut_fn_result_t _zp_unicast_lease_task_fn(void *ztu_arg, _z_executor_t *executor) {\n    _z_transport_unicast_t *ztu = (_z_transport_unicast_t *)ztu_arg;\n    if (ztu->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztu->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    z_whatami_t mode = _z_transport_common_get_session(&ztu->_common)->_mode;\n\n    if (mode == Z_WHATAMI_CLIENT) {\n        _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(ztu->_peers);\n        assert(curr_peer != NULL);\n        if (curr_peer->common._received) {\n            // Reset the lease parameters\n            curr_peer->common._received = false;\n            return _z_fut_fn_result_wake_up_after((unsigned long)ztu->_common._lease);\n        } else {\n            // THIS LOG STRING USED IN TEST, change with caution\n            _Z_INFO(\"Closing session because it has expired after %zums\", ztu->_common._lease);\n            return _zp_unicast_failed_result(ztu, executor);\n        }\n    }\n// TODO: Should we have a task per peer ?\n#if Z_FEATURE_UNICAST_PEER == 1\n    if (mode == Z_WHATAMI_PEER) {\n        _z_transport_peer_unicast_slist_t *dropped_peers = _z_transport_peer_unicast_slist_new();\n        _z_transport_peer_mutex_lock(&ztu->_common);\n        ztu->_peers = _z_transport_peer_unicast_slist_extract_all_filter(ztu->_peers, &dropped_peers,\n                                                                         _zp_unicast_peer_is_expired, NULL);\n        _z_transport_peer_unicast_slist_t *curr_list = ztu->_peers;\n        while (curr_list != NULL) {\n            _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(curr_list);\n            curr_peer->common._received = false;\n            curr_list = _z_transport_peer_unicast_slist_next(curr_list);\n        }\n        _z_transport_peer_mutex_unlock(&ztu->_common);\n        _zp_unicast_report_disconnected_peers(ztu, &dropped_peers);\n        return _z_fut_fn_result_wake_up_after((unsigned long)ztu->_common._lease);\n    }\n#endif\n    return _z_fut_fn_result_ready();\n}\n\n_z_fut_fn_result_t _zp_unicast_keep_alive_task_fn(void *ztu_arg, _z_executor_t *executor) {\n    _z_transport_unicast_t *ztu = (_z_transport_unicast_t *)ztu_arg;\n    if (ztu->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztu->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    z_whatami_t mode = _z_transport_common_get_session(&ztu->_common)->_mode;\n    if (mode == Z_WHATAMI_CLIENT) {\n        assert(_z_transport_peer_unicast_slist_value(ztu->_peers) != NULL);\n        if (!ztu->_common._transmitted) {\n            if (_zp_unicast_send_keep_alive(ztu) < 0) {\n                // THIS LOG STRING USED IN TEST, change with caution\n                _Z_INFO(\"Send keep alive failed.\");\n                return _zp_unicast_failed_result(ztu, executor);\n            }\n        }\n        ztu->_common._transmitted = false;\n        return _z_fut_fn_result_wake_up_after((unsigned long)ztu->_common._lease / Z_TRANSPORT_LEASE_EXPIRE_FACTOR);\n    }\n// TODO: Should we have a task per peer ?\n#if Z_FEATURE_UNICAST_PEER == 1\n    if (mode == Z_WHATAMI_PEER) {\n        if (!ztu->_common._transmitted) {\n            _Z_DEBUG(\"Sending keep alive\");\n            // Send keep alive to all peers\n            _z_transport_message_t t_msg = _z_t_msg_make_keep_alive();\n            _z_transport_peer_mutex_lock(&ztu->_common);\n            if (!_z_transport_peer_unicast_slist_is_empty(ztu->_peers)) {\n                if (_z_transport_tx_send_t_msg(&ztu->_common, &t_msg, ztu->_peers) != _Z_RES_OK) {\n                    _Z_INFO(\"Send keep alive failed.\");\n                    // TODO: report failed peers and close them ?\n                }\n            }\n            _z_transport_peer_mutex_unlock(&ztu->_common);\n        }\n        ztu->_common._transmitted = false;\n        return _z_fut_fn_result_wake_up_after((unsigned long)ztu->_common._lease / Z_TRANSPORT_LEASE_EXPIRE_FACTOR);\n    }\n#endif\n    return _z_fut_fn_result_ready();\n}\n#endif  // Z_FEATURE_UNICAST_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/unicast/read.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/unicast/read.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/link/transport/socket.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/runtime/runtime.h\"\n#include \"zenoh-pico/session/interest.h\"\n#include \"zenoh-pico/transport/common/rx.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast/lease.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#define _Z_UNICAST_PEER_READ_STATUS_OK 0\n#define _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA -1\n#define _Z_UNICAST_PEER_READ_STATUS_SOCKET_CLOSED -2\n#define _Z_UNICAST_PEER_READ_STATUS_CRITICAL_ERROR -3\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\n\nstatic z_result_t _z_unicast_process_messages(_z_transport_unicast_t *ztu, _z_transport_peer_unicast_t *peer,\n                                              size_t to_read) {\n    // Wrap the main buffer to_read bytes\n    _z_zbuf_t zbuf;\n    if (peer->flow_state == _Z_FLOW_STATE_READY) {\n        zbuf = _z_zbuf_view(&peer->flow_buff, to_read);\n    } else {\n        zbuf = _z_zbuf_view(&ztu->_common._zbuf, to_read);\n    }\n\n    peer->common._received = true;\n    while (_z_zbuf_len(&zbuf) > 0) {\n        // Decode one session message\n        _z_transport_message_t t_msg;\n        z_result_t ret = _z_transport_message_decode(&t_msg, &zbuf);\n\n        if (ret != _Z_RES_OK) {\n            _Z_INFO(\"Connection compromised due to malformed message: %d\", ret);\n            return ret;\n        }\n        ret = _z_unicast_handle_transport_message(ztu, &t_msg, peer);\n        if (ret != _Z_RES_OK) {\n            if (ret != _Z_ERR_CONNECTION_CLOSED) {\n                _Z_WARN(\"Connection compromised due to message processing error: %d\", ret);\n            }\n            return ret;\n        }\n    }\n    // Move the read position of the read buffer\n    if (peer->flow_state == _Z_FLOW_STATE_READY) {\n        _z_zbuf_set_rpos(&peer->flow_buff, _z_zbuf_get_rpos(&peer->flow_buff) + to_read);\n    } else {\n        _z_zbuf_set_rpos(&ztu->_common._zbuf, _z_zbuf_get_rpos(&ztu->_common._zbuf) + to_read);\n    }\n\n    if (_z_unicast_update_rx_buffer(ztu) != _Z_RES_OK) {\n        _Z_ERROR(\"Connection closed due to lack of memory to allocate rx buffer\");\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    return _Z_RES_OK;\n}\n\nstatic bool _z_unicast_client_read(_z_transport_unicast_t *ztu, _z_transport_peer_unicast_t *peer, size_t *to_read) {\n    switch (ztu->_common._link->_cap._flow) {\n        case Z_LINK_CAP_FLOW_STREAM:\n            if (_z_zbuf_len(&ztu->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                _z_link_socket_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, peer->_socket);\n                if (_z_zbuf_len(&ztu->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                    _z_zbuf_compact(&ztu->_common._zbuf);\n                    return false;\n                }\n            }\n            // Get stream size\n            *to_read = _z_read_stream_size(&ztu->_common._zbuf);\n            // Read data\n            if (_z_zbuf_len(&ztu->_common._zbuf) < *to_read) {\n                _z_link_socket_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, peer->_socket);\n                if (_z_zbuf_len(&ztu->_common._zbuf) < *to_read) {\n                    _z_zbuf_set_rpos(&ztu->_common._zbuf, _z_zbuf_get_rpos(&ztu->_common._zbuf) - _Z_MSG_LEN_ENC_SIZE);\n                    _z_zbuf_compact(&ztu->_common._zbuf);\n                    return false;\n                }\n            }\n            break;\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n            _z_zbuf_compact(&ztu->_common._zbuf);\n            *to_read = _z_link_socket_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, peer->_socket);\n            if (*to_read == SIZE_MAX) {\n                return false;\n            }\n            break;\n        default:\n            break;\n    }\n    return true;\n}\n\nz_result_t _zp_unicast_read(_z_transport_unicast_t *ztu, bool single_read) {\n    _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(ztu->_peers);\n    if (curr_peer == NULL) {\n        _Z_ERROR(\"Invalid router endpoint\\n\");\n        _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_RX_FAILED);\n    }\n    // Read & process a single message\n    if (single_read) {\n        _z_transport_message_t t_msg;\n        _Z_RETURN_IF_ERR(_z_unicast_recv_t_msg(ztu, &t_msg));\n        _Z_CLEAN_RETURN_IF_ERR(_z_unicast_handle_transport_message(ztu, &t_msg, curr_peer), _z_t_msg_clear(&t_msg));\n        _z_t_msg_clear(&t_msg);\n        // Update buffer\n        _Z_RETURN_IF_ERR(_z_unicast_update_rx_buffer(ztu));\n    } else {\n        // Prepare buffer\n        _z_zbuf_reset(&ztu->_common._zbuf);\n        size_t to_read = 0;\n        // Retrieve data if any\n        if (_z_unicast_client_read(ztu, curr_peer, &to_read)) {\n            // Process data\n            _Z_RETURN_IF_ERR(_z_unicast_process_messages(ztu, curr_peer, to_read))\n        } else {\n            return _Z_NO_DATA_PROCESSED;\n        }\n    }\n    return _Z_RES_OK;\n}\n\n#if Z_FEATURE_UNICAST_PEER == 1\nstatic void _z_unicast_wait_iter_reset(_z_socket_wait_iter_t *iter) { iter->_current_entry = NULL; }\n\nstatic bool _z_unicast_wait_iter_next(_z_socket_wait_iter_t *iter) {\n    _z_transport_unicast_t *ztu = (_z_transport_unicast_t *)iter->_ctx;\n    if (iter->_current_entry == NULL) {\n        iter->_current_entry = ztu->_peers;\n    } else {\n        iter->_current_entry =\n            _z_transport_peer_unicast_slist_next((_z_transport_peer_unicast_slist_t *)iter->_current_entry);\n    }\n    return iter->_current_entry != NULL;\n}\n\nstatic const _z_sys_net_socket_t *_z_unicast_wait_iter_get_socket(const _z_socket_wait_iter_t *iter) {\n    _z_transport_peer_unicast_t *peer =\n        _z_transport_peer_unicast_slist_value((_z_transport_peer_unicast_slist_t *)iter->_current_entry);\n    return &peer->_socket;\n}\n\nstatic void _z_unicast_wait_iter_set_ready(_z_socket_wait_iter_t *iter, bool ready) {\n    _z_transport_peer_unicast_t *peer =\n        _z_transport_peer_unicast_slist_value((_z_transport_peer_unicast_slist_t *)iter->_current_entry);\n    peer->_pending = ready;\n}\n\nstatic z_result_t _z_unicast_wait_peer_event(_z_transport_unicast_t *ztu) {\n    _z_socket_wait_iter_t iter = {\n        ._ctx = ztu,\n        ._current_entry = NULL,\n        ._reset = _z_unicast_wait_iter_reset,\n        ._next = _z_unicast_wait_iter_next,\n        ._get_socket = _z_unicast_wait_iter_get_socket,\n        ._set_ready = _z_unicast_wait_iter_set_ready,\n    };\n    return _z_socket_wait_readable(&iter, Z_CONFIG_SOCKET_TIMEOUT);\n}\n\nstatic z_result_t _z_unicast_handle_remaining_data(_z_transport_unicast_t *ztu, _z_transport_peer_unicast_t *peer,\n                                                   size_t extra_size, size_t *to_read, bool *message_to_process) {\n    *message_to_process = false;\n    if (extra_size < _Z_MSG_LEN_ENC_SIZE) {\n        peer->flow_state = _Z_FLOW_STATE_PENDING_SIZE;\n        peer->flow_curr_size = _z_zbuf_read(&ztu->_common._zbuf);\n        return _Z_RES_OK;\n    }\n    // Get stream size\n    *to_read = _z_read_stream_size(&ztu->_common._zbuf);\n    if (_z_zbuf_len(&ztu->_common._zbuf) < *to_read) {\n        peer->flow_state = _Z_FLOW_STATE_PENDING_DATA;\n        peer->flow_curr_size = (uint16_t)*to_read;\n        peer->flow_buff = _z_zbuf_make(peer->flow_curr_size);\n        if (_z_zbuf_capacity(&peer->flow_buff) != peer->flow_curr_size) {\n            _Z_ERROR(\"Not enough memory to allocate flow state buffer\");\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        _z_zbuf_copy_bytes(&peer->flow_buff, &ztu->_common._zbuf);\n        return _Z_RES_OK;\n    }\n    *message_to_process = true;\n    return _Z_RES_OK;\n}\n\nstatic int _z_unicast_peer_read(_z_transport_unicast_t *ztu, _z_transport_peer_unicast_t *peer, size_t *to_read) {\n    // If we receive fragmented data we have to store it on a separate buffer\n    size_t read_size = 0;\n    switch (ztu->_common._link->_cap._flow) {\n        case Z_LINK_CAP_FLOW_STREAM:\n            switch (peer->flow_state) {\n                case _Z_FLOW_STATE_READY:\n                    peer->flow_state = _Z_FLOW_STATE_INACTIVE;\n                    peer->flow_curr_size = 0;\n                    _z_zbuf_clear(&peer->flow_buff);  // fall through\n                default:                              // fall through\n                case _Z_FLOW_STATE_INACTIVE:\n                    read_size = _z_link_socket_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, peer->_socket);\n                    if (read_size == 0) {\n                        _Z_DEBUG(\"Socket closed\");\n                        return _Z_UNICAST_PEER_READ_STATUS_SOCKET_CLOSED;\n                    } else if (read_size == SIZE_MAX) {\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    }\n                    if (_z_zbuf_len(&ztu->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                        peer->flow_state = _Z_FLOW_STATE_PENDING_SIZE;\n                        peer->flow_curr_size = _z_zbuf_read(&ztu->_common._zbuf);\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    }\n                    // Get stream size\n                    *to_read = _z_read_stream_size(&ztu->_common._zbuf);\n                    // Read data if needed\n                    read_size = _z_zbuf_len(&ztu->_common._zbuf);\n                    if (read_size < *to_read) {\n                        peer->flow_state = _Z_FLOW_STATE_PENDING_DATA;\n                        peer->flow_curr_size = (uint16_t)*to_read;\n                        peer->flow_buff = _z_zbuf_make(peer->flow_curr_size);\n                        if (_z_zbuf_capacity(&peer->flow_buff) != peer->flow_curr_size) {\n                            _Z_ERROR(\"Not enough memory to allocate flow state buffer\");\n                            return _Z_UNICAST_PEER_READ_STATUS_CRITICAL_ERROR;\n                        }\n                        _z_zbuf_copy_bytes(&peer->flow_buff, &ztu->_common._zbuf);\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    }\n                    break;\n                case _Z_FLOW_STATE_PENDING_SIZE:\n                    read_size = _z_link_socket_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, peer->_socket);\n                    if (read_size == 0) {\n                        _Z_DEBUG(\"Socket closed\");\n                        return _Z_UNICAST_PEER_READ_STATUS_SOCKET_CLOSED;\n                    } else if (read_size == SIZE_MAX) {\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    }\n                    peer->flow_curr_size += (uint16_t)(_z_zbuf_read(&ztu->_common._zbuf) << 8);\n                    *to_read = peer->flow_curr_size;\n                    if (_z_zbuf_len(&ztu->_common._zbuf) < *to_read) {\n                        peer->flow_state = _Z_FLOW_STATE_PENDING_DATA;\n                        peer->flow_buff = _z_zbuf_make(peer->flow_curr_size);\n                        if (_z_zbuf_capacity(&peer->flow_buff) != peer->flow_curr_size) {\n                            _Z_ERROR(\"Not enough memory to allocate flow state buffer\");\n                            return _Z_UNICAST_PEER_READ_STATUS_CRITICAL_ERROR;\n                        }\n                        _z_zbuf_copy_bytes(&peer->flow_buff, &ztu->_common._zbuf);\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    }\n                    break;\n                case _Z_FLOW_STATE_PENDING_DATA:\n                    read_size = _z_link_socket_recv_zbuf(ztu->_common._link, &peer->flow_buff, peer->_socket);\n                    if (read_size == 0) {\n                        _Z_DEBUG(\"Socket closed\");\n                        return _Z_UNICAST_PEER_READ_STATUS_SOCKET_CLOSED;\n                    } else if (read_size == SIZE_MAX) {\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    }\n                    *to_read = peer->flow_curr_size;\n                    if (_z_zbuf_len(&peer->flow_buff) < *to_read) {\n                        return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n                    } else {\n                        peer->flow_state = _Z_FLOW_STATE_READY;\n                    }\n                    break;\n            }\n\n            break;\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n            *to_read = _z_link_socket_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, peer->_socket);\n            if (*to_read == SIZE_MAX) {\n                return _Z_UNICAST_PEER_READ_STATUS_PENDING_DATA;\n            }\n            break;\n        default:\n            break;\n    }\n    return _Z_UNICAST_PEER_READ_STATUS_OK;\n}\n\nstatic z_result_t _zp_unicast_process_peer_event(_z_transport_unicast_t *ztu) {\n    _z_transport_peer_mutex_lock(&ztu->_common);\n    _z_transport_peer_unicast_slist_t *curr_list = ztu->_peers;\n    _z_transport_peer_unicast_slist_t *prev = NULL;\n    _z_transport_peer_unicast_slist_t *prev_drop = NULL;\n    size_t to_read = 0;\n    while (curr_list != NULL) {\n        bool drop_peer = false;\n        _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(curr_list);\n        if (curr_peer->_pending) {\n            curr_peer->_pending = false;\n            // Read data from socket\n            int res = _z_unicast_peer_read(ztu, curr_peer, &to_read);\n            if (res == _Z_UNICAST_PEER_READ_STATUS_OK) {  // Messages to process\n                bool message_to_process = false;\n                do {\n                    message_to_process = false;\n                    // Process one message\n                    if (_z_unicast_process_messages(ztu, curr_peer, to_read) != _Z_RES_OK) {\n                        // Failed to process, drop peer\n                        _Z_ERROR(\"Dropping peer due to processing error\");\n                        drop_peer = true;\n                        prev_drop = prev;\n                        break;\n                    } else if (curr_peer->flow_state != _Z_FLOW_STATE_READY) {\n                        // Process remaining data\n                        size_t extra_data = _z_zbuf_len(&ztu->_common._zbuf);\n                        if (extra_data > 0) {\n                            _Z_RETURN_IF_ERR(_z_unicast_handle_remaining_data(ztu, curr_peer, extra_data, &to_read,\n                                                                              &message_to_process));\n                        }\n                    }\n                } while (message_to_process);\n            } else if (res == _Z_UNICAST_PEER_READ_STATUS_SOCKET_CLOSED) {\n                drop_peer = true;\n                prev_drop = prev;\n            } else if (res == _Z_UNICAST_PEER_READ_STATUS_CRITICAL_ERROR) {\n                _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n            }\n        }\n        // Update previous only if current node is not dropped\n        if (!drop_peer) {\n            prev = curr_list;\n        }\n        // Progress list\n        curr_list = _z_transport_peer_unicast_slist_next(curr_list);\n        // Drop peer if needed\n        if (drop_peer) {\n            _Z_DEBUG(\"Dropping peer\");\n            _z_session_t *zs = _z_transport_common_get_session(&ztu->_common);\n#if Z_FEATURE_CONNECTIVITY == 1\n            _z_connectivity_peer_event_data_t disconnected_peer = {0};\n            uint16_t mtu = 0;\n            bool is_streamed = false;\n            bool is_reliable = false;\n            _z_transport_get_link_properties(&ztu->_common, &mtu, &is_streamed, &is_reliable);\n            _z_connectivity_peer_event_data_copy_from_common(&disconnected_peer, &curr_peer->common);\n#endif\n            _z_interest_peer_disconnected(zs, &curr_peer->common);\n            ztu->_peers = _z_transport_peer_unicast_slist_drop_element(ztu->_peers, prev_drop);\n#if Z_FEATURE_CONNECTIVITY == 1\n            _z_transport_peer_mutex_unlock(&ztu->_common);\n            _z_connectivity_peer_disconnected(zs, &disconnected_peer, false, mtu, is_streamed, is_reliable);\n            _z_connectivity_peer_event_data_clear(&disconnected_peer);\n            _z_transport_peer_mutex_lock(&ztu->_common);\n            curr_list = ztu->_peers;\n            prev = NULL;\n            prev_drop = NULL;\n            _z_zbuf_reset(&ztu->_common._zbuf);\n            continue;\n#endif\n        }\n        _z_zbuf_reset(&ztu->_common._zbuf);\n    }\n    _z_transport_peer_mutex_unlock(&ztu->_common);\n    return _Z_RES_OK;\n}\n#endif\n\n_z_fut_fn_result_t _zp_unicast_read_task_fn(void *ztu_arg, _z_executor_t *executor) {\n    _z_transport_unicast_t *ztu = (_z_transport_unicast_t *)ztu_arg;\n    if (ztu->_common._state == _Z_TRANSPORT_STATE_CLOSED) {\n        return _z_fut_fn_result_ready();\n    } else if (ztu->_common._state == _Z_TRANSPORT_STATE_RECONNECTING) {\n        return _z_fut_fn_result_suspend();\n    }\n\n    z_whatami_t mode = _z_transport_common_get_session(&ztu->_common)->_mode;\n    if (mode == Z_WHATAMI_CLIENT) {\n        _z_transport_peer_unicast_t *curr_peer = _z_transport_peer_unicast_slist_value(ztu->_peers);\n        assert(curr_peer != NULL);\n        size_t to_read = 0;\n        // Retrieve data\n        if (_z_unicast_client_read(ztu, curr_peer, &to_read) &&\n            _z_unicast_process_messages(ztu, curr_peer, to_read) != _Z_RES_OK) {\n            _Z_INFO(\"Read task failed, closing session\\n\");\n            return _zp_unicast_failed_result(ztu, executor);\n        }\n    }\n#if Z_FEATURE_UNICAST_PEER == 1\n    if (mode == Z_WHATAMI_PEER) {\n        bool has_peers = !_z_transport_peer_unicast_slist_is_empty(ztu->_peers);\n        if (!has_peers) {\n            return _z_fut_fn_result_wake_up_after(100);\n        }\n\n        if (_z_unicast_wait_peer_event(ztu) == _Z_RES_OK && _zp_unicast_process_peer_event(ztu) != _Z_RES_OK) {\n            // TODO: Close transport on error. Probably we should just close the failed peer and\n            // initiate reconnection task.\n            return _z_fut_fn_result_ready();\n        }\n    }\n#endif\n    return _z_fut_fn_result_continue();\n}\n#endif  // Z_FEATURE_UNICAST_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/unicast/rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/common/rx.h\"\n\n#include <stddef.h>\n\n#include \"zenoh-pico/config.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\n\nz_result_t _z_unicast_recv_t_msg(_z_transport_unicast_t *ztu, _z_transport_message_t *t_msg) {\n    _Z_DEBUG(\">> recv session msg\");\n    z_result_t ret = _Z_RES_OK;\n    size_t to_read = 0;\n    _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(ztu->_peers);\n    do {\n        switch (ztu->_common._link->_cap._flow) {\n            // Stream capable links\n            case Z_LINK_CAP_FLOW_STREAM:\n                if (_z_zbuf_len(&ztu->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                    _z_link_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, NULL);\n                    if (_z_zbuf_len(&ztu->_common._zbuf) < _Z_MSG_LEN_ENC_SIZE) {\n                        _z_zbuf_compact(&ztu->_common._zbuf);\n                        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES);\n                        ret = _Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES;\n                        continue;\n                    }\n                }\n                // Get stream size\n                to_read = _z_read_stream_size(&ztu->_common._zbuf);\n                // Read data\n                if (_z_zbuf_len(&ztu->_common._zbuf) < to_read) {\n                    _z_link_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, NULL);\n                    if (_z_zbuf_len(&ztu->_common._zbuf) < to_read) {\n                        _z_zbuf_set_rpos(&ztu->_common._zbuf,\n                                         _z_zbuf_get_rpos(&ztu->_common._zbuf) - _Z_MSG_LEN_ENC_SIZE);\n                        _z_zbuf_compact(&ztu->_common._zbuf);\n                        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES);\n                        ret = _Z_ERR_TRANSPORT_NOT_ENOUGH_BYTES;\n                        continue;\n                    }\n                }\n                break;\n            // Datagram capable links\n            case Z_LINK_CAP_FLOW_DATAGRAM:\n                _z_zbuf_compact(&ztu->_common._zbuf);\n                to_read = _z_link_recv_zbuf(ztu->_common._link, &ztu->_common._zbuf, NULL);\n                if (to_read == SIZE_MAX) {\n                    _Z_ERROR_LOG(_Z_ERR_TRANSPORT_RX_FAILED);\n                    ret = _Z_ERR_TRANSPORT_RX_FAILED;\n                }\n                break;\n            default:\n                break;\n        }\n    } while (false);  // The 1-iteration loop to use continue to break the entire loop on error\n\n    if (ret == _Z_RES_OK) {\n        _Z_DEBUG(\">> \\t transport_message_decode\");\n\n        // Wrap the main buffer to_read bytes\n        _z_zbuf_t zbuf = _z_zbuf_view(&ztu->_common._zbuf, to_read);\n        ret = _z_transport_message_decode(t_msg, &zbuf);\n\n        if (ret == _Z_RES_OK) {\n            // Mark the session that we have received data\n            peer->common._received = true;\n\n            // Update the actual buffer pointers\n            _z_zbuf_set_rpos(&ztu->_common._zbuf, _z_zbuf_get_rpos(&ztu->_common._zbuf) + _z_zbuf_get_rpos(&zbuf));\n        } else {\n            _Z_ERROR(\"Malformed transport message: %d\", ret);\n            _z_zbuf_set_rpos(&ztu->_common._zbuf, _z_zbuf_get_rpos(&ztu->_common._zbuf) + to_read);\n        }\n    }\n    return ret;\n}\n\nstatic z_result_t _z_unicast_handle_frame(_z_transport_unicast_t *ztu, uint8_t header, _z_t_msg_frame_t *msg,\n                                          _z_transport_peer_unicast_t *peer) {\n    z_reliability_t tmsg_reliability;\n    // Check if the SN is correct\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_FRAME_R)) {\n        tmsg_reliability = Z_RELIABILITY_RELIABLE;\n        // @TODO: amend once reliability is in place. For the time being only\n        //        monotonic SNs are ensured\n        if (_z_sn_precedes(ztu->_common._sn_res, peer->_sn_rx_reliable, msg->_sn)) {\n            peer->_sn_rx_reliable = msg->_sn;\n        } else {\n#if Z_FEATURE_FRAGMENTATION == 1\n            _z_wbuf_clear(&peer->common._dbuf_reliable);\n            peer->common._state_reliable = _Z_DBUF_STATE_NULL;\n#endif\n            _Z_INFO(\"Reliable message dropped because it is out of order\");\n            _z_t_msg_frame_clear(msg);\n            return _Z_RES_OK;\n        }\n    } else {\n        tmsg_reliability = Z_RELIABILITY_BEST_EFFORT;\n        if (_z_sn_precedes(ztu->_common._sn_res, peer->_sn_rx_best_effort, msg->_sn)) {\n            peer->_sn_rx_best_effort = msg->_sn;\n        } else {\n#if Z_FEATURE_FRAGMENTATION == 1\n            _z_wbuf_clear(&peer->common._dbuf_best_effort);\n            peer->common._state_best_effort = _Z_DBUF_STATE_NULL;\n#endif\n            _Z_INFO(\"Best effort message dropped because it is out of order\");\n            _z_t_msg_frame_clear(msg);\n            return _Z_RES_OK;\n        }\n    }\n    // Handle all the zenoh message, one by one\n    // From this point, memory cleaning must be handled by the network message layer\n    _z_network_message_t curr_nmsg = {0};\n    _z_arc_slice_t arcs = _z_arc_slice_empty();\n    while (_z_zbuf_len(msg->_payload) > 0) {\n        _Z_RETURN_IF_ERR(_z_network_message_decode(&curr_nmsg, msg->_payload, &arcs, (uintptr_t)&peer->common));\n        curr_nmsg._reliability = tmsg_reliability;\n        _Z_RETURN_IF_ERR(_z_handle_network_message(&ztu->_common, &curr_nmsg, &peer->common));\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_unicast_handle_fragment_inner(_z_transport_unicast_t *ztu, uint8_t header,\n                                                   _z_t_msg_fragment_t *msg, _z_transport_peer_unicast_t *peer) {\n    z_result_t ret = _Z_RES_OK;\n#if Z_FEATURE_FRAGMENTATION == 1\n    _z_wbuf_t *dbuf;\n    uint8_t *dbuf_state;\n    z_reliability_t tmsg_reliability;\n    bool consecutive;\n\n    // Select the right defragmentation buffer\n    if (_Z_HAS_FLAG(header, _Z_FLAG_T_FRAGMENT_R)) {\n        tmsg_reliability = Z_RELIABILITY_RELIABLE;\n        // Check SN\n        // @TODO: amend once reliability is in place. For the time being only\n        //        monotonic SNs are ensured\n        if (_z_sn_precedes(ztu->_common._sn_res, peer->_sn_rx_reliable, msg->_sn)) {\n            consecutive = _z_sn_consecutive(ztu->_common._sn_res, peer->_sn_rx_reliable, msg->_sn);\n            peer->_sn_rx_reliable = msg->_sn;\n            dbuf = &peer->common._dbuf_reliable;\n            dbuf_state = &peer->common._state_reliable;\n        } else {\n            _z_wbuf_clear(&peer->common._dbuf_reliable);\n            peer->common._state_reliable = _Z_DBUF_STATE_NULL;\n            _Z_INFO(\"Reliable message dropped because it is out of order\");\n            return _Z_RES_OK;\n        }\n    } else {\n        tmsg_reliability = Z_RELIABILITY_BEST_EFFORT;\n        // Check SN\n        if (_z_sn_precedes(ztu->_common._sn_res, peer->_sn_rx_best_effort, msg->_sn)) {\n            consecutive = _z_sn_consecutive(ztu->_common._sn_res, peer->_sn_rx_best_effort, msg->_sn);\n            peer->_sn_rx_best_effort = msg->_sn;\n            dbuf = &peer->common._dbuf_best_effort;\n            dbuf_state = &peer->common._state_best_effort;\n        } else {\n            _z_wbuf_clear(&peer->common._dbuf_best_effort);\n            peer->common._state_best_effort = _Z_DBUF_STATE_NULL;\n            _Z_INFO(\"Best effort message dropped because it is out of order\");\n            return _Z_RES_OK;\n        }\n    }\n    // Check consecutive SN\n    if (!consecutive && _z_wbuf_len(dbuf) > 0) {\n        _z_wbuf_clear(dbuf);\n        *dbuf_state = _Z_DBUF_STATE_NULL;\n        _Z_INFO(\"Defragmentation buffer dropped because non-consecutive fragments received\");\n        return _Z_RES_OK;\n    }\n    // Handle fragment markers\n    if (_Z_PATCH_HAS_FRAGMENT_MARKERS(peer->common._patch)) {\n        if (msg->first) {\n            _z_wbuf_reset(dbuf);\n        } else if (_z_wbuf_len(dbuf) == 0) {\n            _Z_INFO(\"First fragment received without the start marker\");\n            return _Z_RES_OK;\n        }\n        if (msg->drop) {\n            _z_wbuf_reset(dbuf);\n            return _Z_RES_OK;\n        }\n    }\n    // Allocate buffer if needed\n    if (*dbuf_state == _Z_DBUF_STATE_NULL) {\n        *dbuf = _z_wbuf_make(Z_FRAG_MAX_SIZE, false);\n        if (_z_wbuf_capacity(dbuf) != Z_FRAG_MAX_SIZE) {\n            _Z_ERROR(\"Not enough memory to allocate transport defragmentation buffer\");\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        *dbuf_state = _Z_DBUF_STATE_INIT;\n    }\n    // Process fragment data\n    if (*dbuf_state == _Z_DBUF_STATE_INIT) {\n        // Check overflow\n        if ((_z_wbuf_len(dbuf) + msg->_payload.len) > Z_FRAG_MAX_SIZE) {\n            *dbuf_state = _Z_DBUF_STATE_OVERFLOW;\n        } else {\n            // Fill buffer\n            _z_wbuf_write_bytes(dbuf, msg->_payload.start, 0, msg->_payload.len);\n        }\n    }\n    // Process final fragment\n    if (!_Z_HAS_FLAG(header, _Z_FLAG_T_FRAGMENT_M)) {\n        // Drop message if it exceeds the fragmentation size\n        if (*dbuf_state == _Z_DBUF_STATE_OVERFLOW) {\n            _Z_INFO(\"Fragment dropped because defragmentation buffer has overflown\");\n            _z_wbuf_clear(dbuf);\n            *dbuf_state = _Z_DBUF_STATE_NULL;\n            return _Z_RES_OK;\n        }\n        // Convert the defragmentation buffer into a decoding buffer\n        _z_zbuf_t zbf = _z_wbuf_moved_as_zbuf(dbuf);\n        if (_z_zbuf_capacity(&zbf) == 0) {\n            _Z_ERROR(\"Failed to convert defragmentation buffer into a decoding buffer!\");\n            _z_wbuf_clear(dbuf);\n            *dbuf_state = _Z_DBUF_STATE_NULL;\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        // Decode message\n        _z_zenoh_message_t zm = {0};\n        _z_arc_slice_t arcs = _z_arc_slice_empty();\n        ret = _z_network_message_decode(&zm, &zbf, &arcs, (uintptr_t)&peer->common);\n        zm._reliability = tmsg_reliability;\n        if (ret == _Z_RES_OK) {\n            // Memory clear of the network message data must be handled by the network message layer\n            _z_handle_network_message(&ztu->_common, &zm, &peer->common);\n        } else {\n            _Z_INFO(\"Failed to decode defragmented message\");\n            _Z_ERROR_LOG(_Z_ERR_MESSAGE_DESERIALIZATION_FAILED);\n            ret = _Z_ERR_MESSAGE_DESERIALIZATION_FAILED;\n        }\n        // Free the decoding buffer\n        _z_zbuf_clear(&zbf);\n        *dbuf_state = _Z_DBUF_STATE_NULL;\n    }\n#else\n    _ZP_UNUSED(ztu);\n    _ZP_UNUSED(header);\n    _ZP_UNUSED(msg);\n    _ZP_UNUSED(peer);\n    _Z_INFO(\"Fragment dropped because fragmentation feature is deactivated\");\n#endif\n    return ret;\n}\n\nstatic z_result_t _z_unicast_handle_fragment(_z_transport_unicast_t *ztu, uint8_t header, _z_t_msg_fragment_t *msg,\n                                             _z_transport_peer_unicast_t *peer) {\n    z_result_t ret = _z_unicast_handle_fragment_inner(ztu, header, msg, peer);\n    _z_t_msg_fragment_clear(msg);\n    return ret;\n}\n\nz_result_t _z_unicast_handle_transport_message(_z_transport_unicast_t *ztu, _z_transport_message_t *t_msg,\n                                               _z_transport_peer_unicast_t *peer) {\n    z_result_t ret = _Z_RES_OK;\n\n    switch (_Z_MID(t_msg->_header)) {\n        case _Z_MID_T_FRAME:\n            _Z_DEBUG(\"Received Z_FRAME message\");\n            ret = _z_unicast_handle_frame(ztu, t_msg->_header, &t_msg->_body._frame, peer);\n            break;\n\n        case _Z_MID_T_FRAGMENT:\n            _Z_DEBUG(\"Received Z_FRAGMENT message\");\n            ret = _z_unicast_handle_fragment(ztu, t_msg->_header, &t_msg->_body._fragment, peer);\n            break;\n\n        case _Z_MID_T_KEEP_ALIVE: {\n            _Z_DEBUG(\"Received Z_KEEP_ALIVE message\");\n            _z_t_msg_keep_alive_clear(&t_msg->_body._keep_alive);\n            break;\n        }\n\n        case _Z_MID_T_INIT: {\n            // Do nothing, zenoh clients are not expected to handle accept messages on established sessions\n            _z_t_msg_init_clear(&t_msg->_body._init);\n            break;\n        }\n\n        case _Z_MID_T_OPEN: {\n            // Do nothing, zenoh clients are not expected to handle accept messages on established sessions\n            _z_t_msg_open_clear(&t_msg->_body._open);\n            break;\n        }\n\n        case _Z_MID_T_CLOSE: {\n            _Z_INFO(\"Closing session as requested by the remote peer\");\n            // Peer will be dropped thanks to the error\n            _Z_ERROR_LOG(_Z_ERR_CONNECTION_CLOSED);\n            ret = _Z_ERR_CONNECTION_CLOSED;\n            _z_t_msg_close_clear(&t_msg->_body._close);\n            break;\n        }\n\n        default: {\n            _Z_INFO(\"WARNING: Unknown transport message ID\");\n            _z_t_msg_clear(t_msg);\n            break;\n        }\n    }\n    return ret;\n}\n\nz_result_t _z_unicast_update_rx_buffer(_z_transport_unicast_t *ztu) {\n    // Check if user or defragment buffer took ownership of buffer\n    if (_z_zbuf_get_ref_count(&ztu->_common._zbuf) != 1) {\n        // Allocate a new buffer\n        size_t buff_capacity = _z_zbuf_capacity(&ztu->_common._zbuf);\n        _z_zbuf_t new_zbuf = _z_zbuf_make(buff_capacity);\n        if (_z_zbuf_capacity(&new_zbuf) != buff_capacity) {\n            _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n        }\n        // Recopy leftover bytes\n        size_t leftovers = _z_zbuf_len(&ztu->_common._zbuf);\n        if (leftovers > 0) {\n            _z_zbuf_copy_bytes(&new_zbuf, &ztu->_common._zbuf);\n        }\n        // Drop buffer & update\n        _z_zbuf_clear(&ztu->_common._zbuf);\n        ztu->_common._zbuf = new_zbuf;\n    }\n    return _Z_RES_OK;\n}\n\n#else\nz_result_t _z_unicast_recv_t_msg(_z_transport_unicast_t *ztu, _z_transport_message_t *t_msg) {\n    _ZP_UNUSED(ztu);\n    _ZP_UNUSED(t_msg);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_unicast_handle_transport_message(_z_transport_unicast_t *ztu, _z_transport_message_t *t_msg,\n                                               _z_transport_peer_unicast_t *peer) {\n    _ZP_UNUSED(ztu);\n    _ZP_UNUSED(t_msg);\n    _ZP_UNUSED(peer);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n#endif  // Z_FEATURE_UNICAST_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/unicast/transport.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/transport/common/transport.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n#include \"zenoh-pico/transport/common/rx.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/transport/unicast/transport.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\nstatic z_result_t _z_unicast_transport_create_inner(_z_transport_unicast_t *ztu, _z_link_t *zl,\n                                                    _z_transport_unicast_establish_param_t *param) {\n// Initialize batching data\n#if Z_FEATURE_BATCHING == 1\n    ztu->_common._batch_state = _Z_BATCHING_IDLE;\n    ztu->_common._batch_count = 0;\n#endif\n\n#if Z_FEATURE_MULTI_THREAD == 1\n    // Initialize the mutexes\n    _Z_RETURN_IF_ERR(_z_mutex_init(&ztu->_common._mutex_tx));\n    _Z_RETURN_IF_ERR(_z_mutex_rec_init(&ztu->_common._mutex_peer));\n#endif  // Z_FEATURE_MULTI_THREAD == 1\n\n    // Initialize the read and write buffers\n    uint16_t mtu = (zl->_mtu < param->_batch_size) ? zl->_mtu : param->_batch_size;\n    size_t wbuf_size = mtu;\n    size_t zbuf_size = param->_batch_size;\n    // Initialize tx rx buffers\n    ztu->_common._wbuf = _z_wbuf_make(wbuf_size, false);\n    ztu->_common._zbuf = _z_zbuf_make(zbuf_size);\n\n    // Check if a buffer failed to allocate\n    if ((_z_wbuf_capacity(&ztu->_common._wbuf) != wbuf_size) || (_z_zbuf_capacity(&ztu->_common._zbuf) != zbuf_size)) {\n        _Z_ERROR(\"Not enough memory to allocate transport buffers!\");\n        _Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);\n    }\n    // Set default SN resolution\n    ztu->_common._sn_res = _z_sn_max(param->_seq_num_res);\n    // The initial SN at TX side\n    ztu->_common._sn_tx_reliable = param->_initial_sn_tx;\n    ztu->_common._sn_tx_best_effort = param->_initial_sn_tx;\n    // Notifiers\n    ztu->_common._transmitted = 0;\n    // Transport lease\n    ztu->_common._lease = param->_lease;\n    // Transport link for unicast\n    ztu->_common._link = zl;\n\n    ztu->_peers = _z_transport_peer_unicast_slist_new();\n    ztu->_pending_peers = _z_pending_peers_null();\n    return _Z_RES_OK;\n}\n\nz_result_t _z_unicast_transport_create(_z_transport_t *zt, _z_link_t *zl,\n                                       _z_transport_unicast_establish_param_t *param) {\n    zt->_type = _Z_TRANSPORT_UNICAST_TYPE;\n    _z_transport_unicast_t *ztu = &zt->_transport._unicast;\n    memset(ztu, 0, sizeof(_z_transport_unicast_t));\n\n    z_result_t ret = _z_unicast_transport_create_inner(ztu, zl, param);\n    if (ret != _Z_RES_OK) {\n        // Clear alloc data\n#if Z_FEATURE_MULTI_THREAD == 1\n        _z_mutex_drop(&ztu->_common._mutex_tx);\n        _z_mutex_rec_drop(&ztu->_common._mutex_peer);\n#endif\n        _z_wbuf_clear(&ztu->_common._wbuf);\n        _z_zbuf_clear(&ztu->_common._zbuf);\n    }\n    return ret;\n}\n\nstatic z_result_t _z_unicast_handshake_open(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                            const _z_id_t *local_zid, z_whatami_t mode, _z_sys_net_socket_t *socket) {\n    z_clock_t recv_deadline = z_clock_now();\n    z_clock_advance_ms(&recv_deadline, Z_TRANSPORT_CONNECT_TIMEOUT);\n\n    _z_transport_message_t ism = _z_t_msg_make_init_syn(mode, *local_zid);\n    param->_seq_num_res = ism._body._init._seq_num_res;  // The announced sn resolution\n    param->_req_id_res = ism._body._init._req_id_res;    // The announced req id resolution\n    param->_batch_size = ism._body._init._batch_size;    // The announced batch size\n\n    // Encode and send the message\n    _Z_DEBUG(\"Sending Z_INIT(Syn)\");\n    z_result_t ret = _z_link_send_t_msg(zl, &ism, socket);\n    _z_t_msg_clear(&ism);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    // Try to receive response\n    _z_transport_message_t iam = {0};\n    _Z_RETURN_IF_ERR(_z_link_recv_t_msg(&iam, zl, socket, recv_deadline));\n    if ((_Z_MID(iam._header) != _Z_MID_T_INIT) || !_Z_HAS_FLAG(iam._header, _Z_FLAG_T_INIT_A)) {\n        _z_t_msg_clear(&iam);\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_UNEXPECTED);\n    }\n    param->_remote_whatami = iam._body._init._whatami;\n    _Z_DEBUG(\"Received Z_INIT(Ack)\");\n    // Any of the size parameters in the InitAck must be less or equal than the one in the InitSyn,\n    // otherwise the InitAck message is considered invalid and it should be treated as a\n    // CLOSE message with L==0 by the Initiating Peer -- the recipient of the InitAck message.\n    if (iam._body._init._seq_num_res <= param->_seq_num_res) {\n        param->_seq_num_res = iam._body._init._seq_num_res;\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION);\n        ret = _Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION;\n    }\n    if (iam._body._init._req_id_res <= param->_req_id_res) {\n        param->_req_id_res = iam._body._init._req_id_res;\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION);\n        ret = _Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION;\n    }\n    if (iam._body._init._batch_size <= param->_batch_size) {\n        param->_batch_size = iam._body._init._batch_size;\n    } else {\n        _Z_ERROR_LOG(_Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION);\n        ret = _Z_ERR_TRANSPORT_OPEN_SN_RESOLUTION;\n    }\n#if Z_FEATURE_FRAGMENTATION == 1\n    if (iam._body._init._patch <= ism._body._init._patch) {\n        param->_patch = iam._body._init._patch;\n    } else {\n        // TODO: Use a better error code?\n        _Z_ERROR_LOG(_Z_ERR_GENERIC);\n        ret = _Z_ERR_GENERIC;\n    }\n#endif\n    if (ret != _Z_RES_OK) {\n        _z_t_msg_clear(&iam);\n        return ret;\n    }\n    param->_key_id_res = 0x08 << param->_key_id_res;\n    param->_req_id_res = 0x08 << param->_req_id_res;\n\n    if (mode == Z_WHATAMI_CLIENT) {\n        // The initial SN at TX side\n        z_random_fill(&param->_initial_sn_tx, sizeof(param->_initial_sn_tx));\n        param->_initial_sn_tx = param->_initial_sn_tx & !_z_sn_modulo_mask(param->_seq_num_res);\n    }\n    // Should be pre-initialized in peer mode\n\n    // Initialize the Local and Remote Peer IDs\n    param->_remote_zid = iam._body._init._zid;\n\n    // Create the OpenSyn message\n    _z_zint_t lease = Z_TRANSPORT_LEASE;\n    _z_zint_t initial_sn = param->_initial_sn_tx;\n    _z_slice_t cookie = _z_slice_null();\n    if (!_z_slice_is_empty(&iam._body._init._cookie)) {\n        _z_slice_copy(&cookie, &iam._body._init._cookie);\n    }\n    _z_transport_message_t osm = _z_t_msg_make_open_syn(lease, initial_sn, cookie);\n    _z_t_msg_clear(&iam);\n    // Encode and send the message\n    _Z_DEBUG(\"Sending Z_OPEN(Syn)\");\n    ret = _z_link_send_t_msg(zl, &osm, socket);\n    _z_t_msg_clear(&osm);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    // Try to receive response\n    _z_transport_message_t oam = {0};\n    _Z_RETURN_IF_ERR(_z_link_recv_t_msg(&oam, zl, socket, recv_deadline));\n    if ((_Z_MID(oam._header) != _Z_MID_T_OPEN) || !_Z_HAS_FLAG(oam._header, _Z_FLAG_T_OPEN_A)) {\n        _z_t_msg_clear(&oam);\n        _Z_ERROR_LOG(_Z_ERR_MESSAGE_UNEXPECTED);\n        ret = _Z_ERR_MESSAGE_UNEXPECTED;\n    }\n    // THIS LOG STRING USED IN TEST, change with caution\n    _Z_DEBUG(\"Received Z_OPEN(Ack)\");\n    param->_lease = (oam._body._open._lease < Z_TRANSPORT_LEASE) ? oam._body._open._lease : Z_TRANSPORT_LEASE;\n    // The initial SN at RX side. Initialize the session as we had already received\n    // a message with a SN equal to initial_sn - 1.\n    param->_initial_sn_rx = oam._body._open._initial_sn;\n    _z_t_msg_clear(&oam);\n    return _Z_RES_OK;\n}\n\nz_result_t _z_unicast_handshake_listen(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                       const _z_id_t *local_zid, z_whatami_t mode, _z_sys_net_socket_t *socket) {\n    z_clock_t recv_deadline = z_clock_now();\n    z_clock_advance_ms(&recv_deadline, Z_TRANSPORT_ACCEPT_TIMEOUT);\n    assert(mode == Z_WHATAMI_PEER);\n    // Read t message from link\n    _z_transport_message_t tmsg = {0};\n    z_result_t ret = _z_link_recv_t_msg(&tmsg, zl, socket, recv_deadline);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    // Receive InitSyn\n    if (_Z_MID(tmsg._header) != _Z_MID_T_INIT || _Z_HAS_FLAG(tmsg._header, _Z_FLAG_T_INIT_A)) {\n        _z_t_msg_clear(&tmsg);\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_UNEXPECTED);\n    }\n    _Z_DEBUG(\"Received Z_INIT(Syn)\");\n    // Encode InitAck\n    _z_slice_t cookie = _z_slice_null();\n    _z_transport_message_t iam = _z_t_msg_make_init_ack(mode, *local_zid, cookie);\n\n    // If the new node has less representing capabilities adjust settings\n    if (tmsg._body._init._seq_num_res < iam._body._init._seq_num_res) {\n        _Z_DEBUG(\"Adjusting SN resolution from %u to %u\", iam._body._init._seq_num_res, tmsg._body._init._seq_num_res);\n        iam._body._init._seq_num_res = tmsg._body._init._seq_num_res;\n    }\n    if (tmsg._body._init._req_id_res < iam._body._init._req_id_res) {\n        _Z_DEBUG(\"Adjusting Req ID resolution from %u to %u\", iam._body._init._req_id_res,\n                 tmsg._body._init._req_id_res);\n        iam._body._init._req_id_res = tmsg._body._init._req_id_res;\n    }\n    if (tmsg._body._init._batch_size < iam._body._init._batch_size) {\n        _Z_DEBUG(\"Adjusting Batch Size from %u to %u\", iam._body._init._batch_size, tmsg._body._init._batch_size);\n        iam._body._init._batch_size = tmsg._body._init._batch_size;\n    }\n\n#if Z_FEATURE_FRAGMENTATION == 1\n    if (iam._body._init._patch > tmsg._body._init._patch) {\n        iam._body._init._patch = tmsg._body._init._patch;\n    }\n#endif\n    param->_seq_num_res = iam._body._init._seq_num_res;\n    param->_req_id_res = iam._body._init._req_id_res;\n    param->_batch_size = iam._body._init._batch_size;\n    param->_remote_zid = tmsg._body._init._zid;\n    param->_remote_whatami = tmsg._body._init._whatami;\n    param->_key_id_res = 0x08 << param->_key_id_res;\n    param->_req_id_res = 0x08 << param->_req_id_res;\n    _z_t_msg_clear(&tmsg);\n    // Send InitAck\n    _Z_DEBUG(\"Sending Z_INIT(Ack)\");\n    ret = _z_link_send_t_msg(zl, &iam, socket);\n    _z_t_msg_clear(&iam);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    // Read t message from link\n    ret = _z_link_recv_t_msg(&tmsg, zl, socket, recv_deadline);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    // Receive OpenSyn\n    if (_Z_MID(tmsg._header) != _Z_MID_T_OPEN || _Z_HAS_FLAG(tmsg._header, _Z_FLAG_T_INIT_A)) {\n        _z_t_msg_clear(&tmsg);\n        _Z_ERROR_RETURN(_Z_ERR_MESSAGE_UNEXPECTED);\n    }\n    _Z_DEBUG(\"Received Z_OPEN(Syn)\");\n    // Process message\n    param->_lease = (tmsg._body._open._lease < Z_TRANSPORT_LEASE) ? tmsg._body._open._lease : Z_TRANSPORT_LEASE;\n    param->_initial_sn_rx = tmsg._body._open._initial_sn;\n    _z_t_msg_clear(&tmsg);\n\n    // Encode OpenAck\n    _z_zint_t lease = Z_TRANSPORT_LEASE;\n    _z_zint_t initial_sn = param->_initial_sn_tx;\n    _z_transport_message_t oam = _z_t_msg_make_open_ack(lease, initial_sn);\n\n    // Encode and send the message\n    _Z_DEBUG(\"Sending Z_OPEN(Ack)\");\n    ret = _z_link_send_t_msg(zl, &oam, socket);\n    _z_t_msg_clear(&oam);\n    if (ret != _Z_RES_OK) {\n        return ret;\n    }\n    // Handshake finished\n    return _Z_RES_OK;\n}\n\nz_result_t _z_unicast_open_client(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                  const _z_id_t *local_zid) {\n    return _z_unicast_handshake_open(param, zl, local_zid, Z_WHATAMI_CLIENT, NULL);\n}\n\nz_result_t _z_unicast_open_peer(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                const _z_id_t *local_zid, int peer_op, _z_sys_net_socket_t *socket) {\n    z_result_t ret = _Z_RES_OK;\n\n    // Init sn tx\n    z_random_fill(&param->_initial_sn_tx, sizeof(param->_initial_sn_tx));\n    param->_initial_sn_tx = param->_initial_sn_tx & !_z_sn_modulo_mask(param->_seq_num_res);\n\n    if (peer_op == _Z_PEER_OP_OPEN) {\n        ret = _z_unicast_handshake_open(param, zl, local_zid, Z_WHATAMI_PEER, socket);\n    } else {\n        // Initialize common parameters\n        param->_lease = Z_TRANSPORT_LEASE;\n        param->_batch_size = Z_BATCH_UNICAST_SIZE;\n        param->_seq_num_res = Z_SN_RESOLUTION;\n    }\n    return ret;\n}\n\nz_result_t _z_unicast_send_close(_z_transport_unicast_t *ztu, uint8_t reason, bool link_only) {\n    z_result_t ret = _Z_RES_OK;\n    // Send and clear message\n    _z_transport_message_t cm = _z_t_msg_make_close(reason, link_only);\n    ret = _z_transport_tx_send_t_msg(&ztu->_common, &cm, NULL);\n    _z_t_msg_clear(&cm);\n    return ret;\n}\n\nz_result_t _z_unicast_transport_close(_z_transport_unicast_t *ztu, uint8_t reason) {\n    return _z_unicast_send_close(ztu, reason, false);\n}\n\nvoid _z_unicast_transport_clear(_z_transport_unicast_t *ztu) {\n    _z_transport_peer_unicast_slist_free(&ztu->_peers);\n    _z_pending_peers_clear(&ztu->_pending_peers);\n    _z_transport_common_clear(\n        &ztu->_common);  // free common in the very end, as peers might access the link data in common while being freed\n}\n\n#else\n\nz_result_t _z_unicast_transport_create(_z_transport_t *zt, _z_link_t *zl,\n                                       _z_transport_unicast_establish_param_t *param) {\n    _ZP_UNUSED(zt);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(param);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_unicast_open_client(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                  const _z_id_t *local_zid) {\n    _ZP_UNUSED(param);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(local_zid);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_unicast_open_peer(_z_transport_unicast_establish_param_t *param, const _z_link_t *zl,\n                                const _z_id_t *local_zid, int peer_op, _z_sys_net_socket_t *socket) {\n    _ZP_UNUSED(param);\n    _ZP_UNUSED(zl);\n    _ZP_UNUSED(local_zid);\n    _ZP_UNUSED(peer_op);\n    _ZP_UNUSED(socket);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_unicast_send_close(_z_transport_unicast_t *ztu, uint8_t reason, bool link_only) {\n    _ZP_UNUSED(ztu);\n    _ZP_UNUSED(reason);\n    _ZP_UNUSED(link_only);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nz_result_t _z_unicast_transport_close(_z_transport_unicast_t *ztu, uint8_t reason) {\n    _ZP_UNUSED(ztu);\n    _ZP_UNUSED(reason);\n    _Z_ERROR_RETURN(_Z_ERR_TRANSPORT_NOT_AVAILABLE);\n}\n\nvoid _z_unicast_transport_clear(_z_transport_unicast_t *ztu) { _ZP_UNUSED(ztu); }\n\n#endif  // Z_FEATURE_UNICAST_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/unicast.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico/transport/unicast.h\"\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/link/link.h\"\n#include \"zenoh-pico/transport/common/rx.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n#include \"zenoh-pico/transport/multicast/rx.h\"\n#include \"zenoh-pico/transport/unicast/lease.h\"\n#include \"zenoh-pico/transport/unicast/read.h\"\n#include \"zenoh-pico/transport/unicast/rx.h\"\n#include \"zenoh-pico/transport/utils.h\"\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/uuid.h\"\n\n#if Z_FEATURE_UNICAST_TRANSPORT == 1\nvoid _zp_unicast_fetch_zid(const _z_transport_t *zt, _z_closure_zid_t *callback) {\n    void *ctx = callback->context;\n    _z_transport_peer_unicast_slist_t *l = zt->_transport._unicast._peers;\n    for (; l != NULL; l = _z_transport_peer_unicast_slist_next(l)) {\n        _z_transport_peer_unicast_t *val = _z_transport_peer_unicast_slist_value(l);\n        z_id_t id = val->common._remote_zid;\n        callback->call(&id, ctx);\n    }\n}\n\nvoid _zp_unicast_info_session(const _z_transport_t *zt, _z_config_t *ps, int mode) {\n    uint_fast8_t config_entry = (mode == Z_WHATAMI_CLIENT) ? Z_INFO_ROUTER_PID_KEY : Z_INFO_PEER_PID_KEY;\n    _z_transport_peer_unicast_slist_t *xs = zt->_transport._unicast._peers;\n    while (xs != NULL) {\n        _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(xs);\n        _z_string_t remote_zid_str = _z_id_to_string(&peer->common._remote_zid);\n        _zp_config_insert_string(ps, config_entry, &remote_zid_str);\n        _z_string_clear(&remote_zid_str);\n        xs = _z_transport_peer_unicast_slist_next(xs);\n    }\n}\n\n#else\nvoid _zp_unicast_fetch_zid(const _z_transport_t *zt, _z_closure_zid_t *callback) {\n    _ZP_UNUSED(zt);\n    _ZP_UNUSED(callback);\n}\n\nvoid _zp_unicast_info_session(const _z_transport_t *zt, _z_config_t *ps, int mode) {\n    _ZP_UNUSED(zt);\n    _ZP_UNUSED(ps);\n    _ZP_UNUSED(mode);\n}\n#endif  // Z_FEATURE_UNICAST_TRANSPORT == 1\n"
  },
  {
    "path": "src/transport/utils.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/transport/utils.h\"\n\n#include \"zenoh-pico/protocol/core.h\"\n\n#define U8_MAX 0xFF\n#define U16_MAX 0xFFFF\n#define U32_MAX 0xFFFFFFFF\n#define U64_MAX 0xFFFFFFFFFFFFFFFF\n\n_z_zint_t _z_sn_max(uint8_t bits) {\n    _z_zint_t ret = 0;\n    switch (bits) {\n        case 0x00: {\n            ret = U8_MAX >> 1;\n        } break;\n\n        case 0x01: {\n            ret = U16_MAX >> 2;\n        } break;\n\n        case 0x02: {\n            ret = U32_MAX >> 4;\n        } break;\n\n        case 0x03: {\n            ret = (_z_zint_t)(U64_MAX >> 1);\n        } break;\n\n        default: {\n            // Do nothing\n        } break;\n    }\n\n    return ret;\n}\n\n_z_zint_t _z_sn_half(_z_zint_t sn) { return sn >> 1; }\n\n_z_zint_t _z_sn_modulo_mask(uint8_t bits) {\n    _z_zint_t ret = 0;\n    switch (bits) {\n        case 0x00: {\n            ret = U8_MAX >> 1;\n        } break;\n\n        case 0x01: {\n            ret = U16_MAX >> 2;\n        } break;\n\n        case 0x02: {\n            ret = U32_MAX >> 4;\n        } break;\n\n        case 0x03: {\n            ret = (_z_zint_t)(U64_MAX >> 1);\n        } break;\n\n        default: {\n            // Do nothing\n        } break;\n    }\n\n    return ret;\n}\n\nbool _z_sn_precedes(const _z_zint_t sn_resolution, const _z_zint_t sn_left, const _z_zint_t sn_right) {\n    _z_zint_t distance = (sn_right - sn_left) & sn_resolution;\n    return ((distance <= _z_sn_half(sn_resolution)) && (distance != 0));\n}\n\nbool _z_sn_consecutive(const _z_zint_t sn_resolution, const _z_zint_t sn_left, const _z_zint_t sn_right) {\n    _z_zint_t distance = (sn_right - sn_left) & sn_resolution;\n    return distance == 1;\n}\n\n_z_zint_t _z_sn_increment(const _z_zint_t sn_resolution, const _z_zint_t sn) {\n    _z_zint_t ret = sn + 1;\n    return (ret &= sn_resolution);\n}\n\n_z_zint_t _z_sn_decrement(const _z_zint_t sn_resolution, const _z_zint_t sn) {\n    _z_zint_t ret = sn - 1;\n    return (ret &= sn_resolution);\n}\n\nvoid _z_conduit_sn_list_copy(_z_conduit_sn_list_t *dst, const _z_conduit_sn_list_t *src) {\n    dst->_is_qos = src->_is_qos;\n    if (dst->_is_qos == false) {\n        dst->_val._plain._best_effort = src->_val._plain._best_effort;\n        dst->_val._plain._reliable = src->_val._plain._reliable;\n    } else {\n        for (uint8_t i = 0; i < Z_PRIORITIES_NUM; i++) {\n            dst->_val._qos[i]._best_effort = src->_val._qos[i]._best_effort;\n            dst->_val._qos[i]._reliable = src->_val._qos[i]._reliable;\n        }\n    }\n}\n\nvoid _z_conduit_sn_list_decrement(const _z_zint_t sn_resolution, _z_conduit_sn_list_t *sns) {\n    if (sns->_is_qos == false) {\n        sns->_val._plain._best_effort = _z_sn_decrement(sn_resolution, sns->_val._plain._best_effort);\n        sns->_val._plain._reliable = _z_sn_decrement(sn_resolution, sns->_val._plain._reliable);\n    } else {\n        for (uint8_t i = 0; i < Z_PRIORITIES_NUM; i++) {\n            sns->_val._qos[i]._best_effort = _z_sn_decrement(sn_resolution, sns->_val._qos[i]._best_effort);\n            sns->_val._qos[i]._best_effort = _z_sn_decrement(sn_resolution, sns->_val._qos[i]._reliable);\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/checksum.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/checksum.h\"\n\n#define __CRC_POLYNOMIAL 0x04C11DB7\n\nuint32_t _z_crc32(const uint8_t *message, size_t len) {\n    uint32_t crc = 0xFFFFFFFF;\n    for (size_t i = 0; i < len; i++) {\n        crc = crc ^ (uint32_t)message[i];\n        for (uint8_t j = 0; j < (uint8_t)8; j++) {\n            crc = (crc >> 1) ^ ((uint32_t)__CRC_POLYNOMIAL & (uint32_t)(-(int32_t)(crc & (uint32_t)1)));\n        }\n    }\n    return ~crc;\n}\n"
  },
  {
    "path": "src/utils/encoding.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/encoding.h\"\n\n#include \"zenoh-pico/utils/pointers.h\"\n\nsize_t _z_cobs_encode(const uint8_t *input, size_t input_len, uint8_t *output) {\n    size_t len = input_len;\n    uint8_t *pos = output;\n    uint8_t *codep = output;\n    uint8_t code = 1;\n\n    pos = _z_ptr_u8_offset(pos, 1);\n    for (const uint8_t *byte = input; len != (size_t)0; byte++) {\n        if (*byte != 0x00) {\n            *pos = *byte;\n            pos = _z_ptr_u8_offset(pos, 1);\n            code = code + (uint8_t)1;\n        }\n\n        if (!*byte || (code == (uint8_t)0xFF)) {\n            *codep = code;\n            code = 1;\n            codep = pos;\n            if (!*byte || len) {\n                pos = _z_ptr_u8_offset(pos, 1);\n            }\n        }\n\n        len = len - (size_t)1;\n    }\n    *codep = code;\n\n    return _z_ptr_u8_diff(pos, output);\n}\n\nsize_t _z_cobs_decode(const uint8_t *input, size_t input_len, uint8_t *output) {\n    const uint8_t *byte = input;\n    uint8_t *pos = output;\n\n    uint8_t code = (uint8_t)0xFF;\n    const uint8_t *input_end_ptr = _z_cptr_u8_offset(input, (ptrdiff_t)input_len);\n    for (uint8_t block = (uint8_t)0x00; byte < input_end_ptr; block--) {\n        if (block != (uint8_t)0x00) {\n            *pos = *byte;\n            pos = _z_ptr_u8_offset(pos, 1);\n            byte = _z_cptr_u8_offset(byte, 1);\n        } else {\n            if (code != (uint8_t)0xFF) {\n                *pos = (uint8_t)0x00;\n                pos = _z_ptr_u8_offset(pos, 1);\n            }\n            code = *byte;\n            block = *byte;\n            byte = _z_cptr_u8_offset(byte, 1);\n            if (code == (uint8_t)0x00) {\n                pos = _z_ptr_u8_offset(pos, -1);\n                break;\n            }\n        }\n    }\n\n    return _z_ptr_u8_diff(pos, output);\n}\n"
  },
  {
    "path": "src/utils/json_encoder.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/json_encoder.h\"\n\n#include <inttypes.h>\n#include <math.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n\nz_result_t _z_json_encoder_empty(_z_json_encoder_t *je) {\n    if (je == NULL) {\n        return _Z_ERR_INVALID;\n    }\n    *je = (_z_json_encoder_t){0};\n    _Z_RETURN_IF_ERR(z_bytes_writer_empty(&je->_bw));\n    return _Z_RES_OK;\n}\n\nstatic bool _z_json_encoder_value_allowed(_z_json_encoder_t *je) {\n    if (je->_depth == 0) {\n        return je->_done == false;\n    }\n\n    _z_json_frame_t *frame = &je->_stk[je->_depth - 1];\n    if (frame->kind == _Z_JSON_CTX_OBJ && !frame->expect_value) {\n        return false;\n    }\n    return true;\n}\n\nstatic inline z_result_t _z_json_encoder_putc(_z_json_encoder_t *je, char c) {\n    const uint8_t b = (uint8_t)c;\n    return z_bytes_writer_write_all(z_bytes_writer_loan_mut(&je->_bw), &b, 1);\n}\n\nstatic inline z_result_t _z_json_encoder_putsn(_z_json_encoder_t *je, const char *s, size_t len) {\n    return z_bytes_writer_write_all(z_bytes_writer_loan_mut(&je->_bw), (const uint8_t *)s, len);\n}\n\nstatic z_result_t _z_json_encoder_push(_z_json_encoder_t *je, _z_json_ctx_kind_t kind) {\n    if (je->_depth >= Z_JSON_MAX_DEPTH) {\n        return _Z_ERR_OVERFLOW;\n    }\n\n    je->_stk[je->_depth].kind = kind;\n    je->_stk[je->_depth].expect_value = false;\n    je->_stk[je->_depth].first = true;\n    je->_depth++;\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_json_encoder_pop(_z_json_encoder_t *je) {\n    if (je->_depth == 0) {\n        return _Z_ERR_UNDERFLOW;\n    }\n\n    je->_depth--;\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_json_encoder_finish_value(_z_json_encoder_t *je) {\n    if (je->_depth == 0) {\n        je->_done = true;\n        return _Z_RES_OK;\n    }\n\n    _z_json_frame_t *parent = &je->_stk[je->_depth - 1];\n    if (parent->kind == _Z_JSON_CTX_OBJ) {\n        parent->expect_value = false;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_json_encoder_before_key(_z_json_encoder_t *je) {\n    if (je->_depth == 0) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_json_frame_t *frame = &je->_stk[je->_depth - 1];\n    if (frame->kind != _Z_JSON_CTX_OBJ || frame->expect_value) {\n        return _Z_ERR_INVALID;\n    }\n\n    if (!frame->first) {\n        _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, ','));\n    } else {\n        frame->first = false;\n    }\n    return _Z_RES_OK;\n}\n\nstatic z_result_t _z_json_encoder_before_value(_z_json_encoder_t *je) {\n    if (je->_depth == 0) {\n        // root value: no separator\n        return _Z_RES_OK;\n    }\n\n    _z_json_frame_t *frame = &je->_stk[je->_depth - 1];\n\n    if (frame->kind == _Z_JSON_CTX_ARR) {\n        if (!frame->first) {\n            _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, ','));\n        } else {\n            frame->first = false;\n        }\n        return _Z_RES_OK;\n    }\n\n    // object: value separators are handled at key time, and we must be expecting a value now\n    if (frame->kind == _Z_JSON_CTX_OBJ) {\n        if (!frame->expect_value) {\n            return _Z_ERR_INVALID;\n        }\n        return _Z_RES_OK;\n    }\n\n    return _Z_ERR_INVALID;\n}\n\nz_result_t _z_json_encoder_start_object(_z_json_encoder_t *je) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_push(je, _Z_JSON_CTX_OBJ));\n\n    z_result_t res = _z_json_encoder_putc(je, '{');\n    if (res != _Z_RES_OK) {\n        _z_json_encoder_pop(je);\n    }\n    return res;\n}\n\nz_result_t _z_json_encoder_end_object(_z_json_encoder_t *je) {\n    if (je == NULL || je->_depth == 0) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_json_frame_t *frame = &je->_stk[je->_depth - 1];\n    if (frame->kind != _Z_JSON_CTX_OBJ || frame->expect_value) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, '}'));\n    _Z_RETURN_IF_ERR(_z_json_encoder_pop(je));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_start_array(_z_json_encoder_t *je) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n    _Z_RETURN_IF_ERR(_z_json_encoder_push(je, _Z_JSON_CTX_ARR));\n\n    z_result_t res = _z_json_encoder_putc(je, '[');\n    if (res != _Z_RES_OK) {\n        _z_json_encoder_pop(je);\n    }\n    return res;\n}\n\nz_result_t _z_json_encoder_end_array(_z_json_encoder_t *je) {\n    if (je == NULL || je->_depth == 0) {\n        return _Z_ERR_INVALID;\n    }\n\n    _z_json_frame_t *frame = &je->_stk[je->_depth - 1];\n    if (frame->kind != _Z_JSON_CTX_ARR) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, ']'));\n    _Z_RETURN_IF_ERR(_z_json_encoder_pop(je));\n    return _z_json_encoder_finish_value(je);\n}\n\nstatic z_result_t _z_json_encoder_write_escaped_string(_z_json_encoder_t *je, const char *str, size_t len) {\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, '\"'));\n\n    for (size_t i = 0; i < len; i++) {\n        unsigned char c = (unsigned char)str[i];\n\n        switch (c) {\n            case '\"':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\\\\"\", 2));\n                break;\n            case '\\\\':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\\\\\\", 2));\n                break;\n            case '\\b':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\b\", 2));\n                break;\n            case '\\f':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\f\", 2));\n                break;\n            case '\\n':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\n\", 2));\n                break;\n            case '\\r':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\r\", 2));\n                break;\n            case '\\t':\n                _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"\\\\t\", 2));\n                break;\n            default:\n                if (c < 0x20) {\n                    // Encode other control chars as \\u00XX\n                    char buf[7];\n                    int n = snprintf(buf, sizeof(buf), \"\\\\u%04x\", (unsigned)c);\n                    if (n != 6) {\n                        return _Z_ERR_INVALID;\n                    }\n                    _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, buf, 6));\n                } else {\n                    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, (char)c));\n                }\n                break;\n        }\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, '\"'));\n    return _Z_RES_OK;\n}\n\nz_result_t _z_json_encoder_write_key(_z_json_encoder_t *je, const char *key) {\n    if (je == NULL || key == NULL || je->_depth == 0) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_key(je));\n\n    // Flawfinder: ignore [CWE-126] - Intended to take a null terminated string\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_escaped_string(je, key, strlen(key)));\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, ':'));\n\n    _z_json_frame_t *frame = &je->_stk[je->_depth - 1];\n    frame->expect_value = true;\n\n    return _Z_RES_OK;\n}\n\nz_result_t _z_json_encoder_write_string(_z_json_encoder_t *je, const char *value) {\n    if (je == NULL || value == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    // Flawfinder: ignore [CWE-126] - Intended to take a null terminated string\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_escaped_string(je, value, strlen(value)));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_z_string(_z_json_encoder_t *je, const _z_string_t *value) {\n    if (je == NULL || value == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_write_escaped_string(je, _z_string_data(value), _z_string_len(value)));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_z_slice(_z_json_encoder_t *je, const _z_slice_t *value) {\n    static const char hex[] = \"0123456789abcdef\";\n\n    if (je == NULL || value == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    const uint8_t *p = (const uint8_t *)value->start;\n    size_t len = value->len;\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, '\"'));\n\n    for (size_t i = 0; i < len; i++) {\n        uint8_t b = p[i];\n        char out[2] = {hex[b >> 4], hex[b & 0x0F]};\n        _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, out, 2));\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putc(je, '\"'));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_double(_z_json_encoder_t *je, double value) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n    if (!isfinite(value)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    char buf[32];\n    int n = snprintf(buf, sizeof(buf), \"%.17g\", value);\n    if (n <= 0 || (size_t)n >= sizeof(buf)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, buf, (size_t)n));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_i64(_z_json_encoder_t *je, int64_t value) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    char buf[32];\n    // Flawfinder: ignore (CWE-134) - format string is compile-time constant (C99 PRId64), not attacker-controlled.\n    int n = snprintf(buf, sizeof(buf), \"%\" PRId64, value);\n    if (n <= 0 || (size_t)n >= sizeof(buf)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, buf, (size_t)n));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_u64(_z_json_encoder_t *je, uint64_t value) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    char buf[32];\n    // Flawfinder: ignore (CWE-134) - format string is compile-time constant (C99 PRId64), not attacker-controlled.\n    int n = snprintf(buf, sizeof(buf), \"%\" PRIu64, value);\n    if (n <= 0 || (size_t)n >= sizeof(buf)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, buf, (size_t)n));\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_boolean(_z_json_encoder_t *je, bool value) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    if (value) {\n        _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"true\", 4));\n    } else {\n        _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"false\", 5));\n    }\n\n    return _z_json_encoder_finish_value(je);\n}\n\nz_result_t _z_json_encoder_write_null(_z_json_encoder_t *je) {\n    if (je == NULL || !_z_json_encoder_value_allowed(je)) {\n        return _Z_ERR_INVALID;\n    }\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_before_value(je));\n\n    _Z_RETURN_IF_ERR(_z_json_encoder_putsn(je, \"null\", 4));\n    return _z_json_encoder_finish_value(je);\n}\n\nstatic z_result_t _z_json_encoder_validate(const _z_json_encoder_t *je) {\n    if (je == NULL || je->_depth != 0 || !je->_done) {\n        return _Z_ERR_INVALID;\n    }\n    return _Z_RES_OK;\n}\n\nz_result_t _z_json_encoder_finish(_z_json_encoder_t *je, z_owned_bytes_t *bytes) {\n    if (je == NULL || bytes == NULL) {\n        return _Z_ERR_INVALID;\n    }\n    _Z_RETURN_IF_ERR(_z_json_encoder_validate(je));\n    z_bytes_writer_finish(z_bytes_writer_move(&je->_bw), bytes);\n\n    je->_depth = 0;\n    je->_done = false;\n\n    return _Z_RES_OK;\n}\n\nvoid _z_json_encoder_clear(_z_json_encoder_t *je) {\n    if (je == NULL) {\n        return;\n    }\n    z_bytes_writer_drop(z_bytes_writer_move(&je->_bw));\n    je->_depth = 0;\n    je->_done = false;\n}\n\n#endif  // Z_FEATURE_ADMIN_SPACE == 1\n"
  },
  {
    "path": "src/utils/pointers.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/pointers.h\"\n\nconst uint8_t *_z_cptr_u8_offset(const uint8_t *ptr, const ptrdiff_t off) { return ptr + off; }\nconst char *_z_cptr_char_offset(const char *ptr, const ptrdiff_t off) { return ptr + off; }\n"
  },
  {
    "path": "src/utils/query_params.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/query_params.h\"\n\n#include \"zenoh-pico/utils/pointers.h\"\n\n_z_query_param_t _z_query_params_next(_z_str_se_t *str) {\n    _z_query_param_t result = {0};\n\n    _z_splitstr_t params = {.s = *str, .delimiter = _Z_QUERY_PARAMS_LIST_SEPARATOR};\n    _z_str_se_t param = _z_splitstr_next(&params);\n    str->start = params.s.start;\n    str->end = params.s.end;\n\n    if (param.start != NULL) {\n        _z_splitstr_t kvpair = {.s = param, .delimiter = _Z_QUERY_PARAMS_FIELD_SEPARATOR};\n        _z_str_se_t key = _z_splitstr_next(&kvpair);\n\n        // Set key if length > 0\n        if (_z_ptr_char_diff(key.end, key.start) > 0) {\n            result.key.start = key.start;\n            result.key.end = key.end;\n\n            // Set value if length > 0\n            if (_z_ptr_char_diff(kvpair.s.end, kvpair.s.start) > 0) {\n                result.value.start = kvpair.s.start;\n                result.value.end = kvpair.s.end;\n            }\n        }\n    }\n    return result;\n}\n\nbool _z_parameters_has_anyke(const char *parameters, size_t parameters_len) {\n    if (parameters == NULL || parameters_len == 0) {\n        return false;\n    }\n    const char *start = (const char *)parameters;\n    const char *end = start + parameters_len;\n    while (true) {\n        size_t len = (size_t)(end - start);\n        const char *pos = _z_memmem(start, len, _Z_QUERY_PARAMS_KEY_ANYKE, _Z_QUERY_PARAMS_KEY_ANYKE_LEN);\n        if (pos == NULL) {\n            break;\n        }\n        // Check left boundary: must be start of string or preceded by ';'\n        bool left_ok = (pos == parameters) || (*(pos - 1) == _Z_QUERY_PARAMS_LIST_SEPARATOR[0]);\n        // Check right boundary: must be end of string or followed by ';'\n        bool right_ok = (pos + _Z_QUERY_PARAMS_KEY_ANYKE_LEN == end) ||\n                        (*(pos + _Z_QUERY_PARAMS_KEY_ANYKE_LEN) == _Z_QUERY_PARAMS_LIST_SEPARATOR[0]);\n        if (left_ok && right_ok) {\n            return true;\n        }\n\n        start = pos + _Z_QUERY_PARAMS_KEY_ANYKE_LEN + 1;\n        if (start > end) break;\n    }\n    return false;\n}\n"
  },
  {
    "path": "src/utils/string.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/string.h\"\n\n#include <stdbool.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/pointers.h\"\n\n_z_str_se_t _z_bstrnew(const char *start) { return (_z_str_se_t){.start = start, .end = strchr(start, 0)}; }\n\nchar const *_z_rstrstr(char const *haystack_start, char const *haystack_end, const char *needle_start) {\n    char const *hs = haystack_start;\n    char const *he = haystack_end;\n\n    const char *needle_end = strchr(needle_start, 0);\n    hs = _z_cptr_char_offset(hs, (ptrdiff_t)_z_ptr_char_diff(needle_end, needle_start));\n    char const *result = NULL;\n    while ((result == false) && (he >= hs)) {\n        char found = 1;\n        char const *needle = _z_cptr_char_offset(needle_end, -1);\n        char const *haystack = _z_cptr_char_offset(he, -1);\n        while (needle >= needle_start) {\n            if (needle[0] != haystack[0]) {\n                found = 0;\n                break;\n            }\n\n            needle = _z_cptr_char_offset(needle, -1);\n            haystack = _z_cptr_char_offset(haystack, -1);\n        }\n        if (found == true) {\n            result = he;\n        }\n        he = _z_cptr_char_offset(he, -1);\n    }\n    return result;\n}\n\nchar const *_z_bstrstr(_z_str_se_t haystack, _z_str_se_t needle) {\n    haystack.end = _z_cptr_char_offset(haystack.end, -1 * (ptrdiff_t)_z_ptr_char_diff(needle.end, needle.start));\n    char const *result = NULL;\n    for (; (result == false) && (haystack.start <= haystack.end);\n         haystack.start = _z_cptr_char_offset(haystack.start, 1)) {\n        bool found = true;\n        char const *n = needle.start;\n        char const *h = haystack.start;\n        while (_z_ptr_char_diff(needle.end, n) > 0) {\n            if (n[0] != h[0]) {\n                found = false;\n                break;\n            }\n\n            n = _z_cptr_char_offset(n, 1);\n            h = _z_cptr_char_offset(h, 1);\n        }\n        if (found == true) {\n            result = haystack.start;\n        }\n    }\n    return result;\n}\nchar const *_z_strstr(char const *haystack_start, char const *haystack_end, const char *needle_start) {\n    const char *needle_end = strchr(needle_start, 0);\n    return _z_bstrstr((_z_str_se_t){.start = haystack_start, .end = haystack_end},\n                      (_z_str_se_t){.start = needle_start, .end = needle_end});\n}\nchar const *_z_strstr_skipneedle(char const *haystack_start, char const *haystack_end, const char *needle_start) {\n    const char *needle_end = strchr(needle_start, 0);\n    return _z_bstrstr_skipneedle((_z_str_se_t){.start = haystack_start, .end = haystack_end},\n                                 (_z_str_se_t){.start = needle_start, .end = needle_end});\n}\n\nchar const *_z_bstrstr_skipneedle(_z_str_se_t haystack, _z_str_se_t needle) {\n    char const *result = _z_bstrstr(haystack, needle);\n    if (result != NULL) {\n        result = _z_cptr_char_offset(result, (ptrdiff_t)_z_ptr_char_diff(needle.end, needle.start));\n    }\n    return result;\n}\n\nbool _z_splitstr_is_empty(const _z_splitstr_t *src) { return src->s.start == NULL; }\n_z_str_se_t _z_splitstr_next(_z_splitstr_t *str) {\n    _z_str_se_t result = str->s;\n    if (str->s.start != NULL) {\n        result.end = _z_strstr(result.start, result.end, str->delimiter);\n        if (result.end == NULL) {\n            result.end = str->s.end;\n        }\n        if (result.end == str->s.end) {\n            str->s = (_z_str_se_t){.start = NULL, .end = NULL};\n        } else {\n            str->s.start = _z_cptr_char_offset(result.end, (ptrdiff_t)strlen(str->delimiter));\n        }\n    }\n    return result;\n}\n_z_str_se_t _z_splitstr_split_once(_z_splitstr_t src, _z_str_se_t *next) {\n    *next = _z_splitstr_next(&src);\n    return src.s;\n}\n\n_z_str_se_t _z_splitstr_nextback(_z_splitstr_t *str) {\n    _z_str_se_t result = str->s;\n    if (str->s.start != NULL) {\n        result.start = _z_rstrstr(result.start, result.end, str->delimiter);\n        if (result.start == NULL) {\n            result.start = str->s.start;\n        }\n        if (result.start == str->s.start) {\n            str->s = (_z_str_se_t){.start = NULL, .end = NULL};\n        } else {\n            str->s.end = _z_cptr_char_offset(result.start, -1 * (ptrdiff_t)strlen(str->delimiter));\n        }\n    }\n    return result;\n}\n\nsize_t _z_strcnt(char const *haystack_start, const char *harstack_end, const char *needle_start) {\n    char const *hs = haystack_start;\n\n    size_t result = 0;\n    while (hs != NULL) {\n        result = result + (size_t)1;\n        hs = _z_strstr_skipneedle(hs, harstack_end, needle_start);\n    }\n    return result;\n}\n\nsize_t _z_str_startswith(const char *s, const char *needle) {\n    size_t i = 0;\n    for (; needle[i] != '\\0'; i++) {\n        if (s[i] != needle[i]) {\n            i = 0;\n            break;\n        }\n    }\n    return i;\n}\n\nbool _z_str_se_atoui(const _z_str_se_t *str, uint32_t *result) {\n    uint32_t value = 0;\n    size_t len = _z_ptr_char_diff(str->end, str->start);\n\n    if (len == 0 || len > 10) {\n        return false;\n    }\n\n    const uint32_t threshold = UINT32_MAX / 10;\n    const uint32_t rem_threshold = UINT32_MAX % 10;\n\n    for (size_t i = 0; i < len; i++) {\n        const char c = str->start[i];\n        if (c < '0' || c > '9') {\n            return false;\n        }\n        uint32_t digit = (uint32_t)(c - '0');\n\n        if (value > threshold || (value == threshold && digit > rem_threshold)) {\n            return false;\n        }\n        value = value * 10 + digit;\n    }\n\n    *result = value;\n    return true;\n}\n\nbool _z_str_parse_i32(const char *s, int32_t *out) {\n    bool is_negative = false;\n    uint32_t value = 0;\n    const uint32_t limit = ((uint32_t)INT32_MAX) + 1u;\n\n    if (s == NULL || *s == '\\0') {\n        return false;\n    }\n\n    if (*s == '-' || *s == '+') {\n        is_negative = *s == '-';\n        s++;\n    }\n\n    if (*s == '\\0') {\n        return false;\n    }\n\n    uint32_t max_value = is_negative ? limit : (uint32_t)INT32_MAX;\n    while (*s != '\\0') {\n        if (*s < '0' || *s > '9') {\n            return false;\n        }\n\n        uint32_t digit = (uint32_t)(*s - '0');\n        if (value > ((max_value - digit) / 10u)) {\n            return false;\n        }\n\n        value = (value * 10u) + digit;\n        s++;\n    }\n\n    if (is_negative) {\n        *out = (value == limit) ? INT32_MIN : -(int32_t)value;\n    } else {\n        *out = (int32_t)value;\n    }\n    return true;\n}\n\nbool _z_str_parse_bool(const char *s, bool *out) {\n    if (s == NULL) {\n        return false;\n    }\n\n    if (strcmp(s, \"true\") == 0) {\n        *out = true;\n        return true;\n    }\n    if (strcmp(s, \"false\") == 0) {\n        *out = false;\n        return true;\n    }\n\n    return false;\n}\n\nvoid *_z_memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) {\n    if (haystack == NULL || needle == NULL || haystack_len < needle_len) {\n        return NULL;\n    }\n\n    const uint8_t *h = haystack;\n    const uint8_t *h_end = h + haystack_len;\n    const uint8_t *n = needle;\n\n    while (h <= h_end - needle_len) {\n        if (memcmp(h, n, needle_len) == 0) {\n            return (void *)h;\n        }\n        h++;\n    }\n    return NULL;\n}\n"
  },
  {
    "path": "src/utils/time_range.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/time_range.h\"\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/logging.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n/**\n * Parses a _z_str_se_t as a duration.\n * Expected format is a double in seconds, or \"<double><unit>\" where <unit> is:\n *  - 'u'  => microseconds\n *  - \"ms\" => milliseconds\n *  - 's' => seconds\n *  - 'm' => minutes\n *  - 'h' => hours\n *  - 'd' => days\n *  - 'w' => weeks\n *\n * Returns true if the duration is successfully parsed, false otherwise.\n * If true, duration will contain the parsed duration on return.\n */\nstatic bool _z_time_range_parse_duration(const _z_str_se_t *bound, double *duration) {\n    size_t len = _z_ptr_char_diff(bound->end, bound->start);\n    if (len == 0) {\n        return false;\n    }\n\n    double multiplier = 1.0;\n    switch (*_z_cptr_char_offset(bound->end, -1)) {\n        case 'u':\n            multiplier = _Z_TIME_RANGE_U_TO_SECS;\n            len--;\n            break;\n        case 's':\n            if (len > 1 && *_z_cptr_char_offset(bound->end, -2) == 'm') {\n                multiplier = _Z_TIME_RANGE_MS_TO_SECS;\n                len--;\n            }\n            len--;\n            break;\n        case 'm':\n            multiplier = _Z_TIME_RANGE_M_TO_SECS;\n            len--;\n            break;\n        case 'h':\n            multiplier = _Z_TIME_RANGE_H_TO_SECS;\n            len--;\n            break;\n        case 'd':\n            multiplier = _Z_TIME_RANGE_D_TO_SECS;\n            len--;\n            break;\n        case 'w':\n            multiplier = _Z_TIME_RANGE_W_TO_SECS;\n            len--;\n            break;\n    }\n\n    // String contains unit only\n    if (len == 0) {\n        return false;\n    }\n\n    char *buf = z_malloc(len + 1);\n    if (buf == NULL) {\n        _Z_ERROR(\"Failed to allocate buffer.\");\n        return false;\n    }\n    size_t offset = 0;\n    if (!_z_memcpy_checked(buf, len + 1, &offset, bound->start, len)) {\n        z_free(buf);\n        return false;\n    }\n    buf[len] = '\\0';\n    char *err;\n    double value = strtod(bound->start, &err);\n    z_free(buf);\n    if (value == 0 && *err != '\\0') {\n        return false;\n    }\n    value *= multiplier;\n\n    // Check for overflow\n    if (isinf(value)) {\n        return false;\n    }\n\n    *duration = value;\n    return true;\n}\n\nstatic bool _z_time_range_parse_time_bound(_z_str_se_t *str, bool inclusive, _z_time_bound_t *bound) {\n    size_t len = _z_ptr_char_diff(str->end, str->start);\n    if (len == 0) {\n        bound->bound = _Z_TIME_BOUND_UNBOUNDED;\n        return true;\n    } else if (len >= 5) {\n        bound->bound = inclusive ? _Z_TIME_BOUND_INCLUSIVE : _Z_TIME_BOUND_EXCLUSIVE;\n\n        if (*str->start == 'n' && *_z_cptr_char_offset(str->start, 1) == 'o' &&\n            *_z_cptr_char_offset(str->start, 2) == 'w' && *_z_cptr_char_offset(str->start, 3) == '(' &&\n            *_z_cptr_char_offset(str->end, -1) == ')') {\n            if (len == 5) {\n                bound->now_offset = 0;\n            } else {\n                _z_str_se_t duration = {.start = _z_cptr_char_offset(str->start, 4),\n                                        .end = _z_cptr_char_offset(str->end, -1)};\n\n                if (!_z_time_range_parse_duration(&duration, &bound->now_offset)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n        // TODO: Add support for RFC3339 timestamps\n    }\n    return false;\n}\n\nbool _z_time_range_from_str(const char *str, size_t len, _z_time_range_t *range) {\n    // Minimum length is 4 \"[..]\"\n    if (len < 4) {\n        return false;\n    }\n\n    bool inclusive_start;\n    switch (str[0]) {\n        case '[':\n            inclusive_start = true;\n            break;\n        case ']':\n            inclusive_start = false;\n            break;\n        default:\n            return false;\n    }\n\n    bool inclusive_end;\n    switch (str[len - 1]) {\n        case '[':\n            inclusive_end = false;\n            break;\n        case ']':\n            inclusive_end = true;\n            break;\n        default:\n            return false;\n    }\n\n    // Search for '..'\n    const char *separator =\n        _z_strstr(_z_cptr_char_offset(str, 1), _z_cptr_char_offset(str, (ptrdiff_t)(len - 1)), \"..\");\n    if (separator != NULL) {\n        _z_str_se_t start_str = {.start = _z_cptr_char_offset(str, 1), .end = separator};\n        _z_str_se_t end_str = {.start = _z_cptr_char_offset(separator, 2),\n                               .end = _z_cptr_char_offset(str, (ptrdiff_t)(len - 1))};\n\n        if (!_z_time_range_parse_time_bound(&start_str, inclusive_start, &range->start) ||\n            !_z_time_range_parse_time_bound(&end_str, inclusive_end, &range->end)) {\n            return false;\n        }\n    } else {\n        // Search for ';'\n        separator = _z_strstr(_z_cptr_char_offset(str, 1), _z_cptr_char_offset(str, (ptrdiff_t)(len - 1)), \";\");\n        if (separator == NULL) {\n            return false;\n        }\n\n        _z_str_se_t start_str = {.start = _z_cptr_char_offset(str, 1), .end = separator};\n        _z_str_se_t end_str = {.start = _z_cptr_char_offset(separator, 1),\n                               .end = _z_cptr_char_offset(str, (ptrdiff_t)(len - 1))};\n\n        if (!_z_time_range_parse_time_bound(&start_str, inclusive_start, &range->start) ||\n            range->start.bound == _Z_TIME_BOUND_UNBOUNDED) {\n            return false;\n        }\n\n        double duration;\n        if (!_z_time_range_parse_duration(&end_str, &duration)) {\n            return false;\n        }\n        range->end.bound = inclusive_end ? _Z_TIME_BOUND_INCLUSIVE : _Z_TIME_BOUND_EXCLUSIVE;\n        range->end.now_offset = range->start.now_offset + duration;\n    }\n\n    return true;\n}\n\nstatic bool _z_time_bound_delim_to_char(const _z_time_bound_t *bound, bool is_start, char *delim) {\n    if (bound == NULL || delim == NULL) {\n        return false;\n    }\n    switch (bound->bound) {\n        case _Z_TIME_BOUND_INCLUSIVE:\n            *delim = is_start ? '[' : ']';\n            break;\n        case _Z_TIME_BOUND_EXCLUSIVE:\n            *delim = is_start ? ']' : '[';\n            break;\n        case _Z_TIME_BOUND_UNBOUNDED:\n            *delim = is_start ? '[' : ']';\n            break;\n        default:\n            return false;\n    }\n    return true;\n}\n\nbool _z_time_bound_to_str(const _z_time_bound_t *bound, char *buf, size_t buf_len) {\n    if (bound == NULL || buf == NULL || buf_len < 1) {\n        return false;  // Not enough space for at least '\\0'\n    }\n\n    if (bound->bound == _Z_TIME_BOUND_UNBOUNDED) {\n        buf[0] = '\\0';\n        return true;\n    }\n\n    size_t pos = 0;\n\n    // Ensure enough space for \"now(\"\n    if (buf_len < 4) {\n        return false;\n    }\n    buf[pos++] = 'n';\n    buf[pos++] = 'o';\n    buf[pos++] = 'w';\n    buf[pos++] = '(';\n\n    if (bound->now_offset != 0.0) {\n        int len = snprintf(&buf[pos], buf_len - pos, \"%.17f\", bound->now_offset);\n        if (len < 0 || (size_t)len >= buf_len - pos) {\n            return false;  // Not enough space for the formatted string\n        }\n\n        // Trim trailing zeros and decimal point if no fractions remain\n        char *start = &buf[pos];\n        char *dot = strchr(start, '.');\n        if (dot != NULL) {\n            size_t remaining = buf_len - pos;\n            size_t str_len = strnlen(start, remaining);\n            if (str_len == remaining) {\n                // Null terminator not found within bounds\n                return false;\n            }\n            char *end = start + str_len - 1;\n            while (end > dot && *end == '0') {\n                *end-- = '\\0';\n            }\n            if (end == dot) {\n                *end = '\\0';  // remove trailing '.'\n            }\n        }\n\n        size_t remaining = buf_len - pos;\n        size_t str_len = strnlen(start, remaining);\n        if (str_len == remaining) {\n            // Null terminator not found within bounds\n            return false;\n        }\n        pos += str_len;\n\n        if (buf_len - pos < 1) {\n            return false;  // Not enough space for 's'\n        }\n        buf[pos++] = 's';\n    }\n\n    if (buf_len - pos < 2) {\n        return false;  // Not enough space for \")\\0\"\n    }\n\n    buf[pos++] = ')';\n    buf[pos++] = '\\0';\n    return true;\n}\n\nbool _z_time_range_to_str(const _z_time_range_t *range, char *buf, size_t buf_len) {\n    size_t pos = 0;\n\n    if (range == NULL || buf == NULL || buf_len < 3) {\n        return false;  // Not enough space for at least \"[]\"\n    }\n\n    if (!_z_time_bound_delim_to_char(&range->start, true, &buf[pos++])) {\n        return false;  // Invalid bound delimiter\n    }\n\n    if (range->start.bound == _Z_TIME_BOUND_INCLUSIVE || range->start.bound == _Z_TIME_BOUND_EXCLUSIVE) {\n        if (!_z_time_bound_to_str(&range->start, &buf[pos], buf_len - pos)) {\n            return false;\n        }\n        size_t remaining = buf_len - pos;\n        size_t str_len = strnlen(&buf[pos], remaining);\n        if (str_len == remaining) {\n            // Null terminator not found within bounds\n            return false;\n        }\n        pos += str_len;\n    }\n\n    if (buf_len - pos < 2) {\n        return false;  // Not enough space for \"..\"\n    }\n    buf[pos++] = '.';\n    buf[pos++] = '.';\n\n    if (range->end.bound == _Z_TIME_BOUND_INCLUSIVE || range->end.bound == _Z_TIME_BOUND_EXCLUSIVE) {\n        if (!_z_time_bound_to_str(&range->end, &buf[pos], buf_len - pos)) {\n            return false;\n        }\n        size_t remaining = buf_len - pos;\n        size_t str_len = strnlen(&buf[pos], remaining);\n        if (str_len == remaining) {\n            // Null terminator not found within bounds\n            return false;\n        }\n        pos += str_len;\n    }\n\n    if (buf_len - pos < 2) {\n        return false;  // Not enough space for end delimiter and '\\0'\n    }\n    if (!_z_time_bound_delim_to_char(&range->end, false, &buf[pos++])) {\n        return false;  // Invalid bound delimiter\n    }\n    buf[pos] = '\\0';\n\n    return true;\n}\n\n_z_ntp64_t _z_time_range_resolve_offset(_z_ntp64_t base, double offset) {\n    const double FRAC_PER_SEC = 4294967296.0;  // 2^32\n\n    if (offset == 0.0) {\n        return base;\n    }\n\n    double abs_offset = fabs(offset);\n    uint32_t offset_seconds = (uint32_t)abs_offset;\n    double fractions = abs_offset - (double)offset_seconds;\n    uint32_t offset_fractions = (uint32_t)(fractions * FRAC_PER_SEC + 0.5);\n    _z_ntp64_t offset_ntp = ((uint64_t)offset_seconds << 32) | offset_fractions;\n\n    if (offset < 0.0) {\n        return base - offset_ntp;\n    } else {\n        return base + offset_ntp;\n    }\n}\n\nbool _z_time_range_contains_at_time(const _z_time_range_t *range, const _z_ntp64_t timestamp, const _z_ntp64_t time) {\n    if (range == NULL) {\n        return false;\n    }\n\n    if (range->start.bound != _Z_TIME_BOUND_UNBOUNDED) {\n        _z_ntp64_t start = _z_time_range_resolve_offset(time, range->start.now_offset);\n        if (range->start.bound == _Z_TIME_BOUND_INCLUSIVE) {\n            if (start > timestamp) {\n                return false;\n            }\n        } else {  // EXCLUSIVE\n            if (start >= timestamp) {\n                return false;\n            }\n        }\n    }\n\n    if (range->end.bound != _Z_TIME_BOUND_UNBOUNDED) {\n        _z_ntp64_t end = _z_time_range_resolve_offset(time, range->end.now_offset);\n        if (range->end.bound == _Z_TIME_BOUND_INCLUSIVE) {\n            if (end < timestamp) {\n                return false;\n            }\n        } else {  // EXCLUSIVE\n            if (end <= timestamp) {\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/utils/uuid.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/utils/uuid.h\"\n\n#include <ctype.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/utils/pointers.h\"\n\n#define UUID_SIZE 16\n\nvoid _z_uuid_to_bytes(uint8_t *bytes, const char *uuid_str) {\n    uint8_t n_dash = 0;\n    for (uint8_t i = 0; i < 32; i += 2) {\n        if (i == 8 || i == 12 || i == 16 || i == 18) {\n            n_dash += 1;\n        }\n        char val[5] = {'0', 'x', uuid_str[i + n_dash], uuid_str[i + 1 + n_dash], '\\0'};\n        *bytes = (uint8_t)strtoul(val, NULL, 0);\n        bytes = _z_ptr_u8_offset(bytes, 1);\n    }\n}\n\n_z_string_t _z_id_to_string(const _z_id_t *id) {\n    _z_slice_t buf = _z_slice_alias_buf(id->id, sizeof(id->id));\n    return _z_string_convert_bytes_le(&buf);\n}\n\n_z_id_t _z_id_from_string(const _z_string_t *str) {\n    if (str == NULL) {\n        return _z_id_empty();\n    }\n\n    const char *s = _z_string_data(str);\n    size_t len = _z_string_len(str);\n\n    // Expect exactly ZENOH_ID_SIZE * 2 lowercase hex characters\n    if (s == NULL || len != ZENOH_ID_SIZE * 2) {\n        return _z_id_empty();\n    }\n\n    z_id_t id;\n    for (size_t i = 0; i < ZENOH_ID_SIZE; i++) {\n        size_t offset = (ZENOH_ID_SIZE - 1 - i) * 2;\n        char high = s[offset];\n        char low = s[offset + 1];\n\n        if (!isxdigit(high) || !isxdigit(low) || isupper((unsigned char)high) || isupper((unsigned char)low)) {\n            return _z_id_empty();\n        }\n\n        char byte_str[3] = {high, low, '\\0'};\n        unsigned long byte_val = strtoul(byte_str, NULL, 16);\n        id.id[i] = (uint8_t)byte_val;\n    }\n    return id;\n}\n"
  },
  {
    "path": "tests/api.sh",
    "content": "#!/bin/sh\n#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\nTESTBIN=\"$1\"\nTESTDIR=$(dirname \"$0\")\n\nif [ \"$OSTYPE\" = \"msys\" ]; then\n  TESTBIN=\"$TESTDIR/Debug/$TESTBIN.exe\"\nelse\n  TESTBIN=\"./$TESTBIN\"\nfi\n\ncd \"$TESTDIR\"|| exit\n\necho \"------------------ Running test $TESTBIN -------------------\"\n\nsleep 5\n\nif [ ! -f zenohd ]; then\n    git clone https://github.com/eclipse-zenoh/zenoh.git zenoh-git\n    cd zenoh-git || exit\n    if [ -n \"$ZENOH_BRANCH\" ]; then\n        git switch \"$ZENOH_BRANCH\"\n    fi\n    rustup show\n    cargo build --lib --bin zenohd\n    cp ./target/debug/zenohd \"$TESTDIR\"/\n    cd \"$TESTDIR\"|| exit\nfi\n\nchmod +x zenohd\n\nLOCATORS=\"tcp/127.0.0.1:7447\"\nfor LOCATOR in $(echo \"$LOCATORS\" | xargs); do\n    sleep 1\n\n    echo \"> Running zenohd ... $LOCATOR\"\n    RUST_LOG=debug ./zenohd --plugin-search-dir \"$TESTDIR/zenoh-git/target/debug\" -l \"$LOCATOR\" > zenohd.\"$1\".log 2>&1 &\n    ZPID=$!\n\n    sleep 5\n\n    echo \"> Running $TESTBIN ...\"\n    \"$TESTBIN\" \"$LOCATOR\"\n    RETCODE=$?\n\n    echo \"> Stopping zenohd ...\"\n    kill -9 \"$ZPID\"\n\n    sleep 1\n\n    echo \"> Logs of zenohd ...\"\n    cat zenohd.\"$1\".log\n\n    [ \"$RETCODE\" -lt 0 ] && exit \"$RETCODE\"\ndone\n\necho \"> Done ($RETCODE).\"\nexit \"$RETCODE\"\n"
  },
  {
    "path": "tests/attachment.py",
    "content": "import argparse\nimport os\nfrom signal import SIGINT\nimport subprocess\nimport sys\nimport time\nimport re\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\n\n\ndef pub_and_sub():\n    print(\"*** Pub & sub test ***\")\n    test_status = 0\n\n    # Expected z_pub output & status\n    z_pub_expected_status = 0\n    z_pub_expected_output = '''Opening session...\nDeclaring publisher for 'demo/example/zenoh-pico-pub'...\nPress CTRL-C to quit...\nPutting Data ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')...'''\n\n    # Expected z_sub output & status\n    z_sub_expected_status = 0\n    z_sub_expected_output = '''Opening session...\nDeclaring Subscriber on 'demo/example/**'...\nPress CTRL-C to quit...\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')\n    with encoding: zenoh/string;utf8\n    with timestamp: \n    with attachment:\n     0: source, C\n     1: index, 0\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')\n    with encoding: zenoh/string;utf8\n    with timestamp: \n    with attachment:\n     0: source, C\n     1: index, 1\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')\n    with encoding: zenoh/string;utf8\n    with timestamp: \n    with attachment:\n     0: source, C\n     1: index, 2\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')\n    with encoding: zenoh/string;utf8\n    with timestamp: \n    with attachment:\n     0: source, C\n     1: index, 3\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')\n    with encoding: zenoh/string;utf8\n    with timestamp: \n    with attachment:\n     0: source, C\n     1: index, 4'''\n\n    print(\"Start subscriber\")\n    # Start z_sub in the background\n    z_sub_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub_attachment -n 5\"\n\n    z_sub_process = subprocess.Popen(\n        z_sub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True\n    )\n\n    # Introduce a delay to ensure z_sub starts\n    time.sleep(2)\n\n    print(\"Start publisher\")\n    # Start z_pub\n    z_pub_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub_attachment -n 5\"\n    z_pub_process = subprocess.Popen(\n        z_pub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True\n    )\n\n    # Wait for z_pub to finish\n    z_pub_process.wait()\n\n    print(\"Stop subscriber\")\n    time.sleep(2)\n    if z_sub_process.poll() is None:\n        # send SIGINT to group\n        z_sub_process_gid = os.getpgid(z_sub_process.pid)\n        os.killpg(z_sub_process_gid, SIGINT)\n\n    # Wait for z_sub to finish\n    z_sub_process.wait()\n\n    print(\"Check publisher status & output\")\n    # Check the exit status of z_pub\n    z_pub_status = z_pub_process.returncode\n    if z_pub_status == z_pub_expected_status:\n        print(\"z_pub status valid\")\n    else:\n        print(f\"z_pub status invalid, expected: {z_pub_expected_status}, received: {z_pub_status}\")\n        test_status = 1\n\n    # Check output of z_pub\n    z_pub_output = z_pub_process.stdout.read()\n    if z_pub_expected_output in z_pub_output:\n        print(\"z_pub output valid\")\n    else:\n        print(\"z_pub output invalid:\")\n        print(f\"Expected: \\\"{z_pub_expected_output}\\\"\")\n        print(f\"Received: \\\"{z_pub_output}\\\"\")\n        test_status = 1\n\n    print(\"Check subscriber status & output\")\n    # Check the exit status of z_sub\n    z_sub_status = z_sub_process.returncode\n    if z_sub_status == z_sub_expected_status:\n        print(\"z_sub status valid\")\n    else:\n        print(f\"z_sub status invalid, expected: {z_sub_expected_status}, received: {z_sub_status}\")\n        test_status = 1\n\n    # Check output of z_sub\n    z_sub_output = re.sub(r'    with timestamp: \\d+\\n', '    with timestamp: \\n', z_sub_process.stdout.read())\n    if z_sub_expected_output in z_sub_output:\n        print(\"z_sub output valid\")\n    else:\n        print(\"z_sub output invalid:\")\n        print(f\"Expected: \\\"{z_sub_expected_output}\\\"\")\n        print(f\"Received: \\\"{z_sub_output}\\\"\")\n        test_status = 1\n    # Return value\n    return test_status\n\n\ndef query_and_queryable():\n    print(\"*** Query & queryable test ***\")\n    test_status = 0\n\n    # Expected z_query output & status\n\n    z_query_expected_status = 0\n    z_query_expected_output = \"\"\"Opening session...\nSending Query 'demo/example/**'...\n>> Received ('demo/example/**': 'Queryable from Pico!')\n    with encoding: zenoh/string;utf8\n    with attachment:\n     0: reply_key, reply_value\n>> Received query final notification\"\"\"\n\n    # Expected z_queryable output & status\n    z_queryable_expected_status = 0\n    z_queryable_expected_output = \"\"\"Opening session...\nCreating Queryable on 'demo/example/zenoh-pico-queryable'...\nPress CTRL-C to quit...\n >> [Queryable handler] Received Query 'demo/example/**'\n    with encoding: zenoh/string;utf8\n    with attachment:\n     0: test_key, test_value\"\"\"\n\n    print(\"Start queryable\")\n    # Start z_queryable in the background\n    z_queryable_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_queryable_attachment -n 1\"\n    z_queryable_process = subprocess.Popen(\n        z_queryable_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        text=True,\n    )\n\n    # Introduce a delay to ensure z_queryable starts\n    time.sleep(2)\n\n    print(\"Start query\")\n    # Start z_query\n    z_query_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_get_attachment\"\n    z_query_process = subprocess.Popen(\n        z_query_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        text=True,\n    )\n\n    # Wait for z_query to finish\n    z_query_process.wait()\n\n    print(\"Stop queryable\")\n    time.sleep(2)\n    if z_queryable_process.poll() is None:\n        # send SIGINT to group\n        z_quaryable_process_gid = os.getpgid(z_queryable_process.pid)\n        os.killpg(z_quaryable_process_gid, SIGINT)\n\n    # Wait for z_queryable to finish\n    z_queryable_process.wait()\n\n    print(\"Check query status & output\")\n    # Check the exit status of z_query\n    z_query_status = z_query_process.returncode\n    if z_query_status == z_query_expected_status:\n        print(\"z_query status valid\")\n    else:\n        print(f\"z_query status invalid, expected: {z_query_expected_status},\" f\" received: {z_query_status}\")\n        test_status = 1\n\n    # Check output of z_query\n    z_query_output = z_query_process.stdout.read()\n    if z_query_expected_output in z_query_output:\n        print(\"z_query output valid\")\n    else:\n        print(\"z_query output invalid:\")\n        print(f'Expected: \"{z_query_expected_output}\"')\n        print(f'Received: \"{z_query_output}\"')\n        test_status = 1\n\n    print(\"Check queryable status & output\")\n    # Check the exit status of z_queryable\n    z_queryable_status = z_queryable_process.returncode\n    if z_queryable_status == z_queryable_expected_status:\n        print(\"z_queryable status valid\")\n    else:\n        print(f\"z_queryable status invalid, expected: {z_queryable_expected_status},\" f\" received: {z_queryable_status}\")\n        test_status = 1\n\n    # Check output of z_queryable\n    z_queryable_output = z_queryable_process.stdout.read()\n    if z_queryable_expected_output in z_queryable_output:\n        print(\"z_queryable output valid\")\n    else:\n        print(\"z_queryable output invalid:\")\n        print(f'Expected: \"{z_queryable_expected_output}\"')\n        print(f'Received: \"{z_queryable_output}\"')\n        test_status = 1\n    # Return status\n    return test_status\n\n\nif __name__ == \"__main__\":\n    EXIT_STATUS = 0\n\n    # Test pub and sub examples\n    if pub_and_sub() == 1:\n        EXIT_STATUS = 1\n    # Test query and queryable examples\n    if query_and_queryable() == 1:\n        EXIT_STATUS = 1\n    # Exit\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/connection_restore.py",
    "content": "import subprocess\nimport time\nimport sys\nimport os\nimport threading\n\nROUTER_INIT_TIMEOUT_S = 3\nWAIT_MESSAGE_TIMEOUT_S = 15\nDISCONNECT_MESSAGES = [\"Closing session because it has expired\", \"Send keep alive failed\"]\nCONNECT_MESSAGES = [\"Z_OPEN(Ack)\"]\nLIVELINESS_TOKEN_ALIVE_MESSAGES = [\"[LivelinessSubscriber] New alive token\"]\nLIVELINESS_TOKEN_DROP_MESSAGES = [\"[LivelinessSubscriber] Dropped token\"]\nSUBSCRIBER_RECEIVE_MESSAGES = [\"[Subscriber] Received\"]\nROUTER_ERROR_MESSAGE = \"ERROR\"\nWRITE_FILTER_OFF_MESSAGE = \"write filter state: 1\"\nWRITE_FILTER_ACTIVE_MESSAGE = \"write filter state: 0\"\nZENOH_PORT = \"7447\"\n\nROUTER_ARGS = ['-l', f'tcp/0.0.0.0:{ZENOH_PORT}', '--no-multicast-scouting']\nSTDBUF_CMD = [\"stdbuf\", \"-o0\"]\n\nDIR_EXAMPLES = \"build/examples\"\nACTIVE_CLIENT_COMMAND = STDBUF_CMD + [f'{DIR_EXAMPLES}/z_pub', '-e', f'tcp/127.0.0.1:{ZENOH_PORT}']\nPASSIVE_CLIENT_COMMAND = STDBUF_CMD + [f'{DIR_EXAMPLES}/z_sub', '-e', f'tcp/127.0.0.1:{ZENOH_PORT}']\n\nLIVELINESS_CLIENT_COMMAND = STDBUF_CMD + [f'{DIR_EXAMPLES}/z_liveliness', '-e', f'tcp/127.0.0.1:{ZENOH_PORT}']\nLIVELINESS_SUB_CLIENT_COMMAND = STDBUF_CMD + [f'{DIR_EXAMPLES}/z_sub_liveliness', '-h', '-e', f'tcp/127.0.0.1:{ZENOH_PORT}']\n\nLIBASAN_PATH = subprocess.run([\"gcc\", \"-print-file-name=libasan.so\"], stdout=subprocess.PIPE, text=True, check=True).stdout.strip()\n\n\ndef run_process(command, output_collector, process_list):\n    env = os.environ.copy()\n    env[\"RUST_LOG\"] = \"trace\"\n    if LIBASAN_PATH:\n        env[\"LD_PRELOAD\"] = LIBASAN_PATH\n\n    print(f\"Run {command}\")\n    process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=env)\n    process_list.append(process)\n    for line in iter(process.stdout.readline, ''):\n        print(f\"-- [{process.pid}]:\", line.strip())\n        output_collector.append(line.strip())\n    process.stdout.close()\n    process.wait()\n\n\ndef run_background(command, output_collector, process_list):\n    thread = threading.Thread(target=run_process, args=(command, output_collector, process_list))\n    thread.start()\n\n\ndef terminate_processes(process_list):\n    for process in process_list:\n        process.terminate()\n        try:\n            process.wait(timeout=5)\n        except subprocess.TimeoutExpired:\n            process.kill()\n    process_list.clear()\n\n\ndef block_connection():\n    subprocess.run([\"iptables\", \"-A\", \"INPUT\", \"-p\", \"tcp\", \"--dport\", ZENOH_PORT, \"-j\", \"DROP\"], check=True)\n    subprocess.run([\"iptables\", \"-A\", \"OUTPUT\", \"-p\", \"tcp\", \"--sport\", ZENOH_PORT, \"-j\", \"DROP\"], check=True)\n\n\ndef unblock_connection():\n    subprocess.run([\"iptables\", \"-D\", \"INPUT\", \"-p\", \"tcp\", \"--dport\", ZENOH_PORT, \"-j\", \"DROP\"], check=False)\n    subprocess.run([\"iptables\", \"-D\", \"OUTPUT\", \"-p\", \"tcp\", \"--sport\", ZENOH_PORT, \"-j\", \"DROP\"], check=False)\n\n\ndef wait_messages(client_output, messages):\n    start_time = time.time()\n    while time.time() - start_time < WAIT_MESSAGE_TIMEOUT_S:\n        if any(message in line for line in client_output for message in messages):\n            return True\n        time.sleep(1)\n    return False\n\n\ndef wait_connect(client_output):\n    if wait_messages(client_output, CONNECT_MESSAGES):\n        print(\"Initial connection successful.\")\n    else:\n        raise Exception(\"Connection failed.\")\n\n\ndef wait_reconnect(client_output):\n    if wait_messages(client_output, CONNECT_MESSAGES):\n        print(\"Connection restored successfully.\")\n    else:\n        raise Exception(\"Failed to restore connection.\")\n\n\ndef wait_disconnect(client_output):\n    if wait_messages(client_output, DISCONNECT_MESSAGES):\n        print(\"Connection lost successfully.\")\n    else:\n        raise Exception(\"Failed to block connection.\")\n\n\ndef check_router_errors(router_output):\n    for line in router_output:\n        if ROUTER_ERROR_MESSAGE in line:\n            print(line)\n            raise Exception(\"Router have an error.\")\n\n\ndef test_connection_drop(router_command, client_command, timeout):\n    print(f\"Drop test {client_command} for timeout {timeout}\")\n    router_output = []\n    client_output = []\n    process_list = []\n    blocked = False\n    try:\n        run_background(router_command, router_output, process_list)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        run_background(client_command, client_output, process_list)\n\n        # Two iterations because there was an error on the second reconnection\n        for _ in range(2):\n            wait_connect(client_output)\n            client_output.clear()\n\n            print(\"Blocking connection...\")\n            block_connection()\n            blocked = True\n\n            time.sleep(timeout)\n\n            wait_disconnect(client_output)\n            client_output.clear()\n\n            print(\"Unblocking connection...\")\n            unblock_connection()\n            blocked = False\n\n            wait_reconnect(client_output)\n\n        check_router_errors(router_output)\n\n        print(f\"Drop test {client_command} for timeout {timeout} passed\")\n    finally:\n        if blocked:\n            unblock_connection()\n        terminate_processes(process_list)\n\n\ndef test_router_restart(router_command, client_command, timeout):\n    print(f\"Restart test {client_command} for timeout {timeout}\")\n    router_output = []\n    client_output = []\n    router_process_list = []\n    client_process_list = []\n    try:\n        run_background(router_command, router_output, router_process_list)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        run_background(client_command, client_output, client_process_list)\n\n        wait_connect(client_output)\n        client_output.clear()\n\n        print(\"Stop router...\")\n        terminate_processes(router_process_list)\n\n        time.sleep(timeout)\n\n        wait_disconnect(client_output)\n        client_output.clear()\n\n        print(\"Start router...\")\n        run_background(router_command, router_output, router_process_list)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        wait_reconnect(client_output)\n\n        check_router_errors(router_output)\n\n        print(f\"Restart test {client_command} for timeout {timeout} passed\")\n    finally:\n        terminate_processes(client_process_list + router_process_list)\n\n\ndef test_liveliness_drop(router_command, liveliness_command, liveliness_sub_command):\n    print(f\"Liveliness drop test\")\n    router_output = []\n    dummy_output = []\n    client_output = []\n    process_list = []\n    blocked = False\n    try:\n        run_background(router_command, router_output, process_list)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        run_background(liveliness_sub_command, client_output, process_list)\n        run_background(liveliness_command, dummy_output, process_list)\n\n        if wait_messages(client_output, LIVELINESS_TOKEN_ALIVE_MESSAGES):\n            print(\"Liveliness token alive\")\n        else:\n            raise Exception(\"Failed to get liveliness token alive.\")\n        client_output.clear()\n\n        print(\"Blocking connection...\")\n        block_connection()\n        blocked = True\n\n        time.sleep(15)\n\n        if wait_messages(client_output, LIVELINESS_TOKEN_DROP_MESSAGES):\n            print(\"Liveliness token dropped\")\n        else:\n            raise Exception(\"Failed to get liveliness token drop.\")\n        client_output.clear()\n\n        print(\"Unblocking connection...\")\n        unblock_connection()\n        blocked = False\n\n        if wait_messages(client_output, LIVELINESS_TOKEN_ALIVE_MESSAGES):\n            print(\"Liveliness token alive\")\n        else:\n            raise Exception(\"Failed to get liveliness token alive.\")\n        client_output.clear()\n\n        check_router_errors(router_output)\n\n        print(f\"Liveliness drop test passed\")\n    finally:\n        if blocked:\n            unblock_connection()\n        terminate_processes(process_list)\n\n\ndef test_pub_sub_survive_router_restart(router_command, pub_command, sub_command, timeout):\n    \"\"\"\n    Start router, start subscriber and publisher, verify samples flow.\n    Restart router, wait for clients to reconnect, verify samples still flow.\n    \"\"\"\n    print(f\"Pub/Sub flow across router restart (timeout={timeout})\")\n\n    router_output = []\n    pub_output    = []\n    sub_output    = []\n    router_ps = []\n    pub_ps    = []\n    sub_ps    = []\n\n    try:\n        # Router up\n        run_background(router_command, router_output, router_ps)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        # Start subscriber first so it can declare interest\n        run_background(sub_command, sub_output, sub_ps)\n        wait_connect(sub_output)   # session up from sub side\n        sub_output.clear()\n\n        # Start publisher\n        run_background(pub_command, pub_output, pub_ps)\n        wait_connect(pub_output)   # session up from pub side\n        pub_output.clear()\n\n        # Confirm baseline delivery before restart\n        print(\"Verifying baseline delivery...\")\n        if not wait_messages(sub_output, SUBSCRIBER_RECEIVE_MESSAGES):\n            raise Exception(\"Baseline: subscriber did not receive any sample.\")\n        sub_output.clear()\n\n        # Restart router\n        print(\"Restarting router...\")\n        terminate_processes(router_ps)\n        time.sleep(timeout)\n\n        # Both client logs should eventually show disconnect; don't hard-fail if only one shows it\n        try:\n            wait_disconnect(pub_output)\n            pub_output.clear()\n        except Exception:\n            pass\n        try:\n            wait_disconnect(sub_output)\n            sub_output.clear()\n        except Exception:\n            pass\n\n        run_background(router_command, router_output, router_ps)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        # Reconnect\n        wait_reconnect(pub_output)\n        #pub_output.clear()\n        wait_reconnect(sub_output)\n        sub_output.clear()\n\n        # Verify delivery after restart\n        print(\"Verifying delivery after router restart...\")\n        if not wait_messages(sub_output, SUBSCRIBER_RECEIVE_MESSAGES):\n            raise Exception(\"After restart: subscriber did not receive any sample.\")\n        if not wait_messages(pub_output, WRITE_FILTER_OFF_MESSAGE):\n            raise Exception(\"After restart: write filter state not updated to off.\")\n\n        check_router_errors(router_output)\n        print(\"Pub/Sub flow across router restart: PASSED\")\n    finally:\n        terminate_processes(sub_ps + pub_ps + router_ps)\n\n\ndef test_pub_before_restart_then_new_sub(router_command, pub_command, sub_command, timeout):\n    \"\"\"\n    Start router and publisher; restart router; wait for publisher to reconnect;\n    then start a new subscriber and verify it receives samples.\n    This reproduces the writer-side filtering / missing interest issue.\n    \"\"\"\n    print(f\"Pub before restart, new Sub after (timeout={timeout})\")\n\n    router_output = []\n    pub_output    = []\n    sub_output    = []\n    router_ps = []\n    pub_ps    = []\n    sub_ps    = []\n\n    try:\n        # Router up\n        run_background(router_command, router_output, router_ps)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        # Start publisher first\n        run_background(pub_command, pub_output, pub_ps)\n        wait_connect(pub_output)\n        pub_output.clear()\n\n        # Restart router\n        print(\"Restarting router...\")\n        terminate_processes(router_ps)\n        time.sleep(timeout)\n\n        # Publisher should notice disconnect; don't fail if log line format differs\n        try:\n            wait_disconnect(pub_output)\n            pub_output.clear()\n        except Exception:\n            pass\n\n        run_background(router_command, router_output, router_ps)\n        time.sleep(ROUTER_INIT_TIMEOUT_S)\n\n        # Wait for publisher to reconnect\n        wait_reconnect(pub_output)\n        pub_output.clear()\n\n        # Now start NEW subscriber\n        run_background(sub_command, sub_output, sub_ps)\n        wait_connect(sub_output)\n        sub_output.clear()\n\n        # Critical assertion: subscriber should receive samples\n        print(\"Waiting for subscriber to receive samples...\")\n        if not wait_messages(sub_output, SUBSCRIBER_RECEIVE_MESSAGES):\n            # Print some context for debugging\n            print(\"=== Publisher (last lines) ===\")\n            [print(l) for l in pub_output[-50:]]\n            print(\"=== Subscriber (last lines) ===\")\n            [print(l) for l in sub_output[-50:]]\n            print(\"=== Router (last lines) ===\")\n            [print(l) for l in router_output[-50:]]\n            raise Exception(\n                \"New subscriber did not receive samples after router restart while publisher \"\n                \"existed before. This matches the issue where publisher stays in writer-side \"\n                \"filtering and never resends interest.\"\n            )\n        if not wait_messages(pub_output, WRITE_FILTER_OFF_MESSAGE):\n            raise Exception(\"After restart: write filter state not updated to off.\")\n\n        check_router_errors(router_output)\n        print(\"Pub before restart, new Sub after: PASSED\")\n    finally:\n        terminate_processes(sub_ps + pub_ps + router_ps)\n\n\ndef main():\n    if len(sys.argv) != 2:\n        print(\"Usage: sudo python3 ./connection_restore.py /path/to/zenohd\")\n        sys.exit(1)\n\n    router_command = STDBUF_CMD + [sys.argv[1]] + ROUTER_ARGS\n\n    # timeout less than sesson timeout\n    test_connection_drop(router_command, ACTIVE_CLIENT_COMMAND, 15)\n    test_connection_drop(router_command, PASSIVE_CLIENT_COMMAND, 15)\n\n    # timeout more than sesson timeout\n    test_connection_drop(router_command, ACTIVE_CLIENT_COMMAND, 15)\n    test_connection_drop(router_command, PASSIVE_CLIENT_COMMAND, 15)\n\n    # timeout less than sesson timeout\n    test_router_restart(router_command, ACTIVE_CLIENT_COMMAND, 8)\n    test_router_restart(router_command, PASSIVE_CLIENT_COMMAND, 8)\n\n    # timeout more than sesson timeout\n    test_router_restart(router_command, ACTIVE_CLIENT_COMMAND, 15)\n    test_router_restart(router_command, PASSIVE_CLIENT_COMMAND, 15)\n\n    # Existing z_pub <-> z_sub communication survives a router restart\n    test_pub_sub_survive_router_restart(router_command,\n                                        ACTIVE_CLIENT_COMMAND,\n                                        PASSIVE_CLIENT_COMMAND,\n                                        8)\n\n    # After a router restart, a new z_sub can receive samples from a pre-restart z_pub\n    test_pub_before_restart_then_new_sub(router_command,\n                                         ACTIVE_CLIENT_COMMAND,\n                                         PASSIVE_CLIENT_COMMAND,\n                                         8)\n\n    test_liveliness_drop(router_command, LIVELINESS_CLIENT_COMMAND, LIVELINESS_SUB_CLIENT_COMMAND)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "tests/fragment.py",
    "content": "import subprocess\nimport sys\nimport time\n\n# Specify the directory for the binaries\nDIR_TESTS = \"build/tests\"\n\ndef check_output(tx_status, tx_output, rx_status, rx_output):\n    test_status = 0\n\n    # Expected tx output & status\n    z_tx_expected_status = 0\n    z_tx_expected_output = \"[tx]: Sending packet on test/zenoh-pico-fragment, len: 10000\"\n    # Expected rx output & status\n    z_rx_expected_status = 0\n    z_rx_expected_output = (\n        \"[rx]: Received packet on test/zenoh-pico-fragment, len: 10000, validity: 1, qos {priority: 4, cong_ctrl: 1}\")\n\n    # Check the exit status of tx\n    if tx_status == z_tx_expected_status:\n        print(\"z_tx status valid\")\n    else:\n        print(f\"z_tx status invalid, expected: {z_tx_expected_status}, received: {tx_status}\")\n        test_status = 1\n\n    # Check output of tx\n    if z_tx_expected_output in tx_output:\n        print(\"z_tx output valid\")\n    else:\n        print(\"z_tx output invalid:\")\n        print(f\"Expected: \\\"{z_tx_expected_output}\\\"\")\n        print(f\"Received: \\\"{tx_output}\\\"\")\n        test_status = 1\n\n    # Check the exit status of z_rx\n    if rx_status == z_rx_expected_status:\n        print(\"z_rx status valid\")\n    else:\n        print(f\"z_rx status invalid, expected: {z_rx_expected_status}, received: {rx_status}\")\n        test_status = 1\n\n    # Check output of z_rx\n    if z_rx_expected_output in rx_output:\n        print(\"z_rx output valid\")\n    else:\n        print(\"z_rx output invalid:\")\n        print(f\"Expected: \\\"{z_rx_expected_output}\\\"\")\n        print(f\"Received: \\\"{rx_output}\\\"\")\n        test_status = 1\n    # Return value\n    return test_status\n\ndef test_client():\n    # Start rx in the background\n    print(\"Start rx client\")\n    z_rx_command = f\"./{DIR_TESTS}/z_test_fragment_rx\"\n    z_rx_process = subprocess.Popen(z_rx_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE, text=True)\n    # Introduce a delay to ensure rx starts\n    time.sleep(2)\n    # Start tx\n    print(\"Start tx client\")\n    z_tx_command = f\"./{DIR_TESTS}/z_test_fragment_tx\"\n    z_tx_process = subprocess.Popen(z_tx_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE,\n                                    text=True)\n    # Wait for tx to finish\n    z_tx_process.wait()\n    # Wait for rx to receive\n    time.sleep(1)\n    print(\"Stop rx\")\n    if z_rx_process.poll() is None:\n        # Send \"q\" command to rx to stop it\n        z_rx_process.stdin.write(\"q\\n\")\n        z_rx_process.stdin.flush()\n    # Wait for rx to finish\n    z_rx_process.wait()\n    # Check output\n    return check_output(z_tx_process.returncode, z_tx_process.stdout.read(),\n                        z_rx_process.returncode, z_rx_process.stdout.read())\n\ndef test_peer():\n    # Start rx in the background\n    print(\"Start rx peer\")\n    z_rx_command = f\"./{DIR_TESTS}/z_test_fragment_rx 1\"\n    z_rx_process = subprocess.Popen(z_rx_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE, text=True)\n    # Introduce a delay to ensure rx starts\n    time.sleep(2)\n    # Start tx\n    print(\"Start tx peer\")\n    z_tx_command = f\"./{DIR_TESTS}/z_test_fragment_tx 1\"\n    z_tx_process = subprocess.Popen(z_tx_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE,\n                                    text=True)\n    # Wait for tx to finish\n    z_tx_process.wait()\n    # Wait for rx to receive\n    time.sleep(1)\n    print(\"Stop rx\")\n    if z_rx_process.poll() is None:\n        # Send \"q\" command to rx to stop it\n        z_rx_process.stdin.write(\"q\\n\")\n        z_rx_process.stdin.flush()\n    # Wait for rx to finish\n    z_rx_process.wait()\n    # Check output\n    return check_output(z_tx_process.returncode, z_tx_process.stdout.read(),\n                        z_rx_process.returncode, z_rx_process.stdout.read())\n\nif __name__ == \"__main__\":\n    EXIT_STATUS = 0\n\n    # Run tests\n    if test_client() == 1:\n        EXIT_STATUS = 1\n    if test_peer() == 1:\n        EXIT_STATUS = 1\n    # Exit\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/memory_leak.py",
    "content": "import os\nimport signal\nimport subprocess\nimport sys\nimport time\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\n\nNO_LEAK_OUTPUT = \"All heap blocks were freed -- no leaks are possible\"\n\nVALGRIND_CMD = f\"stdbuf -oL -eL valgrind --leak-check=full ./{DIR_EXAMPLES}/\"\n\n\ndef failure_mode(fail_cmd):\n    test_status = 0\n    # Start binary\n    print(\"Start binary\")\n    z_pub_command = VALGRIND_CMD + fail_cmd\n    z_pub_process = subprocess.Popen(\n        z_pub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True\n    )\n    # Wait for process to finish\n    z_pub_process.wait()\n    # Check output\n    print(\"Check output\")\n    z_pub_output = z_pub_process.stderr.read()\n    if NO_LEAK_OUTPUT in z_pub_output:\n        print(\"Failure mode output valid\")\n    else:\n        print(\"Failure mode output invalid:\")\n        print(f\"Received: \\\"{z_pub_output}\\\"\")\n        test_status = 1\n    # Return value\n    return test_status\n\n\ndef pub_and_sub(pub_cmd, sub_cmd):\n    test_status = 0\n\n    print(f\"Start {sub_cmd}\")\n    # Start z_sub in the background\n    z_sub_command = VALGRIND_CMD + sub_cmd\n\n    z_sub_process = subprocess.Popen(\n        z_sub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True\n    )\n    # Introduce a delay to ensure z_sub starts\n    time.sleep(2)\n\n    print(f\"Start {pub_cmd}\")\n    # Start z_pub\n    z_pub_command = VALGRIND_CMD + pub_cmd\n    z_pub_process = subprocess.Popen(\n        z_pub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True\n    )\n    # Wait for z_pub to finish\n    z_pub_process.wait()\n\n    print(f\"Stop {sub_cmd}\")\n    time.sleep(2)\n    if z_sub_process.poll() is None:\n        # send SIGINT to group\n        z_sub_process_gid = os.getpgid(z_sub_process.pid)\n        os.killpg(z_sub_process_gid, signal.SIGINT)\n\n    # Wait for z_sub to finish\n    z_sub_process.wait()\n\n    print(\"Check outputs\")\n    # Check output of z_pub\n    z_pub_output = z_pub_process.stderr.read()\n    if NO_LEAK_OUTPUT in z_pub_output:\n        print(f\"{pub_cmd} output valid\")\n    else:\n        print(f\"{pub_cmd} output invalid:\")\n        print(f\"Received: \\\"{z_pub_output}\\\"\")\n        test_status = 1\n\n    # Check output of z_sub\n    z_sub_output = z_sub_process.stderr.read()\n    if NO_LEAK_OUTPUT in z_sub_output:\n        print(f\"{sub_cmd} output valid\")\n    else:\n        print(f\"{sub_cmd} output invalid:\")\n        print(f\"Received: \\\"{z_sub_output}\\\"\")\n        test_status = 1\n    # Return value\n    return test_status\n\n\ndef query_and_queryable(query_cmd, queryable_cmd):\n    test_status = 0\n    print(f\"Start {queryable_cmd}\")\n    # Start z_queryable in the background\n    z_queryable_command = VALGRIND_CMD + queryable_cmd\n    z_queryable_process = subprocess.Popen(\n        z_queryable_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        text=True,\n    )\n\n    # Introduce a delay to ensure z_queryable starts\n    time.sleep(2)\n\n    print(f\"Start {query_cmd}\")\n    # Start z_query\n    z_query_command = VALGRIND_CMD + query_cmd\n    z_query_process = subprocess.Popen(\n        z_query_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        text=True,\n    )\n    # Wait for z_query to finish\n    z_query_process.wait()\n\n    print(f\"Stop {queryable_cmd}\")\n    time.sleep(5)\n    if z_queryable_process.poll() is None:\n        # send SIGINT to group\n        z_quaryable_process_gid = os.getpgid(z_queryable_process.pid)\n        os.killpg(z_quaryable_process_gid, signal.SIGINT)\n\n    # Wait for z_queryable to finish\n    z_queryable_process.wait()\n\n    print(\"Check outputs\")\n    # Check output of z_query\n    z_query_output = z_query_process.stderr.read()\n    if NO_LEAK_OUTPUT in z_query_output:\n        print(f\"{query_cmd} output valid\")\n    else:\n        print(f\"{query_cmd} output invalid:\")\n        print(f'Received: \"{z_query_output}\"')\n        test_status = 1\n\n    # Check output of z_queryable\n    z_queryable_output = z_queryable_process.stderr.read()\n    if NO_LEAK_OUTPUT in z_queryable_output:\n        print(f\"{queryable_cmd} output valid\")\n    else:\n        print(f\"{queryable_cmd} output invalid:\")\n        print(f'Received: \"{z_queryable_output}\"')\n        test_status = 1\n    # Return status\n    return test_status\n\n\nif __name__ == \"__main__\":\n    signal.signal(signal.SIGINT, signal.SIG_IGN)\n    EXIT_STATUS = 0\n\n    # Test failure mode\n    print(\"*** Failure mode ***\")\n    if failure_mode('z_pub -m invalid') == 1:\n        EXIT_STATUS = 1\n    # Test pub and sub examples\n    print(\"*** Pub & sub test ***\")\n    if pub_and_sub('z_pub -n 1', 'z_sub -n 1') == 1:\n        EXIT_STATUS = 1\n    print(\"*** Pub & sub attachment test ***\")\n    if pub_and_sub('z_pub_attachment -n 1', 'z_sub_attachment -n 1') == 1:\n        EXIT_STATUS = 1\n    print(\"*** Pub & sub listener test ***\")\n    if pub_and_sub('z_pub -n 1 -a', 'z_sub -n 1') == 1:\n        EXIT_STATUS = 1\n    # Test query and queryable examples\n    print(\"*** Query & queryable test ***\")\n    if query_and_queryable('z_get', 'z_queryable -n 1') == 1:\n        EXIT_STATUS = 1\n    print(\"*** Query & queryable attachment test ***\")\n    if query_and_queryable('z_get_attachment -v Something', 'z_queryable_attachment -n 1') == 1:\n        EXIT_STATUS = 1\n    # Test querier and queryable examples\n    print(\"*** Querier & queryable test ***\")\n    if query_and_queryable('z_querier -n 1', 'z_queryable -n 1') == 1:\n        EXIT_STATUS = 1\n    # Test liveliness query\n    print(\"*** Get liveliness test ***\")\n    if query_and_queryable('z_get_liveliness', 'z_liveliness -t 3') == 1:\n        EXIT_STATUS = 1\n    # Test liveliness subscriber\n    print(\"*** Liveliness subscriber test ***\")\n    if query_and_queryable('z_liveliness -t 1', 'z_sub_liveliness -h -n 1') == 1:\n        EXIT_STATUS = 1\n    # Exit\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/modularity.py",
    "content": "import argparse\nimport os\nfrom signal import SIGINT\nimport subprocess\nimport sys\nimport time\nimport difflib\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\n\n\ndef print_string_diff(str_a, str_b):\n    for i, s in enumerate(difflib.ndiff(str_a, str_b)):\n        if s[0] == \" \":\n            continue\n        elif s[0] == \"-\":\n            print('Delete \"{}\" from position {}'.format(s[-1], i))\n        elif s[0] == \"+\":\n            print('Add \"{}\" to position {}'.format(s[-1], i))\n    print()\n\n\ndef pub_and_sub(args):\n    print(\"*** Pub & sub test ***\")\n    test_status = 0\n\n    # Expected z_pub output & status\n    if args.pub == 1:\n        z_pub_expected_status = 0\n        z_pub_expected_output = \"\"\"Opening session...\nDeclaring publisher for 'demo/example/zenoh-pico-pub'...\nPress CTRL-C to quit...\nPutting Data ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   5] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   6] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   7] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   8] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   9] Pub from Pico!')...\"\"\"\n    else:\n        z_pub_expected_status = 254\n        z_pub_expected_output = \"ERROR: Zenoh pico was compiled without \" \"Z_FEATURE_PUBLICATION but this example requires it.\"\n\n    # Expected z_sub output & status\n    if args.sub == 1:\n        if args.pub == 1:\n            z_sub_expected_status = [0, -2]\n            z_sub_expected_output = \"\"\"Opening session...\nDeclaring Subscriber on 'demo/example/**'...\nPress CTRL-C to quit...\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   5] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   6] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   7] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   8] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   9] Pub from Pico!')\"\"\"\n        else:\n            z_sub_expected_status = [-2]\n            z_sub_expected_output = \"\"\"Opening session...\nDeclaring Subscriber on 'demo/example/**'...\nPress CTRL-C to quit...\"\"\"\n    else:\n        z_sub_expected_status = [254]\n        z_sub_expected_output = \"ERROR: Zenoh pico was compiled without \" \"Z_FEATURE_SUBSCRIPTION but this example requires it.\"\n\n    print(\"Start subscriber\")\n    # Start z_sub in the background\n    z_sub_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub -n 10\"\n    z_sub_process = subprocess.Popen(\n        z_sub_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        start_new_session=True,\n        text=True,\n    )\n\n    # Introduce a delay to ensure z_sub starts\n    time.sleep(2)\n\n    print(\"Start publisher\")\n    # Start z_pub\n    z_pub_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub -n 10\"\n    z_pub_process = subprocess.Popen(\n        z_pub_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        text=True,\n    )\n\n    # Wait for z_pub to finish\n    z_pub_process.wait()\n\n    print(\"Stop subscriber\")\n    if z_sub_process.poll() is None:\n        # send SIGINT to group\n        z_sub_process_gid = os.getpgid(z_sub_process.pid)\n        os.killpg(z_sub_process_gid, SIGINT)\n\n    # Wait for z_sub to finish\n    z_sub_process.wait()\n\n    print(\"Check publisher status & output\")\n    # Check the exit status of z_pub\n    z_pub_status = z_pub_process.returncode\n    if z_pub_status == z_pub_expected_status:\n        print(\"z_pub status valid\")\n    else:\n        print(f\"z_pub status invalid, expected: {z_pub_expected_status}, received: {z_pub_status}\")\n        test_status = 1\n\n    # Check output of z_pub\n    z_pub_output = z_pub_process.stdout.read()\n    if z_pub_expected_output in z_pub_output:\n        print(\"z_pub output valid\")\n    else:\n        print(\"z_pub output invalid:\")\n        print(f'Expected: \"{z_pub_expected_output}\"')\n        print(f'Received: \"{z_pub_output}\"')\n        test_status = 1\n\n    print(\"Check subscriber status & output\")\n    # Check the exit status of z_sub\n    z_sub_status = z_sub_process.returncode\n    if z_sub_status in z_sub_expected_status:\n        print(\"z_sub status valid\")\n    else:\n        print(f\"z_sub status invalid, expected: {z_sub_expected_status}, received: {z_sub_status}\")\n        test_status = 1\n\n    # Check output of z_sub\n    z_sub_output = z_sub_process.stdout.read()\n    if z_sub_expected_output in z_sub_output:\n        print(\"z_sub output valid\")\n    else:\n        print(\"z_sub output invalid:\")\n        print(f'Expected: \"{z_sub_expected_output}\"')\n        print(f'Received: \"{z_sub_output}\"')\n        test_status = 1\n    # Return value\n    return test_status\n\n\ndef query_and_queryable(args):\n    print(\"*** Query & queryable test ***\")\n    test_status = 0\n\n    # Expected z_query output & status\n    if args.query == 1:\n        z_query_expected_status = 0\n        if args.queryable == 1:\n            z_query_expected_output = \"\"\"Opening session...\nSending Query 'demo/example/**'...\n>> Received PUT ('demo/example/**': 'Queryable from Pico!')\n>> Received query final notification\"\"\"\n        else:\n            z_query_expected_output = \"\"\"Opening session...\nSending Query 'demo/example/**'...\n>> Received query final notification\"\"\"\n    else:\n        z_query_expected_status = 254\n        z_query_expected_output = (\n            \"ERROR: Zenoh pico was compiled without \" \"Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires them.\"\n        )\n\n    # Expected z_queryable output & status\n    if args.queryable == 1:\n        if args.query == 1:\n            z_queryable_expected_status = [0, -2]\n            z_queryable_expected_output = \"\"\"Opening session...\nCreating Queryable on 'demo/example/zenoh-pico-queryable'...\nPress CTRL-C to quit...\n >> [Queryable handler] Received Query 'demo/example/**'\n\"\"\"\n        else:\n            z_queryable_expected_status = [-2]\n            z_queryable_expected_output = \"\"\"Opening session...\nCreating Queryable on 'demo/example/zenoh-pico-queryable'...\nPress CTRL-C to quit...\"\"\"\n    else:\n        z_queryable_expected_status = [254]\n        z_queryable_expected_output = \"ERROR: Zenoh pico was compiled without \" \"Z_FEATURE_QUERYABLE but this example requires it.\"\n\n    print(\"Start queryable\")\n    # Start z_queryable in the background\n    z_queryable_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_queryable -n 1\"\n    z_queryable_process = subprocess.Popen(\n        z_queryable_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        start_new_session=True,\n        text=True,\n    )\n\n    # Introduce a delay to ensure z_queryable starts\n    time.sleep(2)\n\n    print(\"Start query\")\n    # Start z_query\n    z_query_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_get\"\n    z_query_process = subprocess.Popen(\n        z_query_command,\n        shell=True,\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        text=True,\n    )\n\n    # Wait for z_query to finish\n    z_query_process.wait()\n\n    print(\"Stop queryable\")\n    if z_queryable_process.poll() is None:\n        # send SIGINT to group\n        z_quaryable_process_gid = os.getpgid(z_queryable_process.pid)\n        os.killpg(z_quaryable_process_gid, SIGINT)\n\n    # Wait for z_queryable to finish\n    z_queryable_process.wait()\n\n    print(\"Check query status & output\")\n    # Check the exit status of z_query\n    z_query_status = z_query_process.returncode\n    if z_query_status == z_query_expected_status:\n        print(\"z_query status valid\")\n    else:\n        print(f\"z_query status invalid, expected: {z_query_expected_status},\" f\" received: {z_query_status}\")\n        test_status = 1\n\n    # Check output of z_query\n    z_query_output = z_query_process.stdout.read()\n    if z_query_expected_output in z_query_output:\n        print(\"z_query output valid\")\n    else:\n        print(\"z_query output invalid:\")\n        print(f'Expected: \"{z_query_expected_output}\"')\n        print(f'Received: \"{z_query_output}\"')\n        test_status = 1\n\n    print(\"Check queryable status & output\")\n    # Check the exit status of z_queryable\n    z_queryable_status = z_queryable_process.returncode\n    if z_queryable_status in z_queryable_expected_status:\n        print(\"z_queryable status valid\")\n    else:\n        print(f\"z_queryable status invalid, expected: {z_queryable_expected_status},\" f\" received: {z_queryable_status}\")\n        test_status = 1\n\n    # Check output of z_queryable\n    z_queryable_output = z_queryable_process.stdout.read()\n    if z_queryable_expected_output in z_queryable_output:\n        print(\"z_queryable output valid\")\n    else:\n        print(\"z_queryable output invalid:\")\n        print(f'Expected: \"{z_queryable_expected_output}\"')\n        print(f'Received: \"{z_queryable_output}\"')\n        print_string_diff(z_queryable_expected_output, z_queryable_output)\n        test_status = 1\n    # Return status\n    return test_status\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(\n        description=\"This script runs zenoh-pico examples\" \" and checks them according to the given configuration\"\n    )\n    parser.add_argument(\"--pub\", type=int, choices=[0, 1], help=\"Z_FEATURE_PUBLICATION (0 or 1)\")\n    parser.add_argument(\"--sub\", type=int, choices=[0, 1], help=\"Z_FEATURE_SUBSCRIPTION (0 or 1)\")\n    parser.add_argument(\"--queryable\", type=int, choices=[0, 1], help=\"Z_FEATURE_QUERYABLE (0 or 1)\")\n    parser.add_argument(\"--query\", type=int, choices=[0, 1], help=\"Z_FEATURE_QUERY (0 or 1)\")\n    EXIT_STATUS = 0\n    prog_args = parser.parse_args()\n    print(f\"Args value, pub:{prog_args.pub}, sub:{prog_args.sub}, \" f\"queryable:{prog_args.queryable}, query:{prog_args.query}\")\n\n    # Test pub and sub examples\n    if pub_and_sub(prog_args) == 1:\n        EXIT_STATUS = 1\n    # Test query and queryable examples\n    if query_and_queryable(prog_args) == 1:\n        EXIT_STATUS = 1\n    # Exit\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/multicast.sh",
    "content": "#!/bin/sh\n#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\nTESTBIN=\"$1\"\nTESTDIR=$(dirname \"$0\")\n\nif [ \"$OSTYPE\" = \"msys\" ]; then\n  TESTBIN=\"$TESTDIR/Debug/$TESTBIN.exe\"\nelse\n  TESTBIN=\"./$TESTBIN\"\nfi\n\ncd \"$TESTDIR\" || exit\n\necho \"------------------ Running test $TESTBIN -------------------\"\n\nINTERFACES=$(ifconfig -l)\nfor INTERFACE in $(echo \"$INTERFACES\" | xargs); do\n    INET=$(ifconfig \"$INTERFACE\" | awk '$1 == \"inet\" {print $2}')\n    if [ \"$INET\" != \"127.0.0.1\" ] && [ \"$INET\" != \"\" ]; then\n        break\n    fi\ndone\n\nLOCATORS=\"udp/224.0.0.225:7447#iface=$INTERFACE\"\nfor LOCATOR in $(echo \"$LOCATORS\" | xargs); do\n    sleep 1\n\n    echo \"> Running $TESTBIN $LOCATOR...\"\n    \"$TESTBIN\" \"$LOCATOR\"\n    RETCODE=$?\n\n    [ \"$RETCODE\" -lt 0 ] && exit \"$RETCODE\"\ndone\n\nINTERFACES=$(ifconfig -l)\nfor INTERFACE in $(echo \"$INTERFACES\" | xargs); do\n    INET=$(ifconfig \"$INTERFACE\" | awk '$1 == \"inet6\" {print $2}')\n    if [ \"$INET\" != \"::1\" ] && [ \"$INET\" != \"\" ]; then\n        break\n    fi\ndone\n\nLOCATORS=\"udp/[ff10::1234]:7447#iface=$INTERFACE\"\nfor LOCATOR in $(echo \"$LOCATORS\" | xargs); do\n    sleep 1\n\n    echo \"> Running $TESTBIN $LOCATOR...\"\n    \"$TESTBIN\" \"$LOCATOR\"\n    RETCODE=$?\n\n    [ \"$RETCODE\" -lt 0 ] && exit \"$RETCODE\"\ndone\n\necho \"> Done ($RETCODE).\"\nexit \"$RETCODE\"\n"
  },
  {
    "path": "tests/no_router.py",
    "content": "import subprocess\nimport sys\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\nEXPECTED_STATUS = 255\nEXPECTED_OUTPUT = \"\"\"Opening session...\nUnable to open session!\"\"\"\n\n\ndef run_binary_test(binary_name, expected_status, expected_output):\n    print(f\"*** Testing {binary_name} ***\")\n    command = [f\"./{DIR_EXAMPLES}/{binary_name}\"]\n\n    process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)\n    process.wait()\n\n    # Check output\n    output = process.stdout.read()\n    if expected_output in output:\n        print(f\"{binary_name} output valid\")\n    else:\n        print(f'{binary_name} output invalid:\\nExpected: \"{expected_output}\"\\nReceived: \"{output}\"')\n        return False\n\n    # Check errors\n    errors = process.stderr.read().strip()\n    if errors == \"\":\n        print(f\"{binary_name} no error reported\")\n    else:\n        print(f'{binary_name} errors reported:\\n\"{errors}\"')\n        return False\n\n    # Check exit status\n    status = process.returncode\n    if status == expected_status:\n        print(f\"{binary_name} status valid\")\n    else:\n        print(f\"{binary_name} status invalid, expected: {expected_status}, received: {status}\")\n        return False\n\n    return True\n\n\ndef test_all():\n    binaries = [\"z_sub\", \"z_pub\", \"z_queryable\", \"z_get\", \"z_liveliness\", \"z_get_liveliness\", \"z_sub_liveliness\"]\n\n    all_tests_passed = True\n    for binary in binaries:\n        if not run_binary_test(binary, EXPECTED_STATUS, EXPECTED_OUTPUT):\n            all_tests_passed = False\n\n    return all_tests_passed\n\n\nif __name__ == \"__main__\":\n    EXIT_STATUS = 0\n\n    # Run all tests\n    if not test_all():\n        EXIT_STATUS = 1\n\n    # Exit with final status\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/package_mylinux.sh.in",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nSOURCE_DIR=\"@PROJECT_SOURCE_DIR@\"\nWORK_DIR=\"$(mktemp -d \"${PWD}/zenoh-pico-package-mylinux-XXXXXX\")\"\ntrap 'rm -rf \"$WORK_DIR\"' EXIT\n\nEXAMPLE_DIR=\"$SOURCE_DIR/examples/packages/zenohpico-mylinux\"\nPREFIX_DIR=\"$WORK_DIR/prefix\"\nPACKAGE_BUILD_DIR=\"$WORK_DIR/package-build\"\nSHARED_BUILD_DIR=\"$WORK_DIR/shared-build\"\nSTATIC_BUILD_DIR=\"$WORK_DIR/static-build\"\nINSTALL_DIR=\"$WORK_DIR/install\"\nCONSUMER_BUILD_DIR=\"$WORK_DIR/consumer-build\"\n\ncmake -S \"$EXAMPLE_DIR\" -B \"$PACKAGE_BUILD_DIR\" \\\n  -DZENOH_PICO_SOURCE_DIR=\"$SOURCE_DIR\" \\\n  -DZENOH_PICO_CONFIG_INCLUDE_DIR=\"@PROJECT_BINARY_DIR@/include\"\ncmake --build \"$PACKAGE_BUILD_DIR\" -j\ncmake --install \"$PACKAGE_BUILD_DIR\" --prefix \"$PREFIX_DIR\"\n\ncmake -S \"$SOURCE_DIR\" -B \"$SHARED_BUILD_DIR\" \\\n  -DZ_FEATURE_MULTI_THREAD=@Z_FEATURE_MULTI_THREAD@ \\\n  -DZ_FEATURE_LINK_SERIAL=@Z_FEATURE_LINK_SERIAL@ \\\n  -DBUILD_EXAMPLES=OFF \\\n  -DZP_EXTERNAL_PACKAGES=zenohpico-mylinux \\\n  -DCMAKE_PREFIX_PATH=\"$PREFIX_DIR\" \\\n  -DZP_PLATFORM=mylinux\n\ncmake --build \"$SHARED_BUILD_DIR\" -j --target \\\n  z_endpoint_test \\\n  z_tls_test \\\n  z_executor_test \\\n  z_background_executor_test \\\n  z_local_loopback_test\n\nctest --test-dir \"$SHARED_BUILD_DIR\" --output-on-failure \\\n  -R '^z_endpoint_test$|^z_tls_test$|^z_executor_test$|^z_background_executor_test$|^z_local_loopback_test$' \\\n  --timeout 420\n\ncmake -S \"$SOURCE_DIR\" -B \"$STATIC_BUILD_DIR\" \\\n  -DZ_FEATURE_MULTI_THREAD=@Z_FEATURE_MULTI_THREAD@ \\\n  -DZ_FEATURE_LINK_SERIAL=@Z_FEATURE_LINK_SERIAL@ \\\n  -DBUILD_SHARED_LIBS=OFF \\\n  -DBUILD_EXAMPLES=OFF \\\n  -DBUILD_TESTING=OFF \\\n  -DZP_EXTERNAL_PACKAGES=zenohpico-mylinux \\\n  -DCMAKE_PREFIX_PATH=\"$PREFIX_DIR\" \\\n  -DZP_PLATFORM=mylinux\n\ncmake --build \"$STATIC_BUILD_DIR\" -j --target zenohpico_static\ncmake --install \"$STATIC_BUILD_DIR\" --prefix \"$INSTALL_DIR\"\n\ncmake -S \"$EXAMPLE_DIR/consumer\" -B \"$CONSUMER_BUILD_DIR\" \\\n  -DCMAKE_PREFIX_PATH=\"$INSTALL_DIR;$PREFIX_DIR\"\ncmake --build \"$CONSUMER_BUILD_DIR\" -j --target consumer\n"
  },
  {
    "path": "tests/package_myrtos.sh.in",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nSOURCE_DIR=\"@PROJECT_SOURCE_DIR@\"\nWORK_DIR=\"$(mktemp -d \"${PWD}/zenoh-pico-package-myrtos-XXXXXX\")\"\ntrap 'rm -rf \"$WORK_DIR\"' EXIT\n\nPREFIX_DIR=\"$WORK_DIR/prefix\"\nPACKAGE_DIR=\"$PREFIX_DIR/lib/cmake/zenohpico-myrtos\"\nPLATFORM_DIR=\"$PACKAGE_DIR/platforms\"\nLIB_DIR=\"$PREFIX_DIR/lib\"\nBUILD_DIR=\"$WORK_DIR/build\"\n\nmkdir -p \"$PLATFORM_DIR\" \"$LIB_DIR\"\n\ncat >\"$PLATFORM_DIR/myrtos.cmake\" <<'EOF'\nset(ZP_PLATFORM_COMPILE_DEFINITIONS ZENOH_FREERTOS_LWIP)\nset(ZP_PLATFORM_SOURCE_FILES\n    \"@PROJECT_SOURCE_DIR@/src/system/socket/lwip.c\"\n    \"@PROJECT_SOURCE_DIR@/src/link/transport/tcp/tcp_lwip.c\"\n    \"@PROJECT_SOURCE_DIR@/src/link/transport/udp/udp_lwip.c\")\nif(ZP_UDP_MULTICAST_ENABLED)\n  list(APPEND ZP_PLATFORM_SOURCE_FILES\n       \"@PROJECT_SOURCE_DIR@/src/link/transport/udp/udp_multicast_lwip.c\"\n       \"@PROJECT_SOURCE_DIR@/src/link/transport/udp/udp_multicast_lwip_common.c\")\nendif()\nlist(APPEND ZP_PLATFORM_LINK_LIBRARIES myrtos::system myrtos::serial_uart)\nEOF\n\n: >\"$LIB_DIR/libmyrtos_system.a\"\n: >\"$LIB_DIR/libmyrtos_serial_uart.a\"\n\ncat >\"$PACKAGE_DIR/zenohpico-myrtosConfig.cmake\" <<'EOF'\nif(COMMAND zp_add_platform_dir)\n  zp_add_platform_dir(\"${CMAKE_CURRENT_LIST_DIR}/platforms\")\nendif()\nadd_library(myrtos::system STATIC IMPORTED GLOBAL)\nset_target_properties(myrtos::system PROPERTIES\n                      IMPORTED_LOCATION \"${CMAKE_CURRENT_LIST_DIR}/../../libmyrtos_system.a\")\n\nadd_library(myrtos::serial_uart STATIC IMPORTED GLOBAL)\nset_target_properties(myrtos::serial_uart PROPERTIES\n                      IMPORTED_LOCATION \"${CMAKE_CURRENT_LIST_DIR}/../../libmyrtos_serial_uart.a\")\nEOF\n\ncmake -S \"$SOURCE_DIR\" -B \"$BUILD_DIR\" \\\n  -DZ_FEATURE_MULTI_THREAD=@Z_FEATURE_MULTI_THREAD@ \\\n  -DZ_FEATURE_LINK_SERIAL=@Z_FEATURE_LINK_SERIAL@ \\\n  -DBUILD_EXAMPLES=OFF \\\n  -DBUILD_TESTING=OFF \\\n  -DZ_FEATURE_LINK_UDP_MULTICAST=0 \\\n  -DZ_FEATURE_MULTICAST_TRANSPORT=0 \\\n  -DZP_EXTERNAL_PACKAGES=zenohpico-myrtos \\\n  -DCMAKE_PREFIX_PATH=\"$PREFIX_DIR\" \\\n  -DZP_PLATFORM=myrtos\n"
  },
  {
    "path": "tests/raweth.py",
    "content": "import argparse\nimport os\nfrom signal import SIGINT\nimport subprocess\nimport sys\nimport time\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\n\ndef pub_and_sub(args):\n    print(\"*** Pub & sub test ***\")\n    test_status = 0\n\n    # Expected z_pub output & status\n    if args.reth == 1:\n        z_pub_expected_status = 0\n        z_pub_expected_output = '''Opening session...\nWaiting for joins...\nDeclaring publisher for 'demo/example/zenoh-pico-pub'...\nPress CTRL-C to quit...\nPutting Data ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   5] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   6] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   7] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   8] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   9] Pub from Pico!')...'''\n    else :\n        z_pub_expected_status = 255\n        z_pub_expected_output = '''Opening session...\nUnable to open session!'''\n\n    # Expected z_sub output & status\n    if args.reth == 1:\n        z_sub_expected_status = 0\n        z_sub_expected_output = '''Opening session...\nDeclaring Subscriber on 'demo/example/**'...\nPress CTRL-C to quit...\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   5] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   6] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   7] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   8] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   9] Pub from Pico!')'''\n    else :\n        z_sub_expected_status = 255\n        z_sub_expected_output = '''Opening session...\nUnable to open session!'''\n\n    print(\"Start subscriber\")\n    # Start z_sub in the background\n    z_sub_command = f\"sudo stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub -n 10 -m \\\"peer\\\" -l \\\n                    \\\"reth/30:03:8c:c8:00:a2#iface=lo;whitelist=30:03:8c:c8:00:a1,\\\"s\"  \n\n    z_sub_process = subprocess.Popen(z_sub_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE,\n                                    text=True)\n\n    # Introduce a delay to ensure z_sub starts\n    time.sleep(2)\n\n    print(\"Start publisher\")\n    # Start z_pub\n    z_pub_command = f\"sudo stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub -n 10 -m \\\"peer\\\" -l \\\n                    \\\"reth/30:03:8c:c8:00:a1#iface=lo;whitelist=30:03:8c:c8:00:a2,\\\"s\"\n    z_pub_process = subprocess.Popen(z_pub_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE,\n                                    text=True)\n\n    # Wait for z_pub to finish\n    z_pub_process.wait()\n\n    print(\"Stop subscriber\")\n    time.sleep(2)\n    if z_sub_process.poll() is None:\n        # send SIGINT to group\n        z_sub_process_gid = os.getpgid(z_sub_process.pid)\n        os.killpg(z_sub_process_gid, SIGINT)\n\n    # Wait for z_sub to finish\n    z_sub_process.wait()\n\n    print(\"Check publisher status & output\")\n    # Check the exit status of z_pub\n    z_pub_status = z_pub_process.returncode\n    if z_pub_status == z_pub_expected_status:\n        print(\"z_pub status valid\")\n    else:\n        print(f\"z_pub status invalid, expected: {z_pub_expected_status}, received: {z_pub_status}\")\n        test_status = 1\n\n    # Check output of z_pub\n    z_pub_output = z_pub_process.stdout.read()\n    if z_pub_expected_output in z_pub_output:\n        print(\"z_pub output valid\")\n    else:\n        print(\"z_pub output invalid:\")\n        print(f\"Expected: \\\"{z_pub_expected_output}\\\"\")\n        print(f\"Received: \\\"{z_pub_output}\\\"\")\n        test_status = 1\n\n    print(\"Check subscriber status & output\")\n    # Check the exit status of z_sub\n    z_sub_status = z_sub_process.returncode\n    if z_sub_status == z_sub_expected_status:\n        print(\"z_sub status valid\")\n    else:\n        print(f\"z_sub status invalid, expected: {z_sub_expected_status}, received: {z_sub_status}\")\n        test_status = 1\n\n    # Check output of z_sub\n    z_sub_output = z_sub_process.stdout.read()\n    if z_sub_expected_output in z_sub_output:\n        print(\"z_sub output valid\")\n    else:\n        print(\"z_sub output invalid:\")\n        print(f\"Expected: \\\"{z_sub_expected_output}\\\"\")\n        print(f\"Received: \\\"{z_sub_output}\\\"\")\n        test_status = 1\n    # Return value\n    return test_status\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(description=\"This script runs zenoh-pico examples\"\n                                     \" and checks them according to the given configuration\")\n    parser.add_argument(\"--reth\", type=int, choices=[0, 1],\n                        help=\"Z_FEATURE_RAWETH_TRANSPORT (0 or 1)\")\n\n    EXIT_STATUS = 0\n    prog_args = parser.parse_args()\n    print(f\"Args value, reth:{prog_args.reth}\")\n\n    # Test pub and sub examples\n    if pub_and_sub(prog_args) == 1:\n        EXIT_STATUS = 1\n    # Exit\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/routed.sh",
    "content": "#!/bin/sh\n#\n# Copyright (c) 2022 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\nTESTBIN=\"$1\"\nTESTDIR=$(cd \"$(dirname \"$0\")\" && pwd)\n\nif [ \"$OSTYPE\" = \"msys\" ]; then\n  TESTBIN=\"$TESTDIR/Debug/$TESTBIN.exe\"\nelse\n  TESTBIN=\"./$TESTBIN\"\nfi\n\ncd \"$TESTDIR\" || exit\n\necho \"------------------ Running test $TESTBIN -------------------\"\n\nsleep 5\n\n# Clean up if zenohd exists but is not a regular file (handles corrupted state from interrupted runs)\nif [ -e zenohd ] && [ ! -f zenohd ]; then\n    echo \"Warning: zenohd exists but is not a regular file, removing...\"\n    rm -rf zenohd\nfi\n\nif [ ! -f zenohd ]; then\n    if [ ! -d zenoh-git ]; then\n        git clone https://github.com/eclipse-zenoh/zenoh.git zenoh-git\n    fi\n    cd zenoh-git || exit\n    if [ -n \"$ZENOH_BRANCH\" ]; then\n        git switch \"$ZENOH_BRANCH\"\n    fi\n    rustup show\n    cargo build --lib --bin zenohd\n    cp -f ./target/debug/zenohd \"$TESTDIR\"/\n    cd \"$TESTDIR\" || exit\nfi\n\nchmod +x zenohd\n\n# Verify zenohd is ready to use\nif [ ! -f zenohd ]; then\n    echo \"ERROR: zenohd binary not found after build attempt\"\n    exit 1\nfi\n\nif [ ! -x zenohd ]; then\n    echo \"ERROR: zenohd binary is not executable\"\n    exit 1\nfi\n\nLOCATORS=\"tcp/127.0.0.1:7447 tcp/[::1]:7447 udp/127.0.0.1:7447 udp/[::1]:7447\"\nENABLE_TLS=0\nif [ \"$2\" = \"--enable-tls\" ]; then\n    ENABLE_TLS=1\n    LOCATORS=\"$LOCATORS tls/127.0.0.1:7447#root_ca_certificate=$TESTDIR/ca.pem tls/[::1]:7447#root_ca_certificate=$TESTDIR/ca.pem\"\n\n    rm -f ca.pem ca-key.pem ca.srl server.pem server-key.pem server.csr\n\n    cat > server.cnf <<EOF\n[req]\nprompt = no\ndistinguished_name = dn\nreq_extensions = san\n\n[dn]\nCN = localhost\n\n[san]\nsubjectAltName = DNS:localhost,IP:127.0.0.1,IP:::1\nEOF\n\n    openssl req -x509 -newkey rsa:2048 -keyout ca-key.pem -out ca.pem -days 365 -nodes -subj \"/CN=Test CA\"\n    openssl req -newkey rsa:2048 -keyout server-key.pem -out server.csr -nodes -config server.cnf\n    openssl x509 -req -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server.pem -days 365 \\\n        -extfile server.cnf -extensions san\n    rm server.csr server.cnf\nfi\nfor LOCATOR in $(echo \"$LOCATORS\" | xargs); do\n    sleep 1\n\n    echo \"> Running zenohd ... $LOCATOR\"\n    if [ \"$ENABLE_TLS\" = \"1\" ]; then\n        cat > zenohd_tls.json <<EOF\n{\n  \"transport\": {\n    \"link\": {\n      \"tls\": {\n        \"root_ca_certificate\": \"$TESTDIR/ca.pem\",\n        \"listen_private_key\": \"$TESTDIR/server-key.pem\",\n        \"listen_certificate\": \"$TESTDIR/server.pem\"\n      }\n    }\n  }\n}\nEOF\n        RUST_LOG=debug ./zenohd -c zenohd_tls.json --plugin-search-dir \"$TESTDIR/zenoh-git/target/debug\" -l \"$LOCATOR\" > zenohd.\"$1\".log 2>&1 &\n    else\n        RUST_LOG=debug ./zenohd --plugin-search-dir \"$TESTDIR/zenoh-git/target/debug\" -l \"$LOCATOR\" > zenohd.\"$1\".log 2>&1 &\n    fi\n    ZPID=$!\n\n    sleep 5\n\n    # Verify zenohd is actually running\n    if ! kill -0 \"$ZPID\" 2>/dev/null; then\n        echo \"> ERROR: zenohd failed to start (PID: $ZPID)\"\n        echo \"> Logs of zenohd ...\"\n        cat zenohd.\"$1\".log\n        exit 1\n    fi\n\n    echo \"> Running $TESTBIN ...\"\n    \"$TESTBIN\" \"$LOCATOR\" > client.\"$1\".log 2>&1\n    RETCODE=$?\n\n    echo \"> Stopping zenohd ...\"\n    if kill -0 \"$ZPID\" 2>/dev/null; then\n        kill -9 \"$ZPID\"\n        wait \"$ZPID\" 2>/dev/null\n    else\n        echo \"> WARNING: zenohd (PID: $ZPID) was not running\"\n    fi\n    sleep 1\n\n    if [ \"$RETCODE\" -lt 0 ]; then\n        echo \"> Logs of client ...\"\n        cat client.\"$1\".log\n        echo \"> Logs of zenohd ...\"\n        cat zenohd.\"$1\".log\n        exit \"$RETCODE\"\n    fi\ndone\n\necho \"> Done ($RETCODE).\"\nexit \"$RETCODE\"\n"
  },
  {
    "path": "tests/routed_peer_client.py",
    "content": "\"\"\"Test suite for pub (peer) > router > sub (client) scenarios.\"\"\"\nimport os\nfrom signal import SIGINT\nimport subprocess\nimport sys\nimport time\nimport re\n\n# pylint: disable=consider-using-with\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\n\n\ndef pub_and_sub(pub_args, sub_args, pub_first=True):\n    \"\"\"\n    Run a publisher and subscriber test.\n\n    Parameters:\n        pub_args (str): Arguments passed to the publisher binary.\n        sub_args (str): Arguments passed to the subscriber binary.\n        pub_first (bool): If True, start publisher first; otherwise start subscriber first.\n\n    Returns:\n        int: 0 if the test passes, 1 if it fails.\n    \"\"\"\n    test_status = 0\n\n    # Expected z_pub status\n    z_pub_expected_status = 0\n\n    # Expected z_sub output & status\n    z_sub_expected_status = 0\n    z_sub_expected_pattern = re.compile(\n        r\">> \\[Subscriber\\] Received \\('demo/example/zenoh-pico-pub': '\\[.*?\\] Pub from Pico!'\\)\"\n    )\n\n    z_pub_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub {pub_args} -n 10\"\n    z_sub_command = f\"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub {sub_args} -n 1\"\n\n    print(\"PUB CMD:\", z_pub_command)\n    print(\"SUB CMD:\", z_sub_command)\n\n    if pub_first:\n        print(\"Start publisher\")\n        # Start z_pub first\n        z_pub_process = subprocess.Popen(\n            z_pub_command,\n            shell=True,\n            stdin=subprocess.PIPE,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n            text=True,\n        )\n\n        # Give publisher time to start\n        time.sleep(2)\n\n        print(\"Start subscriber\")\n        # Then start z_sub\n        z_sub_process = subprocess.Popen(\n            z_sub_command,\n            shell=True,\n            stdin=subprocess.PIPE,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n            text=True,\n            start_new_session=True,\n        )\n    else:\n        print(\"Start subscriber\")\n        # Start z_sub first\n        z_sub_process = subprocess.Popen(\n            z_sub_command,\n            shell=True,\n            stdin=subprocess.PIPE,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n            text=True,\n            start_new_session=True,\n        )\n\n        # Give subscriber time to start\n        time.sleep(2)\n\n        print(\"Start publisher\")\n        # Then start z_pub\n        z_pub_process = subprocess.Popen(\n            z_pub_command,\n            shell=True,\n            stdin=subprocess.PIPE,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n            text=True,\n        )\n\n    # Wait for z_pub to finish and capture its output\n    pub_stdout, pub_stderr = z_pub_process.communicate()\n\n    print(\"Stop subscriber\")\n    if z_sub_process.poll() is None:\n        # send SIGINT to group (safe because of start_new_session=True)\n        z_sub_process_gid = os.getpgid(z_sub_process.pid)\n        os.killpg(z_sub_process_gid, SIGINT)\n\n    # Ensure subscriber has exited and capture its output\n    sub_stdout, sub_stderr = z_sub_process.communicate()\n\n    print(\"Check publisher status\")\n    # Check the exit status of z_pub\n    z_pub_status = z_pub_process.returncode\n    if z_pub_status == z_pub_expected_status:\n        print(\"z_pub status valid\")\n    else:\n        print(f\"z_pub status invalid, expected: {z_pub_expected_status}, received: {z_pub_status}\")\n        test_status = 1\n\n    print(\"Check subscriber status & output\")\n    # Check the exit status of z_sub\n    z_sub_status = z_sub_process.returncode\n    if z_sub_status == z_sub_expected_status:\n        print(\"z_sub status valid\")\n    else:\n        print(f\"z_sub status invalid, expected: {z_sub_expected_status}, received: {z_sub_status}\")\n        test_status = 1\n\n    # Check the output of z_sub\n    if z_sub_expected_pattern.search(sub_stdout):\n        print(\"z_sub output valid\")\n    else:\n        print(\"z_sub output invalid:\")\n        test_status = 1\n\n    # If anything failed, dump stdout/stderr for both processes\n    if test_status == 1:\n        print(\"==== z_pub STDOUT ====\")\n        print(pub_stdout or \"\")\n        print(\"==== z_pub STDERR ====\")\n        print(pub_stderr or \"\")\n\n        print(\"==== z_sub STDOUT ====\")\n        print(sub_stdout or \"\")\n        print(\"==== z_sub STDERR ====\")\n        print(sub_stderr or \"\")\n\n    # Return value\n    return test_status\n\ndef test_tcp_unicast(locator, pub_first=True):\n    \"\"\"Run TCP unicast pub/sub test.\"\"\"\n    print(f\"*** TCP Unicast Test (pub_first={pub_first}) ***\")\n    pub_args = f\"-m peer -e {locator}\"\n    sub_args = f\"-m client -e {locator}\"\n\n    return pub_and_sub(pub_args, sub_args, pub_first)\n\ndef test_udp_multicast(tcp_locator, udp_locator, pub_first=True):\n    \"\"\"Run UDP multicast pub/sub test.\"\"\"\n    print(f\"*** UDP Multicast Test (pub_first={pub_first}) ***\")\n    pub_args = f\"-m peer -l {udp_locator}\"\n    sub_args = f\"-m client -e {tcp_locator}\"\n\n    return pub_and_sub(pub_args, sub_args, pub_first)\n\nif __name__ == \"__main__\":\n    EXIT_STATUS = 0\n\n    TCP_UNICAST_LOCATOR = None # pylint: disable=invalid-name\n    UDP_MULTICAST_LOCATOR = None # pylint: disable=invalid-name\n\n    args = sys.argv[1:]\n\n    for arg in args:\n        if arg.startswith(\"tcp/\"):\n            TCP_UNICAST_LOCATOR = arg\n        elif arg.startswith(\"udp/\"):\n            UDP_MULTICAST_LOCATOR = arg\n\n    print(\"TCP unicast locator:\", TCP_UNICAST_LOCATOR)\n    print(\"UDP multicast locator:\", UDP_MULTICAST_LOCATOR)\n\n    if TCP_UNICAST_LOCATOR is not None:\n        if test_tcp_unicast(TCP_UNICAST_LOCATOR, True) == 1:\n            EXIT_STATUS = 1\n        if test_tcp_unicast(TCP_UNICAST_LOCATOR, False) == 1:\n            EXIT_STATUS = 1\n    else:\n        print(\"No TCP unicast locator provided, skipping test_tcp_unicast.\")\n\n    if TCP_UNICAST_LOCATOR is not None and UDP_MULTICAST_LOCATOR is not None:\n        if test_udp_multicast(TCP_UNICAST_LOCATOR, UDP_MULTICAST_LOCATOR, True) == 1:\n            EXIT_STATUS = 1\n        if test_udp_multicast(TCP_UNICAST_LOCATOR, UDP_MULTICAST_LOCATOR, False) == 1:\n            EXIT_STATUS = 1\n    else:\n        print(\"No TCP unicast or UDP multicast locators provided, skipping test_udp_multicast.\")\n\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/single_thread.py",
    "content": "import subprocess\nimport signal\nimport sys\nimport time\n\n# Specify the directory for the binaries\nDIR_EXAMPLES = \"build/examples\"\n\ndef pub_and_sub():\n    print(\"*** Pub & sub test ***\")\n    test_status = 0\n\n    # Expected z_pub output & status\n    z_pub_expected_status = 0\n    z_pub_expected_output = '''Opening session...\nDeclaring publisher for 'demo/example/zenoh-pico-pub'...\nPress CTRL-C to quit...\nPutting Data ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   5] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   6] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   7] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   8] Pub from Pico!')...\nPutting Data ('demo/example/zenoh-pico-pub': '[   9] Pub from Pico!')...'''\n\n    # Expected z_sub output\n    z_sub_expected_status = 0\n    z_sub_expected_output = '''Opening session...\nDeclaring Subscriber on 'demo/example/**'...\nPress CTRL-C to quit...\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   0] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   1] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   2] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   3] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   4] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   5] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   6] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   7] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   8] Pub from Pico!')\n>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[   9] Pub from Pico!')'''\n\n    print(\"Start subscriber\")\n    # Start z_sub in the background\n    z_sub_command = f\"./{DIR_EXAMPLES}/z_sub_st -n 10\"\n    z_sub_process = subprocess.Popen(z_sub_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE,\n                                    text=True)\n\n    # Introduce a delay to ensure z_sub starts\n    time.sleep(2)\n\n    print(\"Start publisher\")\n    # Start z_pub\n    z_pub_command = f\"./{DIR_EXAMPLES}/z_pub_st -n 10\"\n    z_pub_process = subprocess.Popen(z_pub_command,\n                                    shell=True,\n                                    stdin=subprocess.PIPE,\n                                    stdout=subprocess.PIPE,\n                                    stderr=subprocess.PIPE,\n                                    text=True)\n\n    # Wait for z_pub to finish\n    z_pub_process.wait()\n    z_sub_process.wait()\n\n    print(\"Check publisher status & output\")\n    # Check the exit status of z_pub\n    z_pub_status = z_pub_process.returncode\n    if z_pub_status == z_pub_expected_status:\n        print(\"z_pub status valid\")\n    else:\n        print(f\"z_pub status invalid, expected: {z_pub_expected_status}, received: {z_pub_status}\")\n        test_status = 1\n\n    # Check output of z_pub\n    z_pub_output = z_pub_process.stdout.read()\n    if z_pub_expected_output in z_pub_output:\n        print(\"z_pub output valid\")\n    else:\n        print(\"z_pub output invalid:\")\n        print(f\"Expected: \\\"{z_pub_expected_output}\\\"\")\n        print(f\"Received: \\\"{z_pub_output}\\\"\")\n        test_status = 1\n\n    print(\"Check subscriber status & output\")\n    # Check the exit status of z_sub\n    z_sub_status = z_sub_process.returncode\n    if z_sub_status == z_sub_expected_status:\n        print(\"z_sub status valid\")\n    else:\n        print(f\"z_sub status invalid, expected: {z_sub_expected_status}, received: {z_sub_status}\")\n        test_status = 1\n\n    # Check output of z_sub\n    z_sub_output = z_sub_process.stdout.read()\n    if z_sub_expected_output in z_sub_output:\n        print(\"z_sub output valid\")\n    else:\n        print(\"z_sub output invalid:\")\n        print(f\"Expected: \\\"{z_sub_expected_output}\\\"\")\n        print(f\"Received: \\\"{z_sub_output}\\\"\")\n        test_status = 1\n    # Return value\n    return test_status\n\nif __name__ == \"__main__\":\n    EXIT_STATUS = 0\n\n    # Test pub and sub examples\n    if pub_and_sub() == 1:\n        EXIT_STATUS = 1\n    # Exit\n    sys.exit(EXIT_STATUS)\n"
  },
  {
    "path": "tests/tls_verify.sh",
    "content": "#!/bin/sh\n#\n# Copyright (c) 2025 ZettaScale Technology\n#\n# This program and the accompanying materials are made available under the\n# terms of the Eclipse Public License 2.0 which is available at\n# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n# which is available at https://www.apache.org/licenses/LICENSE-2.0.\n#\n# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n#\n# Contributors:\n#   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n#\n\nTESTBIN=\"$1\"\nTESTDIR=$(dirname \"$0\")\n\nif [ \"$OSTYPE\" = \"msys\" ]; then\n  TESTBIN=\"$TESTDIR/Debug/$TESTBIN.exe\"\nelse\n  TESTBIN=\"./$TESTBIN\"\nfi\n\ncd \"$TESTDIR\" || exit 1\n\nif [ ! -f zenohd ]; then\n    git clone https://github.com/eclipse-zenoh/zenoh.git zenoh-git\n    cd zenoh-git || exit 1\n    if [ -n \"$ZENOH_BRANCH\" ]; then\n        git switch \"$ZENOH_BRANCH\"\n    fi\n    cargo build --lib --bin zenohd\n    cp ./target/debug/zenohd \"$TESTDIR\"/\n    cd \"$TESTDIR\" || exit 1\nfi\n\nchmod +x zenohd\n\nrm -f ca.pem ca-key.pem ca.srl server.pem server-key.pem server.csr\ncat > server.cnf <<EOF\n[ req ]\nprompt = no\ndistinguished_name = dn\nreq_extensions = san\n\n[ dn ]\nCN = localhost\n\n[ san ]\nsubjectAltName = DNS:localhost\nEOF\n\nopenssl req -x509 -newkey rsa:2048 -keyout ca-key.pem -out ca.pem -days 30 -nodes -subj \"/CN=Test CA\"\nopenssl req -newkey rsa:2048 -keyout server-key.pem -out server.csr -nodes -config server.cnf\nopenssl x509 -req -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server.pem -days 30 \\\n    -extfile server.cnf -extensions san\nrm -f server.csr server.cnf\n\ncat > client.cnf <<EOF\n[ req ]\nprompt = no\ndistinguished_name = dn\nreq_extensions = v3_req\n\n[ dn ]\nCN = Test Client\n\n[ v3_req ]\nbasicConstraints = CA:FALSE\nkeyUsage = critical, digitalSignature, keyEncipherment\nextendedKeyUsage = clientAuth\nEOF\n\nopenssl req -newkey rsa:2048 -keyout client-key.pem -out client.csr -nodes -config client.cnf\nopenssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client.pem -days 30 \\\n    -extfile client.cnf -extensions v3_req\nrm -f client.csr client.cnf\n\ncat > zenohd_tls.json <<EOF\n{\n  \"transport\": {\n    \"link\": {\n      \"tls\": {\n        \"root_ca_certificate\": \"$TESTDIR/ca.pem\",\n        \"listen_private_key\": \"$TESTDIR/server-key.pem\",\n        \"listen_certificate\": \"$TESTDIR/server.pem\"\n      }\n    }\n  }\n}\nEOF\n\nLOC_BASE=\"tls/127.0.0.1:7447\"\n\nrun_test() {\n    locator=\"$1\"\n    expect_success=\"$2\"\n    config_file=\"${3:-zenohd_tls.json}\"\n\n    echo \"> Running ./zenohd -c $config_file -l ${LOC_BASE} ...\"\n    RUST_LOG=warn ./zenohd -c \"$config_file\" --plugin-search-dir \"$TESTDIR/zenoh-git/target/debug\" \\\n        -l \"$LOC_BASE\" > zenohd.z_tls_verify.log 2>&1 &\n    ZPID=$!\n    sleep 5\n\n    echo \"> Running $TESTBIN \\\"$locator\\\" ...\"\n    \"$TESTBIN\" \"$locator\" --msgs=1 > client.z_tls_verify.log 2>&1\n    RETCODE=$?\n\n    echo \"> Stopping zenohd ...\"\n    kill -9 \"$ZPID\" 2>/dev/null || true\n    wait \"$ZPID\" 2>/dev/null || true\n    sleep 1\n\n    if [ \"$expect_success\" = \"1\" ]; then\n        if [ \"$RETCODE\" -ne 0 ]; then\n            echo \"Expected success but client exited with $RETCODE\" >&2\n            cat client.z_tls_verify.log >&2\n            exit 1\n        fi\n    else\n        if [ \"$RETCODE\" -eq 0 ]; then\n            echo \"Expected failure but client succeeded\" >&2\n            cat client.z_tls_verify.log >&2\n            exit 1\n        fi\n    fi\n}\n\nrun_test \"$LOC_BASE#root_ca_certificate=$TESTDIR/ca.pem\" 0\nrun_test \"$LOC_BASE#root_ca_certificate=$TESTDIR/ca.pem;verify_name_on_connect=0\" 1\n\ncat > zenohd_tls_mtls.json <<EOF\n{\n  \"transport\": {\n    \"link\": {\n      \"tls\": {\n        \"root_ca_certificate\": \"$TESTDIR/ca.pem\",\n        \"listen_private_key\": \"$TESTDIR/server-key.pem\",\n        \"listen_certificate\": \"$TESTDIR/server.pem\",\n        \"enable_mtls\": true\n      }\n    }\n  }\n}\nEOF\n\nrun_test \"$LOC_BASE#root_ca_certificate=$TESTDIR/ca.pem;enable_mtls=1\" 0 zenohd_tls_mtls.json\nrun_test \"$LOC_BASE#root_ca_certificate=$TESTDIR/ca.pem;enable_mtls=1;connect_private_key=$TESTDIR/client-key.pem;connect_certificate=$TESTDIR/client.pem;verify_name_on_connect=0\" 1 zenohd_tls_mtls.json\n\nrm -f client.z_tls_verify.log zenohd.z_tls_verify.log zenohd_tls_mtls.json\nrm -f client.pem client-key.pem server.pem server-key.pem ca.pem ca-key.pem ca.srl\nexit 0\n"
  },
  {
    "path": "tests/utils/assert_helpers.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef ZP_ASSERT_HELPERS_H\n#define ZP_ASSERT_HELPERS_H\n\n#include <assert.h>\n#include <inttypes.h>\n#include <stdbool.h>\n#include <stdio.h>\n\n#include \"zenoh-pico/utils/result.h\"\n\n#ifdef NDEBUG\n#include <stdlib.h>\n#endif\n\n// Fallbacks for older libcs\n#ifndef PRIu32\n#define PRIu32 \"u\"\n#endif\n#ifndef PRIu64\n#define PRIu64 \"llu\"\n#endif\n#ifndef PRIi32\n#define PRIi32 \"d\"\n#endif\n\n// Trap that fails in both debug and release builds\n#ifndef NDEBUG\n#define _ZP_TEST_TRAP() (assert(0 && \"test assertion failed\"))\n#else\n#define _ZP_TEST_TRAP() (abort())\n#endif\n\n// ---------- Assertions ----------\n\n#define ASSERT_TRUE(expr)                                                                         \\\n    do {                                                                                          \\\n        bool _zp_v_ = (expr);                                                                     \\\n        if (!_zp_v_) {                                                                            \\\n            fprintf(stderr, \"[FAIL] %s:%d: expected %s to be true\\n\", __FILE__, __LINE__, #expr); \\\n            fflush(stderr);                                                                       \\\n            _ZP_TEST_TRAP();                                                                      \\\n        }                                                                                         \\\n    } while (0)\n\n#define ASSERT_FALSE(expr)                                                                         \\\n    do {                                                                                           \\\n        bool _zp_v_ = (expr);                                                                      \\\n        if (_zp_v_) {                                                                              \\\n            fprintf(stderr, \"[FAIL] %s:%d: expected %s to be false\\n\", __FILE__, __LINE__, #expr); \\\n            fflush(stderr);                                                                        \\\n            _ZP_TEST_TRAP();                                                                       \\\n        }                                                                                          \\\n    } while (0)\n\n#define ASSERT_EQ_U32(a, b)                                                                                         \\\n    do {                                                                                                            \\\n        uint32_t _zp_a_ = (uint32_t)(a);                                                                            \\\n        uint32_t _zp_b_ = (uint32_t)(b);                                                                            \\\n        if (_zp_a_ != _zp_b_) {                                                                                     \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s (%\" PRIu32 \") != %s (%\" PRIu32 \")\\n\", __FILE__, __LINE__, #a, _zp_a_, \\\n                    #b, _zp_b_);                                                                                    \\\n            fflush(stderr);                                                                                         \\\n            _ZP_TEST_TRAP();                                                                                        \\\n        }                                                                                                           \\\n    } while (0)\n\n#define ASSERT_EQ_U64(a, b)                                                                                         \\\n    do {                                                                                                            \\\n        uint64_t _zp_a_ = (uint64_t)(a);                                                                            \\\n        uint64_t _zp_b_ = (uint64_t)(b);                                                                            \\\n        if (_zp_a_ != _zp_b_) {                                                                                     \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s (%\" PRIu64 \") != %s (%\" PRIu64 \")\\n\", __FILE__, __LINE__, #a, _zp_a_, \\\n                    #b, _zp_b_);                                                                                    \\\n            fflush(stderr);                                                                                         \\\n            _ZP_TEST_TRAP();                                                                                        \\\n        }                                                                                                           \\\n    } while (0)\n\n#define ASSERT_EQ_I32(a, b)                                                                                         \\\n    do {                                                                                                            \\\n        int32_t _zp_a_ = (int32_t)(a);                                                                              \\\n        int32_t _zp_b_ = (int32_t)(b);                                                                              \\\n        if (_zp_a_ != _zp_b_) {                                                                                     \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s (%\" PRIi32 \") != %s (%\" PRIi32 \")\\n\", __FILE__, __LINE__, #a, _zp_a_, \\\n                    #b, _zp_b_);                                                                                    \\\n            fflush(stderr);                                                                                         \\\n            _ZP_TEST_TRAP();                                                                                        \\\n        }                                                                                                           \\\n    } while (0)\n\n#define ASSERT_EQ_PTR(a, b)                                                                                    \\\n    do {                                                                                                       \\\n        const void *_zp_a_ = (const void *)(a);                                                                \\\n        const void *_zp_b_ = (const void *)(b);                                                                \\\n        if (_zp_a_ != _zp_b_) {                                                                                \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s (%p) != %s (%p)\\n\", __FILE__, __LINE__, #a, _zp_a_, #b, _zp_b_); \\\n            fflush(stderr);                                                                                    \\\n            _ZP_TEST_TRAP();                                                                                   \\\n        }                                                                                                      \\\n    } while (0)\n\n#define ASSERT_OK(expr)                                                                                  \\\n    do {                                                                                                 \\\n        z_result_t _zp_res_ = (expr);                                                                    \\\n        if (_zp_res_ != _Z_RES_OK) {                                                                     \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s returned %d\\n\", __FILE__, __LINE__, #expr, (int)_zp_res_); \\\n            fflush(stderr);                                                                              \\\n            _ZP_TEST_TRAP();                                                                             \\\n        }                                                                                                \\\n    } while (0)\n\n// Expect any error (i.e., not _Z_RES_OK)\n#define ASSERT_NOT_OK(expr)                                                                                \\\n    do {                                                                                                   \\\n        z_result_t _zp_res_ = (expr);                                                                      \\\n        if (_zp_res_ == _Z_RES_OK) {                                                                       \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s returned OK (expected error)\\n\", __FILE__, __LINE__, #expr); \\\n            fflush(stderr);                                                                                \\\n            _ZP_TEST_TRAP();                                                                               \\\n        }                                                                                                  \\\n    } while (0)\n\n// Expect a specific error/result code\n#define ASSERT_ERR(expr, expected)                                                                                    \\\n    do {                                                                                                              \\\n        z_result_t _zp_res_ = (expr);                                                                                 \\\n        z_result_t _zp_exp_ = (expected);                                                                             \\\n        if (_zp_res_ != _zp_exp_) {                                                                                   \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s returned %d (expected %d)\\n\", __FILE__, __LINE__, #expr, (int)_zp_res_, \\\n                    (int)_zp_exp_);                                                                                   \\\n            fflush(stderr);                                                                                           \\\n            _ZP_TEST_TRAP();                                                                                          \\\n        }                                                                                                             \\\n    } while (0)\n\n// Expect a non null pointer\n#define ASSERT_NOT_NULL(ptr)                                                         \\\n    do {                                                                             \\\n        const void *_zp_p_ = (const void *)(ptr);                                    \\\n        if (_zp_p_ == NULL) {                                                        \\\n            fprintf(stderr, \"[FAIL] %s:%d: %s is NULL\\n\", __FILE__, __LINE__, #ptr); \\\n            fflush(stderr);                                                          \\\n            _ZP_TEST_TRAP();                                                         \\\n        }                                                                            \\\n    } while (0)\n\n#endif  // ZP_ASSERT_HELPERS_H\n"
  },
  {
    "path": "tests/utils/tcp_proxy.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n//\n// Copyright (c) 2025 ZettaScale Technology\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n\n#include \"tcp_proxy.h\"\n\n#include <arpa/inet.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <netdb.h>\n#include <pthread.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/select.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <time.h>\n#include <unistd.h>\n\n#ifndef TCP_MAX_CONNS\n#define TCP_MAX_CONNS 8\n#endif\n#ifndef TCP_BUFSZ\n#define TCP_BUFSZ 65536\n#endif\n\ntypedef int sock_t;\n\ntypedef struct {\n    sock_t cli;\n    sock_t up;\n} tcp_pair_t;\n\nstruct tcp_proxy {\n    char lhost[64];\n    char thost[64];\n    uint16_t tport;\n\n    volatile bool run;\n    volatile bool enabled;\n    pthread_t thr;\n\n    sock_t lsock;  // listening socket\n    tcp_pair_t conns[TCP_MAX_CONNS];\n    int nconns;\n\n    pthread_mutex_t mtx;  // guards enabled + conns[]\n};\n\n// ---- utilities ----\nstatic void msleep_(int ms) {\n    struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L};\n    nanosleep(&ts, NULL);\n}\n\nstatic int set_nonblock(sock_t s) {\n    int fl = fcntl(s, F_GETFL, 0);\n    return fcntl(s, F_SETFL, fl | O_NONBLOCK);\n}\n\nstatic sock_t tcp_listen4_ephemeral(const char* host) {\n    struct sockaddr_in sa = {0};\n    sa.sin_family = AF_INET;\n    sa.sin_port = htons(0);  // ephemeral\n    if (host == NULL) {\n        host = \"127.0.0.1\";\n    }\n    if (inet_pton(AF_INET, host, &sa.sin_addr) != 1) {\n        return -1;\n    }\n    sock_t s = socket(AF_INET, SOCK_STREAM, 0);\n    if (s < 0) {\n        return -1;\n    }\n    int one = 1;\n    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));\n#ifdef SO_REUSEPORT\n    setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));\n#endif\n    if (bind(s, (struct sockaddr*)&sa, sizeof sa) != 0) {\n        close(s);\n        return -1;\n    }\n    if (listen(s, 64) != 0) {\n        close(s);\n        return -1;\n    }\n    (void)set_nonblock(s);\n    return s;\n}\n\nstatic int get_sock_port(sock_t s) {\n    struct sockaddr_in sa;\n    socklen_t sl = sizeof sa;\n    if (getsockname(s, (struct sockaddr*)&sa, &sl) != 0) {\n        return -1;\n    }\n    return (int)ntohs(sa.sin_port);\n}\n\nstatic int tcp_connect4(const char* host, uint16_t port) {\n    char pbuf[16];\n    snprintf(pbuf, sizeof pbuf, \"%u\", (unsigned)port);\n    struct addrinfo hints = {0};\n    struct addrinfo* res = NULL;\n    hints.ai_family = AF_INET;\n    hints.ai_socktype = SOCK_STREAM;\n    if (getaddrinfo((host != NULL) ? host : \"127.0.0.1\", pbuf, &hints, &res) != 0) {\n        return -1;\n    }\n    sock_t s = -1;\n    for (struct addrinfo* ai = res; ai != NULL; ai = ai->ai_next) {\n        s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);\n        if (s < 0) {\n            continue;\n        }\n        if (connect(s, ai->ai_addr, ai->ai_addrlen) == 0) {\n            break;\n        }\n        close(s);\n        s = -1;\n    }\n    freeaddrinfo(res);\n    if (s >= 0) {\n        (void)set_nonblock(s);\n    }\n    return s;\n}\n\nstatic void pair_close(tcp_pair_t* pr) {\n    if (pr->cli >= 0) {\n        close(pr->cli);\n        pr->cli = -1;\n    }\n    if (pr->up >= 0) {\n        close(pr->up);\n        pr->up = -1;\n    }\n}\n\n// ---- thread ----\n// When disabled, we still recv() (to ACK at TCP level) but DROP data instead of forwarding.\nstatic void* proxy_thread(void* arg) {\n    tcp_proxy_t* p = (tcp_proxy_t*)arg;\n\n    while (p->run) {\n        fd_set rfds;\n        FD_ZERO(&rfds);\n        FD_SET(p->lsock, &rfds);\n        int maxfd = p->lsock;\n\n        pthread_mutex_lock(&p->mtx);\n        for (int i = 0; i < p->nconns; i++) {\n            if (p->conns[i].cli >= 0) {\n                FD_SET(p->conns[i].cli, &rfds);\n                if (p->conns[i].cli > maxfd) {\n                    maxfd = p->conns[i].cli;\n                }\n            }\n            if (p->conns[i].up >= 0) {\n                FD_SET(p->conns[i].up, &rfds);\n                if (p->conns[i].up > maxfd) {\n                    maxfd = p->conns[i].up;\n                }\n            }\n        }\n        bool forward_enabled = p->enabled;\n        pthread_mutex_unlock(&p->mtx);\n\n        struct timeval tv = (struct timeval){.tv_sec = 0, .tv_usec = 200 * 1000};  // 200 ms\n        int ready = select(maxfd + 1, &rfds, NULL, NULL, &tv);\n        if (ready <= 0) {\n            continue;\n        }\n\n        // Accept new clients\n        if (FD_ISSET(p->lsock, &rfds)) {\n            struct sockaddr_in cli;\n            socklen_t clen = sizeof cli;\n            int cs = accept(p->lsock, (struct sockaddr*)&cli, &clen);\n            if (cs >= 0) {\n                (void)set_nonblock(cs);\n                int ups = tcp_connect4(p->thost, p->tport);\n                if (ups < 0) {\n                    close(cs);\n                } else {\n                    pthread_mutex_lock(&p->mtx);\n                    if (p->nconns < TCP_MAX_CONNS) {\n                        p->conns[p->nconns].cli = cs;\n                        p->conns[p->nconns].up = ups;\n                        p->nconns++;\n                    } else {\n                        close(cs);\n                        close(ups);\n                    }\n                    pthread_mutex_unlock(&p->mtx);\n                }\n            }\n        }\n\n        // Pump both directions\n        pthread_mutex_lock(&p->mtx);\n        for (int i = 0; i < p->nconns; i++) {\n            tcp_pair_t* pr = &p->conns[i];\n            char buf[TCP_BUFSZ];\n\n            // client -> upstream\n            if (pr->cli >= 0 && FD_ISSET(pr->cli, &rfds)) {\n                ssize_t nread = recv(pr->cli, buf, sizeof buf, 0);\n                if (nread <= 0) {\n                    pair_close(pr);\n                } else {\n                    if (forward_enabled) {\n                        size_t off = 0;\n                        size_t total = (size_t)nread;\n                        while (off < total) {\n                            ssize_t nw = send(pr->up, buf + off, total - off, 0);\n                            if (nw <= 0) {\n                                pair_close(pr);\n                                break;\n                            }\n                            off += (size_t)nw;\n                        }\n                    }\n                    // else DROP: consumed but not forwarded (client sees ACKs)\n                }\n            }\n\n            // upstream -> client\n            if (pr->up >= 0 && FD_ISSET(pr->up, &rfds)) {\n                ssize_t nread = recv(pr->up, buf, sizeof buf, 0);\n                if (nread <= 0) {\n                    pair_close(pr);\n                } else {\n                    if (forward_enabled) {\n                        size_t off = 0;\n                        size_t total = (size_t)nread;\n                        while (off < total) {\n                            ssize_t nw = send(pr->cli, buf + off, total - off, 0);\n                            if (nw <= 0) {\n                                pair_close(pr);\n                                break;\n                            }\n                            off += (size_t)nw;\n                        }\n                    }\n                    // else DROP: consumed but not forwarded\n                }\n            }\n        }\n\n        // Compact live pairs\n        int w = 0;\n        for (int r = 0; r < p->nconns; r++) {\n            if (p->conns[r].cli >= 0) {\n                p->conns[w++] = p->conns[r];\n            }\n        }\n        p->nconns = w;\n        pthread_mutex_unlock(&p->mtx);\n    }\n\n    return NULL;\n}\n\n// ---- API ----\ntcp_proxy_t* tcp_proxy_create(const char* listen_host, const char* target_host, uint16_t target_port) {\n    tcp_proxy_t* p = calloc(1, sizeof *p);\n    if (p == NULL) {\n        return NULL;\n    }\n    snprintf(p->lhost, sizeof p->lhost, \"%s\", (listen_host != NULL) ? listen_host : \"127.0.0.1\");\n    snprintf(p->thost, sizeof p->thost, \"%s\", (target_host != NULL) ? target_host : \"127.0.0.1\");\n    p->tport = target_port;\n\n    p->run = false;\n    p->enabled = true;\n    p->lsock = -1;\n    p->nconns = 0;\n    for (int i = 0; i < TCP_MAX_CONNS; i++) {\n        p->conns[i].cli = -1;\n        p->conns[i].up = -1;\n    }\n    pthread_mutex_init(&p->mtx, NULL);\n    return p;\n}\n\nint tcp_proxy_start(tcp_proxy_t* p, int ms_timeout) {\n    if (p == NULL) {\n        return -1;  // invalid arg\n    }\n    if (p->run) {\n        int cur = (p->lsock >= 0) ? get_sock_port(p->lsock) : -3;\n        return (cur >= 0) ? cur : -3;\n    }\n\n    // Create listening socket now so we know the ephemeral port.\n    p->lsock = tcp_listen4_ephemeral(p->lhost);\n    if (p->lsock < 0) {\n        return -2;  // listen failed\n    }\n    int port = get_sock_port(p->lsock);\n    if (port < 0) {\n        close(p->lsock);\n        p->lsock = -1;\n        return -3;  // getsockname failed\n    }\n\n    p->run = true;\n    if (pthread_create(&p->thr, NULL, proxy_thread, p) != 0) {\n        p->run = false;\n        close(p->lsock);\n        p->lsock = -1;\n        return -4;  // thread failed\n    }\n\n    // Optional grace period for the thread to enter its loop.\n    if (ms_timeout > 0) {\n        int waited = 0;\n        const int step = 10;\n        while (waited < ms_timeout) {\n            msleep_(step);\n            waited += step;\n        }\n    }\n\n    return port;  // success: ephemeral port\n}\n\nint tcp_proxy_stop(tcp_proxy_t* p) {\n    if (p == NULL) {\n        return -1;\n    }\n    if (!p->run) {\n        return 0;\n    }\n    p->run = false;\n    pthread_join(p->thr, NULL);\n\n    // Close listening socket and all pairs.\n    if (p->lsock >= 0) {\n        close(p->lsock);\n        p->lsock = -1;\n    }\n    pthread_mutex_lock(&p->mtx);\n    for (int i = 0; i < p->nconns; i++) {\n        pair_close(&p->conns[i]);\n    }\n    p->nconns = 0;\n    pthread_mutex_unlock(&p->mtx);\n\n    return 0;\n}\n\nvoid tcp_proxy_destroy(tcp_proxy_t* p) {\n    if (p == NULL) {\n        return;\n    }\n    if (p->run) {\n        (void)tcp_proxy_stop(p);\n    }\n    if (p->lsock >= 0) {\n        close(p->lsock);\n        p->lsock = -1;\n    }\n    pthread_mutex_destroy(&p->mtx);\n    free(p);\n}\n\nvoid tcp_proxy_set_enabled(tcp_proxy_t* p, bool enabled) {\n    if (p == NULL) {\n        return;\n    }\n    pthread_mutex_lock(&p->mtx);\n    p->enabled = enabled;\n    pthread_mutex_unlock(&p->mtx);\n}\n\nbool tcp_proxy_get_enabled(const tcp_proxy_t* p) {\n    if (p == NULL) {\n        return false;\n    }\n    return p->enabled;\n}\n\nvoid tcp_proxy_close_all(tcp_proxy_t* p) {\n    if (p == NULL) {\n        return;\n    }\n    pthread_mutex_lock(&p->mtx);\n    for (int i = 0; i < p->nconns; i++) {\n        pair_close(&p->conns[i]);\n    }\n    p->nconns = 0;\n    pthread_mutex_unlock(&p->mtx);\n}\n\nvoid tcp_proxy_drop_for_ms(tcp_proxy_t* p, int ms) {\n    if (p == NULL) {\n        return;\n    }\n    tcp_proxy_set_enabled(p, false);\n    msleep_(ms);\n    tcp_proxy_set_enabled(p, true);\n}\n"
  },
  {
    "path": "tests/utils/tcp_proxy.h",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#ifndef TCP_PROXY_H\n#define TCP_PROXY_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\ntypedef struct tcp_proxy tcp_proxy_t;\n\n// Create a proxy (not started). The proxy always binds to an ephemeral port.\n// listen_host may be NULL => \"127.0.0.1\"\n// target_host may be NULL => \"127.0.0.1\"\ntcp_proxy_t* tcp_proxy_create(const char* listen_host, const char* target_host, uint16_t target_port);\n\n// Start/stop the background proxy thread.\n// On success, returns the ephemeral TCP port bound on listen_host (>= 0).\n// On failure, returns a negative error code.\nint tcp_proxy_start(tcp_proxy_t* p, int ms_timeout);\nint tcp_proxy_stop(tcp_proxy_t* p);\n\n// Destroy the proxy (safe if already stopped).\nvoid tcp_proxy_destroy(tcp_proxy_t* p);\n\n// Enable/disable forwarding (true = forward, false = drop/blackhole).\nvoid tcp_proxy_set_enabled(tcp_proxy_t* p, bool enabled);\nbool tcp_proxy_get_enabled(const tcp_proxy_t* p);\n\n// Hard disconnect: close all client<->upstream pairs.\nvoid tcp_proxy_close_all(tcp_proxy_t* p);\n\n// Convenience: drop (blackhole) for ms, then restore to enabled = true.\nvoid tcp_proxy_drop_for_ms(tcp_proxy_t* p, int ms);\n\n#endif  // TCP_PROXY_H\n"
  },
  {
    "path": "tests/valgrind.supp",
    "content": "# Suppress GLIBC TLS dtv allocation (false positive)\n{\n   zenoh_pico_pthread_tls\n   Memcheck:Leak\n   match-leak-kinds: possible\n   fun:calloc\n   fun:calloc\n   fun:allocate_dtv\n   fun:_dl_allocate_tls\n   fun:allocate_stack\n   ...\n}"
  },
  {
    "path": "tests/z_api_admin_space_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/utils/string.h\"\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n\ntypedef struct admin_space_query_reply_t {\n    z_owned_keyexpr_t ke;\n    z_owned_string_t payload;\n    z_owned_encoding_t encoding;\n\n} admin_space_query_reply_t;\n\nvoid admin_space_query_reply_clear(admin_space_query_reply_t *reply) {\n    z_drop(z_move(reply->ke));\n    z_drop(z_move(reply->payload));\n    z_drop(z_move(reply->encoding));\n}\n\nbool admin_space_query_reply_same_ke(const admin_space_query_reply_t *left, const admin_space_query_reply_t *right) {\n    return z_keyexpr_equals(z_loan(left->ke), z_loan(right->ke));\n}\n\n#if defined(__clang__) || defined(__GNUC__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wunused-function\"\n#endif\n_Z_ELEM_DEFINE(admin_space_query_reply, admin_space_query_reply_t, _z_noop_size, admin_space_query_reply_clear,\n               _z_noop_copy, _z_noop_move, admin_space_query_reply_same_ke, _z_noop_cmp, _z_noop_hash)\n_Z_LIST_DEFINE(admin_space_query_reply, admin_space_query_reply_t)\n\nstatic admin_space_query_reply_list_t *run_admin_space_query(const z_loaned_session_t *zs,\n                                                             const z_loaned_keyexpr_t *query_ke) {\n    admin_space_query_reply_list_t *results = admin_space_query_reply_list_new();\n\n    z_owned_closure_reply_t closure;\n    z_owned_fifo_handler_reply_t handler;\n    ASSERT_OK(z_fifo_channel_reply_new(&closure, &handler, 10));\n\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    opts.timeout_ms = 1000;\n    ASSERT_OK(z_get(zs, query_ke, \"\", z_move(closure), &opts));\n\n    // Wait for replies to arrive\n    z_time_t start = z_time_now();\n    for (unsigned long elapsed = z_time_elapsed_ms(&start);; elapsed = z_time_elapsed_ms(&start)) {\n        /* Drain everything currently available */\n        z_owned_reply_t reply;\n        z_result_t res;\n        for (res = z_try_recv(z_loan(handler), &reply); res == _Z_RES_OK; res = z_try_recv(z_loan(handler), &reply)) {\n            if (z_reply_is_ok(z_loan(reply))) {\n                admin_space_query_reply_t *result = z_malloc(sizeof(*result));\n                ASSERT_NOT_NULL(result);\n\n                const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n                ASSERT_OK(z_bytes_to_string(z_sample_payload(sample), &result->payload));\n                ASSERT_OK(z_keyexpr_clone(&result->ke, z_sample_keyexpr(sample)));\n                const z_loaned_encoding_t *encoding = z_sample_encoding(sample);\n                ASSERT_OK(z_encoding_clone(&result->encoding, encoding));\n\n                ASSERT_TRUE(admin_space_query_reply_list_find(results, admin_space_query_reply_same_ke, result) ==\n                            NULL);\n\n                admin_space_query_reply_list_t *old = results;\n                admin_space_query_reply_list_t *tmp = admin_space_query_reply_list_push(old, result);\n                ASSERT_TRUE(tmp != old);\n                results = tmp;\n            }\n\n            z_drop(z_move(reply));\n        }\n\n        // If channel is closed, we're done regardless of timeout\n        if (res == Z_CHANNEL_DISCONNECTED) {\n            break;\n        }\n\n        // If nothing available right now, only stop once timeout elapsed\n        if (res == Z_CHANNEL_NODATA) {\n            if (elapsed >= opts.timeout_ms) {\n                break;\n            }\n            z_sleep_ms(1);\n            continue;\n        }\n\n        // Anything else is unexpected\n        ASSERT_OK(res);\n    }\n    z_drop(z_move(handler));\n\n    return results;\n}\n\ntypedef struct admin_space_test_keyexprs_t {\n    z_owned_keyexpr_t pico_ke;\n    z_owned_keyexpr_t session_ke;\n    z_owned_keyexpr_t transports_ke;\n    z_owned_keyexpr_t transport_0_ke;\n    z_owned_keyexpr_t peers_ke;\n} admin_space_test_keyexprs_t;\n\ntypedef struct admin_space_test_sessions_t {\n    z_owned_session_t s1;\n    z_owned_session_t s2;\n} admin_space_test_sessions_t;\n\nstatic void admin_space_test_sessions_open(admin_space_test_sessions_t *ss) {\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    ASSERT_OK(z_open(&ss->s1, z_move(c1), NULL));\n    ASSERT_OK(zp_start_admin_space(z_loan_mut(ss->s1)));\n    ASSERT_OK(z_open(&ss->s2, z_move(c2), NULL));\n\n    z_sleep_ms(250);\n}\n\nstatic void admin_space_test_sessions_close(admin_space_test_sessions_t *ss) {\n    ASSERT_OK(zp_stop_admin_space(z_loan_mut(ss->s1)));\n    z_drop(z_move(ss->s1));\n    z_drop(z_move(ss->s2));\n}\n\nstatic void admin_space_test_keyexprs_clear(admin_space_test_keyexprs_t *kes) {\n    z_drop(z_move(kes->peers_ke));\n    z_drop(z_move(kes->transport_0_ke));\n    z_drop(z_move(kes->transports_ke));\n    z_drop(z_move(kes->session_ke));\n    z_drop(z_move(kes->pico_ke));\n}\n\nstatic void assert_json_object(const z_loaned_string_t *s) {\n    const char *p = z_string_data(s);\n    size_t n = z_string_len(s);\n    ASSERT_TRUE(n >= 2);\n    ASSERT_TRUE(p[0] == '{');\n    ASSERT_TRUE(p[n - 1] == '}');\n}\n\nstatic void assert_json_array(const z_loaned_string_t *s) {\n    const char *p = z_string_data(s);\n    size_t n = z_string_len(s);\n    ASSERT_TRUE(n >= 2);\n    ASSERT_TRUE(p[0] == '[');\n    ASSERT_TRUE(p[n - 1] == ']');\n}\n\nstatic void assert_contains(const z_loaned_string_t *s, const char *needle) {\n    const char *start = z_string_data(s);\n    const char *end = start + z_string_len(s);\n    if (_z_strstr(start, end, needle) == NULL) {\n        fprintf(stderr, \"Assertion failed: expected substring not found.\\nActual: %.*s\\nNeedle: %s\\n\",\n                (int)(end - start), start, needle);\n    }\n    ASSERT_TRUE(_z_strstr(start, end, needle) != NULL);\n}\n\nstatic void assert_not_contains(const z_loaned_string_t *s, const char *needle) {\n    const char *start = z_string_data(s);\n    const char *end = start + z_string_len(s);\n    if (_z_strstr(start, end, needle) != NULL) {\n        fprintf(stderr, \"Assertion failed: unexpected substring found.\\nActual: %.*s\\nNeedle: %s\\n\", (int)(end - start),\n                start, needle);\n    }\n    ASSERT_TRUE(_z_strstr(start, end, needle) == NULL);\n}\n\nstatic void assert_contains_z_string(const z_loaned_string_t *haystack, const z_loaned_string_t *needle) {\n    const char *h_start = z_string_data(haystack);\n    const char *h_end = h_start + z_string_len(haystack);\n\n    size_t n = z_string_len(needle);\n    ASSERT_TRUE(n < 256);\n\n    char buf[256];\n    // Flawfinder: ignore [CWE-120] - checked by assert above\n    memcpy(buf, z_string_data(needle), n);\n    buf[n] = '\\0';\n\n    ASSERT_TRUE(_z_strstr(h_start, h_end, buf) != NULL);\n}\n\nstatic void assert_contains_quoted_value(const z_loaned_string_t *s, const char *key, const char *val) {\n    // e.g. key=\"mode\" val=\"peer\" -> \"\\\"mode\\\":\\\"peer\\\"\"\n    char buf[128];\n    int n = snprintf(buf, sizeof(buf), \"\\\"%s\\\":\\\"%s\\\"\", key, val);\n    ASSERT_TRUE(n > 0 && (size_t)n < sizeof(buf));\n    assert_contains(s, buf);\n}\n\nstatic const char *whatami_to_str(z_whatami_t w) {\n    switch (w) {\n        case Z_WHATAMI_ROUTER:\n            return \"router\";\n        case Z_WHATAMI_PEER:\n            return \"peer\";\n        case Z_WHATAMI_CLIENT:\n            return \"client\";\n        default:\n            return NULL;\n    }\n}\n\nstatic const char *link_type_to_str(int t) {\n    switch (t) {\n        case _Z_LINK_TYPE_TCP:\n            return \"tcp\";\n        case _Z_LINK_TYPE_UDP:\n            return \"udp\";\n        case _Z_LINK_TYPE_BT:\n            return \"bt\";\n        case _Z_LINK_TYPE_SERIAL:\n            return \"serial\";\n        case _Z_LINK_TYPE_WS:\n            return \"ws\";\n        case _Z_LINK_TYPE_TLS:\n            return \"tls\";\n        case _Z_LINK_TYPE_RAWETH:\n            return \"raweth\";\n        default:\n            return NULL;\n    }\n}\n\nstatic const char *cap_transport_to_str(int t) {\n    switch (t) {\n        case Z_LINK_CAP_TRANSPORT_UNICAST:\n            return \"unicast\";\n        case Z_LINK_CAP_TRANSPORT_MULTICAST:\n            return \"multicast\";\n        case Z_LINK_CAP_TRANSPORT_RAWETH:\n            return \"raweth\";\n        default:\n            return NULL;\n    }\n}\n\nstatic const char *cap_flow_to_str(int f) {\n    switch (f) {\n        case Z_LINK_CAP_FLOW_DATAGRAM:\n            return \"datagram\";\n        case Z_LINK_CAP_FLOW_STREAM:\n            return \"stream\";\n        default:\n            return NULL;\n    }\n}\n\nstatic const char *transport_type_to_str(int t) {\n    switch (t) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            return \"unicast\";\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            return \"multicast\";\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            return \"raweth\";\n        default:\n            return NULL;\n    }\n}\n\nstatic const _z_link_t *admin_space_test_transport_link(const _z_session_t *session) {\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            return session->_tp._transport._unicast._common._link;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            return session->_tp._transport._multicast._common._link;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            return session->_tp._transport._raweth._common._link;\n        default:\n            ASSERT_TRUE(false);\n            return NULL;\n    }\n}\n\nstatic void assert_contains_session_header(const z_loaned_string_t *payload, const z_id_t *zid, z_whatami_t whatami,\n                                           bool wrapped) {\n    z_owned_string_t zid_str;\n    ASSERT_OK(z_id_to_string(zid, &zid_str));\n\n    const char *whatami_str = whatami_to_str(whatami);\n    ASSERT_NOT_NULL(whatami_str);\n\n    char buf[256];\n    int n;\n    if (wrapped) {\n        n = snprintf(buf, sizeof(buf), \"\\\"session\\\":{\\\"zid\\\":\\\"%.*s\\\",\\\"whatami\\\":\\\"%s\\\"\",\n                     (int)z_string_len(z_loan(zid_str)), z_string_data(z_loan(zid_str)), whatami_str);\n    } else {\n        n = snprintf(buf, sizeof(buf), \"{\\\"zid\\\":\\\"%.*s\\\",\\\"whatami\\\":\\\"%s\\\"\", (int)z_string_len(z_loan(zid_str)),\n                     z_string_data(z_loan(zid_str)), whatami_str);\n    }\n\n    ASSERT_TRUE(n > 0 && (size_t)n < sizeof(buf));\n    assert_contains(payload, buf);\n    z_drop(z_move(zid_str));\n}\n\nstatic void assert_contains_transport_header(const z_loaned_string_t *payload, const char *transport_type) {\n    char buf[128];\n    int n = snprintf(buf, sizeof(buf), \"{\\\"type\\\":\\\"%s\\\",\\\"link\\\":\", transport_type);\n    ASSERT_TRUE(n > 0 && (size_t)n < sizeof(buf));\n    assert_contains(payload, buf);\n}\n\nstatic void assert_contains_link_header(const z_loaned_string_t *payload, const char *link_type) {\n    char buf[128];\n    int n = snprintf(buf, sizeof(buf), \"\\\"link\\\":{\\\"type\\\":\\\"%s\\\",\\\"endpoint\\\":\", link_type);\n    ASSERT_TRUE(n > 0 && (size_t)n < sizeof(buf));\n    assert_contains(payload, buf);\n}\n\nstatic void assert_contains_peer_header(const z_loaned_string_t *payload, const z_id_t *zid, z_whatami_t whatami,\n                                        bool expect_remote_addr) {\n    z_owned_string_t zid_str;\n    ASSERT_OK(z_id_to_string(zid, &zid_str));\n\n    const char *whatami_str = whatami_to_str(whatami);\n    ASSERT_NOT_NULL(whatami_str);\n\n    char buf[256];\n    int n;\n    if (expect_remote_addr) {\n        n = snprintf(buf, sizeof(buf),\n                     \"{\\\"zid\\\":\\\"%.*s\\\",\\\"whatami\\\":\\\"%s\\\",\\\"remote_addr\\\":\", (int)z_string_len(z_loan(zid_str)),\n                     z_string_data(z_loan(zid_str)), whatami_str);\n    } else {\n        n = snprintf(buf, sizeof(buf), \"{\\\"zid\\\":\\\"%.*s\\\",\\\"whatami\\\":\\\"%s\\\"\", (int)z_string_len(z_loan(zid_str)),\n                     z_string_data(z_loan(zid_str)), whatami_str);\n    }\n\n    ASSERT_TRUE(n > 0 && (size_t)n < sizeof(buf));\n    assert_contains(payload, buf);\n    z_drop(z_move(zid_str));\n}\n\nstatic void build_pico_ke(z_owned_keyexpr_t *out, const z_id_t *zid) {\n    z_owned_string_t s;\n    ASSERT_OK(z_id_to_string(zid, &s));\n\n    z_internal_keyexpr_null(out);\n    ASSERT_OK(_z_keyexpr_append_str(out, _Z_KEYEXPR_AT));\n    ASSERT_OK(_z_keyexpr_append_substr(out, z_string_data(z_loan(s)), z_string_len(z_loan(s))));\n    ASSERT_OK(_z_keyexpr_append_str(out, _Z_KEYEXPR_PICO));\n\n    z_drop(z_move(s));\n}\n\nstatic void build_pico_session_ke(z_owned_keyexpr_t *out, const z_loaned_keyexpr_t *pico_ke) {\n    ASSERT_OK(z_keyexpr_clone(out, pico_ke));\n    ASSERT_OK(_z_keyexpr_append_str(out, _Z_KEYEXPR_SESSION));\n}\n\nstatic void build_pico_transports_ke(z_owned_keyexpr_t *out, const z_loaned_keyexpr_t *session_ke) {\n    ASSERT_OK(z_keyexpr_clone(out, session_ke));\n    ASSERT_OK(_z_keyexpr_append_str(out, _Z_KEYEXPR_TRANSPORTS));\n}\n\nstatic void build_pico_transport_0_ke(z_owned_keyexpr_t *out, const z_loaned_keyexpr_t *transports_ke) {\n    ASSERT_OK(z_keyexpr_clone(out, transports_ke));\n    ASSERT_OK(_z_keyexpr_append_str(out, \"0\"));\n}\n\nstatic void build_pico_transport_0_peers_ke(z_owned_keyexpr_t *out, const z_loaned_keyexpr_t *transport_0_ke) {\n    ASSERT_OK(z_keyexpr_clone(out, transport_0_ke));\n    ASSERT_OK(_z_keyexpr_append_str(out, _Z_KEYEXPR_PEERS));\n}\n\nstatic void build_pico_transport_0_peer_ke(z_owned_keyexpr_t *out, const z_loaned_keyexpr_t *peers_ke,\n                                           const z_id_t *peer_zid) {\n    z_owned_string_t s;\n    ASSERT_OK(z_id_to_string(peer_zid, &s));\n\n    ASSERT_OK(z_keyexpr_clone(out, peers_ke));\n    ASSERT_OK(_z_keyexpr_append_substr(out, z_string_data(z_loan(s)), z_string_len(z_loan(s))));\n\n    z_drop(z_move(s));\n}\n\nstatic const admin_space_query_reply_t *find_expected_reply(const admin_space_query_reply_list_t *results,\n                                                            const z_loaned_keyexpr_t *expected_ke) {\n    admin_space_query_reply_t expected;\n    z_internal_keyexpr_null(&expected.ke);\n    z_internal_string_null(&expected.payload);\n    z_internal_encoding_null(&expected.encoding);\n    ASSERT_OK(z_keyexpr_clone(&expected.ke, expected_ke));\n\n    admin_space_query_reply_list_t *entry =\n        admin_space_query_reply_list_find(results, admin_space_query_reply_same_ke, &expected);\n    admin_space_query_reply_elem_clear(&expected);\n\n    ASSERT_NOT_NULL(entry);\n    const admin_space_query_reply_t *reply = admin_space_query_reply_list_value(entry);\n    ASSERT_NOT_NULL(reply);\n    ASSERT_TRUE(z_encoding_equals(z_loan(reply->encoding), z_encoding_application_json()));\n    return reply;\n}\n\nstatic const admin_space_query_reply_t *run_exact_admin_space_query(const z_loaned_session_t *zs,\n                                                                    const z_loaned_keyexpr_t *ke,\n                                                                    admin_space_query_reply_list_t **results_out) {\n    admin_space_query_reply_list_t *results = run_admin_space_query(zs, ke);\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) == 1);\n\n    const admin_space_query_reply_t *reply = find_expected_reply(results, ke);\n    ASSERT_NOT_NULL(reply);\n\n    *results_out = results;\n    return reply;\n}\n\nstatic void admin_space_test_keyexprs_init(admin_space_test_keyexprs_t *kes, const z_id_t *zid) {\n    z_internal_keyexpr_null(&kes->pico_ke);\n    z_internal_keyexpr_null(&kes->session_ke);\n    z_internal_keyexpr_null(&kes->transports_ke);\n    z_internal_keyexpr_null(&kes->transport_0_ke);\n    z_internal_keyexpr_null(&kes->peers_ke);\n\n    build_pico_ke(&kes->pico_ke, zid);\n    build_pico_session_ke(&kes->session_ke, z_loan(kes->pico_ke));\n    build_pico_transports_ke(&kes->transports_ke, z_loan(kes->session_ke));\n    build_pico_transport_0_ke(&kes->transport_0_ke, z_loan(kes->transports_ke));\n    build_pico_transport_0_peers_ke(&kes->peers_ke, z_loan(kes->transport_0_ke));\n}\n\nstatic size_t expected_admin_space_reply_count(const _z_session_t *session) {\n    size_t count = 5;  // pico, session, transports, transports/0, transports/0/peers\n\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            count += _z_transport_peer_unicast_slist_len(session->_tp._transport._unicast._peers);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            count += _z_transport_peer_multicast_slist_len(session->_tp._transport._multicast._peers);\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            count += _z_transport_peer_multicast_slist_len(session->_tp._transport._raweth._peers);\n            break;\n        default:\n            break;\n    }\n\n    return count;\n}\n\nstatic void verify_peer_json(const z_loaned_string_t *payload, const z_id_t *expected_zid, z_whatami_t expected_whatami,\n                             bool expect_remote_addr) {\n    assert_json_object(payload);\n    assert_contains_peer_header(payload, expected_zid, expected_whatami, expect_remote_addr);\n}\n\nstatic void verify_peers_array_json_unicast(const z_loaned_string_t *payload, const _z_transport_unicast_t *tp) {\n    assert_json_array(payload);\n\n    for (_z_transport_peer_unicast_slist_t *it = tp->_peers; it != NULL;\n         it = _z_transport_peer_unicast_slist_next(it)) {\n        const _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(it);\n        assert_contains_peer_header(payload, &peer->common._remote_zid, peer->common._remote_whatami, false);\n    }\n}\n\nstatic void verify_peers_array_json_multicast(const z_loaned_string_t *payload, const _z_transport_multicast_t *tp) {\n    assert_json_array(payload);\n\n    for (_z_transport_peer_multicast_slist_t *it = tp->_peers; it != NULL;\n         it = _z_transport_peer_multicast_slist_next(it)) {\n        const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(it);\n        assert_contains_peer_header(payload, &peer->common._remote_zid, peer->common._remote_whatami, true);\n    }\n}\n\nstatic void verify_transport_json(const z_loaned_string_t *payload, int transport_type, const _z_link_t *link) {\n    assert_contains(payload, \"\\\"link\\\"\");\n    assert_contains(payload, \"\\\"peers\\\"\");\n\n    const char *tt = transport_type_to_str(transport_type);\n    ASSERT_NOT_NULL(tt);\n    assert_contains_transport_header(payload, tt);\n\n    const char *lt = link_type_to_str(link->_type);\n    ASSERT_NOT_NULL(lt);\n    assert_contains_link_header(payload, lt);\n\n    assert_contains(payload, \"\\\"endpoint\\\"\");\n    assert_contains(payload, \"\\\"locator\\\"\");\n    assert_contains(payload, \"\\\"metadata\\\":{\");\n    assert_contains(payload, \"\\\"protocol\\\"\");\n    assert_contains(payload, \"\\\"address\\\"\");\n    assert_contains(payload, \"\\\"config\\\":{\");\n\n    assert_contains_z_string(payload, &link->_endpoint._locator._protocol);\n    assert_contains_z_string(payload, &link->_endpoint._locator._address);\n\n    assert_contains(payload, \"\\\"capabilities\\\"\");\n    assert_contains(payload, \"\\\"transport\\\"\");\n    assert_contains(payload, \"\\\"flow\\\"\");\n    assert_contains(payload, \"\\\"is_reliable\\\"\");\n\n    const char *ct = cap_transport_to_str(link->_cap._transport);\n    const char *cf = cap_flow_to_str(link->_cap._flow);\n    ASSERT_NOT_NULL(ct);\n    ASSERT_NOT_NULL(cf);\n    assert_contains_quoted_value(payload, \"transport\", ct);\n    assert_contains_quoted_value(payload, \"flow\", cf);\n    assert_contains(payload, link->_cap._is_reliable ? \"\\\"is_reliable\\\":true\" : \"\\\"is_reliable\\\":false\");\n}\n\nstatic void verify_session_json(const z_loaned_string_t *payload, const _z_session_t *session) {\n    assert_json_object(payload);\n    assert_contains(payload, \"\\\"transports\\\"\");\n    assert_contains_session_header(payload, &session->_local_zid, session->_mode, false);\n}\n\nstatic void verify_pico_json(const z_loaned_string_t *payload, const _z_session_t *session) {\n    assert_json_object(payload);\n    assert_contains(payload, \"\\\"session\\\"\");\n    assert_contains(payload, \"\\\"transports\\\"\");\n    assert_contains_session_header(payload, &session->_local_zid, session->_mode, true);\n}\n\nstatic void verify_admin_space_query(const z_loaned_session_t *zs, const admin_space_query_reply_list_t *results) {\n    const _z_session_t *session = _Z_RC_IN_VAL(zs);\n    const admin_space_query_reply_t *reply;\n    const z_loaned_string_t *payload;\n\n    z_owned_keyexpr_t pico_ke, session_ke, transports_ke, transport_0_ke, peers_ke;\n    z_internal_keyexpr_null(&pico_ke);\n    z_internal_keyexpr_null(&session_ke);\n    z_internal_keyexpr_null(&transports_ke);\n    z_internal_keyexpr_null(&transport_0_ke);\n    z_internal_keyexpr_null(&peers_ke);\n\n    build_pico_ke(&pico_ke, &session->_local_zid);\n    build_pico_session_ke(&session_ke, z_loan(pico_ke));\n    build_pico_transports_ke(&transports_ke, z_loan(session_ke));\n    build_pico_transport_0_ke(&transport_0_ke, z_loan(transports_ke));\n    build_pico_transport_0_peers_ke(&peers_ke, z_loan(transport_0_ke));\n\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) == expected_admin_space_reply_count(session));\n\n    reply = find_expected_reply(results, z_loan(pico_ke));\n    verify_pico_json(z_string_loan(&reply->payload), session);\n\n    reply = find_expected_reply(results, z_loan(session_ke));\n    verify_session_json(z_string_loan(&reply->payload), session);\n\n    reply = find_expected_reply(results, z_loan(transports_ke));\n    payload = z_string_loan(&reply->payload);\n    assert_json_array(payload);\n    verify_transport_json(payload, session->_tp._type, admin_space_test_transport_link(session));\n\n    reply = find_expected_reply(results, z_loan(transport_0_ke));\n    payload = z_string_loan(&reply->payload);\n    assert_json_object(payload);\n    verify_transport_json(payload, session->_tp._type, admin_space_test_transport_link(session));\n\n    reply = find_expected_reply(results, z_loan(peers_ke));\n    payload = z_string_loan(&reply->payload);\n\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            verify_peers_array_json_unicast(payload, &session->_tp._transport._unicast);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            verify_peers_array_json_multicast(payload, &session->_tp._transport._multicast);\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            verify_peers_array_json_multicast(payload, &session->_tp._transport._raweth);\n            break;\n        default:\n            ASSERT_TRUE(false);\n    }\n\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            const _z_transport_unicast_t *tp = &session->_tp._transport._unicast;\n            for (_z_transport_peer_unicast_slist_t *it = tp->_peers; it != NULL;\n                 it = _z_transport_peer_unicast_slist_next(it)) {\n                const _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(it);\n\n                z_owned_keyexpr_t peer_ke;\n                z_internal_keyexpr_null(&peer_ke);\n                build_pico_transport_0_peer_ke(&peer_ke, z_loan(peers_ke), &peer->common._remote_zid);\n\n                reply = find_expected_reply(results, z_loan(peer_ke));\n                verify_peer_json(z_string_loan(&reply->payload), &peer->common._remote_zid,\n                                 peer->common._remote_whatami, false);\n\n                z_drop(z_move(peer_ke));\n            }\n            break;\n        }\n\n        case _Z_TRANSPORT_MULTICAST_TYPE: {\n            const _z_transport_multicast_t *tp = &session->_tp._transport._multicast;\n            for (_z_transport_peer_multicast_slist_t *it = tp->_peers; it != NULL;\n                 it = _z_transport_peer_multicast_slist_next(it)) {\n                const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(it);\n\n                z_owned_keyexpr_t peer_ke;\n                z_internal_keyexpr_null(&peer_ke);\n                build_pico_transport_0_peer_ke(&peer_ke, z_loan(peers_ke), &peer->common._remote_zid);\n\n                reply = find_expected_reply(results, z_loan(peer_ke));\n                verify_peer_json(z_string_loan(&reply->payload), &peer->common._remote_zid,\n                                 peer->common._remote_whatami, true);\n\n                z_drop(z_move(peer_ke));\n            }\n            break;\n        }\n\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            const _z_transport_multicast_t *tp = &session->_tp._transport._raweth;\n            for (_z_transport_peer_multicast_slist_t *it = tp->_peers; it != NULL;\n                 it = _z_transport_peer_multicast_slist_next(it)) {\n                const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(it);\n\n                z_owned_keyexpr_t peer_ke;\n                z_internal_keyexpr_null(&peer_ke);\n                build_pico_transport_0_peer_ke(&peer_ke, z_loan(peers_ke), &peer->common._remote_zid);\n\n                reply = find_expected_reply(results, z_loan(peer_ke));\n                verify_peer_json(z_string_loan(&reply->payload), &peer->common._remote_zid,\n                                 peer->common._remote_whatami, true);\n\n                z_drop(z_move(peer_ke));\n            }\n            break;\n        }\n\n        default:\n            ASSERT_TRUE(false);\n    }\n\n    z_drop(z_move(peers_ke));\n    z_drop(z_move(transport_0_ke));\n    z_drop(z_move(transports_ke));\n    z_drop(z_move(session_ke));\n    z_drop(z_move(pico_ke));\n}\n\nvoid test_start_stop_admin_space(void) {\n    printf(\"test_start_stop_admin_space\\n\");\n    z_owned_session_t s;\n    z_owned_config_t c;\n    z_config_default(&c);\n    ASSERT_OK(z_open(&s, z_move(c), NULL));\n    ASSERT_EQ_U32(_Z_RC_IN_VAL(z_loan(s))->_admin_space_queryable_id, 0);\n\n    for (int i = 0; i < 2; i++) {\n        ASSERT_OK(zp_start_admin_space(z_loan_mut(s)));\n        ASSERT_TRUE(_Z_RC_IN_VAL(z_loan(s))->_admin_space_queryable_id > 0);\n        ASSERT_OK(zp_stop_admin_space(z_loan_mut(s)));\n        ASSERT_EQ_U32(_Z_RC_IN_VAL(z_loan(s))->_admin_space_queryable_id, 0);\n    }\n    z_drop(z_move(s));\n}\n\nvoid test_auto_start_admin_space(void) {\n    printf(\"test_auto_start_admin_space\\n\");\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_open_options_t opt1, opt2;\n    z_open_options_default(&opt1);\n    z_open_options_default(&opt2);\n    opt2.auto_start_admin_space = true;\n\n    ASSERT_OK(z_open(&s1, z_move(c1), &opt1));\n    ASSERT_EQ_U32(_Z_RC_IN_VAL(z_loan(s1))->_admin_space_queryable_id, 0);\n    z_drop(z_move(s1));\n\n    ASSERT_OK(z_open(&s2, z_move(c2), &opt2));\n    ASSERT_TRUE(_Z_RC_IN_VAL(z_loan(s2))->_admin_space_queryable_id > 0);\n    z_drop(z_move(s2));\n}\n\nvoid test_admin_space_query_fails_when_not_running(void) {\n    printf(\"test_admin_space_query_fails_when_not_running\\n\");\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    ASSERT_OK(z_open(&s2, z_move(c2), NULL));\n\n    // Wait for sessions to connect\n    z_sleep_ms(250);\n\n    // Build query keyexpr: @/<zid>/pico/**\n    z_id_t zid = z_info_zid(z_loan(s1));\n    z_owned_string_t zid_str;\n    ASSERT_OK(z_id_to_string(&zid, &zid_str));\n\n    z_owned_keyexpr_t ke;\n    z_internal_keyexpr_null(&ke);\n\n    ASSERT_OK(_z_keyexpr_append_str(&ke, _Z_KEYEXPR_AT));\n    ASSERT_OK(_z_keyexpr_append_substr(&ke, z_string_data(z_loan(zid_str)), z_string_len(z_loan(zid_str))));\n    z_drop(z_move(zid_str));\n    ASSERT_OK(_z_keyexpr_append_str(&ke, _Z_KEYEXPR_PICO));\n    ASSERT_OK(_z_keyexpr_append_str(&ke, _Z_KEYEXPR_STARSTAR));\n\n    // 1) Not running - expect no replies\n    admin_space_query_reply_list_t *results = run_admin_space_query(z_loan(s2), z_keyexpr_loan(&ke));\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) == 0);\n    admin_space_query_reply_list_free(&results);\n\n    // 2) Start admin space - expect replies\n    ASSERT_OK(zp_start_admin_space(z_loan_mut(s1)));\n    z_sleep_ms(250);\n    results = run_admin_space_query(z_loan(s2), z_keyexpr_loan(&ke));\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) > 0);\n    admin_space_query_reply_list_free(&results);\n\n    // 3) Stop admin space - expect no replies again\n    ASSERT_OK(zp_stop_admin_space(z_loan_mut(s1)));\n    results = run_admin_space_query(z_loan(s2), z_keyexpr_loan(&ke));\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) == 0);\n    admin_space_query_reply_list_free(&results);\n\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n}\n\nvoid test_admin_space_general_query_succeeds(void) {\n    printf(\"test_admin_space_general_query_succeeds\\n\");\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    ASSERT_OK(zp_start_admin_space(z_loan_mut(s1)));\n    ASSERT_OK(z_open(&s2, z_move(c2), NULL));\n\n    z_sleep_ms(250);\n\n    z_id_t zid = z_info_zid(z_loan(s1));\n    z_owned_string_t zid_str;\n    ASSERT_OK(z_id_to_string(&zid, &zid_str));\n\n    z_owned_keyexpr_t query_ke;\n    z_internal_keyexpr_null(&query_ke);\n    ASSERT_OK(_z_keyexpr_append_str(&query_ke, _Z_KEYEXPR_AT));\n    ASSERT_OK(_z_keyexpr_append_substr(&query_ke, z_string_data(z_loan(zid_str)), z_string_len(z_loan(zid_str))));\n    z_drop(z_move(zid_str));\n    ASSERT_OK(_z_keyexpr_append_str(&query_ke, _Z_KEYEXPR_PICO));\n    ASSERT_OK(_z_keyexpr_append_str(&query_ke, _Z_KEYEXPR_STARSTAR));\n\n    admin_space_query_reply_list_t *results = run_admin_space_query(z_loan(s2), z_loan(query_ke));\n    verify_admin_space_query(z_loan(s1), results);\n\n    admin_space_query_reply_list_free(&results);\n    z_drop(z_move(query_ke));\n\n    ASSERT_OK(zp_stop_admin_space(z_loan_mut(s1)));\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n}\n\nvoid test_admin_space_pico_endpoint_succeeds(void) {\n    printf(\"test_admin_space_pico_endpoint_succeeds\\n\");\n\n    admin_space_test_sessions_t ss;\n    admin_space_test_sessions_open(&ss);\n\n    const _z_session_t *session = _Z_RC_IN_VAL(z_loan(ss.s1));\n\n    admin_space_test_keyexprs_t kes;\n    admin_space_test_keyexprs_init(&kes, &session->_local_zid);\n\n    admin_space_query_reply_list_t *results;\n    const admin_space_query_reply_t *reply = run_exact_admin_space_query(z_loan(ss.s2), z_loan(kes.pico_ke), &results);\n\n    verify_pico_json(z_string_loan(&reply->payload), session);\n\n    admin_space_query_reply_list_free(&results);\n    admin_space_test_keyexprs_clear(&kes);\n    admin_space_test_sessions_close(&ss);\n}\n\nvoid test_admin_space_session_endpoint_succeeds(void) {\n    printf(\"test_admin_space_session_endpoint_succeeds\\n\");\n\n    admin_space_test_sessions_t ss;\n    admin_space_test_sessions_open(&ss);\n\n    const _z_session_t *session = _Z_RC_IN_VAL(z_loan(ss.s1));\n\n    admin_space_test_keyexprs_t kes;\n    admin_space_test_keyexprs_init(&kes, &session->_local_zid);\n\n    admin_space_query_reply_list_t *results;\n    const admin_space_query_reply_t *reply =\n        run_exact_admin_space_query(z_loan(ss.s2), z_loan(kes.session_ke), &results);\n\n    verify_session_json(z_string_loan(&reply->payload), session);\n\n    admin_space_query_reply_list_free(&results);\n    admin_space_test_keyexprs_clear(&kes);\n    admin_space_test_sessions_close(&ss);\n}\n\nvoid test_admin_space_transports_endpoint_succeeds(void) {\n    printf(\"test_admin_space_transports_endpoint_succeeds\\n\");\n\n    admin_space_test_sessions_t ss;\n    admin_space_test_sessions_open(&ss);\n\n    const _z_session_t *session = _Z_RC_IN_VAL(z_loan(ss.s1));\n\n    admin_space_test_keyexprs_t kes;\n    admin_space_test_keyexprs_init(&kes, &session->_local_zid);\n\n    admin_space_query_reply_list_t *results;\n    const admin_space_query_reply_t *reply =\n        run_exact_admin_space_query(z_loan(ss.s2), z_loan(kes.transports_ke), &results);\n\n    const z_loaned_string_t *payload = z_string_loan(&reply->payload);\n    assert_json_array(payload);\n    verify_transport_json(payload, session->_tp._type, admin_space_test_transport_link(session));\n\n    admin_space_query_reply_list_free(&results);\n    admin_space_test_keyexprs_clear(&kes);\n    admin_space_test_sessions_close(&ss);\n}\n\nvoid test_admin_space_transport_0_endpoint_succeeds(void) {\n    printf(\"test_admin_space_transport_0_endpoint_succeeds\\n\");\n\n    admin_space_test_sessions_t ss;\n    admin_space_test_sessions_open(&ss);\n\n    const _z_session_t *session = _Z_RC_IN_VAL(z_loan(ss.s1));\n\n    admin_space_test_keyexprs_t kes;\n    admin_space_test_keyexprs_init(&kes, &session->_local_zid);\n\n    admin_space_query_reply_list_t *results;\n    const admin_space_query_reply_t *reply =\n        run_exact_admin_space_query(z_loan(ss.s2), z_loan(kes.transport_0_ke), &results);\n\n    const z_loaned_string_t *payload = z_string_loan(&reply->payload);\n    assert_json_object(payload);\n    verify_transport_json(payload, session->_tp._type, admin_space_test_transport_link(session));\n\n    admin_space_query_reply_list_free(&results);\n    admin_space_test_keyexprs_clear(&kes);\n    admin_space_test_sessions_close(&ss);\n}\n\nvoid test_admin_space_transport_0_peers_endpoint_succeeds(void) {\n    printf(\"test_admin_space_transport_0_peers_endpoint_succeeds\\n\");\n\n    admin_space_test_sessions_t ss;\n    admin_space_test_sessions_open(&ss);\n\n    const _z_session_t *session = _Z_RC_IN_VAL(z_loan(ss.s1));\n\n    admin_space_test_keyexprs_t kes;\n    admin_space_test_keyexprs_init(&kes, &session->_local_zid);\n\n    admin_space_query_reply_list_t *results;\n    const admin_space_query_reply_t *reply = run_exact_admin_space_query(z_loan(ss.s2), z_loan(kes.peers_ke), &results);\n\n    const z_loaned_string_t *payload = z_string_loan(&reply->payload);\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE:\n            verify_peers_array_json_unicast(payload, &session->_tp._transport._unicast);\n            break;\n        case _Z_TRANSPORT_MULTICAST_TYPE:\n            verify_peers_array_json_multicast(payload, &session->_tp._transport._multicast);\n            break;\n        case _Z_TRANSPORT_RAWETH_TYPE:\n            verify_peers_array_json_multicast(payload, &session->_tp._transport._raweth);\n            break;\n        default:\n            ASSERT_TRUE(false);\n    }\n\n    admin_space_query_reply_list_free(&results);\n    admin_space_test_keyexprs_clear(&kes);\n    admin_space_test_sessions_close(&ss);\n}\n\nvoid test_admin_space_transport_0_peer_endpoints_succeeds(void) {\n    printf(\"test_admin_space_transport_0_peer_endpoints_succeeds\\n\");\n\n    admin_space_test_sessions_t ss;\n    admin_space_test_sessions_open(&ss);\n\n    const _z_session_t *session = _Z_RC_IN_VAL(z_loan(ss.s1));\n\n    admin_space_test_keyexprs_t kes;\n    admin_space_test_keyexprs_init(&kes, &session->_local_zid);\n\n    switch (session->_tp._type) {\n        case _Z_TRANSPORT_UNICAST_TYPE: {\n            const _z_transport_unicast_t *tp = &session->_tp._transport._unicast;\n            for (_z_transport_peer_unicast_slist_t *it = tp->_peers; it != NULL;\n                 it = _z_transport_peer_unicast_slist_next(it)) {\n                const _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(it);\n\n                z_owned_keyexpr_t peer_ke;\n                z_internal_keyexpr_null(&peer_ke);\n                build_pico_transport_0_peer_ke(&peer_ke, z_loan(kes.peers_ke), &peer->common._remote_zid);\n\n                admin_space_query_reply_list_t *results;\n                const admin_space_query_reply_t *reply =\n                    run_exact_admin_space_query(z_loan(ss.s2), z_loan(peer_ke), &results);\n\n                verify_peer_json(z_string_loan(&reply->payload), &peer->common._remote_zid,\n                                 peer->common._remote_whatami, false);\n\n                admin_space_query_reply_list_free(&results);\n                z_drop(z_move(peer_ke));\n            }\n            break;\n        }\n\n        case _Z_TRANSPORT_MULTICAST_TYPE: {\n            const _z_transport_multicast_t *tp = &session->_tp._transport._multicast;\n            for (_z_transport_peer_multicast_slist_t *it = tp->_peers; it != NULL;\n                 it = _z_transport_peer_multicast_slist_next(it)) {\n                const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(it);\n\n                z_owned_keyexpr_t peer_ke;\n                z_internal_keyexpr_null(&peer_ke);\n                build_pico_transport_0_peer_ke(&peer_ke, z_loan(kes.peers_ke), &peer->common._remote_zid);\n\n                admin_space_query_reply_list_t *results;\n                const admin_space_query_reply_t *reply =\n                    run_exact_admin_space_query(z_loan(ss.s2), z_loan(peer_ke), &results);\n\n                verify_peer_json(z_string_loan(&reply->payload), &peer->common._remote_zid,\n                                 peer->common._remote_whatami, true);\n\n                admin_space_query_reply_list_free(&results);\n                z_drop(z_move(peer_ke));\n            }\n            break;\n        }\n\n        case _Z_TRANSPORT_RAWETH_TYPE: {\n            const _z_transport_multicast_t *tp = &session->_tp._transport._raweth;\n            for (_z_transport_peer_multicast_slist_t *it = tp->_peers; it != NULL;\n                 it = _z_transport_peer_multicast_slist_next(it)) {\n                const _z_transport_peer_multicast_t *peer = _z_transport_peer_multicast_slist_value(it);\n\n                z_owned_keyexpr_t peer_ke;\n                z_internal_keyexpr_null(&peer_ke);\n                build_pico_transport_0_peer_ke(&peer_ke, z_loan(kes.peers_ke), &peer->common._remote_zid);\n\n                admin_space_query_reply_list_t *results;\n                const admin_space_query_reply_t *reply =\n                    run_exact_admin_space_query(z_loan(ss.s2), z_loan(peer_ke), &results);\n\n                verify_peer_json(z_string_loan(&reply->payload), &peer->common._remote_zid,\n                                 peer->common._remote_whatami, true);\n\n                admin_space_query_reply_list_free(&results);\n                z_drop(z_move(peer_ke));\n            }\n            break;\n        }\n\n        default:\n            ASSERT_TRUE(false);\n    }\n\n    admin_space_test_keyexprs_clear(&kes);\n    admin_space_test_sessions_close(&ss);\n}\n\n#if Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_UNICAST_TRANSPORT == 1 && Z_FEATURE_LINK_TCP == 1 && \\\n    Z_FEATURE_MULTI_THREAD == 1 && Z_FEATURE_PUBLICATION == 1\nstatic void open_listener_session(z_owned_session_t *session, const char *listen_locator) {\n    z_owned_config_t cfg;\n    z_config_default(&cfg);\n    ASSERT_OK(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_MODE_KEY, \"peer\"));\n    ASSERT_OK(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_LISTEN_KEY, listen_locator));\n    ASSERT_OK(z_open(session, z_config_move(&cfg), NULL));\n}\n\nstatic void open_connector_session(z_owned_session_t *session, const char *connect_locator) {\n    z_owned_config_t cfg;\n    z_config_default(&cfg);\n    ASSERT_OK(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_MODE_KEY, \"peer\"));\n    ASSERT_OK(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_CONNECT_KEY, connect_locator));\n    ASSERT_OK(z_open(session, z_config_move(&cfg), NULL));\n}\n\nstatic void close_session_with_tasks(z_owned_session_t *session) { z_session_drop(z_session_move(session)); }\n\nstatic void wait_for_sample_kind(z_owned_fifo_handler_sample_t *handler, z_sample_kind_t expected_kind,\n                                 z_owned_string_t *payload_out) {\n    if (payload_out != NULL) {\n        z_internal_string_null(payload_out);\n    }\n\n    for (unsigned i = 0; i < 50; ++i) {\n        z_owned_sample_t sample;\n        z_result_t res = z_fifo_handler_sample_try_recv(z_fifo_handler_sample_loan(handler), &sample);\n        if (res == Z_CHANNEL_NODATA) {\n            z_sleep_ms(100);\n            continue;\n        }\n\n        ASSERT_OK(res);\n        if (z_sample_kind(z_loan(sample)) == expected_kind) {\n            if (payload_out != NULL && expected_kind == Z_SAMPLE_KIND_PUT) {\n                ASSERT_OK(z_bytes_to_string(z_sample_payload(z_loan(sample)), payload_out));\n            }\n            z_drop(z_move(sample));\n            return;\n        }\n        z_drop(z_move(sample));\n    }\n\n    ASSERT_TRUE(false);\n}\n\nstatic void assert_no_sample(z_owned_fifo_handler_sample_t *handler) {\n    for (unsigned i = 0; i < 5; ++i) {\n        z_owned_sample_t sample;\n        z_result_t res = z_fifo_handler_sample_try_recv(z_fifo_handler_sample_loan(handler), &sample);\n        if (res == Z_CHANNEL_NODATA) {\n            z_sleep_ms(100);\n            continue;\n        }\n\n        if (res == _Z_RES_OK) {\n            z_drop(z_move(sample));\n        }\n        ASSERT_TRUE(false);\n    }\n}\n\nstatic void wait_admin_space_ready(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *probe_ke) {\n    bool ready = false;\n    for (unsigned i = 0; i < 50; ++i) {\n        admin_space_query_reply_list_t *results = run_admin_space_query(zs, probe_ke);\n        ready = admin_space_query_reply_list_len(results) > 0;\n        admin_space_query_reply_list_free(&results);\n        if (ready) {\n            break;\n        }\n        z_sleep_ms(100);\n    }\n    ASSERT_TRUE(ready);\n}\n\nvoid test_admin_space_rfc_connectivity_query_and_events(void) {\n    z_owned_session_t s1, s2, s3;\n    open_listener_session(&s1, \"tcp/127.0.0.1:7448\");\n    ASSERT_OK(zp_start_admin_space(z_session_loan_mut(&s1)));\n    open_connector_session(&s2, \"tcp/127.0.0.1:7448\");\n\n    z_id_t s1_zid = z_info_zid(z_session_loan(&s1));\n    z_owned_string_t s1_zid_str;\n    ASSERT_OK(z_id_to_string(&s1_zid, &s1_zid_str));\n\n    char session_query_ke_str[256];\n    int session_query_ke_len = snprintf(session_query_ke_str, sizeof(session_query_ke_str), \"@/%.*s/%s/**\",\n                                        (int)z_string_len(z_string_loan(&s1_zid_str)),\n                                        z_string_data(z_string_loan(&s1_zid_str)), _Z_KEYEXPR_SESSION);\n    ASSERT_TRUE(session_query_ke_len > 0 && (size_t)session_query_ke_len < sizeof(session_query_ke_str));\n\n    z_view_keyexpr_t session_query_ke;\n    ASSERT_OK(z_view_keyexpr_from_str(&session_query_ke, session_query_ke_str));\n    wait_admin_space_ready(z_session_loan(&s1), z_view_keyexpr_loan(&session_query_ke));\n\n    admin_space_query_reply_list_t *results =\n        run_admin_space_query(z_session_loan(&s2), z_view_keyexpr_loan(&session_query_ke));\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) == 0);\n    admin_space_query_reply_list_free(&results);\n\n    results = run_admin_space_query(z_session_loan(&s1), z_view_keyexpr_loan(&session_query_ke));\n    ASSERT_TRUE(admin_space_query_reply_list_len(results) >= 2);\n    bool saw_transport = false;\n    bool saw_link = false;\n    for (admin_space_query_reply_list_t *it = results; it != NULL; it = admin_space_query_reply_list_next(it)) {\n        const admin_space_query_reply_t *reply = admin_space_query_reply_list_value(it);\n        z_view_string_t key_view;\n        ASSERT_OK(z_keyexpr_as_view_string(z_keyexpr_loan(&reply->ke), &key_view));\n        const z_loaned_string_t *key = z_view_string_loan(&key_view);\n        const char *k_start = z_string_data(key);\n        const char *k_end = k_start + z_string_len(key);\n        if (_z_strstr(k_start, k_end, \"/session/transport/unicast/\") != NULL &&\n            _z_strstr(k_start, k_end, \"/link/\") == NULL) {\n            saw_transport = true;\n            assert_contains(z_string_loan(&reply->payload), \"\\\"zid\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"whatami\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"is_qos\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"is_shm\\\"\");\n        }\n        if (_z_strstr(k_start, k_end, \"/session/transport/unicast/\") != NULL &&\n            _z_strstr(k_start, k_end, \"/link/\") != NULL) {\n            saw_link = true;\n            assert_contains(z_string_loan(&reply->payload), \"\\\"src\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"dst\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"group\\\":null\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"mtu\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"is_reliable\\\"\");\n            assert_contains(z_string_loan(&reply->payload), \"\\\"is_streamed\\\"\");\n            assert_not_contains(z_string_loan(&reply->payload), \"\\\"zid\\\"\");\n        }\n    }\n    ASSERT_TRUE(saw_transport);\n    ASSERT_TRUE(saw_link);\n    admin_space_query_reply_list_free(&results);\n\n    char transport_sub_ke_str[256];\n    int transport_sub_ke_len =\n        snprintf(transport_sub_ke_str, sizeof(transport_sub_ke_str), \"@/%.*s/%s/%s/*\",\n                 (int)z_string_len(z_string_loan(&s1_zid_str)), z_string_data(z_string_loan(&s1_zid_str)),\n                 _Z_KEYEXPR_SESSION, _Z_KEYEXPR_TRANSPORT_UNICAST);\n    ASSERT_TRUE(transport_sub_ke_len > 0 && (size_t)transport_sub_ke_len < sizeof(transport_sub_ke_str));\n\n    char link_sub_ke_str[320];\n    int link_sub_ke_len = snprintf(\n        link_sub_ke_str, sizeof(link_sub_ke_str), \"@/%.*s/%s/%s/*/%s/*\", (int)z_string_len(z_string_loan(&s1_zid_str)),\n        z_string_data(z_string_loan(&s1_zid_str)), _Z_KEYEXPR_SESSION, _Z_KEYEXPR_TRANSPORT_UNICAST, _Z_KEYEXPR_LINK);\n    ASSERT_TRUE(link_sub_ke_len > 0 && (size_t)link_sub_ke_len < sizeof(link_sub_ke_str));\n    z_drop(z_move(s1_zid_str));\n\n    z_view_keyexpr_t transport_sub_ke;\n    z_view_keyexpr_t link_sub_ke;\n    ASSERT_OK(z_view_keyexpr_from_str(&transport_sub_ke, transport_sub_ke_str));\n    ASSERT_OK(z_view_keyexpr_from_str(&link_sub_ke, link_sub_ke_str));\n\n    z_owned_closure_sample_t transport_sub_closure;\n    z_owned_fifo_handler_sample_t transport_sub_handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&transport_sub_closure, &transport_sub_handler, 8));\n    z_owned_subscriber_t transport_sub;\n    ASSERT_OK(z_declare_subscriber(z_session_loan(&s1), &transport_sub, z_view_keyexpr_loan(&transport_sub_ke),\n                                   z_closure_sample_move(&transport_sub_closure), NULL));\n\n    z_owned_closure_sample_t link_sub_closure;\n    z_owned_fifo_handler_sample_t link_sub_handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&link_sub_closure, &link_sub_handler, 8));\n    z_owned_subscriber_t link_sub;\n    ASSERT_OK(z_declare_subscriber(z_session_loan(&s1), &link_sub, z_view_keyexpr_loan(&link_sub_ke),\n                                   z_closure_sample_move(&link_sub_closure), NULL));\n\n    z_owned_closure_sample_t remote_transport_sub_closure;\n    z_owned_fifo_handler_sample_t remote_transport_sub_handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&remote_transport_sub_closure, &remote_transport_sub_handler, 8));\n    z_owned_subscriber_t remote_transport_sub;\n    ASSERT_OK(z_declare_subscriber(z_session_loan(&s2), &remote_transport_sub, z_view_keyexpr_loan(&transport_sub_ke),\n                                   z_closure_sample_move(&remote_transport_sub_closure), NULL));\n\n    z_owned_closure_sample_t remote_link_sub_closure;\n    z_owned_fifo_handler_sample_t remote_link_sub_handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&remote_link_sub_closure, &remote_link_sub_handler, 8));\n    z_owned_subscriber_t remote_link_sub;\n    ASSERT_OK(z_declare_subscriber(z_session_loan(&s2), &remote_link_sub, z_view_keyexpr_loan(&link_sub_ke),\n                                   z_closure_sample_move(&remote_link_sub_closure), NULL));\n\n    open_connector_session(&s3, \"tcp/127.0.0.1:7448\");\n\n    z_owned_string_t transport_put_payload;\n    z_owned_string_t link_put_payload;\n    wait_for_sample_kind(&transport_sub_handler, Z_SAMPLE_KIND_PUT, &transport_put_payload);\n    wait_for_sample_kind(&link_sub_handler, Z_SAMPLE_KIND_PUT, &link_put_payload);\n    assert_contains(z_string_loan(&transport_put_payload), \"\\\"is_qos\\\"\");\n    assert_contains(z_string_loan(&transport_put_payload), \"\\\"is_shm\\\"\");\n    assert_contains(z_string_loan(&link_put_payload), \"\\\"group\\\":null\");\n    assert_not_contains(z_string_loan(&link_put_payload), \"\\\"zid\\\"\");\n    z_drop(z_move(transport_put_payload));\n    z_drop(z_move(link_put_payload));\n    assert_no_sample(&remote_transport_sub_handler);\n    assert_no_sample(&remote_link_sub_handler);\n\n    close_session_with_tasks(&s3);\n    wait_for_sample_kind(&link_sub_handler, Z_SAMPLE_KIND_DELETE, NULL);\n    wait_for_sample_kind(&transport_sub_handler, Z_SAMPLE_KIND_DELETE, NULL);\n    assert_no_sample(&remote_transport_sub_handler);\n    assert_no_sample(&remote_link_sub_handler);\n\n    ASSERT_OK(z_undeclare_subscriber(z_subscriber_move(&transport_sub)));\n    ASSERT_OK(z_undeclare_subscriber(z_subscriber_move(&link_sub)));\n    ASSERT_OK(z_undeclare_subscriber(z_subscriber_move(&remote_transport_sub)));\n    ASSERT_OK(z_undeclare_subscriber(z_subscriber_move(&remote_link_sub)));\n    z_drop(z_move(transport_sub_handler));\n    z_drop(z_move(link_sub_handler));\n    z_drop(z_move(remote_transport_sub_handler));\n    z_drop(z_move(remote_link_sub_handler));\n\n    ASSERT_OK(zp_stop_admin_space(z_session_loan_mut(&s1)));\n    close_session_with_tasks(&s2);\n    close_session_with_tasks(&s1);\n}\n#endif\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_start_stop_admin_space();\n    test_auto_start_admin_space();\n    test_admin_space_query_fails_when_not_running();\n    test_admin_space_general_query_succeeds();\n    test_admin_space_pico_endpoint_succeeds();\n    test_admin_space_session_endpoint_succeeds();\n    test_admin_space_transports_endpoint_succeeds();\n    test_admin_space_transport_0_endpoint_succeeds();\n    test_admin_space_transport_0_peers_endpoint_succeeds();\n    test_admin_space_transport_0_peer_endpoints_succeeds();\n#if Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_UNICAST_TRANSPORT == 1 && Z_FEATURE_LINK_TCP == 1 &&  \\\n    Z_FEATURE_MULTI_THREAD == 1 && Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_LOCAL_QUERYABLE == 1 && \\\n    Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    test_admin_space_rfc_connectivity_query_and_events();\n#endif\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\"Missing config token to build this test. This test requires: Z_FEATURE_ADMIN_SPACE\\n\");\n    return 0;\n}\n\n#endif  // Z_FEATURE_ADMIN_SPACE == 1\n"
  },
  {
    "path": "tests/z_api_advanced_pubsub_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <assert.h>\n#include <stdatomic.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n\n#ifdef Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY\n#include \"utils/tcp_proxy.h\"\n#endif\n\n#if Z_FEATURE_ADVANCED_PUBLICATION == 1 && Z_FEATURE_ADVANCED_SUBSCRIPTION == 1\n\n// ---- Common test timing constants ----\n#define TEST_SLEEP_MS 4000\n\n// Reconnect waits used across tests\n#define TEST_RECONNECT_MS 10000\n\n// Feature-specific periods used in tests\n#define TEST_PERIODIC_QUERY_MS 1000\n#define TEST_HEARTBEAT_PERIOD_MS 4000\n// ------------------------------------------------------------\n\nstatic void put_str(const ze_loaned_advanced_publisher_t *pub, const char *s) {\n    z_owned_bytes_t payload;\n    ASSERT_OK(z_bytes_copy_from_str(&payload, s));\n    ASSERT_OK(ze_advanced_publisher_put(pub, z_move(payload), NULL));\n    // TODO: cache requires monotonically increasing timestamps to work correctly on advanced subscriber side.\n    // Due to currently imprecise timestamping (due to low resolution of gettimeofday), we need\n    // to add a small delay to ensure that we get monotonically increasing timestamps, until\n    // more accurate timestamping (hlc ?) is implemented.\n    z_sleep_us(50);\n}\n\nstatic void expect_next(const z_loaned_fifo_handler_sample_t *handler, const char *expected) {\n    z_owned_sample_t sample;\n    z_internal_sample_null(&sample);\n    z_owned_string_t value;\n    z_internal_string_null(&value);\n\n    ASSERT_OK(z_try_recv(handler, &sample));\n    assert(z_sample_kind(z_loan(sample)) == Z_SAMPLE_KIND_PUT);\n\n    ASSERT_OK(z_bytes_to_string(z_sample_payload(z_loan(sample)), &value));\n\n    const char *ptr = z_string_data(z_loan(value));\n    size_t len = z_string_len(z_loan(value));\n    // Flawfinder: ignore [CWE-126]\n    size_t exp_len = strlen(expected);\n\n    if (len != exp_len || memcmp(ptr, expected, len) != 0) {\n        fprintf(stderr,\n                \"Mismatch:\\n\"\n                \"  expected (%zu): \\\"%.*s\\\"\\n\"\n                \"  actual   (%zu): \\\"%.*s\\\"\\n\",\n                exp_len, (int)exp_len, expected, len, (int)len, ptr);\n        fflush(stderr);\n        assert(false && \"expect_next() value mismatch\");\n    }\n    z_drop(z_move(value));\n    z_drop(z_move(sample));\n}\n\nstatic void expect_empty(const z_loaned_fifo_handler_sample_t *handler) {\n    z_owned_sample_t sample;\n    ASSERT_NOT_OK(z_try_recv(handler, &sample));\n}\n\nstatic void test_advanced_history(bool p2p) {\n    printf(\"test_advanced_history: peer to peer=%d\\n\", p2p);\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/history\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    if (p2p) {\n        zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n        zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n\n        zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n        zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    }\n\n    ASSERT_OK(z_open(&s1, z_config_move(&c1), NULL));\n    ASSERT_OK(z_open(&s2, z_config_move(&c2), NULL));\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    pub_opts.cache.max_samples = 3;\n    pub_opts.cache.is_enabled = true;\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    char buf[16];\n    for (int idx = 1; idx <= 4; idx++) {\n        snprintf(buf, sizeof(buf), \"%d\", idx);\n        put_str(z_loan(pub), buf);\n    }\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_history_options_default(&sub_opts.history);\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"5\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"2\");\n    expect_next(z_loan(handler), \"3\");\n    expect_next(z_loan(handler), \"4\");\n    expect_next(z_loan(handler), \"5\");\n    expect_empty(z_loan(handler));\n\n    ze_advanced_subscriber_drop(z_move(sub));\n    ze_advanced_publisher_drop(z_move(pub));\n    z_fifo_handler_sample_drop(z_move(handler));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\n#ifdef Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY\nstatic void setup_two_peers_with_proxy(z_owned_session_t *s1, z_owned_session_t *s2, tcp_proxy_t **proxy,\n                                       uint16_t upstream_listen_port) {\n    *proxy = tcp_proxy_create(\"127.0.0.1\", \"127.0.0.1\", upstream_listen_port);\n    assert(*proxy != NULL);\n\n    int port = tcp_proxy_start(*proxy, 100);\n    assert(port > 0);\n\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    char uri[128];\n\n    // s1 listens on the fixed upstream port\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    snprintf(uri, sizeof(uri), \"tcp/127.0.0.1:%u#iface=lo\", (unsigned)upstream_listen_port);\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, uri);\n\n    // s2 connects via proxy ephemeral port\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    snprintf(uri, sizeof(uri), \"tcp/127.0.0.1:%u#iface=lo\", (unsigned)port);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, uri);\n\n    ASSERT_OK(z_open(s1, z_config_move(&c1), NULL));\n    ASSERT_OK(z_open(s2, z_config_move(&c2), NULL));\n}\n\nstatic void test_advanced_retransmission(void) {\n    printf(\"test_advanced_retransmission\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/retransmission\";\n\n    tcp_proxy_t *tcp_proxy;\n    z_owned_session_t s1, s2;\n    setup_two_peers_with_proxy(&s1, &s2, &tcp_proxy, 9000);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_recovery_options_default(&sub_opts.recovery);\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_cache_options_default(&pub_opts.cache);\n    pub_opts.cache.max_samples = 10;\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"2\");\n    put_str(z_loan(pub), \"3\");\n    put_str(z_loan(pub), \"4\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_ms(TEST_RECONNECT_MS);\n\n    put_str(z_loan(pub), \"5\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"2\");\n    expect_next(z_loan(handler), \"3\");\n    expect_next(z_loan(handler), \"4\");\n    expect_next(z_loan(handler), \"5\");\n    expect_empty(z_loan(handler));\n\n    z_drop(z_move(sub));\n    z_drop(z_move(pub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}\n\nstatic void test_advanced_retransmission_periodic(void) {\n    printf(\"test_advanced_retransmission_periodic\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/retransmission_periodic\";\n\n    tcp_proxy_t *tcp_proxy;\n    z_owned_session_t s1, s2;\n    setup_two_peers_with_proxy(&s1, &s2, &tcp_proxy, 9000);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_recovery_options_default(&sub_opts.recovery);\n    ze_advanced_subscriber_last_sample_miss_detection_options_default(&sub_opts.recovery.last_sample_miss_detection);\n    sub_opts.recovery.last_sample_miss_detection.periodic_queries_period_ms = TEST_PERIODIC_QUERY_MS;\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_cache_options_default(&pub_opts.cache);\n    pub_opts.cache.max_samples = 10;\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"2\");\n    put_str(z_loan(pub), \"3\");\n    put_str(z_loan(pub), \"4\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_ms(TEST_RECONNECT_MS);\n\n    put_str(z_loan(pub), \"5\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"2\");\n    expect_next(z_loan(handler), \"3\");\n    expect_next(z_loan(handler), \"4\");\n    expect_next(z_loan(handler), \"5\");\n    expect_empty(z_loan(handler));\n\n    z_drop(z_move(sub));\n    z_drop(z_move(pub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}\n\nstatic void test_advanced_retransmission_heartbeat(void) {\n    printf(\"test_advanced_retransmission_heartbeat\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/retransmission_heartbeat\";\n\n    tcp_proxy_t *tcp_proxy;\n    z_owned_session_t s1, s2;\n    setup_two_peers_with_proxy(&s1, &s2, &tcp_proxy, 9000);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_recovery_options_default(&sub_opts.recovery);\n    ze_advanced_subscriber_last_sample_miss_detection_options_default(&sub_opts.recovery.last_sample_miss_detection);\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_cache_options_default(&pub_opts.cache);\n    pub_opts.cache.max_samples = 10;\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    pub_opts.sample_miss_detection.heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_PERIODIC;\n    pub_opts.sample_miss_detection.heartbeat_period_ms = TEST_HEARTBEAT_PERIOD_MS;\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"2\");\n    put_str(z_loan(pub), \"3\");\n    put_str(z_loan(pub), \"4\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_ms(TEST_RECONNECT_MS);\n\n    expect_next(z_loan(handler), \"2\");\n    expect_next(z_loan(handler), \"3\");\n    expect_next(z_loan(handler), \"4\");\n    expect_empty(z_loan(handler));\n\n    z_drop(z_move(sub));\n    z_drop(z_move(pub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}\n\n#define MAX_MISS_EVENTS 16\n\ntypedef struct {\n    atomic_int event_count;         // number of miss events recorded\n    atomic_uint_fast64_t total_nb;  // sum of all nb across events\n    z_entity_global_id_t sources[MAX_MISS_EVENTS];\n    uint64_t nbs[MAX_MISS_EVENTS];\n} miss_ctx_t;\n\nstatic void miss_ctx_init(miss_ctx_t *ctx) {\n    memset(ctx, 0, sizeof(*ctx));\n    atomic_store_explicit(&ctx->event_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->total_nb, 0, memory_order_relaxed);\n}\n\nstatic void miss_ctx_assert_single(const miss_ctx_t *ctx, const _z_entity_global_id_t *expected_pub_id,\n                                   uint64_t expected_nb) {\n    int count = atomic_load_explicit(&ctx->event_count, memory_order_acquire);\n    uint64_t sum = atomic_load_explicit(&ctx->total_nb, memory_order_acquire);\n\n    if (count != 1) {\n        fprintf(stderr, \"miss_ctx_assert_single: expected exactly 1 miss event, got %d\\n\", count);\n        fflush(stderr);\n        assert(false && \"expected exactly one miss event\");\n    }\n\n    if (sum != expected_nb) {\n        fprintf(stderr, \"total missed samples mismatch: expected=%\" PRIu64 \", actual=%\" PRIu64 \"\\n\", expected_nb, sum);\n        fflush(stderr);\n        assert(false && \"total missed samples does not match\");\n    }\n\n    if (ctx->nbs[0] != expected_nb) {\n        fprintf(stderr, \"single-event nb mismatch: expected=%\" PRIu64 \", actual=%\" PRIu64 \"\\n\", expected_nb,\n                ctx->nbs[0]);\n        fflush(stderr);\n        assert(false && \"unexpected nb in the single miss event\");\n    }\n\n    if (!_z_entity_global_id_eq(&ctx->sources[0], expected_pub_id)) {\n        z_owned_string_t id_string, expected_id_string;\n        ASSERT_OK(z_id_to_string(&ctx->sources[0].zid, &id_string));\n        ASSERT_OK(z_id_to_string(&expected_pub_id->zid, &expected_id_string));\n\n        fprintf(stderr,\n                \"miss source GID mismatch:\\n\"\n                \"   expected: (zid=%.*s, eid=%d)\\n\"\n                \"   actual  : (zid=%.*s, eid=%d)\\n\",\n                (int)z_string_len(z_loan(expected_id_string)), z_string_data(z_loan(expected_id_string)),\n                expected_pub_id->eid, (int)z_string_len(z_loan(id_string)), z_string_data(z_loan(id_string)),\n                ctx->sources[0].eid);\n        fflush(stderr);\n        z_drop(z_move(id_string));\n        z_drop(z_move(expected_id_string));\n        assert(false && \"miss source should match publisher\");\n    }\n}\n\nstatic void miss_handler(const ze_miss_t *miss, void *arg) {\n    miss_ctx_t *ctx = (miss_ctx_t *)arg;\n\n    int idx = atomic_load_explicit(&ctx->event_count, memory_order_relaxed);\n    assert(idx < MAX_MISS_EVENTS);\n\n    ctx->nbs[idx] = miss->nb;\n    ctx->sources[idx] = miss->source;\n    atomic_fetch_add_explicit(&ctx->total_nb, miss->nb, memory_order_relaxed);\n\n    atomic_store_explicit(&ctx->event_count, idx + 1, memory_order_release);\n}\n\nstatic void test_advanced_sample_miss(void) {\n    printf(\"test_advanced_sample_miss\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/sample_miss\";\n\n    tcp_proxy_t *tcp_proxy;\n    z_owned_session_t s1, s2;\n    setup_two_peers_with_proxy(&s1, &s2, &tcp_proxy, 9000);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n\n    ze_owned_sample_miss_listener_t miss_listener;\n    ze_owned_closure_miss_t miss_closure;\n    miss_ctx_t miss_ctx;\n    miss_ctx_init(&miss_ctx);\n    z_closure(&miss_closure, miss_handler, NULL, &miss_ctx);\n    ASSERT_OK(ze_advanced_subscriber_declare_sample_miss_listener(z_loan(sub), &miss_listener, z_move(miss_closure)));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"2\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_ms(TEST_RECONNECT_MS);\n\n    put_str(z_loan(pub), \"3\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"3\");\n    expect_empty(z_loan(handler));\n\n    z_entity_global_id_t pub_id = ze_advanced_publisher_id(z_loan(pub));\n    miss_ctx_assert_single(&miss_ctx, &pub_id, 1);\n\n    z_drop(z_move(miss_listener));\n    z_drop(z_move(sub));\n    z_drop(z_move(pub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}\n\nstatic void test_advanced_retransmission_sample_miss(void) {\n    printf(\"test_advanced_retransmission_sample_miss\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/retransmission_sample_miss\";\n\n    tcp_proxy_t *tcp_proxy;\n    z_owned_session_t s1, s2;\n    setup_two_peers_with_proxy(&s1, &s2, &tcp_proxy, 9000);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_recovery_options_default(&sub_opts.recovery);\n    ze_advanced_subscriber_last_sample_miss_detection_options_default(&sub_opts.recovery.last_sample_miss_detection);\n    sub_opts.recovery.last_sample_miss_detection.periodic_queries_period_ms = TEST_PERIODIC_QUERY_MS;\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n\n    ze_owned_sample_miss_listener_t miss_listener;\n    ze_owned_closure_miss_t miss_closure;\n    miss_ctx_t miss_ctx;\n    miss_ctx_init(&miss_ctx);\n    z_closure(&miss_closure, miss_handler, NULL, &miss_ctx);\n    ASSERT_OK(ze_advanced_subscriber_declare_sample_miss_listener(z_loan(sub), &miss_listener, z_move(miss_closure)));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_cache_options_default(&pub_opts.cache);\n    pub_opts.cache.max_samples = 1;\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"2\");\n    put_str(z_loan(pub), \"3\");\n    put_str(z_loan(pub), \"4\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_ms(TEST_RECONNECT_MS);\n\n    expect_next(z_loan(handler), \"4\");\n    expect_empty(z_loan(handler));\n\n    z_entity_global_id_t pub_id = ze_advanced_publisher_id(z_loan(pub));\n    miss_ctx_assert_single(&miss_ctx, &pub_id, 2);\n\n    z_drop(z_move(miss_listener));\n    z_drop(z_move(sub));\n    z_drop(z_move(pub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}\n\n/* TODO: Test disabled due to session reconnection issues\nstatic void test_advanced_late_joiner(void) {\n    printf(\"test_advanced_late_joiner\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/late_joiner\";\n\n    tcp_proxy_t *tcp_proxy;\n    z_owned_session_t s1, s2;\n    setup_two_peers_with_proxy(&s1, &s2, &tcp_proxy, 9000);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_history_options_default(&sub_opts.history);\n    sub_opts.history.detect_late_publishers = true;\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 10));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s2), &sub, z_loan(k), z_move(closure), &sub_opts));\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_cache_options_default(&pub_opts.cache);\n    pub_opts.cache.max_samples = 10;\n    pub_opts.publisher_detection = true;\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s1), &pub, z_loan(k), &pub_opts));\n\n    put_str(z_loan(pub), \"1\");\n    put_str(z_loan(pub), \"2\");\n    put_str(z_loan(pub), \"3\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_empty(z_loan(handler));\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_ms(TEST_RECONNECT_MS);\n\n    put_str(z_loan(pub), \"4\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_next(z_loan(handler), \"2\");\n    expect_next(z_loan(handler), \"3\");\n    expect_next(z_loan(handler), \"4\");\n    expect_empty(z_loan(handler));\n\n    z_drop(z_move(sub));\n    z_drop(z_move(pub));\n    z_drop(z_move(handler));\n\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}*/\n\n#endif  // Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 && Z_FEATURE_LOCAL_QUERYABLE == 1\nstatic void test_advanced_local_pubsub(void) {\n    printf(\"test_advanced_local_pubsub\\n\");\n\n    const char *expr = \"zenoh-pico/advanced-pubsub/test/local_pubsub\";\n\n    z_owned_session_t s;\n    z_owned_config_t c;\n    z_config_default(&c);\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ASSERT_OK(z_open(&s, z_config_move(&c), NULL));\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    pub_opts.cache.is_enabled = true;\n    pub_opts.cache.max_samples = 1;\n    pub_opts.sample_miss_detection.is_enabled = true;\n\n    ASSERT_OK(ze_declare_advanced_publisher(z_loan(s), &pub, z_loan(k), &pub_opts));\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_history_options_default(&sub_opts.history);\n    ze_advanced_subscriber_recovery_options_default(&sub_opts.recovery);\n    ze_advanced_subscriber_last_sample_miss_detection_options_default(&sub_opts.recovery.last_sample_miss_detection);\n\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 1));\n    ASSERT_OK(ze_declare_advanced_subscriber(z_loan(s), &sub, z_loan(k), z_move(closure), &sub_opts));\n    // z_sleep_ms(TEST_SLEEP_MS);\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    expect_next(z_loan(handler), \"1\");\n    expect_empty(z_loan(handler));\n\n    ze_advanced_subscriber_drop(z_move(sub));\n    ze_advanced_publisher_drop(z_move(pub));\n    z_fifo_handler_sample_drop(z_move(handler));\n\n    z_session_drop(z_session_move(&s));\n}\n#endif\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_advanced_history(false);\n#if defined(ZENOH_LINUX)\n    test_advanced_history(true);\n#endif\n#ifdef Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY\n    test_advanced_retransmission();\n    test_advanced_retransmission_periodic();\n    test_advanced_retransmission_heartbeat();\n    test_advanced_sample_miss();\n    test_advanced_retransmission_sample_miss();\n    // test_advanced_late_joiner();\n#endif\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 && Z_FEATURE_LOCAL_QUERYABLE == 1\n    test_advanced_local_pubsub();\n#endif\n\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\n        \"Missing config token to build this test. This test requires: Z_FEATURE_ADVANCED_PUBLICATION \"\n        \"and Z_FEATURE_ADVANCED_SUBSCRIPTION\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_api_alignment_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/result.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define URI \"demo/example/**/*\"\n// Don't include <windows.h> due to clash with Zenoh Pico system includes\n#if !defined(WIN32) && !defined(_WIN32) && (!defined(__WIN32) || defined(__CYGWIN__))\n#include <unistd.h>\n#endif\n\n#include \"zenoh-pico.h\"\n\n#define SLEEP 2\n#define SCOUTING_TIMEOUT \"1000\"\n\n#define assert_eq(x, y)                                     \\\n    {                                                       \\\n        int l = (int)x;                                     \\\n        int r = (int)y;                                     \\\n        if (l != r) {                                       \\\n            printf(\"assert_eq failed: l=%d, r=%d\\n\", l, r); \\\n            assert(false);                                  \\\n        }                                                   \\\n    }\n\nconst char *value = \"Test value\";\n\nvolatile unsigned int zids = 0;\nvoid zid_handler(const z_id_t *id, void *arg) {\n    (void)(arg);\n    (void)(id);\n    printf(\"%s\\n\", __func__);\n    zids++;\n}\n\nvolatile unsigned int hellos = 0;\nvoid hello_handler(z_loaned_hello_t *hello, void *arg) {\n    (void)hello;\n    (void)(arg);\n    printf(\"%s\\n\", __func__);\n    hellos++;\n}\n\nvolatile unsigned int queries = 0;\nvoid query_handler(z_loaned_query_t *query, void *arg) {\n    printf(\"%s\\n\", __func__);\n    queries++;\n\n    const z_loaned_keyexpr_t *query_ke = z_query_keyexpr(query);\n    z_view_string_t k_str;\n    z_keyexpr_as_view_string(query_ke, &k_str);\n    (void)arg;\n    assert(!z_view_string_is_empty(&k_str));\n\n    z_view_string_t pred;\n    z_query_parameters(query, &pred);\n    (void)(pred);\n    const z_loaned_bytes_t *payload = z_query_payload(query);\n    (void)(payload);\n    z_query_reply_options_t _ret_qreply_opt;\n    z_query_reply_options_default(&_ret_qreply_opt);\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, value);\n\n    z_query_reply(query, query_ke, z_move(reply_payload), &_ret_qreply_opt);\n}\n\nvolatile unsigned int replies = 0;\nvoid reply_handler(z_loaned_reply_t *reply, void *arg) {\n    printf(\"%s\\n\", __func__);\n    replies++;\n    (void)arg;\n\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n\n        z_view_string_t k_str;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &k_str);\n        (void)arg;\n        assert(!z_view_string_is_empty(&k_str));\n    } else {\n        const z_loaned_reply_err_t *_ret_zerr = z_reply_err(reply);\n        (void)(_ret_zerr);\n    }\n}\n\nvolatile unsigned int datas = 0;\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    printf(\"%s\\n\", __func__);\n    datas++;\n\n    z_view_string_t k_str;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &k_str);\n    (void)arg;\n    assert(!z_view_string_is_empty(&k_str));\n    const char *encoding_expected =\n        z_sample_kind(sample) == Z_SAMPLE_KIND_PUT ? \"zenoh/bytes;test_encoding\" : \"zenoh/bytes\";\n    z_owned_string_t encoding;\n    z_encoding_to_string(z_sample_encoding(sample), &encoding);\n    printf(\"%s\\n\", z_string_data(z_loan(encoding)));\n    assert(strncmp(encoding_expected, z_string_data(z_loan(encoding)), strlen(encoding_expected)) == 0);\n    z_drop(z_move(encoding));\n}\n\nint main(int argc, char **argv) {\n    assert_eq(argc, 2);\n    (void)(argc);\n    setvbuf(stdout, NULL, _IOLBF, 1024);\n\n#ifdef ZENOH_C\n    zc_init_logger();\n    const char *encoding_expected =\n        z_sample_kind(sample) == Z_SAMPLE_KIND_PUT ? \"zenoh/bytes\" : \"zenoh/bytes;test_encoding\";\n#endif\n\n    z_view_keyexpr_t key_demo_example, key_demo_example_a, key_demo_example_starstar;\n    z_view_keyexpr_from_str(&key_demo_example, \"demo/example\");\n    z_view_keyexpr_from_str(&key_demo_example_a, \"demo/example/a\");\n    z_view_keyexpr_from_str(&key_demo_example_starstar, \"demo/example/**\");\n\n    bool _ret_bool = z_keyexpr_includes(z_loan(key_demo_example_starstar), z_loan(key_demo_example_a));\n    assert(_ret_bool);\n    _ret_bool = z_keyexpr_intersects(z_loan(key_demo_example_starstar), z_loan(key_demo_example_a));\n    assert(_ret_bool);\n    _ret_bool = z_keyexpr_equals(z_loan(key_demo_example_starstar), z_loan(key_demo_example));\n    assert(!_ret_bool);\n    z_sleep_s(SLEEP);\n\n    size_t keyexpr_len = strlen(URI);\n    char *keyexpr_str = (char *)z_malloc(keyexpr_len + 1);\n    memcpy(keyexpr_str, URI, keyexpr_len);\n    keyexpr_str[keyexpr_len] = '\\0';\n    z_result_t _ret_res = z_keyexpr_is_canon(keyexpr_str, keyexpr_len);\n    assert(_ret_res < 0);\n\n    _ret_res = z_keyexpr_canonize(keyexpr_str, &keyexpr_len);\n    assert_eq(_ret_res, 0);\n    assert_eq(strlen(URI), keyexpr_len);\n\n    printf(\"Ok\\n\");\n    z_sleep_s(SLEEP);\n\n    printf(\"Testing Configs...\");\n    z_owned_config_t _ret_config;\n    z_config_default(&_ret_config);\n    assert(z_internal_check(_ret_config));\n#ifdef ZENOH_PICO\n    _ret_res = zp_config_insert(z_loan_mut(_ret_config), Z_CONFIG_CONNECT_KEY, argv[1]);\n    assert_eq(_ret_res, 0);\n    const char *_ret_cstr = zp_config_get(z_loan(_ret_config), Z_CONFIG_CONNECT_KEY);\n    assert_eq(strlen(_ret_cstr), strlen(argv[1]));\n    assert_eq(strncmp(_ret_cstr, argv[1], strlen(_ret_cstr)), 0);\n#endif\n\n    z_owned_config_t _ret_sconfig;\n    z_config_default(&_ret_sconfig);\n    assert(z_internal_check(_ret_sconfig));\n\n    printf(\"Ok\\n\");\n    z_sleep_s(SLEEP);\n\n    printf(\"Testing Scouting...\");\n    z_owned_closure_hello_t _ret_closure_hello;\n    z_closure(&_ret_closure_hello, hello_handler, NULL, NULL);\n    _ret_res = z_scout(z_move(_ret_sconfig), z_move(_ret_closure_hello), NULL);\n    assert_eq(_ret_res, 0);\n    assert(hellos >= 1);\n\n    uint32_t _scouting_timeout = (uint32_t)strtoul(SCOUTING_TIMEOUT, NULL, 10);\n    z_sleep_ms(_scouting_timeout);\n    printf(\"Ok\\n\");\n    z_sleep_s(SLEEP);\n\n    z_owned_session_t s1;\n    z_open(&s1, z_move(_ret_config), NULL);\n    assert(z_internal_check(s1));\n    z_id_t _ret_zid = z_info_zid(z_loan(s1));\n    printf(\"Session 1 with PID: 0x\");\n    z_owned_string_t id_str;\n    z_id_to_string(&_ret_zid, &id_str);\n    printf(\"%.*s\\n\", (int)z_string_len(z_loan(id_str)), z_string_data(z_loan(id_str)));\n    z_drop(z_move(id_str));\n\n    z_owned_closure_zid_t _ret_closure_zid;\n    z_closure(&_ret_closure_zid, zid_handler, NULL, NULL);\n    _ret_res = z_info_peers_zid(z_loan(s1), z_move(_ret_closure_zid));\n    assert_eq(_ret_res, 0);\n    z_sleep_s(SLEEP);\n    assert_eq(zids, 0);\n\n    z_closure(&_ret_closure_zid, zid_handler, NULL, NULL);\n    _ret_res = z_info_routers_zid(z_loan(s1), z_move(_ret_closure_zid));\n    assert_eq(_ret_res, 0);\n\n    z_sleep_s(SLEEP);\n    assert_eq(zids, 1);\n\n    z_sleep_s(SLEEP);\n\n    z_config_default(&_ret_config);\n#ifdef ZENOH_PICO\n    _ret_res = zp_config_insert(z_loan_mut(_ret_config), Z_CONFIG_CONNECT_KEY, argv[1]);\n    assert_eq(_ret_res, 0);\n    _ret_cstr = zp_config_get(z_loan(_ret_config), Z_CONFIG_CONNECT_KEY);\n    assert_eq(strlen(_ret_cstr), strlen(argv[1]));\n    assert_eq(strncmp(_ret_cstr, argv[1], strlen(_ret_cstr)), 0);\n#endif\n\n    z_owned_session_t s2;\n    z_open(&s2, z_move(_ret_config), NULL);\n    assert(z_internal_check(s2));\n    _ret_zid = z_info_zid(z_loan(s2));\n    printf(\"Session 2 with PID: 0x\");\n    z_id_to_string(&_ret_zid, &id_str);\n    printf(\"%.*s\\n\", (int)z_string_len(z_loan(id_str)), z_string_data(z_loan(id_str)));\n    z_drop(z_move(id_str));\n\n    z_sleep_s(SLEEP);\n\n    const z_loaned_session_t *ls1 = z_loan(s1);\n    printf(\"Declaring Subscriber...\");\n    z_owned_closure_sample_t _ret_closure_sample;\n    z_closure(&_ret_closure_sample, data_handler, NULL, &ls1);\n    z_subscriber_options_t _ret_sub_opt;\n    z_subscriber_options_default(&_ret_sub_opt);\n\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, keyexpr_str);\n    z_owned_subscriber_t _ret_sub;\n    _ret_res = z_declare_subscriber(z_loan(s2), &_ret_sub, z_loan(ke), z_move(_ret_closure_sample), &_ret_sub_opt);\n    assert(_ret_res == _Z_RES_OK);\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n\n    char s1_res[64];\n    sprintf(s1_res, \"%s/chunk/%d\", keyexpr_str, 1);\n    z_view_keyexpr_t s1_key;\n    z_view_keyexpr_from_str(&s1_key, s1_res);\n    z_owned_keyexpr_t _ret_expr;\n    z_declare_keyexpr(z_loan(s1), &_ret_expr, z_loan(s1_key));\n    assert(z_internal_check(_ret_expr));\n    printf(\"Ok\\n\");\n\n    printf(\"Session Put...\");\n    z_put_options_t _ret_put_opt;\n    z_put_options_default(&_ret_put_opt);\n    z_owned_encoding_t encoding;\n    z_encoding_from_str(&encoding, \"test_encoding\");\n    _ret_put_opt.encoding = z_move(encoding);\n    _ret_put_opt.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_str(&payload, (char *)value, NULL, NULL);\n\n    _ret_res = z_put(z_loan(s1), z_loan(_ret_expr), z_move(payload), &_ret_put_opt);\n    assert_eq(_ret_res, 0);\n    assert(!z_internal_check(encoding));\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n    assert_eq(datas, 1);\n\n    printf(\"Session delete...\");\n    z_delete_options_t _ret_delete_opt;\n    z_delete_options_default(&_ret_delete_opt);\n    _ret_delete_opt.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n    _ret_res = z_delete(z_loan(s1), z_loan(_ret_expr), &_ret_delete_opt);\n    assert_eq(_ret_res, 0);\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n    assert_eq(datas, 2);\n\n    printf(\"Declaring Publisher...\");\n    z_publisher_options_t _ret_pub_opt;\n    z_publisher_options_default(&_ret_pub_opt);\n    z_encoding_from_str(&encoding, \"test_encoding\");\n    _ret_pub_opt.encoding = z_move(encoding);\n    _ret_pub_opt.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n    z_owned_publisher_t _ret_pub;\n    _ret_res = z_declare_publisher(z_loan(s1), &_ret_pub, z_loan(s1_key), &_ret_pub_opt);\n    assert(_ret_res == _Z_RES_OK);\n    assert(!z_internal_check(encoding));\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n\n    printf(\"Publisher Put...\");\n    // Create payload\n    z_bytes_copy_from_str(&payload, value);\n\n    z_publisher_put_options_t _ret_pput_opt;\n    z_publisher_put_options_default(&_ret_pput_opt);\n    _ret_res = z_publisher_put(z_loan(_ret_pub), z_move(payload), &_ret_pput_opt);\n    assert_eq(_ret_res, 0);\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n    assert_eq(datas, 3);\n\n    printf(\"Publisher Delete...\");\n    z_publisher_delete_options_t _ret_pdelete_opt;\n    z_publisher_delete_options_default(&_ret_pdelete_opt);\n    _ret_res = z_publisher_delete(z_loan(_ret_pub), &_ret_pdelete_opt);\n    assert_eq(_ret_res, 0);\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n    assert_eq(datas, 4);\n\n    printf(\"Undeclaring Publisher...\");\n    z_drop(z_move(_ret_pub));\n    assert(!z_internal_check(_ret_pub));\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n\n    printf(\"Undeclaring Subscriber...\");\n    z_drop(z_move(_ret_sub));\n    assert(!z_internal_check(_ret_sub));\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n\n    printf(\"Declaring Queryable...\");\n    z_owned_closure_query_t _ret_closure_query;\n    z_closure(&_ret_closure_query, query_handler, NULL, &ls1);\n    z_queryable_options_t _ret_qle_opt;\n    z_queryable_options_default(&_ret_qle_opt);\n    z_owned_queryable_t qle;\n    assert(z_declare_queryable(z_loan(s1), &qle, z_loan(s1_key), z_move(_ret_closure_query), &_ret_qle_opt) ==\n           _Z_RES_OK);\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n\n    printf(\"Testing Consolidations...\");\n    const z_loaned_session_t *ls2 = z_loan(s2);\n    z_owned_closure_reply_t _ret_closure_reply;\n    z_closure(&_ret_closure_reply, reply_handler, NULL, &ls2);\n    z_get_options_t _ret_get_opt;\n    z_get_options_default(&_ret_get_opt);\n    _ret_get_opt.target = z_query_target_default();\n    _ret_get_opt.consolidation = z_query_consolidation_auto();\n    (void)(_ret_get_opt.consolidation);\n    _ret_get_opt.consolidation = z_query_consolidation_default();\n    (void)(_ret_get_opt.consolidation);\n    _ret_get_opt.consolidation = z_query_consolidation_latest();\n    (void)(_ret_get_opt.consolidation);\n    _ret_get_opt.consolidation = z_query_consolidation_monotonic();\n    (void)(_ret_get_opt.consolidation);\n    _ret_get_opt.consolidation = z_query_consolidation_none();\n    (void)(_ret_get_opt.consolidation);\n    printf(\"Ok\\n\");\n\n    printf(\"Testing Get...\");\n    _ret_res = z_get(z_loan(s2), z_loan(s1_key), \"\", z_move(_ret_closure_reply), &_ret_get_opt);\n    assert_eq(_ret_res, 0);\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP);\n    assert_eq(queries, 1);\n    assert_eq(replies, 1);\n\n    printf(\"Undeclaring Queryable...\");\n    z_drop(z_move(qle));\n    printf(\"Ok\\n\");\n\n    printf(\"Undeclaring Keyexpr...\");\n    _ret_res = z_undeclare_keyexpr(z_loan(s1), z_move(_ret_expr));\n    printf(\" %02x\\n\", _ret_res);\n    assert_eq(_ret_res, 0);\n    assert(!z_internal_check(_ret_expr));\n    printf(\"Ok\\n\");\n\n    printf(\"Close sessions...\");\n    _ret_res = z_close(z_loan_mut(s1), NULL);\n    assert_eq(_ret_res, 0);\n    z_drop(z_move(s1));\n\n    _ret_res = z_close(z_loan_mut(s2), NULL);\n    assert_eq(_ret_res, 0);\n    z_drop(z_move(s2));\n    printf(\"Ok\\n\");\n\n    z_sleep_s(SLEEP * 5);\n\n    z_free(keyexpr_str);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_api_batching_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <assert.h>\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_BATCHING == 1\n\nvoid test_batching_while_connected(void) {\n    printf(\"test_batching_while_connected\\n\");\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    ASSERT_OK(z_open(&s2, z_move(c2), NULL));\n\n    z_sleep_ms(1000);  // Wait for connection to establish\n\n    ASSERT_OK(zp_batch_start(z_loan_mut(s2)));\n    ASSERT_OK(zp_batch_flush(z_loan_mut(s2)));\n    ASSERT_OK(zp_batch_stop(z_loan_mut(s2)));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nvoid test_batching_after_disconnection(void) {\n    printf(\"test_batching_after_disconnection\\n\");\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, \"tcp/127.0.0.1:12345\");\n\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"client\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:12345\");\n\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    ASSERT_OK(z_open(&s2, z_move(c2), NULL));\n\n    // Wait for connection to establish\n    z_sleep_ms(1000);\n\n    // Drop session and wait for it to be detected as dropped\n    z_session_drop(z_session_move(&s1));\n    z_sleep_ms(10000);\n\n    ASSERT_ERR(zp_batch_start(z_loan_mut(s2)), _Z_ERR_TRANSPORT_NOT_AVAILABLE);\n    ASSERT_ERR(zp_batch_flush(z_loan_mut(s2)), _Z_ERR_TRANSPORT_NOT_AVAILABLE);\n    ASSERT_ERR(zp_batch_stop(z_loan_mut(s2)), _Z_ERR_TRANSPORT_NOT_AVAILABLE);\n\n    z_session_drop(z_session_move(&s2));\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_batching_while_connected();\n    test_batching_after_disconnection();\n\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\"Missing config token to build this test. This test requires: Z_FEATURE_BATCHING\\n\");\n    return 0;\n}\n\n#endif  // Z_FEATURE_BATCHING == 1\n"
  },
  {
    "path": "tests/z_api_bytes_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/serialization.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nvoid test_reader_seek(void) {\n    uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, data, 10, NULL, NULL);\n\n    z_bytes_reader_t reader = z_bytes_get_reader(z_bytes_loan(&payload));\n    assert(z_bytes_reader_tell(&reader) == 0);\n\n    assert(0 == z_bytes_reader_seek(&reader, 5, SEEK_CUR));\n    assert(z_bytes_reader_tell(&reader) == 5);\n\n    assert(0 == z_bytes_reader_seek(&reader, 7, SEEK_SET));\n    assert(z_bytes_reader_tell(&reader) == 7);\n\n    assert(0 == z_bytes_reader_seek(&reader, -1, SEEK_END));\n    assert(z_bytes_reader_tell(&reader) == 9);\n\n    assert(z_bytes_reader_seek(&reader, 20, SEEK_SET) < 0);\n\n    assert(0 == z_bytes_reader_seek(&reader, 5, SEEK_SET));\n    assert(z_bytes_reader_tell(&reader) == 5);\n\n    assert(z_bytes_reader_seek(&reader, 10, SEEK_CUR) < 0);\n    assert(z_bytes_reader_seek(&reader, 10, SEEK_END) < 0);\n    assert(z_bytes_reader_seek(&reader, -20, SEEK_END) < 0);\n\n    z_bytes_drop(z_bytes_move(&payload));\n}\n\nvoid test_reader_read(void) {\n    uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    uint8_t data_out[10] = {0};\n\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, data, 10, NULL, NULL);\n    z_bytes_reader_t reader = z_bytes_get_reader(z_bytes_loan(&payload));\n\n    assert(5 == z_bytes_reader_read(&reader, data_out, 5));\n    assert(5 == z_bytes_reader_remaining(&reader));\n\n    z_bytes_reader_seek(&reader, 2, SEEK_CUR);\n    assert(2 == z_bytes_reader_read(&reader, data_out + 7, 2));\n    assert(1 == z_bytes_reader_remaining(&reader));\n\n    z_bytes_reader_seek(&reader, 5, SEEK_SET);\n    assert(2 == z_bytes_reader_read(&reader, data_out + 5, 2));\n    assert(3 == z_bytes_reader_remaining(&reader));\n\n    z_bytes_reader_seek(&reader, -1, SEEK_END);\n    assert(1 == z_bytes_reader_read(&reader, data_out + 9, 10));\n    assert(0 == z_bytes_reader_remaining(&reader));\n\n    assert(0 == z_bytes_reader_read(&reader, data_out, 10));\n\n    assert(!memcmp(data, data_out, 10));\n\n    z_bytes_drop(z_bytes_move(&payload));\n}\n\nvoid test_writer(void) {\n    uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    uint8_t data_out[10] = {0};\n\n    z_owned_bytes_writer_t writer;\n    z_bytes_writer_empty(&writer);\n\n    assert(z_bytes_writer_write_all(z_bytes_writer_loan_mut(&writer), data, 3) == 0);\n    assert(z_bytes_writer_write_all(z_bytes_writer_loan_mut(&writer), data + 3, 5) == 0);\n    assert(z_bytes_writer_write_all(z_bytes_writer_loan_mut(&writer), data + 8, 2) == 0);\n\n    z_owned_bytes_t payload;\n    z_bytes_writer_finish(z_bytes_writer_move(&writer), &payload);\n\n    z_bytes_reader_t reader = z_bytes_get_reader(z_bytes_loan(&payload));\n\n    assert(10 == z_bytes_reader_read(&reader, data_out, 10));\n    assert(0 == memcmp(data, data_out, 10));\n\n    z_bytes_drop(z_bytes_move(&payload));\n}\n\nvoid test_append(void) {\n    uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    uint8_t data_out[10] = {0};\n\n    z_owned_bytes_t payload;\n    z_bytes_copy_from_buf(&payload, data, 5);\n\n    z_owned_bytes_writer_t writer;\n    z_bytes_writer_empty(&writer);\n    z_bytes_writer_append(z_bytes_writer_loan_mut(&writer), z_bytes_move(&payload));\n    {\n        z_owned_bytes_t b;\n        z_bytes_copy_from_buf(&b, data + 5, 5);\n        assert(z_bytes_writer_append(z_bytes_writer_loan_mut(&writer), z_bytes_move(&b)) == 0);\n    }\n\n    z_bytes_writer_finish(z_bytes_writer_move(&writer), &payload);\n    z_bytes_reader_t reader = z_bytes_get_reader(z_bytes_loan(&payload));\n    z_bytes_reader_read(&reader, data_out, 10);\n\n    assert(!memcmp(data, data_out, 10));\n\n    uint8_t d;\n    assert(0 == z_bytes_reader_read(&reader, &d, 1));  // we reached the end of the payload\n\n    z_bytes_drop(z_bytes_move(&payload));\n}\n\nvoid custom_deleter(void *data, void *context) {\n    (void)data;\n    size_t *cnt = (size_t *)context;\n    (*cnt)++;\n}\n\nbool z_check_and_drop_payload(z_owned_bytes_t *payload, uint8_t *data, size_t len) {\n    z_owned_slice_t out;\n    z_bytes_to_slice(z_bytes_loan(payload), &out);\n    z_bytes_drop(z_bytes_move(payload));\n    bool res = memcmp(data, z_slice_data(z_slice_loan(&out)), len) == 0;\n    z_slice_drop(z_slice_move(&out));\n\n    return res;\n}\n\nvoid test_slice(void) {\n    uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n\n    size_t cnt = 0;\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, data, 10, custom_deleter, (void *)&cnt);\n\n    z_owned_slice_t out;\n    z_bytes_to_slice(z_bytes_loan(&payload), &out);\n\n    assert(cnt == 0);\n    z_bytes_drop(z_bytes_move(&payload));\n    assert(cnt == 1);\n\n    assert(!memcmp(data, z_slice_data(z_slice_loan(&out)), 10));\n    z_slice_drop(z_slice_move(&out));\n\n    z_owned_bytes_t payload2;\n    z_owned_slice_t s;\n    z_slice_copy_from_buf(&s, data, 10);\n    z_bytes_copy_from_slice(&payload2, z_slice_loan(&s));\n    assert(z_internal_slice_check(&s));\n    z_slice_drop(z_slice_move(&s));\n    assert(z_check_and_drop_payload(&payload2, data, 10));\n\n    z_owned_bytes_t payload3;\n    z_slice_copy_from_buf(&s, data, 10);\n    z_bytes_from_slice(&payload3, z_slice_move(&s));\n    assert(!z_internal_slice_check(&s));\n    assert(z_check_and_drop_payload(&payload3, data, 10));\n\n    z_owned_bytes_t payload4;\n    z_bytes_copy_from_buf(&payload4, data, 10);\n    assert(z_check_and_drop_payload(&payload4, data, 10));\n\n    z_owned_bytes_t payload5;\n    z_bytes_from_static_buf(&payload5, data, 10);\n    assert(z_check_and_drop_payload(&payload5, data, 10));\n}\n\n#define TEST_ARITHMETIC(TYPE, EXT, VAL)                     \\\n    {                                                       \\\n        TYPE in = VAL, out;                                 \\\n        z_owned_bytes_t payload;                            \\\n        ze_serialize_##EXT(&payload, in);                   \\\n        ze_deserialize_##EXT(z_bytes_loan(&payload), &out); \\\n        assert(in == out);                                  \\\n        z_bytes_drop(z_bytes_move(&payload));               \\\n    }\n\nvoid test_arithmetic(void) {\n    TEST_ARITHMETIC(uint8_t, uint8, 5);\n    TEST_ARITHMETIC(uint16_t, uint16, 1000);\n    TEST_ARITHMETIC(uint32_t, uint32, 51000000);\n    TEST_ARITHMETIC(uint64_t, uint64, 1000000000005);\n\n    TEST_ARITHMETIC(int8_t, int8, 5);\n    TEST_ARITHMETIC(int16_t, int16, -1000);\n    TEST_ARITHMETIC(int32_t, int32, 51000000);\n    TEST_ARITHMETIC(int64_t, int64, -1000000000005);\n\n    TEST_ARITHMETIC(float, float, 10.1f);\n    TEST_ARITHMETIC(double, double, -105.001);\n}\n\nbool check_slice(const z_loaned_bytes_t *b, const uint8_t *data, size_t len) {\n    z_bytes_slice_iterator_t it = z_bytes_get_slice_iterator(b);\n    uint8_t *data_out = (uint8_t *)malloc(len);\n    z_view_slice_t v;\n    size_t pos = 0;\n    while (z_bytes_slice_iterator_next(&it, &v)) {\n        const uint8_t *slice_data = z_slice_data(z_view_slice_loan(&v));\n        size_t slice_len = z_slice_len(z_view_slice_loan(&v));\n        memcpy(data_out + pos, slice_data, slice_len);\n        pos += slice_len;\n    }\n    assert(pos == len);\n    assert(memcmp(data, data_out, len) == 0);\n    free(data_out);\n    return true;\n}\n\nvoid test_slices(void) {\n    uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    z_owned_bytes_t payload;\n    z_bytes_copy_from_buf(&payload, data, 10);\n    assert(check_slice(z_bytes_loan(&payload), data, 10));\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n    z_view_slice_t view;\n    assert(z_bytes_get_contiguous_view(z_bytes_loan(&payload), &view) == Z_OK);\n    assert(z_slice_len(z_view_slice_loan(&view)) == 10);\n    assert(memcmp(data, z_slice_data(z_view_slice_loan(&view)), 10) == 0);\n#endif\n    z_bytes_drop(z_bytes_move(&payload));\n\n    z_owned_bytes_writer_t writer;\n    z_bytes_writer_empty(&writer);\n\n    // possible multiple slices\n    // reusing empty writer\n    for (size_t i = 0; i < 10; i++) {\n        z_owned_bytes_t b;\n        z_bytes_copy_from_buf(&b, data + i, 1);\n        z_bytes_writer_append(z_bytes_writer_loan_mut(&writer), z_bytes_move(&b));\n    }\n\n    z_bytes_writer_finish(z_bytes_writer_move(&writer), &payload);\n    assert(check_slice(z_bytes_loan(&payload), data, 10));\n#if defined(Z_FEATURE_UNSTABLE_API)\n    assert(z_bytes_get_contiguous_view(z_bytes_loan(&payload), &view) != Z_OK);\n#endif\n    z_bytes_drop(z_bytes_move(&payload));\n}\n\nvoid test_serialize_simple(void) {\n    z_owned_bytes_t b;\n\n    ze_owned_serializer_t serializer;\n    ze_serializer_empty(&serializer);\n\n    assert(ze_serializer_serialize_bool(ze_serializer_loan_mut(&serializer), true) == 0);\n    assert(ze_serializer_serialize_bool(ze_serializer_loan_mut(&serializer), false) == 0);\n    assert(ze_serializer_serialize_double(ze_serializer_loan_mut(&serializer), 0.5) == 0);\n    assert(ze_serializer_serialize_int32(ze_serializer_loan_mut(&serializer), -1111) == 0);\n    assert(ze_serializer_serialize_str(ze_serializer_loan_mut(&serializer), \"abc\") == 0);\n    ze_serializer_finish(ze_serializer_move(&serializer), &b);\n    double d;\n    int32_t i;\n    z_owned_string_t s;\n    bool bl = false;\n\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(z_bytes_loan(&b));\n    assert(!ze_deserializer_is_done(&deserializer));\n    assert(ze_deserializer_deserialize_bool(&deserializer, &bl) == 0);\n    assert(bl);\n    assert(ze_deserializer_deserialize_bool(&deserializer, &bl) == 0);\n    assert(!bl);\n    assert(ze_deserializer_deserialize_double(&deserializer, &d) == 0);\n    assert(ze_deserializer_deserialize_int32(&deserializer, &i) == 0);\n    assert(ze_deserializer_deserialize_string(&deserializer, &s) == 0);\n    assert(ze_deserializer_is_done(&deserializer));\n\n    assert(d == 0.5);\n    assert(i == -1111);\n    assert(strncmp(\"abc\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n\n    z_string_drop(z_string_move(&s));\n    z_bytes_drop(z_bytes_move(&b));\n}\n\nvoid test_serialize_sequence(void) {\n    uint32_t input[6] = {1, 2, 3, 100, 10000, 100000};\n    z_owned_bytes_t b;\n\n    ze_owned_serializer_t serializer;\n    ze_serializer_empty(&serializer);\n    ze_serializer_serialize_sequence_length(ze_serializer_loan_mut(&serializer), 6);\n    for (size_t i = 0; i < 6; ++i) {\n        ze_serializer_serialize_uint32(ze_serializer_loan_mut(&serializer), input[i]);\n    }\n\n    ze_serializer_finish(ze_serializer_move(&serializer), &b);\n\n    ze_deserializer_t deserializer = ze_deserializer_from_bytes(z_bytes_loan(&b));\n    size_t len = 0;\n    assert(!ze_deserializer_is_done(&deserializer));\n    assert(ze_deserializer_deserialize_sequence_length(&deserializer, &len) == 0);\n    assert(len == 6);\n    for (size_t i = 0; i < 6; i++) {\n        uint32_t u = 0;\n        assert(ze_deserializer_deserialize_uint32(&deserializer, &u) == 0);\n        assert(u == input[i]);\n    }\n    assert(ze_deserializer_is_done(&deserializer));\n    z_bytes_drop(z_bytes_move(&b));\n}\n\nint main(void) {\n    test_reader_seek();\n    test_reader_read();\n    test_writer();\n    test_slice();\n    test_append();\n    test_slices();\n    test_arithmetic();\n    test_serialize_simple();\n    test_serialize_sequence();\n}\n"
  },
  {
    "path": "tests/z_api_callback_drop_on_undeclare_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#ifdef Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY\n#include \"utils/tcp_proxy.h\"\n#endif\n\n#undef NDEBUG\n#include <assert.h>\n\ntypedef struct callback_arg_t {\n    volatile bool called;\n    volatile bool dropped;\n} callback_arg_t;\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct thread_arg_t {\n    z_owned_session_t* session;\n    z_view_keyexpr_t* ke;\n} thread_arg_t;\n#endif\n\nz_result_t open_session(z_owned_session_t* s) {\n    z_owned_config_t config;\n    _Z_RETURN_IF_ERR(z_config_default(&config));\n    return z_open(s, z_config_move(&config), NULL);\n}\n\n#define DECLARE_ON_RECEIVE_HANDLER(_type, cv)                     \\\n    void on_receive_##_type##_handler(cv _type* msg, void* arg) { \\\n        (void)msg;                                                \\\n        callback_arg_t* callback_arg = (callback_arg_t*)arg;      \\\n        z_sleep_s(3);                                             \\\n        callback_arg->called = true;                              \\\n    }                                                             \\\n    void on_drop_##_type##_handler(void* arg) {                   \\\n        callback_arg_t* callback_arg = (callback_arg_t*)arg;      \\\n        z_sleep_s(1);                                             \\\n        callback_arg->dropped = true;                             \\\n    }\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\n#if Z_FEATURE_MULTI_THREAD == 1\nvoid* put_from_another_thread(void* targ) {\n    thread_arg_t* arg = (thread_arg_t*)targ;\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, \"payload\");\n    assert(z_put(z_session_loan(arg->session), z_view_keyexpr_loan(arg->ke), z_bytes_move(&payload), NULL) == Z_OK);\n    return NULL;\n}\n#endif\n\nDECLARE_ON_RECEIVE_HANDLER(z_loaned_sample_t, _ZP_NOTHING)\nvoid test_subscriber_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_owned_subscriber_t subscriber;\n    z_view_keyexpr_t ke;\n    z_owned_closure_sample_t closure;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/subscriber_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/subscriber_callback_drop\") == Z_OK);\n    }\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Subscriber callback drop on undeclare: background = %d\\n\", background);\n    z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_declare_subscriber(z_session_loan(&session1), &subscriber, z_view_keyexpr_loan(&ke),\n                                    z_closure_sample_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(z_declare_background_subscriber(z_session_loan(&session1), z_view_keyexpr_loan(&ke),\n                                               z_closure_sample_move(&closure), NULL) == Z_OK);\n    }\n    z_sleep_s(2);\n\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, \"payload\");\n    assert(z_put(z_session_loan(&session2), z_view_keyexpr_loan(&ke), z_bytes_move(&payload), NULL) == Z_OK);\n    z_sleep_s(1);\n    if (!background) {\n        z_undeclare_subscriber(z_subscriber_move(&subscriber));\n    } else {\n        z_close(z_session_loan_mut(&session1), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 && Z_FEATURE_MULTI_THREAD == 1\n    printf(\"Test: Local Subscriber callback drop on undeclare: background = %d\\n\", background);\n    arg.called = false;\n    arg.dropped = false;\n    z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_declare_subscriber(z_session_loan(&session2), &subscriber, z_view_keyexpr_loan(&ke),\n                                    z_closure_sample_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(z_declare_background_subscriber(z_session_loan(&session2), z_view_keyexpr_loan(&ke),\n                                               z_closure_sample_move(&closure), NULL) == Z_OK);\n    }\n    thread_arg_t thread_arg = {\n        .session = &session2,\n        .ke = &ke,\n    };\n    z_owned_task_t task;\n    z_task_init(&task, NULL, put_from_another_thread, &thread_arg);\n    z_sleep_s(1);\n    if (!background) {\n        z_undeclare_subscriber(z_subscriber_move(&subscriber));\n    } else {\n        z_close(z_session_loan_mut(&session2), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    z_task_join(z_task_move(&task));\n#endif\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n}\n\n#if Z_FEATURE_LIVELINESS == 1\nvoid test_liveliness_subscriber_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_owned_subscriber_t subscriber;\n    z_view_keyexpr_t ke;\n    z_owned_closure_sample_t closure;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/liveliness_subscriber_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/liveliness_subscriber_callback_drop\") == Z_OK);\n    }\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Liveliness Subscriber callback drop on undeclare: background = %d\\n\", background);\n    z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_liveliness_declare_subscriber(z_session_loan(&session1), &subscriber, z_view_keyexpr_loan(&ke),\n                                               z_closure_sample_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(z_liveliness_declare_background_subscriber(z_session_loan(&session1), z_view_keyexpr_loan(&ke),\n                                                          z_closure_sample_move(&closure), NULL) == Z_OK);\n    }\n    z_sleep_s(2);\n\n    z_owned_liveliness_token_t token;\n    assert(z_liveliness_declare_token(z_session_loan(&session2), &token, z_view_keyexpr_loan(&ke), NULL) == Z_OK);\n    z_sleep_s(1);\n\n    if (!background) {\n        z_undeclare_subscriber(z_subscriber_move(&subscriber));\n    } else {\n        z_close(z_session_loan_mut(&session1), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n\n    z_liveliness_token_drop(z_liveliness_token_move(&token));\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n}\n#endif\n\n#if Z_FEATURE_ADVANCED_SUBSCRIPTION == 1 && Z_FEATURE_ADVANCED_PUBLICATION == 1\nvoid test_advanced_subscriber_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    ze_owned_advanced_subscriber_t subscriber;\n    z_view_keyexpr_t ke;\n    z_owned_closure_sample_t closure;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/advanced_subscriber_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/advanced_subscriber_callback_drop\") == Z_OK);\n    }\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Advanced Subscriber callback drop on undeclare: background = %d\\n\", background);\n    z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler, (void*)&arg);\n    if (!background) {\n        assert(ze_declare_advanced_subscriber(z_session_loan(&session1), &subscriber, z_view_keyexpr_loan(&ke),\n                                              z_closure_sample_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(ze_declare_background_advanced_subscriber(z_session_loan(&session1), z_view_keyexpr_loan(&ke),\n                                                         z_closure_sample_move(&closure), NULL) == Z_OK);\n    }\n    z_sleep_s(2);\n\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, \"payload\");\n    assert(z_put(z_session_loan(&session2), z_view_keyexpr_loan(&ke), z_bytes_move(&payload), NULL) == Z_OK);\n    z_sleep_s(1);\n    if (!background) {\n        ze_undeclare_advanced_subscriber(ze_advanced_subscriber_move(&subscriber));\n    } else {\n        z_close(z_session_loan_mut(&session1), NULL);\n    }\n    assert(arg.dropped == true);\n    assert(arg.called == true);\n    z_session_drop(z_session_move(&session1));\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 && Z_FEATURE_MULTI_THREAD == 1\n    printf(\"Test: Local Advanced Subscriber callback drop on undeclare: background = %d\\n\", background);\n    arg.called = false;\n    arg.dropped = false;\n    z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler, (void*)&arg);\n    if (!background) {\n        assert(ze_declare_advanced_subscriber(z_session_loan(&session2), &subscriber, z_view_keyexpr_loan(&ke),\n                                              z_closure_sample_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(ze_declare_background_advanced_subscriber(z_session_loan(&session2), z_view_keyexpr_loan(&ke),\n                                                         z_closure_sample_move(&closure), NULL) == Z_OK);\n    }\n    thread_arg_t thread_arg = {\n        .session = &session2,\n        .ke = &ke,\n    };\n    z_owned_task_t task;\n    z_task_init(&task, NULL, put_from_another_thread, &thread_arg);\n    z_sleep_s(1);\n    if (!background) {\n        ze_undeclare_advanced_subscriber(ze_advanced_subscriber_move(&subscriber));\n    } else {\n        z_close(z_session_loan_mut(&session2), NULL);\n    }\n\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    z_task_join(z_task_move(&task));\n#endif\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n}\n\nvoid test_advanced_subscriber_late_join_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_view_keyexpr_t ke;\n    z_owned_closure_sample_t closure;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/late_advanced_subscriber_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/late_advanced_subscriber_callback_drop\") ==\n               Z_OK);\n    }\n    printf(\"Test: Advanced Subscriber late join callback drop on undeclare: background = %d\\n\", background);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_cache_options_default(&pub_opts.cache);\n    pub_opts.cache.max_samples = 10;\n    pub_opts.publisher_detection = true;\n    assert(ze_declare_advanced_publisher(z_loan(session2), &pub, z_view_keyexpr_loan(&ke), &pub_opts) == Z_OK);\n    z_sleep_s(1);\n\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, \"payload\");\n    ze_advanced_publisher_put(z_loan(pub), z_bytes_move(&payload), NULL);\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n    z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler, (void*)&arg);\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    ze_advanced_subscriber_history_options_default(&sub_opts.history);\n    sub_opts.history.detect_late_publishers = true;\n    if (!background) {\n        assert(ze_declare_advanced_subscriber(z_session_loan(&session1), &sub, z_view_keyexpr_loan(&ke),\n                                              z_closure_sample_move(&closure), &sub_opts) == Z_OK);\n    } else {\n        assert(ze_declare_background_advanced_subscriber(z_session_loan(&session1), z_view_keyexpr_loan(&ke),\n                                                         z_closure_sample_move(&closure), &sub_opts) == Z_OK);\n    }\n\n    z_sleep_s(1);\n    if (!background) {\n        ze_undeclare_advanced_subscriber(ze_advanced_subscriber_move(&sub));\n    } else {\n        z_close(z_session_loan_mut(&session1), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    ze_advanced_publisher_drop(ze_advanced_publisher_move(&pub));\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n}\n\n#if Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY == 1\nDECLARE_ON_RECEIVE_HANDLER(ze_miss_t, const)\nvoid put_str(const ze_loaned_advanced_publisher_t* pub, const char* str) {\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, str);\n    ze_advanced_publisher_put(pub, z_bytes_move(&payload), NULL);\n}\nvoid setup_two_peers_with_proxy(z_owned_session_t* s1, z_owned_session_t* s2, tcp_proxy_t** proxy,\n                                uint16_t upstream_listen_port) {\n    *proxy = tcp_proxy_create(\"127.0.0.1\", \"127.0.0.1\", upstream_listen_port);\n    assert(*proxy != NULL);\n\n    int port = tcp_proxy_start(*proxy, 100);\n    assert(port > 0);\n\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    char uri[128];\n\n    // s1 listens on the fixed upstream port\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    snprintf(uri, sizeof(uri), \"tcp/127.0.0.1:%u#iface=lo\", (unsigned)upstream_listen_port);\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, uri);\n\n    // s2 connects via proxy ephemeral port\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    snprintf(uri, sizeof(uri), \"tcp/127.0.0.1:%u#iface=lo\", (unsigned)port);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, uri);\n\n    assert(z_open(s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(s2, z_config_move(&c2), NULL) == Z_OK);\n}\n\nvoid test_advanced_sample_miss_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_view_keyexpr_t ke;\n\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/sample_miss_listener_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/sample_miss_listener_callback_drop\") == Z_OK);\n    }\n    printf(\"Test: Sample Miss Listener callback drop on undeclare: background = %d\\n\", background);\n\n    tcp_proxy_t* tcp_proxy;\n    setup_two_peers_with_proxy(&session1, &session2, &tcp_proxy, 9000);\n\n    ze_owned_advanced_subscriber_t sub;\n    ze_advanced_subscriber_options_t sub_opts;\n    ze_advanced_subscriber_options_default(&sub_opts);\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    assert(z_fifo_channel_sample_new(&closure, &handler, 10) == Z_OK);\n    assert(ze_declare_advanced_subscriber(z_session_loan(&session2), &sub, z_loan(ke), z_move(closure), &sub_opts) ==\n           Z_OK);\n\n    ze_owned_sample_miss_listener_t miss_listener;\n    ze_owned_closure_miss_t miss_closure;\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n    ze_closure_miss(&miss_closure, on_receive_ze_miss_t_handler, on_drop_ze_miss_t_handler, (void*)&arg);\n    if (!background) {\n        assert(ze_advanced_subscriber_declare_sample_miss_listener(ze_advanced_subscriber_loan(&sub), &miss_listener,\n                                                                   ze_closure_miss_move(&miss_closure)) == Z_OK);\n    } else {\n        assert(ze_advanced_subscriber_declare_background_sample_miss_listener(\n                   ze_advanced_subscriber_loan(&sub), ze_closure_miss_move(&miss_closure)) == Z_OK);\n    }\n    z_sleep_s(1);\n\n    ze_owned_advanced_publisher_t pub;\n    ze_advanced_publisher_options_t pub_opts;\n    ze_advanced_publisher_options_default(&pub_opts);\n    ze_advanced_publisher_sample_miss_detection_options_default(&pub_opts.sample_miss_detection);\n    assert(ze_declare_advanced_publisher(z_session_loan(&session1), &pub, z_loan(ke), &pub_opts) == Z_OK);\n\n    put_str(z_loan(pub), \"1\");\n    z_sleep_ms(500);\n    put_str(z_loan(pub), \"2\");\n    z_sleep_ms(500);\n\n    tcp_proxy_set_enabled(tcp_proxy, false);\n    z_sleep_ms(500);\n\n    put_str(z_loan(pub), \"3\");\n    z_sleep_ms(500);\n\n    tcp_proxy_set_enabled(tcp_proxy, true);\n    z_sleep_s(1);\n\n    put_str(z_loan(pub), \"4\");\n    z_sleep_ms(500);\n\n    if (!background) {\n        ze_undeclare_sample_miss_listener(ze_sample_miss_listener_move(&miss_listener));\n    } else {\n        ze_undeclare_advanced_subscriber(ze_advanced_subscriber_move(&sub));\n    }\n    assert(arg.dropped == true);\n    assert(arg.called == true);\n\n    z_fifo_handler_sample_drop(z_fifo_handler_sample_move(&handler));\n    if (!background) {\n        ze_advanced_subscriber_drop(ze_advanced_subscriber_move(&sub));\n    }\n    ze_advanced_publisher_drop(ze_advanced_publisher_move(&pub));\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n\n    tcp_proxy_stop(tcp_proxy);\n    tcp_proxy_destroy(tcp_proxy);\n}\n#endif\n#endif\n\n#if Z_FEATURE_MATCHING == 1\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct sub_thread_arg_t {\n    z_owned_session_t* session;\n    z_view_keyexpr_t* ke;\n    z_owned_subscriber_t* sub;\n    z_owned_closure_sample_t* closure;\n    z_owned_fifo_handler_sample_t* handler;\n} sub_thread_arg_t;\n\nvoid* declare_sub_from_another_thread(void* targ) {\n    sub_thread_arg_t* arg = (sub_thread_arg_t*)targ;\n    z_owned_closure_sample_t sample_closure;\n    z_owned_fifo_handler_sample_t sample_handler;\n    assert(z_fifo_channel_sample_new(&sample_closure, &sample_handler, 3) == Z_OK);\n    assert(z_declare_subscriber(z_session_loan(arg->session), arg->sub, z_view_keyexpr_loan(arg->ke),\n                                z_closure_sample_move(&sample_closure), NULL) == Z_OK);\n    *(arg->handler) = sample_handler;\n    return NULL;\n}\n#endif\nDECLARE_ON_RECEIVE_HANDLER(z_matching_status_t, const)\nvoid test_matching_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_view_keyexpr_t ke;\n    z_owned_publisher_t pub;\n    z_owned_subscriber_t sub;\n    z_owned_matching_listener_t listener;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n\n    printf(\"Test: Matching callback drop on undeclare: background = %d\\n\", background);\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/matching_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/matching_callback_drop\") == Z_OK);\n    }\n\n    assert(z_declare_publisher(z_session_loan(&session1), &pub, z_view_keyexpr_loan(&ke), NULL) == Z_OK);\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n    z_owned_closure_matching_status_t closure;\n    z_closure_matching_status(&closure, on_receive_z_matching_status_t_handler, on_drop_z_matching_status_t_handler,\n                              (void*)&arg);\n    if (!background) {\n        assert(z_publisher_declare_matching_listener(z_publisher_loan(&pub), &listener,\n                                                     z_closure_matching_status_move(&closure)) == Z_OK);\n    } else {\n        assert(z_publisher_declare_background_matching_listener(z_publisher_loan(&pub),\n                                                                z_closure_matching_status_move(&closure)) == Z_OK);\n    }\n    z_sleep_s(1);\n    z_owned_closure_sample_t sample_closure;\n    z_owned_fifo_handler_sample_t sample_handler;\n    assert(z_fifo_channel_sample_new(&sample_closure, &sample_handler, 3) == Z_OK);\n    assert(z_declare_subscriber(z_session_loan(&session2), &sub, z_view_keyexpr_loan(&ke),\n                                z_closure_sample_move(&sample_closure), NULL) == Z_OK);\n    z_sleep_s(1);\n\n    if (!background) {\n        z_matching_listener_drop(z_matching_listener_move(&listener));\n    } else {\n        z_publisher_drop(z_publisher_move(&pub));\n    }\n    assert(arg.dropped == true);\n    assert(arg.called == true);\n    z_publisher_drop(z_publisher_move(&pub));\n    z_session_drop(z_session_move(&session1));\n    z_subscriber_drop(z_subscriber_move(&sub));\n    z_fifo_handler_sample_drop(z_fifo_handler_sample_move(&sample_handler));\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1 && Z_FEATURE_MULTI_THREAD == 1\n    printf(\"Test: Local Matching callback drop on undeclare: background = %d\\n\", background);\n\n    assert(z_declare_publisher(z_session_loan(&session2), &pub, z_view_keyexpr_loan(&ke), NULL) == Z_OK);\n    arg.called = false;\n    arg.dropped = false;\n    z_closure_matching_status(&closure, on_receive_z_matching_status_t_handler, on_drop_z_matching_status_t_handler,\n                              (void*)&arg);\n    if (!background) {\n        assert(z_publisher_declare_matching_listener(z_publisher_loan(&pub), &listener,\n                                                     z_closure_matching_status_move(&closure)) == Z_OK);\n    } else {\n        assert(z_publisher_declare_background_matching_listener(z_publisher_loan(&pub),\n                                                                z_closure_matching_status_move(&closure)) == Z_OK);\n    }\n\n    // Declare subscriber from another thread to avoid blocking on the matching callback\n    sub_thread_arg_t sub_thread_arg = {\n        .session = &session2,\n        .ke = &ke,\n        .sub = &sub,\n        .closure = NULL,\n        .handler = &sample_handler,\n    };\n    z_owned_task_t task;\n    z_task_init(&task, NULL, declare_sub_from_another_thread, &sub_thread_arg);\n    z_sleep_s(1);\n\n    if (!background) {\n        z_matching_listener_drop(z_matching_listener_move(&listener));\n    } else {\n        z_publisher_drop(z_publisher_move(&pub));\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    z_task_join(z_task_move(&task));\n    z_publisher_drop(z_publisher_move(&pub));\n    z_subscriber_drop(z_subscriber_move(&sub));\n    z_fifo_handler_sample_drop(z_fifo_handler_sample_move(&sample_handler));\n#endif\n    z_session_drop(z_session_move(&session2));\n}\n#endif\n#endif\n\n#if Z_FEATURE_QUERYABLE == 1 && Z_FEATURE_QUERY == 1\n#if Z_FEATURE_MULTI_THREAD == 1\nvoid* get_from_another_thread(void* targ) {\n    thread_arg_t* arg = (thread_arg_t*)targ;\n    z_owned_closure_reply_t callback_reply;\n    z_owned_fifo_handler_reply_t fifo_reply;\n    assert(z_fifo_channel_reply_new(&callback_reply, &fifo_reply, 3) == Z_OK);\n    assert(z_get(z_session_loan(arg->session), z_view_keyexpr_loan(arg->ke), \"\", z_closure_reply_move(&callback_reply),\n                 NULL) == Z_OK);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&fifo_reply));\n    return NULL;\n}\n#endif\nDECLARE_ON_RECEIVE_HANDLER(z_loaned_query_t, _ZP_NOTHING)\nvoid test_queryable_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_owned_queryable_t queryable;\n    z_view_keyexpr_t ke;\n    z_owned_closure_query_t closure;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/queryable_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/queryable_callback_drop\") == Z_OK);\n    }\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Queryable callback drop on undeclare: background = %d\\n\", background);\n    z_closure_query(&closure, on_receive_z_loaned_query_t_handler, on_drop_z_loaned_query_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_declare_queryable(z_session_loan(&session1), &queryable, z_view_keyexpr_loan(&ke),\n                                   z_closure_query_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(z_declare_background_queryable(z_session_loan(&session1), z_view_keyexpr_loan(&ke),\n                                              z_closure_query_move(&closure), NULL) == Z_OK);\n    }\n    z_sleep_s(2);\n\n    z_owned_closure_reply_t callback_reply;\n    z_owned_fifo_handler_reply_t fifo_reply;\n    assert(z_fifo_channel_reply_new(&callback_reply, &fifo_reply, 3) == Z_OK);\n    assert(z_get(z_session_loan(&session2), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&callback_reply),\n                 NULL) == Z_OK);\n    z_sleep_s(1);\n    if (!background) {\n        z_undeclare_queryable(z_queryable_move(&queryable));\n    } else {\n        z_close(z_session_loan_mut(&session1), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n\n#if Z_FEATURE_LOCAL_QUERYABLE == 1 && Z_FEATURE_MULTI_THREAD == 1\n    printf(\"Test: Local Queryable callback drop on undeclare, background = %d\\n\", background);\n    arg.called = false;\n    arg.dropped = false;\n    z_closure_query(&closure, on_receive_z_loaned_query_t_handler, on_drop_z_loaned_query_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_declare_queryable(z_session_loan(&session2), &queryable, z_view_keyexpr_loan(&ke),\n                                   z_closure_query_move(&closure), NULL) == Z_OK);\n    } else {\n        assert(z_declare_background_queryable(z_session_loan(&session2), z_view_keyexpr_loan(&ke),\n                                              z_closure_query_move(&closure), NULL) == Z_OK);\n    }\n    thread_arg_t thread_arg = {\n        .session = &session2,\n        .ke = &ke,\n    };\n    z_owned_task_t task;\n    z_task_init(&task, NULL, get_from_another_thread, &thread_arg);\n    z_sleep_s(1);\n    if (!background) {\n        z_undeclare_queryable(z_queryable_move(&queryable));\n    } else {\n        z_close(z_session_loan_mut(&session2), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    z_task_join(z_task_move(&task));\n#endif\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&fifo_reply));\n}\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct query_thread_arg_t {\n    z_owned_fifo_handler_query_t* receiver;\n    z_view_keyexpr_t* ke;\n} query_thread_arg_t;\n\nvoid* reply_from_another_thread(void* targ) {\n    query_thread_arg_t* arg = (query_thread_arg_t*)targ;\n    z_owned_query_t query;\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(arg->receiver), &query) == Z_OK);\n\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, \"payload\");\n    z_query_reply(z_query_loan(&query), z_view_keyexpr_loan(arg->ke), z_bytes_move(&payload), NULL);\n    z_query_drop(z_query_move(&query));\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(arg->receiver));\n    return NULL;\n}\n#endif\n\nDECLARE_ON_RECEIVE_HANDLER(z_loaned_reply_t, _ZP_NOTHING)\nvoid test_querier_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1, session2;\n    z_owned_queryable_t queryable;\n    z_owned_querier_t querier;\n    z_view_keyexpr_t ke;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n\n    if (!background) {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/querier_callback_drop\") == Z_OK);\n    } else {\n        assert(z_view_keyexpr_from_str(&ke, \"test/undeclare_background/querier_callback_drop\") == Z_OK);\n    }\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Querier callback drop on undeclare: background = %d\\n\", background);\n    z_owned_closure_query_t query_closure;\n    z_owned_fifo_handler_query_t query_handler;\n    z_fifo_channel_query_new(&query_closure, &query_handler, 3);\n    assert(z_declare_queryable(z_session_loan(&session2), &queryable, z_view_keyexpr_loan(&ke),\n                               z_closure_query_move(&query_closure), NULL) == Z_OK);\n\n    z_owned_closure_reply_t reply_closure;\n    z_closure_reply(&reply_closure, on_receive_z_loaned_reply_t_handler, on_drop_z_loaned_reply_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_declare_querier(z_session_loan(&session1), &querier, z_view_keyexpr_loan(&ke), NULL) == Z_OK);\n        z_sleep_s(2);\n        assert(z_querier_get(z_querier_loan(&querier), \"\", z_closure_reply_move(&reply_closure), NULL) == Z_OK);\n    } else {\n        z_sleep_s(2);\n        assert(z_get(z_session_loan(&session1), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_closure),\n                     NULL) == Z_OK);\n    }\n\n    z_owned_query_t query;\n    z_sleep_s(1);\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &query) == Z_OK);\n    z_owned_bytes_t payload;\n    z_bytes_from_static_str(&payload, \"payload\");\n    assert(z_query_reply(z_query_loan(&query), z_view_keyexpr_loan(&ke), z_bytes_move(&payload), NULL) == Z_OK);\n    z_query_drop(z_query_move(&query));\n    z_sleep_s(1);\n\n    if (!background) {\n        z_undeclare_querier(z_querier_move(&querier));\n    } else {\n        z_close(z_session_loan_mut(&session1), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    z_undeclare_queryable(z_queryable_move(&queryable));\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler));\n\n#if Z_FEATURE_LOCAL_QUERYABLE == 1 && Z_FEATURE_MULTI_THREAD == 1\n    printf(\"Test: Local Querier callback drop on undeclare: background = %d\\n\", background);\n    arg.called = false;\n    arg.dropped = false;\n    z_fifo_channel_query_new(&query_closure, &query_handler, 3);\n    assert(z_declare_queryable(z_session_loan(&session2), &queryable, z_view_keyexpr_loan(&ke),\n                               z_closure_query_move(&query_closure), NULL) == Z_OK);\n    z_closure_reply(&reply_closure, on_receive_z_loaned_reply_t_handler, on_drop_z_loaned_reply_t_handler, (void*)&arg);\n    if (!background) {\n        assert(z_declare_querier(z_session_loan(&session2), &querier, z_view_keyexpr_loan(&ke), NULL) == Z_OK);\n        assert(z_querier_get(z_querier_loan(&querier), \"\", z_closure_reply_move(&reply_closure), NULL) == Z_OK);\n    } else {\n        assert(z_get(z_session_loan(&session2), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_closure),\n                     NULL) == Z_OK);\n    }\n\n    query_thread_arg_t thread_arg = {\n        .receiver = &query_handler,\n        .ke = &ke,\n    };\n    z_owned_task_t task;\n    z_task_init(&task, NULL, reply_from_another_thread, &thread_arg);\n    z_sleep_s(1);\n    if (!background) {\n        z_undeclare_querier(z_querier_move(&querier));\n    } else {\n        z_close(z_session_loan_mut(&session2), NULL);\n    }\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n    z_task_join(z_task_move(&task));\n    z_undeclare_queryable(z_queryable_move(&queryable));\n#endif\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n}\n\n#if Z_FEATURE_LIVELINESS == 1\nvoid test_liveliness_get_callback_drop_on_undeclare(void) {\n    z_owned_session_t session1, session2;\n    z_view_keyexpr_t ke;\n    z_owned_closure_reply_t closure;\n\n    assert(open_session(&session1) == Z_OK);\n    assert(open_session(&session2) == Z_OK);\n    assert(z_view_keyexpr_from_str(&ke, \"test/undeclare/liveliness_get_callback_drop\") == Z_OK);\n\n    callback_arg_t arg;\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Liveliness Get callback drop on undeclare\\n\");\n    z_closure_reply(&closure, on_receive_z_loaned_reply_t_handler, on_drop_z_loaned_reply_t_handler, (void*)&arg);\n    z_owned_liveliness_token_t token;\n    assert(z_liveliness_declare_token(z_session_loan(&session2), &token, z_view_keyexpr_loan(&ke), NULL) == Z_OK);\n    z_sleep_s(1);\n    assert(z_liveliness_get(z_session_loan(&session1), z_view_keyexpr_loan(&ke), z_closure_reply_move(&closure),\n                            NULL) == Z_OK);\n    z_sleep_s(1);\n    z_close(z_session_loan_mut(&session1), NULL);\n\n    assert(arg.called == true);\n    assert(arg.dropped == true);\n\n    z_liveliness_token_drop(z_liveliness_token_move(&token));\n    z_session_drop(z_session_move(&session1));\n    z_session_drop(z_session_move(&session2));\n}\n#endif\n\n#endif\n\nvoid test_no_declare_after_session_close(void) {\n#if Z_FEATURE_SUBSCRIPTION == 1\n    {\n        printf(\"Test: No subscriber can be declared after session close\\n\");\n        z_owned_session_t session;\n        z_owned_subscriber_t subscriber;\n        z_view_keyexpr_t ke;\n        z_owned_closure_sample_t closure;\n\n        callback_arg_t arg;\n        arg.called = false;\n        arg.dropped = false;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/subscriber\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n\n        z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler,\n                         (void*)&arg);\n        assert(z_declare_subscriber(z_session_loan(&session), &subscriber, z_view_keyexpr_loan(&ke),\n                                    z_closure_sample_move(&closure), NULL) == _Z_ERR_SESSION_CLOSED);\n        assert(arg.called == false);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n\n#if Z_FEATURE_QUERYABLE == 1\n    {\n        printf(\"Test: No queryable can be declared after session close\\n\");\n        z_owned_session_t session;\n        z_owned_queryable_t queryable;\n        z_view_keyexpr_t ke;\n        z_owned_closure_query_t closure;\n\n        callback_arg_t arg;\n        arg.called = false;\n        arg.dropped = false;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/queryable\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n\n        z_closure_query(&closure, on_receive_z_loaned_query_t_handler, on_drop_z_loaned_query_t_handler, (void*)&arg);\n        assert(z_declare_queryable(z_session_loan(&session), &queryable, z_view_keyexpr_loan(&ke),\n                                   z_closure_query_move(&closure), NULL) == _Z_ERR_SESSION_CLOSED);\n        assert(arg.called == false);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n\n#if Z_FEATURE_LIVELINESS == 1\n#if Z_FEATURE_SUBSCRIPTION == 1\n    {\n        printf(\"Test: No liveliness subscriber can be declared after session close\\n\");\n        z_owned_session_t session;\n        z_owned_subscriber_t subscriber;\n        z_view_keyexpr_t ke;\n        z_owned_closure_sample_t closure;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/liveliness_subscriber\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n\n        callback_arg_t arg;\n        arg.called = false;\n        arg.dropped = false;\n\n        z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler,\n                         (void*)&arg);\n        assert(z_liveliness_declare_subscriber(z_session_loan(&session), &subscriber, z_view_keyexpr_loan(&ke),\n                                               z_closure_sample_move(&closure), NULL) == _Z_ERR_SESSION_CLOSED);\n        assert(arg.called == false);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n\n#if Z_FEATURE_QUERY == 1\n    {\n        printf(\"Test: No z_liveliness_get can be issued after session close\\n\");\n        z_owned_session_t session;\n        z_view_keyexpr_t ke;\n        z_owned_closure_reply_t closure;\n\n        callback_arg_t arg;\n        arg.called = false;\n        arg.dropped = false;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/liveliness_get\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n\n        z_closure_reply(&closure, on_receive_z_loaned_reply_t_handler, on_drop_z_loaned_reply_t_handler, (void*)&arg);\n        assert(z_liveliness_get(z_session_loan(&session), z_view_keyexpr_loan(&ke), z_closure_reply_move(&closure),\n                                NULL) == _Z_ERR_SESSION_CLOSED);\n        assert(arg.called == false);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n\n    {\n        printf(\"Test: No liveliness token can be declared after session close\\n\");\n        z_owned_session_t session;\n        z_owned_liveliness_token_t token;\n        z_view_keyexpr_t ke;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/liveliness_token\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n\n        assert(z_liveliness_declare_token(z_session_loan(&session), &token, z_view_keyexpr_loan(&ke), NULL) ==\n               _Z_ERR_SESSION_CLOSED);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n\n#if Z_FEATURE_QUERY == 1\n    {\n        printf(\"Test: No z_get can be issued after session close\\n\");\n        z_owned_session_t session;\n        z_view_keyexpr_t ke;\n        z_owned_closure_reply_t closure;\n\n        callback_arg_t arg;\n        arg.called = false;\n        arg.dropped = false;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/get\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n\n        z_closure_reply(&closure, on_receive_z_loaned_reply_t_handler, on_drop_z_loaned_reply_t_handler, (void*)&arg);\n        assert(z_get(z_session_loan(&session), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&closure), NULL) ==\n               _Z_ERR_SESSION_CLOSED);\n        assert(arg.called == false);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n\n#if Z_FEATURE_ADVANCED_SUBSCRIPTION == 1\n    {\n        printf(\"Test: No advanced subscriber can be declared after session close\\n\");\n        z_owned_session_t session;\n        ze_owned_advanced_subscriber_t subscriber;\n        z_view_keyexpr_t ke;\n        z_owned_closure_sample_t closure;\n\n        callback_arg_t arg;\n        arg.called = false;\n        arg.dropped = false;\n\n        assert(open_session(&session) == Z_OK);\n        assert(z_view_keyexpr_from_str(&ke, \"test/closed/advanced_subscriber\") == Z_OK);\n        z_close(z_session_loan_mut(&session), NULL);\n        z_closure_sample(&closure, on_receive_z_loaned_sample_t_handler, on_drop_z_loaned_sample_t_handler,\n                         (void*)&arg);\n        assert(ze_declare_advanced_subscriber(z_session_loan(&session), &subscriber, z_view_keyexpr_loan(&ke),\n                                              z_closure_sample_move(&closure), NULL) == _Z_ERR_SESSION_CLOSED);\n        assert(arg.called == false);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session));\n    }\n#endif\n}\n#if Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_UNICAST_TRANSPORT == 1 && Z_FEATURE_MULTI_THREAD == 1\nDECLARE_ON_RECEIVE_HANDLER(z_loaned_transport_event_t, _ZP_NOTHING)\nvoid test_transport_events_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1;\n    callback_arg_t arg;\n    z_owned_closure_transport_event_t callback;\n    z_transport_events_listener_options_t options;\n\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Transport events callback drop on undeclare: background = %d\\n\", background);\n    assert(open_session(&session1) == Z_OK);\n    z_closure_transport_event(&callback, on_receive_z_loaned_transport_event_t_handler,\n                              on_drop_z_loaned_transport_event_t_handler, (void*)&arg);\n    z_transport_events_listener_options_default(&options);\n    options.history = true;\n\n    if (!background) {\n        z_owned_transport_events_listener_t listener;\n        assert(z_declare_transport_events_listener(z_session_loan(&session1), &listener,\n                                                   z_closure_transport_event_move(&callback), &options) == Z_OK);\n        assert(z_undeclare_transport_events_listener(z_transport_events_listener_move(&listener)) == Z_OK);\n        assert(arg.called == true);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session1));\n    } else {\n        assert(z_declare_background_transport_events_listener(\n                   z_session_loan(&session1), z_closure_transport_event_move(&callback), &options) == Z_OK);\n        assert(z_close(z_session_loan_mut(&session1), NULL) == Z_OK);\n        assert(arg.called == true);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session1));\n    }\n}\n\nDECLARE_ON_RECEIVE_HANDLER(z_loaned_link_event_t, _ZP_NOTHING)\nvoid test_link_events_callback_drop_on_undeclare(bool background) {\n    z_owned_session_t session1;\n    callback_arg_t arg;\n    z_owned_closure_link_event_t callback;\n    z_link_events_listener_options_t options;\n\n    arg.called = false;\n    arg.dropped = false;\n\n    printf(\"Test: Link events callback drop on undeclare: background = %d\\n\", background);\n    assert(open_session(&session1) == Z_OK);\n    z_closure_link_event(&callback, on_receive_z_loaned_link_event_t_handler, on_drop_z_loaned_link_event_t_handler,\n                         (void*)&arg);\n    z_link_events_listener_options_default(&options);\n    options.history = true;\n\n    if (!background) {\n        z_owned_link_events_listener_t listener;\n        assert(z_declare_link_events_listener(z_session_loan(&session1), &listener,\n                                              z_closure_link_event_move(&callback), &options) == Z_OK);\n        assert(z_undeclare_link_events_listener(z_link_events_listener_move(&listener)) == Z_OK);\n        assert(arg.called == true);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session1));\n    } else {\n        assert(z_declare_background_link_events_listener(z_session_loan(&session1),\n                                                         z_closure_link_event_move(&callback), &options) == Z_OK);\n        assert(z_close(z_session_loan_mut(&session1), NULL) == Z_OK);\n        assert(arg.called == true);\n        assert(arg.dropped == true);\n        z_session_drop(z_session_move(&session1));\n    }\n}\n#endif\nint main(void) {\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\n    test_subscriber_callback_drop_on_undeclare(false);\n    test_subscriber_callback_drop_on_undeclare(true);\n#if Z_FEATURE_MATCHING == 1\n    test_matching_callback_drop_on_undeclare(false);\n    test_matching_callback_drop_on_undeclare(true);\n#endif\n#if Z_FEATURE_LIVELINESS == 1\n    test_liveliness_subscriber_callback_drop_on_undeclare(false);\n    test_liveliness_subscriber_callback_drop_on_undeclare(true);\n#endif\n#endif\n#if Z_FEATURE_QUERYABLE == 1 && Z_FEATURE_QUERY == 1\n    test_queryable_callback_drop_on_undeclare(false);\n    test_queryable_callback_drop_on_undeclare(true);\n    test_querier_callback_drop_on_undeclare(false);\n    test_querier_callback_drop_on_undeclare(true);\n#if Z_FEATURE_LIVELINESS == 1\n    test_liveliness_get_callback_drop_on_undeclare();\n#endif\n#endif\n#if Z_FEATURE_ADVANCED_SUBSCRIPTION == 1 && Z_FEATURE_ADVANCED_PUBLICATION == 1\n    test_advanced_subscriber_callback_drop_on_undeclare(false);\n    test_advanced_subscriber_callback_drop_on_undeclare(true);\n    test_advanced_subscriber_late_join_callback_drop_on_undeclare(false);\n    test_advanced_subscriber_late_join_callback_drop_on_undeclare(true);\n#if Z_ADVANCED_PUBSUB_TEST_USE_TCP_PROXY == 1\n    test_advanced_sample_miss_callback_drop_on_undeclare(false);\n    test_advanced_sample_miss_callback_drop_on_undeclare(true);\n#endif\n#endif\n#if Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_UNICAST_TRANSPORT == 1 && Z_FEATURE_MULTI_THREAD == 1\n    test_transport_events_callback_drop_on_undeclare(false);\n    test_transport_events_callback_drop_on_undeclare(true);\n    test_link_events_callback_drop_on_undeclare(false);\n    test_link_events_callback_drop_on_undeclare(true);\n#endif\n    test_no_declare_after_session_close();\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_api_cancellation_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1 && defined(Z_FEATURE_UNSTABLE_API)\n\nvoid on_reply(z_loaned_reply_t* reply, void* arg) {\n    uint32_t* t = (uint32_t*)arg;\n    z_sleep_s(3);\n    (*t) += 1;\n    _ZP_UNUSED(reply);\n}\n\nvoid on_drop(void* arg) {\n    uint32_t* t = (uint32_t*)arg;\n    z_sleep_s(3);\n    (*t) += 2;\n}\n\nvoid test_cancel_get(void) {\n    printf(\"test_cancel_get\\n\");\n    const char* query_expr = \"zenoh-pico/query/cancellation/test\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, query_expr);\n\n    assert(z_open(&s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(&s2, z_config_move(&c2), NULL) == Z_OK);\n\n    z_owned_queryable_t queryable;\n    z_owned_closure_query_t query_callback;\n    z_owned_fifo_handler_query_t query_handler;\n    z_fifo_channel_query_new(&query_callback, &query_handler, 16);\n    z_declare_queryable(z_session_loan(&s1), &queryable, z_view_keyexpr_loan(&ke),\n                        z_closure_query_move(&query_callback), NULL);\n    z_sleep_s(2);\n\n    z_owned_closure_reply_t reply_callback;\n    z_owned_fifo_handler_reply_t reply_handler;\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n\n    printf(\"Check cancel removes callback\\n\");\n    z_owned_cancellation_token_t ct, ct_clone;\n    assert(z_cancellation_token_new(&ct) == Z_OK);\n    assert(!z_cancellation_token_is_cancelled(z_cancellation_token_loan(&ct)));\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    z_get(z_session_loan(&s2), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_callback), &opts);\n    z_sleep_s(1);\n    assert(z_cancellation_token_cancel(z_cancellation_token_loan_mut(&ct)) == Z_OK);\n    assert(z_cancellation_token_is_cancelled(z_cancellation_token_loan(&ct)));\n    z_cancellation_token_drop(z_cancellation_token_move(&ct));\n\n    z_owned_reply_t reply;\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler), &reply) == Z_CHANNEL_DISCONNECTED);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n\n    z_owned_query_t q;\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q) == Z_OK);\n    z_query_drop(z_query_move(&q));\n    z_sleep_s(1);\n\n    printf(\"Check cancel blocks until callback is finished\\n\");\n    uint32_t t = 0;\n    assert(z_cancellation_token_new(&ct) == Z_OK);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    z_closure_reply(&reply_callback, on_reply, on_drop, (void*)&t);\n\n    z_get(z_session_loan(&s2), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_callback), &opts);\n    z_sleep_s(1);\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q) == Z_OK);\n\n    z_owned_bytes_t b;\n    z_bytes_from_static_str(&b, \"ok\");\n    z_query_reply(z_query_loan(&q), z_query_keyexpr(z_query_loan(&q)), z_bytes_move(&b), NULL);\n    z_query_drop(z_query_move(&q));\n    z_sleep_s(1);\n    assert(z_cancellation_token_cancel(z_cancellation_token_loan_mut(&ct)) == Z_OK);\n    assert(t == 3);\n\n    printf(\"Check cancelled token does not send a query\\n\");\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    assert(z_get(z_session_loan(&s2), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_callback), &opts) ==\n           Z_ERR_CANCELLED);\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler), &reply) == Z_CHANNEL_DISCONNECTED);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n\n    z_sleep_s(1);\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q) == Z_CHANNEL_NODATA);\n\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler));\n\n    z_cancellation_token_drop(z_cancellation_token_move(&ct));\n    z_queryable_drop(z_queryable_move(&queryable));\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nvoid test_cancel_querier_get(void) {\n    printf(\"test_cancel_querier_get\\n\");\n    const char* query_expr = \"zenoh-pico/querier/cancellation/test\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, query_expr);\n\n    assert(z_open(&s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(&s2, z_config_move(&c2), NULL) == Z_OK);\n\n    z_owned_queryable_t queryable;\n    z_owned_closure_query_t query_callback;\n    z_owned_fifo_handler_query_t query_handler;\n    z_fifo_channel_query_new(&query_callback, &query_handler, 16);\n    z_declare_queryable(z_session_loan(&s1), &queryable, z_view_keyexpr_loan(&ke),\n                        z_closure_query_move(&query_callback), NULL);\n\n    z_owned_querier_t querier;\n    z_declare_querier(z_session_loan(&s2), &querier, z_view_keyexpr_loan(&ke), NULL);\n    z_sleep_s(2);\n\n    z_owned_closure_reply_t reply_callback;\n    z_owned_fifo_handler_reply_t reply_handler;\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n\n    printf(\"Check cancel removes callback\\n\");\n    z_owned_cancellation_token_t ct, ct_clone;\n    assert(z_cancellation_token_new(&ct) == Z_OK);\n    assert(!z_cancellation_token_is_cancelled(z_cancellation_token_loan(&ct)));\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_querier_get_options_t opts;\n    z_querier_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    z_querier_get(z_querier_loan(&querier), \"\", z_closure_reply_move(&reply_callback), &opts);\n    z_sleep_s(1);\n\n    assert(z_cancellation_token_cancel(z_cancellation_token_loan_mut(&ct)) == Z_OK);\n    assert(z_cancellation_token_is_cancelled(z_cancellation_token_loan(&ct)));\n    z_cancellation_token_drop(z_cancellation_token_move(&ct));\n\n    z_owned_reply_t reply;\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler), &reply) == Z_CHANNEL_DISCONNECTED);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n\n    z_owned_query_t q;\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q) == Z_OK);\n    z_query_drop(z_query_move(&q));\n    z_sleep_s(1);\n\n    printf(\"Check cancel blocks until callback is finished\\n\");\n    uint32_t t = 0;\n    assert(z_cancellation_token_new(&ct) == Z_OK);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_querier_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    z_closure_reply(&reply_callback, on_reply, on_drop, (void*)&t);\n\n    z_querier_get(z_querier_loan(&querier), \"\", z_closure_reply_move(&reply_callback), &opts);\n    z_sleep_s(1);\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q) == Z_OK);\n\n    z_owned_bytes_t b;\n    z_bytes_from_static_str(&b, \"ok\");\n    z_query_reply(z_query_loan(&q), z_query_keyexpr(z_query_loan(&q)), z_bytes_move(&b), NULL);\n    z_query_drop(z_query_move(&q));\n    z_sleep_s(1);\n    assert(z_cancellation_token_cancel(z_cancellation_token_loan_mut(&ct)) == Z_OK);\n    assert(t == 3);\n\n    printf(\"Check cancelled token does not send a query\\n\");\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_querier_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    assert(z_querier_get(z_querier_loan(&querier), \"\", z_closure_reply_move(&reply_callback), &opts) ==\n           Z_ERR_CANCELLED);\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler), &reply) == Z_CHANNEL_DISCONNECTED);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n\n    z_sleep_s(1);\n    assert(z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q) == Z_CHANNEL_NODATA);\n\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler));\n\n    z_cancellation_token_drop(z_cancellation_token_move(&ct));\n    z_queryable_drop(z_queryable_move(&queryable));\n    z_querier_drop(z_querier_move(&querier));\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nvoid test_cancel_does_not_prevent_session_close_on_drop(void) {\n    printf(\"test_cancel_does_not_prevent_session_close_on_drop\\n\");\n    const char* query_expr = \"zenoh-pico/cancellation_does_not_prevent_session_close_on_drop\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, query_expr);\n\n    assert(z_open(&s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(&s2, z_config_move(&c2), NULL) == Z_OK);\n\n    z_owned_queryable_t queryable;\n    z_owned_closure_query_t query_callback;\n    z_owned_fifo_handler_query_t query_handler;\n    z_fifo_channel_query_new(&query_callback, &query_handler, 16);\n    z_declare_queryable(z_session_loan(&s1), &queryable, z_view_keyexpr_loan(&ke),\n                        z_closure_query_move(&query_callback), NULL);\n\n    z_owned_querier_t querier;\n    z_declare_querier(z_session_loan(&s2), &querier, z_view_keyexpr_loan(&ke), NULL);\n    z_sleep_s(2);\n\n    z_owned_closure_reply_t reply_callback, reply_callback2;\n    z_owned_fifo_handler_reply_t reply_handler, reply_handler2;\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n    z_fifo_channel_reply_new(&reply_callback2, &reply_handler2, 16);\n\n    z_owned_cancellation_token_t ct, ct_clone, ct_clone2;\n    assert(z_cancellation_token_new(&ct) == Z_OK);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    assert(z_cancellation_token_clone(&ct_clone2, z_cancellation_token_loan(&ct)) == Z_OK);\n\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    z_get(z_session_loan(&s2), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_callback), &opts);\n\n    z_querier_get_options_t opts2;\n    z_querier_get_options_default(&opts2);\n    opts2.cancellation_token = z_cancellation_token_move(&ct_clone2);\n    z_querier_get(z_querier_loan(&querier), \"\", z_closure_reply_move(&reply_callback2), &opts2);\n\n    z_session_drop(z_session_move(&s2));\n    z_owned_reply_t reply;\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler), &reply) == Z_CHANNEL_DISCONNECTED);\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler2), &reply) == Z_CHANNEL_DISCONNECTED);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler2));\n\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler));\n\n    z_cancellation_token_drop(z_cancellation_token_move(&ct));\n    z_queryable_drop(z_queryable_move(&queryable));\n    z_querier_drop(z_querier_move(&querier));\n    z_session_drop(z_session_move(&s1));\n}\n\n#if Z_FEATURE_LIVELINESS == 1\nvoid test_liveliness_get(void) {\n    printf(\"test_cancel_liveliness_get\\n\");\n    const char* query_expr = \"zenoh-pico/liveliness_query/cancellation/test\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, query_expr);\n\n    assert(z_open(&s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(&s2, z_config_move(&c2), NULL) == Z_OK);\n\n    z_owned_liveliness_token_t token;\n    z_liveliness_declare_token(z_session_loan(&s1), &token, z_view_keyexpr_loan(&ke), NULL);\n    z_sleep_s(2);\n\n    z_owned_closure_reply_t reply_callback;\n\n    printf(\"Check cancel blocks until callback is finished\\n\");\n    z_owned_cancellation_token_t ct, ct_clone;\n    uint32_t t = 0;\n    assert(z_cancellation_token_new(&ct) == Z_OK);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_liveliness_get_options_t opts;\n    z_liveliness_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    z_closure_reply(&reply_callback, on_reply, on_drop, (void*)&t);\n    z_liveliness_get(z_session_loan(&s2), z_view_keyexpr_loan(&ke), z_closure_reply_move(&reply_callback), &opts);\n    z_sleep_s(1);\n    assert(z_cancellation_token_cancel(z_cancellation_token_loan_mut(&ct)) == Z_OK);\n    assert(t == 3);\n\n    printf(\"Check cancelled token does not send a query\\n\");\n    z_owned_fifo_handler_reply_t reply_handler;\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n    assert(z_cancellation_token_clone(&ct_clone, z_cancellation_token_loan(&ct)) == Z_OK);\n    z_liveliness_get_options_default(&opts);\n    opts.cancellation_token = z_cancellation_token_move(&ct_clone);\n    assert(z_liveliness_get(z_session_loan(&s2), z_view_keyexpr_loan(&ke), z_closure_reply_move(&reply_callback),\n                            &opts) == Z_ERR_CANCELLED);\n    z_owned_reply_t reply;\n    assert(z_fifo_handler_reply_try_recv(z_fifo_handler_reply_loan(&reply_handler), &reply) == Z_CHANNEL_DISCONNECTED);\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n    z_cancellation_token_drop(z_cancellation_token_move(&ct));\n    z_liveliness_token_drop(z_liveliness_token_move(&token));\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n#endif\n\n#endif\n\nint main(void) {\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1 && defined(Z_FEATURE_UNSTABLE_API)\n    test_cancel_get();\n    test_cancel_querier_get();\n    test_cancel_does_not_prevent_session_close_on_drop();\n#if Z_FEATURE_LIVELINESS == 1\n    test_liveliness_get();\n#endif\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_api_connectivity_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdatomic.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#if defined(Z_FEATURE_UNSTABLE_API) && Z_FEATURE_CONNECTIVITY == 1 && Z_FEATURE_UNICAST_TRANSPORT == 1 && \\\n    Z_FEATURE_LINK_TCP == 1 && Z_FEATURE_MULTI_THREAD == 1\n\n#undef NDEBUG\n#include <assert.h>\n\n#define assert_ok(x)                            \\\n    {                                           \\\n        int ret = (int)x;                       \\\n        if (ret != Z_OK) {                      \\\n            printf(\"%s failed: %d\\n\", #x, ret); \\\n            assert(false);                      \\\n        }                                       \\\n    }\n\ntypedef struct events_ctx_t {\n    atomic_uint transport_put;\n    atomic_uint transport_delete;\n    atomic_uint link_put;\n    atomic_uint link_delete;\n} events_ctx_t;\n\ntypedef struct transport_events_ctx_t {\n    atomic_uint put;\n    atomic_uint delete_;\n    atomic_bool put_zid_set;\n    atomic_bool delete_zid_set;\n    atomic_bool put_snapshot_set;\n    z_id_t put_zid;\n    z_id_t delete_zid;\n    z_whatami_t put_whatami;\n    bool put_is_qos;\n    bool put_is_multicast;\n    bool put_is_shm;\n} transport_events_ctx_t;\n\ntypedef struct link_events_ctx_t {\n    atomic_uint put;\n    atomic_uint delete_;\n    atomic_bool put_zid_set;\n    atomic_bool delete_zid_set;\n    atomic_bool put_snapshot_set;\n    z_id_t put_zid;\n    z_id_t delete_zid;\n    bool put_src_non_empty;\n    bool put_dst_non_empty;\n    uint16_t put_mtu;\n    bool put_is_streamed;\n    bool put_is_reliable;\n} link_events_ctx_t;\n\ntypedef struct transport_capture_t {\n    z_owned_transport_t transport;\n    unsigned count;\n} transport_capture_t;\n\ntypedef struct transport_info_capture_t {\n    unsigned count;\n    z_id_t first_zid;\n    bool has_first;\n} transport_info_capture_t;\n\ntypedef struct link_info_capture_t {\n    unsigned count;\n    z_id_t first_zid;\n    bool has_first;\n    bool first_src_non_empty;\n    bool first_dst_non_empty;\n} link_info_capture_t;\n\nstatic void events_ctx_reset(events_ctx_t *ctx) {\n    atomic_store_explicit(&ctx->transport_put, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->transport_delete, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->link_put, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->link_delete, 0, memory_order_relaxed);\n}\n\nstatic void transport_events_ctx_reset(transport_events_ctx_t *ctx) {\n    atomic_store_explicit(&ctx->put, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->delete_, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->put_zid_set, false, memory_order_relaxed);\n    atomic_store_explicit(&ctx->delete_zid_set, false, memory_order_relaxed);\n    atomic_store_explicit(&ctx->put_snapshot_set, false, memory_order_relaxed);\n    ctx->put_whatami = Z_WHATAMI_CLIENT;\n    ctx->put_is_qos = false;\n    ctx->put_is_multicast = false;\n    ctx->put_is_shm = false;\n}\n\nstatic void link_events_ctx_reset(link_events_ctx_t *ctx) {\n    atomic_store_explicit(&ctx->put, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->delete_, 0, memory_order_relaxed);\n    atomic_store_explicit(&ctx->put_zid_set, false, memory_order_relaxed);\n    atomic_store_explicit(&ctx->delete_zid_set, false, memory_order_relaxed);\n    atomic_store_explicit(&ctx->put_snapshot_set, false, memory_order_relaxed);\n    ctx->put_src_non_empty = false;\n    ctx->put_dst_non_empty = false;\n    ctx->put_mtu = 0;\n    ctx->put_is_streamed = false;\n    ctx->put_is_reliable = false;\n}\n\nstatic bool wait_counter_at_least(atomic_uint *counter, unsigned expected) {\n    for (unsigned i = 0; i < 50; ++i) {\n        if (atomic_load_explicit(counter, memory_order_acquire) >= expected) {\n            return true;\n        }\n        z_sleep_ms(100);\n    }\n    return false;\n}\n\nstatic void open_listener_session(z_owned_session_t *session, const char *listen_locator) {\n    z_owned_config_t cfg;\n    z_config_default(&cfg);\n    assert_ok(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_MODE_KEY, \"peer\"));\n    assert_ok(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_LISTEN_KEY, listen_locator));\n    assert_ok(z_open(session, z_config_move(&cfg), NULL));\n}\n\nstatic void open_connector_session(z_owned_session_t *session, const char *connect_locator) {\n    z_owned_config_t cfg;\n    z_config_default(&cfg);\n    assert_ok(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_MODE_KEY, \"peer\"));\n    assert_ok(zp_config_insert(z_config_loan_mut(&cfg), Z_CONFIG_CONNECT_KEY, connect_locator));\n    assert_ok(z_open(session, z_config_move(&cfg), NULL));\n}\n\nstatic void close_session_with_tasks(z_owned_session_t *session) { z_session_drop(z_session_move(session)); }\n\nstatic void on_transport_event(z_loaned_transport_event_t *event, void *arg) {\n    transport_events_ctx_t *ctx = (transport_events_ctx_t *)arg;\n    const z_loaned_transport_t *transport = z_transport_event_transport(event);\n    z_id_t zid = z_transport_zid(transport);\n    switch (z_transport_event_kind(event)) {\n        case Z_SAMPLE_KIND_PUT:\n            if (!atomic_load_explicit(&ctx->put_zid_set, memory_order_relaxed)) {\n                ctx->put_zid = zid;\n                atomic_store_explicit(&ctx->put_zid_set, true, memory_order_release);\n            }\n            if (!atomic_load_explicit(&ctx->put_snapshot_set, memory_order_relaxed)) {\n                ctx->put_whatami = z_transport_whatami(transport);\n                ctx->put_is_qos = z_transport_is_qos(transport);\n                ctx->put_is_multicast = z_transport_is_multicast(transport);\n                ctx->put_is_shm = z_transport_is_shm(transport);\n                atomic_store_explicit(&ctx->put_snapshot_set, true, memory_order_release);\n            }\n            atomic_fetch_add_explicit(&ctx->put, 1, memory_order_release);\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            if (!atomic_load_explicit(&ctx->delete_zid_set, memory_order_relaxed)) {\n                ctx->delete_zid = zid;\n                atomic_store_explicit(&ctx->delete_zid_set, true, memory_order_release);\n            }\n            atomic_fetch_add_explicit(&ctx->delete_, 1, memory_order_release);\n            break;\n        default:\n            break;\n    }\n}\n\nstatic void on_link_event(z_loaned_link_event_t *event, void *arg) {\n    link_events_ctx_t *ctx = (link_events_ctx_t *)arg;\n    const z_loaned_link_t *link = z_link_event_link(event);\n    z_id_t zid = z_link_zid(link);\n    switch (z_link_event_kind(event)) {\n        case Z_SAMPLE_KIND_PUT:\n            if (!atomic_load_explicit(&ctx->put_zid_set, memory_order_relaxed)) {\n                ctx->put_zid = zid;\n                atomic_store_explicit(&ctx->put_zid_set, true, memory_order_release);\n            }\n            if (!atomic_load_explicit(&ctx->put_snapshot_set, memory_order_relaxed)) {\n                z_owned_string_t src;\n                z_owned_string_t dst;\n                z_internal_string_null(&src);\n                z_internal_string_null(&dst);\n                assert_ok(z_link_src(link, &src));\n                assert_ok(z_link_dst(link, &dst));\n                ctx->put_src_non_empty = z_string_len(z_loan(src)) > 0;\n                ctx->put_dst_non_empty = z_string_len(z_loan(dst)) > 0;\n                z_string_drop(z_string_move(&src));\n                z_string_drop(z_string_move(&dst));\n                ctx->put_mtu = z_link_mtu(link);\n                ctx->put_is_streamed = z_link_is_streamed(link);\n                ctx->put_is_reliable = z_link_is_reliable(link);\n                atomic_store_explicit(&ctx->put_snapshot_set, true, memory_order_release);\n            }\n            atomic_fetch_add_explicit(&ctx->put, 1, memory_order_release);\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            if (!atomic_load_explicit(&ctx->delete_zid_set, memory_order_relaxed)) {\n                ctx->delete_zid = zid;\n                atomic_store_explicit(&ctx->delete_zid_set, true, memory_order_release);\n            }\n            atomic_fetch_add_explicit(&ctx->delete_, 1, memory_order_release);\n            break;\n        default:\n            break;\n    }\n}\n\nstatic void on_link_event_count_only(z_loaned_link_event_t *event, void *arg) {\n    events_ctx_t *ctx = (events_ctx_t *)arg;\n    switch (z_link_event_kind(event)) {\n        case Z_SAMPLE_KIND_PUT:\n            atomic_fetch_add_explicit(&ctx->link_put, 1, memory_order_relaxed);\n            break;\n        case Z_SAMPLE_KIND_DELETE:\n            atomic_fetch_add_explicit(&ctx->link_delete, 1, memory_order_relaxed);\n            break;\n        default:\n            break;\n    }\n}\n\nstatic void capture_transport(z_loaned_transport_t *transport, void *arg) {\n    transport_capture_t *ctx = (transport_capture_t *)arg;\n    ctx->count++;\n    if (ctx->count == 1) {\n        assert_ok(z_transport_clone(&ctx->transport, transport));\n    }\n}\n\nstatic void capture_transport_info(z_loaned_transport_t *transport, void *arg) {\n    transport_info_capture_t *ctx = (transport_info_capture_t *)arg;\n    ctx->count++;\n    if (!ctx->has_first) {\n        ctx->first_zid = z_transport_zid(transport);\n        ctx->has_first = true;\n    }\n}\n\nstatic void capture_link_info(z_loaned_link_t *link, void *arg) {\n    link_info_capture_t *ctx = (link_info_capture_t *)arg;\n    ctx->count++;\n    if (!ctx->has_first) {\n        z_owned_string_t src;\n        z_owned_string_t dst;\n        z_internal_string_null(&src);\n        z_internal_string_null(&dst);\n        assert_ok(z_link_src(link, &src));\n        assert_ok(z_link_dst(link, &dst));\n\n        ctx->first_zid = z_link_zid(link);\n        ctx->has_first = true;\n        ctx->first_src_non_empty = z_string_len(z_loan(src)) > 0;\n        ctx->first_dst_non_empty = z_string_len(z_loan(dst)) > 0;\n\n        z_string_drop(z_string_move(&src));\n        z_string_drop(z_string_move(&dst));\n    }\n}\n\nstatic unsigned capture_single_transport(const z_loaned_session_t *session, z_owned_transport_t *out) {\n    transport_capture_t ctx;\n    z_internal_transport_null(&ctx.transport);\n    ctx.count = 0;\n\n    z_owned_closure_transport_t callback;\n    assert_ok(z_closure_transport(&callback, capture_transport, NULL, &ctx));\n    assert_ok(z_info_transports(session, z_closure_transport_move(&callback)));\n\n    z_internal_transport_null(out);\n    if (ctx.count > 0) {\n        z_transport_take(out, z_transport_move(&ctx.transport));\n    }\n    return ctx.count;\n}\n\nstatic void test_info_transports_and_links(void) {\n    printf(\"test_info_transports_and_links\\n\");\n\n    z_owned_session_t s1, s2;\n    open_listener_session(&s1, \"tcp/127.0.0.1:7452\");\n    open_connector_session(&s2, \"tcp/127.0.0.1:7452\");\n    z_sleep_s(1);\n\n    z_id_t s2_zid = z_info_zid(z_session_loan(&s2));\n\n    transport_info_capture_t transport_ctx = {0};\n    z_owned_closure_transport_t transport_callback;\n    assert_ok(z_closure_transport(&transport_callback, capture_transport_info, NULL, &transport_ctx));\n    assert_ok(z_info_transports(z_session_loan(&s1), z_closure_transport_move(&transport_callback)));\n    assert(transport_ctx.count == 1);\n    assert(transport_ctx.has_first);\n    assert(memcmp(&transport_ctx.first_zid, &s2_zid, sizeof(z_id_t)) == 0);\n\n    link_info_capture_t link_ctx = {0};\n    z_owned_closure_link_t link_callback;\n    assert_ok(z_closure_link(&link_callback, capture_link_info, NULL, &link_ctx));\n    assert_ok(z_info_links(z_session_loan(&s1), z_closure_link_move(&link_callback), NULL));\n    assert(link_ctx.count == 1);\n    assert(link_ctx.has_first);\n    assert(memcmp(&link_ctx.first_zid, &s2_zid, sizeof(z_id_t)) == 0);\n    assert(link_ctx.first_src_non_empty);\n    assert(link_ctx.first_dst_non_empty);\n\n    close_session_with_tasks(&s2);\n    close_session_with_tasks(&s1);\n}\n\nstatic void test_info_links_filtered(void) {\n    printf(\"test_info_links_filtered\\n\");\n\n    z_owned_session_t s1, s2;\n    open_listener_session(&s1, \"tcp/127.0.0.1:7453\");\n    open_connector_session(&s2, \"tcp/127.0.0.1:7453\");\n    z_sleep_s(1);\n\n    z_id_t s2_zid = z_info_zid(z_session_loan(&s2));\n\n    z_owned_transport_t s1_transport;\n    z_owned_transport_t s2_transport;\n    z_internal_transport_null(&s1_transport);\n    z_internal_transport_null(&s2_transport);\n    assert(capture_single_transport(z_session_loan(&s1), &s1_transport) == 1);\n    assert(capture_single_transport(z_session_loan(&s2), &s2_transport) == 1);\n    assert(z_internal_transport_check(&s1_transport));\n    assert(z_internal_transport_check(&s2_transport));\n\n    link_info_capture_t match_ctx = {0};\n    z_owned_closure_link_t match_callback;\n    assert_ok(z_closure_link(&match_callback, capture_link_info, NULL, &match_ctx));\n    z_info_links_options_t match_opts;\n    z_info_links_options_default(&match_opts);\n    match_opts.transport = z_transport_move(&s1_transport);\n    assert_ok(z_info_links(z_session_loan(&s1), z_closure_link_move(&match_callback), &match_opts));\n    assert(match_ctx.count == 1);\n    assert(match_ctx.has_first);\n    assert(memcmp(&match_ctx.first_zid, &s2_zid, sizeof(z_id_t)) == 0);\n    assert(match_ctx.first_src_non_empty);\n    assert(match_ctx.first_dst_non_empty);\n\n    link_info_capture_t miss_ctx = {0};\n    z_owned_closure_link_t miss_callback;\n    assert_ok(z_closure_link(&miss_callback, capture_link_info, NULL, &miss_ctx));\n    z_info_links_options_t miss_opts;\n    z_info_links_options_default(&miss_opts);\n    miss_opts.transport = z_transport_move(&s2_transport);\n    assert_ok(z_info_links(z_session_loan(&s1), z_closure_link_move(&miss_callback), &miss_opts));\n    assert(miss_ctx.count == 0);\n    assert(!miss_ctx.has_first);\n\n    z_transport_drop(z_transport_move(&s1_transport));\n    z_transport_drop(z_transport_move(&s2_transport));\n\n    close_session_with_tasks(&s2);\n    close_session_with_tasks(&s1);\n}\n\nstatic void test_info_transports_and_links_empty(void) {\n    printf(\"test_info_transports_and_links_empty\\n\");\n\n    z_owned_session_t s1;\n    open_listener_session(&s1, \"tcp/127.0.0.1:7460\");\n    z_sleep_ms(250);\n\n    transport_info_capture_t transport_ctx = {0};\n    z_owned_closure_transport_t transport_callback;\n    assert_ok(z_closure_transport(&transport_callback, capture_transport_info, NULL, &transport_ctx));\n    assert_ok(z_info_transports(z_session_loan(&s1), z_closure_transport_move(&transport_callback)));\n    assert(transport_ctx.count == 0);\n    assert(!transport_ctx.has_first);\n\n    link_info_capture_t link_ctx = {0};\n    z_owned_closure_link_t link_callback;\n    assert_ok(z_closure_link(&link_callback, capture_link_info, NULL, &link_ctx));\n    assert_ok(z_info_links(z_session_loan(&s1), z_closure_link_move(&link_callback), NULL));\n    assert(link_ctx.count == 0);\n    assert(!link_ctx.has_first);\n\n    close_session_with_tasks(&s1);\n}\n\nstatic void run_transport_events_test(const char *locator, bool history, bool background) {\n    z_owned_session_t s1, s2;\n    transport_events_ctx_t ctx;\n    transport_events_ctx_reset(&ctx);\n\n    open_listener_session(&s1, locator);\n    if (history) {\n        open_connector_session(&s2, locator);\n        z_sleep_s(1);\n    }\n\n    z_owned_closure_transport_event_t callback;\n    assert_ok(z_closure_transport_event(&callback, on_transport_event, NULL, &ctx));\n\n    z_transport_events_listener_options_t opts;\n    z_transport_events_listener_options_default(&opts);\n    opts.history = history;\n\n    z_owned_transport_events_listener_t listener;\n    if (background) {\n        assert_ok(z_declare_background_transport_events_listener(z_session_loan(&s1),\n                                                                 z_closure_transport_event_move(&callback), &opts));\n    } else {\n        assert_ok(z_declare_transport_events_listener(z_session_loan(&s1), &listener,\n                                                      z_closure_transport_event_move(&callback), &opts));\n    }\n\n    if (!history) {\n        assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 0);\n        open_connector_session(&s2, locator);\n    }\n\n    z_id_t s2_zid = z_info_zid(z_session_loan(&s2));\n    assert(wait_counter_at_least(&ctx.put, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 1);\n    assert(atomic_load_explicit(&ctx.put_zid_set, memory_order_acquire));\n    assert(atomic_load_explicit(&ctx.put_snapshot_set, memory_order_acquire));\n    assert(memcmp(&ctx.put_zid, &s2_zid, sizeof(z_id_t)) == 0);\n    assert(ctx.put_whatami == Z_WHATAMI_PEER);\n    assert(!ctx.put_is_qos);\n    assert(!ctx.put_is_multicast);\n    assert(!ctx.put_is_shm);\n\n    close_session_with_tasks(&s2);\n\n    assert(wait_counter_at_least(&ctx.delete_, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&ctx.delete_, memory_order_acquire) == 1);\n    assert(atomic_load_explicit(&ctx.delete_zid_set, memory_order_acquire));\n    assert(memcmp(&ctx.delete_zid, &s2_zid, sizeof(z_id_t)) == 0);\n\n    if (!background) {\n        assert_ok(z_undeclare_transport_events_listener(z_transport_events_listener_move(&listener)));\n    }\n    close_session_with_tasks(&s1);\n}\n\nstatic void run_link_events_test(const char *locator, bool history, bool background) {\n    z_owned_session_t s1, s2;\n    link_events_ctx_t ctx;\n    link_events_ctx_reset(&ctx);\n\n    open_listener_session(&s1, locator);\n    if (history) {\n        open_connector_session(&s2, locator);\n        z_sleep_s(1);\n    }\n\n    z_owned_closure_link_event_t callback;\n    assert_ok(z_closure_link_event(&callback, on_link_event, NULL, &ctx));\n\n    z_link_events_listener_options_t opts;\n    z_link_events_listener_options_default(&opts);\n    opts.history = history;\n\n    z_owned_link_events_listener_t listener;\n    if (background) {\n        assert_ok(z_declare_background_link_events_listener(z_session_loan(&s1), z_closure_link_event_move(&callback),\n                                                            &opts));\n    } else {\n        assert_ok(z_declare_link_events_listener(z_session_loan(&s1), &listener, z_closure_link_event_move(&callback),\n                                                 &opts));\n    }\n\n    if (!history) {\n        assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 0);\n        open_connector_session(&s2, locator);\n    }\n\n    z_id_t s2_zid = z_info_zid(z_session_loan(&s2));\n    assert(wait_counter_at_least(&ctx.put, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 1);\n    assert(atomic_load_explicit(&ctx.put_zid_set, memory_order_acquire));\n    assert(atomic_load_explicit(&ctx.put_snapshot_set, memory_order_acquire));\n    assert(memcmp(&ctx.put_zid, &s2_zid, sizeof(z_id_t)) == 0);\n    assert(ctx.put_src_non_empty);\n    assert(ctx.put_dst_non_empty);\n    assert(ctx.put_mtu > 0);\n    assert(ctx.put_is_streamed);\n    assert(ctx.put_is_reliable);\n\n    close_session_with_tasks(&s2);\n\n    assert(wait_counter_at_least(&ctx.delete_, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&ctx.delete_, memory_order_acquire) == 1);\n    assert(atomic_load_explicit(&ctx.delete_zid_set, memory_order_acquire));\n    assert(memcmp(&ctx.delete_zid, &s2_zid, sizeof(z_id_t)) == 0);\n\n    if (!background) {\n        assert_ok(z_undeclare_link_events_listener(z_link_events_listener_move(&listener)));\n    }\n    close_session_with_tasks(&s1);\n}\n\nstatic void test_transport_events_no_history(void) {\n    printf(\"test_transport_events_no_history\\n\");\n    run_transport_events_test(\"tcp/127.0.0.1:7448\", false, false);\n}\n\nstatic void test_transport_events_history(void) {\n    printf(\"test_transport_events_history\\n\");\n    run_transport_events_test(\"tcp/127.0.0.1:7449\", true, false);\n}\n\nstatic void test_transport_events_background(void) {\n    printf(\"test_transport_events_background\\n\");\n    run_transport_events_test(\"tcp/127.0.0.1:7450\", false, true);\n}\n\nstatic void test_transport_events_background_history(void) {\n    printf(\"test_transport_events_background_history\\n\");\n    run_transport_events_test(\"tcp/127.0.0.1:7461\", true, true);\n}\n\nstatic void test_link_events_no_history(void) {\n    printf(\"test_link_events_no_history\\n\");\n    run_link_events_test(\"tcp/127.0.0.1:7451\", false, false);\n}\n\nstatic void test_link_events_history(void) {\n    printf(\"test_link_events_history\\n\");\n    run_link_events_test(\"tcp/127.0.0.1:7454\", true, false);\n}\n\nstatic void test_link_events_background(void) {\n    printf(\"test_link_events_background\\n\");\n    run_link_events_test(\"tcp/127.0.0.1:7455\", false, true);\n}\n\nstatic void test_link_events_background_history(void) {\n    printf(\"test_link_events_background_history\\n\");\n    run_link_events_test(\"tcp/127.0.0.1:7462\", true, true);\n}\n\nstatic void test_transport_events_undeclare(void) {\n    printf(\"test_transport_events_undeclare\\n\");\n\n    z_owned_session_t s1, s2, s3;\n    transport_events_ctx_t ctx;\n    transport_events_ctx_reset(&ctx);\n\n    open_listener_session(&s1, \"tcp/127.0.0.1:7463\");\n    z_owned_closure_transport_event_t callback;\n    assert_ok(z_closure_transport_event(&callback, on_transport_event, NULL, &ctx));\n    z_owned_transport_events_listener_t listener;\n    assert_ok(z_declare_transport_events_listener(z_session_loan(&s1), &listener,\n                                                  z_closure_transport_event_move(&callback), NULL));\n\n    open_connector_session(&s2, \"tcp/127.0.0.1:7463\");\n    assert(wait_counter_at_least(&ctx.put, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 1);\n\n    assert_ok(z_undeclare_transport_events_listener(z_transport_events_listener_move(&listener)));\n\n    close_session_with_tasks(&s2);\n    z_sleep_ms(500);\n    assert(atomic_load_explicit(&ctx.delete_, memory_order_acquire) == 0);\n\n    open_connector_session(&s3, \"tcp/127.0.0.1:7463\");\n    z_sleep_ms(500);\n    assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 1);\n    assert(atomic_load_explicit(&ctx.delete_, memory_order_acquire) == 0);\n\n    close_session_with_tasks(&s3);\n    close_session_with_tasks(&s1);\n}\n\nstatic void test_link_events_undeclare(void) {\n    printf(\"test_link_events_undeclare\\n\");\n\n    z_owned_session_t s1, s2, s3;\n    link_events_ctx_t ctx;\n    link_events_ctx_reset(&ctx);\n\n    open_listener_session(&s1, \"tcp/127.0.0.1:7464\");\n    z_owned_closure_link_event_t callback;\n    assert_ok(z_closure_link_event(&callback, on_link_event, NULL, &ctx));\n    z_owned_link_events_listener_t listener;\n    assert_ok(\n        z_declare_link_events_listener(z_session_loan(&s1), &listener, z_closure_link_event_move(&callback), NULL));\n\n    open_connector_session(&s2, \"tcp/127.0.0.1:7464\");\n    assert(wait_counter_at_least(&ctx.put, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 1);\n\n    assert_ok(z_undeclare_link_events_listener(z_link_events_listener_move(&listener)));\n\n    close_session_with_tasks(&s2);\n    z_sleep_ms(500);\n    assert(atomic_load_explicit(&ctx.delete_, memory_order_acquire) == 0);\n\n    open_connector_session(&s3, \"tcp/127.0.0.1:7464\");\n    z_sleep_ms(500);\n    assert(atomic_load_explicit(&ctx.put, memory_order_acquire) == 1);\n    assert(atomic_load_explicit(&ctx.delete_, memory_order_acquire) == 0);\n\n    close_session_with_tasks(&s3);\n    close_session_with_tasks(&s1);\n}\n\nstatic void test_link_events_filtered(void) {\n    printf(\"test_link_events_filtered\\n\");\n\n    z_owned_session_t s1, s2;\n    open_listener_session(&s1, \"tcp/127.0.0.1:7456\");\n    open_connector_session(&s2, \"tcp/127.0.0.1:7456\");\n    z_sleep_s(1);\n\n    z_owned_transport_t s1_transport;\n    z_owned_transport_t s2_transport;\n    z_internal_transport_null(&s1_transport);\n    z_internal_transport_null(&s2_transport);\n\n    assert(capture_single_transport(z_session_loan(&s1), &s1_transport) == 1);\n    assert(capture_single_transport(z_session_loan(&s2), &s2_transport) == 1);\n    assert(z_internal_transport_check(&s1_transport));\n    assert(z_internal_transport_check(&s2_transport));\n\n    events_ctx_t match_ctx;\n    events_ctx_reset(&match_ctx);\n\n    z_owned_closure_link_event_t match_callback;\n    assert_ok(z_closure_link_event(&match_callback, on_link_event_count_only, NULL, &match_ctx));\n\n    z_link_events_listener_options_t match_opts;\n    z_link_events_listener_options_default(&match_opts);\n    match_opts.history = true;\n    match_opts.transport = z_transport_move(&s1_transport);\n\n    z_owned_link_events_listener_t match_listener;\n    assert_ok(z_declare_link_events_listener(z_session_loan(&s1), &match_listener,\n                                             z_closure_link_event_move(&match_callback), &match_opts));\n\n    assert(wait_counter_at_least(&match_ctx.link_put, 1));\n    z_sleep_ms(250);\n    assert(atomic_load_explicit(&match_ctx.link_put, memory_order_acquire) == 1);\n    assert_ok(z_undeclare_link_events_listener(z_link_events_listener_move(&match_listener)));\n\n    events_ctx_t miss_ctx;\n    events_ctx_reset(&miss_ctx);\n\n    z_owned_closure_link_event_t miss_callback;\n    assert_ok(z_closure_link_event(&miss_callback, on_link_event_count_only, NULL, &miss_ctx));\n\n    z_link_events_listener_options_t miss_opts;\n    z_link_events_listener_options_default(&miss_opts);\n    miss_opts.history = true;\n    miss_opts.transport = z_transport_move(&s2_transport);\n\n    z_owned_link_events_listener_t miss_listener;\n    assert_ok(z_declare_link_events_listener(z_session_loan(&s1), &miss_listener,\n                                             z_closure_link_event_move(&miss_callback), &miss_opts));\n\n    z_sleep_ms(500);\n    assert(atomic_load_explicit(&miss_ctx.link_put, memory_order_acquire) == 0);\n    assert(atomic_load_explicit(&miss_ctx.link_delete, memory_order_acquire) == 0);\n    assert_ok(z_undeclare_link_events_listener(z_link_events_listener_move(&miss_listener)));\n\n    z_transport_drop(z_transport_move(&s1_transport));\n    z_transport_drop(z_transport_move(&s2_transport));\n\n    close_session_with_tasks(&s2);\n    close_session_with_tasks(&s1);\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n\n    test_info_transports_and_links();\n    test_info_links_filtered();\n    test_info_transports_and_links_empty();\n    test_transport_events_no_history();\n    test_transport_events_history();\n    test_transport_events_background();\n    test_transport_events_background_history();\n    test_transport_events_undeclare();\n    test_link_events_no_history();\n    test_link_events_history();\n    test_link_events_background();\n    test_link_events_background_history();\n    test_link_events_undeclare();\n    test_link_events_filtered();\n    return 0;\n}\n\n#else\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "tests/z_api_double_drop_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define URL \"demo/example\"\n\nvoid test_keyexpr(void) {\n    z_owned_keyexpr_t keyexpr;\n    z_keyexpr_from_str(&keyexpr, URL);\n    assert(z_internal_check(keyexpr));\n    z_drop(z_move(keyexpr));\n    assert(!z_internal_check(keyexpr));\n    z_drop(z_move(keyexpr));\n    assert(!z_internal_check(keyexpr));\n}\n\nvoid test_config(void) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    assert(z_internal_check(config));\n    z_drop(z_move(config));\n    assert(!z_internal_check(config));\n    z_drop(z_move(config));\n    assert(!z_internal_check(config));\n}\n\nint main(void) {\n    test_keyexpr();\n    test_config();\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_api_encoding_test.c",
    "content": "#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/api/encoding.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nvoid test_null_encoding(void) {\n    z_owned_encoding_t e;\n    z_internal_encoding_null(&e);\n    assert(!z_internal_encoding_check(&e));\n    z_encoding_drop(z_encoding_move(&e));\n}\n\nvoid test_encoding_without_id(void) {\n    z_owned_encoding_t e1;\n    z_encoding_from_str(&e1, \"my_encoding\");\n    assert(z_internal_encoding_check(&e1));\n    z_owned_string_t s;\n    z_encoding_to_string(z_encoding_loan(&e1), &s);\n    assert(strncmp(\"zenoh/bytes;my_encoding\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e1));\n    z_string_drop(z_string_move(&s));\n\n    z_owned_encoding_t e2;\n    z_encoding_from_substr(&e2, \"my_encoding\", 4);\n    assert(z_internal_encoding_check(&e2));\n\n    z_encoding_to_string(z_encoding_loan(&e2), &s);\n    assert(strncmp(\"zenoh/bytes;my_e\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e2));\n    z_string_drop(z_string_move(&s));\n}\n\nvoid test_encoding_with_id(void) {\n    z_owned_encoding_t e1;\n    z_encoding_from_str(&e1, \"zenoh/string;utf8\");\n    assert(z_internal_encoding_check(&e1));\n    z_owned_string_t s;\n    z_encoding_to_string(z_encoding_loan(&e1), &s);\n    assert(strncmp(\"zenoh/string;utf8\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e1));\n    z_string_drop(z_string_move(&s));\n\n    z_owned_encoding_t e2;\n    z_encoding_from_substr(&e2, \"zenoh/string;utf8\", 15);\n    assert(z_internal_encoding_check(&e2));\n\n    z_encoding_to_string(z_encoding_loan(&e2), &s);\n    assert(strncmp(\"zenoh/string;utf8\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e2));\n    z_string_drop(z_string_move(&s));\n\n    z_owned_encoding_t e3;\n    z_encoding_from_str(&e3, \"custom_id;custom_schema\");\n    assert(z_internal_encoding_check(&e3));\n\n    z_encoding_to_string(z_encoding_loan(&e3), &s);\n    assert(strncmp(\"zenoh/bytes;custom_id;custom_schema\", z_string_data(z_string_loan(&s)),\n                   z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e3));\n    z_string_drop(z_string_move(&s));\n\n    z_owned_encoding_t e4;\n    z_encoding_from_substr(&e4, \"custom_id;custom_schema\", 16);\n    assert(z_internal_encoding_check(&e2));\n\n    z_encoding_to_string(z_encoding_loan(&e4), &s);\n    assert(strncmp(\"zenoh/bytes;custom_id;custom\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) ==\n           0);\n    z_encoding_drop(z_encoding_move(&e4));\n    z_string_drop(z_string_move(&s));\n}\n\nvoid test_with_schema(void) {\n    z_owned_encoding_t e;\n    z_internal_encoding_null(&e);\n    z_encoding_set_schema_from_str(z_encoding_loan_mut(&e), \"my_schema\");\n\n    z_owned_string_t s;\n    z_encoding_to_string(z_encoding_loan_mut(&e), &s);\n    assert(strncmp(\"zenoh/bytes;my_schema\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e));\n    z_string_drop(z_string_move(&s));\n\n    z_encoding_from_str(&e, \"zenoh/string;\");\n    z_encoding_set_schema_from_substr(z_encoding_loan_mut(&e), \"my_schema\", 3);\n\n    z_encoding_to_string(z_encoding_loan(&e), &s);\n    assert(strncmp(\"zenoh/string;my_\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_encoding_drop(z_encoding_move(&e));\n    z_string_drop(z_string_move(&s));\n}\n\nvoid test_constants(void) {\n#if Z_FEATURE_ENCODING_VALUES == 1\n    z_owned_string_t s;\n    z_encoding_to_string(z_encoding_zenoh_bytes(), &s);\n    assert(strncmp(\"zenoh/bytes\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n    z_string_drop(z_string_move(&s));\n\n    z_encoding_to_string(z_encoding_zenoh_string(), &s);\n    assert(strncmp(\"zenoh/string\", z_string_data(z_string_loan(&s)), z_string_len(z_string_loan(&s))) == 0);\n\n    z_string_drop(z_string_move(&s));\n#endif\n}\n\nvoid test_equals(void) {\n#if Z_FEATURE_ENCODING_VALUES == 1\n    z_owned_encoding_t e;\n    z_encoding_from_str(&e, \"zenoh/string\");\n    assert(z_encoding_equals(z_encoding_loan(&e), z_encoding_zenoh_string()));\n    assert(!z_encoding_equals(z_encoding_loan(&e), z_encoding_zenoh_serialized()));\n    z_encoding_drop(z_encoding_move(&e));\n#endif\n}\n\nint main(void) {\n    test_null_encoding();\n    test_encoding_without_id();\n    test_encoding_with_id();\n    test_with_schema();\n    test_constants();\n    test_equals();\n}\n"
  },
  {
    "path": "tests/z_api_liveliness_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/liveliness.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n\n#if Z_FEATURE_LIVELINESS == 1 && Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_QUERY == 1\n\n#undef NDEBUG\n#include <assert.h>\ntypedef struct context_t {\n    bool token1_put;\n    bool token2_put;\n    bool token1_drop;\n    bool token2_drop;\n} context_t;\n\n#define assert_ok(x)                            \\\n    {                                           \\\n        int ret = (int)x;                       \\\n        if (ret != Z_OK) {                      \\\n            printf(\"%s failed: %d\\n\", #x, ret); \\\n            assert(false);                      \\\n        }                                       \\\n    }\n\nconst char* token1_expr = \"zenoh-pico/liveliness/test/1\";\nconst char* token2_expr = \"zenoh-pico/liveliness/test/2\";\n\nvoid on_receive(z_loaned_sample_t* s, void* context) {\n    context_t* c = (context_t*)context;\n    const z_loaned_keyexpr_t* k = z_sample_keyexpr(s);\n    z_view_string_t ks;\n    z_keyexpr_as_view_string(k, &ks);\n\n    if (z_sample_kind(s) == Z_SAMPLE_KIND_PUT) {\n        if (strncmp(token1_expr, z_string_data(z_view_string_loan(&ks)), z_string_len(z_view_string_loan(&ks))) == 0) {\n            c->token1_put = true;\n        } else if (strncmp(token2_expr, z_string_data(z_view_string_loan(&ks)),\n                           z_string_len(z_view_string_loan(&ks))) == 0) {\n            c->token2_put = true;\n        }\n    } else if (z_sample_kind(s) == Z_SAMPLE_KIND_DELETE) {\n        if (strncmp(token1_expr, z_string_data(z_view_string_loan(&ks)), z_string_len(z_view_string_loan(&ks))) == 0) {\n            c->token1_drop = true;\n        } else if (strncmp(token2_expr, z_string_data(z_view_string_loan(&ks)),\n                           z_string_len(z_view_string_loan(&ks))) == 0) {\n            c->token2_drop = true;\n        }\n    }\n}\n\nvoid test_liveliness_sub(bool multicast, bool history) {\n    printf(\"test_liveliness_sub: multicast=%d, history=%d\\n\", multicast, history);\n    const char* expr = \"zenoh-pico/liveliness/test/*\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k, k1, k2;\n    z_view_keyexpr_from_str(&k, expr);\n    z_view_keyexpr_from_str(&k1, token1_expr);\n    z_view_keyexpr_from_str(&k2, token2_expr);\n\n    if (multicast) {\n        zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n        zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n\n        zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"client\");\n        zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    }\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n    z_owned_liveliness_token_t t1, t2;\n    // In history mode we can declare token before subscribing\n    if (history) {\n        assert_ok(z_liveliness_declare_token(z_session_loan(&s2), &t1, z_view_keyexpr_loan(&k1), NULL));\n        assert_ok(z_liveliness_declare_token(z_session_loan(&s2), &t2, z_view_keyexpr_loan(&k2), NULL));\n    }\n\n    z_sleep_s(1);\n    z_owned_closure_sample_t closure;\n    context_t context = {false, false, false, false};\n    z_closure_sample(&closure, on_receive, NULL, (void*)(&context));\n\n    z_owned_subscriber_t sub;\n    z_liveliness_subscriber_options_t sub_opt;\n    z_liveliness_subscriber_options_default(&sub_opt);\n    sub_opt.history = history;\n    assert_ok(z_liveliness_declare_subscriber(z_session_loan(&s1), &sub, z_view_keyexpr_loan(&k),\n                                              z_closure_sample_move(&closure), &sub_opt));\n\n    z_sleep_s(1);\n    if (!history) {\n        assert_ok(z_liveliness_declare_token(z_session_loan(&s2), &t1, z_view_keyexpr_loan(&k1), NULL));\n        assert_ok(z_liveliness_declare_token(z_session_loan(&s2), &t2, z_view_keyexpr_loan(&k2), NULL));\n    }\n\n    z_sleep_s(1);\n\n    assert(context.token1_put);\n    assert(context.token2_put);\n\n    assert_ok(z_liveliness_undeclare_token(z_liveliness_token_move(&t1)));\n    z_sleep_s(1);\n\n    assert(context.token1_drop);\n    assert(!context.token2_drop);\n\n    assert_ok(z_liveliness_undeclare_token(z_liveliness_token_move(&t2)));\n    z_sleep_s(1);\n    assert(context.token2_drop);\n\n    z_closure_sample_drop(z_closure_sample_move(&closure));\n    z_subscriber_drop(z_subscriber_move(&sub));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nvoid test_liveliness_get(void) {\n    const char* expr = \"zenoh-pico/liveliness/test/*\";\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k, k1;\n    z_view_keyexpr_from_str(&k, expr);\n    z_view_keyexpr_from_str(&k1, token1_expr);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n    z_sleep_s(1);\n    z_owned_liveliness_token_t t1;\n    assert_ok(z_liveliness_declare_token(z_session_loan(&s1), &t1, z_view_keyexpr_loan(&k1), NULL));\n    z_sleep_s(1);\n\n    z_owned_fifo_handler_reply_t handler;\n    z_owned_closure_reply_t cb;\n    assert_ok(z_fifo_channel_reply_new(&cb, &handler, 3));\n\n    assert_ok(z_liveliness_get(z_session_loan(&s2), z_view_keyexpr_loan(&k), z_closure_reply_move(&cb), NULL));\n    z_owned_reply_t reply;\n    assert_ok(z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&handler), &reply));\n    assert(z_reply_is_ok(z_reply_loan(&reply)));\n    const z_loaned_keyexpr_t* reply_keyexpr = z_sample_keyexpr(z_reply_ok(z_reply_loan(&reply)));\n    z_view_string_t reply_keyexpr_s;\n    z_keyexpr_as_view_string(reply_keyexpr, &reply_keyexpr_s);\n    assert(strlen(token1_expr) == z_string_len(z_view_string_loan(&reply_keyexpr_s)));\n    assert(strncmp(token1_expr, z_string_data(z_view_string_loan(&reply_keyexpr_s)),\n                   z_string_len(z_view_string_loan(&reply_keyexpr_s))) == 0);\n\n    z_reply_drop(z_reply_move(&reply));\n    assert(z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&handler), &reply) == Z_CHANNEL_DISCONNECTED);\n\n    z_liveliness_token_drop(z_liveliness_token_move(&t1));\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&handler));\n    z_sleep_s(1);\n    assert_ok(z_fifo_channel_reply_new(&cb, &handler, 3));\n\n    z_liveliness_get(z_session_loan(&s2), z_view_keyexpr_loan(&k), z_closure_reply_move(&cb), NULL);\n    assert(z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&handler), &reply) == Z_CHANNEL_DISCONNECTED);\n\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&handler));\n    z_closure_reply_drop(z_closure_reply_move(&cb));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n#if defined(ZENOH_LINUX)\n    test_liveliness_sub(true, false);\n    test_liveliness_sub(true, true);\n#endif\n    test_liveliness_sub(false, false);\n    test_liveliness_sub(false, true);\n    test_liveliness_get();\n}\n\n#else\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n}\n#endif\n"
  },
  {
    "path": "tests/z_api_local_queryable_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_QUERYABLE == 1 && Z_FEATURE_LOCAL_QUERYABLE == 1 && Z_FEATURE_MULTI_THREAD == 1\n\nstatic const char *QUERYABLE_EXPR = \"zenoh-pico/locality/query\";\n\nvoid test_queryable(z_locality_t get_allowed_destination, z_locality_t q1_allowed_origin,\n                    z_locality_t q2_allowed_origin) {\n    printf(\"Testing Quryables: get_dest=%d q1_origin=%d q2_origin=%d\\n\", get_allowed_destination, q1_allowed_origin,\n           q2_allowed_origin);\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, QUERYABLE_EXPR);\n\n    assert(z_open(&s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(&s2, z_config_move(&c2), NULL) == Z_OK);\n\n    z_owned_queryable_t queryable1, queryable2;\n    z_queryable_options_t opts1, opts2;\n    z_queryable_options_default(&opts1);\n    z_queryable_options_default(&opts2);\n    opts1.allowed_origin = q1_allowed_origin;\n    opts2.allowed_origin = q2_allowed_origin;\n\n    z_owned_closure_query_t query_callback1, query_callback2;\n    z_owned_fifo_handler_query_t query_handler1, query_handler2;\n    z_fifo_channel_query_new(&query_callback1, &query_handler1, 16);\n    z_declare_queryable(z_session_loan(&s1), &queryable1, z_view_keyexpr_loan(&ke),\n                        z_closure_query_move(&query_callback1), &opts1);\n    z_fifo_channel_query_new(&query_callback2, &query_handler2, 16);\n    z_declare_queryable(z_session_loan(&s2), &queryable2, z_view_keyexpr_loan(&ke),\n                        z_closure_query_move(&query_callback2), &opts2);\n\n    z_owned_closure_reply_t reply_callback;\n    z_owned_fifo_handler_reply_t reply_handler;\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    opts.allowed_destination = get_allowed_destination;\n    opts.consolidation = z_query_consolidation_none();\n\n    z_sleep_s(1);\n\n    z_get(z_session_loan(&s1), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_callback), &opts);\n\n    z_sleep_s(1);\n\n    z_owned_query_t q1, q2;\n\n    z_result_t ret1 = z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler1), &q1);\n    z_result_t ret2 = z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler2), &q2);\n    bool expect_1 = false;\n    bool expect_2 = false;\n    size_t expect_responses = 0;\n    if (_z_locality_allows_local(get_allowed_destination) && _z_locality_allows_local(q1_allowed_origin)) {\n        assert(ret1 == Z_OK);\n        z_owned_bytes_t payload1;\n        z_bytes_copy_from_str(&payload1, \"1\");\n        z_query_reply(z_query_loan(&q1), z_view_keyexpr_loan(&ke), z_bytes_move(&payload1), NULL);\n        z_query_drop(z_query_move(&q1));\n        expect_1 = true;\n        expect_responses++;\n    } else {\n        assert(ret1 != Z_OK);\n    }\n    if (_z_locality_allows_remote(get_allowed_destination) && _z_locality_allows_remote(q2_allowed_origin)) {\n        assert(ret2 == Z_OK);\n        z_owned_bytes_t payload2;\n        z_bytes_copy_from_str(&payload2, \"2\");\n        z_query_reply(z_query_loan(&q2), z_view_keyexpr_loan(&ke), z_bytes_move(&payload2), NULL);\n        z_query_drop(z_query_move(&q2));\n        expect_2 = true;\n        expect_responses++;\n    } else {\n        assert(ret2 != Z_OK);\n    }\n\n    bool found_1 = false;\n    bool found_2 = false;\n    size_t reply_count = 0;\n\n    z_sleep_s(1);\n\n    z_owned_reply_t reply;\n    for (z_result_t res = z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&reply_handler), &reply);\n         res != Z_CHANNEL_DISCONNECTED;\n         res = z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&reply_handler), &reply)) {\n        assert(z_reply_is_ok(z_loan(reply)));\n        const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        if (strncmp(z_string_data(z_loan(replystr)), \"1\", 1) == 0) {\n            found_1 = true;\n        }\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        if (strncmp(z_string_data(z_loan(replystr)), \"2\", 1) == 0) {\n            found_2 = true;\n        }\n        reply_count++;\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        assert(strncmp(z_string_data(z_loan(keystr)), QUERYABLE_EXPR, strlen(QUERYABLE_EXPR)) == 0);\n        z_reply_drop(z_reply_move(&reply));\n        z_string_drop(z_string_move(&replystr));\n    }\n\n    assert(reply_count == expect_responses);\n    assert(found_1 == expect_1);\n    assert(found_2 == expect_2);\n\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler1));\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler2));\n\n    z_queryable_drop(z_queryable_move(&queryable1));\n    z_queryable_drop(z_queryable_move(&queryable2));\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nvoid test_queryable_peer_mode(z_locality_t get_allowed_destination, z_locality_t q_allowed_origin) {\n    printf(\"Testing peer mode: get_dest=%d q_origin=%d\\n\", get_allowed_destination, q_allowed_origin);\n\n    z_owned_session_t s;\n    z_owned_config_t c;\n    z_config_default(&c);\n    assert(zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\") == Z_OK);\n    assert(zp_config_insert(z_loan_mut(c), Z_CONFIG_LISTEN_KEY, \"tcp/127.0.0.1:10000\") == Z_OK);\n    assert(zp_config_insert(z_loan_mut(c), Z_CONFIG_MULTICAST_SCOUTING_KEY, \"false\") == Z_OK);\n\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, QUERYABLE_EXPR);\n\n    assert(z_open(&s, z_config_move(&c), NULL) == Z_OK);\n\n    z_owned_queryable_t queryable;\n    z_queryable_options_t qopts;\n    z_queryable_options_default(&qopts);\n    qopts.allowed_origin = q_allowed_origin;\n\n    z_owned_closure_query_t query_callback;\n    z_owned_fifo_handler_query_t query_handler;\n    z_fifo_channel_query_new(&query_callback, &query_handler, 16);\n    z_declare_queryable(z_session_loan(&s), &queryable, z_view_keyexpr_loan(&ke), z_closure_query_move(&query_callback),\n                        &qopts);\n\n    z_owned_closure_reply_t reply_callback;\n    z_owned_fifo_handler_reply_t reply_handler;\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 16);\n\n    z_get_options_t opts;\n    z_get_options_default(&opts);\n    opts.allowed_destination = get_allowed_destination;\n\n    z_get(z_session_loan(&s), z_view_keyexpr_loan(&ke), \"\", z_closure_reply_move(&reply_callback), &opts);\n\n    z_owned_query_t q;\n    z_result_t ret = z_fifo_handler_query_try_recv(z_fifo_handler_query_loan(&query_handler), &q);\n\n    bool expect_response =\n        _z_locality_allows_local(get_allowed_destination) && _z_locality_allows_local(q_allowed_origin);\n    size_t expect_responses = 0;\n\n    if (expect_response) {\n        assert(ret == Z_OK);\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, \"peer_reply\");\n        z_query_reply(z_query_loan(&q), z_view_keyexpr_loan(&ke), z_bytes_move(&payload), NULL);\n        z_query_drop(z_query_move(&q));\n        expect_responses = 1;\n    } else {\n        assert(ret != Z_OK);\n    }\n\n    size_t reply_count = 0;\n    bool found_reply = false;\n\n    z_sleep_s(1);\n\n    z_owned_reply_t reply;\n    for (z_result_t res = z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&reply_handler), &reply);\n         res != Z_CHANNEL_DISCONNECTED;\n         res = z_fifo_handler_reply_recv(z_fifo_handler_reply_loan(&reply_handler), &reply)) {\n        assert(z_reply_is_ok(z_loan(reply)));\n        const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t replystr;\n        z_bytes_to_string(z_sample_payload(sample), &replystr);\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        if (strncmp(z_string_data(z_loan(replystr)), \"peer_reply\", 10) == 0) {\n            found_reply = true;\n        }\n        reply_count++;\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        assert(strncmp(z_string_data(z_loan(keystr)), QUERYABLE_EXPR, strlen(QUERYABLE_EXPR)) == 0);\n        z_reply_drop(z_reply_move(&reply));\n        z_string_drop(z_string_move(&replystr));\n    }\n\n    assert(reply_count == expect_responses);\n    assert(found_reply == expect_response);\n\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&reply_handler));\n    z_fifo_handler_query_drop(z_fifo_handler_query_move(&query_handler));\n    z_queryable_drop(z_queryable_move(&queryable));\n    z_session_drop(z_session_move(&s));\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    z_locality_t localities[] = {Z_LOCALITY_ANY, Z_LOCALITY_REMOTE, Z_LOCALITY_SESSION_LOCAL};\n    for (size_t i = 0; i < 3; i++) {\n        for (size_t j = 0; j < 3; j++) {\n            for (size_t k = 0; k < 3; k++) {\n                test_queryable(localities[i], localities[j], localities[k]);\n            }\n        }\n    }\n    // Test local query on a single session in peer mode\n    test_queryable_peer_mode(Z_LOCALITY_ANY, Z_LOCALITY_ANY);\n}\n\n#else\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n}\n#endif\n"
  },
  {
    "path": "tests/z_api_local_subscriber_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include \"zenoh-pico.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_LOCAL_SUBSCRIBER == 1 && \\\n    Z_FEATURE_MULTI_THREAD == 1\n\nstatic const char *PUB_EXPR = \"zenoh-pico/locality/pub-sub\";\nstatic const char *PAYLOAD = \"payload\";\n\nvoid test_put_sub(z_locality_t pub_allowed_destination, z_locality_t s1_allowed_origin,\n                  z_locality_t s2_allowed_origin) {\n    printf(\"Testing: %d %d %d\\n\", pub_allowed_destination, s1_allowed_origin, s2_allowed_origin);\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, PUB_EXPR);\n\n    assert(z_open(&s1, z_config_move(&c1), NULL) == Z_OK);\n    assert(z_open(&s2, z_config_move(&c2), NULL) == Z_OK);\n\n    z_owned_subscriber_t subscriber1, subscriber2;\n    z_subscriber_options_t opts1, opts2;\n    z_subscriber_options_default(&opts1);\n    z_subscriber_options_default(&opts2);\n    opts1.allowed_origin = s1_allowed_origin;\n    opts2.allowed_origin = s2_allowed_origin;\n\n    z_owned_closure_sample_t subscriber_callback1, subscriber_callback2;\n    z_owned_fifo_handler_sample_t subscriber_handler1, subscriber_handler2;\n    z_fifo_channel_sample_new(&subscriber_callback1, &subscriber_handler1, 16);\n    z_declare_subscriber(z_session_loan(&s1), &subscriber1, z_view_keyexpr_loan(&ke),\n                         z_closure_sample_move(&subscriber_callback1), &opts1);\n\n    z_fifo_channel_sample_new(&subscriber_callback2, &subscriber_handler2, 16);\n    z_declare_subscriber(z_session_loan(&s2), &subscriber2, z_view_keyexpr_loan(&ke),\n                         z_closure_sample_move(&subscriber_callback2), &opts2);\n\n    z_put_options_t opts;\n    z_put_options_default(&opts);\n    opts.allowed_destination = pub_allowed_destination;\n\n    z_sleep_s(1);\n    z_owned_bytes_t payload;\n    z_bytes_copy_from_str(&payload, PAYLOAD);\n\n    z_put(z_session_loan(&s1), z_view_keyexpr_loan(&ke), z_bytes_move(&payload), &opts);\n\n    z_sleep_s(1);\n\n    z_owned_sample_t sample1, sample2;\n\n    z_result_t ret1 = z_fifo_handler_sample_try_recv(z_fifo_handler_sample_loan(&subscriber_handler1), &sample1);\n    z_result_t ret2 = z_fifo_handler_sample_try_recv(z_fifo_handler_sample_loan(&subscriber_handler2), &sample2);\n    if (_z_locality_allows_local(pub_allowed_destination) && _z_locality_allows_local(s1_allowed_origin)) {\n        assert(ret1 == Z_OK);\n        const z_loaned_sample_t *sample = z_sample_loan(&sample1);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t payloadstr;\n        z_bytes_to_string(z_sample_payload(sample), &payloadstr);\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        assert(strncmp(z_string_data(z_loan(payloadstr)), PAYLOAD, strlen(PAYLOAD)) == 0);\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        assert(strncmp(z_string_data(z_loan(keystr)), PUB_EXPR, strlen(PUB_EXPR)) == 0);\n        z_string_drop(z_string_move(&payloadstr));\n        z_sample_drop(z_sample_move(&sample1));\n    } else {\n        assert(ret1 != Z_OK);\n    }\n    if (_z_locality_allows_remote(pub_allowed_destination) && _z_locality_allows_remote(s2_allowed_origin)) {\n        assert(ret2 == Z_OK);\n        const z_loaned_sample_t *sample = z_sample_loan(&sample2);\n        z_view_string_t keystr;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n        z_owned_string_t payloadstr;\n        z_bytes_to_string(z_sample_payload(sample), &payloadstr);\n\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        assert(strncmp(z_string_data(z_loan(payloadstr)), PAYLOAD, strlen(PAYLOAD)) == 0);\n        // SAFETY: test.\n        // Flawfinder: ignore [CWE-126]\n        assert(strncmp(z_string_data(z_loan(keystr)), PUB_EXPR, strlen(PUB_EXPR)) == 0);\n        z_string_drop(z_string_move(&payloadstr));\n        z_sample_drop(z_sample_move(&sample2));\n    } else {\n        assert(ret2 != Z_OK);\n    }\n\n    z_fifo_handler_sample_drop(z_fifo_handler_sample_move(&subscriber_handler1));\n    z_fifo_handler_sample_drop(z_fifo_handler_sample_move(&subscriber_handler2));\n\n    z_subscriber_drop(z_subscriber_move(&subscriber1));\n    z_subscriber_drop(z_subscriber_move(&subscriber2));\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    z_locality_t localities[] = {Z_LOCALITY_ANY, Z_LOCALITY_REMOTE, Z_LOCALITY_SESSION_LOCAL};\n    for (size_t i = 0; i < 3; i++) {\n        for (size_t j = 0; j < 3; j++) {\n            for (size_t k = 0; k < 3; k++) {\n                test_put_sub(localities[i], localities[j], localities[k]);\n            }\n        }\n    }\n}\n\n#else\nint main(int argc, char** argv) {\n    (void)argc;\n    (void)argv;\n}\n#endif\n"
  },
  {
    "path": "tests/z_api_matching_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_MATCHING == 1 && Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1\n\n#undef NDEBUG\n#include <assert.h>\n\nstatic const char *PUB_EXPR = \"zenoh-pico/matching/test/val\";\nstatic const char *SUB_EXPR = \"zenoh-pico/matching/**\";\nstatic const char *KEY_EXPR_WRONG = \"zenoh-pico/matching/test_wrong/*\";\n\nstatic const char *QUERYABLE_EXPR = \"zenoh-pico/matching/query_test/val\";\nstatic const char *QUERIER_EXPR = \"zenoh-pico/matching/query_test/*\";\nstatic const char *QUERYABLE_EXPR_WILD = \"zenoh-pico/matching/query_test/**\";\n\nstatic unsigned long DEFAULT_TIMEOUT_S = 10;\n\ntypedef enum { NONE, MATCH, UNMATCH, DROP } context_state_t;\n\ntypedef struct context_t {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_owned_condvar_t cv;\n    z_owned_mutex_t m;\n#else\n    z_loaned_session_t *s1;\n    z_loaned_session_t *s2;\n#endif\n    context_state_t state;\n} context_t;\n\nstatic void _context_init(context_t *c) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_condvar_init(&c->cv);\n    z_mutex_init(&c->m);\n#endif\n    c->state = NONE;\n}\n\nstatic void _context_drop(context_t *c) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_condvar_drop(z_condvar_move(&c->cv));\n    z_mutex_drop(z_mutex_move(&c->m));\n#else\n    (void)c;\n#endif\n}\n\n#if Z_FEATURE_MULTI_THREAD == 1\nstatic bool _context_wait(context_t *c, context_state_t state, unsigned long timeout_s) {\n    z_mutex_lock(z_mutex_loan_mut(&c->m));\n    if (c->state != state) {\n        printf(\"Waiting for state %d...\\n\", state);\n#ifdef ZENOH_MACOS\n        _ZP_UNUSED(timeout_s);\n        z_condvar_wait(z_condvar_loan_mut(&c->cv), z_mutex_loan_mut(&c->m));\n#else\n        z_clock_t clock = z_clock_now();\n        z_clock_advance_s(&clock, timeout_s);\n        z_result_t res = z_condvar_wait_until(z_condvar_loan_mut(&c->cv), z_mutex_loan_mut(&c->m), &clock);\n        if (res == Z_ETIMEDOUT) {\n            fprintf(stderr, \"Timeout waiting for state %d\\n\", state);\n            return false;\n        }\n#endif\n        if (c->state != state) {\n            fprintf(stderr, \"Expected state %d, got %d\\n\", state, c->state);\n            return false;\n        }\n    }\n    c->state = NONE;\n    z_mutex_unlock(z_mutex_loan_mut(&c->m));\n    return true;\n}\n\nstatic bool _context_wait_none(context_t *c, unsigned long timeout_s) {\n    z_sleep_s(timeout_s);\n    z_mutex_lock(z_mutex_loan_mut(&c->m));\n    context_state_t s = c->state;\n    z_mutex_unlock(z_mutex_loan_mut(&c->m));\n    if (s != NONE) {\n        fprintf(stderr, \"Expected state %d, got %d\\n\", NONE, s);\n        return false;\n    }\n    return true;\n}\n#else\nstatic bool _context_wait_none(context_t *c, unsigned long timeout_s) {\n    unsigned long tm = timeout_s * 1000;\n    while (c->state == NONE && tm > 0) {\n        zp_spin_once(c->s1);\n        zp_spin_once(c->s2);\n        z_sleep_ms(100);\n        tm -= 100;\n    }\n    if (c->state != NONE) {\n        fprintf(stderr, \"Expected state %d, got %d\\n\", NONE, c->state);\n        return false;\n    }\n    return true;\n}\n\nstatic bool _context_wait(context_t *c, context_state_t state, unsigned long timeout_s) {\n    unsigned long tm = timeout_s * 1000;\n    while (c->state == NONE && tm > 0) {\n        zp_spin_once(c->s1);\n        zp_spin_once(c->s2);\n        z_sleep_ms(100);\n        tm -= 100;\n    }\n    if (tm <= 0) {\n        fprintf(stderr, \"Timeout waiting for state %d\\n\", state);\n        return false;\n    }\n    if (c->state != state) {\n        fprintf(stderr, \"Expected state %d, got %d\\n\", state, c->state);\n        return false;\n    }\n    c->state = NONE;\n    return true;\n}\n#endif\n\nstatic void _context_notify(context_t *c, context_state_t state) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_mutex_lock(z_mutex_loan_mut(&c->m));\n#endif\n    if (c->state != NONE) {\n        fprintf(stderr, \"State already set %d\\n\", c->state);\n        assert(false);\n    }\n    c->state = state;\n    fprintf(stderr, \"State recieved %d\\n\", state);\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_condvar_signal(z_condvar_loan_mut(&c->cv));\n    z_mutex_unlock(z_mutex_loan_mut(&c->m));\n#endif\n}\n\n#define assert_ok(x)                                     \\\n    {                                                    \\\n        int ret = (int)x;                                \\\n        if (ret != Z_OK) {                               \\\n            fprintf(stderr, \"%s failed: %d\\n\", #x, ret); \\\n            assert(false);                               \\\n        }                                                \\\n    }\n\nvoid on_receive(const z_matching_status_t *s, void *context) {\n    context_t *c = (context_t *)context;\n    _context_notify(c, s->matching ? MATCH : UNMATCH);\n}\n\nvoid on_drop(void *context) {\n    context_t *c = (context_t *)context;\n    _context_notify(c, DROP);\n}\n\nvoid test_matching_listener_publisher(bool background, bool history) {\n    printf(\"test_matching_listener_publisher: background=%d, history=%d\\n\", background, history);\n    context_t context = {0};\n    _context_init(&context);\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k_sub, k_pub;\n    z_view_keyexpr_from_str(&k_sub, SUB_EXPR);\n    z_view_keyexpr_from_str(&k_pub, PUB_EXPR);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n#if Z_FEATURE_MULTI_THREAD == 0\n    context.s1 = z_loan_mut(s1);\n    context.s2 = z_loan_mut(s2);\n#endif\n\n    z_owned_publisher_t pub;\n    assert_ok(z_declare_publisher(z_session_loan(&s1), &pub, z_view_keyexpr_loan(&k_pub), NULL));\n\n    z_owned_closure_matching_status_t closure;\n    z_closure_matching_status(&closure, on_receive, on_drop, (void *)(&context));\n\n    z_owned_matching_listener_t matching_listener;\n    z_owned_subscriber_t sub, sub2;\n    z_owned_closure_sample_t callback, callback2;\n    z_closure_sample(&callback, NULL, NULL, NULL);\n    z_closure_sample(&callback2, NULL, NULL, NULL);\n\n    if (history) {\n        assert_ok(z_declare_subscriber(z_session_loan(&s2), &sub, z_view_keyexpr_loan(&k_pub),\n                                       z_closure_sample_move(&callback), NULL));\n        z_sleep_s(3);\n        if (background) {\n            assert_ok(z_publisher_declare_background_matching_listener(z_publisher_loan(&pub),\n                                                                       z_closure_matching_status_move(&closure)));\n        } else {\n            assert_ok(z_publisher_declare_matching_listener(z_publisher_loan(&pub), &matching_listener,\n                                                            z_closure_matching_status_move(&closure)));\n        }\n    } else {\n        if (background) {\n            assert_ok(z_publisher_declare_background_matching_listener(z_publisher_loan(&pub),\n                                                                       z_closure_matching_status_move(&closure)));\n        } else {\n            assert_ok(z_publisher_declare_matching_listener(z_publisher_loan(&pub), &matching_listener,\n                                                            z_closure_matching_status_move(&closure)));\n        }\n        assert_ok(z_declare_subscriber(z_session_loan(&s2), &sub, z_view_keyexpr_loan(&k_pub),\n                                       z_closure_sample_move(&callback), NULL));\n    }\n\n    assert(_context_wait(&context, MATCH, DEFAULT_TIMEOUT_S));\n\n    assert_ok(z_declare_subscriber(z_session_loan(&s2), &sub2, z_view_keyexpr_loan(&k_sub),\n                                   z_closure_sample_move(&callback2), NULL));\n    z_sleep_s(1);\n    assert(_context_wait_none(&context, 1));\n    z_subscriber_drop(z_subscriber_move(&sub));\n    assert(_context_wait_none(&context, 1));\n    z_subscriber_drop(z_subscriber_move(&sub2));\n    assert(_context_wait(&context, UNMATCH, DEFAULT_TIMEOUT_S));\n    z_publisher_drop(z_publisher_move(&pub));\n\n    assert(_context_wait(&context, DROP, DEFAULT_TIMEOUT_S));\n    if (!background) {\n        z_matching_listener_drop(z_matching_listener_move(&matching_listener));\n    }\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n\n    _context_drop(&context);\n}\n\nvoid test_matching_listener_querier(bool complete, bool background) {\n    printf(\"test_matching_listener_querier: complete=%d, background=%d\\n\", complete, background);\n\n    context_t context = {0};\n    _context_init(&context);\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k_queryable, k_querier, k_queryable_wild, k_queryable_wrong;\n    z_view_keyexpr_from_str(&k_queryable, QUERYABLE_EXPR);\n    z_view_keyexpr_from_str(&k_queryable_wild, QUERYABLE_EXPR_WILD);\n    z_view_keyexpr_from_str(&k_querier, QUERIER_EXPR);\n    z_view_keyexpr_from_str(&k_queryable_wrong, KEY_EXPR_WRONG);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n#if Z_FEATURE_MULTI_THREAD == 0\n    context.s1 = z_loan_mut(s1);\n    context.s2 = z_loan_mut(s2);\n#endif\n\n    z_querier_options_t querier_opts;\n    z_querier_options_default(&querier_opts);\n    querier_opts.target = complete ? Z_QUERY_TARGET_ALL_COMPLETE : Z_QUERY_TARGET_BEST_MATCHING;\n\n    z_owned_querier_t querier;\n    assert_ok(z_declare_querier(z_session_loan(&s1), &querier, z_view_keyexpr_loan(&k_querier), &querier_opts));\n\n    z_owned_closure_matching_status_t closure;\n    z_closure_matching_status(&closure, on_receive, on_drop, (void *)(&context));\n\n    z_owned_matching_listener_t matching_listener;\n    if (background) {\n        assert_ok(z_querier_declare_background_matching_listener(z_querier_loan(&querier),\n                                                                 z_closure_matching_status_move(&closure)));\n    } else {\n        assert_ok(z_querier_declare_matching_listener(z_querier_loan(&querier), &matching_listener,\n                                                      z_closure_matching_status_move(&closure)));\n    }\n\n    z_sleep_s(1);\n    assert(_context_wait_none(&context, 1));\n\n    z_owned_queryable_t queryable_wrong;\n    z_owned_closure_query_t callback_wrong;\n    z_closure_query(&callback_wrong, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable_wrong, z_view_keyexpr_loan(&k_queryable_wrong),\n                                  z_closure_query_move(&callback_wrong), NULL));\n    assert(_context_wait_none(&context, 1));\n\n    z_queryable_options_t queryable_options;\n    z_queryable_options_default(&queryable_options);\n    queryable_options.complete = false;\n\n    z_owned_queryable_t queryable1, queryable2, queryable3;\n    z_owned_closure_query_t callback1, callback2, callback3;\n\n    z_closure_query(&callback1, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable1, z_view_keyexpr_loan(&k_queryable),\n                                  z_closure_query_move(&callback1), &queryable_options));\n    if (complete) {\n        assert(_context_wait_none(&context, 1));\n    } else {\n        assert(_context_wait(&context, MATCH, DEFAULT_TIMEOUT_S));\n    }\n\n    queryable_options.complete = false;\n    z_closure_query(&callback2, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable2, z_view_keyexpr_loan(&k_queryable_wild),\n                                  z_closure_query_move(&callback2), &queryable_options));\n    assert(_context_wait_none(&context, 1));\n\n    queryable_options.complete = true;\n    z_closure_query(&callback3, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable3, z_view_keyexpr_loan(&k_queryable_wild),\n                                  z_closure_query_move(&callback3), &queryable_options));\n    if (!complete) {\n        assert(_context_wait_none(&context, 1));\n    } else {\n        assert(_context_wait(&context, MATCH, DEFAULT_TIMEOUT_S));\n    }\n\n    z_queryable_drop(z_queryable_move(&queryable2));\n    assert(_context_wait_none(&context, 1));\n\n    z_queryable_drop(z_queryable_move(&queryable3));\n    if (complete) {\n        assert(_context_wait(&context, UNMATCH, DEFAULT_TIMEOUT_S));\n    } else {\n        assert(_context_wait_none(&context, 1));\n    }\n\n    z_queryable_drop(z_queryable_move(&queryable1));\n    if (!complete) {\n        assert(_context_wait(&context, UNMATCH, DEFAULT_TIMEOUT_S));\n    } else {\n        assert(_context_wait_none(&context, 1));\n    }\n\n    z_querier_drop(z_querier_move(&querier));\n    z_queryable_drop(z_queryable_move(&queryable_wrong));\n\n    assert(_context_wait(&context, DROP, DEFAULT_TIMEOUT_S));\n\n    if (!background) {\n        z_matching_listener_drop(z_matching_listener_move(&matching_listener));\n    }\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\nstatic bool _check_publisher_status(z_owned_publisher_t *pub, z_loaned_session_t *s1, z_loaned_session_t *s2,\n                                    bool expected) {\n    z_matching_status_t status;\n    status.matching = !expected;\n    z_clock_t clock = z_clock_now();\n    while (status.matching != expected && z_clock_elapsed_s(&clock) < DEFAULT_TIMEOUT_S) {\n        assert_ok(z_publisher_get_matching_status(z_publisher_loan(pub), &status));\n        z_sleep_ms(100);\n#if Z_FEATURE_MULTI_THREAD == 1\n        (void)s1;\n        (void)s2;\n#else\n        zp_spin_once(s1);\n        zp_spin_once(s2);\n#endif\n    }\n    if (status.matching != expected) {\n        fprintf(stderr, \"Expected matching status %d, got %d\\n\", expected, status.matching);\n        return false;\n    }\n    return true;\n}\n\nvoid test_matching_status_publisher(void) {\n    printf(\"test_matching_status_publisher\\n\");\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k_sub, k_pub, k_sub_wrong;\n    z_view_keyexpr_from_str(&k_sub, SUB_EXPR);\n    z_view_keyexpr_from_str(&k_pub, PUB_EXPR);\n    z_view_keyexpr_from_str(&k_sub_wrong, KEY_EXPR_WRONG);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n    z_owned_publisher_t pub;\n    assert_ok(z_declare_publisher(z_session_loan(&s1), &pub, z_view_keyexpr_loan(&k_pub), NULL));\n    z_sleep_s(1);\n\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), false));\n\n    z_owned_subscriber_t sub_wrong;\n    z_owned_closure_sample_t callback_wrong;\n    z_closure_sample(&callback_wrong, NULL, NULL, NULL);\n    assert_ok(z_declare_subscriber(z_session_loan(&s2), &sub_wrong, z_view_keyexpr_loan(&k_sub_wrong),\n                                   z_closure_sample_move(&callback_wrong), NULL));\n    z_sleep_s(1);\n\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), false));\n\n    z_owned_subscriber_t sub;\n    z_owned_closure_sample_t callback;\n    z_closure_sample(&callback, NULL, NULL, NULL);\n    assert_ok(z_declare_subscriber(z_session_loan(&s2), &sub, z_view_keyexpr_loan(&k_sub),\n                                   z_closure_sample_move(&callback), NULL));\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), true));\n\n    z_owned_subscriber_t sub2;\n    z_owned_closure_sample_t callback2;\n    z_closure_sample(&callback2, NULL, NULL, NULL);\n    assert_ok(z_declare_subscriber(z_session_loan(&s2), &sub2, z_view_keyexpr_loan(&k_pub),\n                                   z_closure_sample_move(&callback), NULL));\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), true));\n\n    z_subscriber_drop(z_subscriber_move(&sub));\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), true));\n    z_subscriber_drop(z_subscriber_move(&sub2));\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), false));\n\n    z_publisher_drop(z_publisher_move(&pub));\n    z_subscriber_drop(z_subscriber_move(&sub_wrong));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\nstatic void test_matching_status_publisher_locality(z_locality_t locality, bool create_local_sub,\n                                                    bool create_remote_sub, bool expected) {\n    printf(\"test_matching_status_publisher_locality locality=%d local=%d remote=%d expected=%d\\n\", (int)locality,\n           create_local_sub, create_remote_sub, expected);\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k_pub, k_sub;\n    z_view_keyexpr_from_str(&k_pub, PUB_EXPR);\n    z_view_keyexpr_from_str(&k_sub, SUB_EXPR);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n    z_publisher_options_t pub_opts;\n    z_publisher_options_default(&pub_opts);\n    pub_opts.allowed_destination = locality;\n\n    z_owned_publisher_t pub;\n    assert_ok(z_declare_publisher(z_session_loan(&s1), &pub, z_view_keyexpr_loan(&k_pub), &pub_opts));\n\n    z_owned_subscriber_t local_sub;\n    z_owned_subscriber_t remote_sub;\n\n    if (create_local_sub) {\n        z_subscriber_options_t opts;\n        z_subscriber_options_default(&opts);\n        opts.allowed_origin = Z_LOCALITY_SESSION_LOCAL;\n        z_owned_closure_sample_t cb;\n        z_closure_sample(&cb, NULL, NULL, NULL);\n        assert_ok(z_declare_subscriber(z_session_loan(&s1), &local_sub, z_view_keyexpr_loan(&k_sub),\n                                       z_closure_sample_move(&cb), &opts));\n    }\n\n    if (create_remote_sub) {\n        z_owned_closure_sample_t cb;\n        z_closure_sample(&cb, NULL, NULL, NULL);\n        assert_ok(z_declare_subscriber(z_session_loan(&s2), &remote_sub, z_view_keyexpr_loan(&k_sub),\n                                       z_closure_sample_move(&cb), NULL));\n    }\n\n    assert(_check_publisher_status(&pub, z_loan_mut(s1), z_loan_mut(s2), expected));\n\n    if (create_local_sub) {\n        z_subscriber_drop(z_subscriber_move(&local_sub));\n    }\n    if (create_remote_sub) {\n        z_subscriber_drop(z_subscriber_move(&remote_sub));\n    }\n    z_publisher_drop(z_publisher_move(&pub));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n#endif  // Z_FEATURE_LOCAL_SUBSCRIBER == 1\n\nstatic bool _check_querier_status(z_owned_querier_t *querier, z_loaned_session_t *s1, z_loaned_session_t *s2,\n                                  bool expected) {\n    z_matching_status_t status;\n    status.matching = !expected;\n    z_clock_t clock = z_clock_now();\n    while (status.matching != expected && z_clock_elapsed_s(&clock) < DEFAULT_TIMEOUT_S) {\n        assert_ok(z_querier_get_matching_status(z_querier_loan(querier), &status));\n#if Z_FEATURE_MULTI_THREAD == 1\n        (void)s1;\n        (void)s2;\n#else\n        zp_spin_once(s1);\n        zp_spin_once(s2);\n#endif\n        z_sleep_ms(100);\n    }\n    if (status.matching != expected) {\n        fprintf(stderr, \"Expected matching status %d, got %d\\n\", expected, status.matching);\n        return false;\n    }\n    return true;\n}\n\nvoid test_matching_status_querier(bool complete) {\n    printf(\"test_matching_status_querier: complete=%d\\n\", complete);\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k_queryable, k_querier, k_queryable_wrong, k_queryable_wild;\n    z_view_keyexpr_from_str(&k_queryable_wild, QUERYABLE_EXPR_WILD);\n    z_view_keyexpr_from_str(&k_queryable, QUERYABLE_EXPR);\n    z_view_keyexpr_from_str(&k_querier, QUERIER_EXPR);\n    z_view_keyexpr_from_str(&k_queryable_wrong, KEY_EXPR_WRONG);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n    z_querier_options_t querier_opts;\n    z_querier_options_default(&querier_opts);\n    querier_opts.target = complete ? Z_QUERY_TARGET_ALL_COMPLETE : Z_QUERY_TARGET_BEST_MATCHING;\n\n    z_owned_querier_t querier;\n    assert_ok(z_declare_querier(z_session_loan(&s1), &querier, z_view_keyexpr_loan(&k_querier), &querier_opts));\n\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), false);\n\n    z_owned_queryable_t queryable_wrong;\n    z_owned_closure_query_t callback_wrong;\n    z_closure_query(&callback_wrong, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable_wrong, z_view_keyexpr_loan(&k_queryable_wrong),\n                                  z_closure_query_move(&callback_wrong), NULL));\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), false);\n\n    z_queryable_options_t queryable_options;\n    z_queryable_options_default(&queryable_options);\n    queryable_options.complete = false;\n\n    z_owned_queryable_t queryable1, queryable2, queryable3;\n    z_owned_closure_query_t callback1, callback2, callback3;\n\n    z_closure_query(&callback1, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable1, z_view_keyexpr_loan(&k_queryable),\n                                  z_closure_query_move(&callback1), &queryable_options));\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), !complete);\n\n    queryable_options.complete = false;\n    z_closure_query(&callback2, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable2, z_view_keyexpr_loan(&k_queryable_wild),\n                                  z_closure_query_move(&callback2), &queryable_options));\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), !complete);\n\n    queryable_options.complete = true;\n    z_closure_query(&callback3, NULL, NULL, NULL);\n    assert_ok(z_declare_queryable(z_session_loan(&s2), &queryable3, z_view_keyexpr_loan(&k_queryable_wild),\n                                  z_closure_query_move(&callback3), &queryable_options));\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), true);\n\n    z_queryable_drop(z_queryable_move(&queryable2));\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), true);\n\n    z_queryable_drop(z_queryable_move(&queryable3));\n    z_sleep_s(1);\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), !complete);\n\n    z_queryable_drop(z_queryable_move(&queryable1));\n    z_sleep_s(1);\n\n    _check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), false);\n\n    z_querier_drop(z_querier_move(&querier));\n    z_queryable_drop(z_queryable_move(&queryable_wrong));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\nstatic void test_matching_status_querier_locality(z_locality_t locality, bool create_local_queryable,\n                                                  bool create_remote_queryable, bool expected) {\n    printf(\"test_matching_status_querier_locality locality=%d local=%d remote=%d expected=%d\\n\", (int)locality,\n           create_local_queryable, create_remote_queryable, expected);\n\n    z_owned_session_t s1, s2;\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_view_keyexpr_t k_queryable, k_querier;\n    z_view_keyexpr_from_str(&k_queryable, QUERYABLE_EXPR);\n    z_view_keyexpr_from_str(&k_querier, QUERIER_EXPR);\n\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n    assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n    z_querier_options_t querier_opts;\n    z_querier_options_default(&querier_opts);\n    querier_opts.allowed_destination = locality;\n\n    z_owned_querier_t querier;\n    assert_ok(z_declare_querier(z_session_loan(&s1), &querier, z_view_keyexpr_loan(&k_querier), &querier_opts));\n\n    z_owned_queryable_t local_queryable;\n    z_owned_queryable_t remote_queryable;\n\n    if (create_local_queryable) {\n        z_queryable_options_t opts;\n        z_queryable_options_default(&opts);\n        opts.allowed_origin = Z_LOCALITY_SESSION_LOCAL;\n        z_owned_closure_query_t cb;\n        z_closure_query(&cb, NULL, NULL, NULL);\n        assert_ok(z_declare_queryable(z_session_loan(&s1), &local_queryable, z_view_keyexpr_loan(&k_queryable),\n                                      z_closure_query_move(&cb), &opts));\n    }\n\n    if (create_remote_queryable) {\n        z_queryable_options_t opts;\n        z_queryable_options_default(&opts);\n        z_owned_closure_query_t cb;\n        z_closure_query(&cb, NULL, NULL, NULL);\n        assert_ok(z_declare_queryable(z_session_loan(&s2), &remote_queryable, z_view_keyexpr_loan(&k_queryable),\n                                      z_closure_query_move(&cb), &opts));\n    }\n\n    assert(_check_querier_status(&querier, z_loan_mut(s1), z_loan_mut(s2), expected));\n\n    if (create_local_queryable) {\n        z_queryable_drop(z_queryable_move(&local_queryable));\n    }\n    if (create_remote_queryable) {\n        z_queryable_drop(z_queryable_move(&remote_queryable));\n    }\n    z_querier_drop(z_querier_move(&querier));\n\n    z_session_drop(z_session_move(&s1));\n    z_session_drop(z_session_move(&s2));\n}\n#endif  // Z_FEATURE_LOCAL_QUERYABLE == 1\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_matching_listener_publisher(true, false);\n    test_matching_listener_publisher(false, false);\n    test_matching_listener_publisher(true, true);\n    test_matching_listener_publisher(false, true);\n    test_matching_status_publisher();\n\n    test_matching_listener_querier(false, false);\n    test_matching_listener_querier(true, false);\n    test_matching_listener_querier(true, true);\n    test_matching_listener_querier(false, true);\n    test_matching_status_querier(false);\n    test_matching_status_querier(true);\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    test_matching_status_publisher_locality(Z_LOCALITY_SESSION_LOCAL, true, false, true);\n    test_matching_status_publisher_locality(Z_LOCALITY_SESSION_LOCAL, false, true, false);\n    test_matching_status_publisher_locality(Z_LOCALITY_SESSION_LOCAL, true, true, true);\n    test_matching_status_publisher_locality(Z_LOCALITY_REMOTE, true, false, false);\n    test_matching_status_publisher_locality(Z_LOCALITY_REMOTE, false, true, true);\n    test_matching_status_publisher_locality(Z_LOCALITY_REMOTE, true, true, true);\n#endif\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    test_matching_status_querier_locality(Z_LOCALITY_SESSION_LOCAL, true, false, true);\n    test_matching_status_querier_locality(Z_LOCALITY_SESSION_LOCAL, false, true, false);\n    test_matching_status_querier_locality(Z_LOCALITY_SESSION_LOCAL, true, true, true);\n    test_matching_status_querier_locality(Z_LOCALITY_REMOTE, true, false, false);\n    test_matching_status_querier_locality(Z_LOCALITY_REMOTE, false, true, true);\n    test_matching_status_querier_locality(Z_LOCALITY_REMOTE, true, true, true);\n#endif\n}\n\n#else\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n}\n#endif\n"
  },
  {
    "path": "tests/z_api_null_drop_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n\n#undef NDEBUG\n#include <assert.h>\n\n#include \"zenoh-pico.h\"\n\n// fill v with invalid values\n// set v to null\n// check if v it is null\n// make sure that drop on null does not crash\n// make sure that double drop on null does not crash\n// fill v with invalid values again\n//\n// set v1 to null\n// move v to v1\n// make sure that v is null now\n#define TEST(name)                    \\\n    {                                 \\\n        name v;                       \\\n        memset(&v, -1, sizeof(v));    \\\n        z_internal_null(&v);          \\\n        assert(!z_internal_check(v)); \\\n        z_drop(z_move(v));            \\\n        z_drop(z_move(v));            \\\n        name v1;                      \\\n        z_internal_null(&v1);         \\\n        memset(&v, -1, sizeof(v));    \\\n        z_take(&v1, z_move(v));       \\\n        assert(!z_internal_check(v)); \\\n    }\n\nint main(void) {\n    TEST(z_owned_session_t)\n    TEST(z_owned_keyexpr_t)\n    TEST(z_owned_config_t)\n    TEST(z_owned_hello_t)\n    TEST(z_owned_closure_sample_t)\n    TEST(z_owned_closure_query_t)\n    TEST(z_owned_closure_reply_t)\n    TEST(z_owned_closure_hello_t)\n    TEST(z_owned_closure_zid_t)\n    TEST(z_owned_string_t)\n    TEST(z_owned_string_array_t)\n    TEST(z_owned_sample_t)\n    TEST(z_owned_slice_t)\n    TEST(z_owned_bytes_t)\n    TEST(z_owned_bytes_writer_t)\n    TEST(ze_owned_serializer_t)\n    TEST(z_owned_encoding_t)\n#if Z_FEATURE_PUBLICATION == 1\n    TEST(z_owned_publisher_t)\n#endif\n#if Z_FEATURE_SUBSCRIPTION == 1\n    TEST(z_owned_subscriber_t)\n#endif\n#if Z_FEATURE_QUERYABLE == 1\n    TEST(z_owned_query_t)\n    TEST(z_owned_queryable_t)\n#endif\n#if Z_FEATURE_QUERY == 1\n    TEST(z_owned_reply_t)\n#endif\n    // Double drop not supported for these types\n    // TEST(z_owned_task_t)\n    // TEST(z_owned_mutex_t)\n    // TEST(z_owned_condvar_t)\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_api_queryable_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/macros.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_QUERYABLE\n\nvoid test_queryable_keyexpr(void) {\n    printf(\"Testing queryable key expressions...\\n\");\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, \"client\");\n\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n\n    z_view_keyexpr_t ke1;\n    z_view_keyexpr_from_str(&ke1, \"test/queryable_keyexpr\");\n\n    z_owned_queryable_t q1;\n    z_owned_closure_query_t cb1;\n    z_owned_fifo_handler_query_t h1;\n    z_fifo_channel_query_new(&cb1, &h1, 16);\n    z_declare_queryable(z_loan(s), &q1, z_loan(ke1), z_move(cb1), NULL);\n\n    z_view_string_t sv1;\n    z_keyexpr_as_view_string(z_queryable_keyexpr(z_loan(q1)), &sv1);\n    assert(strncmp(\"test/queryable_keyexpr\", z_string_data(z_loan(sv1)), z_string_len(z_loan(sv1))) == 0);\n    z_drop(z_move(q1));\n    z_drop(z_move(h1));\n\n    z_view_keyexpr_t ke2;\n    z_owned_keyexpr_t ke2_declared;\n    z_view_keyexpr_from_str(&ke2, \"test/queryable_declared_keyexpr\");\n    z_declare_keyexpr(z_loan(s), &ke2_declared, z_loan(ke2));\n\n    z_owned_queryable_t q2;\n    z_owned_closure_query_t cb2;\n    z_owned_fifo_handler_query_t h2;\n    z_fifo_channel_query_new(&cb2, &h2, 16);\n    z_declare_queryable(z_loan(s), &q2, z_loan(ke2_declared), z_move(cb2), NULL);\n\n    z_view_string_t sv2;\n    z_keyexpr_as_view_string(z_queryable_keyexpr(z_loan(q2)), &sv2);\n    assert(strncmp(\"test/queryable_declared_keyexpr\", z_string_data(z_loan(sv2)), z_string_len(z_loan(sv2))) == 0);\n    z_drop(z_move(ke2_declared));\n    z_drop(z_move(q2));\n    z_drop(z_move(h2));\n\n    z_drop(z_move(s));\n}\n\nvoid open_sessions(z_owned_session_t *s, z_owned_session_t *s2, bool local) {\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, \"client\");\n\n    if (z_open(s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n\n    if (local) {\n        *s2 = *s;\n    } else {\n        z_owned_config_t config2;\n        z_config_default(&config2);\n        zp_config_insert(z_loan_mut(config2), Z_CONFIG_MODE_KEY, \"client\");\n        if (z_open(s2, z_move(config2), NULL) < 0) {\n            printf(\"Unable to open second session for local queryable test!\\n\");\n            z_drop(z_move(*s));\n            exit(-1);\n        }\n    }\n}\n\nvoid test_get_accept_replies(bool local) {\n    printf(\"Testing get accept_replies options local = %d...\\n\", local);\n\n    z_owned_session_t s, s2;\n    open_sessions(&s, &s2, local);\n\n    // Declare a queryable on a wildcard key expression\n    z_view_keyexpr_t queryable_ke;\n    z_view_keyexpr_from_str(&queryable_ke, \"test/accept_replies/**\");\n\n    z_owned_queryable_t q;\n    z_owned_closure_query_t cb;\n    z_owned_fifo_handler_query_t h;\n    z_fifo_channel_query_new(&cb, &h, 16);\n    z_declare_queryable(z_loan(s), &q, z_loan(queryable_ke), z_move(cb), NULL);\n    assert(z_internal_check(q));\n    z_sleep_s(1);\n\n    // --- Test 1: Z_REPLY_KEYEXPR_ANY ---\n    // With accept_replies = Z_REPLY_KEYEXPR_ANY, the queryable should be able\n    // to reply on any key expression, even one not matching the query key\n    {\n        z_owned_fifo_handler_reply_t reply_handler;\n        z_owned_closure_reply_t reply_cb;\n        z_fifo_channel_reply_new(&reply_cb, &reply_handler, 16);\n\n        z_view_keyexpr_t get_ke;\n        z_view_keyexpr_from_str(&get_ke, \"test/accept_replies/a\");\n\n        z_get_options_t get_opts;\n        z_get_options_default(&get_opts);\n        get_opts.accept_replies = Z_REPLY_KEYEXPR_ANY;\n\n        z_get(z_loan(s2), z_loan(get_ke), \"\", z_move(reply_cb), &get_opts);\n        z_sleep_s(1);\n\n        // Receive the incoming query\n        z_owned_query_t query;\n        assert(z_recv(z_loan(h), &query) == _Z_RES_OK);\n        assert(z_query_accepts_replies(z_loan(query)) == Z_REPLY_KEYEXPR_ANY);\n\n        // Reply on a different key expression (not intersecting with query key)\n        z_view_keyexpr_t reply_ke;\n        z_view_keyexpr_from_str(&reply_ke, \"test/accept_replies/b\");\n\n        z_owned_bytes_t payload;\n        z_bytes_from_static_str(&payload, \"reply_any\");\n\n        z_query_reply_options_t reply_opts;\n        z_query_reply_options_default(&reply_opts);\n        z_result_t ret = z_query_reply(z_loan(query), z_loan(reply_ke), z_move(payload), &reply_opts);\n        assert(ret == _Z_RES_OK);\n        z_drop(z_move(query));\n        z_sleep_s(1);\n        // The reply should arrive and carry the replied key expression\n        z_owned_reply_t reply;\n        assert(z_recv(z_loan(reply_handler), &reply) == _Z_RES_OK);\n        assert(z_reply_is_ok(z_loan(reply)));\n\n        z_view_string_t reply_key_str;\n        z_keyexpr_as_view_string(z_sample_keyexpr(z_reply_ok(z_loan(reply))), &reply_key_str);\n        assert(strncmp(\"test/accept_replies/b\", z_string_data(z_loan(reply_key_str)),\n                       z_string_len(z_loan(reply_key_str))) == 0);\n\n        z_drop(z_move(reply));\n        z_drop(z_move(reply_handler));\n    }\n\n    // --- Test 2: Z_REPLY_KEYEXPR_MATCHING_QUERY (default) ---\n    // With accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY, the queryable must\n    // reply on a key expression that intersects with the query key expression.\n    // A reply on a matching key should be accepted; one on a non-matching key should be rejected.\n    {\n        // 2a: reply on a key expression matching the query key — should succeed\n        z_owned_fifo_handler_reply_t reply_handler;\n        z_owned_closure_reply_t reply_cb;\n        z_fifo_channel_reply_new(&reply_cb, &reply_handler, 16);\n\n        z_view_keyexpr_t get_ke;\n        z_view_keyexpr_from_str(&get_ke, \"test/accept_replies/c\");\n\n        z_get_options_t get_opts;\n        z_get_options_default(&get_opts);\n        get_opts.accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY;\n\n        z_get(z_loan(s2), z_loan(get_ke), \"\", z_move(reply_cb), &get_opts);\n        z_sleep_s(1);\n        z_owned_query_t query;\n        assert(z_recv(z_loan(h), &query) == _Z_RES_OK);\n        assert(z_query_accepts_replies(z_loan(query)) == Z_REPLY_KEYEXPR_MATCHING_QUERY);\n\n        z_view_keyexpr_t reply_ke_matching;\n        z_view_keyexpr_from_str(&reply_ke_matching, \"test/accept_replies/c\");\n\n        z_owned_bytes_t payload_matching;\n        z_bytes_from_static_str(&payload_matching, \"reply_matching\");\n\n        z_query_reply_options_t reply_opts;\n        z_query_reply_options_default(&reply_opts);\n        z_result_t ret = z_query_reply(z_loan(query), z_loan(reply_ke_matching), z_move(payload_matching), &reply_opts);\n        assert(ret == _Z_RES_OK);\n        z_drop(z_move(query));\n\n        z_sleep_s(1);\n        z_owned_reply_t reply;\n        assert(z_recv(z_loan(reply_handler), &reply) == _Z_RES_OK);\n        assert(z_reply_is_ok(z_loan(reply)));\n\n        z_view_string_t reply_key_str;\n        z_keyexpr_as_view_string(z_sample_keyexpr(z_reply_ok(z_loan(reply))), &reply_key_str);\n        assert(strncmp(\"test/accept_replies/c\", z_string_data(z_loan(reply_key_str)),\n                       z_string_len(z_loan(reply_key_str))) == 0);\n\n        z_drop(z_move(reply));\n        z_drop(z_move(reply_handler));\n\n        // 2b: reply on a key expression NOT matching the query key — should be rejected\n        z_owned_fifo_handler_reply_t reply_handler2;\n        z_owned_closure_reply_t reply_cb2;\n        z_fifo_channel_reply_new(&reply_cb2, &reply_handler2, 16);\n\n        z_view_keyexpr_t get_ke2;\n        z_view_keyexpr_from_str(&get_ke2, \"test/accept_replies/d\");\n\n        z_get_options_t get_opts2;\n        z_get_options_default(&get_opts2);\n        get_opts2.accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY;\n\n        z_get(z_loan(s2), z_loan(get_ke2), \"\", z_move(reply_cb2), &get_opts2);\n        z_sleep_s(1);\n\n        z_owned_query_t query2;\n        assert(z_recv(z_loan(h), &query2) == _Z_RES_OK);\n        assert(z_query_accepts_replies(z_loan(query2)) == Z_REPLY_KEYEXPR_MATCHING_QUERY);\n\n        z_view_keyexpr_t reply_ke_nonmatching;\n        z_view_keyexpr_from_str(&reply_ke_nonmatching, \"test/other/key\");\n\n        z_owned_bytes_t payload_nonmatching;\n        z_bytes_from_static_str(&payload_nonmatching, \"reply_nonmatching\");\n\n        ret = z_query_reply(z_loan(query2), z_loan(reply_ke_nonmatching), z_move(payload_nonmatching), &reply_opts);\n        assert(ret != _Z_RES_OK);\n\n        z_drop(z_move(query2));\n        z_drop(z_move(reply_handler2));\n    }\n\n    z_drop(z_move(q));\n    z_drop(z_move(h));\n    z_drop(z_move(s));\n    if (!local) {\n        z_drop(z_move(s2));\n    }\n}\n\nvoid test_querier_accept_replies(bool local) {\n    printf(\"Testing querier accept_replies options local = %d...\\n\", local);\n\n    z_owned_session_t s, s2;\n    open_sessions(&s, &s2, local);\n\n    // Declare a queryable on a wildcard key expression to handle incoming queries\n    z_view_keyexpr_t queryable_ke;\n    z_view_keyexpr_from_str(&queryable_ke, \"test/querier_accept/**\");\n\n    z_owned_queryable_t q;\n    z_owned_closure_query_t cb;\n    z_owned_fifo_handler_query_t h;\n    z_fifo_channel_query_new(&cb, &h, 16);\n    z_declare_queryable(z_loan(s), &q, z_loan(queryable_ke), z_move(cb), NULL);\n    assert(z_internal_check(q));\n    z_sleep_s(1);\n\n    // --- Test 1: Z_REPLY_KEYEXPR_ANY ---\n    // With accept_replies = Z_REPLY_KEYEXPR_ANY set on the querier, the queryable\n    // should be able to reply on any key expression, even one not matching the query key\n    {\n        z_view_keyexpr_t querier_ke;\n        z_view_keyexpr_from_str(&querier_ke, \"test/querier_accept/a\");\n\n        z_querier_options_t querier_opts;\n        z_querier_options_default(&querier_opts);\n        querier_opts.accept_replies = Z_REPLY_KEYEXPR_ANY;\n\n        z_owned_querier_t querier;\n        z_declare_querier(z_loan(s2), &querier, z_loan(querier_ke), &querier_opts);\n        assert(z_internal_check(querier));\n        z_sleep_s(1);\n\n        z_owned_fifo_handler_reply_t reply_handler;\n        z_owned_closure_reply_t reply_cb;\n        z_fifo_channel_reply_new(&reply_cb, &reply_handler, 16);\n\n        z_querier_get_options_t get_opts;\n        z_querier_get_options_default(&get_opts);\n        z_querier_get(z_loan(querier), \"\", z_move(reply_cb), &get_opts);\n        z_sleep_s(1);\n\n        // Receive the incoming query on the queryable side\n        z_owned_query_t query;\n        assert(z_recv(z_loan(h), &query) == _Z_RES_OK);\n        assert(z_query_accepts_replies(z_loan(query)) == Z_REPLY_KEYEXPR_ANY);\n\n        // Reply on a different key expression (not intersecting with the query key)\n        z_view_keyexpr_t reply_ke;\n        z_view_keyexpr_from_str(&reply_ke, \"test/querier_accept/b\");\n\n        z_owned_bytes_t payload;\n        z_bytes_from_static_str(&payload, \"reply_any\");\n\n        z_query_reply_options_t reply_opts;\n        z_query_reply_options_default(&reply_opts);\n        z_result_t ret = z_query_reply(z_loan(query), z_loan(reply_ke), z_move(payload), &reply_opts);\n        assert(ret == _Z_RES_OK);\n        z_drop(z_move(query));\n        z_sleep_s(1);\n\n        // The reply should arrive and carry the replied key expression\n        z_owned_reply_t reply;\n        assert(z_recv(z_loan(reply_handler), &reply) == _Z_RES_OK);\n        assert(z_reply_is_ok(z_loan(reply)));\n\n        z_view_string_t reply_key_str;\n        z_keyexpr_as_view_string(z_sample_keyexpr(z_reply_ok(z_loan(reply))), &reply_key_str);\n        assert(strncmp(\"test/querier_accept/b\", z_string_data(z_loan(reply_key_str)),\n                       z_string_len(z_loan(reply_key_str))) == 0);\n\n        z_drop(z_move(reply));\n        z_drop(z_move(reply_handler));\n        z_drop(z_move(querier));\n    }\n\n    // --- Test 2: Z_REPLY_KEYEXPR_MATCHING_QUERY (default) ---\n    // With accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY set on the querier,\n    // the queryable must reply on a key expression that intersects with the query key.\n    // A reply on a matching key should be accepted; one on a non-matching key should be rejected.\n    {\n        // 2a: reply on a key expression matching the querier key — should succeed\n        z_view_keyexpr_t querier_ke;\n        z_view_keyexpr_from_str(&querier_ke, \"test/querier_accept/c\");\n\n        z_querier_options_t querier_opts;\n        z_querier_options_default(&querier_opts);\n        querier_opts.accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY;\n\n        z_owned_querier_t querier;\n        z_declare_querier(z_loan(s2), &querier, z_loan(querier_ke), &querier_opts);\n        assert(z_internal_check(querier));\n        z_sleep_s(1);\n        z_owned_fifo_handler_reply_t reply_handler;\n        z_owned_closure_reply_t reply_cb;\n        z_fifo_channel_reply_new(&reply_cb, &reply_handler, 16);\n\n        z_querier_get_options_t get_opts;\n        z_querier_get_options_default(&get_opts);\n        z_querier_get(z_loan(querier), \"\", z_move(reply_cb), &get_opts);\n        z_sleep_s(1);\n\n        z_owned_query_t query;\n        assert(z_recv(z_loan(h), &query) == _Z_RES_OK);\n        assert(z_query_accepts_replies(z_loan(query)) == Z_REPLY_KEYEXPR_MATCHING_QUERY);\n\n        // Reply on a key matching the querier key expression\n        z_view_keyexpr_t reply_ke_matching;\n        z_view_keyexpr_from_str(&reply_ke_matching, \"test/querier_accept/c\");\n\n        z_owned_bytes_t payload_matching;\n        z_bytes_from_static_str(&payload_matching, \"reply_matching\");\n\n        z_query_reply_options_t reply_opts;\n        z_query_reply_options_default(&reply_opts);\n        z_result_t ret = z_query_reply(z_loan(query), z_loan(reply_ke_matching), z_move(payload_matching), &reply_opts);\n        assert(ret == _Z_RES_OK);\n        z_drop(z_move(query));\n\n        z_sleep_s(1);\n        z_owned_reply_t reply;\n        assert(z_recv(z_loan(reply_handler), &reply) == _Z_RES_OK);\n        assert(z_reply_is_ok(z_loan(reply)));\n\n        z_view_string_t reply_key_str;\n        z_keyexpr_as_view_string(z_sample_keyexpr(z_reply_ok(z_loan(reply))), &reply_key_str);\n        assert(strncmp(\"test/querier_accept/c\", z_string_data(z_loan(reply_key_str)),\n                       z_string_len(z_loan(reply_key_str))) == 0);\n\n        z_drop(z_move(reply));\n        z_drop(z_move(reply_handler));\n        z_drop(z_move(querier));\n\n        // 2b: reply on a key expression NOT matching the querier key — should be rejected\n        z_view_keyexpr_t querier_ke2;\n        z_view_keyexpr_from_str(&querier_ke2, \"test/querier_accept/d\");\n\n        z_querier_options_t querier_opts2;\n        z_querier_options_default(&querier_opts2);\n        querier_opts2.accept_replies = Z_REPLY_KEYEXPR_MATCHING_QUERY;\n\n        z_owned_querier_t querier2;\n        z_declare_querier(z_loan(s2), &querier2, z_loan(querier_ke2), &querier_opts2);\n        assert(z_internal_check(querier2));\n        z_sleep_s(1);\n\n        z_owned_fifo_handler_reply_t reply_handler2;\n        z_owned_closure_reply_t reply_cb2;\n        z_fifo_channel_reply_new(&reply_cb2, &reply_handler2, 16);\n\n        z_querier_get_options_t get_opts2;\n        z_querier_get_options_default(&get_opts2);\n        z_querier_get(z_loan(querier2), \"\", z_move(reply_cb2), &get_opts2);\n        z_sleep_s(1);\n\n        z_owned_query_t query2;\n        assert(z_recv(z_loan(h), &query2) == _Z_RES_OK);\n        assert(z_query_accepts_replies(z_loan(query2)) == Z_REPLY_KEYEXPR_MATCHING_QUERY);\n\n        // Reply on a key expression not intersecting with the querier key\n        z_view_keyexpr_t reply_ke_nonmatching;\n        z_view_keyexpr_from_str(&reply_ke_nonmatching, \"test/other/key\");\n\n        z_owned_bytes_t payload_nonmatching;\n        z_bytes_from_static_str(&payload_nonmatching, \"reply_nonmatching\");\n\n        ret = z_query_reply(z_loan(query2), z_loan(reply_ke_nonmatching), z_move(payload_nonmatching), &reply_opts);\n        assert(ret != _Z_RES_OK);\n\n        z_drop(z_move(query2));\n        z_drop(z_move(reply_handler2));\n        z_drop(z_move(querier2));\n    }\n\n    z_drop(z_move(q));\n    z_drop(z_move(h));\n    z_drop(z_move(s));\n    if (!local) {\n        z_drop(z_move(s2));\n    }\n}\n\nint main(void) {\n    test_queryable_keyexpr();\n    test_get_accept_replies(false);\n    test_querier_accept_replies(false);\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    test_get_accept_replies(true);\n    test_querier_accept_replies(true);\n#endif\n    return 0;\n}\n#else\nint main(void) {}\n#endif\n"
  },
  {
    "path": "tests/z_api_source_info_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdatomic.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_QUERY == 1 && Z_FEATURE_QUERYABLE == 1 && \\\n    defined(Z_FEATURE_UNSTABLE_API)\n\n#undef NDEBUG\n#include <assert.h>\n\nconst char *keyexpr = \"zenoh-pico/source_info/test\";\nconst char test_payload[] = \"source-info-test\";\n\n#define SAMPLE_BUF_CAP 128\n\n#define assert_ok(x)                            \\\n    {                                           \\\n        int ret = (int)x;                       \\\n        if (ret != Z_OK) {                      \\\n            printf(\"%s failed: %d\\n\", #x, ret); \\\n            assert(false);                      \\\n        }                                       \\\n    }\n\ntypedef struct sample_capture_t {\n    atomic_bool ready;\n    bool payload_ok;\n    z_entity_global_id_t source;\n    uint32_t sn;\n    z_sample_kind_t kind;\n} sample_capture_t;\n\nstatic void sample_capture_reset(sample_capture_t *capture) {\n    atomic_store_explicit(&capture->ready, false, memory_order_relaxed);\n    capture->payload_ok = false;\n    capture->source = (z_entity_global_id_t){0};\n    capture->sn = 0;\n    capture->kind = Z_SAMPLE_KIND_PUT;\n}\n\nstatic bool wait_for_capture(sample_capture_t *capture) {\n    for (int attempt = 0; attempt < 50; ++attempt) {\n        if (atomic_load_explicit(&capture->ready, memory_order_acquire)) {\n            return true;\n        }\n        z_sleep_ms(100);\n    }\n    return false;\n}\n\nstatic void sample_capture_callback(_z_sample_t *sample, void *arg) {\n    sample_capture_t *capture = (sample_capture_t *)arg;\n    if ((sample == NULL) || (capture == NULL)) {\n        return;\n    }\n    capture->kind = sample->kind;\n    if (sample->kind == Z_SAMPLE_KIND_PUT) {\n        size_t len = _z_bytes_len(&sample->payload);\n        if ((len == sizeof(test_payload) - 1) && (len < SAMPLE_BUF_CAP)) {\n            char buf[SAMPLE_BUF_CAP];\n            size_t copied = _z_bytes_to_buf(&sample->payload, (uint8_t *)buf, len);\n            capture->payload_ok = (copied == len) && (memcmp(buf, test_payload, sizeof(test_payload) - 1) == 0);\n        } else {\n            capture->payload_ok = false;\n        }\n    } else {\n        capture->payload_ok = true;\n    }\n\n    capture->source = sample->source_info._source_id;\n    capture->sn = sample->source_info._source_sn;\n    atomic_store_explicit(&capture->ready, true, memory_order_release);\n}\n\nstatic void assert_source_info_equal(const z_entity_global_id_t *expected, uint32_t expected_sn,\n                                     const z_entity_global_id_t *actual, uint32_t actual_sn) {\n    assert(expected->eid == actual->eid);\n    assert(memcmp(expected->zid.id, actual->zid.id, Z_ZID_LENGTH) == 0);\n    assert(expected_sn == actual_sn);\n}\n\nvoid test_source_info(bool put, bool publisher, bool local_subscriber) {\n    z_owned_config_t c1;\n    z_config_default(&c1);\n\n    z_owned_session_t s1;\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n\n    z_owned_session_t s2;\n    const z_loaned_session_t *sub_session = z_loan(s1);\n    if (!local_subscriber) {\n        z_owned_config_t c2;\n        z_config_default(&c2);\n\n        assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n\n        sub_session = z_loan(s2);\n    }\n\n    z_view_keyexpr_t ke;\n    assert_ok(z_view_keyexpr_from_str(&ke, keyexpr));\n\n    z_owned_closure_sample_t callback;\n    z_owned_fifo_handler_sample_t handler;\n    sample_capture_t capture;\n    if (local_subscriber) {\n        sample_capture_reset(&capture);\n        assert_ok(z_closure_sample(&callback, sample_capture_callback, NULL, &capture));\n    } else {\n        assert_ok(z_fifo_channel_sample_new(&callback, &handler, 1));\n    }\n    z_owned_subscriber_t sub;\n    assert_ok(z_declare_subscriber(sub_session, &sub, z_loan(ke), z_move(callback), NULL));\n    z_sleep_s(1);\n\n    z_owned_bytes_t payload;\n    if (put) {\n        assert_ok(z_bytes_copy_from_str(&payload, test_payload));\n    }\n\n    z_entity_global_id_t egid = _z_entity_global_id_null();\n    uint32_t sn = z_random_u32();\n    if (put && publisher) {\n        z_owned_publisher_t pub;\n        assert_ok(z_declare_publisher(z_loan(s1), &pub, z_loan(ke), NULL));\n        z_sleep_s(1);\n\n        z_publisher_put_options_t opt;\n        z_publisher_put_options_default(&opt);\n        egid = z_publisher_id(z_loan(pub));\n        z_source_info_t si = z_source_info_new(&egid, sn);\n        opt.source_info = &si;\n\n        z_publisher_put(z_loan(pub), z_move(payload), &opt);\n        z_sleep_s(1);\n        assert_ok(z_undeclare_publisher(z_move(pub)));\n    } else if (put) {\n        z_put_options_t opt;\n        z_put_options_default(&opt);\n        egid = z_session_id(z_loan(s1));\n        z_source_info_t si = z_source_info_new(&egid, sn);\n        opt.source_info = &si;\n\n        assert_ok(z_put(z_loan(s1), z_loan(ke), z_move(payload), &opt));\n    } else if (!put && publisher) {\n        z_owned_publisher_t pub;\n        assert_ok(z_declare_publisher(z_loan(s1), &pub, z_loan(ke), NULL));\n        z_sleep_s(1);\n\n        z_publisher_delete_options_t opt;\n        z_publisher_delete_options_default(&opt);\n        egid = z_publisher_id(z_loan(pub));\n        z_source_info_t si = z_source_info_new(&egid, sn);\n        opt.source_info = &si;\n\n        z_publisher_delete(z_loan(pub), &opt);\n        z_sleep_s(1);\n        assert_ok(z_undeclare_publisher(z_move(pub)));\n    } else {\n        z_delete_options_t opt;\n        z_delete_options_default(&opt);\n        egid = z_session_id(z_loan(s1));\n        z_source_info_t si = z_source_info_new(&egid, sn);\n        opt.source_info = &si;\n\n        assert_ok(z_delete(z_loan(s1), z_loan(ke), &opt));\n    }\n    z_sleep_s(1);\n\n    if (local_subscriber) {\n        assert(wait_for_capture(&capture));\n        assert(capture.kind == (put ? Z_SAMPLE_KIND_PUT : Z_SAMPLE_KIND_DELETE));\n        if (put) {\n            assert(capture.payload_ok);\n        }\n        assert_source_info_equal(&egid, sn, &capture.source, capture.sn);\n    } else {\n        z_owned_sample_t sample;\n        z_result_t r = Z_CHANNEL_NODATA;\n        for (int attempt = 0; attempt < 50; ++attempt) {\n            r = z_fifo_handler_sample_try_recv(z_fifo_handler_sample_loan(&handler), &sample);\n            if (r == Z_OK) {\n                break;\n            }\n            assert(r == Z_CHANNEL_NODATA);\n            z_sleep_ms(100);\n        }\n        assert(r == Z_OK);\n\n        if (put) {\n            z_owned_string_t value;\n            assert_ok(z_bytes_to_string(z_sample_payload(z_loan(sample)), &value));\n            assert((sizeof(test_payload) - 1) == z_string_len(z_loan(value)));\n            assert(memcmp(test_payload, z_string_data(z_loan(value)), sizeof(test_payload) - 1) == 0);\n            z_drop(z_move(value));\n        }\n\n        const z_source_info_t *si = z_sample_source_info(z_loan(sample));\n        assert(si != NULL);\n        z_entity_global_id_t gid = z_source_info_id(si);\n        assert_source_info_equal(&egid, sn, &gid, z_source_info_sn(si));\n\n        z_drop(z_move(sample));\n    }\n\n    assert_ok(z_undeclare_subscriber(z_move(sub)));\n\n    if (!local_subscriber) {\n        z_drop(z_move(handler));\n    }\n\n    z_session_drop(z_session_move(&s1));\n\n    if (!local_subscriber) {\n        z_session_drop(z_session_move(&s2));\n    }\n}\n\nvoid test_source_info_put(bool publisher, bool local_subscriber) {\n    printf(\"test_source_info_put: publisher=%d, local_subscriber=%d\\n\", publisher, local_subscriber);\n    test_source_info(true, publisher, local_subscriber);\n}\n\nvoid test_source_info_delete(bool publisher, bool local_subscriber) {\n    printf(\"test_source_info_delete: publisher=%d, local_subscriber=%d\\n\", publisher, local_subscriber);\n    test_source_info(false, publisher, local_subscriber);\n}\n\nvoid test_source_info_query(bool use_querier, bool local_queryable) {\n    printf(\"test_source_info_query: querier=%d, local_queryable=%d\\n\", use_querier, local_queryable);\n\n    z_owned_config_t c1;\n    z_config_default(&c1);\n\n    z_owned_session_t s1;\n    assert_ok(z_open(&s1, z_config_move(&c1), NULL));\n\n    z_owned_session_t s2 = s1;\n    if (!local_queryable) {\n        z_owned_config_t c2;\n        z_config_default(&c2);\n\n        assert_ok(z_open(&s2, z_config_move(&c2), NULL));\n    }\n\n    z_view_keyexpr_t ke;\n    assert_ok(z_view_keyexpr_from_str(&ke, keyexpr));\n\n    z_owned_closure_query_t query_callback;\n    z_owned_closure_reply_t reply_callback;\n    z_owned_fifo_handler_query_t query_handler;\n    z_owned_fifo_handler_reply_t reply_handler;\n\n    z_fifo_channel_query_new(&query_callback, &query_handler, 1);\n    z_fifo_channel_reply_new(&reply_callback, &reply_handler, 1);\n\n    z_owned_queryable_t qbl;\n    assert_ok(z_declare_queryable(z_loan(s2), &qbl, z_loan(ke), z_move(query_callback), NULL));\n    z_sleep_s(1);\n\n    z_entity_global_id_t egid = _z_entity_global_id_null();\n    uint32_t sn = z_random_u32();\n    z_owned_querier_t querier;\n    z_internal_querier_null(&querier);\n    if (use_querier) {\n        assert_ok(z_declare_querier(z_loan(s1), &querier, z_loan(ke), NULL));\n        z_sleep_s(1);\n        z_querier_get_options_t opt;\n        z_querier_get_options_default(&opt);\n        egid = z_querier_id(z_loan(querier));\n        z_source_info_t si = z_source_info_new(&egid, sn);\n        opt.source_info = &si;\n\n        z_querier_get(z_loan(querier), NULL, z_move(reply_callback), &opt);\n    } else {\n        z_get_options_t opt;\n        z_get_options_default(&opt);\n        egid = z_session_id(z_loan(s1));\n        z_source_info_t si = z_source_info_new(&egid, sn);\n        opt.source_info = &si;\n\n        z_get(z_loan(s1), z_loan(ke), NULL, z_move(reply_callback), &opt);\n    }\n    z_sleep_s(1);\n\n    z_owned_query_t q;\n    assert(z_try_recv(z_loan(query_handler), &q) == Z_OK);\n    const z_source_info_t *si = z_query_source_info(z_loan(q));\n    assert(si != NULL);\n    assert_source_info_equal(&egid, sn, &si->_source_id, si->_source_sn);\n\n    z_query_reply_options_t opts;\n    z_query_reply_options_default(&opts);\n    egid = z_queryable_id(z_loan(qbl));\n    sn = z_random_u32();\n    z_source_info_t si2 = z_source_info_new(&egid, sn);\n    opts.source_info = &si2;\n    z_query_reply(z_loan(q), z_loan(ke), NULL, &opts);\n    z_query_drop(z_move(q));\n\n    z_sleep_s(1);\n    z_owned_reply_t r;\n    assert(z_try_recv(z_loan(reply_handler), &r) == Z_OK);\n    assert(z_reply_is_ok(z_loan(r)));\n    si = z_sample_source_info(z_reply_ok(z_loan(r)));\n    assert(si != NULL);\n    assert_source_info_equal(&egid, sn, &si->_source_id, si->_source_sn);\n    z_reply_drop(z_move(r));\n\n    z_drop(z_move(qbl));\n    z_drop(z_move(query_handler));\n    z_drop(z_move(reply_handler));\n    z_drop(z_move(querier));\n\n    z_drop(z_move(s1));\n    if (!local_queryable) {\n        z_drop(z_move(s2));\n    }\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_source_info_put(false, false);\n    test_source_info_delete(false, false);\n    test_source_info_put(true, false);\n    test_source_info_delete(true, false);\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    test_source_info_put(false, true);\n    test_source_info_put(true, true);\n#endif\n    test_source_info_query(false, false);\n    test_source_info_query(true, false);\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    test_source_info_query(false, true);\n    test_source_info_query(true, true);\n#endif\n}\n\n#else\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n}\n#endif\n"
  },
  {
    "path": "tests/z_background_executor_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n\n#include \"zenoh-pico/runtime/background_executor.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_MULTI_THREAD == 1\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\n// Shared state between the test thread and the background executor thread.\n// All fields are protected by mutex + condvar except where noted.\ntypedef struct {\n    _z_mutex_t mutex;\n    _z_condvar_t condvar;\n    int call_count;         // number of times fn body was entered\n    bool destroyed;         // destroy_fn was called\n    unsigned long wait_ms;  // wait for timed part of fn_reschedule_once\n} test_arg_t;\n\nstatic void test_arg_init(test_arg_t *a) {\n    _z_mutex_init(&a->mutex);\n    _z_condvar_init(&a->condvar);\n    a->call_count = 0;\n    a->destroyed = false;\n    a->wait_ms = 0;\n}\n\nstatic void test_arg_clear(test_arg_t *a) {\n    _z_condvar_drop(&a->condvar);\n    _z_mutex_drop(&a->mutex);\n}\n\n// Block until call_count >= expected.\nstatic void test_arg_wait_calls(test_arg_t *a, int expected) {\n    _z_mutex_lock(&a->mutex);\n    while (a->call_count < expected) {\n        _z_condvar_wait(&a->condvar, &a->mutex);\n    }\n    _z_mutex_unlock(&a->mutex);\n}\n\nstatic int test_arg_get_calls(test_arg_t *a) {\n    _z_mutex_lock(&a->mutex);\n    int calls = a->call_count;\n    _z_mutex_unlock(&a->mutex);\n    return calls;\n}\n\nstatic int test_arg_get_destroyed(test_arg_t *a) {\n    _z_mutex_lock(&a->mutex);\n    bool destroyed = a->destroyed;\n    _z_mutex_unlock(&a->mutex);\n    return destroyed;\n}\n\n// Block until destroyed == true.\nstatic void test_arg_wait_destroyed(test_arg_t *a) {\n    _z_mutex_lock(&a->mutex);\n    while (!a->destroyed) {\n        _z_condvar_wait(&a->condvar, &a->mutex);\n    }\n    _z_mutex_unlock(&a->mutex);\n}\n\n// ── fut_fn helpers ────────────────────────────────────────────────────────────\n\n// Increments call_count and finishes immediately.\nstatic _z_fut_fn_result_t fn_finish(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    _z_mutex_lock(&a->mutex);\n    a->call_count++;\n    _z_condvar_signal_all(&a->condvar);\n    _z_mutex_unlock(&a->mutex);\n    return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_READY};\n}\n\n// Reschedules with immediate wake_up_time on first call, finishes on second.\nstatic _z_fut_fn_result_t fn_reschedule_once(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    _z_mutex_lock(&a->mutex);\n    int count = ++a->call_count;\n    _z_condvar_signal_all(&a->condvar);\n    _z_mutex_unlock(&a->mutex);\n    z_clock_t wake = z_clock_now();\n    z_clock_advance_ms(&wake, a->wait_ms);\n    if (count == 1) {\n        return (_z_fut_fn_result_t){\n            ._status = _Z_FUT_STATUS_SLEEPING,\n            ._wake_up_time = wake,\n        };\n    }\n    return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_READY};\n}\n\nstatic void destroy_fn(void *arg) {\n    test_arg_t *a = (test_arg_t *)arg;\n    _z_mutex_lock(&a->mutex);\n    a->destroyed = true;\n    _z_condvar_signal_all(&a->condvar);\n    _z_mutex_unlock(&a->mutex);\n}\n\n// ─── Tests ───────────────────────────────────────────────────────────────────\n\n// _z_background_executor_init + _z_background_executor_destroy with no tasks.\nstatic void test_new_destroy_no_tasks(void) {\n    printf(\"Test: new and destroy with no tasks\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n    _z_background_executor_destroy(&be);\n}\n\n// A spawned future runs on the background thread; destroy_fn is called.\nstatic void test_spawn_runs_task(void) {\n    printf(\"Test: spawn runs task on background thread and calls destroy_fn\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n\n    test_arg_wait_calls(&arg, 1);\n    assert(arg.call_count == 1);\n\n    test_arg_wait_destroyed(&arg);\n    assert(arg.destroyed == true);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// A future with a handle: cancel before it runs — body never called, destroy_fn called.\nstatic void test_cancel_before_execution(void) {\n    printf(\"Test: cancel before execution prevents body; destroy_fn still called\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    // Suspend so the task cannot be picked up before we cancel it\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h;\n    assert(_z_background_executor_spawn(&be, &fut, &h) == _Z_RES_OK);\n    assert(!_z_fut_handle_is_null(h));\n\n    // Cancel while executor is suspended\n    assert(_z_background_executor_cancel_fut(&be, &h) == _Z_RES_OK);\n    _z_fut_status_t status;\n    assert(_z_background_executor_get_fut_status(&be, &h, &status) == _Z_RES_OK);\n    assert(status == _Z_FUT_STATUS_READY);  // cancelled tasks are considered ready (not pending, running, or sleeping);\n\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n\n    // destroy_fn must be called even though the task was cancelled\n    test_arg_wait_destroyed(&arg);\n    assert(arg.destroyed == true);\n    assert(arg.call_count == 0);  // body never ran\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// A future with timed reschedule runs exactly twice.\nstatic void test_timed_reschedule_runs_twice(void) {\n    printf(\"Test: timed reschedule runs task body exactly twice\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n    arg.wait_ms = 500;\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_reschedule_once, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n\n    z_sleep_ms(100);                        // give the background thread a chance to run the first call and reschedule\n    assert(test_arg_get_calls(&arg) == 1);  // first call must have happened, but not the second yet\n    assert(test_arg_get_destroyed(&arg) == false);  // destroy_fn must not have been called yet\n    z_sleep_ms(500);                                // wait for the rescheduled call to become ready and run\n    assert(test_arg_get_calls(&arg) == 2);\n    assert(test_arg_get_destroyed(&arg) == true);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Tasks do not run while the executor is suspended; they run after resume.\nstatic void test_suspend_blocks_execution(void) {\n    printf(\"Test: tasks do not run while suspended; run after resume\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n\n    // Give the background thread ample opportunity to (incorrectly) run the task\n    z_sleep_ms(100);\n    _z_mutex_lock(&arg.mutex);\n    int calls_while_suspended = arg.call_count;\n    _z_mutex_unlock(&arg.mutex);\n    assert(calls_while_suspended == 0);  // must not have run yet\n\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n\n    test_arg_wait_calls(&arg, 1);\n    assert(arg.call_count == 1);\n\n    test_arg_wait_destroyed(&arg);\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Nested suspend/resume: execution resumes only after all suspenders have resumed.\nstatic void test_nested_suspend_resume(void) {\n    printf(\"Test: nested suspend/resume — task runs only after all resumes\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    // Two independent suspenders\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n\n    z_sleep_ms(100);\n    _z_mutex_lock(&arg.mutex);\n    assert(arg.call_count == 0);\n    _z_mutex_unlock(&arg.mutex);\n\n    // First resume — still one suspender outstanding\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n    z_sleep_ms(100);\n    _z_mutex_lock(&arg.mutex);\n    assert(arg.call_count == 0);\n    _z_mutex_unlock(&arg.mutex);\n\n    // Second resume — now fully unblocked\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n    test_arg_wait_calls(&arg, 1);\n    assert(arg.call_count == 1);\n\n    test_arg_wait_destroyed(&arg);\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Multiple concurrent tasks all complete.\nstatic void test_multiple_tasks_all_complete(void) {\n    printf(\"Test: multiple concurrent tasks all complete\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    const int N = 8;\n    test_arg_t args[8];\n    z_clock_t start = z_clock_now();\n    for (int i = 0; i < N; i++) {\n        test_arg_init(&args[i]);\n        args[i].wait_ms = (unsigned long)(300 * (i + 1));  // stagger the wait times so tasks finish in order\n        _z_fut_t fut = _z_fut_new(&args[i], fn_reschedule_once, destroy_fn);\n        assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n    }\n\n    for (int i = 0; i < N; i++) {\n        test_arg_wait_calls(&args[i], 2);\n        test_arg_wait_destroyed(&args[i]);\n        z_clock_t now = z_clock_now();\n        unsigned long elapsed_ms = zp_clock_elapsed_ms_since(&now, &start);\n        assert(args[i].call_count == 2);\n        assert(args[i].destroyed == true);\n        assert(elapsed_ms >=\n               args[i].wait_ms);  // each task must have taken at least as long as its wait time, indicating it\n        assert(elapsed_ms <= args[i].wait_ms + 300);  // but not too much longer\n    }\n\n    _z_background_executor_destroy(&be);\n    for (int i = 0; i < N; i++) {\n        test_arg_clear(&args[i]);\n    }\n}\n\n// destroy while tasks are pending: destroy_fn is called for each.\nstatic void test_destroy_with_pending_tasks(void) {\n    printf(\"Test: destroy calls destroy_fn on all pending tasks\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    const int N = 4;\n    test_arg_t args[4];\n\n    // Queue tasks while suspended so none run before destroy\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n    for (int i = 0; i < N; i++) {\n        test_arg_init(&args[i]);\n        _z_fut_t fut = _z_fut_new(&args[i], fn_finish, destroy_fn);\n        assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n    }\n    // Resume so the background thread can process cancellations on destroy\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n\n    // Destroy immediately — some or all tasks may not have run yet\n    _z_background_executor_destroy(&be);\n\n    // Every destroy_fn must have been called by now (destroy is synchronous)\n    for (int i = 0; i < N; i++) {\n        assert(args[i].destroyed == true);\n        test_arg_clear(&args[i]);\n    }\n}\n\n// Handle status is PENDING before execution, READY after.\nstatic void test_handle_status_transitions(void) {\n    printf(\"Test: handle status transitions PENDING -> READY\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h;\n    assert(_z_background_executor_spawn(&be, &fut, &h) == _Z_RES_OK);\n    _z_fut_status_t status;\n    assert(_z_background_executor_get_fut_status(&be, &h, &status) == _Z_RES_OK);\n    assert(status == _Z_FUT_STATUS_RUNNING);\n\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n\n    test_arg_wait_calls(&arg, 1);\n    assert(_z_background_executor_get_fut_status(&be, &h, &status) == _Z_RES_OK);\n    assert(status == _Z_FUT_STATUS_READY);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Deferred init: create without thread, add tasks, then start.\nstatic void test_deferred_init_and_start(void) {\n    printf(\"Test: deferred init allows adding tasks before start\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init_deferred(&be) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    // Spawn a task before the executor thread is running\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h;\n    assert(_z_background_executor_spawn(&be, &fut, &h) == _Z_RES_OK);\n    assert(!_z_fut_handle_is_null(h));\n\n    // Task should be pending but not executed\n    _z_fut_status_t status;\n    assert(_z_background_executor_get_fut_status(&be, &h, &status) == _Z_RES_OK);\n    assert(status == _Z_FUT_STATUS_RUNNING);\n\n    z_sleep_ms(100);\n    assert(test_arg_get_calls(&arg) == 0);  // no thread running, so task cannot execute\n\n    // Now start the background thread\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n\n    // Task should now execute\n    test_arg_wait_calls(&arg, 1);\n    assert(arg.call_count == 1);\n    test_arg_wait_destroyed(&arg);\n    assert(arg.destroyed == true);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Deferred init: destroy without ever starting should clean up properly.\nstatic void test_deferred_destroy_without_start(void) {\n    printf(\"Test: deferred init + destroy without start cleans up\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init_deferred(&be) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut, NULL) == _Z_RES_OK);\n\n    // Destroy without starting — destroy_fn must still be called\n    _z_background_executor_destroy(&be);\n    assert(arg.destroyed == true);\n    assert(arg.call_count == 0);  // body never ran\n\n    test_arg_clear(&arg);\n}\n\n// Deferred init: starting second time is no-op.\nstatic void test_deferred_second_start_is_no_op(void) {\n    printf(\"Test: deferred init + double start is no-op\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init_deferred(&be) == _Z_RES_OK);\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n    _z_background_executor_destroy(&be);\n}\n\n// Deferred init: cancel a task before starting, then start — cancelled task should not run.\nstatic void test_deferred_cancel_before_start(void) {\n    printf(\"Test: deferred init + cancel before start\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init_deferred(&be) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h;\n    assert(_z_background_executor_spawn(&be, &fut, &h) == _Z_RES_OK);\n\n    // Cancel before starting\n    assert(_z_background_executor_cancel_fut(&be, &h) == _Z_RES_OK);\n    _z_fut_status_t status;\n    assert(_z_background_executor_get_fut_status(&be, &h, &status) == _Z_RES_OK);\n    assert(status == _Z_FUT_STATUS_READY);\n\n    // Start the executor\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n\n    // Give it time, but the task should never run\n    z_sleep_ms(100);\n    assert(test_arg_get_calls(&arg) == 0);\n    assert(test_arg_get_destroyed(&arg) == true);  // destroy_fn must have been called on cancel\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Stop a running executor, verify tasks don't execute, then restart.\nstatic void test_stop_and_restart(void) {\n    printf(\"Test: stop and restart executor\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    // Run a task to confirm executor is working\n    test_arg_t arg1;\n    test_arg_init(&arg1);\n    _z_fut_t fut1 = _z_fut_new(&arg1, fn_finish, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut1, NULL) == _Z_RES_OK);\n    test_arg_wait_calls(&arg1, 1);\n    assert(test_arg_get_calls(&arg1) == 1);\n\n    // Stop the executor\n    assert(_z_background_executor_stop(&be) == _Z_RES_OK);\n\n    // Stopping again should be a no-op (idempotent)\n    assert(_z_background_executor_stop(&be) == _Z_RES_OK);\n\n    // Spawn a task while stopped — should succeed but not execute\n    test_arg_t arg2;\n    test_arg_init(&arg2);\n    _z_fut_t fut2 = _z_fut_new(&arg2, fn_finish, destroy_fn);\n    _z_fut_handle_t h2;\n    assert(_z_background_executor_spawn(&be, &fut2, &h2) == _Z_RES_OK);\n    z_sleep_ms(100);\n    assert(test_arg_get_calls(&arg2) == 0);\n\n    // Restart the executor\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n\n    // The pending task should now execute\n    test_arg_wait_calls(&arg2, 1);\n    assert(test_arg_get_calls(&arg2) == 1);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg1);\n    test_arg_clear(&arg2);\n}\n\n// Stop executor with pending tasks — tasks should be preserved, not destroyed.\nstatic void test_stop_preserves_pending_tasks(void) {\n    printf(\"Test: stop preserves pending tasks\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    // Suspend so the task doesn't run before we stop\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n\n    test_arg_t arg;\n    test_arg_init(&arg);\n    arg.wait_ms = 500;  // ensure the task would still be pending after we stop\n    _z_fut_t fut = _z_fut_new(&arg, fn_reschedule_once, destroy_fn);\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n    _z_fut_handle_t h;\n    assert(_z_background_executor_spawn(&be, &fut, &h) == _Z_RES_OK);\n    // Stop the executor — task should still be pending, destroy_fn should NOT have been called\n    assert(_z_background_executor_stop(&be) == _Z_RES_OK);\n    z_sleep_ms(1000);\n\n    _z_fut_status_t status;\n    assert(_z_background_executor_get_fut_status(&be, &h, &status) == _Z_RES_OK);\n    assert(status != _Z_FUT_STATUS_READY);\n    assert(arg.destroyed == false);\n\n    // Restart and let it complete\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n    z_sleep_ms(1000);  // give it time to run the first call and reschedule\n    test_arg_wait_calls(&arg, 2);\n    test_arg_wait_destroyed(&arg);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg);\n}\n\n// Suspend executor, than verify that stopping does not hang, nor causes pending tasks to be destroyed.\n// Then restart and verify pending tasks still run.\nstatic void test_suspend_stop_restart_resume(void) {\n    printf(\"Test: suspend-stop-restart-resume executor\\n\");\n    _z_background_executor_t be;\n    assert(_z_background_executor_init(&be, NULL) == _Z_RES_OK);\n\n    // Suspend the executor so tasks won't run until we explicitly resume\n    assert(_z_background_executor_suspend(&be) == _Z_RES_OK);\n\n    // Run a task to confirm executor is working\n    test_arg_t arg1;\n    test_arg_init(&arg1);\n    _z_fut_t fut1 = _z_fut_new(&arg1, fn_finish, destroy_fn);\n    assert(_z_background_executor_spawn(&be, &fut1, NULL) == _Z_RES_OK);\n    // Ensure that stopping suspended executor works\n    assert(_z_background_executor_stop(&be) == _Z_RES_OK);\n    z_sleep_ms(500);  // give it time to (incorrectly) run if stop didn't work\n    assert(test_arg_get_calls(&arg1) == 0);\n    assert(test_arg_get_destroyed(&arg1) == false);\n\n    // Restart the executor\n    assert(_z_background_executor_start(&be, NULL) == _Z_RES_OK);\n    // Resume the executor so the pending task can run\n    assert(_z_background_executor_resume(&be) == _Z_RES_OK);\n\n    z_sleep_ms(500);  // give it time to (incorrectly) run if stop didn't work\n    assert(test_arg_get_calls(&arg1) == 1);\n    assert(test_arg_get_destroyed(&arg1) == true);\n\n    _z_background_executor_destroy(&be);\n    test_arg_clear(&arg1);\n}\n\n// ─── main ────────────────────────────────────────────────────────────────────\n\nint main(void) {\n    test_new_destroy_no_tasks();\n    test_spawn_runs_task();\n    test_cancel_before_execution();\n    test_timed_reschedule_runs_twice();\n    test_suspend_blocks_execution();\n    test_nested_suspend_resume();\n    test_multiple_tasks_all_complete();\n    test_destroy_with_pending_tasks();\n    test_handle_status_transitions();\n    test_deferred_init_and_start();\n    test_deferred_destroy_without_start();\n    test_deferred_second_start_is_no_op();\n    test_deferred_cancel_before_start();\n    test_stop_and_restart();\n    test_stop_preserves_pending_tasks();\n    test_suspend_stop_restart_resume();\n    printf(\"All background executor tests passed.\\n\");\n    return 0;\n}\n\n#else\n\nint main(void) {\n    printf(\"Skipping background executor tests (Z_FEATURE_MULTI_THREAD disabled)\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_bytes_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/collections/bytes.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nvoid test_null_bytes(void) {\n    _z_bytes_t b = _z_bytes_null();\n    assert(_z_bytes_len(&b) == 0);\n    assert(_z_bytes_is_empty(&b));\n    assert(!_z_bytes_check(&b));\n    assert(_z_bytes_num_slices(&b) == 0);\n    _z_bytes_drop(&b);  // no crush\n}\n\nvoid test_slice(void) {\n    uint8_t data[5] = {1, 2, 3, 4, 5};\n    uint8_t data_out[5] = {0};\n    _z_slice_t s = _z_slice_copy_from_buf(data, 5);\n    _z_bytes_t b;\n    _z_bytes_from_slice(&b, &s);\n\n    assert(_z_bytes_len(&b) == 5);\n    assert(!_z_bytes_is_empty(&b));\n    assert(_z_bytes_check(&b));\n    assert(_z_bytes_num_slices(&b) == 1);\n    assert(_z_slice_eq(_z_slice_simple_rc_value(&_z_bytes_get_slice(&b, 0)->slice), &s));\n\n    assert(_z_bytes_to_buf(&b, data_out, 5) == 5);\n    assert(memcmp(data, data_out, 5) == 0);\n\n    _z_bytes_drop(&b);\n}\n\nvoid test_append(void) {\n    uint8_t data1[5] = {1, 2, 3, 4, 5};\n    uint8_t data2[5] = {1, 2, 6, 7, 8};\n    uint8_t data3[3] = {3, 9, 10};\n    uint8_t data_in[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n    uint8_t data_out[10] = {0};\n\n    _z_slice_t tmp1 = _z_slice_copy_from_buf(data1, 5);\n    _z_slice_t tmp2 = _z_slice_copy_from_buf(data2, 5);\n    _z_slice_t tmp3 = _z_slice_copy_from_buf(data3, 3);\n    _z_arc_slice_t s1 = _z_arc_slice_wrap(&tmp1, 0, 5);\n    _z_arc_slice_t s2 = _z_arc_slice_wrap(&tmp2, 2, 3);\n    _z_arc_slice_t s3 = _z_arc_slice_wrap(&tmp3, 1, 2);\n\n    _z_bytes_t b = _z_bytes_null();\n\n    _z_bytes_append_slice(&b, &s1);\n    _z_bytes_append_slice(&b, &s2);\n    _z_bytes_append_slice(&b, &s3);\n\n    assert(_z_bytes_len(&b) == 10);\n    assert(!_z_bytes_is_empty(&b));\n    assert(_z_bytes_check(&b));\n    assert(_z_bytes_num_slices(&b) == 3);\n    assert(\n        _z_slice_eq(_z_slice_simple_rc_value(&_z_bytes_get_slice(&b, 0)->slice), _z_slice_simple_rc_value(&s1.slice)));\n    assert(\n        _z_slice_eq(_z_slice_simple_rc_value(&_z_bytes_get_slice(&b, 1)->slice), _z_slice_simple_rc_value(&s2.slice)));\n    assert(\n        _z_slice_eq(_z_slice_simple_rc_value(&_z_bytes_get_slice(&b, 2)->slice), _z_slice_simple_rc_value(&s3.slice)));\n\n    assert(_z_bytes_to_buf(&b, data_out, 15) == 10);\n    assert(memcmp(data_in, data_out, 10) == 0);\n\n    _z_bytes_drop(&b);\n}\n\nvoid test_reader_read(void) {\n    uint8_t data1[5] = {1, 2, 3, 4, 5};\n    uint8_t data2[5] = {1, 2, 6, 7, 8};\n    uint8_t data3[3] = {3, 9, 10};\n    uint8_t data_in[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n    uint8_t data_out[10] = {0};\n\n    _z_slice_t tmp1 = _z_slice_copy_from_buf(data1, 5);\n    _z_slice_t tmp2 = _z_slice_copy_from_buf(data2, 5);\n    _z_slice_t tmp3 = _z_slice_copy_from_buf(data3, 3);\n    _z_arc_slice_t s1 = _z_arc_slice_wrap(&tmp1, 0, 5);\n    _z_arc_slice_t s2 = _z_arc_slice_wrap(&tmp2, 2, 3);\n    _z_arc_slice_t s3 = _z_arc_slice_wrap(&tmp3, 1, 2);\n\n    _z_bytes_t b = _z_bytes_null();\n\n    _z_bytes_append_slice(&b, &s1);\n    _z_bytes_append_slice(&b, &s2);\n    _z_bytes_append_slice(&b, &s3);\n\n    _z_bytes_reader_t reader = _z_bytes_get_reader(&b);\n\n    uint8_t out;\n    assert(_z_bytes_reader_tell(&reader) == 0);\n    _z_bytes_reader_read(&reader, &out, 1);\n    assert(_z_bytes_reader_tell(&reader) == 1);\n    assert(out == 1);\n\n    _z_bytes_reader_read(&reader, data_out, 3);\n    assert(_z_bytes_reader_tell(&reader) == 4);\n    assert(memcmp(data_out, data_in + 1, 3) == 0);\n\n    _z_bytes_reader_read(&reader, data_out, 6);\n    assert(_z_bytes_reader_tell(&reader) == 10);\n    assert(memcmp(data_out, data_in + 4, 6) == 0);\n\n    _z_bytes_drop(&b);\n}\n\nvoid test_reader_seek(void) {\n    uint8_t data1[5] = {1, 2, 3, 4, 5};\n    uint8_t data2[5] = {1, 2, 6, 7, 8};\n    uint8_t data3[3] = {3, 9, 10};\n\n    _z_slice_t tmp1 = _z_slice_copy_from_buf(data1, 5);\n    _z_slice_t tmp2 = _z_slice_copy_from_buf(data2, 5);\n    _z_slice_t tmp3 = _z_slice_copy_from_buf(data3, 3);\n    _z_arc_slice_t s1 = _z_arc_slice_wrap(&tmp1, 0, 5);\n    _z_arc_slice_t s2 = _z_arc_slice_wrap(&tmp2, 2, 3);\n    _z_arc_slice_t s3 = _z_arc_slice_wrap(&tmp3, 1, 2);\n\n    _z_bytes_t b = _z_bytes_null();\n\n    _z_bytes_append_slice(&b, &s1);\n    _z_bytes_append_slice(&b, &s2);\n    _z_bytes_append_slice(&b, &s3);\n\n    _z_bytes_reader_t reader = _z_bytes_get_reader(&b);\n\n    assert(_z_bytes_reader_tell(&reader) == 0);\n    assert(_z_bytes_reader_seek(&reader, 3, SEEK_CUR) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 3);\n    assert(_z_bytes_reader_seek(&reader, 5, SEEK_CUR) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 8);\n    assert(_z_bytes_reader_seek(&reader, 10, SEEK_CUR) != 0);\n\n    assert(_z_bytes_reader_seek(&reader, 0, SEEK_SET) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 0);\n\n    assert(_z_bytes_reader_seek(&reader, 3, SEEK_SET) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 3);\n    assert(_z_bytes_reader_seek(&reader, 8, SEEK_SET) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 8);\n    assert(_z_bytes_reader_seek(&reader, 20, SEEK_SET) != 0);\n    assert(_z_bytes_reader_seek(&reader, -20, SEEK_SET) != 0);\n\n    assert(_z_bytes_reader_seek(&reader, 0, SEEK_END) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 10);\n    assert(_z_bytes_reader_seek(&reader, -3, SEEK_END) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 7);\n    assert(_z_bytes_reader_seek(&reader, -8, SEEK_END) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 2);\n    assert(_z_bytes_reader_seek(&reader, -10, SEEK_END) == 0);\n    assert(_z_bytes_reader_tell(&reader) == 0);\n    assert(_z_bytes_reader_seek(&reader, -20, SEEK_END) != 0);\n    assert(_z_bytes_reader_seek(&reader, 5, SEEK_END) != 0);\n\n    _z_bytes_drop(&b);\n}\n\nvoid test_writer(void) {\n    uint8_t data1[5] = {1, 2, 3, 4, 5};\n    uint8_t data2[5] = {1, 2, 6, 7, 8};\n    uint8_t data3[3] = {3, 9, 10};\n\n    uint8_t data1_out[5] = {1, 2, 3, 4, 5};\n    uint8_t data2_out[8] = {1, 2, 6, 7, 8, 3, 9, 10};\n\n    _z_bytes_writer_t writer = _z_bytes_writer_empty();\n\n    _z_bytes_writer_write_all(&writer, data1, 5);\n    _z_bytes_writer_write_all(&writer, data2, 5);\n    _z_bytes_writer_write_all(&writer, data3, 3);\n    _z_bytes_t b = _z_bytes_writer_finish(&writer);\n\n    assert(_z_bytes_len(&b) == 13);\n    assert(_z_bytes_num_slices(&b) == 2);\n\n    assert(_z_arc_slice_len(_z_bytes_get_slice(&b, 0)) == 5);\n    assert(_z_arc_slice_len(_z_bytes_get_slice(&b, 1)) == 8);\n    assert(memcmp(data1_out, _z_arc_slice_data(_z_bytes_get_slice(&b, 0)), 5) == 0);\n    assert(memcmp(data2_out, _z_arc_slice_data(_z_bytes_get_slice(&b, 1)), 8) == 0);\n    _z_bytes_drop(&b);\n}\n\nint main(void) {\n    test_null_bytes();\n    test_slice();\n    test_append();\n    test_reader_read();\n    test_reader_seek();\n    test_writer();\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_cancellation_token_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\ntypedef struct {\n    size_t called;\n    size_t dropped;\n} token_handler_arg_t;\n\nz_result_t cancel_callback(void* arg) {\n    token_handler_arg_t* typed = (token_handler_arg_t*)arg;\n    (typed->called)++;\n    return Z_OK;\n}\n\nvoid cancel_drop(void* arg) {\n    token_handler_arg_t* typed = (token_handler_arg_t*)arg;\n    (typed->dropped)++;\n}\n\nvoid test_cancellation_token_cancel(void) {\n    _z_cancellation_token_t ct;\n    assert(_z_cancellation_token_create(&ct) == Z_OK);\n\n    token_handler_arg_t arg1 = {0};\n    token_handler_arg_t arg2 = {0};\n    _z_cancellation_token_on_cancel_handler_t h1 = {\n        ._arg = &arg1, ._on_cancel = cancel_callback, ._on_drop = cancel_drop};\n    _z_cancellation_token_on_cancel_handler_t h2 = {\n        ._arg = &arg2, ._on_cancel = cancel_callback, ._on_drop = cancel_drop};\n\n    _z_sync_group_notifier_t notifier;\n    assert(_z_cancellation_token_get_notifier(&ct, &notifier) == _Z_RES_OK);\n    size_t id1, id2;\n    assert(_z_cancellation_token_add_on_cancel_handler(&ct, &h1, &id1) == Z_OK);\n    assert(_z_cancellation_token_add_on_cancel_handler(&ct, &h2, &id2) == Z_OK);\n    _z_sync_group_notifier_drop(&notifier);\n    assert(!_z_cancellation_token_is_cancelled(&ct));\n    assert(_z_cancellation_token_cancel(&ct) == Z_OK);\n    assert(_z_cancellation_token_is_cancelled(&ct));\n    assert(arg1.called == 1);\n    assert(arg1.dropped == 1);\n    assert(arg2.called == 1);\n    assert(arg2.dropped == 1);\n    _z_cancellation_token_clear(&ct);\n}\n\nvoid test_cancellation_token_cancel_timeout(void) {\n    _z_cancellation_token_t ct;\n    assert(_z_cancellation_token_create(&ct) == Z_OK);\n\n    token_handler_arg_t arg1 = {0};\n    token_handler_arg_t arg2 = {0};\n    _z_cancellation_token_on_cancel_handler_t h1 = {\n        ._arg = &arg1, ._on_cancel = cancel_callback, ._on_drop = cancel_drop};\n    _z_cancellation_token_on_cancel_handler_t h2 = {\n        ._arg = &arg2, ._on_cancel = cancel_callback, ._on_drop = cancel_drop};\n\n    _z_sync_group_notifier_t notifier;\n    assert(_z_cancellation_token_get_notifier(&ct, &notifier) == _Z_RES_OK);\n    size_t id1, id2;\n    assert(_z_cancellation_token_add_on_cancel_handler(&ct, &h1, &id1) == Z_OK);\n    assert(_z_cancellation_token_add_on_cancel_handler(&ct, &h2, &id2) == Z_OK);\n\n    assert(!_z_cancellation_token_is_cancelled(&ct));\n    assert(_z_cancellation_token_cancel_with_timeout(&ct, 1000) == Z_ETIMEDOUT);\n    assert(!_z_cancellation_token_is_cancelled(&ct));\n\n    _z_sync_group_notifier_drop(&notifier);\n    assert(_z_cancellation_token_cancel_with_timeout(&ct, 1000) == _Z_RES_OK);\n    assert(_z_cancellation_token_is_cancelled(&ct));\n    _z_cancellation_token_clear(&ct);\n}\n\nvoid test_cancellation_token_remove_handler(void) {\n    _z_cancellation_token_t ct;\n    assert(_z_cancellation_token_create(&ct) == Z_OK);\n\n    token_handler_arg_t arg1 = {0};\n    token_handler_arg_t arg2 = {0};\n    _z_cancellation_token_on_cancel_handler_t h1 = {\n        ._arg = &arg1, ._on_cancel = cancel_callback, ._on_drop = cancel_drop};\n    _z_cancellation_token_on_cancel_handler_t h2 = {\n        ._arg = &arg2, ._on_cancel = cancel_callback, ._on_drop = cancel_drop};\n\n    _z_sync_group_notifier_t notifier;\n    assert(_z_cancellation_token_get_notifier(&ct, &notifier) == _Z_RES_OK);\n    size_t id1, id2;\n    assert(_z_cancellation_token_add_on_cancel_handler(&ct, &h1, &id1) == Z_OK);\n    assert(_z_cancellation_token_add_on_cancel_handler(&ct, &h2, &id2) == Z_OK);\n    assert(_z_cancellation_token_remove_on_cancel_handler(&ct, id2) == Z_OK);\n    assert(arg2.dropped == 1);\n\n    _z_sync_group_notifier_drop(&notifier);\n    assert(!_z_cancellation_token_is_cancelled(&ct));\n    assert(_z_cancellation_token_cancel(&ct) == Z_OK);\n    assert(_z_cancellation_token_is_cancelled(&ct));\n    assert(arg1.called == 1);\n    assert(arg1.dropped == 1);\n    assert(arg2.called == 0);\n\n    _z_cancellation_token_clear(&ct);\n}\n\nint main(void) {\n    test_cancellation_token_cancel();\n    test_cancellation_token_cancel_timeout();\n    test_cancellation_token_remove_handler();\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_channels_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <assert.h>\n#include <stddef.h>\n\n#include \"zenoh-pico/api/handlers.h\"\n#include \"zenoh-pico/api/macros.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define SEND(closure, v)                                                    \\\n    do {                                                                    \\\n        _z_bytes_t payload;                                                 \\\n        _z_slice_t slice = {.start = (const uint8_t *)v, .len = strlen(v)}; \\\n        _z_bytes_from_slice(&payload, &slice);                              \\\n        z_loaned_sample_t sample = {                                        \\\n            .keyexpr = _z_declared_keyexpr_alias_from_str(\"key\"),           \\\n            .payload = payload,                                             \\\n            .timestamp = _z_timestamp_null(),                               \\\n            .encoding = _z_encoding_null(),                                 \\\n            .kind = 0,                                                      \\\n            .qos = {0},                                                     \\\n            .attachment = _z_bytes_null(),                                  \\\n        };                                                                  \\\n        z_call(*z_loan(closure), &sample);                                  \\\n    } while (0);\n\n#define _RECV(handler, method, buf)                                             \\\n    do {                                                                        \\\n        z_owned_sample_t sample;                                                \\\n        z_result_t res = method(z_loan(handler), &sample);                      \\\n        if (res == Z_CHANNEL_DISCONNECTED) {                                    \\\n            strcpy(buf, \"closed\");                                              \\\n        } else if (res == Z_OK) {                                               \\\n            z_owned_slice_t value;                                              \\\n            z_bytes_to_slice(z_sample_payload(z_loan(sample)), &value);         \\\n            size_t value_len = z_slice_len(z_loan(value));                      \\\n            strncpy(buf, (const char *)z_slice_data(z_loan(value)), value_len); \\\n            buf[value_len] = '\\0';                                              \\\n            z_drop(z_move(sample));                                             \\\n            z_drop(z_move(value));                                              \\\n        } else if (res == Z_CHANNEL_NODATA) {                                   \\\n            strcpy(buf, \"nodata\");                                              \\\n        }                                                                       \\\n    } while (0);\n\n#define RECV(handler, buf) _RECV(handler, z_recv, buf)\n#define TRY_RECV(handler, buf) _RECV(handler, z_try_recv, buf)\n\nvoid sample_fifo_channel_test(void) {\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    z_fifo_channel_sample_new(&closure, &handler, 10);\n\n    SEND(closure, \"v1\")\n    SEND(closure, \"v22\")\n    SEND(closure, \"v333\")\n    SEND(closure, \"v4444\")\n\n    char buf[100];\n\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v1\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v22\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v333\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v4444\") == 0);\n\n    z_drop(z_move(closure));\n\n    RECV(handler, buf)\n    assert(strcmp(buf, \"closed\") == 0);\n\n    z_drop(z_move(handler));\n}\n\nvoid sample_fifo_channel_test_try_recv(void) {\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    z_fifo_channel_sample_new(&closure, &handler, 10);\n\n    char buf[100];\n\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"nodata\") == 0);\n\n    SEND(closure, \"v1\")\n    SEND(closure, \"v22\")\n    SEND(closure, \"v333\")\n    SEND(closure, \"v4444\")\n\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"v1\") == 0);\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"v22\") == 0);\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"v333\") == 0);\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"v4444\") == 0);\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"nodata\") == 0);\n\n    z_drop(z_move(closure));\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"closed\") == 0);\n\n    z_drop(z_move(handler));\n}\n\nvoid sample_ring_channel_test_in_size(void) {\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, 10);\n\n    char buf[100];\n\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"nodata\") == 0);\n\n    SEND(closure, \"v1\")\n    SEND(closure, \"v22\")\n    SEND(closure, \"v333\")\n    SEND(closure, \"v4444\")\n\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v1\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v22\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v333\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v4444\") == 0);\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"nodata\") == 0);\n\n    z_drop(z_move(closure));\n    RECV(handler, buf)\n    assert(strcmp(buf, \"closed\") == 0);\n\n    z_drop(z_move(handler));\n}\n\nvoid sample_ring_channel_test_over_size(void) {\n    z_owned_closure_sample_t closure;\n    z_owned_ring_handler_sample_t handler;\n    z_ring_channel_sample_new(&closure, &handler, 3);\n\n    char buf[100];\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"nodata\") == 0);\n\n    SEND(closure, \"v1\")\n    SEND(closure, \"v22\")\n    SEND(closure, \"v333\")\n    SEND(closure, \"v4444\")\n\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v22\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v333\") == 0);\n    RECV(handler, buf)\n    assert(strcmp(buf, \"v4444\") == 0);\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"nodata\") == 0);\n    z_drop(z_move(closure));\n    TRY_RECV(handler, buf)\n    assert(strcmp(buf, \"closed\") == 0);\n\n    z_drop(z_move(handler));\n}\n\nvoid zero_size_test(void) {\n    z_owned_closure_sample_t closure;\n\n    z_owned_fifo_handler_sample_t fifo_handler;\n    assert(z_fifo_channel_sample_new(&closure, &fifo_handler, 0) != Z_OK);\n    assert(z_fifo_channel_sample_new(&closure, &fifo_handler, 1) == Z_OK);\n    z_drop(z_move(closure));\n    z_drop(z_move(fifo_handler));\n\n    z_owned_ring_handler_sample_t ring_handler;\n    assert(z_ring_channel_sample_new(&closure, &ring_handler, 0) != Z_OK);\n    assert(z_ring_channel_sample_new(&closure, &ring_handler, 1) == Z_OK);\n    z_drop(z_move(closure));\n    z_drop(z_move(ring_handler));\n}\n\nint main(void) {\n    sample_fifo_channel_test();\n    sample_fifo_channel_test_try_recv();\n    sample_ring_channel_test_in_size();\n    sample_ring_channel_test_over_size();\n    zero_size_test();\n}\n"
  },
  {
    "path": "tests/z_client_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <assert.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/utils/uuid.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define MSG 1000\n#define MSG_LEN 1024\n#define FRAGMENT_MSG_NB 100\n#define FRAGMENT_MSG_LEN 100000\n#define QRY 100\n#define QRY_CLT 10\n#define SET 100\n#define SLEEP 1\n#define TIMEOUT 60\n\nconst char *uri = \"demo/example/\";\nunsigned int idx[SET];\n\n// The active resource, subscriber, queryable declarations\n_z_list_t *pubs1 = NULL;\nz_owned_keyexpr_t rids1[SET];\n\n_z_list_t *subs2 = NULL;\n_z_list_t *qles2 = NULL;\nz_owned_keyexpr_t rids2[SET];\n\nvolatile unsigned int total = 0;\n\nvolatile unsigned int queries = 0;\nvoid query_handler(z_loaned_query_t *query, void *arg) {\n    char *res = (char *)malloc(64);\n    snprintf(res, 64, \"%s%u\", uri, *(unsigned int *)arg);\n    printf(\">> Received query: %s\\t(%u/%u)\\n\", res, queries, total);\n\n    z_view_string_t k_str, res_str;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &k_str);\n    z_view_string_from_str(&res_str, res);\n    assert(_z_string_equals(z_loan(k_str), z_loan(res_str)));\n\n    z_view_string_t pred;\n    z_query_parameters(query, &pred);\n    assert(z_string_len(z_loan(pred)) == 0);\n\n    // Reply value encoding\n    z_owned_bytes_t reply_payload;\n    z_bytes_copy_from_str(&reply_payload, res);\n\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n    queries++;\n    free(res);\n}\n\nvolatile unsigned int replies = 0;\nvoid reply_handler(z_loaned_reply_t *reply, void *arg) {\n    char *res = (char *)malloc(64);\n    snprintf(res, 64, \"%s%u\", uri, *(unsigned int *)arg);\n    if (z_reply_is_ok(reply)) {\n        const z_loaned_sample_t *sample = z_reply_ok(reply);\n        printf(\">> Received reply data: %s\\t(%u/%u)\\n\", res, replies, total);\n\n        z_view_string_t k_str, res_str;\n        z_keyexpr_as_view_string(z_sample_keyexpr(sample), &k_str);\n        z_owned_string_t value;\n        z_bytes_to_string(z_sample_payload(sample), &value);\n        assert(z_string_len(z_loan(value)) == strlen(res));\n        assert(strncmp(res, z_string_data(z_loan(value)), strlen(res)) == 0);\n        z_view_string_from_str(&res_str, res);\n        assert(_z_string_equals(z_loan(k_str), z_loan(res_str)));\n\n        replies++;\n        z_drop(z_move(value));\n    } else {\n        printf(\">> Received an error\\n\");\n    }\n    free(res);\n}\n\nvolatile unsigned int datas = 0;\nvoid data_handler(z_loaned_sample_t *sample, void *arg) {\n    char *res = (char *)malloc(64);\n    snprintf(res, 64, \"%s%u\", uri, *(unsigned int *)arg);\n    printf(\">> Received data: %s\\t(%u/%u)\\n\", res, datas, total);\n\n    _z_string_t res_str = _z_string_alias_str(res);\n    z_view_string_t k_str;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &k_str);\n    z_owned_slice_t value;\n    z_bytes_to_slice(z_sample_payload(sample), &value);\n    size_t payload_len = z_slice_len(z_loan(value));\n    assert((payload_len == MSG_LEN) || (payload_len == FRAGMENT_MSG_LEN));\n    assert(_z_string_equals(z_loan(k_str), &res_str));\n\n    datas++;\n    z_drop(z_move(value));\n    free(res);\n}\n\nint main(int argc, char **argv) {\n    setvbuf(stdout, NULL, _IOLBF, 1024);\n\n    assert(argc >= 2);\n\n    int is_reliable = strncmp(argv[1], \"tcp\", 3) == 0;\n    unsigned int msg_count = MSG;\n    for (int i = 2; i < argc; ++i) {\n        if (strncmp(argv[i], \"--msgs=\", 7) == 0) {\n            msg_count = (unsigned int)strtoul(argv[i] + 7, NULL, 10);\n        }\n    }\n\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, argv[1]);\n\n    for (unsigned int i = 0; i < SET; i++) idx[i] = i;\n\n    z_owned_session_t s1;\n    assert(z_open(&s1, z_move(config), NULL) == Z_OK);\n    _z_string_t zid1 = _z_id_to_string(&(_Z_RC_IN_VAL(z_loan(s1))->_local_zid));\n    printf(\"Session 1 with PID: %.*s\\n\", (int)_z_string_len(&zid1), _z_string_data(&zid1));\n    _z_string_clear(&zid1);\n\n    z_sleep_s(SLEEP);\n\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, argv[1]);\n\n    z_owned_session_t s2;\n    assert(z_open(&s2, z_move(config), NULL) == Z_OK);\n    assert(z_internal_check(s2));\n    _z_string_t zid2 = _z_id_to_string(&(_Z_RC_IN_VAL(z_loan(s2))->_local_zid));\n    printf(\"Session 2 with PID: %.*s\\n\", (int)_z_string_len(&zid2), _z_string_data(&zid2));\n    _z_string_clear(&zid2);\n\n    z_sleep_s(SLEEP);\n\n    // Declare resources on both sessions\n    char *s1_res = (char *)malloc(64);\n    for (unsigned int i = 0; i < SET; i++) {\n        snprintf(s1_res, 64, \"%s%u\", uri, i);\n        z_view_keyexpr_t ke;\n        z_view_keyexpr_from_str(&ke, s1_res);\n        z_owned_keyexpr_t expr;\n        z_declare_keyexpr(z_loan(s1), &expr, z_loan(ke));\n        printf(\"Declared resource on session 1: %.*s\\n\", (int)z_string_len(&z_loan(expr)->_inner._keyexpr),\n               z_string_data(&z_loan(expr)->_inner._keyexpr));\n        rids1[i] = expr;\n    }\n\n    z_sleep_s(SLEEP);\n\n    for (unsigned int i = 0; i < SET; i++) {\n        snprintf(s1_res, 64, \"%s%u\", uri, i);\n        z_view_keyexpr_t ke;\n        z_view_keyexpr_from_str(&ke, s1_res);\n        z_owned_keyexpr_t expr;\n        z_declare_keyexpr(z_loan(s2), &expr, z_loan(ke));\n        printf(\"Declared resource on session 2: %.*s\\n\", (int)z_string_len(&z_loan(expr)->_inner._keyexpr),\n               z_string_data(&z_loan(expr)->_inner._keyexpr));\n        rids2[i] = expr;\n    }\n\n    z_sleep_s(SLEEP);\n\n    // Declare subscribers and queryabales on second session\n    for (unsigned int i = 0; i < SET; i++) {\n        z_owned_closure_sample_t callback;\n        z_closure(&callback, data_handler, NULL, &idx[i]);\n        z_owned_subscriber_t *sub = (z_owned_subscriber_t *)z_malloc(sizeof(z_owned_subscriber_t));\n        z_result_t res = z_declare_subscriber(z_loan(s2), sub, z_loan(rids2[i]), z_move(callback), NULL);\n        assert(res == _Z_RES_OK);\n        printf(\"Declared subscription on session 2: %ju %.*s\\n\", (uintmax_t)z_subscriber_loan(sub)->_entity_id,\n               (int)z_string_len(&z_loan(rids2[i])->_inner._keyexpr),\n               z_string_data(&z_loan(rids2[i])->_inner._keyexpr));\n        subs2 = _z_list_push(subs2, sub);\n    }\n\n    z_sleep_s(SLEEP);\n\n    for (unsigned int i = 0; i < SET; i++) {\n        snprintf(s1_res, 64, \"%s%u\", uri, i);\n        z_owned_closure_query_t callback;\n        z_closure(&callback, query_handler, NULL, &idx[i]);\n        z_owned_queryable_t *qle = (z_owned_queryable_t *)z_malloc(sizeof(z_owned_queryable_t));\n        z_view_keyexpr_t ke;\n        z_view_keyexpr_from_str(&ke, s1_res);\n        assert(z_declare_queryable(z_loan(s2), qle, z_loan(ke), z_move(callback), NULL) == _Z_RES_OK);\n        printf(\"Declared queryable on session 2: %ju %i %s\\n\", (uintmax_t)qle->_val._entity_id, 0, s1_res);\n        qles2 = _z_list_push(qles2, qle);\n    }\n\n    z_sleep_s(SLEEP);\n\n    // Declare publisher on first session\n    for (unsigned int i = 0; i < SET; i++) {\n        z_owned_publisher_t *pub = (z_owned_publisher_t *)z_malloc(sizeof(z_owned_publisher_t));\n        if (z_declare_publisher(z_loan(s1), pub, z_loan(rids1[i]), NULL) < 0) {\n            printf(\"Declared publisher on session 1: %zu\\n\", z_loan(*pub)->_id);\n        }\n        pubs1 = _z_list_push(pubs1, pub);\n    }\n\n    z_sleep_s(SLEEP);\n\n    // Write data from first session\n    size_t len = MSG_LEN;\n    uint8_t *value = (uint8_t *)z_malloc(len);\n    memset(value, 1, MSG_LEN);\n\n    total = msg_count * SET;\n    for (unsigned int n = 0; n < msg_count; n++) {\n        for (unsigned int i = 0; i < SET; i++) {\n            z_put_options_t opt;\n            z_put_options_default(&opt);\n            opt.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n\n            // Create payload\n            z_owned_bytes_t payload;\n            z_bytes_from_buf(&payload, value, len, NULL, NULL);\n\n            z_put(z_loan(s1), z_loan(rids1[i]), z_move(payload), &opt);\n            printf(\"Wrote data from session 1: %.*s %zu b\\t(%u/%u)\\n\",\n                   (int)z_string_len(&z_loan(rids1[i])->_inner._keyexpr),\n                   z_string_data(&z_loan(rids1[i])->_inner._keyexpr), len, n * SET + (i + 1), total);\n        }\n    }\n\n    // Wait to receive all the data\n    z_clock_t now = z_clock_now();\n    unsigned int expected = is_reliable ? total : 1;\n    while (datas < expected) {\n        assert(z_clock_elapsed_s(&now) < TIMEOUT);\n        printf(\"Waiting for datas... %u/%u\\n\", datas, expected);\n        z_sleep_s(SLEEP);\n    }\n    if (is_reliable == true)\n        assert(datas == expected);\n    else\n        assert(datas >= expected);\n    datas = 0;\n\n    z_sleep_s(SLEEP);\n\n    // Write fragment data from first session\n    if (is_reliable) {\n        z_free((uint8_t *)value);\n        len = FRAGMENT_MSG_LEN;\n        value = (uint8_t *)z_malloc(len);\n        memset(value, 1, FRAGMENT_MSG_LEN);\n\n        total = FRAGMENT_MSG_NB * SET;\n        for (unsigned int n = 0; n < FRAGMENT_MSG_NB; n++) {\n            for (unsigned int i = 0; i < SET; i++) {\n                z_put_options_t opt;\n                z_put_options_default(&opt);\n                opt.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n\n                // Create payload\n                z_owned_bytes_t payload;\n                z_bytes_from_buf(&payload, value, len, NULL, NULL);\n\n                z_put(z_loan(s1), z_loan(rids1[i]), z_move(payload), &opt);\n                printf(\"Wrote fragment data from session 1: %.*s %zu b\\t(%u/%u)\\n\",\n                       (int)z_string_len(&z_loan(rids1[i])->_inner._keyexpr),\n                       z_string_data(&z_loan(rids1[i])->_inner._keyexpr), len, n * SET + (i + 1), total);\n            }\n        }\n        // Wait to receive all the data\n        now = z_clock_now();\n        while (datas < total) {\n            assert(z_clock_elapsed_s(&now) < TIMEOUT);\n            printf(\"Waiting for fragment datas... %u/%u\\n\", datas, total);\n            z_sleep_s(SLEEP);\n        }\n        if (is_reliable == true) {\n            assert(datas == total);\n        }\n        datas = 0;\n        z_sleep_s(SLEEP);\n    }\n\n    // Query data from first session\n    total = QRY * SET;\n    for (unsigned int n = 0; n < QRY; n++) {\n        for (unsigned int i = 0; i < SET; i++) {\n            snprintf(s1_res, 64, \"%s%u\", uri, i);\n            z_owned_closure_reply_t callback;\n            z_closure(&callback, reply_handler, NULL, &idx[i]);\n            z_view_keyexpr_t ke;\n            z_view_keyexpr_from_str(&ke, s1_res);\n            z_get(z_loan(s1), z_loan(ke), \"\", z_move(callback), NULL);\n            printf(\"Queried data from session 1: %i %s\\n\", 0, s1_res);\n        }\n    }\n\n    // Wait to receive all the expected queries\n    now = z_clock_now();\n    expected = is_reliable ? total : 1;\n    while (queries < expected) {\n        assert(z_clock_elapsed_s(&now) < TIMEOUT);\n        printf(\"Waiting for queries... %u/%u\\n\", queries, expected);\n        z_sleep_s(SLEEP);\n    }\n    if (is_reliable == true)\n        assert(queries == expected);\n    else\n        assert(queries >= expected);\n    queries = 0;\n\n    // Wait to receive all the expected replies\n    now = z_clock_now();\n    while (replies < expected) {\n        assert(z_clock_elapsed_s(&now) < TIMEOUT);\n        printf(\"Waiting for replies... %u/%u\\n\", replies, expected);\n        z_sleep_s(SLEEP);\n    }\n    if (is_reliable == true)\n        assert(replies == expected);\n    else\n        assert(replies >= expected);\n    replies = 0;\n\n    z_sleep_s(SLEEP);\n\n    // Undeclare publishers on first session\n    while (pubs1) {\n        z_owned_publisher_t *pub = _z_list_value(pubs1);\n        printf(\"Undeclared publisher on session 2: %zu\\n\", z_loan(*pub)->_id);\n        z_drop(z_move(*pub));\n        pubs1 = _z_list_pop(pubs1, _z_noop_elem_free, NULL);\n    }\n\n    z_sleep_s(SLEEP);\n\n    // Undeclare subscribers and queryables on second session\n    while (subs2) {\n        z_owned_subscriber_t *sub = _z_list_value(subs2);\n        printf(\"Undeclared subscriber on session 2: %ju\\n\", (uintmax_t)sub->_val._entity_id);\n        z_drop(z_move(*sub));\n        subs2 = _z_list_pop(subs2, _z_noop_elem_free, NULL);\n    }\n\n    z_sleep_s(SLEEP);\n\n    while (qles2) {\n        z_owned_queryable_t *qle = _z_list_value(qles2);\n        printf(\"Undeclared queryable on session 2: %ju\\n\", (uintmax_t)qle->_val._entity_id);\n        z_drop(z_move(*qle));\n        qles2 = _z_list_pop(qles2, _z_noop_elem_free, NULL);\n    }\n\n    z_sleep_s(SLEEP);\n\n    // Undeclare resources on both sessions\n    for (unsigned int i = 0; i < SET; i++) {\n        printf(\"Undeclared resource on session 1: %.*s\\n\", (int)z_string_len(&z_loan(rids1[i])->_inner._keyexpr),\n               z_string_data(&z_loan(rids1[i])->_inner._keyexpr));\n        z_undeclare_keyexpr(z_loan(s1), z_move(rids1[i]));\n    }\n\n    z_sleep_s(SLEEP);\n\n    for (unsigned int i = 0; i < SET; i++) {\n        printf(\"Undeclared resource on session 2: %.*s\\n\", (int)z_string_len(&z_loan(rids2[i])->_inner._keyexpr),\n               z_string_data(&z_loan(rids2[i])->_inner._keyexpr));\n        z_undeclare_keyexpr(z_loan(s2), z_move(rids2[i]));\n    }\n\n    z_sleep_s(SLEEP);\n\n    // Close both sessions\n    printf(\"Closing session 1\\n\");\n    z_drop(z_move(s1));\n\n    z_sleep_s(SLEEP);\n\n    printf(\"Closing session 2\\n\");\n    z_drop(z_move(s2));\n\n    z_free((uint8_t *)value);\n    value = NULL;\n\n    free(s1_res);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_collections_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <assert.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/collections/fifo.h\"\n#include \"zenoh-pico/collections/lifo.h\"\n#include \"zenoh-pico/collections/ring.h\"\n#include \"zenoh-pico/collections/sortedmap.h\"\n#include \"zenoh-pico/collections/string.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nchar *a = \"a\";\nchar *b = \"b\";\nchar *c = \"c\";\nchar *d = \"d\";\n\n// RING\n_Z_RING_DEFINE(_z_str, char)\n\n// SORTED MAP\n_Z_SORTEDMAP_DEFINE(_z_str, _z_str, char, char)\n\nvoid print_ring(_z_str_ring_t *r) {\n    printf(\"Ring { capacity: %zu, r_idx: %zu, w_idx: %zu, len: %zu }\\n\", _z_str_ring_capacity(r), r->_r_idx, r->_w_idx,\n           _z_str_ring_len(r));\n}\n\nvoid ring_test(void) {\n    _z_str_ring_t r = _z_str_ring_make(3);\n    print_ring(&r);\n    assert(_z_str_ring_is_empty(&r));\n\n    // One\n    char *s = _z_str_ring_push(&r, a);\n    print_ring(&r);\n    assert(s == NULL);\n    assert(_z_str_ring_len(&r) == 1);\n\n    s = _z_str_ring_pull(&r);\n    print_ring(&r);\n    assert(strcmp(a, s) == 0);\n    assert(_z_str_ring_is_empty(&r));\n\n    s = _z_str_ring_pull(&r);\n    print_ring(&r);\n    assert(s == NULL);\n    assert(_z_str_ring_is_empty(&r));\n\n    // Two\n    s = _z_str_ring_push(&r, a);\n    print_ring(&r);\n    assert(s == NULL);\n    assert(_z_str_ring_len(&r) == 1);\n\n    s = _z_str_ring_push(&r, b);\n    print_ring(&r);\n    assert(s == NULL);\n    assert(_z_str_ring_len(&r) == 2);\n\n    s = _z_str_ring_push(&r, c);\n    print_ring(&r);\n    assert(s == NULL);\n    assert(_z_str_ring_len(&r) == 3);\n    assert(_z_str_ring_is_full(&r));\n\n    s = _z_str_ring_push(&r, d);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", d, s);\n    assert(strcmp(d, s) == 0);\n    assert(_z_str_ring_len(&r) == 3);\n    assert(_z_str_ring_is_full(&r));\n\n    s = _z_str_ring_push_force(&r, d);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", a, s);\n    assert(strcmp(a, s) == 0);\n    assert(_z_str_ring_len(&r) == 3);\n    assert(_z_str_ring_is_full(&r));\n\n    s = _z_str_ring_push_force(&r, d);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", b, s);\n    assert(strcmp(b, s) == 0);\n    assert(_z_str_ring_len(&r) == 3);\n    assert(_z_str_ring_is_full(&r));\n\n    s = _z_str_ring_push_force(&r, d);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", c, s);\n    assert(strcmp(c, s) == 0);\n    assert(_z_str_ring_len(&r) == 3);\n    assert(_z_str_ring_is_full(&r));\n\n    s = _z_str_ring_pull(&r);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", d, s);\n    assert(strcmp(d, s) == 0);\n    assert(_z_str_ring_len(&r) == 2);\n\n    s = _z_str_ring_pull(&r);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", d, s);\n    assert(strcmp(d, s) == 0);\n    assert(_z_str_ring_len(&r) == 1);\n\n    s = _z_str_ring_pull(&r);\n    print_ring(&r);\n    printf(\"%s == %s\\n\", d, s);\n    assert(strcmp(d, s) == 0);\n    assert(_z_str_ring_is_empty(&r));\n\n    _z_str_ring_clear(&r);\n}\n\nvoid ring_test_init_free(void) {\n    _z_str_ring_t *r = (_z_str_ring_t *)malloc(sizeof(_z_str_ring_t));\n    _z_str_ring_init(r, 1);\n    assert(r != NULL);\n\n    char *str = (char *)calloc(1, sizeof(char));\n    _z_str_ring_push_force_drop(r, str);\n\n    _z_str_ring_free(&r);\n    assert(r == NULL);\n}\n\nvoid ring_iterator_test(void) {\n#define TEST_RING(ring, values, n)                                                              \\\n    {                                                                                           \\\n        _z_str_ring_iterator_t iter = _z_str_ring_iterator_make(&ring);                         \\\n        _z_str_ring_reverse_iterator_t reverse_iter = _z_str_ring_reverse_iterator_make(&ring); \\\n                                                                                                \\\n        for (int i = 0; i < n; i++) {                                                           \\\n            assert(_z_str_ring_iterator_next(&iter));                                           \\\n            assert(strcmp(_z_str_ring_iterator_value(&iter), values[i]) == 0);                  \\\n        }                                                                                       \\\n                                                                                                \\\n        for (int i = n - 1; i >= 0; i--) {                                                      \\\n            assert(_z_str_ring_reverse_iterator_next(&reverse_iter));                           \\\n            assert(strcmp(_z_str_ring_reverse_iterator_value(&reverse_iter), values[i]) == 0);  \\\n        }                                                                                       \\\n                                                                                                \\\n        assert(!_z_str_ring_iterator_next(&iter));                                              \\\n        assert(!_z_str_ring_reverse_iterator_next(&reverse_iter));                              \\\n    }\n\n    _z_str_ring_t ring = _z_str_ring_make(4);\n\n    char *values[] = {\"A\", \"B\", \"C\", \"D\", \"E\", \"F\"};\n\n    assert(_z_str_ring_push(&ring, values[0]) == NULL);\n    // { \"A\" }\n    TEST_RING(ring, values, 1);\n\n    assert(_z_str_ring_push(&ring, values[1]) == NULL);\n    // { \"A\", \"B\" }\n    TEST_RING(ring, values, 2);\n\n    assert(_z_str_ring_push(&ring, values[2]) == NULL);\n    // { \"A\", \"B\", \"C\" }\n    TEST_RING(ring, values, 3);\n\n    assert(_z_str_ring_push(&ring, values[3]) == NULL);\n    // { \"A\", \"B\", \"C\", \"D\" }\n    TEST_RING(ring, values, 4);\n\n    assert(_z_str_ring_pull(&ring) != NULL);\n    // { \"B\", \"C\", \"D\" }\n    TEST_RING(ring, (values + 1), 3);\n    assert(_z_str_ring_push(&ring, values[4]) == NULL);\n    // { \"B\", \"C\", \"D\", \"E\" }\n    TEST_RING(ring, (values + 1), 4);\n\n    assert(_z_str_ring_pull(&ring) != NULL);\n    // { \"C\", \"D\", \"E\" }\n    TEST_RING(ring, (values + 2), 3);\n    assert(_z_str_ring_push(&ring, values[5]) == NULL);\n    // { \"C\", \"D\", \"E\", \"F\" }\n    TEST_RING(ring, (values + 2), 4);\n\n    assert(_z_str_ring_pull(&ring) != NULL);\n    // { \"D\", \"E\", \"F\" }\n    TEST_RING(ring, (values + 3), 3);\n\n    assert(_z_str_ring_pull(&ring) != NULL);\n    // { \"E\", \"F\" }\n    TEST_RING(ring, (values + 4), 2);\n\n    assert(_z_str_ring_pull(&ring) != NULL);\n    // { \"F\" }\n    TEST_RING(ring, (values + 5), 1);\n\n    assert(_z_str_ring_pull(&ring) != NULL);\n    // {}\n    TEST_RING(ring, values, 0);\n\n    _z_str_ring_clear(&ring);\n\n#undef TEST_RING\n}\n\n// LIFO\n_Z_LIFO_DEFINE(_z_str, char)\n\nvoid print_lifo(_z_str_lifo_t *r) {\n    printf(\"Lifo { capacity: %zu, len: %zu }\\n\", _z_str_lifo_capacity(r), _z_str_lifo_len(r));\n}\n\nvoid lifo_test(void) {\n    _z_str_lifo_t r = _z_str_lifo_make(3);\n    print_lifo(&r);\n    assert(_z_str_lifo_is_empty(&r));\n\n    // One\n    char *s = _z_str_lifo_push(&r, a);\n    print_lifo(&r);\n    assert(s == NULL);\n    assert(_z_str_lifo_len(&r) == 1);\n\n    s = _z_str_lifo_pull(&r);\n    print_lifo(&r);\n    printf(\"%s == %s\\n\", a, s);\n    assert(strcmp(a, s) == 0);\n    assert(_z_str_lifo_is_empty(&r));\n\n    s = _z_str_lifo_pull(&r);\n    print_lifo(&r);\n    assert(s == NULL);\n    assert(_z_str_lifo_is_empty(&r));\n\n    // Two\n    s = _z_str_lifo_push(&r, a);\n    print_lifo(&r);\n    assert(s == NULL);\n    assert(_z_str_lifo_len(&r) == 1);\n\n    s = _z_str_lifo_push(&r, b);\n    print_lifo(&r);\n    assert(s == NULL);\n    assert(_z_str_lifo_len(&r) == 2);\n\n    s = _z_str_lifo_push(&r, c);\n    print_lifo(&r);\n    assert(s == NULL);\n    assert(_z_str_lifo_len(&r) == 3);\n    assert(_z_str_lifo_is_full(&r));\n\n    s = _z_str_lifo_push(&r, d);\n    print_lifo(&r);\n    printf(\"%s == %s\\n\", d, s);\n    assert(strcmp(d, s) == 0);\n    assert(_z_str_lifo_len(&r) == 3);\n    assert(_z_str_lifo_is_full(&r));\n\n    s = _z_str_lifo_pull(&r);\n    print_lifo(&r);\n    printf(\"%s == %s\\n\", c, s);\n    assert(strcmp(c, s) == 0);\n    assert(_z_str_lifo_len(&r) == 2);\n\n    s = _z_str_lifo_pull(&r);\n    print_lifo(&r);\n    printf(\"%s == %s\\n\", b, s);\n    assert(strcmp(b, s) == 0);\n    assert(_z_str_lifo_len(&r) == 1);\n\n    s = _z_str_lifo_pull(&r);\n    print_lifo(&r);\n    printf(\"%s == %s\\n\", a, s);\n    assert(strcmp(a, s) == 0);\n    assert(_z_str_lifo_is_empty(&r));\n\n    _z_str_lifo_clear(&r);\n}\n\nvoid lifo_test_init_free(void) {\n    _z_str_lifo_t *r = (_z_str_lifo_t *)malloc(sizeof(_z_str_lifo_t));\n    _z_str_lifo_init(r, 1);\n    assert(r != NULL);\n\n    char *str = (char *)calloc(1, sizeof(char));\n    _z_str_lifo_push_drop(r, str);\n\n    _z_str_lifo_free(&r);\n    assert(r == NULL);\n}\n\n// FIFO\n_Z_FIFO_DEFINE(_z_str, char)\n\nvoid print_fifo(_z_str_fifo_t *r) {\n    printf(\"Fifo { capacity: %zu, len: %zu }\\n\", _z_str_fifo_capacity(r), _z_str_fifo_len(r));\n}\n\nvoid fifo_test(void) {\n    _z_str_fifo_t r = _z_str_fifo_make(3);\n    print_fifo(&r);\n    assert(_z_str_fifo_is_empty(&r));\n\n    // One\n    char *s = _z_str_fifo_push(&r, a);\n    print_fifo(&r);\n    assert(s == NULL);\n    assert(_z_str_fifo_len(&r) == 1);\n\n    s = _z_str_fifo_pull(&r);\n    print_fifo(&r);\n    printf(\"%s == %s\\n\", a, s);\n    assert(strcmp(a, s) == 0);\n    assert(_z_str_fifo_is_empty(&r));\n\n    s = _z_str_fifo_pull(&r);\n    print_fifo(&r);\n    assert(s == NULL);\n    assert(_z_str_fifo_is_empty(&r));\n\n    // Two\n    s = _z_str_fifo_push(&r, a);\n    print_fifo(&r);\n    assert(s == NULL);\n    assert(_z_str_fifo_len(&r) == 1);\n\n    s = _z_str_fifo_push(&r, b);\n    print_fifo(&r);\n    assert(s == NULL);\n    assert(_z_str_fifo_len(&r) == 2);\n\n    s = _z_str_fifo_push(&r, c);\n    print_fifo(&r);\n    assert(s == NULL);\n    assert(_z_str_fifo_len(&r) == 3);\n    assert(_z_str_fifo_is_full(&r));\n\n    s = _z_str_fifo_push(&r, d);\n    print_fifo(&r);\n    printf(\"%s == %s\\n\", d, s);\n    assert(strcmp(d, s) == 0);\n    assert(_z_str_fifo_len(&r) == 3);\n    assert(_z_str_fifo_is_full(&r));\n\n    s = _z_str_fifo_pull(&r);\n    print_fifo(&r);\n    printf(\"%s == %s\\n\", a, s);\n    assert(strcmp(a, s) == 0);\n    assert(_z_str_fifo_len(&r) == 2);\n\n    s = _z_str_fifo_pull(&r);\n    print_fifo(&r);\n    printf(\"%s == %s\\n\", b, s);\n    assert(strcmp(b, s) == 0);\n    assert(_z_str_fifo_len(&r) == 1);\n\n    s = _z_str_fifo_pull(&r);\n    print_fifo(&r);\n    printf(\"%s == %s\\n\", c, s);\n    assert(strcmp(c, s) == 0);\n    assert(_z_str_fifo_is_empty(&r));\n\n    _z_str_fifo_clear(&r);\n}\n\nvoid fifo_test_init_free(void) {\n    _z_str_fifo_t *r = (_z_str_fifo_t *)malloc(sizeof(_z_str_fifo_t));\n    _z_str_fifo_init(r, 1);\n    assert(r != NULL);\n\n    char *str = (char *)calloc(1, sizeof(char));\n    _z_str_fifo_push_drop(r, str);\n\n    _z_str_fifo_free(&r);\n    assert(r == NULL);\n}\n\nvoid int_map_iterator_test(void) {\n    _z_str_intmap_t map;\n\n    map = _z_str_intmap_make();\n    _z_str_intmap_insert(&map, 10, _z_str_clone(\"A\"));\n    _z_str_intmap_insert(&map, 20, _z_str_clone(\"B\"));\n    _z_str_intmap_insert(&map, 30, _z_str_clone(\"C\"));\n    _z_str_intmap_insert(&map, 40, _z_str_clone(\"D\"));\n\n#define TEST_MAP(map)                                                      \\\n    {                                                                      \\\n        _z_str_intmap_iterator_t iter = _z_str_intmap_iterator_make(&map); \\\n        assert(_z_str_intmap_iterator_next(&iter));                        \\\n        assert(_z_str_intmap_iterator_key(&iter) == 20);                   \\\n        assert(strcmp(_z_str_intmap_iterator_value(&iter), \"B\") == 0);     \\\n                                                                           \\\n        assert(_z_str_intmap_iterator_next(&iter));                        \\\n        assert(_z_str_intmap_iterator_key(&iter) == 40);                   \\\n        assert(strcmp(_z_str_intmap_iterator_value(&iter), \"D\") == 0);     \\\n                                                                           \\\n        assert(_z_str_intmap_iterator_next(&iter));                        \\\n        assert(_z_str_intmap_iterator_key(&iter) == 10);                   \\\n        assert(strcmp(_z_str_intmap_iterator_value(&iter), \"A\") == 0);     \\\n                                                                           \\\n        assert(_z_str_intmap_iterator_next(&iter));                        \\\n        assert(_z_str_intmap_iterator_key(&iter) == 30);                   \\\n        assert(strcmp(_z_str_intmap_iterator_value(&iter), \"C\") == 0);     \\\n                                                                           \\\n        assert(!_z_str_intmap_iterator_next(&iter));                       \\\n    }\n\n    TEST_MAP(map);\n\n    _z_str_intmap_t map2 = _z_str_intmap_clone(&map);\n\n    TEST_MAP(map2);\n\n    _z_str_intmap_clear(&map);\n    _z_str_intmap_clear(&map2);\n\n#undef TEST_MAP\n}\n\nvoid int_map_iterator_deletion_test(void) {\n    _z_str_intmap_t map;\n\n    map = _z_str_intmap_make();\n    _z_str_intmap_insert(&map, 10, _z_str_clone(\"A\"));\n    _z_str_intmap_insert(&map, 20, _z_str_clone(\"B\"));\n    _z_str_intmap_insert(&map, 30, _z_str_clone(\"C\"));\n    _z_str_intmap_insert(&map, 40, _z_str_clone(\"D\"));\n\n    _z_str_intmap_iterator_t iter = _z_str_intmap_iterator_make(&map);\n    _z_str_intmap_iterator_next(&iter);\n    for (size_t s = 4; s != 0; s--) {\n        assert(s == _z_str_intmap_len(&map));\n        size_t key = _z_str_intmap_iterator_key(&iter);\n        assert(strlen(_z_str_intmap_iterator_value(&iter)) == 1);\n        _z_str_intmap_iterator_next(&iter);\n        _z_str_intmap_remove(&map, key);\n    }\n    _z_str_intmap_clear(&map);\n}\n\nvoid int_map_extract_test(void) {\n    _z_str_intmap_t map;\n\n    map = _z_str_intmap_make();\n    _z_str_intmap_insert(&map, 10, _z_str_clone(\"A\"));\n    _z_str_intmap_insert(&map, 20, _z_str_clone(\"B\"));\n    _z_str_intmap_insert(&map, 30, _z_str_clone(\"C\"));\n    _z_str_intmap_insert(&map, 40, _z_str_clone(\"D\"));\n\n    assert(_z_str_intmap_extract(&map, 100) == NULL);\n    char *item_c = _z_str_intmap_extract(&map, 30);\n    assert(strcmp(item_c, \"C\") == 0);\n    z_free(item_c);\n    assert(_z_str_intmap_len(&map) == 3);\n    assert(_z_str_intmap_get(&map, 30) == NULL);\n\n    assert(_z_str_intmap_extract(&map, 30) == NULL);\n\n    _z_str_intmap_clear(&map);\n}\n\nstatic bool slist_eq_f(const void *left, const void *right) { return strcmp((char *)left, (char *)right) == 0; }\nstatic bool slist_starts_with_f(const void *left, const void *right) {\n    // SAFETY: left and right are guaranteed to be null-terminated.\n    // Flawfinder: ignore [CWE-126]\n    return strncmp((char *)left, (char *)right, strlen((char *)left)) == 0;\n}\n\nvoid slist_test(void) {\n    char *values[] = {\"test1\", \"test2\", \"test3\"};\n    _z_slist_t *slist = NULL;\n    // Test empty\n    assert(_z_slist_is_empty(slist));\n    assert(_z_slist_len(slist) == 0);\n\n    // Add value test\n    slist = _z_slist_push(slist, values[0], strlen(values[0]) + 1, _z_noop_copy, false);\n    assert(!_z_slist_is_empty(slist));\n    assert(_z_slist_len(slist) == 1);\n    assert(strcmp(values[0], (char *)_z_slist_value(slist)) == 0);\n    assert(_z_slist_next(slist) == NULL);\n\n    slist = _z_slist_push(slist, values[1], strlen(values[1]) + 1, _z_noop_copy, false);\n    assert(_z_slist_len(slist) == 2);\n    assert(strcmp(values[1], (char *)_z_slist_value(slist)) == 0);\n    assert(strcmp(values[0], (char *)_z_slist_value(_z_slist_next(slist))) == 0);\n\n    // Push back test\n    slist = _z_slist_push_back(slist, values[2], strlen(values[2]) + 1, _z_noop_copy, false);\n    assert(_z_slist_len(slist) == 3);\n    assert(strcmp(values[2], (char *)_z_slist_value(_z_slist_next(_z_slist_next(slist)))) == 0);\n\n    // Pop test\n    slist = _z_slist_pop(slist, _z_noop_clear);\n    assert(_z_slist_len(slist) == 2);\n    assert(strcmp(values[0], (char *)_z_slist_value(slist)) == 0);\n    assert(strcmp(values[2], (char *)_z_slist_value(_z_slist_next(slist))) == 0);\n    slist = _z_slist_pop(slist, _z_noop_clear);\n    assert(_z_slist_len(slist) == 1);\n    assert(strcmp(values[2], (char *)_z_slist_value(slist)) == 0);\n    assert(strlen(values[2]) == 5);\n    slist = _z_slist_pop(slist, _z_noop_clear);\n    assert(_z_slist_is_empty(slist));\n\n    // Drop element test\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(values); i++) {\n        slist = _z_slist_push(slist, values[i], strlen(values[i]) + 1, _z_noop_copy, false);\n    }\n    // Drop second element\n    slist = _z_slist_drop_element(slist, slist, _z_noop_clear);\n    assert(_z_slist_len(slist) == 2);\n    assert(strcmp(values[2], (char *)_z_slist_value(slist)) == 0);\n    assert(strcmp(values[0], (char *)_z_slist_value(_z_slist_next(slist))) == 0);\n\n    // Free test\n    _z_slist_free(&slist, _z_noop_clear);\n    assert(_z_slist_is_empty(slist));\n\n    // Push empty test\n    slist = _z_slist_push_empty(slist, strlen(values[0]) + 1);\n    assert(_z_slist_len(slist) == 1);\n    char *val = (char *)_z_slist_value(slist);\n    strcpy(val, values[0]);\n    assert(strcmp(values[0], (char *)_z_slist_value(slist)) == 0);\n    _z_slist_free(&slist, _z_noop_clear);\n\n    // Drop filter test\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(values); i++) {\n        slist = _z_slist_push(slist, values[i], strlen(values[i]) + 1, _z_noop_copy, false);\n    }\n    slist = _z_slist_drop_filter(slist, _z_noop_clear, slist_eq_f, values[1], true);\n    assert(_z_slist_len(slist) == 2);\n    assert(strcmp(values[2], (char *)_z_slist_value(slist)) == 0);\n    assert(strcmp(values[0], (char *)_z_slist_value(_z_slist_next(slist))) == 0);\n    _z_slist_free(&slist, _z_noop_clear);\n\n    // Find test\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(values); i++) {\n        slist = _z_slist_push(slist, values[i], strlen(values[i]) + 1, _z_noop_copy, false);\n    }\n    _z_slist_t *elem = NULL;\n    elem = _z_slist_find(slist, slist_eq_f, \"bob\");\n    assert(elem == NULL);\n    elem = _z_slist_find(slist, slist_eq_f, values[2]);\n    assert(elem != NULL);\n    _z_slist_free(&slist, _z_noop_clear);\n\n    // Extract test\n    char *values2[] = {\"test1\", \"tes2\", \"test3\"};\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(values2); i++) {\n        // SAFETY: values2[i] only contains null-terminated strings.\n        // Flawfinder: ignore [CWE-126]\n        slist = _z_slist_push(slist, values2[i], strlen(values2[i]) + 1, _z_noop_copy, false);\n    }\n    _z_slist_t *extracted = NULL;\n    slist = _z_slist_extract_filter(slist, slist_starts_with_f, \"test\", &extracted, false);\n\n    assert(_z_slist_len(slist) == 1);\n    assert(_z_slist_len(extracted) == 2);\n    elem = NULL;\n    elem = _z_slist_find(extracted, slist_eq_f, \"test1\");\n    assert(elem != NULL);\n    elem = _z_slist_find(extracted, slist_eq_f, \"test3\");\n    assert(elem != NULL);\n    elem = _z_slist_find(slist, slist_eq_f, \"tes2\");\n    assert(elem != NULL);\n    _z_slist_free(&slist, _z_noop_clear);\n    _z_slist_free(&extracted, _z_noop_clear);\n\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(values2); i++) {\n        // SAFETY: values2[i] only contains null-terminated strings.\n        // Flawfinder: ignore [CWE-126]\n        slist = _z_slist_push(slist, values2[i], strlen(values2[i]) + 1, _z_noop_copy, false);\n    }\n    slist = _z_slist_extract_filter(slist, slist_starts_with_f, \"test\", &extracted, true);\n\n    assert(_z_slist_len(slist) == 2);\n    assert(_z_slist_len(extracted) == 1);\n    elem = _z_slist_find(slist, slist_eq_f, \"tes2\");\n    assert(elem != NULL);\n    _z_slist_free(&slist, _z_noop_clear);\n    _z_slist_free(&extracted, _z_noop_clear);\n\n    // Clone test\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(values); i++) {\n        slist = _z_slist_push(slist, values[i], strlen(values[i]) + 1, _z_noop_copy, false);\n    }\n    _z_slist_t *clone = NULL;\n    clone = _z_slist_clone(slist, strlen(values[0]), _z_noop_copy, false);\n    assert(_z_slist_len(slist) == 3);\n    assert(strcmp(values[2], (char *)_z_slist_value(slist)) == 0);\n    assert(strcmp(values[1], (char *)_z_slist_value(_z_slist_next(slist))) == 0);\n    assert(strcmp(values[0], (char *)_z_slist_value(_z_slist_next(_z_slist_next(slist)))) == 0);\n    _z_slist_free(&slist, _z_noop_clear);\n    _z_slist_free(&clone, _z_noop_clear);\n}\n\nvoid sorted_map_iterator_test(void) {\n    _z_str__z_str_sortedmap_t map;\n\n    map = _z_str__z_str_sortedmap_make();\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"4\"), _z_str_clone(\"D\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"1\"), _z_str_clone(\"A\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"3\"), _z_str_clone(\"C\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"2\"), _z_str_clone(\"B\"));\n\n#define TEST_SORTEDMAP(map)                                                                    \\\n    {                                                                                          \\\n        assert(_z_str__z_str_sortedmap_len(&map) == 4);                                        \\\n        _z_str__z_str_sortedmap_iterator_t iter = _z_str__z_str_sortedmap_iterator_make(&map); \\\n                                                                                               \\\n        assert(_z_str__z_str_sortedmap_iterator_next(&iter));                                  \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_key(&iter), \"1\") == 0);                 \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_value(&iter), \"A\") == 0);               \\\n                                                                                               \\\n        assert(_z_str__z_str_sortedmap_iterator_next(&iter));                                  \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_key(&iter), \"2\") == 0);                 \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_value(&iter), \"B\") == 0);               \\\n                                                                                               \\\n        assert(_z_str__z_str_sortedmap_iterator_next(&iter));                                  \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_key(&iter), \"3\") == 0);                 \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_value(&iter), \"C\") == 0);               \\\n                                                                                               \\\n        assert(_z_str__z_str_sortedmap_iterator_next(&iter));                                  \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_key(&iter), \"4\") == 0);                 \\\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_value(&iter), \"D\") == 0);               \\\n                                                                                               \\\n        assert(!_z_str__z_str_sortedmap_iterator_next(&iter));                                 \\\n    }\n\n    TEST_SORTEDMAP(map);\n\n    _z_str__z_str_sortedmap_t map2 = _z_str__z_str_sortedmap_clone(&map);\n\n    TEST_SORTEDMAP(map2);\n\n    _z_str__z_str_sortedmap_clear(&map);\n    _z_str__z_str_sortedmap_clear(&map2);\n\n#undef TEST_SORTEDMAP\n}\n\nvoid sorted_map_iterator_deletion_test(void) {\n    _z_str__z_str_sortedmap_t map;\n\n    map = _z_str__z_str_sortedmap_make();\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"4\"), _z_str_clone(\"D\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"1\"), _z_str_clone(\"A\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"3\"), _z_str_clone(\"C\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"2\"), _z_str_clone(\"B\"));\n\n    _z_str__z_str_sortedmap_iterator_t iter = _z_str__z_str_sortedmap_iterator_make(&map);\n    _z_str__z_str_sortedmap_iterator_next(&iter);\n    for (size_t s = 4; s != 0; s--) {\n        assert(s == _z_str__z_str_sortedmap_len(&map));\n        char *key = _z_str__z_str_sortedmap_iterator_key(&iter);\n        // SAFETY: returned _z_str_t should be null-terminated.\n        // Flawfinder: ignore [CWE-126]\n        assert(strlen(_z_str__z_str_sortedmap_iterator_value(&iter)) == 1);\n        _z_str__z_str_sortedmap_iterator_next(&iter);\n        _z_str__z_str_sortedmap_remove(&map, key);\n    }\n    _z_str__z_str_sortedmap_clear(&map);\n}\n\nvoid sorted_map_replace_test(void) {\n    _z_str__z_str_sortedmap_t map = _z_str__z_str_sortedmap_make();\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"key\"), _z_str_clone(\"old\"));\n    assert(strcmp(_z_str__z_str_sortedmap_get(&map, \"key\"), \"old\") == 0);\n\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"key\"), _z_str_clone(\"new\"));\n    assert(strcmp(_z_str__z_str_sortedmap_get(&map, \"key\"), \"new\") == 0);\n\n    _z_str__z_str_sortedmap_clear(&map);\n}\n\nvoid sorted_map_missing_key_test(void) {\n    _z_str__z_str_sortedmap_t map = _z_str__z_str_sortedmap_make();\n    assert(_z_str__z_str_sortedmap_get(&map, \"absent\") == NULL);\n    _z_str__z_str_sortedmap_clear(&map);\n}\n\nvoid sorted_map_empty_test(void) {\n    _z_str__z_str_sortedmap_t map = _z_str__z_str_sortedmap_make();\n    assert(_z_str__z_str_sortedmap_is_empty(&map));\n    assert(_z_str__z_str_sortedmap_len(&map) == 0);\n\n    _z_str__z_str_sortedmap_iterator_t iter = _z_str__z_str_sortedmap_iterator_make(&map);\n    assert(!_z_str__z_str_sortedmap_iterator_next(&iter));\n\n    _z_str__z_str_sortedmap_clear(&map);\n}\n\nvoid sorted_map_pop_first_test(void) {\n    _z_str__z_str_sortedmap_t map;\n    _z_str__z_str_sortedmap_init(&map);\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"3\"), _z_str_clone(\"three\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"1\"), _z_str_clone(\"one\"));\n    _z_str__z_str_sortedmap_insert(&map, _z_str_clone(\"2\"), _z_str_clone(\"two\"));\n\n    _z_str__z_str_sortedmap_entry_t *entry = _z_str__z_str_sortedmap_pop_first(&map);\n    assert(entry != NULL);\n    assert(strcmp(_z_str__z_str_sortedmap_entry_key(entry), \"1\") == 0);\n    assert(strcmp(_z_str__z_str_sortedmap_entry_val(entry), \"one\") == 0);\n    _z_str__z_str_sortedmap_entry_free(&entry);\n\n    assert(_z_str__z_str_sortedmap_len(&map) == 2);\n\n    _z_str__z_str_sortedmap_clear(&map);\n}\n\nvoid sorted_map_copy_move_test(void) {\n    _z_str__z_str_sortedmap_t src = _z_str__z_str_sortedmap_make();\n    _z_str__z_str_sortedmap_insert(&src, _z_str_clone(\"key\"), _z_str_clone(\"value\"));\n\n    _z_str__z_str_sortedmap_t dst = _z_str__z_str_sortedmap_make();\n    assert(_z_str__z_str_sortedmap_copy(&dst, &src) == _Z_RES_OK);\n    assert(strcmp(_z_str__z_str_sortedmap_get(&dst, \"key\"), \"value\") == 0);\n\n    _z_str__z_str_sortedmap_clear(&src);\n    assert(_z_str__z_str_sortedmap_move(&src, &dst) == _Z_RES_OK);\n    assert(strcmp(_z_str__z_str_sortedmap_get(&src, \"key\"), \"value\") == 0);\n\n    _z_str__z_str_sortedmap_clear(&src);\n}\n\nvoid sorted_map_free_test(void) {\n    _z_str__z_str_sortedmap_t *map_ptr = z_malloc(sizeof(_z_str__z_str_sortedmap_t));\n    assert(map_ptr != NULL);\n\n    *map_ptr = _z_str__z_str_sortedmap_make();\n    _z_str__z_str_sortedmap_insert(map_ptr, _z_str_clone(\"K\"), _z_str_clone(\"V\"));\n\n    _z_str__z_str_sortedmap_free(&map_ptr);\n    assert(map_ptr == NULL);  // should be nullified after free\n}\n\nvoid sorted_map_stress_test(void) {\n    _z_str__z_str_sortedmap_t map = _z_str__z_str_sortedmap_make();\n    char key[16], val[16];\n    for (int i = 100; i >= 1; i--) {\n        snprintf(key, sizeof(key), \"%03d\", i);\n        snprintf(val, sizeof(val), \"val%d\", i);\n        _z_str__z_str_sortedmap_insert(&map, _z_str_clone(key), _z_str_clone(val));\n    }\n\n    _z_str__z_str_sortedmap_iterator_t iter = _z_str__z_str_sortedmap_iterator_make(&map);\n    int expected = 1;\n    while (_z_str__z_str_sortedmap_iterator_next(&iter)) {\n        char expected_key[16];\n        snprintf(expected_key, sizeof(expected_key), \"%03d\", expected);\n        assert(strcmp(_z_str__z_str_sortedmap_iterator_key(&iter), expected_key) == 0);\n        expected++;\n    }\n    assert(expected == 101);  // 1..100\n    _z_str__z_str_sortedmap_clear(&map);\n}\n\nsize_t destroyed_elts = 0;\ntypedef struct {\n    int id;\n} _z_elt_t;\n\nvoid _z_elt_destroy(_z_elt_t *elt) {\n    (void)elt;\n    destroyed_elts++;\n}\n\nvoid _z_elt_move(_z_elt_t *dst, _z_elt_t *src) {\n    dst->id = src->id;\n    src->id = -1;  // Invalidate source to detect use-after-move\n}\n\n#define _ZP_DEQUE_TEMPLATE_ELEM_TYPE _z_elt_t\n#define _ZP_DEQUE_TEMPLATE_NAME _z_elt_deque\n#define _ZP_DEQUE_TEMPLATE_ELEM_DESTROY_FN_NAME _z_elt_destroy\n#define _ZP_DEQUE_TEMPLATE_ELEM_MOVE_FN_NAME _z_elt_move\n#define _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME _z_elt_compare\n#define _ZP_DEQUE_TEMPLATE_SIZE 4\n#include \"zenoh-pico/collections/deque_template.h\"\n\nvoid deque_test(void) {\n    destroyed_elts = 0;\n    _z_elt_deque_t deque = _z_elt_deque_new();\n    assert(_z_elt_deque_size(&deque) == 0);\n    assert(_z_elt_deque_is_empty(&deque));\n    assert(_z_elt_deque_front(&deque) == NULL);\n    assert(_z_elt_deque_back(&deque) == NULL);\n    _z_elt_t elt0 = {.id = 0};\n\n    assert(_z_elt_deque_push_front(&deque, &elt0));\n\n    assert(_z_elt_deque_front(&deque)->id == 0);\n    assert(_z_elt_deque_back(&deque)->id == 0);\n    _z_elt_t elt1 = {.id = 1};\n    assert(_z_elt_deque_push_front(&deque, &elt1));\n\n    _z_elt_t elt2 = {.id = 2};\n    assert(_z_elt_deque_push_back(&deque, &elt2));\n    assert(_z_elt_deque_front(&deque)->id == 1);\n    assert(_z_elt_deque_back(&deque)->id == 2);\n\n    _z_elt_t elt3 = {.id = 3};\n    assert(_z_elt_deque_push_back(&deque, &elt3));\n    assert(_z_elt_deque_front(&deque)->id == 1);\n    assert(_z_elt_deque_back(&deque)->id == 3);\n\n    assert(_z_elt_deque_size(&deque) == 4);\n    assert(!_z_elt_deque_is_empty(&deque));\n\n    _z_elt_t elt4 = {.id = 4};\n    assert(!_z_elt_deque_push_back(&deque, &elt4));\n    assert(_z_elt_deque_front(&deque)->id == 1);\n    assert(_z_elt_deque_back(&deque)->id == 3);\n\n    _z_elt_t out;\n    assert(_z_elt_deque_pop_front(&deque, &out));\n    assert(out.id == 1);\n    assert(_z_elt_deque_front(&deque)->id == 0);\n    assert(_z_elt_deque_back(&deque)->id == 3);\n    assert(_z_elt_deque_pop_back(&deque, &out));\n    assert(out.id == 3);\n    assert(_z_elt_deque_front(&deque)->id == 0);\n    assert(_z_elt_deque_back(&deque)->id == 2);\n    assert(_z_elt_deque_size(&deque) == 2);\n\n    // Clean up remaining elements\n    _z_elt_deque_destroy(&deque);\n    assert(_z_elt_deque_size(&deque) == 0);\n    assert(destroyed_elts == 2);\n}\n\nint main(void) {\n    ring_test();\n    ring_test_init_free();\n    lifo_test();\n    lifo_test_init_free();\n    fifo_test();\n    fifo_test_init_free();\n\n    int_map_iterator_test();\n    int_map_iterator_deletion_test();\n    int_map_extract_test();\n    ring_iterator_test();\n\n    slist_test();\n\n    sorted_map_iterator_test();\n    sorted_map_iterator_deletion_test();\n    sorted_map_replace_test();\n    sorted_map_missing_key_test();\n    sorted_map_empty_test();\n    sorted_map_pop_first_test();\n    sorted_map_copy_move_test();\n    sorted_map_free_test();\n    sorted_map_stress_test();\n\n    deque_test();\n}\n"
  },
  {
    "path": "tests/z_condvar_wait_until_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <assert.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/system/platform.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_MULTI_THREAD == 1\ntypedef struct {\n    z_loaned_mutex_t* m;\n    z_loaned_condvar_t* cv;\n} task_arg_t;\n\nvoid* task_fn(void* arg) {\n    task_arg_t* typed = (task_arg_t*)arg;\n    z_mutex_lock(typed->m);\n    z_sleep_s(2);\n    z_condvar_signal(typed->cv);\n    z_mutex_unlock(typed->m);\n    return NULL;\n}\n#endif\n\nint main(void) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    z_owned_condvar_t cv;\n    z_owned_mutex_t m;\n\n    z_mutex_init(&m);\n    z_condvar_init(&cv);\n\n    assert(z_mutex_lock(z_mutex_loan_mut(&m)) == Z_OK);\n    for (unsigned i = 1; i <= 5; i++) {\n        printf(\"Check timedout wait: %d seconds\\n\", i);\n        z_clock_t c = z_clock_now();\n        z_clock_t deadline = c;\n        z_clock_advance_s(&deadline, i);\n        assert(z_condvar_wait_until(z_condvar_loan_mut(&cv), z_mutex_loan_mut(&m), &deadline) == Z_ETIMEDOUT);\n        ;\n        unsigned long elapsed = z_clock_elapsed_ms(&c);\n        assert(elapsed > (i * 1000 - 500) && elapsed < (i * 1000 + 500));\n    }\n\n    printf(\"Check successful wait\\n\");\n    z_clock_t c = z_clock_now();\n    z_clock_t deadline = c;\n    z_clock_advance_s(&deadline, 10);\n    z_owned_task_t task;\n    task_arg_t arg;\n    arg.m = z_mutex_loan_mut(&m);\n    arg.cv = z_condvar_loan_mut(&cv);\n\n    assert(z_task_init(&task, NULL, task_fn, &arg) == Z_OK);\n\n    assert(z_condvar_wait_until(z_condvar_loan_mut(&cv), z_mutex_loan_mut(&m), &deadline) == Z_OK);\n    unsigned long elapsed = z_clock_elapsed_ms(&c);\n    assert(elapsed < 5000);\n\n    z_task_join(z_task_move(&task));\n    z_mutex_unlock(z_mutex_loan_mut(&m));\n    z_condvar_drop(z_condvar_move(&cv));\n    z_mutex_drop(z_mutex_move(&m));\n#endif\n}\n"
  },
  {
    "path": "tests/z_data_struct_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nvoid str_vec_list_intmap_test(void) {\n    char *s = (char *)malloc(64);\n    size_t len = 128;\n\n    // str-vec\n    printf(\">>> str-vec\\r\\n\");\n\n    _z_str_vec_t vec = _z_str_vec_make(1);\n    assert(_z_str_vec_is_empty(&vec) == true);\n\n    for (size_t i = 0; i < len; i++) {\n        snprintf(s, 64, \"%zu\", i);\n\n        _z_str_vec_append(&vec, _z_str_clone(s));\n        char *e = _z_str_vec_get(&vec, i);\n        printf(\"append(%zu) = %s\\r\\n\", i, e);\n        assert(_z_str_eq(s, e) == true);\n\n        _z_str_vec_set(&vec, i, _z_str_clone(s));\n        e = _z_str_vec_get(&vec, i);\n        printf(\"set(%zu) = %s\\r\\n\", i, e);\n        assert(_z_str_eq(s, e) == true);\n\n        assert(_z_str_vec_len(&vec) == i + 1);\n    }\n    assert(_z_str_vec_len(&vec) == len);\n\n    _z_str_vec_clear(&vec);\n    assert(_z_str_vec_is_empty(&vec) == true);\n\n    // str-list\n    printf(\">>> str-list\\r\\n\");\n\n    _z_str_list_t *list = _z_str_list_new();\n    assert(_z_str_list_is_empty(list) == true);\n\n    for (size_t i = 0; i < len; i++) {\n        snprintf(s, 64, \"%zu\", i);\n        list = _z_str_list_push(list, _z_str_clone(s));\n\n        char *e = _z_str_list_value(list);\n        printf(\"push(%zu) = %s\\r\\n\", i, e);\n        assert(_z_str_eq(s, e) == true);\n\n        assert(_z_str_list_len(list) == i + 1);\n    }\n    assert(_z_str_list_len(list) == len);\n\n    for (size_t i = 0; i < len; i++) {\n        snprintf(s, 64, \"%zu\", i);\n        list = _z_str_list_pop(list, NULL);\n        assert(_z_str_list_len(list) == len - (i + 1));\n    }\n    assert(_z_str_list_is_empty(list) == true);\n\n    for (size_t i = 0; i < len; i++) {\n        snprintf(s, 64, \"%zu\", i);\n        list = _z_str_list_push(list, _z_str_clone(s));\n        assert(_z_str_eq(s, _z_str_list_value(list)) == true);\n    }\n    assert(_z_str_list_len(list) == len);\n    _z_str_list_free(&list);\n    assert(_z_str_list_is_empty(list) == true);\n\n    // str-intmap\n    printf(\">>> str-intmap\\r\\n\");\n\n    _z_str_intmap_t map = _z_str_intmap_make();\n    assert(_z_str_intmap_is_empty(&map) == true);\n\n    for (size_t i = 0; i < len; i++) {\n        snprintf(s, 64, \"%zu\", i);\n        _z_str_intmap_insert(&map, i, _z_str_clone(s));\n\n        char *e = _z_str_intmap_get(&map, i);\n        printf(\"get(%zu) = %s\\r\\n\", i, e);\n        assert(_z_str_eq(s, e) == true);\n\n        assert(_z_str_intmap_len(&map) == i + 1);\n    }\n    assert(_z_str_intmap_len(&map) == len);\n\n    for (size_t i = 0; i < len; i++) {\n        _z_str_intmap_remove(&map, i);\n        assert(_z_str_intmap_get(&map, i) == NULL);\n        assert(_z_str_intmap_len(&map) == (len - 1) - i);\n    }\n    assert(_z_str_intmap_is_empty(&map) == true);\n\n    _z_str_intmap_clear(&map);\n    assert(_z_str_intmap_is_empty(&map) == true);\n\n    z_free(s);\n}\n\nvoid _z_slice_custom_deleter(void *data, void *context) {\n    _ZP_UNUSED(data);\n    size_t *cnt = (size_t *)context;\n    (*cnt)++;\n}\n\nvoid z_slice_custom_delete_test(void) {\n    size_t counter = 0;\n    uint8_t data[5] = {1, 2, 3, 4, 5};\n    _z_delete_context_t dc = (_z_delete_context_t){.deleter = _z_slice_custom_deleter, .context = &counter};\n    _z_slice_t s1 = _z_slice_from_buf_custom_deleter(data, 5, dc);\n    _z_slice_t s2 = _z_slice_from_buf_custom_deleter(data, 5, dc);\n    _z_slice_t s3 = _z_slice_copy_from_buf(data, 5);\n    _z_slice_t s4 = _z_slice_alias_buf(data, 5);\n    assert(_z_slice_is_alloced(&s1));\n    assert(_z_slice_is_alloced(&s2));\n    assert(_z_slice_is_alloced(&s3));\n    assert(!_z_slice_is_alloced(&s4));\n\n    _z_slice_clear(&s1);\n    _z_slice_clear(&s2);\n    _z_slice_clear(&s3);\n    _z_slice_clear(&s4);\n    assert(counter == 2);\n}\n\nvoid z_string_array_test(void) {\n    // create new array\n    z_owned_string_array_t a;\n    z_string_array_new(&a);\n\n    char s1[] = \"string1\";\n    char s2[] = \"string2\";\n    char s3[] = \"string3\";\n    char s4[] = \"string4\";\n\n    // add by copy\n    z_view_string_t vs1;\n    z_view_string_from_str(&vs1, s1);\n    assert(z_string_array_push_by_copy(z_string_array_loan_mut(&a), z_view_string_loan(&vs1)) == 1);\n\n    z_view_string_t vs2;\n    z_view_string_from_str(&vs2, s2);\n    assert(z_string_array_push_by_copy(z_string_array_loan_mut(&a), z_view_string_loan(&vs2)) == 2);\n\n    // add by alias\n    z_view_string_t vs3;\n    z_view_string_from_str(&vs3, s3);\n    assert(z_string_array_push_by_alias(z_string_array_loan_mut(&a), z_view_string_loan(&vs3)) == 3);\n\n    z_view_string_t vs4;\n    z_view_string_from_str(&vs4, s4);\n    assert(z_string_array_push_by_alias(z_string_array_loan_mut(&a), z_view_string_loan(&vs4)) == 4);\n\n    // check values\n    const z_loaned_string_t *ls1 = z_string_array_get(z_string_array_loan(&a), 0);\n    assert(strncmp(z_string_data(ls1), s1, z_string_len(ls1)) == 0);\n\n    const z_loaned_string_t *ls2 = z_string_array_get(z_string_array_loan(&a), 1);\n    assert(strncmp(z_string_data(ls2), s2, z_string_len(ls2)) == 0);\n\n    const z_loaned_string_t *ls3 = z_string_array_get(z_string_array_loan(&a), 2);\n    assert(strncmp(z_string_data(ls3), s3, z_string_len(ls3)) == 0);\n\n    const z_loaned_string_t *ls4 = z_string_array_get(z_string_array_loan(&a), 3);\n    assert(strncmp(z_string_data(ls4), s4, z_string_len(ls4)) == 0);\n\n    // modify original strings values\n    s1[0] = 'X';\n    s2[0] = 'X';\n    s3[0] = 'X';\n    s4[0] = 'X';\n\n    // values passed by copy should NOT be changed\n    ls1 = z_string_array_get(z_string_array_loan(&a), 0);\n    assert(strncmp(z_string_data(ls1), \"string1\", z_string_len(ls1)) == 0);\n\n    ls2 = z_string_array_get(z_string_array_loan(&a), 1);\n    assert(strncmp(z_string_data(ls2), \"string2\", z_string_len(ls2)) == 0);\n\n    // values passed by alias should be changed\n    ls3 = z_string_array_get(z_string_array_loan(&a), 2);\n    assert(strncmp(z_string_data(ls3), s3, z_string_len(ls3)) == 0);\n\n    ls4 = z_string_array_get(z_string_array_loan(&a), 3);\n    assert(strncmp(z_string_data(ls4), s4, z_string_len(ls4)) == 0);\n\n    // cleanup\n    z_string_array_drop(z_string_array_move(&a));\n}\n\nvoid z_id_to_string_test(void) {\n    z_id_t id;\n    for (uint8_t i = 0; i < sizeof(id.id); i++) {\n        id.id[i] = i;\n    }\n    z_owned_string_t id_str;\n    z_id_to_string(&id, &id_str);\n    assert(z_string_len(z_string_loan(&id_str)) == 32);\n    assert(strncmp(\"0f0e0d0c0b0a09080706050403020100\", z_string_data(z_string_loan(&id_str)),\n                   z_string_len(z_string_loan(&id_str))) == 0);\n    z_string_drop(z_string_move(&id_str));\n}\n\nint main(void) {\n    str_vec_list_intmap_test();\n    z_slice_custom_delete_test();\n    z_string_array_test();\n    z_id_to_string_test();\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_endpoint_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/link/config/udp.h\"\n#include \"zenoh-pico/link/endpoint.h\"\n#include \"zenoh-pico/utils/result.h\"\n#if Z_FEATURE_LINK_WS == 1\n#include \"zenoh-pico/link/config/ws.h\"\n#endif\n#if Z_FEATURE_LINK_TLS == 1\n#include \"zenoh-pico/link/config/tls.h\"\n#endif\n\n#undef NDEBUG\n#include <assert.h>\n\nint main(void) {\n    // Locator\n    printf(\">>> Testing locators...\\n\");\n\n    _z_locator_t lc;\n\n    _z_string_t str = _z_string_alias_str(\"tcp/127.0.0.1:7447\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_RES_OK);\n\n    str = _z_string_alias_str(\"tcp\");\n    assert(_z_string_equals(&lc._protocol, &str) == true);\n    str = _z_string_alias_str(\"127.0.0.1:7447\");\n    assert(_z_string_equals(&lc._address, &str) == true);\n    assert(_z_str_intmap_is_empty(&lc._metadata) == true);\n    _z_locator_clear(&lc);\n\n    str = _z_string_alias_str(\"\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_locator_clear(&lc);\n\n    str = _z_string_alias_str(\"/\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_locator_clear(&lc);\n\n    str = _z_string_alias_str(\"tcp\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_locator_clear(&lc);\n\n    str = _z_string_alias_str(\"tcp/\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_locator_clear(&lc);\n\n    str = _z_string_alias_str(\"127.0.0.1:7447\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_locator_clear(&lc);\n\n    str = _z_string_alias_str(\"tcp/127.0.0.1:7447?\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_RES_OK);\n    _z_locator_clear(&lc);\n\n    // No metadata defined so far... but this is a valid syntax in principle\n    str = _z_string_alias_str(\"tcp/127.0.0.1:7447?invalid=ctrl\");\n    assert(_z_locator_from_string(&lc, &str) == _Z_RES_OK);\n    _z_locator_clear(&lc);\n\n    // Endpoint\n    printf(\">>> Testing endpoints...\\n\");\n\n    _z_endpoint_t ep;\n\n    str = _z_string_alias_str(\"tcp/127.0.0.1:7447\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n\n    str = _z_string_alias_str(\"tcp\");\n    assert(_z_string_equals(&ep._locator._protocol, &str) == true);\n    str = _z_string_alias_str(\"127.0.0.1:7447\");\n    assert(_z_string_equals(&ep._locator._address, &str) == true);\n    assert(_z_str_intmap_is_empty(&ep._locator._metadata) == true);\n    assert(_z_str_intmap_is_empty(&ep._config) == true);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"/\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tcp\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tcp/\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"127.0.0.1:7447\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tcp/127.0.0.1:7447?\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    // No metadata defined so far... but this is a valid syntax in principle\n    str = _z_string_alias_str(\"tcp/127.0.0.1:7447?invalid=ctrl\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"udp/127.0.0.1:7447#iface=eth0\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n\n    str = _z_string_alias_str(\"udp\");\n    assert(_z_string_equals(&ep._locator._protocol, &str) == true);\n    str = _z_string_alias_str(\"127.0.0.1:7447\");\n    assert(_z_string_equals(&ep._locator._address, &str) == true);\n    assert(_z_str_intmap_is_empty(&ep._locator._metadata) == true);\n    assert(_z_str_intmap_len(&ep._config) == 1);\n    char *p = _z_str_intmap_get(&ep._config, UDP_CONFIG_IFACE_KEY);\n    assert(_z_str_eq(p, \"eth0\") == true);\n    (void)(p);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"udp/127.0.0.1:7447#invalid=eth0\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"udp/127.0.0.1:7447?invalid=ctrl#iface=eth0\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"udp/127.0.0.1:7447?invalid=ctrl#invalid=eth0\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n#if Z_FEATURE_LINK_WS == 1\n    str = _z_string_alias_str(\"ws/localhost:7447#tout=1000\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n\n    str = _z_string_alias_str(\"ws\");\n    assert(_z_string_equals(&ep._locator._protocol, &str) == true);\n    str = _z_string_alias_str(\"localhost:7447\");\n    assert(_z_string_equals(&ep._locator._address, &str) == true);\n    assert(_z_str_intmap_len(&ep._config) == 1);\n    char *tout = _z_str_intmap_get(&ep._config, WS_CONFIG_TOUT_KEY);\n    assert(_z_str_eq(tout, \"1000\") == true);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"ws/[::1]:7447\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"ws/\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n#endif\n\n#if Z_FEATURE_LINK_TLS == 1\n    str = _z_string_alias_str(\"tls/localhost:7447#root_ca_certificate=/path/ca.pem\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n\n    str = _z_string_alias_str(\"tls\");\n    assert(_z_string_equals(&ep._locator._protocol, &str) == true);\n    str = _z_string_alias_str(\"localhost:7447\");\n    assert(_z_string_equals(&ep._locator._address, &str) == true);\n    assert(_z_str_intmap_len(&ep._config) == 1);\n    char *ca_path = _z_str_intmap_get(&ep._config, TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY);\n    assert(_z_str_eq(ca_path, \"/path/ca.pem\") == true);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tls/[::1]:7447\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tls/localhost:7447#invalid=value\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_RES_OK);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tls/\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n\n    str = _z_string_alias_str(\"tls\");\n    assert(_z_endpoint_from_string(&ep, &str) == _Z_ERR_CONFIG_LOCATOR_INVALID);\n    _z_endpoint_clear(&ep);\n#endif\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_executor_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n\n#include \"zenoh-pico/runtime/executor.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\ntypedef struct {\n    int call_count;\n    bool destroyed;\n} test_arg_t;\n\n// Finishes immediately\nstatic _z_fut_fn_result_t fn_finish(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    a->call_count++;\n    return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_READY};\n}\n\n// Reschedules with a wake_up_time, finishes on second call\nstatic _z_fut_fn_result_t fn_reschedule_timed(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    a->call_count++;\n    if (a->call_count == 1) {\n        z_clock_t wake = z_clock_now();\n        z_clock_advance_ms(&wake, 500);  // wake up after 500ms\n        return (_z_fut_fn_result_t){\n            ._status = _Z_FUT_STATUS_SLEEPING,\n            ._wake_up_time = wake,\n        };\n    }\n    return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_READY};\n}\n\n// Reschedules without wake_up_time (goes back to regular deque), finishes on second call\nstatic _z_fut_fn_result_t fn_reschedule_deque(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    a->call_count++;\n    if (a->call_count == 1) {\n        return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_RUNNING};\n    }\n    return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_READY};\n}\n\n// Spawns a child future into the executor, then finishes\nstatic _z_fut_fn_result_t fn_spawn_child(void *arg, _z_executor_t *ex) {\n    test_arg_t *child_arg = (test_arg_t *)arg;\n    _z_fut_t child = _z_fut_new(child_arg, fn_finish, NULL);\n    _z_executor_spawn(ex, &child);\n    return (_z_fut_fn_result_t){._status = _Z_FUT_STATUS_READY};\n}\n\nstatic void destroy_fn(void *arg) {\n    test_arg_t *a = (test_arg_t *)arg;\n    a->destroyed = true;\n}\n\n// Suspends on first call; caller must resume it externally; finishes on second call.\nstatic _z_fut_fn_result_t fn_suspend_once(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    a->call_count++;\n    if (a->call_count == 1) {\n        return _z_fut_fn_result_suspend();\n    }\n    return _z_fut_fn_result_ready();\n}\n\n// Suspends indefinitely (never returns READY on its own).\nstatic _z_fut_fn_result_t fn_suspend_forever(void *arg, _z_executor_t *ex) {\n    (void)ex;\n    test_arg_t *a = (test_arg_t *)arg;\n    a->call_count++;\n    return _z_fut_fn_result_suspend();\n}\n\n// Drain the executor until NO_TASKS or max_spins reached; return number of spins\nstatic int drain(_z_executor_t *ex, int max_spins) {\n    int spins = 0;\n    while (spins++ < max_spins) {\n        _z_executor_spin_result_t r = _z_executor_spin(ex);\n        if (r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS) break;\n    }\n    return spins;\n}\n\n// ─── Tests ───────────────────────────────────────────────────────────────────\n\n// Spin on a freshly created executor returns NO_TASKS.\nstatic void test_spin_empty(void) {\n    printf(\"Test: spin on empty executor returns NO_TASKS\\n\");\n    _z_executor_t ex = _z_executor_new();\n    _z_executor_spin_result_t r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n    _z_executor_destroy(&ex);\n}\n\n// A future with a handle: status transitions RUNNING → READY.\nstatic void test_spawn_with_handle_status_transitions(void) {\n    printf(\"Test: future with handle transitions RUNNING -> READY\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_RUNNING);\n\n    drain(&ex, 10);\n    assert(arg.call_count == 1);\n    assert(arg.destroyed == true);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    _z_executor_destroy(&ex);\n}\n\n// A future returning SLEEPING is re-queued in the timed pqueue.\nstatic void test_timed_reschedule(void) {\n    printf(\"Test: timed reschedule re-queues in timed pqueue and eventually finishes\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_reschedule_timed, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n\n    // First spin: task runs once, reschedules with immediate wake_up_time\n    _z_executor_spin_result_t r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK);\n    assert(arg.call_count == 1);\n    assert(arg.destroyed == false);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_SLEEPING);\n\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_SHOULD_WAIT);\n    z_clock_t now = z_clock_now();\n    assert(zp_clock_elapsed_ms_since(&r.next_wake_up_time, &now) > 300);\n    z_sleep_ms(100);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_SHOULD_WAIT);\n    assert(zp_clock_elapsed_ms_since(&r.next_wake_up_time, &now) > 200);\n\n    z_sleep_ms(600);\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    assert(arg.call_count == 2);\n    assert(arg.destroyed == true);\n\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n\n    _z_executor_destroy(&ex);\n}\n\n// A future returning RUNNING is re-queued in the regular deque.\nstatic void test_deque_reschedule(void) {\n    printf(\"Test: deque reschedule re-queues at back of deque and finishes on next spin\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_reschedule_deque, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n\n    // First spin: task runs, returns not-ready, pushed back to deque\n    _z_executor_spin_result_t r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK);\n    assert(arg.call_count == 1);\n    assert(arg.destroyed == false);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_RUNNING);\n\n    // Second spin: task runs again and finishes\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK);\n    assert(arg.call_count == 2);\n    assert(arg.destroyed == true);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n    _z_executor_destroy(&ex);\n}\n\n// Cancelling a handle before spin: body never runs, destroy_fn still called.\nstatic void test_cancel_before_spin(void) {\n    printf(\"Test: cancel before spin prevents body; destroy_fn still called\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n    _z_executor_cancel_fut(&ex, &h);\n    assert(_z_executor_get_fut_status(&ex, &h) ==\n           _Z_FUT_STATUS_READY);  // cancelled tasks are considered ready (not pending or running)\n\n    drain(&ex, 10);\n    assert(arg.call_count == 0);    // body never ran\n    assert(arg.destroyed == true);  // destroy_fn still ran\n\n    _z_executor_destroy(&ex);\n}\n\n// Cancelling after the task finishes is a safe no-op; status stays READY.\nstatic void test_cancel_after_finish(void) {\n    printf(\"Test: cancel on READY handle is a no-op\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n\n    drain(&ex, 10);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    // Must not crash or corrupt status\n    assert(!_z_executor_cancel_fut(&ex, &h));\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    _z_executor_destroy(&ex);\n}\n\n// A task may spawn a child via the executor* passed to the fn.\nstatic void test_task_spawns_child(void) {\n    printf(\"Test: task can spawn a child future via executor pointer\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t child_arg = {0};\n\n    _z_fut_t parent = _z_fut_new(&child_arg, fn_spawn_child, NULL);\n    assert(!_z_fut_handle_is_null(_z_executor_spawn(&ex, &parent)));\n\n    // First spin: parent runs, spawns child into executor\n    _z_executor_spin(&ex);\n\n    // Remaining spins: child runs\n    drain(&ex, 10);\n    assert(child_arg.call_count == 1);\n\n    _z_executor_destroy(&ex);\n}\n\n// N independent tasks all complete when drained.\nstatic void test_multiple_tasks(void) {\n    printf(\"Test: multiple futures all complete\\n\");\n    _z_executor_t ex = _z_executor_new();\n    const int N = 8;\n    test_arg_t args[8];\n\n    for (int i = 0; i < N; i++) {\n        args[i] = (test_arg_t){0};\n        _z_fut_t fut = _z_fut_new(&args[i], fn_finish, destroy_fn);\n        assert(!_z_fut_handle_is_null(_z_executor_spawn(&ex, &fut)));\n    }\n\n    drain(&ex, N * 4);\n\n    for (int i = 0; i < N; i++) {\n        assert(args[i].call_count == 1);\n        assert(args[i].destroyed == true);\n    }\n    assert(_z_executor_spin(&ex).status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n    _z_executor_destroy(&ex);\n}\n\n// _z_executor_destroy calls destroy_fn on tasks that never ran.\nstatic void test_destroy_drains_pending(void) {\n    printf(\"Test: _z_executor_destroy calls destroy_fn on all pending futures\\n\");\n    _z_executor_t ex = _z_executor_new();\n    const int N = 4;\n    test_arg_t args[4];\n\n    for (int i = 0; i < N; i++) {\n        args[i] = (test_arg_t){0};\n        _z_fut_t fut = _z_fut_new(&args[i], fn_finish, destroy_fn);\n        assert(!_z_fut_handle_is_null(_z_executor_spawn(&ex, &fut)));\n    }\n\n    // Destroy without any spinning\n    _z_executor_destroy(&ex);\n\n    for (int i = 0; i < N; i++) {\n        assert(args[i].call_count == 0);    // body never ran\n        assert(args[i].destroyed == true);  // destroy_fn called by deque teardown\n    }\n}\n\n// ─── Tests: suspend / resume ─────────────────────────────────────────────────\n\n// A task returning SUSPENDED is not run again until explicitly resumed.\nstatic void test_suspend_and_resume(void) {\n    printf(\"Test: suspended task is skipped until resumed\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_suspend_once, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n\n    // First spin: task runs and suspends — counts as EXECUTED_TASK.\n    _z_executor_spin_result_t r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK);\n    assert(arg.call_count == 1);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_SUSPENDED);\n\n    // Additional spins do nothing — task is still suspended.\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n    assert(arg.call_count == 1);  // body must not have run again\n\n    // Resume: task becomes runnable again.\n    assert(_z_executor_resume_suspended_fut(&ex, &h));\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    // Next spin: task runs and finishes.\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_EXECUTED_TASK);\n    assert(arg.call_count == 2);\n    assert(arg.destroyed == true);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n\n    _z_executor_destroy(&ex);\n}\n\n// Resuming a task that is not suspended is a safe no-op.\nstatic void test_resume_non_suspended_is_noop(void) {\n    printf(\"Test: resume on non-suspended task is a no-op\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_finish, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n\n    // Task is RUNNING (not yet executed), resume must be a no-op.\n    assert(!_z_executor_resume_suspended_fut(&ex, &h));\n\n    drain(&ex, 10);\n    assert(arg.call_count == 1);\n\n    // Task is now gone (READY); resume must be a no-op.\n    assert(!_z_executor_resume_suspended_fut(&ex, &h));\n\n    _z_executor_destroy(&ex);\n}\n\n// A suspended task can be cancelled; its destroy_fn is still called.\nstatic void test_cancel_suspended(void) {\n    printf(\"Test: cancel on suspended task calls destroy_fn\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_suspend_forever, destroy_fn);\n    _z_fut_handle_t h = _z_executor_spawn(&ex, &fut);\n    assert(!_z_fut_handle_is_null(h));\n\n    // Run once: task suspends.\n    _z_executor_spin(&ex);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_SUSPENDED);\n    assert(arg.destroyed == false);\n\n    // Cancel while suspended.\n    assert(_z_executor_cancel_fut(&ex, &h));\n    assert(arg.destroyed == true);\n    assert(_z_executor_get_fut_status(&ex, &h) == _Z_FUT_STATUS_READY);\n\n    // Executor is now empty.\n    _z_executor_spin_result_t r = _z_executor_spin(&ex);\n    assert(r.status == _Z_EXECUTOR_SPIN_RESULT_NO_TASKS);\n\n    _z_executor_destroy(&ex);\n}\n\n// Suspend does not starve other ready tasks: they run while one task is suspended.\nstatic void test_other_tasks_run_while_suspended(void) {\n    printf(\"Test: other tasks run while one task is suspended\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t suspended_arg = {0};\n    test_arg_t other_arg = {0};\n\n    _z_fut_t suspended_fut = _z_fut_new(&suspended_arg, fn_suspend_once, NULL);\n    _z_fut_handle_t suspended_h = _z_executor_spawn(&ex, &suspended_fut);\n\n    _z_fut_t other_fut = _z_fut_new(&other_arg, fn_finish, destroy_fn);\n    _z_executor_spawn(&ex, &other_fut);\n\n    // Spin until suspended task suspends: the other task should also get a turn.\n    drain(&ex, 10);\n\n    assert(suspended_arg.call_count == 1);\n    assert(_z_executor_get_fut_status(&ex, &suspended_h) == _Z_FUT_STATUS_SUSPENDED);\n    assert(other_arg.call_count == 1);  // other_fut must have run\n    assert(other_arg.destroyed == true);\n\n    _z_executor_resume_suspended_fut(&ex, &suspended_h);\n    drain(&ex, 10);\n    assert(suspended_arg.call_count == 2);\n\n    _z_executor_destroy(&ex);\n}\n\n// destroy is called for suspended tasks that are still pending when executor is torn down.\nstatic void test_destroy_cleans_up_suspended(void) {\n    printf(\"Test: _z_executor_destroy calls destroy_fn on suspended futures\\n\");\n    _z_executor_t ex = _z_executor_new();\n    test_arg_t arg = {0};\n\n    _z_fut_t fut = _z_fut_new(&arg, fn_suspend_forever, destroy_fn);\n    _z_executor_spawn(&ex, &fut);\n\n    _z_executor_spin(&ex);  // task suspends\n    assert(arg.destroyed == false);\n\n    _z_executor_destroy(&ex);\n    assert(arg.destroyed == true);\n}\n\n// ─── main ────────────────────────────────────────────────────────────────────\n\nint main(void) {\n    test_spin_empty();\n    test_spawn_with_handle_status_transitions();\n    test_timed_reschedule();\n    test_deque_reschedule();\n    test_cancel_before_spin();\n    test_cancel_after_finish();\n    test_task_spawns_child();\n    test_multiple_tasks();\n    test_destroy_drains_pending();\n    test_suspend_and_resume();\n    test_resume_non_suspended_is_noop();\n    test_cancel_suspended();\n    test_other_tasks_run_while_suspended();\n    test_destroy_cleans_up_suspended();\n    printf(\"All executor tests passed.\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_hashmap_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n\n#undef NDEBUG\n#include <assert.h>\n\n// ── Instantiate uint32_t -> uint32_t, 8 buckets, capacity 12 ─────────────────\n\nstatic inline size_t u32_hash(const uint32_t *k) {\n    uint32_t x = *k;\n    x ^= x >> 16;\n    x *= 0x45d9f3bU;\n    x ^= x >> 16;\n    return (size_t)x;\n}\nstatic inline bool u32_eq(const uint32_t *a, const uint32_t *b) { return *a == *b; }\n\n#define _ZP_HASHMAP_TEMPLATE_KEY_TYPE uint32_t\n#define _ZP_HASHMAP_TEMPLATE_VAL_TYPE uint32_t\n#define _ZP_HASHMAP_TEMPLATE_NAME u32map\n#define _ZP_HASHMAP_TEMPLATE_BUCKET_COUNT 8\n#define _ZP_HASHMAP_TEMPLATE_CAPACITY 12\n#define _ZP_HASHMAP_TEMPLATE_KEY_HASH_FN_NAME u32_hash\n#define _ZP_HASHMAP_TEMPLATE_KEY_EQ_FN_NAME u32_eq\n#include \"zenoh-pico/collections/hashmap_template.h\"\n\n// ── Tests ─────────────────────────────────────────────────────────────────────\n\nstatic void test_new_is_empty(void) {\n    printf(\"Test: new map is empty\\n\");\n    u32map_t m = u32map_new();\n    assert(u32map_is_empty(&m));\n    assert(u32map_size(&m) == 0);\n    u32map_destroy(&m);\n}\n\nstatic void test_insert_and_get(void) {\n    printf(\"Test: insert then get returns value\\n\");\n    u32map_t m = u32map_new();\n    uint32_t k = 1, v = 10;\n    assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    assert(u32map_size(&m) == 1);\n    uint32_t *got = u32map_get(&m, &(uint32_t){1});\n    assert(got != NULL && *got == 10);\n    u32map_destroy(&m);\n}\n\nstatic void test_get_missing_returns_null(void) {\n    printf(\"Test: get on missing key returns NULL\\n\");\n    u32map_t m = u32map_new();\n    assert(u32map_get(&m, &(uint32_t){42}) == NULL);\n    u32map_destroy(&m);\n}\n\nstatic void test_insert_updates_existing(void) {\n    printf(\"Test: insert with duplicate key updates value, size stays same\\n\");\n    u32map_t m = u32map_new();\n    uint32_t k = 5, v1 = 50, v2 = 99;\n    assert(u32map_index_valid(u32map_insert(&m, &k, &v1)));\n    assert(u32map_index_valid(u32map_insert(&m, &(uint32_t){5}, &v2)));\n    assert(u32map_size(&m) == 1);\n    assert(*u32map_get(&m, &(uint32_t){5}) == 99);\n    u32map_destroy(&m);\n}\n\nstatic void test_remove_existing(void) {\n    printf(\"Test: remove existing key moves value out\\n\");\n    u32map_t m = u32map_new();\n    uint32_t k = 7, v = 70;\n    assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    uint32_t out = 0;\n    assert(u32map_remove(&m, &(uint32_t){7}, &out));\n    assert(out == 70);\n    assert(u32map_size(&m) == 0);\n    assert(u32map_get(&m, &(uint32_t){7}) == NULL);\n    u32map_destroy(&m);\n}\n\nstatic void test_remove_missing_returns_false(void) {\n    printf(\"Test: remove on missing key returns false\\n\");\n    u32map_t m = u32map_new();\n    assert(!u32map_remove(&m, &(uint32_t){99}, NULL));\n    u32map_destroy(&m);\n}\n\nstatic void test_remove_head_of_chain(void) {\n    printf(\"Test: remove head of a collision chain; remaining entry still accessible\\n\");\n    u32map_t m = u32map_new();\n    // Keys 0 and 8 both hash to bucket 0 with BUCKET_COUNT=8 (hash%8 == 0 for both)\n    uint32_t k0 = 0, v0 = 100;\n    uint32_t k8 = 8, v8 = 800;\n    assert(u32map_index_valid(u32map_insert(&m, &k0, &v0)));\n    assert(u32map_index_valid(u32map_insert(&m, &k8, &v8)));\n    assert(u32map_size(&m) == 2);\n    // Remove whichever is the head (k8, inserted last → prepended)\n    assert(u32map_remove(&m, &(uint32_t){8}, NULL));\n    assert(u32map_size(&m) == 1);\n    assert(*u32map_get(&m, &(uint32_t){0}) == 100);\n    assert(u32map_get(&m, &(uint32_t){8}) == NULL);\n    u32map_destroy(&m);\n}\n\nstatic void test_remove_tail_of_chain(void) {\n    printf(\"Test: remove tail of a collision chain; head still accessible\\n\");\n    u32map_t m = u32map_new();\n    uint32_t k0 = 0, v0 = 100;\n    uint32_t k8 = 8, v8 = 800;\n    assert(u32map_index_valid(u32map_insert(&m, &k0, &v0)));\n    assert(u32map_index_valid(u32map_insert(&m, &k8, &v8)));\n    assert(u32map_remove(&m, &(uint32_t){0}, NULL));  // tail (inserted first)\n    assert(u32map_size(&m) == 1);\n    assert(*u32map_get(&m, &(uint32_t){8}) == 800);\n    assert(u32map_get(&m, &(uint32_t){0}) == NULL);\n    u32map_destroy(&m);\n}\n\nstatic void test_contains(void) {\n    printf(\"Test: contains\\n\");\n    u32map_t m = u32map_new();\n    assert(!u32map_contains(&m, &(uint32_t){3}));\n    uint32_t k = 3, v = 30;\n    assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    assert(u32map_contains(&m, &(uint32_t){3}));\n    assert(u32map_remove(&m, &(uint32_t){3}, NULL));\n    assert(!u32map_contains(&m, &(uint32_t){3}));\n    u32map_destroy(&m);\n}\n\nstatic void test_clear_and_reuse(void) {\n    printf(\"Test: clear empties the map and frees pool for reuse\\n\");\n    u32map_t m = u32map_new();\n    for (uint32_t i = 0; i < 12; i++) {\n        uint32_t k = i, v = i * 10;\n        assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    }\n    assert(u32map_size(&m) == 12);\n    u32map_destroy(&m);\n    assert(u32map_is_empty(&m));\n    // Pool fully freed — all 12 slots available again\n    for (uint32_t i = 0; i < 12; i++) {\n        uint32_t k = i + 100, v = i;\n        assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    }\n    assert(u32map_size(&m) == 12);\n    u32map_destroy(&m);\n}\n\nstatic void test_pool_exhaustion(void) {\n    printf(\"Test: insert fails when pool is exhausted\\n\");\n    u32map_t m = u32map_new();\n    for (uint32_t i = 0; i < 12; i++) {\n        uint32_t k = i, v = i;\n        assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    }\n    // One more distinct key must fail\n    uint32_t k = 200, v = 200;\n    assert(!u32map_index_valid(u32map_insert(&m, &k, &v)));\n    // Updating an existing key must still succeed (no new pool slot needed)\n    uint32_t ku = 0, vu = 255;\n    assert(u32map_index_valid(u32map_insert(&m, &ku, &vu)));\n    assert(*u32map_get(&m, &(uint32_t){0}) == 255);\n    u32map_destroy(&m);\n}\n\nstatic void test_pool_slot_reused_after_remove(void) {\n    printf(\"Test: pool slot freed by remove is reused by subsequent insert\\n\");\n    u32map_t m = u32map_new();\n    // Fill to capacity\n    for (uint32_t i = 0; i < 12; i++) {\n        uint32_t k = i, v = i;\n        assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    }\n    // Remove one entry to free a slot\n    assert(u32map_remove(&m, &(uint32_t){0}, NULL));\n    assert(u32map_size(&m) == 11);\n    // Now a new key must succeed\n    uint32_t k = 200, v = 200;\n    assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    assert(u32map_size(&m) == 12);\n    assert(*u32map_get(&m, &(uint32_t){200}) == 200);\n    u32map_destroy(&m);\n}\n\nstatic void test_multiple_collisions(void) {\n    printf(\"Test: many keys colliding into the same bucket\\n\");\n    u32map_t m = u32map_new();\n    // With BUCKET_COUNT=8, keys 0,8,16,24,32,40 all land in bucket 0\n    uint32_t keys[] = {0, 8, 16, 24, 32, 40};\n    for (size_t i = 0; i < 6; i++) {\n        uint32_t k = keys[i], v = keys[i] * 10;\n        assert(u32map_index_valid(u32map_insert(&m, &k, &v)));\n    }\n    assert(u32map_size(&m) == 6);\n    for (size_t i = 0; i < 6; i++) {\n        uint32_t *got = u32map_get(&m, &keys[i]);\n        assert(got != NULL && *got == keys[i] * 10);\n    }\n    // Remove middle entries and verify survivors\n    assert(u32map_remove(&m, &(uint32_t){16}, NULL));\n    assert(u32map_remove(&m, &(uint32_t){32}, NULL));\n    assert(u32map_size(&m) == 4);\n    assert(u32map_get(&m, &(uint32_t){16}) == NULL);\n    assert(u32map_get(&m, &(uint32_t){32}) == NULL);\n    assert(*u32map_get(&m, &(uint32_t){0}) == 0);\n    assert(*u32map_get(&m, &(uint32_t){8}) == 80);\n    assert(*u32map_get(&m, &(uint32_t){24}) == 240);\n    assert(*u32map_get(&m, &(uint32_t){40}) == 400);\n    u32map_destroy(&m);\n}\n\nint main(void) {\n    test_new_is_empty();\n    test_insert_and_get();\n    test_get_missing_returns_null();\n    test_insert_updates_existing();\n    test_remove_existing();\n    test_remove_missing_returns_false();\n    test_remove_head_of_chain();\n    test_remove_tail_of_chain();\n    test_contains();\n    test_clear_and_reuse();\n    test_pool_exhaustion();\n    test_pool_slot_reused_after_remove();\n    test_multiple_collisions();\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_iobuf_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/protocol/iobuf.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define RUNS 1000\n\n/*=============================*/\n/*     Printing functions      */\n/*=============================*/\nvoid print_zbuf_overview(_z_zbuf_t *zbf) { printf(\"    ZBuf => Capacity: %zu\\n\", zbf->_ios._capacity); }\n\nvoid print_wbuf_overview(_z_wbuf_t *wbf) {\n    printf(\"    WBuf => Expandable: %zu, Capacity: %zu\\n\", wbf->_expansion_step, _z_wbuf_capacity(wbf));\n}\n\nvoid print_iosli(_z_iosli_t *ios) {\n    printf(\"IOSli: Capacity: %zu, Rpos: %zu, Wpos: %zu, Buffer: [ \", ios->_capacity, ios->_r_pos, ios->_w_pos);\n    for (size_t i = 0; i < ios->_w_pos; i++) {\n        printf(\"%02x\", ios->_buf[i]);\n        if (i < ios->_capacity - 1) printf(\" \");\n    }\n    printf(\" ]\");\n}\n\n/*=============================*/\n/*    Generating functions     */\n/*=============================*/\nint gen_bool(void) { return z_random_u8() % 2; }\n\nuint8_t gen_uint8(void) { return z_random_u8() % 255; }\n\nsize_t gen_size_t(void) {\n    size_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\n_z_zbuf_t gen_zbuf(size_t len) { return _z_zbuf_make(len); }\n\n_z_wbuf_t gen_wbuf(size_t len) {\n    bool is_expandable = false;\n\n    if (gen_bool() == true) {\n        is_expandable = true;\n        len = 1 + (gen_size_t() % len);\n    }\n\n    _z_wbuf_t wbuf = _z_wbuf_make(len, is_expandable);\n    assert(_z_wbuf_capacity(&wbuf) == len);\n    return wbuf;\n}\n\n/*=============================*/\n/*           Tests             */\n/*=============================*/\nvoid iosli_writable_readable(void) {\n    size_t len = 128;\n    _z_iosli_t ios = _z_iosli_make(len);\n    _z_iosli_t *pios = _z_iosli_new(len);\n\n    printf(\"\\n>>> IOSli => Writable and Readable\\n\");\n\n    printf(\"  - IOSli write\\n\");\n    assert(_z_iosli_writable(&ios) == _z_iosli_writable(pios));\n    assert(_z_iosli_readable(&ios) == _z_iosli_readable(pios));\n\n    size_t writable = _z_iosli_writable(&ios);\n    size_t readable = _z_iosli_readable(&ios);\n\n    printf(\"    Writable: %zu\\tReadable: %zu\\n\", writable, readable);\n    assert(writable == len);\n    assert(readable == 0);\n\n    for (size_t i = 0; i < len; i++) {\n        uint8_t byte = gen_uint8();\n        _z_iosli_write(&ios, byte);\n        _z_iosli_write(pios, byte);\n\n        assert(_z_iosli_writable(&ios) == _z_iosli_writable(pios));\n        assert(_z_iosli_readable(&ios) == _z_iosli_readable(pios));\n\n        writable = _z_iosli_writable(&ios);\n        readable = _z_iosli_readable(&ios);\n\n        printf(\"    Writable: %zu\\tReadable: %zu\\n\", writable, readable);\n        assert(writable == len - (i + 1));\n        assert(readable == i + 1);\n\n        uint8_t b1 = _z_iosli_get(&ios, i);\n        uint8_t b2 = _z_iosli_get(pios, i);\n\n        assert(b1 == b2);\n        (void)(b1);\n        (void)(b2);\n    }\n\n    _z_iosli_t *cios = _z_iosli_clone(pios);\n    assert(_z_iosli_writable(pios) == _z_iosli_writable(cios));\n    assert(_z_iosli_readable(pios) == _z_iosli_readable(cios));\n\n    printf(\"  - IOSli read\\n\");\n    for (size_t i = 0; i < len; i++) {\n        uint8_t b1 = _z_iosli_read(&ios);\n        uint8_t b2 = _z_iosli_read(pios);\n        uint8_t b3 = _z_iosli_read(cios);\n\n        assert(b1 == b2 && b2 == b3);\n        (void)(b1);\n        (void)(b2);\n        (void)(b3);\n\n        assert(_z_iosli_writable(&ios) == _z_iosli_writable(pios) &&\n               _z_iosli_writable(pios) == _z_iosli_writable(cios));\n        assert(_z_iosli_readable(&ios) == _z_iosli_readable(pios) &&\n               _z_iosli_readable(pios) == _z_iosli_readable(cios));\n\n        writable = _z_iosli_writable(&ios);\n        readable = _z_iosli_readable(&ios);\n\n        printf(\"    Writable: %zu\\tReadable: %zu\\n\", writable, readable);\n        assert(writable == 0);\n        assert(readable == len - (i + 1));\n    }\n\n    _z_iosli_reset(&ios);\n    assert(_z_iosli_writable(&ios) == len);\n    assert(_z_iosli_readable(&ios) == 0);\n\n    _z_iosli_reset(pios);\n    assert(_z_iosli_writable(pios) == len);\n    assert(_z_iosli_readable(pios) == 0);\n\n    _z_iosli_clear(cios);\n    assert(_z_iosli_writable(cios) == 0);\n    assert(_z_iosli_readable(cios) == 0);\n\n    printf(\"  - IOSli bytes\\n\");\n    uint8_t *payload = (uint8_t *)z_malloc(len);\n    memset((uint8_t *)payload, 1, len);\n\n    for (size_t i = 0; i < len; i++) {\n        payload[i] = gen_uint8();\n        _z_iosli_put(pios, payload[i], i);\n\n        assert(payload[i] == _z_iosli_get(pios, i));\n        pios->_w_pos++;\n\n        writable = _z_iosli_writable(pios);\n        readable = _z_iosli_readable(pios);\n\n        printf(\"    Writable: %zu\\tReadable: %zu\\n\", writable, readable);\n        assert(writable == len - (i + 1));\n        assert(readable == i + 1);\n    }\n\n    uint8_t *buffer = (uint8_t *)z_malloc(len);\n    memset((uint8_t *)buffer, 1, len);\n\n    _z_iosli_write_bytes(&ios, payload, 0, len);\n    _z_iosli_read_bytes(&ios, buffer, 0, len);\n    assert(memcmp(payload, buffer, len) == 0);\n\n    memset(buffer, 0, len);\n\n    _z_iosli_read_bytes(pios, buffer, 0, len);\n    assert(memcmp(payload, buffer, len) == 0);\n\n    memset(buffer, 0, len);\n\n    _z_iosli_t wios = _z_iosli_wrap(payload, len, 0, len);\n    _z_iosli_read_bytes(&wios, buffer, 0, len);\n    assert(memcmp(payload, buffer, len) == 0);\n\n    _z_iosli_clear(&ios);\n    assert(_z_iosli_writable(&ios) == 0);\n    assert(_z_iosli_readable(&ios) == 0);\n\n    _z_iosli_clear(pios);\n    assert(_z_iosli_writable(pios) == 0);\n    assert(_z_iosli_readable(pios) == 0);\n\n    _z_iosli_clear(&wios);\n    assert(_z_iosli_writable(&wios) == 0);\n    assert(_z_iosli_readable(&wios) == 0);\n\n    _z_iosli_clear(pios);\n    z_free(pios);\n    _z_iosli_clear(cios);\n    z_free(cios);\n\n    z_free(buffer);\n    z_free(payload);\n}\n\nvoid zbuf_writable_readable(void) {\n    size_t len = 128;\n    _z_zbuf_t zbf = _z_zbuf_make(len);\n    printf(\"\\n>>> ZBuf => Writable and Readable\\n\");\n\n    size_t writable = _z_zbuf_space_left(&zbf);\n    printf(\"    Writable: %zu\\n\", writable);\n    assert(writable == len);\n\n    size_t readable = _z_zbuf_len(&zbf);\n    printf(\"    Readable: %zu\\n\", readable);\n    assert(readable == 0);\n\n    _z_zbuf_set_wpos(&zbf, len);\n\n    size_t read = 0;\n    while (read < len) {\n        size_t to_read = 1 + gen_size_t() % (len - read);\n        for (size_t i = 0; i < to_read; i++) {\n            _z_zbuf_read(&zbf);\n        }\n        read = read + to_read;\n\n        writable = _z_zbuf_space_left(&zbf);\n        printf(\"    Writable: %zu\\n\", writable);\n        assert(writable == 0);\n\n        readable = _z_zbuf_len(&zbf);\n        printf(\"    Readable: %zu\\n\", readable);\n        assert(readable == len - read);\n    }\n\n    _z_zbuf_clear(&zbf);\n}\n\nvoid zbuf_compact(void) {\n    uint8_t len = 128;\n    _z_zbuf_t zbf = _z_zbuf_make(len);\n    printf(\"\\n>>> ZBuf => Compact\\n\");\n\n    for (uint8_t i = 0; i < len; i++) {\n        _z_iosli_write(&zbf._ios, i);\n    }\n\n    uint8_t counter = 0;\n\n    while (counter < len) {\n        size_t len01 = _z_zbuf_len(&zbf);\n        _z_zbuf_compact(&zbf);\n        assert(_z_zbuf_get_rpos(&zbf) == 0);\n        assert(_z_zbuf_get_wpos(&zbf) == len01);\n        assert(_z_zbuf_len(&zbf) == len01);\n        printf(\"    Len: %zu, Rpos: %zu, Wpos: %zu\\n\", len01, _z_zbuf_get_rpos(&zbf), _z_zbuf_get_wpos(&zbf));\n\n        uint8_t vs = (uint8_t)(1 + gen_uint8() % (len - counter));\n        printf(\"    Read %u bytes => [\", vs);\n        for (uint8_t i = 0; i < vs; i++) {\n            uint8_t l = counter++;\n            uint8_t r = _z_zbuf_read(&zbf);\n            printf(\" %02x:%02x\", l, r);\n            assert(l == r);\n        }\n        printf(\" ]\\n\");\n    }\n\n    _z_zbuf_clear(&zbf);\n}\n\nvoid zbuf_view(void) {\n    uint8_t len = 128;\n    _z_zbuf_t zbf = _z_zbuf_make(len);\n    printf(\"\\n>>> ZBuf => View\\n\");\n\n    for (uint8_t i = 0; i < len; i++) {\n        _z_iosli_write(&zbf._ios, i);\n    }\n\n    uint8_t counter = 0;\n\n    while (counter < len) {\n        uint8_t vs = (uint8_t)(1 + gen_uint8() % (len - counter));\n        _z_zbuf_t rv = _z_zbuf_view(&zbf, vs);\n\n        printf(\"    View of %u bytes: \", vs);\n        assert(_z_zbuf_capacity(&rv) == vs);\n        assert(_z_zbuf_len(&rv) == vs);\n        assert(_z_zbuf_space_left(&rv) == 0);\n\n        printf(\"[\");\n        for (uint8_t i = 0; i < vs; i++) {\n            uint8_t l = counter++;\n            uint8_t r = _z_zbuf_read(&rv);\n            printf(\" %02x:%02x\", l, r);\n            assert(l == r);\n        }\n        printf(\" ]\\n\");\n\n        _z_zbuf_set_rpos(&zbf, _z_zbuf_get_rpos(&zbf) + vs);\n    }\n\n    _z_zbuf_clear(&zbf);\n}\n\nvoid wbuf_writable_readable(void) {\n    size_t len = 128;\n    _z_wbuf_t wbf = _z_wbuf_make(len, false);\n    assert(_z_wbuf_capacity(&wbf) == len);\n    printf(\"\\n>>> WBuf => Writable and Readable\\n\");\n\n    size_t writable = _z_wbuf_space_left(&wbf);\n    printf(\"    Writable: %zu\\n\", writable);\n    assert(writable == len);\n\n    size_t readable = _z_wbuf_len(&wbf);\n    printf(\"    Readable: %zu\\n\", readable);\n    assert(readable == 0);\n\n    size_t written = 0;\n    while (written < len) {\n        size_t to_write = 1 + gen_size_t() % (len - written);\n        for (size_t i = 0; i < to_write; i++) {\n            _z_wbuf_write(&wbf, 0);\n        }\n        written = written + to_write;\n\n        writable = _z_wbuf_space_left(&wbf);\n        printf(\"    Writable: %zu\\n\", writable);\n        assert(writable == len - written);\n\n        readable = _z_wbuf_len(&wbf);\n        printf(\"    Readable: %zu\\n\", readable);\n        assert(readable == written);\n    }\n\n    _z_wbuf_clear(&wbf);\n}\n\nvoid wbuf_write_zbuf_read(void) {\n    size_t len = 128;\n    _z_wbuf_t wbf = gen_wbuf(len);\n    printf(\"\\n>>> WBuf => Write and Read\\n\");\n    print_wbuf_overview(&wbf);\n    printf(\"    Writing %zu bytes\\n\", len);\n    for (size_t i = 0; i < len; i++) _z_wbuf_write(&wbf, (uint8_t)i % 255);\n\n    printf(\"    IOSlices: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(&wbf), wbf._r_idx, wbf._w_idx);\n    printf(\"    Written: %zu, Readable: %zu\\n\", len, _z_wbuf_len(&wbf));\n    assert(_z_wbuf_len(&wbf) == len);\n\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    assert(_z_zbuf_len(&zbf) == len);\n    printf(\"    Reading %zu bytes\\n\", len);\n    printf(\"    [\");\n    for (uint8_t i = 0; i < len; i++) {\n        uint8_t l = (uint8_t)i % 255;\n        uint8_t r = _z_zbuf_read(&zbf);\n        printf(\" %02x:%02x\", l, r);\n        assert(l == r);\n    }\n    printf(\"]\\n\");\n\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\nvoid wbuf_write_zbuf_read_bytes(void) {\n    size_t len = 128;\n    _z_wbuf_t wbf = gen_wbuf(len);\n    printf(\"\\n>>> WBuf => Write and Read bytes\\n\");\n    print_wbuf_overview(&wbf);\n\n    printf(\"    Writing %zu bytes\\n\", len);\n    uint8_t *buf01 = (uint8_t *)z_malloc(len);\n    for (size_t i = 0; i < len; i++) {\n        buf01[i] = (uint8_t)i % 255;\n    }\n    _z_wbuf_write_bytes(&wbf, buf01, 0, len);\n\n    printf(\"    IOSlices: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(&wbf), wbf._r_idx, wbf._w_idx);\n    printf(\"    Written: %zu, Readable: %zu\\n\", len, _z_wbuf_len(&wbf));\n    assert(_z_wbuf_len(&wbf) == len);\n\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    printf(\"    [\");\n    for (size_t i = 0; i < len; i++) {\n        uint8_t l = buf01[i];\n        uint8_t r = _z_zbuf_read(&zbf);\n        printf(\" %02x:%02x\", l, r);\n        assert(l == r);\n    }\n    printf(\" ]\\n\");\n\n    z_free(buf01);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\nvoid wbuf_put_zbuf_get(void) {\n    size_t len = 128;\n    _z_wbuf_t wbf = gen_wbuf(len);\n    printf(\"\\n>>> WBuf => Put and Get\\n\");\n    print_wbuf_overview(&wbf);\n    // Initialize to 0\n    for (size_t i = 0; i < len; i++) {\n        _z_wbuf_write(&wbf, 0);\n    }\n    printf(\"    IOSlices: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(&wbf), wbf._r_idx, wbf._w_idx);\n\n    printf(\"    Putting %zu bytes\\n\", len);\n    // Put data\n    for (size_t i = 0; i < len; i++) {\n        _z_wbuf_put(&wbf, (uint8_t)i % 255, i);\n    }\n\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    printf(\"    Getting %zu bytes\\n\", len);\n    printf(\"    [\");\n    for (uint8_t i = 0; i < len; i++) {\n        uint8_t l = (uint8_t)i % 255;\n        uint8_t r = _z_zbuf_read(&zbf);\n        printf(\" %02x:%02x\", l, r);\n        assert(l == r);\n    }\n    printf(\" ]\\n\");\n\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\nvoid wbuf_reusable_write_zbuf_read(void) {\n    _z_wbuf_t wbf = gen_wbuf(128);\n    for (int i = 1; i <= 10; i++) {\n        size_t len = z_random_u8() % 128;\n        printf(\"\\n>>> WBuf => Write and Read round %d\\n\", i);\n        print_wbuf_overview(&wbf);\n        printf(\"    Writing %zu bytes\\n\", len);\n        for (size_t z = 0; z < len; z++) {\n            size_t prev_len = _z_wbuf_len(&wbf);\n            assert(_z_wbuf_write(&wbf, (uint8_t)(z % 255)) == 0);\n            assert(_z_wbuf_len(&wbf) == prev_len + 1);\n        }\n\n        printf(\"    IOSlices: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(&wbf), wbf._r_idx, wbf._w_idx);\n        printf(\"    Written: %zu, Readable: %zu\\n\", len, _z_wbuf_len(&wbf));\n        assert(_z_wbuf_len(&wbf) == len);\n\n        _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n        assert(_z_zbuf_len(&zbf) == len);\n        printf(\"    Reading %zu bytes\\n\", len);\n        printf(\"    [\");\n        for (uint8_t j = 0; j < len; j++) {\n            uint8_t l = j % (uint8_t)255;\n            uint8_t r = _z_zbuf_read(&zbf);\n            printf(\" %02x:%02x\", l, r);\n            assert(l == r);\n        }\n        printf(\"]\\n\");\n        _z_zbuf_clear(&zbf);\n        _z_wbuf_reset(&wbf);\n    }\n\n    _z_wbuf_clear(&wbf);\n}\n\nvoid wbuf_set_pos_wbuf_get_pos(void) {\n    size_t len = 128;\n    _z_wbuf_t wbf = gen_wbuf(len);\n    printf(\"\\n>>> WBuf => SetPos and GetPos\\n\");\n    print_wbuf_overview(&wbf);\n    // Initialize to 0\n    for (size_t i = 0; i < len; i++) {\n        _z_wbuf_write(&wbf, 0);\n    }\n    assert(_z_wbuf_get_rpos(&wbf) == 0);\n    assert(_z_wbuf_get_wpos(&wbf) == len);\n    printf(\"    IOSlices: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(&wbf), wbf._r_idx, wbf._w_idx);\n\n    for (size_t i = 0; i < 10; i++) {\n        _z_wbuf_reset(&wbf);\n        assert(_z_wbuf_get_rpos(&wbf) == 0);\n        assert(_z_wbuf_get_wpos(&wbf) == 0);\n\n        size_t lw_pos = gen_size_t() % (len + 1);\n        printf(\"    Setting WPos: %zu\\n\", lw_pos);\n        _z_wbuf_set_wpos(&wbf, lw_pos);\n\n        size_t rw_pos = _z_wbuf_get_wpos(&wbf);\n        printf(\"    Getting WPos: %zu\\n\", rw_pos);\n        assert(lw_pos == rw_pos);\n\n        size_t lr_pos = gen_size_t() % (lw_pos + 1);\n        printf(\"    Setting RPos: %zu\\n\", lr_pos);\n        _z_wbuf_set_rpos(&wbf, lr_pos);\n\n        size_t rr_pos = _z_wbuf_get_rpos(&wbf);\n        printf(\"    Getting RPos: %zu\\n\", rr_pos);\n        assert(lr_pos == rr_pos);\n    }\n\n    _z_wbuf_clear(&wbf);\n}\n\nvoid wbuf_add_iosli(void) {\n    uint8_t len = 16;\n    _z_wbuf_t wbf = _z_wbuf_make(len, true);\n    assert(_z_wbuf_capacity(&wbf) == len);\n    printf(\"\\n>>> WBuf => Add IOSli\\n\");\n    print_wbuf_overview(&wbf);\n\n    uint8_t written = 0;\n    uint8_t counter = 0;\n    while (written < 255) {\n        uint8_t remaining = 255 - written;\n        uint8_t range = remaining < len ? remaining : len;\n        uint8_t to_write = 1 + gen_uint8() % range;\n        printf(\"    Writing %u bytes\\n\", to_write);\n        for (uint8_t i = 0; i < to_write; i++) {\n            _z_wbuf_write(&wbf, counter);\n            counter++;\n        }\n        written = written + to_write;\n    }\n\n    printf(\"    IOSlices: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(&wbf), wbf._r_idx, wbf._w_idx);\n    for (size_t i = 0; i < _z_wbuf_len_iosli(&wbf); i++) {\n        _z_iosli_t *ios = _z_wbuf_get_iosli(&wbf, i);\n        printf(\"    Idx: %zu => \", i);\n        print_iosli(ios);\n        printf(\"\\n\");\n    }\n\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    printf(\"    [\");\n    for (uint8_t i = 0; i < counter; i++) {\n        uint8_t l = i;\n        uint8_t r = _z_zbuf_read(&zbf);\n        printf(\" %02x:%02x\", l, r);\n        assert(l == r);\n    }\n    printf(\" ]\\n\");\n\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n#define VAL_SIZE 20\n#define PAYLOAD_SIZE 32\n\nvoid test_wbuf_wrap_bytes(void) {\n    printf(\"Testing wbuf_wrap_bytes... \");\n    // Emulate eclipse-zenoh/zenoh-pico issue #979\n    uint8_t val[VAL_SIZE];\n    memset(val, 0xaa, sizeof(val));\n    uint8_t payload[PAYLOAD_SIZE];\n    memset(payload, 0x55, sizeof(payload));\n    uint16_t payload_size = _ZP_ARRAY_SIZE(payload);\n    _z_wbuf_t wbf = _z_wbuf_make(PAYLOAD_SIZE, true);\n    assert(_z_wbuf_capacity(&wbf) == PAYLOAD_SIZE);\n    // Write header\n    _z_wbuf_write_bytes(&wbf, val, 0, sizeof(val));\n    // Write attachment\n    _z_wbuf_write_bytes(&wbf, (uint8_t *)&payload_size, 0, sizeof(payload_size));\n    _z_wbuf_wrap_bytes(&wbf, payload, 0, sizeof(payload));\n    // Write payload\n    _z_wbuf_write_bytes(&wbf, (uint8_t *)&payload_size, 0, sizeof(payload_size));\n    _z_wbuf_wrap_bytes(&wbf, payload, 0, sizeof(payload));\n    assert(_z_iosli_svec_len(&wbf._ioss) == 5);\n    // Check header + attachment size\n    _z_iosli_t *ios = _z_wbuf_get_iosli(&wbf, 0);\n    assert(_z_iosli_readable(ios) == VAL_SIZE + sizeof(payload_size));\n    for (size_t i = 0; i < _z_iosli_readable(ios) - sizeof(payload_size); i++) {\n        assert(ios->_buf[i] == 0xaa);\n    }\n    assert(ios->_buf[_z_iosli_readable(ios) - 2] == (payload_size & 0xff));\n    assert(ios->_buf[_z_iosli_readable(ios) - 1] == (payload_size >> 8));\n    // Check attachment\n    ios = _z_wbuf_get_iosli(&wbf, 1);\n    assert(_z_iosli_readable(ios) == PAYLOAD_SIZE);\n    for (size_t i = 0; i < _z_iosli_readable(ios); i++) {\n        assert(ios->_buf[i] == 0x55);\n    }\n    // Check payload size\n    ios = _z_wbuf_get_iosli(&wbf, 2);\n    assert(_z_iosli_readable(ios) == sizeof(payload_size));\n    assert(ios->_buf[0] == (payload_size & 0xff));\n    assert(ios->_buf[1] == (payload_size >> 8));\n    // Check payload\n    ios = _z_wbuf_get_iosli(&wbf, 3);\n    assert(_z_iosli_readable(ios) == PAYLOAD_SIZE);\n    for (size_t i = 0; i < _z_iosli_readable(ios); i++) {\n        assert(ios->_buf[i] == 0x55);\n    }\n    _z_wbuf_clear(&wbf);\n    printf(\"Ok\\n\");\n}\n\n/*=============================*/\n/*            Main             */\n/*=============================*/\nint main(void) {\n    for (unsigned int i = 0; i < RUNS; i++) {\n        printf(\"\\n\\n== RUN %u\\n\", i);\n        // IOsli\n        iosli_writable_readable();\n        // ZBuf\n        zbuf_writable_readable();\n        zbuf_compact();\n        zbuf_view();\n        // WBuf\n        wbuf_writable_readable();\n        wbuf_set_pos_wbuf_get_pos();\n        wbuf_add_iosli();\n        // WBuf and ZBuf\n        wbuf_write_zbuf_read();\n        wbuf_write_zbuf_read_bytes();\n        wbuf_put_zbuf_get();\n\n        // Reusable WBuf\n        wbuf_reusable_write_zbuf_read();\n    }\n    test_wbuf_wrap_bytes();\n}\n"
  },
  {
    "path": "tests/z_json_encoder_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/utils/json_encoder.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_ADMIN_SPACE == 1\n\nstatic void assert_bytes_eq_buf(const z_owned_bytes_t *b, const uint8_t *expected, size_t expected_len) {\n    assert(b != NULL);\n    assert(expected != NULL);\n\n    assert(z_bytes_len(z_bytes_loan(b)) == expected_len);\n\n    uint8_t *buf = (uint8_t *)z_malloc(expected_len);\n    assert(buf != NULL);\n\n    size_t n = _z_bytes_to_buf(&b->_val, buf, expected_len);\n    assert(n == expected_len);\n\n    assert(memcmp(buf, expected, expected_len) == 0);\n    z_free(buf);\n}\n\n#define ASSERT_BYTES_EQ_LIT(bytes_ptr, lit) assert_bytes_eq_buf((bytes_ptr), (const uint8_t *)(lit), sizeof(lit) - 1)\n\nstatic void test_finish_requires_done(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    // Nothing written => finish must fail (validate checks !done)\n    assert(_z_json_encoder_finish(&je, &out) == _Z_ERR_INVALID);\n\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_empty_object(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    assert(_z_json_encoder_start_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_end_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out) == _Z_RES_OK);\n\n    ASSERT_BYTES_EQ_LIT(&out, \"{}\");\n    z_bytes_drop(z_bytes_move(&out));\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_simple_object_string(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    assert(_z_json_encoder_start_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_key(&je, \"k\") == _Z_RES_OK);\n    assert(_z_json_encoder_write_string(&je, \"v\") == _Z_RES_OK);\n    assert(_z_json_encoder_end_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out) == _Z_RES_OK);\n\n    ASSERT_BYTES_EQ_LIT(&out, \"{\\\"k\\\":\\\"v\\\"}\");\n    z_bytes_drop(z_bytes_move(&out));\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_array_two_values(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    assert(_z_json_encoder_start_array(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_string(&je, \"a\") == _Z_RES_OK);\n    assert(_z_json_encoder_write_string(&je, \"b\") == _Z_RES_OK);\n    assert(_z_json_encoder_end_array(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out) == _Z_RES_OK);\n\n    ASSERT_BYTES_EQ_LIT(&out, \"[\\\"a\\\",\\\"b\\\"]\");\n    z_bytes_drop(z_bytes_move(&out));\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_nested_object_array_numbers(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    assert(_z_json_encoder_start_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_key(&je, \"a\") == _Z_RES_OK);\n\n    assert(_z_json_encoder_start_array(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_i64(&je, -1) == _Z_RES_OK);\n    assert(_z_json_encoder_write_u64(&je, 2) == _Z_RES_OK);\n    assert(_z_json_encoder_end_array(&je) == _Z_RES_OK);\n\n    assert(_z_json_encoder_end_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out) == _Z_RES_OK);\n\n    ASSERT_BYTES_EQ_LIT(&out, \"{\\\"a\\\":[-1,2]}\");\n    z_bytes_drop(z_bytes_move(&out));\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_boolean_null_double(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    assert(_z_json_encoder_start_array(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_boolean(&je, true) == _Z_RES_OK);\n    assert(_z_json_encoder_write_boolean(&je, false) == _Z_RES_OK);\n    assert(_z_json_encoder_write_null(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_double(&je, 1.25) == _Z_RES_OK);\n    assert(_z_json_encoder_end_array(&je) == _Z_RES_OK);\n\n    assert(_z_json_encoder_finish(&je, &out) == _Z_RES_OK);\n\n    // write_double uses \"%.17g\" => 1.25\n    ASSERT_BYTES_EQ_LIT(&out, \"[true,false,null,1.25]\");\n    z_bytes_drop(z_bytes_move(&out));\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_string_escaping_key_and_value(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out;\n\n    assert(_z_json_encoder_start_object(&je) == _Z_RES_OK);\n\n    // key contains quote and backslash\n    assert(_z_json_encoder_write_key(&je, \"k\\\"\\\\\") == _Z_RES_OK);\n\n    // value contains newline and tab\n    assert(_z_json_encoder_write_string(&je, \"line1\\n\\tline2\") == _Z_RES_OK);\n\n    assert(_z_json_encoder_end_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out) == _Z_RES_OK);\n\n    ASSERT_BYTES_EQ_LIT(&out, \"{\\\"k\\\\\\\"\\\\\\\\\\\":\\\"line1\\\\n\\\\tline2\\\"}\");\n    z_bytes_drop(z_bytes_move(&out));\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_invalid_write_key_outside_object(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_key(&je, \"k\") == _Z_ERR_INVALID);\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_invalid_value_in_object_without_key(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n\n    assert(_z_json_encoder_start_object(&je) == _Z_RES_OK);\n    // In object, value not allowed until key written\n    assert(_z_json_encoder_write_string(&je, \"v\") == _Z_ERR_INVALID);\n\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_invalid_end_object_when_expect_value(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n\n    assert(_z_json_encoder_start_object(&je) == _Z_RES_OK);\n    assert(_z_json_encoder_write_key(&je, \"k\") == _Z_RES_OK);\n    // Expecting value => cannot end object\n    assert(_z_json_encoder_end_object(&je) == _Z_ERR_INVALID);\n\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_depth_overflow(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n\n    for (size_t i = 0; i < Z_JSON_MAX_DEPTH; i++) {\n        assert(_z_json_encoder_start_array(&je) == _Z_RES_OK);\n    }\n    assert(_z_json_encoder_start_array(&je) == _Z_ERR_OVERFLOW);\n\n    _z_json_encoder_clear(&je);\n}\n\nstatic void test_finish_resets_encoder_state(void) {\n    _z_json_encoder_t je;\n    assert(_z_json_encoder_empty(&je) == _Z_RES_OK);\n    z_owned_bytes_t out1;\n    z_owned_bytes_t out2;\n\n    assert(_z_json_encoder_write_string(&je, \"one\") == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out1) == _Z_RES_OK);\n    ASSERT_BYTES_EQ_LIT(&out1, \"\\\"one\\\"\");\n    z_bytes_drop(z_bytes_move(&out1));\n\n    // After finish, encoder should allow a new top-level value\n    assert(_z_json_encoder_write_string(&je, \"two\") == _Z_RES_OK);\n    assert(_z_json_encoder_finish(&je, &out2) == _Z_RES_OK);\n    ASSERT_BYTES_EQ_LIT(&out2, \"\\\"two\\\"\");\n    z_bytes_drop(z_bytes_move(&out2));\n\n    _z_json_encoder_clear(&je);\n}\n\nint main(void) {\n    test_finish_requires_done();\n    test_empty_object();\n    test_simple_object_string();\n    test_array_two_values();\n    test_nested_object_array_numbers();\n    test_boolean_null_double();\n    test_string_escaping_key_and_value();\n    test_invalid_write_key_outside_object();\n    test_invalid_value_in_object_without_key();\n    test_invalid_end_object_when_expect_value();\n    test_depth_overflow();\n    test_finish_resets_encoder_state();\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\"Missing config token to build this test. This test requires: Z_FEATURE_ADMIN_SPACE\\n\");\n    return 0;\n}\n\n#endif  // Z_FEATURE_ADMIN_SPACE == 1\n"
  },
  {
    "path": "tests/z_keyexpr_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define TEST_TRUE_INTERSECT(a, b)        \\\n    ke_a = _z_keyexpr_alias_from_str(a); \\\n    ke_b = _z_keyexpr_alias_from_str(b); \\\n    assert(_z_keyexpr_intersects(&ke_a, &ke_b));\n\n#define TEST_FALSE_INTERSECT(a, b)       \\\n    ke_a = _z_keyexpr_alias_from_str(a); \\\n    ke_b = _z_keyexpr_alias_from_str(b); \\\n    assert(!_z_keyexpr_intersects(&ke_a, &ke_b));\n\n#define TEST_TRUE_INCLUDE(a, b)          \\\n    ke_a = _z_keyexpr_alias_from_str(a); \\\n    ke_b = _z_keyexpr_alias_from_str(b); \\\n    assert(_z_keyexpr_includes(&ke_a, &ke_b));\n\n#define TEST_FALSE_INCLUDE(a, b)         \\\n    ke_a = _z_keyexpr_alias_from_str(a); \\\n    ke_b = _z_keyexpr_alias_from_str(b); \\\n    assert(!_z_keyexpr_includes(&ke_a, &ke_b));\n\n#define TEST_TRUE_EQUAL(a, b)            \\\n    ke_a = _z_keyexpr_alias_from_str(a); \\\n    ke_b = _z_keyexpr_alias_from_str(b); \\\n    assert(_z_keyexpr_equals(&ke_a, &ke_b));\n\n#define TEST_FALSE_EQUAL(a, b)           \\\n    ke_a = _z_keyexpr_alias_from_str(a); \\\n    ke_b = _z_keyexpr_alias_from_str(b); \\\n    assert(!_z_keyexpr_equals(&ke_a, &ke_b));\n\nvoid test_intersects(void) {\n    _z_keyexpr_t ke_a, ke_b;\n    TEST_TRUE_INTERSECT(\"a\", \"a\")\n    TEST_TRUE_INTERSECT(\"a/b\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"*\", \"abc\")\n    TEST_TRUE_INTERSECT(\"*\", \"abc\")\n    TEST_TRUE_INTERSECT(\"*\", \"abc\")\n    TEST_TRUE_INTERSECT(\"*\", \"xxx\")\n    TEST_TRUE_INTERSECT(\"ab$*\", \"abcd\")\n    TEST_TRUE_INTERSECT(\"ab$*d\", \"abcd\")\n    TEST_TRUE_INTERSECT(\"ab$*\", \"ab\")\n    TEST_FALSE_INTERSECT(\"ab/*\", \"ab\")\n    TEST_TRUE_INTERSECT(\"a/*/c/*/e\", \"a/b/c/d/e\")\n    TEST_TRUE_INTERSECT(\"a/**/d/**/l\", \"a/b/c/d/e/f/g/h/i/l\")\n    TEST_TRUE_INTERSECT(\"a/**/d/**/l\", \"a/d/foo/l\")\n    TEST_TRUE_INTERSECT(\"a/$*b/c/$*d/e\", \"a/xb/c/xd/e\")\n    TEST_FALSE_INTERSECT(\"a/*/c/*/e\", \"a/c/e\")\n    TEST_FALSE_INTERSECT(\"a/*/c/*/e\", \"a/b/c/d/x/e\")\n    TEST_FALSE_INTERSECT(\"ab$*cd\", \"abxxcxxd\")\n    TEST_TRUE_INTERSECT(\"ab$*cd\", \"abxxcxxcd\")\n    TEST_FALSE_INTERSECT(\"ab$*cd\", \"abxxcxxcdx\")\n    TEST_TRUE_INTERSECT(\"**\", \"abc\")\n    TEST_TRUE_INTERSECT(\"**\", \"a/b/c\")\n    TEST_TRUE_INTERSECT(\"ab/**\", \"ab\")\n    TEST_TRUE_INTERSECT(\"**/xyz\", \"a/b/xyz/d/e/f/xyz\")\n    TEST_FALSE_INTERSECT(\"**/xyz$*xyz\", \"a/b/xyz/d/e/f/xyz\")\n    TEST_TRUE_INTERSECT(\"a/**/c/**/e\", \"a/b/b/b/c/d/d/d/e\")\n    TEST_TRUE_INTERSECT(\"a/**/c/**/e\", \"a/c/e\")\n    TEST_TRUE_INTERSECT(\"a/**/c/*/e/*\", \"a/b/b/b/c/d/d/c/d/e/f\")\n    TEST_FALSE_INTERSECT(\"a/**/c/*/e/*\", \"a/b/b/b/c/d/d/c/d/d/e/f\")\n    TEST_FALSE_INTERSECT(\"ab$*cd\", \"abxxcxxcdx\")\n    TEST_TRUE_INTERSECT(\"x/abc\", \"x/abc\")\n    TEST_FALSE_INTERSECT(\"x/abc\", \"abc\")\n    TEST_TRUE_INTERSECT(\"x/*\", \"x/abc\")\n    TEST_FALSE_INTERSECT(\"x/*\", \"abc\")\n    TEST_FALSE_INTERSECT(\"*\", \"x/abc\")\n    TEST_TRUE_INTERSECT(\"x/*\", \"x/abc$*\")\n    TEST_TRUE_INTERSECT(\"x/$*abc\", \"x/abc$*\")\n    TEST_TRUE_INTERSECT(\"x/a$*\", \"x/abc$*\")\n    TEST_TRUE_INTERSECT(\"x/a$*de\", \"x/abc$*de\")\n    TEST_TRUE_INTERSECT(\"x/a$*d$*e\", \"x/a$*e\")\n    TEST_TRUE_INTERSECT(\"x/a$*d$*e\", \"x/a$*c$*e\")\n    TEST_TRUE_INTERSECT(\"x/a$*d$*e\", \"x/ade\")\n    TEST_FALSE_INTERSECT(\"x/c$*\", \"x/abc$*\")\n    TEST_FALSE_INTERSECT(\"x/$*d\", \"x/$*e\")\n    TEST_TRUE_INTERSECT(\"a\", \"a\")\n    TEST_TRUE_INTERSECT(\"a/b\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"*\", \"a\")\n    TEST_TRUE_INTERSECT(\"a\", \"*\")\n    TEST_TRUE_INTERSECT(\"*\", \"aaaaa\")\n    TEST_TRUE_INTERSECT(\"**\", \"a\")\n    TEST_TRUE_INTERSECT(\"a\", \"**\")\n    TEST_TRUE_INTERSECT(\"**\", \"a\")\n    TEST_TRUE_INTERSECT(\"a/a/a/a\", \"**\")\n    TEST_TRUE_INTERSECT(\"a/*\", \"a/b\")\n    TEST_FALSE_INTERSECT(\"a/*/b\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/**/b\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/b$*\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/$*b$*\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/$*b\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/b$*\", \"a/bc\")\n    TEST_TRUE_INTERSECT(\"a/$*b$*\", \"a/ebc\")\n    TEST_TRUE_INTERSECT(\"a/$*b\", \"a/cb\")\n    TEST_FALSE_INTERSECT(\"a/b$*\", \"a/ebc\")\n    TEST_FALSE_INTERSECT(\"a/$*b\", \"a/cbc\")\n    TEST_TRUE_INTERSECT(\"a/**/b$*\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/**/$*b$*\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/**/$*b\", \"a/b\")\n    TEST_TRUE_INTERSECT(\"a/**/b$*\", \"a/bc\")\n    TEST_TRUE_INTERSECT(\"a/**/$*b$*\", \"a/ebc\")\n    TEST_TRUE_INTERSECT(\"a/**/$*b\", \"a/cb\")\n    TEST_FALSE_INTERSECT(\"a/**/b$*\", \"a/ebc\")\n    TEST_FALSE_INTERSECT(\"a/**/$*b\", \"a/cbc\")\n\n    TEST_TRUE_INTERSECT(\"@a\", \"@a\")\n    TEST_FALSE_INTERSECT(\"@a\", \"@ab\")\n    TEST_FALSE_INTERSECT(\"@a\", \"@a/b\")\n    TEST_FALSE_INTERSECT(\"@a\", \"@a/*\")\n    TEST_FALSE_INTERSECT(\"@a\", \"@a/*/**\")\n    TEST_TRUE_INTERSECT(\"@a\", \"@a/**\")\n    TEST_FALSE_INTERSECT(\"**/xyz$*xyz\", \"@a/b/xyzdefxyz\")\n    TEST_TRUE_INTERSECT(\"@a/**/c/**/e\", \"@a/b/b/b/c/d/d/d/e\")\n    TEST_FALSE_INTERSECT(\"@a/**/c/**/e\", \"@a/@b/b/b/c/d/d/d/e\")\n    TEST_TRUE_INTERSECT(\"@a/**/@c/**/e\", \"@a/b/b/b/@c/d/d/d/e\")\n    TEST_TRUE_INTERSECT(\"@a/**/e\", \"@a/b/b/d/d/d/e\")\n    TEST_TRUE_INTERSECT(\"@a/**/e\", \"@a/b/b/b/d/d/d/e\")\n    TEST_TRUE_INTERSECT(\"@a/**/e\", \"@a/b/b/c/d/d/d/e\")\n    TEST_FALSE_INTERSECT(\"@a/**/e\", \"@a/b/b/@c/b/d/d/d/e\")\n    TEST_FALSE_INTERSECT(\"@a/*\", \"@a/@b\")\n    TEST_FALSE_INTERSECT(\"@a/**\", \"@a/@b\")\n    TEST_TRUE_INTERSECT(\"@a/**/@b\", \"@a/@b\")\n    TEST_FALSE_INTERSECT(\"@a/**/@b\", \"@a/**/@c/**/@b\")\n    TEST_TRUE_INTERSECT(\"@a/@b/**\", \"@a/@b\")\n    TEST_TRUE_INTERSECT(\"@a/**/@c/@b\", \"@a/**/@c/**/@b\")\n    TEST_TRUE_INTERSECT(\"@a/**/@c/**/@b\", \"@a/**/@c/@b\")\n    TEST_TRUE_INTERSECT(\"a\", \"$*a\");\n    TEST_TRUE_INTERSECT(\"$*a\", \"a\");\n    TEST_FALSE_INTERSECT(\"a/**/$*b\", \"a/@b\")\n    TEST_TRUE_INTERSECT(\"**/@a/b/c/**\", \"@a/b/c\");\n    TEST_FALSE_INTERSECT(\"**/@a/b/c/**\", \"@b/b/c\");\n    TEST_TRUE_INTERSECT(\"**/@a/@b/@c/**\", \"@a/@b/@c\");\n    TEST_FALSE_INTERSECT(\"**/@a/@b/@c/**\", \"@a/@a/@c\");\n}\n\nvoid test_includes(void) {\n    _z_keyexpr_t ke_a, ke_b;\n    TEST_TRUE_INCLUDE(\"a\", \"a\")\n    TEST_TRUE_INCLUDE(\"a/b\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"*\", \"a\")\n    TEST_FALSE_INCLUDE(\"a\", \"*\")\n    TEST_TRUE_INCLUDE(\"*\", \"aaaaa\")\n    TEST_TRUE_INCLUDE(\"**\", \"a\")\n    TEST_FALSE_INCLUDE(\"a\", \"**\")\n    TEST_TRUE_INCLUDE(\"**\", \"a\")\n    TEST_TRUE_INCLUDE(\"**\", \"a/a/a/a\")\n    TEST_TRUE_INCLUDE(\"**\", \"*/**\")\n    TEST_TRUE_INCLUDE(\"*/**\", \"*/**\")\n    TEST_FALSE_INCLUDE(\"*/**\", \"**\")\n    TEST_FALSE_INCLUDE(\"a/a/a/a\", \"**\")\n    TEST_TRUE_INCLUDE(\"a/*\", \"a/b\")\n    TEST_FALSE_INCLUDE(\"a/*/b\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/**/b\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/b$*\", \"a/b\")\n    TEST_FALSE_INCLUDE(\"a/b\", \"a/b$*\")\n    TEST_TRUE_INCLUDE(\"a/$*b$*\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/$*b\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/b$*\", \"a/bc\")\n    TEST_TRUE_INCLUDE(\"a/$*b$*\", \"a/ebc\")\n    TEST_TRUE_INCLUDE(\"a/$*b\", \"a/cb\")\n    TEST_FALSE_INCLUDE(\"a/b$*\", \"a/ebc\")\n    TEST_FALSE_INCLUDE(\"a/$*b\", \"a/cbc\")\n    TEST_TRUE_INCLUDE(\"a/**/b$*\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/**/$*b$*\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/**/$*b\", \"a/b\")\n    TEST_TRUE_INCLUDE(\"a/**/b$*\", \"a/bc\")\n    TEST_TRUE_INCLUDE(\"a/**/$*b$*\", \"a/ebc\")\n    TEST_TRUE_INCLUDE(\"a/**/$*b\", \"a/cb\")\n    TEST_FALSE_INCLUDE(\"a/**/b$*\", \"a/ebc\")\n    TEST_FALSE_INCLUDE(\"a/**/$*b\", \"a/cbc\")\n\n    TEST_TRUE_INCLUDE(\"@a\", \"@a\")\n    TEST_FALSE_INCLUDE(\"@a\", \"@ab\")\n    TEST_FALSE_INCLUDE(\"@a\", \"@a/b\")\n    TEST_FALSE_INCLUDE(\"@a\", \"@a/*\")\n    TEST_FALSE_INCLUDE(\"@a\", \"@a/*/**\")\n    TEST_FALSE_INCLUDE(\"@a\", \"@a/**\")\n    TEST_TRUE_INCLUDE(\"@a/**\", \"@a\")\n    TEST_FALSE_INCLUDE(\"**/xyz$*xyz\", \"@a/b/xyzdefxyz\")\n    TEST_TRUE_INCLUDE(\"@a/**/c/**/e\", \"@a/b/b/b/c/d/d/d/e\")\n    TEST_FALSE_INCLUDE(\"@a/*\", \"@a/@b\")\n    TEST_FALSE_INCLUDE(\"@a/**\", \"@a/@b\")\n    TEST_TRUE_INCLUDE(\"@a/**/@b\", \"@a/@b\")\n    TEST_TRUE_INCLUDE(\"@a/@b/**\", \"@a/@b\")\n    TEST_FALSE_INCLUDE(\"a/**/$*b\", \"a/@b\")\n    TEST_TRUE_INCLUDE(\"**/@a/b/c/**\", \"@a/b/c\");\n    TEST_FALSE_INCLUDE(\"**/@a/b/c/**\", \"@b/b/c\");\n    TEST_TRUE_INCLUDE(\"**/@a/@b/@c/**\", \"@a/@b/@c\");\n    TEST_FALSE_INCLUDE(\"**/@a/@b/@c/**\", \"@a/@a/@c\");\n}\n\nvoid test_canonize(void) {\n    // clang-format off\n\n#define N 31\n    const char *input[N] = {\"greetings/hello/there\",\n                            \"greetings/good/*/morning\",\n                            \"greetings/*\",\n                            \"greetings/*/**\",\n                            \"greetings/$*\",\n                            \"greetings/**/*/morning\",\n                            \"greetings/**/*/g/morning\",\n                            \"greetings/**/*/m\",\n                            \"greetings/**/*\",\n                            \"greetings/**/**\",\n                            \"greetings/**/**/morning\",\n                            \"greetings/**/**/g/morning\",\n                            \"greetings/**/**/m\",\n                            \"greetings/**/*/**\",\n                            \"$*\",\n                            \"$*$*\",\n                            \"$*$*$*\",\n                            \"$*hi$*$*\",\n                            \"$*$*hi$*\",\n                            \"hi$*$*$*\",\n                            \"$*$*$*hi\",\n                            \"$*$*$*hi$*$*$*\",\n                            \"hi*\",\n                            \"/hi\",\n                            \"hi/\",\n                            \"\",\n                            \"greetings/**/*/\",\n                            \"greetings/**/*/e?\",\n                            \"greetings/**/*/e#\",\n                            \"greetings/**/*/e$\",\n                            \"greetings/**/*/$e\"};\n    const zp_keyexpr_canon_status_t expected[N] = {Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_SUCCESS,\n                                                   Z_KEYEXPR_CANON_STARS_IN_CHUNK,\n                                                   Z_KEYEXPR_CANON_EMPTY_CHUNK,\n                                                   Z_KEYEXPR_CANON_EMPTY_CHUNK,\n                                                   Z_KEYEXPR_CANON_EMPTY_CHUNK,\n                                                   Z_KEYEXPR_CANON_EMPTY_CHUNK,\n                                                   Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK,\n                                                   Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK,\n                                                   Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR,\n                                                   Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR};\n    const char *canonized[N] = {\"greetings/hello/there\",\n                                \"greetings/good/*/morning\",\n                                \"greetings/*\",\n                                \"greetings/*/**\",\n                                \"greetings/*\",\n                                \"greetings/*/**/morning\",\n                                \"greetings/*/**/g/morning\",\n                                \"greetings/*/**/m\",\n                                \"greetings/*/**\",\n                                \"greetings/**\",\n                                \"greetings/**/morning\",\n                                \"greetings/**/g/morning\",\n                                \"greetings/**/m\",\n                                \"greetings/*/**\",\n                                \"*\",\n                                \"*\",\n                                \"*\",\n                                \"$*hi$*\",\n                                \"$*hi$*\",\n                                \"hi$*\",\n                                \"$*hi\",\n                                \"$*hi$*\",\n                                \"hi*\",\n                                \"/hi\",\n                                \"hi/\",\n                                \"\",\n                                \"greetings/**/*/\",\n                                \"greetings/**/*/e?\",\n                                \"greetings/**/*/e#\",\n                                \"greetings/**/*/e$\",\n                                \"greetings/**/*/$e\"};\n\n    // clang-format on\n\n    for (int i = 0; i < N; i++) {\n        const char *ke = input[i];\n        char *canon = (char *)malloc(128);\n        memset(canon, 0, 128);\n        strncpy(canon, ke, 128);\n        size_t canon_len = strlen(canon);\n        zp_keyexpr_canon_status_t status = z_keyexpr_canonize(canon, &canon_len);\n        printf(\"%s \", ke);\n        printf(\"  Status: %d : %d\\n\", status, expected[i]);\n        assert(status == expected[i]);\n        if (status == Z_KEYEXPR_CANON_SUCCESS) {\n            printf(\"  Match: %.*s : %s\\n\", (int)canon_len, canon, canonized[i]);\n            assert(strncmp(canonized[i], canon, canon_len) == 0);\n        }\n        free(canon);\n    }\n\n    for (int i = 0; i < N; i++) {\n        const char *ke = input[i];\n        char *canon = (char *)malloc(128);\n        memset(canon, 0, 128);\n        strncpy(canon, ke, 128);\n        size_t canon_len = strlen(canon);\n        zp_keyexpr_canon_status_t status = z_keyexpr_canonize(canon, &canon_len);\n        printf(\"%s \", ke);\n        printf(\"  Status: %d : %d\", status, expected[i]);\n        assert(status == expected[i]);\n        if (status == Z_KEYEXPR_CANON_SUCCESS) {\n            printf(\"  Match: %.*s : %s\", (int)canon_len, canon, canonized[i]);\n            assert(strncmp(canonized[i], canon, canon_len) == 0);\n        }\n        printf(\"\\n\");\n        free(canon);\n    }\n}\n\nvoid test_equals(void) {\n    _z_keyexpr_t ke_a, ke_b;\n    TEST_FALSE_EQUAL(\"a/**/$*b\", \"a/cb\");\n    TEST_FALSE_EQUAL(\"a/bc\", \"a/cb\");\n    TEST_TRUE_EQUAL(\"greetings/hello/there\", \"greetings/hello/there\");\n}\n\nbool keyexpr_equals_string(const z_loaned_keyexpr_t *ke, const char *s) {\n    z_view_string_t vs;\n    z_keyexpr_as_view_string(ke, &vs);\n    _z_string_t str = _z_string_alias_str(s);\n    return _z_string_equals(z_view_string_loan(&vs), &str);\n}\n\nvoid test_keyexpr_constructor(void) {\n    z_owned_keyexpr_t ke;\n    z_keyexpr_from_str(&ke, \"a/b/c\");\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke), \"a/b/c\"));\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n\n    z_keyexpr_from_substr(&ke, \"a/b/c/d/e\", 5);\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke), \"a/b/c\"));\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n\n    assert(0 == z_keyexpr_from_str_autocanonize(&ke, \"a/**/**\"));\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke), \"a/**\"));\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n\n    size_t len = 9;\n    assert(0 == z_keyexpr_from_substr_autocanonize(&ke, \"a/**/**/m/b/c\", &len));\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke), \"a/**/m\"));\n    assert(len == 6);\n    z_keyexpr_drop(z_keyexpr_move(&ke));\n\n    z_view_keyexpr_t vke;\n    z_view_keyexpr_from_str(&vke, \"a/b/c\");\n    assert(keyexpr_equals_string(z_view_keyexpr_loan(&vke), \"a/b/c\"));\n\n    char s[] = \"a/**/**\";\n    z_view_keyexpr_from_str_autocanonize(&vke, s);\n    assert(keyexpr_equals_string(z_view_keyexpr_loan(&vke), \"a/**\"));\n}\n\nvoid test_concat(void) {\n    z_owned_keyexpr_t ke1, ke2;\n    z_keyexpr_from_str(&ke1, \"a/b/c/*\");\n    assert(0 == z_keyexpr_concat(&ke2, z_keyexpr_loan(&ke1), \"/d/e/*\", 4));\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke2), \"a/b/c/*/d/e\"));\n    z_keyexpr_drop(z_keyexpr_move(&ke2));\n\n    assert(0 != z_keyexpr_concat(&ke2, z_keyexpr_loan(&ke1), \"*/e/*\", 3));\n    assert(!z_internal_keyexpr_check(&ke2));\n\n    z_keyexpr_drop(z_keyexpr_move(&ke1));\n}\n\nvoid test_join(void) {\n    z_owned_keyexpr_t ke1, ke2, ke3;\n    z_keyexpr_from_str(&ke1, \"a/b/c/*\");\n    z_keyexpr_from_str(&ke2, \"d/e/*\");\n    assert(0 == z_keyexpr_join(&ke3, z_keyexpr_loan(&ke1), z_keyexpr_loan(&ke2)));\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke3), \"a/b/c/*/d/e/*\"));\n    z_keyexpr_drop(z_keyexpr_move(&ke1));\n    z_keyexpr_drop(z_keyexpr_move(&ke2));\n    z_keyexpr_drop(z_keyexpr_move(&ke3));\n\n    z_keyexpr_from_str(&ke1, \"a/*/**\");\n    z_keyexpr_from_str(&ke2, \"**/d/e/c\");\n\n    assert(0 == z_keyexpr_join(&ke3, z_keyexpr_loan(&ke1), z_keyexpr_loan(&ke2)));\n    assert(keyexpr_equals_string(z_keyexpr_loan(&ke3), \"a/*/**/d/e/c\"));\n\n    z_keyexpr_drop(z_keyexpr_move(&ke1));\n    z_keyexpr_drop(z_keyexpr_move(&ke2));\n    z_keyexpr_drop(z_keyexpr_move(&ke3));\n}\n\nvoid test_relation_to(void) {\n    z_view_keyexpr_t foobar, foostar, barstar;\n    z_view_keyexpr_from_str(&foobar, \"foo/bar\");\n    z_view_keyexpr_from_str(&foostar, \"foo/*\");\n    z_view_keyexpr_from_str(&barstar, \"bar/*\");\n\n    assert(z_keyexpr_relation_to(z_view_keyexpr_loan(&foostar), z_view_keyexpr_loan(&foobar)) ==\n           Z_KEYEXPR_INTERSECTION_LEVEL_INCLUDES);\n    assert(z_keyexpr_relation_to(z_view_keyexpr_loan(&foobar), z_view_keyexpr_loan(&foostar)) ==\n           Z_KEYEXPR_INTERSECTION_LEVEL_INTERSECTS);\n    assert(z_keyexpr_relation_to(z_view_keyexpr_loan(&foostar), z_view_keyexpr_loan(&foostar)) ==\n           Z_KEYEXPR_INTERSECTION_LEVEL_EQUALS);\n    assert(z_keyexpr_relation_to(z_view_keyexpr_loan(&barstar), z_view_keyexpr_loan(&foobar)) ==\n           Z_KEYEXPR_INTERSECTION_LEVEL_DISJOINT);\n}\n\nvoid test_non_wild_prefix_len(void) {\n    _z_keyexpr_t ke1, ke2, ke3, ke4, ke5;\n    ke1 = _z_keyexpr_alias_from_str(\"foo/bar/**\");\n    ke2 = _z_keyexpr_alias_from_str(\"foo/*/baz\");\n    ke3 = _z_keyexpr_alias_from_str(\"bar1/ab$*/baz\");\n    ke4 = _z_keyexpr_alias_from_str(\"foo/bar\");\n    ke5 = _z_keyexpr_alias_from_str(\"**\");\n\n    assert(_z_keyexpr_non_wild_prefix_len(&ke1) == 7);\n    assert(_z_keyexpr_non_wild_prefix_len(&ke2) == 3);\n    assert(_z_keyexpr_non_wild_prefix_len(&ke3) == 4);\n    assert(_z_keyexpr_non_wild_prefix_len(&ke4) == 7);\n    assert(_z_keyexpr_non_wild_prefix_len(&ke5) == 0);\n}\n\nint main(void) {\n    test_intersects();\n    test_includes();\n    test_canonize();\n    test_equals();\n    test_keyexpr_constructor();\n    test_concat();\n    test_join();\n    test_relation_to();\n    test_non_wild_prefix_len();\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_local_loopback_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#undef NDEBUG\n#include <assert.h>\n#include <stdatomic.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/api/macros.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/bytes.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/net/primitives.h\"\n#include \"zenoh-pico/net/reply.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/session/keyexpr.h\"\n#include \"zenoh-pico/session/loopback.h\"\n#include \"zenoh-pico/session/query.h\"\n#include \"zenoh-pico/session/queryable.h\"\n#include \"zenoh-pico/session/resource.h\"\n#include \"zenoh-pico/session/session.h\"\n#include \"zenoh-pico/session/subscription.h\"\n#include \"zenoh-pico/session/utils.h\"\n#include \"zenoh-pico/transport/transport.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#if (Z_FEATURE_SUBSCRIPTION == 1) && (Z_FEATURE_QUERYABLE == 1) && (Z_FEATURE_QUERY == 1) && \\\n    (Z_FEATURE_LOCAL_SUBSCRIBER == 1) && (Z_FEATURE_LOCAL_QUERYABLE == 1)\n\nstatic atomic_uint g_network_send_count = 0;\nstatic atomic_uint g_network_final_send_count = 0;\nstatic atomic_uint g_local_put_delivery_count = 0;\nstatic atomic_uint g_local_query_delivery_count = 0;\nstatic atomic_uint g_query_drop_callback_count = 0;\nstatic atomic_uint g_query_reply_callback_count = 0;\n\nstatic _z_session_t g_session;\nstatic _z_session_rc_t g_session_rc = {0};\nstatic _z_transport_common_t g_fake_transport = {0};\nstatic bool g_transport_ready = false;\nstatic _z_link_t g_dummy_link = {0};\n\nstatic _z_transport_common_t *loopback_override(_z_session_t *zn) {\n    if (g_transport_ready && zn == &g_session) {\n        return &g_fake_transport;\n    }\n    return NULL;\n}\n\nstatic z_result_t z_send_override(_z_session_t *zn, const _z_network_message_t *n_msg, z_reliability_t reliability,\n                                  z_congestion_control_t cong_ctrl, void *peer, bool *handled) {\n    _ZP_UNUSED(zn);\n    _ZP_UNUSED(reliability);\n    _ZP_UNUSED(cong_ctrl);\n    _ZP_UNUSED(peer);\n    if (n_msg != NULL) {\n        atomic_fetch_add_explicit(&g_network_send_count, 1, memory_order_relaxed);\n        if (n_msg->_tag == _Z_N_RESPONSE_FINAL) {\n            atomic_fetch_add_explicit(&g_network_final_send_count, 1, memory_order_relaxed);\n        }\n    }\n    if (handled != NULL) {\n        *handled = true;\n    }\n    return _Z_RES_OK;\n}\n\nstatic void local_sample_callback(_z_sample_t *sample, void *arg) {\n    _ZP_UNUSED(sample);\n    atomic_fetch_add_explicit((atomic_uint *)arg, 1, memory_order_relaxed);\n}\n\nstatic void local_query_callback(_z_query_rc_t *query_rc, void *arg) {\n    atomic_fetch_add_explicit((atomic_uint *)arg, 1, memory_order_relaxed);\n\n    const char data[] = \"loopback-response\";\n    _z_bytes_t payload = _z_bytes_null();\n    assert(_z_bytes_from_buf(&payload, (const uint8_t *)data, sizeof(data) - 1) == _Z_RES_OK);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t timestamp = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n\n    _z_network_message_t msg;\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(&_Z_RC_IN_VAL(query_rc)->_key, &g_session);\n    _z_n_msg_make_reply_ok_put(&msg, &g_session._local_zid, _Z_RC_IN_VAL(query_rc)->_request_id, &wireexpr,\n                               Z_RELIABILITY_DEFAULT, Z_CONSOLIDATION_MODE_DEFAULT, qos, &timestamp, &source_info,\n                               &payload, &encoding, NULL);\n    assert(_z_handle_network_message(&g_fake_transport, &msg, NULL) == _Z_RES_OK);\n}\n\nstatic void query_reply_callback(_z_reply_t *reply, void *arg) {\n    _ZP_UNUSED(reply);\n    _ZP_UNUSED(arg);\n    atomic_fetch_add_explicit(&g_query_reply_callback_count, 1, memory_order_relaxed);\n}\n\nstatic void query_dropper(void *arg) {\n    _ZP_UNUSED(arg);\n    atomic_fetch_add_explicit(&g_query_drop_callback_count, 1, memory_order_relaxed);\n}\n\nstatic void add_fake_peer(void) {\n    // Add a fake peer to simulate a remote connection\n    g_session._tp._transport._unicast._peers =\n        _z_transport_peer_unicast_slist_push_empty(g_session._tp._transport._unicast._peers);\n    _z_transport_peer_unicast_t *peer = _z_transport_peer_unicast_slist_value(g_session._tp._transport._unicast._peers);\n    *peer = (_z_transport_peer_unicast_t){0};\n    g_session._tp._transport._unicast._common._link = &g_dummy_link;\n}\n\nstatic void setup_session(void) {\n    _z_id_t zid;\n    _z_session_generate_zid(&zid, Z_ZID_LENGTH);\n    assert(_z_session_init(&g_session, &zid) == _Z_RES_OK);\n    if (_Z_RC_IS_NULL(&g_session_rc)) {\n        g_session_rc = _z_session_rc_new(&g_session);\n        assert(!_Z_RC_IS_NULL(&g_session_rc));\n    } else {\n        g_session_rc._val = &g_session;\n    }\n\n    g_dummy_link = (_z_link_t){0};\n    g_fake_transport = (_z_transport_common_t){0};\n    g_fake_transport._session = _z_session_rc_clone_as_weak(&g_session_rc);\n    g_fake_transport._link = &g_dummy_link;\n    g_transport_ready = true;\n    _z_session_set_transport_common_override(loopback_override);\n    _z_transport_set_send_n_msg_override(z_send_override);\n\n    g_session._tp._type = _Z_TRANSPORT_UNICAST_TYPE;\n}\n\nstatic void cleanup_session(void) {\n    if (g_transport_ready) {\n        g_transport_ready = false;\n    }\n    _z_transport_peer_unicast_slist_free(&g_session._tp._transport._unicast._peers);\n    g_session._tp._transport._unicast._peers = NULL;\n    g_session._tp._transport._unicast._common._link = NULL;\n    g_session._tp._type = _Z_TRANSPORT_NONE;\n    _z_session_clear(&g_session);\n    _z_session_set_transport_common_override(NULL);\n    _z_transport_set_send_n_msg_override(NULL);\n}\n\nstatic _z_declared_keyexpr_t create_local_resource(const char *key_str) {\n    _z_declared_keyexpr_t ke = _z_declared_keyexpr_alias_from_str(key_str);\n    _z_declared_keyexpr_t keyexpr;\n    assert(_z_declared_keyexpr_declare(&g_session_rc, &keyexpr, &ke) == _Z_RES_OK);\n    return keyexpr;\n}\n\nstatic void cleanup_local_resource(_z_declared_keyexpr_t *keyexpr) { _z_declared_keyexpr_clear(keyexpr); }\n\nstatic _z_subscription_rc_t register_local_subscription(const _z_declared_keyexpr_t *keyexpr, atomic_uint *counter,\n                                                        z_locality_t allowed_origin) {\n    _z_subscription_t sub_entry = {0};\n    sub_entry._id = _z_get_entity_id(&g_session);\n    _z_declared_keyexpr_copy(&sub_entry._key, keyexpr);\n    sub_entry._callback = local_sample_callback;\n    sub_entry._dropper = NULL;\n    sub_entry._arg = counter;\n    sub_entry._allowed_origin = allowed_origin;\n\n    _z_subscription_rc_t subscription_rc =\n        _z_register_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sub_entry);\n    assert(!_Z_RC_IS_NULL(&subscription_rc));\n    return subscription_rc;\n}\n\nstatic _z_session_queryable_rc_t register_local_queryable(const _z_declared_keyexpr_t *keyexpr, atomic_uint *counter,\n                                                          z_locality_t allowed_origin) {\n    _z_session_queryable_t queryable_entry = {0};\n    _z_declared_keyexpr_copy(&queryable_entry._key, keyexpr);\n    queryable_entry._callback = local_query_callback;\n    queryable_entry._dropper = NULL;\n    queryable_entry._arg = counter;\n    queryable_entry._complete = false;\n    queryable_entry._allowed_origin = allowed_origin;\n\n    _z_session_queryable_rc_t queryable_rc = _z_register_session_queryable(&g_session, &queryable_entry);\n    assert(!_Z_RC_IS_NULL(&queryable_rc));\n    return queryable_rc;\n}\n\nstatic void test_put_local_only_single(void) {\n    setup_session();\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put\");\n    _z_subscription_rc_t subscription_rc =\n        register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_SESSION_LOCAL);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    _z_bytes_t payload;\n    assert(_z_bytes_from_buf(&payload, (const uint8_t *)payload_data, sizeof(payload_data) - 1) == _Z_RES_OK);\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t ts = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n    z_result_t delivered =\n        _z_session_deliver_push_locally(&g_session, &keyexpr._inner, &payload, &encoding, Z_SAMPLE_KIND_PUT, qos, &ts,\n                                        NULL, Z_RELIABILITY_RELIABLE, &source_info);\n    assert(delivered == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n    _z_bytes_drop(&payload);\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &subscription_rc);\n    cleanup_local_resource(&keyexpr);\n    cleanup_session();\n}\n\nstatic void test_put_local_only_via_api(void) {\n    setup_session();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put/api\");\n    _z_subscription_rc_t subscription_rc =\n        register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_SESSION_LOCAL);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    z_owned_bytes_t payload = {0};\n    assert(z_bytes_from_buf(&payload, (uint8_t *)payload_data, sizeof(payload_data) - 1, NULL, NULL) == Z_OK);\n\n    z_put_options_t opt;\n    z_put_options_default(&opt);\n    opt.allowed_destination = Z_LOCALITY_SESSION_LOCAL;\n\n    z_result_t res = z_put(&g_session_rc, (const z_loaned_keyexpr_t *)&keyexpr, z_move(payload), &opt);\n    assert(res == Z_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    z_owned_bytes_t payload2 = {0};\n    assert(z_bytes_from_buf(&payload2, (uint8_t *)payload_data, sizeof(payload_data) - 1, NULL, NULL) == Z_OK);\n    z_put_options_default(&opt);\n    opt.allowed_destination = Z_LOCALITY_ANY;\n    res = z_put(&g_session_rc, (const z_loaned_keyexpr_t *)&keyexpr, z_move(payload2), &opt);\n    assert(res == Z_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &subscription_rc);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_put_local_and_remote_via_api(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put/api-mixed\");\n    _z_subscription_rc_t subscription_rc =\n        register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_ANY);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    z_owned_bytes_t payload = {0};\n    assert(z_bytes_from_buf(&payload, (uint8_t *)payload_data, sizeof(payload_data) - 1, NULL, NULL) == Z_OK);\n\n    z_put_options_t opt;\n    z_put_options_default(&opt);\n    opt.allowed_destination = Z_LOCALITY_SESSION_LOCAL;\n    z_result_t res = z_put(&g_session_rc, (const z_loaned_keyexpr_t *)&keyexpr, z_move(payload), &opt);\n    assert(res == Z_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    z_owned_bytes_t payload2 = {0};\n    assert(z_bytes_from_buf(&payload2, (uint8_t *)payload_data, sizeof(payload_data) - 1, NULL, NULL) == Z_OK);\n    opt.allowed_destination = Z_LOCALITY_ANY;\n    res = z_put(&g_session_rc, (const z_loaned_keyexpr_t *)&keyexpr, z_move(payload2), &opt);\n    assert(res == Z_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &subscription_rc);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_query_local_only_single(void) {\n    setup_session();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/query\");\n\n    _z_session_queryable_rc_t queryable_rc =\n        register_local_queryable(&keyexpr, &g_local_query_delivery_count, Z_LOCALITY_SESSION_LOCAL);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_final_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_drop_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_reply_callback_count, 0, memory_order_relaxed);\n\n    // With Z_CONSOLIDATION_MODE_DEFAULT should be set to LATEST, when no time is specified\n    // Explicitly set LATEST consolidation mode for clarity\n    assert(g_session._tp._transport._unicast._common._link == NULL);\n    assert(_z_transport_peer_unicast_slist_is_empty(g_session._tp._transport._unicast._peers));\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    z_result_t res = _z_query(&g_session_rc, _z_optional_id_make_none(), &keyexpr, NULL, 0, Z_QUERY_TARGET_DEFAULT,\n                              Z_CONSOLIDATION_MODE_LATEST, NULL, NULL, query_reply_callback, query_dropper, NULL, 1000,\n                              NULL, qos, NULL, Z_REPLY_KEYEXPR_MATCHING_QUERY, Z_LOCALITY_SESSION_LOCAL, NULL);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_query_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_final_send_count, memory_order_relaxed) == 0);\n    assert(g_session._pending_queries == NULL);\n\n    _z_unregister_session_queryable(&g_session, &queryable_rc);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_put_local_only_multiple(void) {\n    setup_session();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put/multi\");\n\n    _z_subscription_rc_t sub_primary =\n        register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_SESSION_LOCAL);\n    atomic_uint local_put_secondary_count = 0;\n    _z_subscription_rc_t sub_secondary =\n        register_local_subscription(&keyexpr, &local_put_secondary_count, Z_LOCALITY_SESSION_LOCAL);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&local_put_secondary_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    _z_bytes_t payload;\n    assert(_z_bytes_from_buf(&payload, (const uint8_t *)payload_data, sizeof(payload_data) - 1) == _Z_RES_OK);\n\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t ts = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n    z_result_t delivered =\n        _z_session_deliver_push_locally(&g_session, &keyexpr._inner, &payload, &encoding, Z_SAMPLE_KIND_PUT, qos, &ts,\n                                        NULL, Z_RELIABILITY_RELIABLE, &source_info);\n    assert(delivered == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&local_put_secondary_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n\n    _z_bytes_drop(&payload);\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sub_secondary);\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sub_primary);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_put_local_and_remote(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put/mixed\");\n\n    _z_subscription_rc_t sub_primary =\n        register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_ANY);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    _z_bytes_t payload;\n    assert(_z_bytes_from_buf(&payload, (const uint8_t *)payload_data, sizeof(payload_data) - 1) == _Z_RES_OK);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t ts = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n\n    // Session-local only delivery should not touch transport\n    z_result_t res =\n        _z_write(&g_session, &keyexpr, &payload, &encoding, Z_SAMPLE_KIND_PUT, Z_CONGESTION_CONTROL_BLOCK,\n                 Z_PRIORITY_DEFAULT, false, &ts, NULL, Z_RELIABILITY_RELIABLE, &source_info, Z_LOCALITY_SESSION_LOCAL);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n\n    // Allow remote recipients; send to transport in addition to local delivery\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    res = _z_write(&g_session, &keyexpr, &payload, &encoding, Z_SAMPLE_KIND_PUT, Z_CONGESTION_CONTROL_BLOCK,\n                   Z_PRIORITY_DEFAULT, false, &ts, NULL, Z_RELIABILITY_RELIABLE, &source_info, Z_LOCALITY_ANY);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n\n    _z_bytes_drop(&payload);\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sub_primary);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_query_local_only_multiple(void) {\n    setup_session();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/query/multi\");\n\n    _z_session_queryable_rc_t queryable_primary =\n        register_local_queryable(&keyexpr, &g_local_query_delivery_count, Z_LOCALITY_SESSION_LOCAL);\n    atomic_uint local_query_secondary_count = 0;\n    _z_session_queryable_rc_t queryable_secondary =\n        register_local_queryable(&keyexpr, &local_query_secondary_count, Z_LOCALITY_SESSION_LOCAL);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_final_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&local_query_secondary_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_drop_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_reply_callback_count, 0, memory_order_relaxed);\n\n    // Explicitly set LATEST consolidation mode for clarity (should be default)\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    z_result_t res = _z_query(&g_session_rc, _z_optional_id_make_none(), &keyexpr, NULL, 0, Z_QUERY_TARGET_DEFAULT,\n                              Z_CONSOLIDATION_MODE_LATEST, NULL, NULL, query_reply_callback, query_dropper, NULL, 1000,\n                              NULL, qos, NULL, Z_REPLY_KEYEXPR_MATCHING_QUERY, Z_LOCALITY_SESSION_LOCAL, NULL);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_query_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&local_query_secondary_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_final_send_count, memory_order_relaxed) == 0);\n    assert(g_session._pending_queries == NULL);\n\n    _z_unregister_session_queryable(&g_session, &queryable_secondary);\n    _z_unregister_session_queryable(&g_session, &queryable_primary);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_query_local_and_remote(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/query/mixed\");\n    _z_session_queryable_rc_t queryable_primary =\n        register_local_queryable(&keyexpr, &g_local_query_delivery_count, Z_LOCALITY_SESSION_LOCAL);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_final_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_drop_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_reply_callback_count, 0, memory_order_relaxed);\n\n    // Explicitly set LATEST consolidation mode for clarity (should be default)\n    // Locality limited to session, loopback-only, transport untouched\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    z_result_t res = _z_query(&g_session_rc, _z_optional_id_make_none(), &keyexpr, NULL, 0, Z_QUERY_TARGET_DEFAULT,\n                              Z_CONSOLIDATION_MODE_LATEST, NULL, NULL, query_reply_callback, query_dropper, NULL, 1000,\n                              NULL, qos, NULL, Z_REPLY_KEYEXPR_MATCHING_QUERY, Z_LOCALITY_SESSION_LOCAL, NULL);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_query_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_final_send_count, memory_order_relaxed) == 0);\n    assert(g_session._pending_queries == NULL);\n\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_reply_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_drop_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_final_send_count, 0, memory_order_relaxed);\n    // Permit remote delivery; still send to loopback, but network request must be emitted as well\n    res = _z_query(&g_session_rc, _z_optional_id_make_none(), &keyexpr, NULL, 0, Z_QUERY_TARGET_DEFAULT,\n                   Z_CONSOLIDATION_MODE_LATEST, NULL, NULL, query_reply_callback, query_dropper, NULL, 1000, NULL, qos,\n                   NULL, Z_REPLY_KEYEXPR_MATCHING_QUERY, Z_LOCALITY_ANY, NULL);\n    assert(res == _Z_RES_OK);\n\n    assert(atomic_load_explicit(&g_local_query_delivery_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_network_final_send_count, memory_order_relaxed) == 0);\n    assert(g_session._pending_queries != NULL);\n\n    // Simulate REPLY from remote queryable\n    _z_pending_query_t *pq = _z_pending_query_slist_value(g_session._pending_queries);\n    _z_zint_t request_id = pq->_id;\n\n    const char remote_data[] = \"remote-response\";\n    _z_bytes_t remote_payload = _z_bytes_null();\n    assert(_z_bytes_from_buf(&remote_payload, (const uint8_t *)remote_data, sizeof(remote_data) - 1) == _Z_RES_OK);\n\n    _z_id_t remote_zid = _z_id_empty();\n    _z_session_generate_zid(&remote_zid, Z_ZID_LENGTH);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t timestamp = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n\n    _z_network_message_t reply_msg;\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(&keyexpr, &g_session);\n    _z_n_msg_make_reply_ok_put(&reply_msg, &remote_zid, request_id, &wireexpr, Z_RELIABILITY_RELIABLE,\n                               Z_CONSOLIDATION_MODE_DEFAULT, qos, &timestamp, &source_info, &remote_payload, &encoding,\n                               NULL);\n    res = _z_handle_network_message(&g_fake_transport, &reply_msg, NULL);\n    assert(res == _Z_RES_OK);\n\n    // Remote reply buffered (LATEST mode), not delivered yet,\n    // will be delivered on RESPONSE_FINAL\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 0);\n    assert(g_session._pending_queries != NULL);\n\n    // Receiving RESPONSE_FINAL from remote queryable\n    _z_network_message_t final_msg;\n    _z_n_msg_make_response_final(&final_msg, request_id);\n    res = _z_handle_network_message(&g_fake_transport, &final_msg, NULL);\n    assert(res == _Z_RES_OK);\n\n    // Remote reply delivered, query finalized\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 1);\n    assert(g_session._pending_queries == NULL);\n\n    _z_unregister_session_queryable(&g_session, &queryable_primary);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_query_local_and_remote_via_api(void) {\n    setup_session();\n    add_fake_peer();\n\n    const char *kestr = \"zenoh-pico/tests/local/query/api-mixed\";\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(kestr);\n\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_final_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_drop_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_reply_callback_count, 0, memory_order_relaxed);\n\n    z_owned_closure_query_t q_closure = {0};\n    assert(z_closure_query(&q_closure, (z_closure_query_callback_t)local_query_callback, NULL,\n                           &g_local_query_delivery_count) == Z_OK);\n\n    z_owned_queryable_t queryable = {0};\n    z_queryable_options_t qopt;\n    z_queryable_options_default(&qopt);\n    qopt.allowed_origin = Z_LOCALITY_ANY;\n\n    z_owned_keyexpr_t keyexpr_owned = {0};\n    assert(z_keyexpr_from_str(&keyexpr_owned, kestr) == Z_OK);\n\n    z_result_t res = z_declare_queryable((const z_loaned_session_t *)&g_session_rc, &queryable,\n                                         (const z_loaned_keyexpr_t *)&keyexpr_owned, z_move(q_closure), &qopt);\n    assert(res == Z_OK);\n\n    z_owned_closure_reply_t r_closure = {0};\n    assert(z_closure_reply(&r_closure, query_reply_callback, query_dropper, NULL) == Z_OK);\n\n    z_get_options_t gopt;\n    z_get_options_default(&gopt);\n    gopt.allowed_destination = Z_LOCALITY_ANY;\n\n    res = z_get((const z_loaned_session_t *)&g_session_rc, (const z_loaned_keyexpr_t *)&keyexpr_owned, \"\",\n                z_move(r_closure), &gopt);\n    assert(res == Z_OK);\n\n    _z_pending_query_t *pq = _z_pending_query_slist_value(g_session._pending_queries);\n    assert(pq != NULL);\n    _z_zint_t request_id = pq->_id;\n\n    const char remote_data[] = \"remote-response\";\n    _z_bytes_t remote_payload = _z_bytes_null();\n    assert(_z_bytes_from_buf(&remote_payload, (const uint8_t *)remote_data, sizeof(remote_data) - 1) == _Z_RES_OK);\n\n    _z_id_t remote_zid = _z_id_empty();\n    _z_session_generate_zid(&remote_zid, Z_ZID_LENGTH);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t timestamp = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n\n    _z_network_message_t reply_msg;\n    _z_wireexpr_t wireexpr = _z_declared_keyexpr_alias_to_wire(&keyexpr, &g_session);\n    _z_n_msg_make_reply_ok_put(&reply_msg, &remote_zid, request_id, &wireexpr, Z_RELIABILITY_RELIABLE,\n                               Z_CONSOLIDATION_MODE_DEFAULT, _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT),\n                               &timestamp, &source_info, &remote_payload, &encoding, NULL);\n    res = _z_handle_network_message(&g_fake_transport, &reply_msg, NULL);\n    assert(res == _Z_RES_OK);\n\n    _z_network_message_t final_msg;\n    _z_n_msg_make_response_final(&final_msg, request_id);\n    res = _z_handle_network_message(&g_fake_transport, &final_msg, NULL);\n    assert(res == _Z_RES_OK);\n\n    assert(atomic_load_explicit(&g_query_reply_callback_count, memory_order_relaxed) == 1);\n    assert(atomic_load_explicit(&g_query_drop_callback_count, memory_order_relaxed) == 1);\n    assert(g_session._pending_queries == NULL);\n\n    z_moved_queryable_t *mq = z_queryable_move(&queryable);\n    z_queryable_drop(mq);\n    z_moved_keyexpr_t *mk = z_keyexpr_move(&keyexpr_owned);\n    z_keyexpr_drop(mk);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_put_remote_only_destination(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put/remote-only\");\n\n    _z_subscription_rc_t sub = register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_ANY);\n\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    _z_bytes_t payload;\n    assert(_z_bytes_from_buf(&payload, (const uint8_t *)payload_data, sizeof(payload_data) - 1) == _Z_RES_OK);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t ts = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n\n    z_result_t res =\n        _z_write(&g_session, &keyexpr, &payload, &encoding, Z_SAMPLE_KIND_PUT, Z_CONGESTION_CONTROL_BLOCK,\n                 Z_PRIORITY_DEFAULT, false, &ts, NULL, Z_RELIABILITY_RELIABLE, &source_info, Z_LOCALITY_REMOTE);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n\n    _z_bytes_drop(&payload);\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sub);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_subscriber_remote_only_origin(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/put/remote-origin\");\n\n    _z_subscription_rc_t sub = register_local_subscription(&keyexpr, &g_local_put_delivery_count, Z_LOCALITY_REMOTE);\n\n    atomic_store_explicit(&g_local_put_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n\n    const char payload_data[] = \"payload\";\n    _z_bytes_t payload;\n    assert(_z_bytes_from_buf(&payload, (const uint8_t *)payload_data, sizeof(payload_data) - 1) == _Z_RES_OK);\n    _z_encoding_t encoding = _z_encoding_null();\n    _z_timestamp_t ts = _z_timestamp_null();\n    _z_source_info_t source_info = _z_source_info_null();\n\n    z_result_t res =\n        _z_write(&g_session, &keyexpr, &payload, &encoding, Z_SAMPLE_KIND_PUT, Z_CONGESTION_CONTROL_BLOCK,\n                 Z_PRIORITY_DEFAULT, false, &ts, NULL, Z_RELIABILITY_RELIABLE, &source_info, Z_LOCALITY_ANY);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_put_delivery_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n\n    _z_bytes_drop(&payload);\n    _z_unregister_subscription(&g_session, _Z_SUBSCRIBER_KIND_SUBSCRIBER, &sub);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_query_remote_only_destination(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/query/remote-only\");\n\n    _z_session_queryable_rc_t queryable_rc =\n        register_local_queryable(&keyexpr, &g_local_query_delivery_count, Z_LOCALITY_ANY);\n\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_reply_callback_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_query_drop_callback_count, 0, memory_order_relaxed);\n\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    z_result_t res = _z_query(&g_session_rc, _z_optional_id_make_none(), &keyexpr, NULL, 0, Z_QUERY_TARGET_DEFAULT,\n                              Z_CONSOLIDATION_MODE_LATEST, NULL, NULL, query_reply_callback, query_dropper, NULL, 1000,\n                              NULL, qos, NULL, Z_REPLY_KEYEXPR_MATCHING_QUERY, Z_LOCALITY_REMOTE, NULL);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_query_delivery_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n\n    // Clean pending query by simulating RESPONSE_FINAL\n    _z_pending_query_t *pq = _z_pending_query_slist_value(g_session._pending_queries);\n    assert(pq != NULL);\n    _z_network_message_t final_msg;\n    _z_n_msg_make_response_final(&final_msg, pq->_id);\n    res = _z_handle_network_message(&g_fake_transport, &final_msg, NULL);\n    assert(res == _Z_RES_OK);\n    assert(g_session._pending_queries == NULL);\n\n    _z_unregister_session_queryable(&g_session, &queryable_rc);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nstatic void test_queryable_remote_only_origin(void) {\n    setup_session();\n    add_fake_peer();\n\n    _z_declared_keyexpr_t keyexpr = create_local_resource(\"zenoh-pico/tests/local/query/remote-origin\");\n\n    _z_session_queryable_rc_t queryable_rc =\n        register_local_queryable(&keyexpr, &g_local_query_delivery_count, Z_LOCALITY_REMOTE);\n\n    atomic_store_explicit(&g_local_query_delivery_count, 0, memory_order_relaxed);\n    atomic_store_explicit(&g_network_send_count, 0, memory_order_relaxed);\n\n    _z_n_qos_t qos = _z_n_qos_make(false, false, Z_PRIORITY_DEFAULT);\n    z_result_t res = _z_query(&g_session_rc, _z_optional_id_make_none(), &keyexpr, NULL, 0, Z_QUERY_TARGET_DEFAULT,\n                              Z_CONSOLIDATION_MODE_LATEST, NULL, NULL, query_reply_callback, query_dropper, NULL, 1000,\n                              NULL, qos, NULL, Z_REPLY_KEYEXPR_MATCHING_QUERY, Z_LOCALITY_ANY, NULL);\n    assert(res == _Z_RES_OK);\n    assert(atomic_load_explicit(&g_local_query_delivery_count, memory_order_relaxed) == 0);\n    assert(atomic_load_explicit(&g_network_send_count, memory_order_relaxed) == 1);\n\n    _z_pending_query_t *pq = _z_pending_query_slist_value(g_session._pending_queries);\n    assert(pq != NULL);\n    _z_network_message_t final_msg2;\n    _z_n_msg_make_response_final(&final_msg2, pq->_id);\n    res = _z_handle_network_message(&g_fake_transport, &final_msg2, NULL);\n    assert(res == _Z_RES_OK);\n\n    _z_unregister_session_queryable(&g_session, &queryable_rc);\n    cleanup_local_resource(&keyexpr);\n\n    cleanup_session();\n}\n\nint main(void) {\n    test_put_local_only_single();\n    test_put_local_only_via_api();\n    test_put_local_and_remote_via_api();\n    test_put_local_only_multiple();\n    test_put_local_and_remote();\n    test_query_local_only_single();\n    test_query_local_only_multiple();\n    test_query_local_and_remote();\n    test_query_local_and_remote_via_api();\n    test_put_remote_only_destination();\n    test_subscriber_remote_only_origin();\n    test_query_remote_only_destination();\n    test_queryable_remote_only_origin();\n    return 0;\n}\n\n#else\nint main(void) {\n    printf(\n        \"This test requires: Z_FEATURE_SUBSCRIPTION, Z_FEATURE_QUERYABLE, Z_FEATURE_QUERY, Z_FEATURE_LOCAL_SUBSCRIBER\"\n        \"and Z_FEATURE_LOCAL_QUERYABLE.\\n\");\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "tests/z_lru_cache_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/lru_cache.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define CACHE_CAPACITY 10\n\ntypedef struct _dummy_t {\n    int foo;\n} _dummy_t;\n\nint _dummy_compare(const void *first, const void *second) {\n    _dummy_t *d_first = (_dummy_t *)first;\n    _dummy_t *d_second = (_dummy_t *)second;\n\n    if (d_first->foo == d_second->foo) {\n        return 0;\n    } else if (d_first->foo > d_second->foo) {\n        return 1;\n    }\n    return -1;\n}\n\nstatic inline void _dummy_elem_clear(void *e) { _z_noop_clear((_dummy_t *)e); }\n\n_Z_LRU_CACHE_DEFINE(_dummy, _dummy_t, _dummy_compare)\n\nvoid test_lru_init(void) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(CACHE_CAPACITY);\n    assert(dcache.capacity == CACHE_CAPACITY);\n    assert(dcache.len == 0);\n    assert(dcache.head == NULL);\n    assert(dcache.tail == NULL);\n    assert(dcache.slist == NULL);\n}\n\nvoid test_lru_cache_insert(void) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(CACHE_CAPACITY);\n\n    _dummy_t v0 = {0};\n    assert(dcache.slist == NULL);\n    assert(_dummy_lru_cache_get(&dcache, &v0) == NULL);\n    assert(_dummy_lru_cache_insert(&dcache, &v0) == 0);\n    assert(dcache.slist != NULL);\n    _dummy_t *res = _dummy_lru_cache_get(&dcache, &v0);\n    assert(res != NULL);\n    assert(res->foo == v0.foo);\n\n    _dummy_t data[CACHE_CAPACITY] = {0};\n    for (size_t i = 1; i < CACHE_CAPACITY; i++) {\n        data[i].foo = (int)i;\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    for (size_t i = 0; i < CACHE_CAPACITY; i++) {\n        res = _dummy_lru_cache_get(&dcache, &data[i]);\n        assert(res != NULL);\n        assert(res->foo == data[i].foo);\n    }\n    _dummy_lru_cache_delete(&dcache);\n}\n\nvoid test_lru_cache_clear(void) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(CACHE_CAPACITY);\n\n    _dummy_t data[CACHE_CAPACITY] = {0};\n    for (size_t i = 0; i < CACHE_CAPACITY; i++) {\n        data[i].foo = (int)i;\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    _dummy_lru_cache_clear(&dcache);\n    assert(dcache.capacity == CACHE_CAPACITY);\n    assert(dcache.len == 0);\n    assert(dcache.slist != NULL);\n    assert(dcache.head == NULL);\n    assert(dcache.tail == NULL);\n    for (size_t i = 0; i < CACHE_CAPACITY; i++) {\n        assert(_dummy_lru_cache_get(&dcache, &data[i]) == NULL);\n    }\n    _dummy_lru_cache_delete(&dcache);\n}\n\nvoid test_lru_cache_deletion(void) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(CACHE_CAPACITY);\n\n    _dummy_t data[CACHE_CAPACITY + 1] = {0};\n    for (size_t i = 0; i < CACHE_CAPACITY + 1; i++) {\n        data[i].foo = (int)i;\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    // Check value deleted\n    assert(_dummy_lru_cache_get(&dcache, &data[0]) == NULL);\n    // Check remaining value\n    for (size_t i = 1; i < CACHE_CAPACITY + 1; i++) {\n        _dummy_t *res = _dummy_lru_cache_get(&dcache, &data[i]);\n        assert(res != NULL);\n        assert(res->foo == data[i].foo);\n    }\n    _dummy_lru_cache_delete(&dcache);\n}\n\nvoid test_lru_cache_update(void) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(CACHE_CAPACITY);\n\n    _dummy_t data[CACHE_CAPACITY] = {0};\n    for (size_t i = 0; i < CACHE_CAPACITY; i++) {\n        data[i].foo = (int)i;\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    // Update value\n    assert(_dummy_lru_cache_get(&dcache, &data[0]) != NULL);\n    // Insert extra value\n    _dummy_t extra_data = {55};\n    assert(_dummy_lru_cache_insert(&dcache, &extra_data) == 0);\n    // Check value deleted\n    assert(_dummy_lru_cache_get(&dcache, &data[1]) == NULL);\n    _dummy_lru_cache_delete(&dcache);\n}\n\nstatic bool val_in_array(int val, int *array, size_t array_size) {\n    for (size_t i = 0; i < array_size; i++) {\n        if (val == array[i]) {\n            return true;\n        }\n    }\n    return false;\n}\n\nvoid test_lru_cache_random_val(void) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(10 * CACHE_CAPACITY);\n\n    _dummy_t data[11 * CACHE_CAPACITY] = {\n        {1804289383}, {846930886},  {1681692777}, {1714636915}, {1957747793}, {424238335},  {719885386},  {1649760492},\n        {596516649},  {1189641421}, {1025202362}, {1350490027}, {783368690},  {1102520059}, {2044897763}, {1967513926},\n        {1365180540}, {1540383426}, {304089172},  {1303455736}, {35005211},   {521595368},  {294702567},  {1726956429},\n        {336465782},  {861021530},  {278722862},  {233665123},  {2145174067}, {468703135},  {1101513929}, {1801979802},\n        {1315634022}, {635723058},  {1369133069}, {1125898167}, {1059961393}, {2089018456}, {628175011},  {1656478042},\n        {1131176229}, {1653377373}, {859484421},  {1914544919}, {608413784},  {756898537},  {1734575198}, {1973594324},\n        {149798315},  {2038664370}, {1129566413}, {184803526},  {412776091},  {1424268980}, {1911759956}, {749241873},\n        {137806862},  {42999170},   {982906996},  {135497281},  {511702305},  {2084420925}, {1937477084}, {1827336327},\n        {572660336},  {1159126505}, {805750846},  {1632621729}, {1100661313}, {1433925857}, {1141616124}, {84353895},\n        {939819582},  {2001100545}, {1998898814}, {1548233367}, {610515434},  {1585990364}, {1374344043}, {760313750},\n        {1477171087}, {356426808},  {945117276},  {1889947178}, {1780695788}, {709393584},  {491705403},  {1918502651},\n        {752392754},  {1474612399}, {2053999932}, {1264095060}, {1411549676}, {1843993368}, {943947739},  {1984210012},\n        {855636226},  {1749698586}, {1469348094}, {1956297539}, {1036140795}, {463480570},  {2040651434}, {1975960378},\n        {317097467},  {1892066601}, {1376710097}, {927612902},  {1330573317}, {603570492},\n    };\n    // Insert data\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(data); i++) {\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    // Check values\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(data); i++) {\n        _dummy_t *res = _dummy_lru_cache_get(&dcache, &data[i]);\n        if (i < CACHE_CAPACITY) {\n            assert(res == NULL);\n        } else {\n            assert(res != NULL);\n            assert(res->foo == data[i].foo);\n        }\n    }\n    // Update most values\n    int not_upd_idx[CACHE_CAPACITY] = {\n        34, 12, 42, 46, 56, 109, 103, 15, 96, 31,\n    };\n    for (size_t i = CACHE_CAPACITY; i < _ZP_ARRAY_SIZE(data); i++) {\n        if (!val_in_array((int)i, not_upd_idx, _ZP_ARRAY_SIZE(not_upd_idx))) {\n            assert(_dummy_lru_cache_get(&dcache, &data[i]) != NULL);\n        }\n    }\n    // Insert back deleted value\n    for (size_t i = 0; i < CACHE_CAPACITY; i++) {\n        assert(_dummy_lru_cache_get(&dcache, &data[i]) == NULL);\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    // Check deleted values\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(data); i++) {\n        _dummy_t *res = _dummy_lru_cache_get(&dcache, &data[i]);\n        if (val_in_array((int)i, not_upd_idx, _ZP_ARRAY_SIZE(not_upd_idx))) {\n            assert(res == NULL);\n        } else {\n            assert(res != NULL);\n            assert(res->foo == data[i].foo);\n        }\n    }\n    // Clean-up\n    _dummy_lru_cache_delete(&dcache);\n}\n\n#if 0\n#define BENCH_THRESHOLD 1000000\n\nvoid test_search_benchmark(size_t capacity) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(capacity);\n    _dummy_t data[capacity];\n    memset(data, 0, capacity * sizeof(_dummy_t));\n\n    srand(0x55);\n    // Insert data\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(data); i++) {\n        data[i].foo = rand();\n        assert(_dummy_lru_cache_insert(&dcache, &data[i]) == 0);\n    }\n    z_clock_t measure_start = z_clock_now();\n    for (size_t get_cnt = 0; get_cnt <= BENCH_THRESHOLD; get_cnt++) {\n        int i = rand() % (int)_ZP_ARRAY_SIZE(data);\n        _dummy_t *src = &data[i];\n        _dummy_t *res = _dummy_lru_cache_get(&dcache, src);\n        assert(res != NULL);\n    }\n    unsigned long elapsed_us = z_clock_elapsed_us(&measure_start);\n    printf(\"Time to search: %ld\\n\", elapsed_us);\n}\n\nvoid test_insert_benchmark(size_t capacity) {\n    _dummy_lru_cache_t dcache = _dummy_lru_cache_init(capacity);\n\n    srand(0x55);\n    // Insert data\n    z_clock_t measure_start = z_clock_now();\n    for (size_t get_cnt = 0; get_cnt <= BENCH_THRESHOLD; get_cnt++) {\n        _dummy_t data = {.foo = rand()};\n        assert(_dummy_lru_cache_insert(&dcache, &data) == 0);\n    }\n    unsigned long elapsed_us = z_clock_elapsed_us(&measure_start);\n    printf(\"Time to insert: %ld\\n\", elapsed_us);\n}\n\nvoid test_benchmark(void) {\n    for (size_t i = 1; i <= BENCH_THRESHOLD; i *= 10) {\n        printf(\"Capacity: %ld\\n\", i);\n        test_search_benchmark(i);\n        test_insert_benchmark(i);\n    }\n}\n#endif\n\nint main(void) {\n    test_lru_init();\n    test_lru_cache_insert();\n    test_lru_cache_clear();\n    test_lru_cache_deletion();\n    test_lru_cache_update();\n    test_lru_cache_random_val();\n#if 0\n    test_benchmark();\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_msgcodec_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include \"zenoh-pico/api/constants.h\"\n#include \"zenoh-pico/protocol/codec/message.h\"\n#include \"zenoh-pico/protocol/codec/network.h\"\n#include \"zenoh-pico/protocol/codec/serial.h\"\n#include \"zenoh-pico/protocol/definitions/message.h\"\n#include \"zenoh-pico/protocol/definitions/transport.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n#define ZENOH_PICO_TEST_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/slice.h\"\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/protocol/codec/core.h\"\n#include \"zenoh-pico/protocol/codec/declarations.h\"\n#include \"zenoh-pico/protocol/codec/ext.h\"\n#include \"zenoh-pico/protocol/codec/interest.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/protocol/core.h\"\n#include \"zenoh-pico/protocol/definitions/declarations.h\"\n#include \"zenoh-pico/protocol/definitions/interest.h\"\n#include \"zenoh-pico/protocol/definitions/network.h\"\n#include \"zenoh-pico/protocol/ext.h\"\n#include \"zenoh-pico/protocol/iobuf.h\"\n#include \"zenoh-pico/system/platform.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define RUNS 1000\n\n#define _Z_MOCK_EXTENSION_UNIT 0x01\n#define _Z_MOCK_EXTENSION_ZINT 0x02\n#define _Z_MOCK_EXTENSION_ZBUF 0x03\n\n#if defined(_WIN32) || defined(WIN32)\n#pragma warning(push)\n#pragma warning(disable : 4244 4267)  // Disable truncation warnings in MSVC,\n                                      // as it is used voluntarily in this file when working with RNG\n#endif\n\n/*=============================*/\n/*       Helper functions      */\n/*=============================*/\nvoid print_iosli(_z_iosli_t *ios) {\n    printf(\"IOSli: Capacity: %zu, Rpos: %zu, Wpos: %zu, Buffer: [\", ios->_capacity, ios->_r_pos, ios->_w_pos);\n    for (size_t i = ios->_r_pos; i < ios->_w_pos; i++) {\n        printf(\"%02x\", ios->_buf[i]);\n        if (i < ios->_w_pos - ios->_r_pos - 1) printf(\" \");\n    }\n    printf(\"]\");\n}\n\nvoid print_wbuf(_z_wbuf_t *wbf) {\n    printf(\"   WBuf: %zu, RIdx: %zu, WIdx: %zu\\n\", _z_wbuf_len_iosli(wbf), wbf->_r_idx, wbf->_w_idx);\n    for (size_t i = 0; i < _z_wbuf_len_iosli(wbf); i++) {\n        printf(\"   - \");\n        print_iosli(_z_wbuf_get_iosli(wbf, i));\n        printf(\"\\n\");\n    }\n}\n\nvoid print_zbuf(_z_zbuf_t *zbf) { print_iosli(&zbf->_ios); }\n\nvoid print_uint8_array(_z_slice_t *arr) {\n    printf(\"Length: %zu, Buffer: [\", arr->len);\n    for (size_t i = 0; i < arr->len; i++) {\n        printf(\"%02x\", arr->start[i]);\n        if (i < arr->len - 1) printf(\" \");\n    }\n    printf(\"]\");\n}\n\nvoid print_transport_message_type(uint8_t header) {\n    switch (_Z_MID(header)) {\n        case _Z_MID_T_JOIN:\n            printf(\"Join message\");\n            break;\n        case _Z_MID_T_INIT:\n            printf(\"Init message\");\n            break;\n        case _Z_MID_T_OPEN:\n            printf(\"Open message\");\n            break;\n        case _Z_MID_T_CLOSE:\n            printf(\"Close message\");\n            break;\n        case _Z_MID_T_KEEP_ALIVE:\n            printf(\"KeepAlive message\");\n            break;\n        case _Z_MID_T_FRAME:\n            printf(\"Frame message\");\n            break;\n        case _Z_MID_T_FRAGMENT:\n            printf(\"Frame message\");\n            break;\n        default:\n            assert(0);\n            break;\n    }\n}\n\nvoid print_scouting_message_type(uint8_t header) {\n    switch (_Z_MID(header)) {\n        case _Z_MID_SCOUT:\n            printf(\"Scout message\");\n            break;\n        case _Z_MID_HELLO:\n            printf(\"Hello message\");\n            break;\n        default:\n            assert(0);\n            break;\n    }\n}\n\n/*=============================*/\n/*    Generating functions     */\n/*=============================*/\nbool gen_bool(void) { return z_random_u8() % 2; }\n\nuint8_t gen_uint8(void) { return z_random_u8(); }\n\nuint16_t gen_uint16(void) { return z_random_u16(); }\n\nuint64_t gen_uint64(void) {\n    uint64_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\nuint32_t gen_uint32(void) {\n    unsigned int ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\n_z_zint_t gen_zint(void) {\n    _z_zint_t ret = 0;\n    z_random_fill(&ret, sizeof(ret));\n    return ret;\n}\n\n_z_wbuf_t gen_wbuf(size_t len) {\n    bool is_expandable = false;\n\n    if (gen_bool()) {\n        is_expandable = true;\n        len = 1 + (gen_zint() % len);\n    }\n\n    _z_wbuf_t wbuf = _z_wbuf_make(len, is_expandable);\n    assert(_z_wbuf_capacity(&wbuf) == len);\n    return wbuf;\n}\n\n_z_slice_t gen_slice(size_t len) {\n    if (len == 0) {\n        return _z_slice_null();\n    }\n\n    uint8_t *p = (uint8_t *)z_malloc(sizeof(uint8_t) * len);\n    for (_z_zint_t i = 0; i < len; i++) {\n        ((uint8_t *)p)[i] = gen_uint8() & 0x7f;  // 0b01111111\n    }\n    return _z_slice_from_buf_custom_deleter(p, len, _z_delete_context_default());\n}\n\n_z_bytes_t gen_payload(size_t len) {\n    _z_slice_t pld = gen_slice(len);\n    _z_bytes_t b;\n    _z_bytes_from_slice(&b, &pld);\n\n    return b;\n}\n\n_z_bytes_t gen_bytes(size_t len) {\n    _z_slice_t s = gen_slice(len);\n    _z_bytes_t b;\n    _z_bytes_from_slice(&b, &s);\n    return b;\n}\n\n_z_id_t gen_zid(void) {\n    _z_id_t id = _z_id_empty();\n    uint8_t hash = 55;\n    uint8_t len = gen_uint8() % 16;\n    for (uint8_t i = 0; i < len; i++) {\n        uint8_t byte = gen_uint8();\n        id.id[i] = byte;\n        hash = (uint8_t)(hash ^ i * byte);\n    }\n    id.id[0] = hash;\n    return id;\n}\n\nchar *gen_str(size_t size) {\n    char charset[] = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n    char *str = (char *)z_malloc(size + 1);\n    for (_z_zint_t i = 0; i < size; i++) {\n        uint32_t key = z_random_u32() % (sizeof(charset) - 1);\n        str[i] = charset[key];\n    }\n    str[size] = '\\0';\n    return str;\n}\n\n_z_string_t gen_string(size_t len) {\n    char *str = gen_str(len);\n    _z_string_t ret = _z_string_copy_from_str(str);\n    z_free(str);\n    return ret;\n}\n\n_z_string_svec_t gen_str_array(size_t size) {\n    _z_string_svec_t sa = _z_string_svec_make(size);\n    for (size_t i = 0; i < size; i++) {\n        _z_string_t s = gen_string(16);\n        assert(_z_string_svec_append(&sa, &s, true) == _Z_RES_OK);\n    }\n\n    return sa;\n}\n\n_z_locator_array_t gen_locator_array(size_t size) {\n    _z_locator_array_t la = _z_locator_array_make(size);\n    for (size_t i = 0; i < size; i++) {\n        _z_locator_t *val = &la._val[i];\n        val->_protocol = gen_string(3);\n        val->_address = gen_string(12);\n        val->_metadata = _z_str_intmap_make();  // @TODO: generate metadata\n    }\n\n    return la;\n}\n\n_z_encoding_t gen_encoding(void) {\n    _z_encoding_t en;\n    en.id = gen_uint16();\n    if (gen_bool()) {\n        en.schema = gen_string(16);\n    } else {\n        en.schema = _z_string_null();\n    }\n    return en;\n}\n\n_z_value_t gen_value(void) {\n    _z_value_t val;\n    val.encoding = gen_encoding();\n    if (gen_bool()) {\n        val.payload = _z_bytes_null();\n    } else {\n        val.payload = gen_bytes(16);\n    }\n\n    return val;\n}\n\n/*=============================*/\n/*     Asserting functions     */\n/*=============================*/\nvoid assert_eq_iosli(_z_iosli_t *left, _z_iosli_t *right) {\n    printf(\"IOSli -> \");\n    printf(\"Capacity (%zu:%zu), \", left->_capacity, right->_capacity);\n\n    assert(left->_capacity == right->_capacity);\n\n    printf(\"Content (\");\n    for (_z_zint_t i = 0; i < left->_capacity; i++) {\n        uint8_t l = left->_buf[i];\n        uint8_t r = right->_buf[i];\n\n        printf(\"%02x:%02x\", l, r);\n        if (i < left->_capacity - 1) printf(\" \");\n\n        assert(l == r);\n    }\n    printf(\")\");\n}\n\nvoid assert_eq_uint8_array(const _z_slice_t *left, const _z_slice_t *right) {\n    printf(\"Array -> \");\n    printf(\"Length (%zu:%zu), \", left->len, right->len);\n\n    assert(left->len == right->len);\n    printf(\"Content (\");\n    for (size_t i = 0; i < left->len; i++) {\n        uint8_t l = left->start[i];\n        uint8_t r = right->start[i];\n\n        printf(\"%02x:%02x\", l, r);\n        if (i < left->len - 1) printf(\" \");\n\n        assert(l == r);\n    }\n    printf(\")\");\n}\n\nvoid assert_eq_string_array(_z_string_svec_t *left, _z_string_svec_t *right) {\n    printf(\"Array -> \");\n    printf(\"Length (%zu:%zu), \", left->_len, right->_len);\n\n    assert(left->_len == right->_len);\n    printf(\"Content (\");\n    for (size_t i = 0; i < left->_len; i++) {\n        const char *l = _z_string_data(_z_string_svec_get(left, i));\n        const char *r = _z_string_data(_z_string_svec_get(right, i));\n        size_t l_len = _z_string_len(_z_string_svec_get(left, i));\n        size_t r_len = _z_string_len(_z_string_svec_get(right, i));\n\n        printf(\"%.*s:%.*s\", (int)l_len, l, (int)r_len, r);\n        if (i < left->_len - 1) printf(\" \");\n\n        assert(_z_string_equals(_z_string_svec_get(left, i), _z_string_svec_get(right, i)));\n    }\n    printf(\")\");\n}\n\nvoid assert_eq_locator_array(const _z_locator_array_t *left, const _z_locator_array_t *right) {\n    printf(\"Locators -> \");\n    printf(\"Length (%zu:%zu), \", left->_len, right->_len);\n\n    assert(left->_len == right->_len);\n    printf(\"Content (\");\n    for (size_t i = 0; i < left->_len; i++) {\n        const _z_locator_t *l = &left->_val[i];\n        const _z_locator_t *r = &right->_val[i];\n\n        _z_string_t ls = _z_locator_to_string(l);\n        _z_string_t rs = _z_locator_to_string(r);\n\n        printf(\"%.*s:%.*s\", (int)_z_string_len(&ls), _z_string_data(&ls), (int)_z_string_len(&rs), _z_string_data(&rs));\n        if (i < left->_len - 1) printf(\" \");\n\n        _z_string_clear(&ls);\n        _z_string_clear(&rs);\n\n        assert(_z_locator_eq(l, r) == true);\n    }\n    printf(\")\");\n}\n\n/*=============================*/\n/*      Zenoh Core Fields      */\n/*=============================*/\nvoid zint(void) {\n    printf(\"\\n>> ZINT\\n\");\n    _z_wbuf_t wbf = gen_wbuf(9);\n\n    // Initialize\n    _z_zint_t e_z = gen_zint();\n\n    // Encode\n    z_result_t res = _z_zsize_encode(&wbf, e_z);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_zint_t d_z;\n    res = _z_zsize_decode(&d_z, &zbf);\n    assert(res == _Z_RES_OK);\n    assert(e_z == d_z);\n\n    // Free\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*=============================*/\n/*  Zenoh Messages Extensions  */\n/*=============================*/\n/*------------------ UNIT extension ------------------*/\n_z_msg_ext_t gen_unit_extension(void) { return _z_msg_ext_make_unit(_Z_MOCK_EXTENSION_UNIT); }\n\nvoid assert_eq_unit_extension(_z_msg_ext_unit_t *left, _z_msg_ext_unit_t *right) {\n    (void)(left);\n    (void)(right);\n}\n\nvoid unit_extension(void) {\n    printf(\"\\n>> UNIT Extension\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_msg_ext_t ext = gen_unit_extension();\n    assert(_Z_EXT_ENC(ext._header) == _Z_MSG_EXT_ENC_UNIT);\n\n    _z_msg_ext_unit_t e_u = ext._body._unit;\n\n    // Encode\n    z_result_t res = _z_msg_ext_encode_unit(&wbf, &e_u);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_msg_ext_unit_t d_u;\n    res = _z_msg_ext_decode_unit(&d_u, &zbf);\n    assert(res == _Z_RES_OK);\n\n    assert_eq_unit_extension(&e_u, &d_u);\n\n    // Free\n    _z_msg_ext_clear_unit(&d_u);\n    _z_msg_ext_clear(&ext);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ ZINT extension ------------------*/\n_z_msg_ext_t gen_zint_extension(void) {\n    _z_zint_t val = gen_zint();\n    return _z_msg_ext_make_zint(_Z_MOCK_EXTENSION_ZINT, val);\n}\n\nvoid assert_eq_zint_extension(_z_msg_ext_zint_t *left, _z_msg_ext_zint_t *right) {\n    printf(\"    ZINT (%ju:%ju), \", (uintmax_t)left->_val, (uintmax_t)right->_val);\n    assert(left->_val == right->_val);\n}\n\nvoid zint_extension(void) {\n    printf(\"\\n>> ZINT Extension\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_msg_ext_t ext = gen_zint_extension();\n    assert(_Z_EXT_ENC(ext._header) == _Z_MSG_EXT_ENC_ZINT);\n\n    _z_msg_ext_zint_t e_u = ext._body._zint;\n\n    // Encode\n    z_result_t res = _z_msg_ext_encode_zint(&wbf, &e_u);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_msg_ext_zint_t d_u;\n    res = _z_msg_ext_decode_zint(&d_u, &zbf);\n    assert(res == _Z_RES_OK);\n\n    assert_eq_zint_extension(&e_u, &d_u);\n\n    // Free\n    _z_msg_ext_clear_zint(&d_u);\n    _z_msg_ext_clear(&ext);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Unit extension ------------------*/\n_z_msg_ext_t gen_zbuf_extension(void) {\n    _z_slice_t val = gen_slice(gen_uint8());\n    return _z_msg_ext_make_zbuf(_Z_MOCK_EXTENSION_ZBUF, val);\n}\n\nvoid assert_eq_zbuf_extension(_z_msg_ext_zbuf_t *left, _z_msg_ext_zbuf_t *right) {\n    printf(\"    ZBUF (\");\n    assert_eq_uint8_array(&left->_val, &right->_val);\n    printf(\")\");\n}\n\nvoid zbuf_extension(void) {\n    printf(\"\\n>> ZBUF Extension\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_msg_ext_t ext = gen_zbuf_extension();\n    assert(_Z_EXT_ENC(ext._header) == _Z_MSG_EXT_ENC_ZBUF);\n\n    _z_msg_ext_zbuf_t e_u = ext._body._zbuf;\n\n    // Encode\n    z_result_t res = _z_msg_ext_encode_zbuf(&wbf, &e_u);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_msg_ext_zbuf_t d_u;\n    res = _z_msg_ext_decode_zbuf(&d_u, &zbf);\n    assert(res == _Z_RES_OK);\n\n    assert_eq_zbuf_extension(&e_u, &d_u);\n\n    // Free\n    _z_msg_ext_clear_zbuf(&d_u);\n    _z_msg_ext_clear(&ext);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*=============================*/\n/*       Message Fields        */\n/*=============================*/\n/*------------------ Payload field ------------------*/\nvoid assert_eq_slice(const _z_slice_t *left, const _z_slice_t *right) { assert_eq_uint8_array(left, right); }\n\nvoid assert_eq_string(const _z_string_t *left, const _z_string_t *right) {\n    assert(_z_string_len(left) == _z_string_len(right));\n    if (_z_string_len(left) > 0) {\n        assert(_z_string_equals(left, right));\n    }\n}\n\nvoid assert_eq_bytes(const _z_bytes_t *left, const _z_bytes_t *right) {\n    size_t len_left = _z_bytes_len(left);\n    size_t len_right = _z_bytes_len(right);\n    printf(\"Array -> \");\n    printf(\"Length (%zu:%zu), \", len_left, len_right);\n\n    assert(len_left == len_right);\n    printf(\"Content (\");\n    _z_bytes_reader_t reader_left = _z_bytes_get_reader(left);\n    _z_bytes_reader_t reader_right = _z_bytes_get_reader(right);\n    for (size_t i = 0; i < len_left; i++) {\n        uint8_t l = 0, r = 0;\n        _z_bytes_reader_read(&reader_left, &l, 1);\n        _z_bytes_reader_read(&reader_right, &r, 1);\n\n        printf(\"%02x:%02x\", l, r);\n        if (i < len_left - 1) printf(\" \");\n\n        assert(l == r);\n    }\n    printf(\")\");\n}\n\nvoid payload_field(void) {\n    printf(\"\\n>> Payload field\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_bytes_t e_pld = gen_payload(64);\n\n    // Encode\n    z_result_t res = _z_bytes_encode(&wbf, &e_pld);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n\n    _z_bytes_t d_pld = _z_bytes_null();\n    _z_arc_slice_t arcs = {0};\n    res = _z_bytes_decode(&d_pld, &zbf, &arcs);\n    assert(res == _Z_RES_OK);\n    printf(\"   \");\n    assert_eq_bytes(&e_pld, &d_pld);\n    printf(\"\\n\");\n\n    // Free\n    _z_bytes_drop(&e_pld);\n    _z_bytes_drop(&d_pld);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\nvoid assert_eq_encoding(const _z_encoding_t *left, const _z_encoding_t *right) {\n    assert(left->id == right->id);\n    assert_eq_string(&left->schema, &right->schema);\n}\nvoid assert_eq_value(const _z_value_t *left, const _z_value_t *right) {\n    assert_eq_encoding(&left->encoding, &right->encoding);\n    assert_eq_bytes(&left->payload, &right->payload);\n}\n\n/*----------------- Source info field -----------------*/\n_z_source_info_t gen_source_info(void) {\n    return (_z_source_info_t){\n        ._source_id.zid = gen_zid(), ._source_sn = (uint32_t)gen_uint64(), ._source_id.eid = (uint32_t)gen_uint64()};\n}\n\nvoid assert_eq_source_info(const _z_source_info_t *left, const _z_source_info_t *right) {\n    assert(left->_source_sn == right->_source_sn);\n    assert(left->_source_id.eid == right->_source_id.eid);\n    assert(memcmp(left->_source_id.zid.id, right->_source_id.zid.id, 16) == 0);\n}\n\nvoid source_info_field(void) {\n    printf(\"\\n>> Source info field\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_source_info_t e_si = gen_source_info();\n    printf(\"eid: %u, sn: %u\\n\", e_si._source_id.eid, e_si._source_sn);\n\n    // Encode\n    z_result_t res = _z_source_info_encode(&wbf, &e_si);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    print_wbuf(&wbf);\n    print_iosli(&zbf._ios);\n    printf(\"\\n\");\n    _z_source_info_t d_si;\n    res = _z_source_info_decode(&d_si, &zbf);\n    assert(res == _Z_RES_OK);\n    printf(\"eid: %u, sn: %u\\n\", d_si._source_id.eid, d_si._source_sn);\n\n    printf(\"   \");\n    assert_eq_source_info(&e_si, &d_si);\n    printf(\"\\n\");\n\n    // Free\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Timestamp field ------------------*/\n_z_timestamp_t gen_timestamp(void) {\n    _z_timestamp_t ts;\n    ts.valid = true;\n    ts.time = gen_uint64();\n    for (size_t i = 0; i < 16; i++) {\n        ts.id.id[i] = gen_uint8() & 0x7f;  // 0b01111111\n    }\n    return ts;\n}\n\nvoid assert_eq_timestamp(const _z_timestamp_t *left, const _z_timestamp_t *right) {\n    printf(\"Timestamp -> \");\n    printf(\"Time (%llu:%llu), \", (unsigned long long)left->time, (unsigned long long)right->time);\n    assert(left->time == right->time);\n\n    printf(\"ID (\");\n    for (int i = 0; i < 16; i++) {\n        printf(\"%02x:%02x, \", left->id.id[i], right->id.id[i]);\n    }\n    printf(\")\\n\");\n    assert(memcmp(left->id.id, right->id.id, 16) == 0);\n}\n\nvoid timestamp_field(void) {\n    printf(\"\\n>> Timestamp field\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_timestamp_t e_ts = gen_timestamp();\n\n    // Encode\n    z_result_t res = _z_timestamp_encode(&wbf, &e_ts);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    print_wbuf(&wbf);\n    print_iosli(&zbf._ios);\n    printf(\"\\n\");\n    _z_timestamp_t d_ts;\n    res = _z_timestamp_decode(&d_ts, &zbf);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_timestamp(&e_ts, &d_ts);\n    printf(\"\\n\");\n\n    // Free\n    _z_timestamp_clear(&e_ts);\n    _z_timestamp_clear(&d_ts);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ ResKey field ------------------*/\n_z_wireexpr_t gen_wireexpr(void) {\n    _z_wireexpr_t key;\n    key._id = gen_uint16();\n    key._mapping = gen_uint32();\n    bool is_numerical = gen_bool();\n    if (is_numerical == true) {\n        key._suffix = _z_string_null();\n    } else {\n        size_t len = gen_zint() % 16 + 1;\n        key._suffix = _z_string_preallocate(len);\n        char *suffix = gen_str(len);\n        memcpy((char *)_z_string_data(&key._suffix), suffix, len);\n        z_free(suffix);\n    }\n    return key;\n}\n\nvoid assert_eq_keyexpr(const _z_wireexpr_t *left, const _z_wireexpr_t *right) {\n    printf(\"ResKey -> \");\n    printf(\"ID (%u:%u), \", left->_id, right->_id);\n    assert(left->_id == right->_id);\n    assert(_z_wireexpr_has_suffix(left) == _z_wireexpr_has_suffix(right));\n\n    printf(\"Name (\");\n    if (_z_wireexpr_has_suffix(left)) {\n        printf(\"%.*s:%.*s\", (int)_z_string_len(&left->_suffix), _z_string_data(&left->_suffix),\n               (int)_z_string_len(&right->_suffix), _z_string_data(&right->_suffix));\n        assert(_z_string_equals(&left->_suffix, &right->_suffix) == true);\n    } else {\n        printf(\"NULL:NULL\");\n    }\n    printf(\")\");\n}\n\nvoid keyexpr_field(void) {\n    printf(\"\\n>> ResKey field\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_wireexpr_t e_rk = gen_wireexpr();\n\n    // Encode\n    uint8_t header = (_z_wireexpr_has_suffix(&e_rk)) ? _Z_FLAG_Z_K : 0;\n    z_result_t res = _z_wireexpr_encode(&wbf, _Z_HAS_FLAG(header, _Z_FLAG_Z_K), &e_rk);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_wireexpr_t d_rk;\n    res = _z_wireexpr_decode(&d_rk, &zbf, _Z_HAS_FLAG(header, _Z_FLAG_Z_K), false, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_keyexpr(&e_rk, &d_rk);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_rk);\n    _z_wireexpr_clear(&d_rk);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*=============================*/\n/*      Declaration Fields     */\n/*=============================*/\n/*------------------ Resource declaration ------------------*/\n_z_decl_kexpr_t gen_resource_declaration(void) {\n    return (_z_decl_kexpr_t){._id = gen_uint16(), ._keyexpr = gen_wireexpr()};\n}\n\nvoid assert_eq_resource_declaration(const _z_decl_kexpr_t *left, const _z_decl_kexpr_t *right) {\n    printf(\"RID (%u:%u), \", left->_id, right->_id);\n    assert(left->_id == right->_id);\n    assert_eq_keyexpr(&left->_keyexpr, &right->_keyexpr);\n}\n\nvoid resource_declaration(void) {\n    printf(\"\\n>> Resource declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_decl_kexpr_t e_rd = gen_resource_declaration();\n\n    // Encode\n    z_result_t res = _z_decl_kexpr_encode(&wbf, &e_rd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_decl_kexpr_t d_rd;\n    uint8_t e_hdr;\n    _z_uint8_decode(&e_hdr, &zbf);\n    res = _z_decl_kexpr_decode(&d_rd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_resource_declaration(&e_rd, &d_rd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_rd._keyexpr);\n    _z_wireexpr_clear(&d_rd._keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Subscriber declaration ------------------*/\n_z_decl_subscriber_t gen_subscriber_declaration(void) {\n    _z_decl_subscriber_t e_sd = {._keyexpr = gen_wireexpr(), ._id = (uint32_t)gen_uint64()};\n    return e_sd;\n}\n\nvoid assert_eq_subscriber_declaration(const _z_decl_subscriber_t *left, const _z_decl_subscriber_t *right) {\n    assert_eq_keyexpr(&left->_keyexpr, &right->_keyexpr);\n    assert(left->_id == right->_id);\n}\n\nvoid subscriber_declaration(void) {\n    printf(\"\\n>> Subscriber declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_decl_subscriber_t e_sd = gen_subscriber_declaration();\n    // Encode\n    z_result_t res = _z_decl_subscriber_encode(&wbf, &e_sd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_decl_subscriber_t d_sd;\n    uint8_t e_hdr;\n    _z_uint8_decode(&e_hdr, &zbf);\n    res = _z_decl_subscriber_decode(&d_sd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_subscriber_declaration(&e_sd, &d_sd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_sd._keyexpr);\n    _z_wireexpr_clear(&d_sd._keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Queryable declaration ------------------*/\n_z_decl_queryable_t gen_queryable_declaration(void) {\n    _z_decl_queryable_t e_qd = {._keyexpr = gen_wireexpr(),\n                                ._id = (uint32_t)gen_uint64(),\n                                ._ext_queryable_info = {._complete = gen_uint8(), ._distance = gen_uint16()}};\n\n    return e_qd;\n}\n\nvoid assert_eq_queryable_declaration(const _z_decl_queryable_t *left, const _z_decl_queryable_t *right) {\n    assert_eq_keyexpr(&left->_keyexpr, &right->_keyexpr);\n\n    printf(\"Complete (%u:%u), \", left->_ext_queryable_info._complete, right->_ext_queryable_info._complete);\n    assert(left->_ext_queryable_info._complete == right->_ext_queryable_info._complete);\n    printf(\"Distance (%u:%u), \", left->_ext_queryable_info._distance, right->_ext_queryable_info._distance);\n    assert(left->_ext_queryable_info._distance == right->_ext_queryable_info._distance);\n}\n\nvoid queryable_declaration(void) {\n    printf(\"\\n>> Queryable declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_decl_queryable_t e_qd = gen_queryable_declaration();\n\n    // Encode\n    z_result_t res = _z_decl_queryable_encode(&wbf, &e_qd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_decl_queryable_t d_qd;\n    uint8_t e_hdr = 0;\n    _z_uint8_decode(&e_hdr, &zbf);\n    res = _z_decl_queryable_decode(&d_qd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_queryable_declaration(&e_qd, &d_qd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_qd._keyexpr);\n    _z_wireexpr_clear(&d_qd._keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Token declaration ------------------*/\n_z_decl_token_t gen_token_declaration(void) {\n    _z_decl_token_t e_qd = {._keyexpr = gen_wireexpr(), ._id = (uint32_t)gen_uint64()};\n\n    return e_qd;\n}\n\nvoid assert_eq_token_declaration(const _z_decl_token_t *left, const _z_decl_token_t *right) {\n    assert_eq_keyexpr(&left->_keyexpr, &right->_keyexpr);\n    assert(left->_id == right->_id);\n}\n\nvoid token_declaration(void) {\n    printf(\"\\n>> Queryable declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_decl_token_t e_qd = gen_token_declaration();\n\n    // Encode\n    int8_t res = _z_decl_token_encode(&wbf, &e_qd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_decl_token_t d_qd;\n    uint8_t e_hdr = 0;\n    _z_uint8_decode(&e_hdr, &zbf);\n    res = _z_decl_token_decode(&d_qd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_token_declaration(&e_qd, &d_qd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_qd._keyexpr);\n    _z_wireexpr_clear(&d_qd._keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Forget Resource declaration ------------------*/\n_z_undecl_kexpr_t gen_forget_resource_declaration(void) {\n    _z_undecl_kexpr_t e_frd;\n\n    e_frd._id = gen_uint16();\n\n    return e_frd;\n}\n\nvoid assert_eq_forget_resource_declaration(const _z_undecl_kexpr_t *left, const _z_undecl_kexpr_t *right) {\n    printf(\"RID (%u:%u)\", left->_id, right->_id);\n    assert(left->_id == right->_id);\n}\n\nvoid forget_resource_declaration(void) {\n    printf(\"\\n>> Forget resource declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_undecl_kexpr_t e_frd = gen_forget_resource_declaration();\n\n    // Encode\n    z_result_t res = _z_undecl_kexpr_encode(&wbf, &e_frd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_undecl_kexpr_t d_frd;\n    uint8_t hdr;\n    _z_uint8_decode(&hdr, &zbf);\n    res = _z_undecl_kexpr_decode(&d_frd, &zbf, hdr);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_forget_resource_declaration(&e_frd, &d_frd);\n    printf(\"\\n\");\n\n    // Free\n    // NOTE: forget_res_decl does not involve any heap allocation\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Forget Subscriber declaration ------------------*/\n_z_undecl_subscriber_t gen_forget_subscriber_declaration(void) {\n    _z_undecl_subscriber_t e_fsd = {._ext_keyexpr = gen_wireexpr(), ._id = (uint32_t)gen_uint64()};\n    return e_fsd;\n}\n\nvoid assert_eq_forget_subscriber_declaration(const _z_undecl_subscriber_t *left, const _z_undecl_subscriber_t *right) {\n    assert_eq_keyexpr(&left->_ext_keyexpr, &right->_ext_keyexpr);\n    assert(left->_id == right->_id);\n}\n\nvoid forget_subscriber_declaration(void) {\n    printf(\"\\n>> Forget subscriber declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_undecl_subscriber_t e_fsd = gen_forget_subscriber_declaration();\n\n    // Encode\n    z_result_t res = _z_undecl_subscriber_encode(&wbf, &e_fsd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_undecl_subscriber_t d_fsd = {._id = 0, ._ext_keyexpr = {0}};\n    uint8_t e_hdr = 0;\n    _z_uint8_decode(&e_hdr, &zbf);\n    res = _z_undecl_subscriber_decode(&d_fsd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n    printf(\"   \");\n    assert_eq_forget_subscriber_declaration(&e_fsd, &d_fsd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_fsd._ext_keyexpr);\n    _z_wireexpr_clear(&d_fsd._ext_keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Forget Queryable declaration ------------------*/\n_z_undecl_queryable_t gen_forget_queryable_declaration(void) {\n    _z_undecl_queryable_t e_fqd = {._ext_keyexpr = gen_wireexpr(), ._id = (uint32_t)gen_zint()};\n    return e_fqd;\n}\n\nvoid assert_eq_forget_queryable_declaration(const _z_undecl_queryable_t *left, const _z_undecl_queryable_t *right) {\n    assert_eq_keyexpr(&left->_ext_keyexpr, &right->_ext_keyexpr);\n    assert(left->_id == right->_id);\n}\n\nvoid forget_queryable_declaration(void) {\n    printf(\"\\n>> Forget queryable declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_undecl_queryable_t e_fqd = gen_forget_queryable_declaration();\n\n    // Encode\n    z_result_t res = _z_undecl_queryable_encode(&wbf, &e_fqd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t e_hdr = 0;\n    _z_uint8_decode(&e_hdr, &zbf);\n    _z_undecl_queryable_t d_fqd = {._ext_keyexpr = _z_wireexpr_null()};\n    res = _z_undecl_queryable_decode(&d_fqd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_forget_queryable_declaration(&e_fqd, &d_fqd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_fqd._ext_keyexpr);\n    _z_wireexpr_clear(&d_fqd._ext_keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Forget Token declaration ------------------*/\n_z_undecl_token_t gen_forget_token_declaration(void) {\n    _z_undecl_token_t e_fqd = {._ext_keyexpr = gen_wireexpr(), ._id = (uint32_t)gen_zint()};\n    return e_fqd;\n}\n\nvoid assert_eq_forget_token_declaration(const _z_undecl_token_t *left, const _z_undecl_token_t *right) {\n    assert_eq_keyexpr(&left->_ext_keyexpr, &right->_ext_keyexpr);\n    assert(left->_id == right->_id);\n}\n\nvoid forget_token_declaration(void) {\n    printf(\"\\n>> Forget token declaration\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_undecl_token_t e_fqd = gen_forget_token_declaration();\n\n    // Encode\n    int8_t res = _z_undecl_token_encode(&wbf, &e_fqd);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t e_hdr = 0;\n    _z_uint8_decode(&e_hdr, &zbf);\n    _z_undecl_token_t d_fqd = {._ext_keyexpr = _z_wireexpr_null()};\n    res = _z_undecl_token_decode(&d_fqd, &zbf, e_hdr, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    printf(\"   \");\n    assert_eq_forget_token_declaration(&e_fqd, &d_fqd);\n    printf(\"\\n\");\n\n    // Free\n    _z_wireexpr_clear(&e_fqd._ext_keyexpr);\n    _z_wireexpr_clear(&d_fqd._ext_keyexpr);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Declaration ------------------*/\n_z_declaration_t gen_declaration(void) {\n    uint8_t decl[] = {_Z_DECL_KEXPR,     _Z_UNDECL_KEXPR,     _Z_DECL_SUBSCRIBER, _Z_UNDECL_SUBSCRIBER,\n                      _Z_DECL_QUERYABLE, _Z_UNDECL_QUERYABLE, _Z_DECL_TOKEN,      _Z_UNDECL_TOKEN};\n\n    _z_declaration_t d;\n    d._tag = decl[gen_uint8() % (sizeof(decl) / sizeof(uint8_t))];\n\n    switch (d._tag) {\n        case _Z_DECL_KEXPR: {\n            d._body._decl_kexpr = gen_resource_declaration();\n        } break;\n        case _Z_UNDECL_KEXPR: {\n            d._body._undecl_kexpr = gen_forget_resource_declaration();\n        } break;\n        case _Z_DECL_SUBSCRIBER: {\n            d._body._decl_subscriber = gen_subscriber_declaration();\n        } break;\n        case _Z_UNDECL_SUBSCRIBER: {\n            d._body._undecl_subscriber = gen_forget_subscriber_declaration();\n        } break;\n        case _Z_DECL_QUERYABLE: {\n            d._body._decl_queryable = gen_queryable_declaration();\n        } break;\n        case _Z_UNDECL_QUERYABLE: {\n            d._body._undecl_queryable = gen_forget_queryable_declaration();\n        } break;\n        case _Z_DECL_TOKEN: {\n            d._body._decl_token = gen_token_declaration();\n        } break;\n        case _Z_UNDECL_TOKEN: {\n            d._body._undecl_token = gen_forget_token_declaration();\n        } break;\n        default:\n            assert(false);\n    }\n\n    return d;\n}\n\nvoid assert_eq_declaration(const _z_declaration_t *left, const _z_declaration_t *right) {\n    printf(\"Declaration -> \");\n    printf(\"Header (%x:%x), \", left->_tag, right->_tag);\n    assert(left->_tag == right->_tag);\n\n    switch (left->_tag) {\n        case _Z_DECL_KEXPR:\n            assert_eq_resource_declaration(&left->_body._decl_kexpr, &right->_body._decl_kexpr);\n            break;\n        case _Z_DECL_SUBSCRIBER:\n            assert_eq_subscriber_declaration(&left->_body._decl_subscriber, &right->_body._decl_subscriber);\n            break;\n        case _Z_DECL_QUERYABLE:\n            assert_eq_queryable_declaration(&left->_body._decl_queryable, &right->_body._decl_queryable);\n            break;\n        case _Z_DECL_TOKEN:\n            assert_eq_token_declaration(&left->_body._decl_token, &right->_body._decl_token);\n            break;\n        case _Z_UNDECL_KEXPR:\n            assert_eq_forget_resource_declaration(&left->_body._undecl_kexpr, &right->_body._undecl_kexpr);\n            break;\n        case _Z_UNDECL_SUBSCRIBER:\n            assert_eq_forget_subscriber_declaration(&left->_body._undecl_subscriber, &right->_body._undecl_subscriber);\n            break;\n        case _Z_UNDECL_QUERYABLE:\n            assert_eq_forget_queryable_declaration(&left->_body._undecl_queryable, &right->_body._undecl_queryable);\n            break;\n        case _Z_UNDECL_TOKEN:\n            assert_eq_forget_token_declaration(&left->_body._undecl_token, &right->_body._undecl_token);\n            break;\n        default:\n            assert(false);\n    }\n}\n\n/*------------------ Declare message ------------------*/\n_z_network_message_t gen_declare_message(void) {\n    _z_declaration_t declaration = gen_declaration();\n    bool has_id = gen_bool();\n    uint32_t id = gen_uint32();\n    _z_network_message_t n_msg;\n    _z_n_msg_make_declare(&n_msg, declaration, has_id ? _z_optional_id_make_some(id) : _z_optional_id_make_none());\n    return n_msg;\n}\n\nvoid assert_eq_declare_message(_z_n_msg_declare_t *left, _z_n_msg_declare_t *right) {\n    printf(\"   \");\n    assert(left->_interest_id.has_value == right->_interest_id.has_value);\n    if (left->_interest_id.has_value) {\n        assert(left->_interest_id.value == right->_interest_id.value);\n    }\n    assert_eq_declaration(&left->_decl, &right->_decl);\n    printf(\"\\n\");\n}\n\nvoid declare_message(void) {\n    printf(\"\\n>> Declare message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_network_message_t n_msg = gen_declare_message();\n\n    // Encode\n    z_result_t res = _z_network_message_encode(&wbf, &n_msg);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_network_message_t d_dcl = {0};\n    _z_arc_slice_t arcs = {0};\n    res = _z_network_message_decode(&d_dcl, &zbf, &arcs, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(res == _Z_RES_OK);\n\n    assert_eq_declare_message(&n_msg._body._declare, &d_dcl._body._declare);\n\n    // Free\n    _z_n_msg_clear(&d_dcl);\n    _z_n_msg_clear(&n_msg);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*------------------ Interest ------------------*/\n#define _Z_MSGCODEC_INTEREST_BASE_FLAGS_MASK 0x8f  // Used to remove R, C & F flags\n\n_z_interest_t gen_interest(void) {\n    _z_interest_t i = {0};\n    bool is_final = gen_bool();  // To determine if interest is final or not\n    // Generate interest id\n    i._id = gen_uint32();\n    printf(\"Gen interest %d\\n\", is_final);\n    // Add regular interest data\n    if (!is_final) {\n        // Generate base flags\n        i.flags = gen_uint8() & _Z_MSGCODEC_INTEREST_BASE_FLAGS_MASK;\n        // Generate test cases\n        bool is_restricted = gen_bool();\n        uint8_t cf_type = gen_uint8() % 3;  // Flags must be c, f or cf\n        switch (cf_type) {\n            default:\n            case 0:\n                i.flags |= _Z_INTEREST_FLAG_CURRENT;\n                break;\n            case 1:\n                i.flags |= _Z_INTEREST_FLAG_FUTURE;\n                break;\n            case 2:\n                i.flags |= (_Z_INTEREST_FLAG_CURRENT | _Z_INTEREST_FLAG_FUTURE);\n                break;\n        }\n        if (is_restricted) {\n            i.flags |= _Z_INTEREST_FLAG_RESTRICTED;\n            // Generate ke\n            i._keyexpr = gen_wireexpr();\n        }\n    };\n    return i;\n}\n\n_z_network_message_t gen_interest_message(void) {\n    _z_interest_t interest = gen_interest();\n    _z_network_message_t msg;\n    _z_n_msg_make_interest(&msg, interest);\n    return msg;\n}\n\nvoid assert_eq_interest(const _z_interest_t *left, const _z_interest_t *right) {\n    printf(\"Interest: 0x%x, 0x%x, %u, %u\\n\", left->flags, right->flags, left->_id, right->_id);\n    printf(\"Interest ke: %d, %d, %d, %d, %.*s, %.*s\\n\", left->_keyexpr._id, right->_keyexpr._id,\n           (unsigned int)left->_keyexpr._mapping, (unsigned int)right->_keyexpr._mapping,\n           (int)_z_string_len(&left->_keyexpr._suffix), _z_string_data(&left->_keyexpr._suffix),\n           (int)_z_string_len(&right->_keyexpr._suffix), _z_string_data(&right->_keyexpr._suffix));\n    assert(left->flags == right->flags);\n    assert(left->_id == right->_id);\n    assert_eq_keyexpr(&left->_keyexpr, &right->_keyexpr);\n}\nvoid interest_message(void) {\n    printf(\"\\n>> Interest message\\n\");\n    // Init\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_network_message_t expected = gen_interest_message();\n    // Encode\n    assert(_z_n_interest_encode(&wbf, &expected._body._interest) == _Z_RES_OK);\n    // Decode\n    _z_n_msg_interest_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    assert(_z_n_interest_decode(&decoded, &zbf, header, _Z_KEYEXPR_MAPPING_LOCAL) == _Z_RES_OK);\n    // Check\n    assert_eq_interest(&expected._body._interest._interest, &decoded._interest);\n    // Clean-up\n    _z_n_msg_interest_clear(&decoded);\n    _z_n_msg_interest_clear(&expected._body._interest);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n/*=============================*/\n/*        Zenoh Messages       */\n/*=============================*/\n/*------------------ Push message ------------------*/\n_z_push_body_t gen_push_body(void) {\n    bool isput = gen_bool();\n    _z_timestamp_t ts = gen_bool() ? gen_timestamp() : _z_timestamp_null();\n    _z_source_info_t sinfo = gen_bool() ? gen_source_info() : _z_source_info_null();\n    _z_m_push_commons_t commons = {._source_info = sinfo, ._timestamp = ts};\n    if (isput) {\n        return (_z_push_body_t){._is_put = true,\n                                ._body._put = {\n                                    ._commons = commons,\n                                    ._payload = gen_bytes(64),\n                                    ._encoding = gen_encoding(),\n                                }};\n    } else {\n        return (_z_push_body_t){._is_put = false, ._body._del = {._commons = commons}};\n    }\n}\n\nvoid assert_eq_push_body(const _z_push_body_t *left, const _z_push_body_t *right) {\n    assert(left->_is_put == right->_is_put);\n    if (left->_is_put) {\n        assert_eq_bytes(&left->_body._put._payload, &right->_body._put._payload);\n        assert_eq_encoding(&left->_body._put._encoding, &right->_body._put._encoding);\n        assert_eq_timestamp(&left->_body._put._commons._timestamp, &right->_body._put._commons._timestamp);\n        assert_eq_source_info(&left->_body._put._commons._source_info, &right->_body._put._commons._source_info);\n    } else {\n        assert_eq_timestamp(&left->_body._del._commons._timestamp, &right->_body._del._commons._timestamp);\n        assert_eq_source_info(&left->_body._del._commons._source_info, &right->_body._del._commons._source_info);\n    }\n}\n\nvoid push_body_message(void) {\n    printf(\"\\n>> Put/Del message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    // Initialize\n    _z_push_body_t e_da = gen_push_body();\n\n    // Encode\n    z_result_t res = _z_push_body_encode(&wbf, &e_da);\n    assert(res == _Z_RES_OK);\n    (void)(res);\n\n    // Decode\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    _z_push_body_t d_da = {0};\n    _z_arc_slice_t arcs = {0};\n    uint8_t header = _z_zbuf_read(&zbf);\n    res = _z_push_body_decode(&d_da, &zbf, header, &arcs);\n    assert(res == _Z_RES_OK);\n\n    assert_eq_push_body(&e_da, &d_da);\n\n    // Free\n    _z_push_body_clear(&d_da);\n    _z_push_body_clear(&e_da);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_msg_query_t gen_query(void) {\n    return (_z_msg_query_t){\n        ._consolidation = (gen_uint8() % 4) - 1,\n        ._ext_info = gen_source_info(),\n        ._parameters = gen_slice(16),\n        ._ext_value = gen_bool() ? gen_value() : _z_value_null(),\n    };\n}\n\n_z_msg_query_t gen_query_anyke(const char *parameters, bool _anyke) {\n    return (_z_msg_query_t){\n        ._consolidation = (gen_uint8() % 4) - 1,\n        ._ext_info = gen_source_info(),\n        ._parameters = _z_slice_from_buf_custom_deleter(\n            // SAFETY: only use null-terminated parameters in tests.\n            // Flawfinder: ignore [CWE-126]\n            (const uint8_t *)parameters, parameters == NULL ? 0 : strlen(parameters), _z_delete_context_static()),\n        ._implicit_anyke = _anyke,\n        ._ext_value = gen_bool() ? gen_value() : _z_value_null(),\n    };\n}\n\nvoid assert_eq_query(const _z_msg_query_t *left, const _z_msg_query_t *right) {\n    assert(left->_consolidation == right->_consolidation);\n    assert_eq_source_info(&left->_ext_info, &right->_ext_info);\n    assert_eq_slice(&left->_parameters, &right->_parameters);\n    assert_eq_value(&left->_ext_value, &right->_ext_value);\n}\n\nvoid query_message(void) {\n    printf(\"\\n>> Query message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_msg_query_t expected = gen_query();\n    assert(_z_query_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_msg_query_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    z_result_t res = _z_query_decode(&decoded, &zbf, header);\n    assert(_Z_RES_OK == res);\n    assert_eq_query(&expected, &decoded);\n    _z_msg_query_clear(&decoded);\n    _z_msg_query_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\nvoid query_message_anyke(void) {\n    printf(\"\\n>> Query message _anyke\\n\");\n    const char *params[] = {NULL, \"\", \"param1\", \"param2;_anyke\", \"param3;_anyke;param4\", \"_anyke;param5\"};\n    for (size_t i = 0; i < sizeof(params) / sizeof(char *); i++) {\n        for (size_t j = 0; j < 2; j++) {\n            _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n            bool anyke = j == 0;\n            _z_msg_query_t expected = gen_query_anyke(params[i], anyke);\n            assert(_z_query_encode(&wbf, &expected) == _Z_RES_OK);\n            _z_msg_query_t decoded = {0};\n            _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n            uint8_t header = _z_zbuf_read(&zbf);\n            z_result_t res = _z_query_decode(&decoded, &zbf, header);\n            assert(_Z_RES_OK == res);\n            if (anyke) {\n                // SAFETY: only use null-terminated parameters in tests.\n                // Flawfinder: ignore [CWE-126]\n                size_t params_len = params[i] == NULL ? 0 : strlen(params[i]);\n                assert(!decoded._implicit_anyke);  // implicit _anyke is always false upon decoding, since _anyke should\n                                                   // be explicitly present in parameters\n                assert(_z_parameters_has_anyke((const char *)decoded._parameters.start, decoded._parameters.len));\n                assert(params_len <= decoded._parameters.len);\n                if (params_len > 0) {\n                    assert(strncmp(params[i], (const char *)decoded._parameters.start, params_len) == 0);\n                }\n            } else {\n                assert_eq_query(&expected, &decoded);\n            }\n            _z_msg_query_clear(&decoded);\n            _z_msg_query_clear(&expected);\n            _z_zbuf_clear(&zbf);\n            _z_wbuf_clear(&wbf);\n        }\n    }\n}\n\n_z_msg_err_t gen_err(void) {\n    size_t len = 1 + gen_uint8();\n    return (_z_msg_err_t){\n        ._encoding = gen_encoding(),\n        ._ext_source_info = gen_bool() ? gen_source_info() : _z_source_info_null(),\n        ._payload = gen_payload(len),  // Hangs if 0\n    };\n}\n\nvoid assert_eq_err(const _z_msg_err_t *left, const _z_msg_err_t *right) {\n    assert_eq_encoding(&left->_encoding, &right->_encoding);\n    assert_eq_source_info(&left->_ext_source_info, &right->_ext_source_info);\n    assert_eq_bytes(&left->_payload, &right->_payload);\n}\n\nvoid err_message(void) {\n    printf(\"\\n>> Err message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_msg_err_t expected = gen_err();\n    assert(_z_err_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_msg_err_t decoded = {0};\n    _z_arc_slice_t arcs = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    assert(_Z_RES_OK == _z_err_decode(&decoded, &zbf, header, &arcs));\n    assert_eq_err(&expected, &decoded);\n    _z_msg_err_clear(&decoded);\n    _z_msg_err_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_msg_reply_t gen_reply(void) {\n    return (_z_msg_reply_t){\n        ._consolidation = (gen_uint8() % 4) - 1,\n        ._body = gen_push_body(),\n    };\n}\n\nvoid assert_eq_reply(const _z_msg_reply_t *left, const _z_msg_reply_t *right) {\n    assert(left->_consolidation == right->_consolidation);\n    assert_eq_push_body(&left->_body, &right->_body);\n}\n\nvoid reply_message(void) {\n    printf(\"\\n>> Reply message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_msg_reply_t expected = gen_reply();\n    assert(_z_reply_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_msg_reply_t decoded = {0};\n    _z_arc_slice_t arcs = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    assert(_Z_RES_OK == _z_reply_decode(&decoded, &zbf, header, &arcs));\n    assert_eq_reply(&expected, &decoded);\n    _z_msg_reply_clear(&decoded);\n    _z_msg_reply_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_n_msg_push_t gen_push(void) {\n    return (_z_n_msg_push_t){\n        ._body = gen_push_body(),\n        ._key = gen_wireexpr(),\n        ._qos = _z_n_qos_make(gen_bool(), gen_bool(), gen_uint8() % 8),\n        ._timestamp = gen_timestamp(),\n    };\n}\n\nstatic _z_network_message_t gen_push_message(void) {\n    return (_z_network_message_t){\n        ._tag = _Z_N_PUSH,\n        ._body._push = gen_push(),\n    };\n}\n\nvoid assert_eq_push(const _z_n_msg_push_t *left, const _z_n_msg_push_t *right) {\n    assert_eq_timestamp(&left->_timestamp, &right->_timestamp);\n    assert_eq_keyexpr(&left->_key, &right->_key);\n    assert(left->_qos._val == right->_qos._val);\n    assert_eq_push_body(&left->_body, &right->_body);\n}\n\nvoid push_message(void) {\n    printf(\"\\n>> Push message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_n_msg_push_t expected = gen_push();\n    assert(_z_push_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_n_msg_push_t decoded = {0};\n    _z_arc_slice_t arcs = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    assert(_Z_RES_OK == _z_push_decode(&decoded, &zbf, header, &arcs, _Z_KEYEXPR_MAPPING_LOCAL));\n    assert_eq_push(&expected, &decoded);\n    _z_n_msg_push_clear(&decoded);\n    _z_n_msg_push_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_n_msg_request_t gen_request(void) {\n    _z_qos_t qos_default = {._val = 5};\n    _z_n_msg_request_t request = {\n        ._rid = gen_zint(),\n        ._key = gen_wireexpr(),\n        ._ext_qos = gen_bool() ? _z_n_qos_make(gen_bool(), gen_bool(), gen_uint8() % 8) : qos_default,\n        ._ext_timestamp = gen_bool() ? gen_timestamp() : _z_timestamp_null(),\n        ._ext_target = gen_uint8() % 3,\n        ._ext_budget = gen_bool() ? (uint32_t)gen_uint64() : 0,\n        ._ext_timeout_ms = gen_bool() ? gen_uint64() : 0,\n    };\n    switch (gen_uint8() % 2) {\n        case 0: {\n            request._tag = _Z_REQUEST_QUERY;\n            request._body._query = gen_query();\n        } break;\n        case 1:\n        default: {\n            _z_push_body_t body = gen_push_body();\n            if (body._is_put) {\n                request._tag = _Z_REQUEST_PUT;\n                request._body._put = body._body._put;\n            } else {\n                request._tag = _Z_REQUEST_DEL;\n                request._body._del = body._body._del;\n            }\n        }\n    }\n    return request;\n}\n\nstatic _z_network_message_t gen_request_message(void) {\n    return (_z_network_message_t){\n        ._tag = _Z_N_REQUEST,\n        ._body._request = gen_request(),\n    };\n}\n\nvoid assert_eq_request(const _z_n_msg_request_t *left, const _z_n_msg_request_t *right) {\n    assert(left->_rid == right->_rid);\n    assert_eq_keyexpr(&left->_key, &right->_key);\n    assert(left->_ext_qos._val == right->_ext_qos._val);\n    assert_eq_timestamp(&left->_ext_timestamp, &right->_ext_timestamp);\n    assert(left->_ext_target == right->_ext_target);\n    assert(left->_ext_budget == right->_ext_budget);\n    assert(left->_ext_timeout_ms == right->_ext_timeout_ms);\n    assert(left->_tag == right->_tag);\n    switch (left->_tag) {\n        case _Z_REQUEST_QUERY: {\n            assert_eq_query(&left->_body._query, &right->_body._query);\n        } break;\n        case _Z_REQUEST_PUT: {\n            assert_eq_push_body(&(_z_push_body_t){._is_put = true, ._body._put = left->_body._put},\n                                &(_z_push_body_t){._is_put = true, ._body._put = right->_body._put});\n        } break;\n        case _Z_REQUEST_DEL: {\n            assert_eq_push_body(&(_z_push_body_t){._is_put = false, ._body._del = left->_body._del},\n                                &(_z_push_body_t){._is_put = false, ._body._del = right->_body._del});\n        } break;\n    }\n}\n\nvoid request_message(void) {\n    printf(\"\\n>> Request message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_n_msg_request_t expected = gen_request();\n    assert(_z_request_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_n_msg_request_t decoded = {0};\n    _z_arc_slice_t arcs = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    z_result_t ret = _z_request_decode(&decoded, &zbf, header, &arcs, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(_Z_RES_OK == ret);\n    assert_eq_request(&expected, &decoded);\n    _z_n_msg_request_clear(&decoded);\n    _z_n_msg_request_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_n_msg_response_t gen_response(void) {\n    _z_n_msg_response_t ret = {\n        ._key = gen_wireexpr(),\n        ._request_id = gen_zint(),\n        ._ext_qos = _z_n_qos_make(gen_bool(), gen_bool(), gen_uint8() % 8),\n        ._ext_timestamp = gen_bool() ? gen_timestamp() : _z_timestamp_null(),\n        ._ext_responder = {._eid = gen_uint16(), ._zid = gen_zid()},\n    };\n    switch (gen_uint32() % 2) {\n        case 0: {\n            ret._tag = _Z_RESPONSE_BODY_ERR;\n            ret._body._err = gen_err();\n        } break;\n        case 1:\n        default: {\n            ret._tag = _Z_RESPONSE_BODY_REPLY;\n            ret._body._reply = gen_reply();\n        } break;\n    }\n    return ret;\n}\n\nstatic _z_network_message_t gen_response_message(void) {\n    return (_z_network_message_t){\n        ._tag = _Z_N_RESPONSE,\n        ._body._response = gen_response(),\n    };\n}\n\nvoid assert_eq_response(const _z_n_msg_response_t *left, const _z_n_msg_response_t *right) {\n    assert_eq_keyexpr(&left->_key, &right->_key);\n    assert_eq_timestamp(&left->_ext_timestamp, &right->_ext_timestamp);\n    assert(left->_request_id == right->_request_id);\n    assert(left->_ext_qos._val == right->_ext_qos._val);\n    assert(left->_ext_responder._eid == right->_ext_responder._eid);\n    assert(memcmp(left->_ext_responder._zid.id, right->_ext_responder._zid.id, 16) == 0);\n    assert(left->_tag == right->_tag);\n    switch (left->_tag) {\n        case _Z_RESPONSE_BODY_REPLY: {\n            assert_eq_reply(&left->_body._reply, &right->_body._reply);\n        } break;\n        case _Z_RESPONSE_BODY_ERR: {\n            assert_eq_err(&left->_body._err, &right->_body._err);\n\n        } break;\n    }\n}\n\nvoid response_message(void) {\n    printf(\"\\n>> Response message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_n_msg_response_t expected = gen_response();\n    assert(_z_response_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_n_msg_response_t decoded = {0};\n    _z_arc_slice_t arcs = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    z_result_t ret = _z_response_decode(&decoded, &zbf, header, &arcs, _Z_KEYEXPR_MAPPING_LOCAL);\n    assert(_Z_RES_OK == ret);\n    assert_eq_response(&expected, &decoded);\n    _z_n_msg_response_clear(&decoded);\n    _z_n_msg_response_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_n_msg_response_final_t gen_response_final(void) { return (_z_n_msg_response_final_t){._request_id = gen_zint()}; }\n\nstatic _z_network_message_t gen_response_final_message(void) {\n    return (_z_network_message_t){\n        ._tag = _Z_N_RESPONSE_FINAL,\n        ._body._response_final = gen_response_final(),\n    };\n}\n\nvoid assert_eq_response_final(const _z_n_msg_response_final_t *left, const _z_n_msg_response_final_t *right) {\n    assert(left->_request_id == right->_request_id);\n}\nvoid response_final_message(void) {\n    printf(\"\\n>> Request Final message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_n_msg_response_final_t expected = gen_response_final();\n    assert(_z_response_final_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_n_msg_response_final_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    z_result_t ret = _z_response_final_decode(&decoded, &zbf, header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_response_final(&expected, &decoded);\n    _z_n_msg_response_final_clear(&decoded);\n    _z_n_msg_response_final_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_n_msg_oam_t gen_oam(void) {\n    _z_qos_t qos_default = {._val = 5};\n    _z_n_msg_oam_t oam = {\n        ._id = gen_uint16(),\n        ._ext_timestamp = gen_bool() ? gen_timestamp() : _z_timestamp_null(),\n        ._ext_qos = gen_bool() ? _z_n_qos_make(gen_bool(), gen_bool(), gen_uint8() % 8) : qos_default,\n    };\n    switch (gen_uint8() % 3) {\n        case 0: {\n            oam._enc = _Z_OAM_BODY_UNIT;\n        } break;\n        case 1: {\n            oam._enc = _Z_OAM_BODY_ZINT;\n            oam._body._zint._val = gen_zint();\n        } break;\n        case 2:\n        default: {\n            oam._enc = _Z_OAM_BODY_ZBUF;\n            oam._body._zbuf._val = gen_slice(gen_uint8());\n        } break;\n    }\n    return oam;\n}\nvoid assert_eq_oam(const _z_n_msg_oam_t *left, const _z_n_msg_oam_t *right) {\n    assert(left->_id == right->_id);\n    assert_eq_timestamp(&left->_ext_timestamp, &right->_ext_timestamp);\n    assert(left->_ext_qos._val == right->_ext_qos._val);\n    assert(left->_enc == right->_enc);\n    switch (left->_enc) {\n        case _Z_OAM_BODY_UNIT:\n            break;\n            ;\n        case _Z_OAM_BODY_ZINT:\n            assert(left->_body._zint._val == right->_body._zint._val);\n            break;\n        case _Z_OAM_BODY_ZBUF:\n            assert_eq_slice(&left->_body._zbuf._val, &right->_body._zbuf._val);\n            break;\n        default:\n            assert(false);\n    }\n}\nvoid oam_message(void) {\n    printf(\"\\n>> OAM message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_n_msg_oam_t expected = gen_oam();\n    assert(_z_oam_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_n_msg_oam_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    uint8_t header = _z_zbuf_read(&zbf);\n    z_result_t ret = _z_oam_decode(&decoded, &zbf, header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_oam(&expected, &decoded);\n    _z_n_msg_oam_clear(&decoded);\n    _z_n_msg_oam_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_transport_message_t gen_join(void) {\n    _z_conduit_sn_list_t conduit = {._is_qos = gen_bool()};\n    if (conduit._is_qos) {\n        for (int i = 0; i < Z_PRIORITIES_NUM; i++) {\n            conduit._val._qos[i]._best_effort = gen_zint();\n            conduit._val._qos[i]._reliable = gen_zint();\n        }\n    } else {\n        conduit._val._plain._best_effort = gen_zint();\n        conduit._val._plain._reliable = gen_zint();\n    }\n    return _z_t_msg_make_join(_z_whatami_from_uint8((gen_uint8() % 3)), gen_zint(), gen_zid(), conduit);\n}\nvoid assert_eq_join(const _z_t_msg_join_t *left, const _z_t_msg_join_t *right) {\n    assert(memcmp(left->_zid.id, right->_zid.id, 16) == 0);\n    assert(left->_lease == right->_lease);\n    assert(left->_batch_size == right->_batch_size);\n    assert(left->_whatami == right->_whatami);\n    assert(left->_req_id_res == right->_req_id_res);\n    assert(left->_seq_num_res == right->_seq_num_res);\n    assert(left->_version == right->_version);\n    assert(left->_next_sn._is_qos == right->_next_sn._is_qos);\n    if (left->_next_sn._is_qos) {\n        for (int i = 0; i < Z_PRIORITIES_NUM; i++) {\n            assert(left->_next_sn._val._qos[i]._best_effort == right->_next_sn._val._qos[i]._best_effort);\n            assert(left->_next_sn._val._qos[i]._reliable == right->_next_sn._val._qos[i]._reliable);\n        }\n    } else {\n        assert(left->_next_sn._val._plain._best_effort == right->_next_sn._val._plain._best_effort);\n        assert(left->_next_sn._val._plain._reliable == right->_next_sn._val._plain._reliable);\n    }\n}\nvoid join_message(void) {\n    printf(\"\\n>> Join message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_join();\n    assert(_z_join_encode(&wbf, expected._header, &expected._body._join) == _Z_RES_OK);\n    _z_t_msg_join_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_join_decode(&decoded, &zbf, expected._header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_join(&expected._body._join, &decoded);\n    _z_t_msg_join_clear(&decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_transport_message_t gen_init(void) {\n    if (gen_bool()) {\n        return _z_t_msg_make_init_syn(_z_whatami_from_uint8((gen_uint8() % 3)), gen_zid());\n    } else {\n        return _z_t_msg_make_init_ack(_z_whatami_from_uint8((gen_uint8() % 3)), gen_zid(), gen_slice(16));\n    }\n}\nvoid assert_eq_init(const _z_t_msg_init_t *left, const _z_t_msg_init_t *right) {\n    assert(left->_batch_size == right->_batch_size);\n    assert(left->_req_id_res == right->_req_id_res);\n    assert(left->_seq_num_res == right->_seq_num_res);\n    assert_eq_slice(&left->_cookie, &right->_cookie);\n    assert(memcmp(left->_zid.id, right->_zid.id, 16) == 0);\n    assert(left->_version == right->_version);\n    assert(left->_whatami == right->_whatami);\n}\nvoid init_message(void) {\n    printf(\"\\n>> Init message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_init();\n    assert(_z_init_encode(&wbf, expected._header, &expected._body._init) == _Z_RES_OK);\n    _z_t_msg_init_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_init_decode(&decoded, &zbf, expected._header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_init(&expected._body._init, &decoded);\n    _z_t_msg_init_clear(&decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_transport_message_t gen_open(void) {\n    if (gen_bool()) {\n        return _z_t_msg_make_open_syn(gen_uint32(), gen_uint32(), gen_slice(16));\n    } else {\n        return _z_t_msg_make_open_ack(gen_uint32(), gen_uint32());\n    }\n}\nvoid assert_eq_open(const _z_t_msg_open_t *left, const _z_t_msg_open_t *right) {\n    assert_eq_slice(&left->_cookie, &right->_cookie);\n    assert(left->_initial_sn == right->_initial_sn);\n    assert(left->_lease == right->_lease);\n}\nvoid open_message(void) {\n    printf(\"\\n>> open message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_open();\n    assert(_z_open_encode(&wbf, expected._header, &expected._body._open) == _Z_RES_OK);\n    _z_t_msg_open_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_open_decode(&decoded, &zbf, expected._header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_open(&expected._body._open, &decoded);\n    _z_t_msg_open_clear(&decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_transport_message_t gen_close(void) { return _z_t_msg_make_close(gen_uint8(), gen_bool()); }\nvoid assert_eq_close(const _z_t_msg_close_t *left, const _z_t_msg_close_t *right) {\n    assert(left->_reason == right->_reason);\n}\nvoid close_message(void) {\n    printf(\"\\n>> close message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_close();\n    assert(_z_close_encode(&wbf, expected._header, &expected._body._close) == _Z_RES_OK);\n    _z_t_msg_close_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_close_decode(&decoded, &zbf, expected._header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_close(&expected._body._close, &decoded);\n    _z_t_msg_close_clear(&decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_transport_message_t gen_keep_alive(void) { return _z_t_msg_make_keep_alive(); }\nvoid assert_eq_keep_alive(const _z_t_msg_keep_alive_t *left, const _z_t_msg_keep_alive_t *right) {\n    (void)left;\n    (void)right;\n}\nvoid keep_alive_message(void) {\n    printf(\"\\n>> keep_alive message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_keep_alive();\n    assert(_z_keep_alive_encode(&wbf, expected._header, &expected._body._keep_alive) == _Z_RES_OK);\n    _z_t_msg_keep_alive_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_keep_alive_decode(&decoded, &zbf, expected._header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_keep_alive(&expected._body._keep_alive, &decoded);\n    _z_t_msg_keep_alive_clear(&decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n_z_network_message_t gen_net_msg(void) {\n    switch (gen_uint8() % 6) {\n        default:\n        case 0: {\n            return gen_declare_message();\n        } break;\n        case 1: {\n            return (_z_network_message_t){._tag = _Z_N_PUSH, ._body._push = gen_push()};\n        } break;\n        case 2: {\n            return (_z_network_message_t){._tag = _Z_N_REQUEST, ._body._request = gen_request()};\n        } break;\n        case 3: {\n            return (_z_network_message_t){._tag = _Z_N_RESPONSE, ._body._response = gen_response()};\n        } break;\n        case 4: {\n            return (_z_network_message_t){._tag = _Z_N_RESPONSE_FINAL, ._body._response_final = gen_response_final()};\n        } break;\n        case 5: {\n            return (_z_network_message_t){._tag = _Z_N_INTEREST, ._body._interest._interest = gen_interest()};\n        } break;\n    }\n}\nvoid assert_eq_net_msg(const _z_network_message_t *left, const _z_network_message_t *right) {\n    assert(left->_tag == right->_tag);\n    switch (left->_tag) {\n        case _Z_N_DECLARE: {\n            assert_eq_declaration(&left->_body._declare._decl, &right->_body._declare._decl);\n            assert_eq_timestamp(&left->_body._declare._ext_timestamp, &right->_body._declare._ext_timestamp);\n            assert(left->_body._declare._ext_qos._val == right->_body._declare._ext_qos._val);\n        } break;\n        case _Z_N_PUSH: {\n            assert_eq_push(&left->_body._push, &right->_body._push);\n        } break;\n        case _Z_N_REQUEST: {\n            assert_eq_request(&left->_body._request, &right->_body._request);\n        } break;\n        case _Z_N_RESPONSE: {\n            assert_eq_response(&left->_body._response, &right->_body._response);\n        } break;\n        case _Z_N_RESPONSE_FINAL: {\n            assert_eq_response_final(&left->_body._response_final, &right->_body._response_final);\n        } break;\n        case _Z_N_INTEREST: {\n            assert_eq_interest(&left->_body._interest._interest, &right->_body._interest._interest);\n        } break;\n        default:\n            assert(false);\n            break;\n    }\n}\n\n_z_network_message_svec_t gen_net_msgs(size_t n) {\n    _z_network_message_svec_t ret = _z_network_message_svec_make(n);\n    for (size_t i = 0; i < n; i++) {\n        _z_network_message_t msg = gen_net_msg();\n        assert(_z_network_message_svec_append(&ret, &msg, false) == _Z_RES_OK);\n    }\n    return ret;\n}\n\n_z_transport_message_t gen_frame(_z_wbuf_t *wbf, _z_zbuf_t *zbf, _z_network_message_svec_t *nmsgs) {\n    // Generate payload\n    for (size_t i = 0; i < _z_network_message_svec_len(nmsgs); i++) {\n        _z_network_message_t *msg = _z_network_message_svec_get(nmsgs, i);\n        assert(_z_network_message_encode(wbf, msg) == _Z_RES_OK);\n    }\n    *zbf = _z_wbuf_to_zbuf(wbf);\n    return _z_t_msg_make_frame(gen_uint32(), zbf, gen_bool());\n}\n\nvoid assert_eq_frame(_z_network_message_svec_t *nmsgs, _z_t_msg_frame_t *left, _z_t_msg_frame_t *right) {\n    assert(left->_sn == right->_sn);\n    for (size_t i = 0; i < _z_network_message_svec_len(nmsgs); i++) {\n        _z_network_message_t *expected = _z_network_message_svec_get(nmsgs, i);\n        _z_network_message_t received = {0};\n        _z_arc_slice_t arcs = _z_arc_slice_empty();\n        assert(_z_network_message_decode(&received, right->_payload, &arcs, _Z_KEYEXPR_MAPPING_LOCAL) == _Z_RES_OK);\n        assert_eq_net_msg(expected, &received);\n        _z_n_msg_clear(&received);\n    }\n}\nvoid frame_message(void) {\n    printf(\"\\n>> frame message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_wbuf_t tmp_wbf = gen_wbuf(UINT16_MAX);\n    _z_zbuf_t tmp_zbf = _z_zbuf_null();\n    _z_network_message_svec_t nmsgs = gen_net_msgs(1);\n    _z_transport_message_t expected = gen_frame(&tmp_wbf, &tmp_zbf, &nmsgs);\n    assert(_z_frame_encode(&wbf, expected._header, &expected._body._frame) == _Z_RES_OK);\n    _z_t_msg_frame_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    assert(_z_frame_decode(&decoded, &zbf, expected._header) == _Z_RES_OK);\n    assert_eq_frame(&nmsgs, &expected._body._frame, &decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n    _z_wbuf_clear(&tmp_wbf);\n    _z_zbuf_clear(&tmp_zbf);\n    _z_network_message_svec_clear(&nmsgs);\n}\n\n_z_transport_message_t gen_fragment(void) {\n    return _z_t_msg_make_fragment(gen_uint32(), gen_slice(gen_uint8()), gen_bool(), gen_bool(), gen_bool(), gen_bool());\n}\nvoid assert_eq_fragment(const _z_t_msg_fragment_t *left, const _z_t_msg_fragment_t *right) {\n    assert(left->_sn == right->_sn);\n    assert_eq_slice(&left->_payload, &right->_payload);\n}\nvoid fragment_message(void) {\n    printf(\"\\n>> fragment message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_fragment();\n    assert(_z_fragment_encode(&wbf, expected._header, &expected._body._fragment) == _Z_RES_OK);\n    _z_t_msg_fragment_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_fragment_decode(&decoded, &zbf, expected._header);\n    assert(_Z_RES_OK == ret);\n    assert_eq_fragment(&expected._body._fragment, &decoded);\n    _z_t_msg_fragment_clear(&decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_transport_message_t gen_transport(void) {\n    switch (gen_uint8() % 5) {\n        case 0: {\n            return gen_join();\n        };\n        case 1: {\n            return gen_init();\n        };\n        case 2: {\n            return gen_open();\n        };\n        case 3: {\n            return gen_close();\n        };\n        default:\n        case 4: {\n            return gen_keep_alive();\n        };\n    }\n}\nvoid assert_eq_transport(const _z_transport_message_t *left, const _z_transport_message_t *right) {\n    assert(left->_header == right->_header);\n    switch (_Z_MID(left->_header)) {\n        case _Z_MID_T_JOIN: {\n            assert_eq_join(&left->_body._join, &right->_body._join);\n        } break;\n        case _Z_MID_T_CLOSE: {\n            assert_eq_close(&left->_body._close, &right->_body._close);\n        } break;\n        case _Z_MID_T_INIT: {\n            assert_eq_init(&left->_body._init, &right->_body._init);\n        } break;\n        case _Z_MID_T_OPEN: {\n            assert_eq_open(&left->_body._open, &right->_body._open);\n        } break;\n        case _Z_MID_T_KEEP_ALIVE: {\n            assert_eq_keep_alive(&left->_body._keep_alive, &right->_body._keep_alive);\n        } break;\n        default:\n            assert(false);\n    }\n}\nvoid transport_message(void) {\n    printf(\"\\n>> transport message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_transport_message_t expected = gen_transport();\n    assert(_z_transport_message_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_transport_message_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_transport_message_decode(&decoded, &zbf);\n    assert(_Z_RES_OK == ret);\n    assert_eq_transport(&expected, &decoded);\n    _z_t_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n_z_scouting_message_t gen_scouting(void) {\n    if (gen_bool()) {\n        return _z_s_msg_make_scout((z_what_t)_z_whatami_from_uint8((gen_uint8() % 3)), gen_zid());\n    } else {\n        return _z_s_msg_make_hello(_z_whatami_from_uint8((gen_uint8() % 3)), gen_zid(),\n                                   gen_locator_array((gen_uint8() % 16) + 1));\n    }\n}\nvoid assert_eq_scouting(const _z_scouting_message_t *left, const _z_scouting_message_t *right) {\n    assert(left->_header == right->_header);\n    switch (_Z_MID(left->_header)) {\n        case _Z_MID_SCOUT: {\n            assert(left->_body._scout._version == right->_body._scout._version);\n            assert(left->_body._scout._what == right->_body._scout._what);\n            assert(memcmp(left->_body._scout._zid.id, right->_body._scout._zid.id, 16) == 0);\n        } break;\n        case _Z_MID_HELLO: {\n            assert(left->_body._hello._version == right->_body._hello._version);\n            assert(left->_body._hello._whatami == right->_body._hello._whatami);\n            assert(memcmp(left->_body._hello._zid.id, right->_body._hello._zid.id, 16) == 0);\n            assert_eq_locator_array(&left->_body._hello._locators, &right->_body._hello._locators);\n        } break;\n        default:\n            assert(false);\n    }\n}\nvoid scouting_message(void) {\n    printf(\"\\n>> scouting message\\n\");\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n    _z_scouting_message_t expected = gen_scouting();\n    assert(_z_scouting_message_encode(&wbf, &expected) == _Z_RES_OK);\n    _z_scouting_message_t decoded = {0};\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n    z_result_t ret = _z_scouting_message_decode(&decoded, &zbf);\n    assert(_Z_RES_OK == ret);\n    assert_eq_scouting(&expected, &decoded);\n    _z_s_msg_clear(&decoded);\n    _z_s_msg_clear(&expected);\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\nvoid test_serialize_deserialize(void) {\n    uint8_t src_data[] = \"Test\\0Payload\\0Data\";\n    size_t src_len = sizeof(src_data) - 1;\n    uint8_t header = 0xAB;\n    uint8_t serialized[256] = {0};\n    uint8_t deserialized[256] = {0};\n    uint8_t tmp_buf[256] = {0};\n\n    size_t serialized_len =\n        _z_serial_msg_serialize(serialized, sizeof(serialized), src_data, src_len, header, tmp_buf, sizeof(tmp_buf));\n    assert(serialized_len > 0);\n\n    uint8_t decoded_header = 0;\n    size_t deserialized_len = _z_serial_msg_deserialize(serialized, serialized_len, deserialized, sizeof(deserialized),\n                                                        &decoded_header, tmp_buf, sizeof(tmp_buf));\n    assert(deserialized_len != SIZE_MAX);\n\n    assert(decoded_header == header);\n\n    assert(deserialized_len == src_len);\n    assert(memcmp(src_data, deserialized, src_len) == 0);\n}\n\nvoid test_crc_mismatch(void) {\n    uint8_t src_data[] = \"Test\\0Payload\\0Data\";\n    size_t src_len = sizeof(src_data) - 1;\n    uint8_t header = 0xCD;\n    uint8_t serialized[256] = {0};\n    uint8_t tmp_buf[256] = {0};\n\n    size_t serialized_len =\n        _z_serial_msg_serialize(serialized, sizeof(serialized), src_data, src_len, header, tmp_buf, sizeof(tmp_buf));\n    assert(serialized_len != SIZE_MAX);\n\n    serialized[serialized_len - 2] ^= 0xFF;\n\n    uint8_t decoded_header = 0;\n    uint8_t deserialized[256] = {0};\n    size_t deserialized_len = _z_serial_msg_deserialize(serialized, serialized_len, deserialized, sizeof(deserialized),\n                                                        &decoded_header, tmp_buf, sizeof(tmp_buf));\n\n    assert(deserialized_len == SIZE_MAX);\n}\n\nvoid test_buffer_too_small(void) {\n    uint8_t src_data[] = \"Test\\0Payload\\0Data\";\n    size_t src_len = sizeof(src_data) - 1;\n    uint8_t header = 0xEF;\n    uint8_t serialized[256] = {0};\n    uint8_t tmp_buf[256] = {0};\n\n    size_t serialized_len =\n        _z_serial_msg_serialize(serialized, sizeof(serialized), src_data, src_len, header, tmp_buf, sizeof(tmp_buf));\n    assert(serialized_len != SIZE_MAX);\n\n    uint8_t decoded_header = 0;\n    uint8_t deserialized[4] = {0};  // Too small\n    size_t deserialized_len = _z_serial_msg_deserialize(serialized, serialized_len, deserialized, sizeof(deserialized),\n                                                        &decoded_header, tmp_buf, sizeof(tmp_buf));\n\n    assert(deserialized_len == SIZE_MAX);\n}\n\nstatic _z_network_message_t make_specific_net_msg(uint8_t which) {\n    switch (which) {\n        case 0:\n            return gen_declare_message();\n        case 1:\n            return gen_push_message();\n        case 2:\n            return gen_request_message();\n        case 3:\n            return gen_response_message();\n        case 4:\n            return gen_response_final_message();\n        case 5:\n            return gen_interest_message();\n        default:\n            assert(false && \"Invalid network message selector\");\n    }\n\n    return (_z_network_message_t){0};\n}\n\nstatic const char *net_msg_name(uint8_t which) {\n    switch (which) {\n        case 0:\n            return \"DECLARE\";\n        case 1:\n            return \"PUSH\";\n        case 2:\n            return \"INTEREST\";\n        case 3:\n            return \"RESPONSE\";\n        case 4:\n            return \"RESPONSE_FINAL\";\n        case 5:\n            return \"REQUEST\";\n        default:\n            return \"???\";\n    }\n}\n\n// Encode exactly 2 messages (A then B) into one buffer, then decode them sequentially reusing the SAME decoded object.\nstatic void network_message_decode_pair_reuse(uint8_t a, uint8_t b, bool check_contents) {\n    printf(\"\\n>> Pair %s(%u) -> %s(%u) (check: %s)\\n\", net_msg_name(a), a, net_msg_name(b), b,\n           check_contents ? \"true\" : \"false\");\n\n    _z_wbuf_t wbf = gen_wbuf(UINT16_MAX);\n\n    _z_network_message_t expected[2];\n    expected[0] = make_specific_net_msg(a);\n    expected[1] = make_specific_net_msg(b);\n\n    assert(_z_network_message_encode(&wbf, &expected[0]) == _Z_RES_OK);\n    assert(_z_network_message_encode(&wbf, &expected[1]) == _Z_RES_OK);\n\n    _z_zbuf_t zbf = _z_wbuf_to_zbuf(&wbf);\n\n    _z_network_message_t decoded = {0};\n    _z_arc_slice_t arcs = _z_arc_slice_empty();\n\n    for (int i = 0; i < 2; i++) {\n        _z_n_msg_clear(&decoded);\n\n        z_result_t r = _z_network_message_decode(&decoded, &zbf, &arcs, _Z_KEYEXPR_MAPPING_LOCAL);\n        assert(r == _Z_RES_OK);\n\n        if (check_contents) {\n            assert_eq_net_msg(&expected[i], &decoded);\n        }\n    }\n\n    _z_n_msg_clear(&decoded);\n    _z_n_msg_clear(&expected[0]);\n    _z_n_msg_clear(&expected[1]);\n\n    _z_zbuf_clear(&zbf);\n    _z_wbuf_clear(&wbf);\n}\n\n// 6x6 matrix: test all A->B transitions, one invocation per pair\nstatic void network_message_decode_pairwise_matrix(bool check_contents, size_t itr) {\n    enum { TYPES = 6 };\n\n    printf(\n        \"\\n>> Network pairwise matrix \"\n        \"(2 messages per run), check: %s, iterations: %zu\\n\",\n        check_contents ? \"true\" : \"false\", itr);\n\n    for (size_t it = 0; it < itr; it++) {\n        printf(\"\\n-- MATRIX ITERATION %zu --\\n\", it);\n\n        for (uint8_t a = 0; a < TYPES; a++) {\n            for (uint8_t b = 0; b < TYPES; b++) {\n                network_message_decode_pair_reuse(a, b, check_contents);\n            }\n        }\n    }\n}\n\n/*=============================*/\n/*            Main             */\n/*=============================*/\nint main(void) {\n    setvbuf(stdout, NULL, _IOLBF, 1024);\n\n    for (unsigned int i = 0; i < RUNS; i++) {\n        printf(\"\\n\\n== RUN %u\", i);\n\n        // Core\n        zint();\n\n        // Message fields\n        payload_field();\n        timestamp_field();\n        keyexpr_field();\n        source_info_field();\n\n        // Zenoh declarations\n        resource_declaration();\n        subscriber_declaration();\n        queryable_declaration();\n        forget_resource_declaration();\n        forget_subscriber_declaration();\n        forget_queryable_declaration();\n\n        // Zenoh messages\n        declare_message();\n        push_body_message();\n        query_message();\n        query_message_anyke();\n        err_message();\n        reply_message();\n        interest_message();\n\n        // Network messages\n        push_message();\n        request_message();\n        response_message();\n        response_final_message();\n        oam_message();\n\n        // Transport messages\n        join_message();\n        init_message();\n        open_message();\n        close_message();\n        keep_alive_message();\n        frame_message();\n        fragment_message();\n        transport_message();\n\n        // Scouting messages\n        scouting_message();\n    }\n\n    // Serial serialization\n    test_serialize_deserialize();\n    test_crc_mismatch();\n    test_buffer_too_small();\n\n    // Ensure that we can decode a sequence of messages reusing the same decoded object\n    network_message_decode_pairwise_matrix(false, 1000);\n    network_message_decode_pairwise_matrix(true, 1000);\n\n    return 0;\n}\n\n#if defined(_WIN32) || defined(WIN32)\n#pragma warning(pop)\n#endif\n"
  },
  {
    "path": "tests/z_multi_pubsub_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <errno.h>\n#include <limits.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_SUBSCRIPTION == 1\n\n#define TEST_SLEEP_MS 2000\n#define NUM_MSGS 8\n\nstatic void pub_put_str(const z_loaned_publisher_t *pub, const char *s) {\n    z_owned_bytes_t payload;\n    ASSERT_OK(z_bytes_copy_from_str(&payload, s));\n    ASSERT_OK(z_publisher_put(pub, z_move(payload), NULL));\n}\n\nstatic bool try_recv_pub_id(const z_loaned_fifo_handler_sample_t *handler, int *out_pub_id) {\n    z_owned_sample_t sample;\n    z_internal_sample_null(&sample);\n\n    if (z_try_recv(handler, &sample) != Z_OK) {\n        return false;\n    }\n\n    ASSERT_TRUE(z_sample_kind(z_loan(sample)) == Z_SAMPLE_KIND_PUT);\n\n    // Parse payload as string: expected \"m=%d p=%d\"\n    z_owned_string_t s;\n    z_internal_string_null(&s);\n    ASSERT_OK(z_bytes_to_string(z_sample_payload(z_loan(sample)), &s));\n\n    const char *ptr = z_string_data(z_loan(s));\n    int m = -1, p = -1;\n    if (ptr != NULL && sscanf(ptr, \"m=%d p=%d\", &m, &p) == 2) {\n        *out_pub_id = p;\n    } else {\n        // Ignore unexpected payloads (e.g., from other tests/processes)\n        *out_pub_id = -1;\n    }\n\n    z_drop(z_move(s));\n    z_drop(z_move(sample));\n    return true;\n}\n\nstatic bool all_seen_publishers(const bool *seen, int num_pubs) {\n    for (int i = 0; i < num_pubs; i++) {\n        if (!seen[i]) {\n            return false;\n        }\n    }\n    return true;\n}\n\nstatic size_t collect_seen_publishers(const z_loaned_fifo_handler_sample_t *handler, unsigned total_wait_ms,\n                                      unsigned step_ms, bool *seen, int num_pubs) {\n    size_t got = 0;\n    unsigned waited = 0;\n\n    while (waited < total_wait_ms && !all_seen_publishers(seen, num_pubs)) {\n        int pub_id = -1;\n        while (try_recv_pub_id(handler, &pub_id)) {\n            got++;\n            if (pub_id >= 0 && pub_id < num_pubs) {\n                seen[pub_id] = true;\n            }\n        }\n        z_sleep_ms(step_ms);\n        waited += step_ms;\n    }\n\n    // Final drain of what's currently available\n    int pub_id = -1;\n    while (try_recv_pub_id(handler, &pub_id)) {\n        got++;\n        if (pub_id >= 0 && pub_id < num_pubs) {\n            seen[pub_id] = true;\n        }\n    }\n\n    return got;\n}\n\nstatic void test_multi_pub_multi_sub(int num_pubs, int num_subs) {\n    printf(\"test_multi_pub_multi_sub (pubs=%d subs=%d)\\n\", num_pubs, num_subs);\n\n    const char *expr = \"zenoh-pico/multi-pubsub\";\n\n    z_owned_session_t s_pub, s_sub;\n    z_owned_config_t c_pub, c_sub;\n    z_config_default(&c_pub);\n    z_config_default(&c_sub);\n\n    z_view_keyexpr_t k;\n    ASSERT_OK(z_view_keyexpr_from_str(&k, expr));\n\n    ASSERT_OK(z_open(&s_pub, z_config_move(&c_pub), NULL));\n    ASSERT_OK(z_open(&s_sub, z_config_move(&c_sub), NULL));\n\n    // Declare N publishers on s_pub\n    z_owned_publisher_t *pubs = (z_owned_publisher_t *)z_malloc((size_t)num_pubs * sizeof(z_owned_publisher_t));\n    ASSERT_NOT_NULL(pubs);\n\n    z_publisher_options_t pub_opts;\n    z_publisher_options_default(&pub_opts);\n\n    for (int i = 0; i < num_pubs; i++) {\n        ASSERT_OK(z_declare_publisher(z_loan(s_pub), &pubs[i], z_loan(k), &pub_opts));\n    }\n\n    // Declare M subscribers on s_sub, each with its own fifo channel\n    z_owned_subscriber_t *subs = (z_owned_subscriber_t *)z_malloc((size_t)num_subs * sizeof(z_owned_subscriber_t));\n    z_owned_fifo_handler_sample_t *handlers =\n        (z_owned_fifo_handler_sample_t *)z_malloc((size_t)num_subs * sizeof(z_owned_fifo_handler_sample_t));\n    ASSERT_NOT_NULL(subs);\n    ASSERT_NOT_NULL(handlers);\n\n    z_subscriber_options_t sub_opts;\n    z_subscriber_options_default(&sub_opts);\n\n    size_t fifo_capacity = (size_t)num_pubs * NUM_MSGS;\n    for (int i = 0; i < num_subs; i++) {\n        z_owned_closure_sample_t closure;\n        ASSERT_OK(z_fifo_channel_sample_new(&closure, &handlers[i], fifo_capacity));\n        ASSERT_OK(z_declare_subscriber(z_loan(s_sub), &subs[i], z_loan(k), z_move(closure), &sub_opts));\n    }\n\n    // Allow subscription declarations to propagate\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    // Publish multiple messages (from all publishers) to reduce flakiness.\n    char msg[64];\n    for (int m = 0; m < NUM_MSGS; m++) {\n        for (int p = 0; p < num_pubs; p++) {\n            snprintf(msg, sizeof(msg), \"m=%d p=%d\", m, p);\n            pub_put_str(z_loan(pubs[p]), msg);\n        }\n        // tiny pacing so we don't instantly overflow FIFOs at high fanout\n        z_sleep_ms(5);\n    }\n\n    // Give time for delivery then assert each subscriber got >= 1 from each publisher\n    for (int i = 0; i < num_subs; i++) {\n        bool *seen = (bool *)z_malloc((size_t)num_pubs * sizeof(bool));\n        ASSERT_NOT_NULL(seen);\n\n        size_t got = collect_seen_publishers(z_loan(handlers[i]),\n                                             /*total_wait_ms=*/TEST_SLEEP_MS,\n                                             /*step_ms=*/50, seen, num_pubs);\n\n        if (!all_seen_publishers(seen, num_pubs)) {\n            fprintf(stderr, \"Subscriber %d missing samples from publishers:\", i);\n            for (int p = 0; p < num_pubs; p++) {\n                if (!seen[p]) {\n                    fprintf(stderr, \" %d\", p);\n                }\n            }\n            fprintf(stderr, \" (total samples seen=%zu)\\n\", got);\n            fflush(stderr);\n            assert(false && \"subscriber missing at least one publisher\");\n        }\n\n        z_free(seen);\n    }\n\n    // Cleanup\n    for (int i = 0; i < num_subs; i++) {\n        z_subscriber_drop(z_subscriber_move(&subs[i]));\n        z_fifo_handler_sample_drop(z_fifo_handler_sample_move(&handlers[i]));\n    }\n    for (int i = 0; i < num_pubs; i++) {\n        z_publisher_drop(z_publisher_move(&pubs[i]));\n    }\n\n    z_free(handlers);\n    z_free(subs);\n    z_free(pubs);\n\n    z_session_drop(z_session_move(&s_pub));\n    z_session_drop(z_session_move(&s_sub));\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n\n    test_multi_pub_multi_sub(1, 1);\n    test_multi_pub_multi_sub(1, 4);\n    test_multi_pub_multi_sub(1, 5);\n    test_multi_pub_multi_sub(10, 10);\n\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\n        \"Missing config token to build this test. This test requires: Z_FEATURE_PUBLICATION \"\n        \"and Z_FEATURE_SUBSCRIPTION\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_multi_queryable_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <assert.h>\n#include <errno.h>\n#include <limits.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_QUERY == 1 && Z_FEATURE_QUERYABLE == 1\n\n#define TEST_SLEEP_MS 2000\n#define BASE_EXPR \"zenoh-pico/multi-queryable\"\n\n// Per-queryable state (kept alive for the lifetime of the queryable)\ntypedef struct {\n    int qid;\n    z_owned_keyexpr_t ke;  // concrete keyexpr for this queryable\n} qstate_t;\n\nstatic void on_query(z_loaned_query_t *query, void *ctx) {\n    const qstate_t *st = (const qstate_t *)ctx;\n\n    char msg[32];\n    (void)snprintf(msg, sizeof(msg), \"q=%d\", st->qid);\n\n    z_owned_bytes_t payload;\n    ASSERT_OK(z_bytes_copy_from_str(&payload, msg));\n    ASSERT_OK(z_query_reply(query, z_keyexpr_loan(&st->ke), z_move(payload), NULL));\n}\n\nstatic bool all_seen(const bool *seen, int n) {\n    for (int i = 0; i < n; i++) {\n        if (!seen[i]) return false;\n    }\n    return true;\n}\n\nstatic bool try_recv_qid(const z_loaned_fifo_handler_reply_t *handler, int *out_qid) {\n    z_owned_reply_t r;\n    z_internal_reply_null(&r);\n\n    if (z_try_recv(handler, &r) != Z_OK) {\n        return false;\n    }\n\n    if (!z_reply_is_ok(z_loan(r))) {\n        z_drop(z_move(r));\n        *out_qid = -1;\n        return true;\n    }\n\n    const z_loaned_sample_t *sample = z_reply_ok(z_loan(r));\n    ASSERT_NOT_NULL(sample);\n\n    z_owned_string_t s;\n    z_internal_string_null(&s);\n    ASSERT_OK(z_bytes_to_string(z_sample_payload(sample), &s));\n\n    const char *ptr = z_string_data(z_loan(s));\n    int qid = -1;\n    if (ptr != NULL && sscanf(ptr, \"q=%d\", &qid) == 1) {\n        *out_qid = qid;\n    } else {\n        *out_qid = -1;\n    }\n\n    z_drop(z_move(s));\n    z_drop(z_move(r));\n    return true;\n}\n\nstatic size_t collect_seen_queriables(const z_loaned_fifo_handler_reply_t *handler, unsigned total_wait_ms,\n                                      unsigned step_ms, bool *seen, int num_q) {\n    size_t got = 0;\n    unsigned waited = 0;\n\n    while (waited < total_wait_ms && !all_seen(seen, num_q)) {\n        int qid = -1;\n        while (try_recv_qid(handler, &qid)) {\n            got++;\n            if (qid >= 0 && qid < num_q) {\n                seen[qid] = true;\n            }\n        }\n        z_sleep_ms(step_ms);\n        waited += step_ms;\n    }\n\n    // Final drain\n    int qid = -1;\n    while (try_recv_qid(handler, &qid)) {\n        got++;\n        if (qid >= 0 && qid < num_q) {\n            seen[qid] = true;\n        }\n    }\n\n    return got;\n}\n\nstatic void test_multi_queryables(int num_q) {\n    printf(\"test_multi_queryables (queriables=%d)\\n\", num_q);\n\n    z_owned_session_t s_q, s_cli;\n    z_owned_config_t c_q, c_cli;\n    z_config_default(&c_q);\n    z_config_default(&c_cli);\n\n    ASSERT_OK(z_open(&s_q, z_config_move(&c_q), NULL));\n    ASSERT_OK(z_open(&s_cli, z_config_move(&c_cli), NULL));\n\n    // Declare N queryables, each on its own keyexpr: BASE_EXPR/<qid>\n    z_owned_queryable_t *qs = (z_owned_queryable_t *)z_malloc((size_t)num_q * sizeof(z_owned_queryable_t));\n    qstate_t *states = (qstate_t *)z_malloc((size_t)num_q * sizeof(qstate_t));\n    ASSERT_NOT_NULL(qs);\n    ASSERT_NOT_NULL(states);\n\n    z_queryable_options_t qopts;\n    z_queryable_options_default(&qopts);\n\n    for (int i = 0; i < num_q; i++) {\n        states[i].qid = i;\n        z_internal_keyexpr_null(&states[i].ke);\n\n        char expr[128];\n        (void)snprintf(expr, sizeof(expr), \"%s/%d\", BASE_EXPR, i);\n\n        ASSERT_OK(z_keyexpr_from_str(&states[i].ke, expr));\n\n        z_owned_closure_query_t cb;\n        ASSERT_OK(z_closure_query(&cb, on_query, NULL, &states[i]));\n\n        ASSERT_OK(z_declare_queryable(z_loan(s_q), &qs[i], z_keyexpr_loan(&states[i].ke), z_move(cb), &qopts));\n    }\n\n    // Let declarations propagate\n    z_sleep_ms(TEST_SLEEP_MS);\n\n    // Query with wildcard to match them all\n    char qexpr[128];\n    (void)snprintf(qexpr, sizeof(qexpr), \"%s/**\", BASE_EXPR);\n\n    z_view_keyexpr_t qke;\n    ASSERT_OK(z_view_keyexpr_from_str(&qke, qexpr));\n\n    z_owned_fifo_handler_reply_t rh;\n    z_owned_closure_reply_t rcb;\n\n    // Capacity: expect at least num_q replies\n    ASSERT_OK(z_fifo_channel_reply_new(&rcb, &rh, (size_t)num_q * 2));\n\n    z_get_options_t gopts;\n    z_get_options_default(&gopts);\n    gopts.timeout_ms = TEST_SLEEP_MS;\n    gopts.target = Z_QUERY_TARGET_ALL;\n\n    ASSERT_OK(z_get(z_loan(s_cli), z_loan(qke), \"\", z_closure_reply_move(&rcb), &gopts));\n\n    bool *seen = (bool *)z_malloc((size_t)num_q * sizeof(bool));\n    ASSERT_NOT_NULL(seen);\n    (void)memset(seen, 0, (size_t)num_q * sizeof(bool));\n\n    size_t got = collect_seen_queriables(z_loan(rh), TEST_SLEEP_MS, 50, seen, num_q);\n\n    if (!all_seen(seen, num_q)) {\n        fprintf(stderr, \"Missing replies from queryables:\");\n        for (int i = 0; i < num_q; i++) {\n            if (!seen[i]) fprintf(stderr, \" %d\", i);\n        }\n        fprintf(stderr, \" (total replies seen=%zu)\\n\", got);\n        fflush(stderr);\n        assert(false && \"missing at least one queryable reply\");\n    }\n\n    z_free(seen);\n\n    // Cleanup\n    z_fifo_handler_reply_drop(z_fifo_handler_reply_move(&rh));\n    for (int i = 0; i < num_q; i++) {\n        z_queryable_drop(z_queryable_move(&qs[i]));\n        z_keyexpr_drop(z_keyexpr_move(&states[i].ke));\n    }\n    z_free(states);\n    z_free(qs);\n\n    z_session_drop(z_session_move(&s_q));\n    z_session_drop(z_session_move(&s_cli));\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n\n    test_multi_queryables(1);\n    test_multi_queryables(4);\n    test_multi_queryables(5);\n    test_multi_queryables(10);\n\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\n        \"Missing config token to build this test. This test requires: \"\n        \"Z_FEATURE_QUERY and Z_FEATURE_QUERYABLE\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_open_test.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#if defined(ZENOH_WINDOWS)\n#define WIN32_LEAN_AND_MEAN\n#define _WINSOCKAPI_\n#include <windows.h>\n#else\n#include <pthread.h>\n#endif\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/macros.h\"\n#include \"zenoh-pico/api/primitives.h\"\n#include \"zenoh-pico/net/session.h\"\n#include \"zenoh-pico/transport/transport.h\"\n\n#define OPEN_TEST_UNUSED_LOCATOR_1 \"tcp/127.0.0.1:18101\"\n#define OPEN_TEST_UNUSED_LOCATOR_2 \"tcp/127.0.0.1:18102\"\n#define OPEN_TEST_UNUSED_LOCATOR_3 \"tcp/127.0.0.1:18103\"\n#define OPEN_TEST_UNUSED_LOCATOR_4 \"tcp/127.0.0.1:18104\"\n#define OPEN_TEST_ALT_LOCATOR \"tcp/127.0.0.1:18105\"\n\n#define OPEN_TEST_MT_LOCATOR_1 \"tcp/127.0.0.1:18111\"\n#define OPEN_TEST_MT_LOCATOR_2 \"tcp/127.0.0.1:18112\"\n#define OPEN_TEST_MT_LOCATOR_3 \"tcp/127.0.0.1:18113\"\n#define OPEN_TEST_MT_LOCATOR_4 \"tcp/127.0.0.1:18114\"\n#define OPEN_TEST_MT_LOCATOR_5 \"tcp/127.0.0.1:18115\"\n#define OPEN_TEST_MT_LOCATOR_6 \"tcp/127.0.0.1:18116\"\n#define OPEN_TEST_MT_LOCATOR_7 \"tcp/127.0.0.1:18117\"\n\n#define OPEN_TEST_ST_LOCATOR_1 \"tcp/127.0.0.1:18121\"\n#define OPEN_TEST_ST_LOCATOR_2 \"tcp/127.0.0.1:18122\"\n#define OPEN_TEST_ST_LOCATOR_3 \"tcp/127.0.0.1:18123\"\n\n// Keep this conservative: busy CI runners may delay executor progress after z_open().\n#define OPEN_TEST_LISTENER_SETTLE_MS 1000\n\n/*\n * These OS thread helpers are test-harness concurrency only. They let the tests\n * exercise a single-threaded zenoh-pico build while another in-process session\n * is blocked in z_open(), and the main test thread can keep spinning listeners.\n */\n#if defined(ZENOH_WINDOWS)\ntypedef HANDLE open_test_task_t;\ntypedef DWORD open_test_task_ret_t;\n#define OPEN_TEST_TASK_CALL WINAPI\n#define OPEN_TEST_TASK_RETURN 0\n#else\ntypedef pthread_t open_test_task_t;\ntypedef void *open_test_task_ret_t;\n#define OPEN_TEST_TASK_CALL\n#define OPEN_TEST_TASK_RETURN NULL\n#endif\n\ntypedef struct {\n    z_owned_config_t config;\n    z_owned_session_t session;\n    uint32_t delay_ms;\n    volatile bool done;\n    z_result_t ret;\n} open_test_async_open_t;\n\ntypedef struct {\n    z_owned_session_t *session;\n    volatile bool done;\n} open_test_async_spin_t;\n\nstatic z_result_t open_test_task_init(open_test_task_t *task, open_test_task_ret_t(OPEN_TEST_TASK_CALL *fun)(void *),\n                                      void *arg) {\n#if defined(ZENOH_WINDOWS)\n    *task = CreateThread(NULL, 0, fun, arg, 0, NULL);\n    return (*task != NULL) ? _Z_RES_OK : _Z_ERR_GENERIC;\n#else\n    return (pthread_create(task, NULL, fun, arg) == 0) ? _Z_RES_OK : _Z_ERR_GENERIC;\n#endif\n}\n\nstatic z_result_t open_test_task_join(open_test_task_t *task) {\n#if defined(ZENOH_WINDOWS)\n    DWORD ret = WaitForSingleObject(*task, INFINITE);\n    CloseHandle(*task);\n    return (ret == WAIT_OBJECT_0) ? _Z_RES_OK : _Z_ERR_GENERIC;\n#else\n    return (pthread_join(*task, NULL) == 0) ? _Z_RES_OK : _Z_ERR_GENERIC;\n#endif\n}\n\nstatic open_test_task_ret_t OPEN_TEST_TASK_CALL open_test_async_open_task(void *arg) {\n    open_test_async_open_t *ctx = (open_test_async_open_t *)arg;\n\n    z_sleep_ms(ctx->delay_ms);\n    ctx->ret = z_open(&ctx->session, z_move(ctx->config), NULL);\n    ctx->done = true;\n\n    return OPEN_TEST_TASK_RETURN;\n}\n\nstatic void open_test_start_async_open(open_test_task_t *task, open_test_async_open_t *ctx, z_owned_config_t config,\n                                       uint32_t delay_ms) {\n    ctx->config = config;\n    ctx->delay_ms = delay_ms;\n    ctx->done = false;\n    ctx->ret = _Z_ERR_GENERIC;\n    ASSERT_OK(open_test_task_init(task, open_test_async_open_task, ctx));\n}\n\nstatic void open_test_spin_once(z_owned_session_t *session) {\n#if Z_FEATURE_MULTI_THREAD == 0\n    (void)zp_spin_once(z_session_loan(session));\n#else\n    _ZP_UNUSED(session);\n#endif\n}\n\n#if Z_FEATURE_MULTI_THREAD == 0 && defined(Z_FEATURE_UNSTABLE_API)\nstatic open_test_task_ret_t OPEN_TEST_TASK_CALL open_test_async_spin_task(void *arg) {\n    open_test_async_spin_t *ctx = (open_test_async_spin_t *)arg;\n    while (!ctx->done) {\n        open_test_spin_once(ctx->session);\n        z_sleep_ms(10);\n    }\n\n    return OPEN_TEST_TASK_RETURN;\n}\n\nstatic void open_test_start_async_spin(open_test_task_t *task, open_test_async_spin_t *ctx,\n                                       z_owned_session_t *session) {\n    ctx->session = session;\n    ctx->done = false;\n    ASSERT_OK(open_test_task_init(task, open_test_async_spin_task, ctx));\n}\n\nstatic void open_test_stop_async_spin(open_test_task_t *task, open_test_async_spin_t *ctx) {\n    ctx->done = true;\n    ASSERT_OK(open_test_task_join(task));\n}\n#endif\n\nstatic size_t open_test_peer_count(z_owned_session_t *session) {\n    _z_session_t *zs = _Z_RC_IN_VAL(&session->_rc);\n    if (zs->_tp._type != _Z_TRANSPORT_UNICAST_TYPE) {\n        return 0;\n    }\n\n    _z_transport_unicast_t *ztu = &zs->_tp._transport._unicast;\n    _z_transport_peer_mutex_lock(&ztu->_common);\n    size_t len = _z_transport_peer_unicast_slist_len(ztu->_peers);\n    _z_transport_peer_mutex_unlock(&ztu->_common);\n    return len;\n}\n\nstatic bool open_test_wait_for_peer_count(z_owned_session_t *target, size_t expected_count,\n                                          z_owned_session_t **sessions, size_t session_count, uint32_t timeout_ms) {\n    z_clock_t start = z_clock_now();\n    while (z_clock_elapsed_ms(&start) < timeout_ms) {\n        if (open_test_peer_count(target) >= expected_count) {\n            return true;\n        }\n\n        for (size_t i = 0; i < session_count; i++) {\n            open_test_spin_once(sessions[i]);\n        }\n        z_sleep_ms(50);\n    }\n\n    return open_test_peer_count(target) >= expected_count;\n}\n\nstatic void open_test_settle_listener(z_owned_session_t **sessions, size_t session_count) {\n    z_clock_t start = z_clock_now();\n    do {\n        for (size_t i = 0; i < session_count; i++) {\n            open_test_spin_once(sessions[i]);\n        }\n        z_sleep_ms(10);\n    } while (z_clock_elapsed_ms(&start) < OPEN_TEST_LISTENER_SETTLE_MS);\n}\n\nstatic void open_test_wait_for_async_open(open_test_async_open_t *ctx, z_owned_session_t **sessions,\n                                          size_t session_count, uint32_t timeout_ms) {\n    z_clock_t start = z_clock_now();\n    while (!ctx->done && z_clock_elapsed_ms(&start) < timeout_ms) {\n        for (size_t i = 0; i < session_count; i++) {\n            open_test_spin_once(sessions[i]);\n        }\n        z_sleep_ms(10);\n    }\n    ASSERT_TRUE(ctx->done);\n}\n\n#if defined(Z_FEATURE_UNSTABLE_API)\nstatic void test_open_timeout_single_locator(void) {\n    printf(\"Running test_open_timeout_single_locator() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_1);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"1000\");\n\n    z_owned_session_t s;\n\n    z_clock_t start = z_clock_now();\n    z_result_t ret = z_open(&s, z_move(c), NULL);\n    unsigned long elapsed_ms = z_clock_elapsed_ms(&start);\n\n    ASSERT_ERR(ret, _Z_ERR_TRANSPORT_OPEN_FAILED);\n    ASSERT_TRUE(elapsed_ms >= 1000);\n}\n\nstatic void test_open_client_connect_exit_on_failure_false_still_requires_transport(void) {\n    printf(\"Running test_open_client_connect_exit_on_failure_false_still_requires_transport() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"client\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_2);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"1000\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY, \"false\");\n\n    z_owned_session_t s;\n\n    z_clock_t start = z_clock_now();\n    z_result_t ret = z_open(&s, z_move(c), NULL);\n    unsigned long elapsed_ms = z_clock_elapsed_ms(&start);\n\n    ASSERT_ERR(ret, _Z_ERR_TRANSPORT_OPEN_FAILED);\n    ASSERT_TRUE(elapsed_ms >= 1000);\n}\n\nstatic void test_open_invalid_timeout_value(void) {\n    printf(\"Running test_open_invalid_timeout_value() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_3);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"not-a-number\");\n\n    z_owned_session_t s;\n    ASSERT_ERR(z_open(&s, z_move(c), NULL), _Z_ERR_CONFIG_INVALID_VALUE);\n}\n\nstatic void test_open_timeout_overflow_value(void) {\n    printf(\"Running test_open_timeout_overflow_value() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_3);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"2147483648\");\n\n    z_owned_session_t s;\n    ASSERT_ERR(z_open(&s, z_move(c), NULL), _Z_ERR_CONFIG_INVALID_VALUE);\n}\n\nstatic void test_open_invalid_bool_value(void) {\n    printf(\"Running test_open_invalid_bool_value() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_4);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY, \"maybe\");\n\n    z_owned_session_t s;\n    ASSERT_ERR(z_open(&s, z_move(c), NULL), _Z_ERR_CONFIG_INVALID_VALUE);\n}\n\nstatic void test_open_rejects_negative_connect_timeout_below_minus_one(void) {\n    printf(\"Running test_open_rejects_negative_connect_timeout_below_minus_one() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_1);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"-2\");\n\n    z_owned_session_t s;\n    ASSERT_ERR(z_open(&s, z_move(c), NULL), _Z_ERR_CONFIG_INVALID_VALUE);\n}\n\nstatic void test_open_rejects_negative_listen_timeout_below_minus_one(void) {\n    printf(\"Running test_open_rejects_negative_listen_timeout_below_minus_one() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_LISTEN_KEY, OPEN_TEST_UNUSED_LOCATOR_2);\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_LISTEN_TIMEOUT_KEY, \"-2\");\n\n    z_owned_session_t s;\n    ASSERT_ERR(z_open(&s, z_move(c), NULL), _Z_ERR_CONFIG_INVALID_VALUE);\n}\n#endif\n\nstatic void test_open_multiple_listen_locators_are_rejected(void) {\n    printf(\"Running test_open_multiple_listen_locators_are_rejected() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    _z_str_intmap_insert_push(z_loan_mut(c), Z_CONFIG_LISTEN_KEY, _z_str_clone(OPEN_TEST_UNUSED_LOCATOR_1));\n    _z_str_intmap_insert_push(z_loan_mut(c), Z_CONFIG_LISTEN_KEY, _z_str_clone(OPEN_TEST_UNUSED_LOCATOR_2));\n\n    z_owned_session_t s;\n    ASSERT_ERR(z_open(&s, z_move(c), NULL), _Z_ERR_CONFIG_LOCATOR_INVALID);\n}\n\nstatic void test_open_peer_listen_succeeds(void) {\n    printf(\"Running test_open_peer_listen_succeeds() ...\\n\");\n\n    z_owned_config_t c;\n    z_config_default(&c);\n\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c), Z_CONFIG_LISTEN_KEY, OPEN_TEST_ALT_LOCATOR);\n\n    z_owned_session_t s;\n    ASSERT_OK(z_open(&s, z_move(c), NULL));\n    z_drop(z_move(s));\n}\n\nstatic void test_open_peer_uses_next_connect_locator_for_primary_transport(void) {\n    printf(\"Running test_open_peer_uses_next_connect_locator_for_primary_transport() ...\\n\");\n\n    z_owned_config_t c1;\n    z_owned_config_t c2;\n\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, OPEN_TEST_ALT_LOCATOR);\n\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_UNUSED_LOCATOR_1);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_ALT_LOCATOR);\n#if defined(Z_FEATURE_UNSTABLE_API)\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"1000\");\n#endif\n\n    z_owned_session_t s1;\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    z_owned_session_t *listener_sessions[] = {&s1};\n    open_test_settle_listener(listener_sessions, _ZP_ARRAY_SIZE(listener_sessions));\n\n    open_test_task_t task;\n    open_test_async_open_t ctx;\n    open_test_start_async_open(&task, &ctx, c2, 0);\n    open_test_wait_for_async_open(&ctx, listener_sessions, _ZP_ARRAY_SIZE(listener_sessions), 3000);\n    ASSERT_OK(open_test_task_join(&task));\n    ASSERT_OK(ctx.ret);\n\n    z_owned_session_t *sessions[] = {&s1, &ctx.session};\n    ASSERT_TRUE(open_test_wait_for_peer_count(&s1, 1, sessions, _ZP_ARRAY_SIZE(sessions), 1000));\n\n    z_drop(z_move(ctx.session));\n    z_drop(z_move(s1));\n}\n\n#if Z_FEATURE_UNICAST_PEER == 1 && defined(Z_FEATURE_UNSTABLE_API)\nstatic void _test_open_timeout_partial_connectivity(const char *connect_exit_on_failure, z_result_t expected_ret,\n                                                    const char *good_locator, const char *bad_locator) {\n    z_owned_config_t c1;\n    z_owned_config_t c2;\n\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, good_locator);\n\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, good_locator);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, bad_locator);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"1000\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY, connect_exit_on_failure);\n\n    z_owned_session_t s1;\n\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    z_owned_session_t *listener_sessions[] = {&s1};\n    open_test_settle_listener(listener_sessions, _ZP_ARRAY_SIZE(listener_sessions));\n\n    z_clock_t start = z_clock_now();\n    open_test_task_t task;\n    open_test_async_open_t ctx;\n    open_test_start_async_open(&task, &ctx, c2, 0);\n    open_test_wait_for_async_open(&ctx, listener_sessions, _ZP_ARRAY_SIZE(listener_sessions), 3000);\n    unsigned long elapsed_ms = z_clock_elapsed_ms(&start);\n    ASSERT_OK(open_test_task_join(&task));\n    z_result_t ret = ctx.ret;\n\n    ASSERT_ERR(ret, expected_ret);\n\n    if ((expected_ret == _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY) ||\n        (expected_ret == _Z_ERR_TRANSPORT_OPEN_FAILED)) {\n        ASSERT_TRUE(elapsed_ms >= 1000);\n    }\n\n    if (ret == _Z_RES_OK) {\n        ASSERT_TRUE(open_test_peer_count(&ctx.session) >= 1);\n        z_drop(z_move(ctx.session));\n    }\n    z_drop(z_move(s1));\n}\n\nstatic void test_open_timeout_partial_connectivity_exit_on_failure_false(void) {\n    printf(\"Running test_open_timeout_partial_connectivity_exit_on_failure_false() ...\\n\");\n\n    _test_open_timeout_partial_connectivity(\"false\", _Z_RES_OK, OPEN_TEST_MT_LOCATOR_1, OPEN_TEST_MT_LOCATOR_2);\n}\n\nstatic void test_open_timeout_partial_connectivity_exit_on_failure_true(void) {\n    printf(\"Running test_open_timeout_partial_connectivity_exit_on_failure_true() ...\\n\");\n\n    _test_open_timeout_partial_connectivity(\"true\", _Z_ERR_TRANSPORT_OPEN_PARTIAL_CONNECTIVITY, OPEN_TEST_MT_LOCATOR_3,\n                                            OPEN_TEST_MT_LOCATOR_4);\n}\n\nstatic void test_open_peer_listen_failure_strict_fails_before_connect(void) {\n    printf(\"Running test_open_peer_listen_failure_strict_fails_before_connect() ...\\n\");\n\n    z_owned_config_t c1;\n    z_config_default(&c1);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, OPEN_TEST_MT_LOCATOR_5);\n\n    z_owned_session_t s1;\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    z_owned_session_t *listener_sessions[] = {&s1};\n    open_test_settle_listener(listener_sessions, _ZP_ARRAY_SIZE(listener_sessions));\n\n    z_owned_config_t c2;\n    z_config_default(&c2);\n\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_KEY, OPEN_TEST_MT_LOCATOR_5);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY, \"true\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_MT_LOCATOR_5);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"1000\");\n\n    z_owned_session_t s2;\n    ASSERT_ERR(z_open(&s2, z_move(c2), NULL), _Z_ERR_TRANSPORT_OPEN_FAILED);\n\n    z_drop(z_move(s1));\n}\n\nstatic void test_open_peer_listen_failure_can_fallback_to_connect(void) {\n    printf(\"Running test_open_peer_listen_failure_can_fallback_to_connect() ...\\n\");\n\n    z_owned_config_t c1;\n    z_config_default(&c1);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, OPEN_TEST_MT_LOCATOR_6);\n\n    z_owned_session_t s1;\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    z_owned_session_t *listener_sessions[] = {&s1};\n    open_test_settle_listener(listener_sessions, _ZP_ARRAY_SIZE(listener_sessions));\n\n    z_owned_config_t c2;\n    z_config_default(&c2);\n\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_KEY, OPEN_TEST_MT_LOCATOR_6);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_EXIT_ON_FAILURE_KEY, \"false\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_MT_LOCATOR_6);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"1000\");\n\n    open_test_task_t task;\n    open_test_async_open_t ctx;\n    open_test_start_async_open(&task, &ctx, c2, 0);\n    open_test_wait_for_async_open(&ctx, listener_sessions, _ZP_ARRAY_SIZE(listener_sessions), 3000);\n    ASSERT_OK(open_test_task_join(&task));\n    ASSERT_OK(ctx.ret);\n\n    z_owned_session_t *sessions[] = {&s1, &ctx.session};\n    ASSERT_TRUE(open_test_wait_for_peer_count(&ctx.session, 1, sessions, _ZP_ARRAY_SIZE(sessions), 1000));\n\n    z_drop(z_move(ctx.session));\n    z_drop(z_move(s1));\n}\n#endif\n\n#if Z_FEATURE_UNICAST_PEER == 1 && defined(Z_FEATURE_UNSTABLE_API)\nstatic void test_open_pending_peer_progresses_after_partial_connectivity(void) {\n    printf(\"Running test_open_pending_peer_progresses_after_partial_connectivity() ...\\n\");\n\n    z_owned_config_t c1;\n    z_owned_config_t c2;\n    z_owned_config_t c3;\n\n    z_config_default(&c1);\n    z_config_default(&c2);\n    z_config_default(&c3);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, OPEN_TEST_ST_LOCATOR_1);\n\n    /*\n     * s2 opens its own listen locator, so it has a primary transport and z_open()\n     * can return without requiring the connect locators to complete immediately.\n     *\n     * The second connect locator is left pending until s3 starts listening.\n     * This verifies that the background add-peers task completes the pending\n     * connection after z_open() has accepted partial connectivity.\n     */\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_KEY, OPEN_TEST_ST_LOCATOR_2);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_ST_LOCATOR_1);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_ST_LOCATOR_3);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"5000\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_EXIT_ON_FAILURE_KEY, \"false\");\n\n    zp_config_insert(z_loan_mut(c3), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c3), Z_CONFIG_LISTEN_KEY, OPEN_TEST_ST_LOCATOR_3);\n\n    z_owned_session_t s1;\n    z_owned_session_t s3;\n\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    z_owned_session_t *listener_sessions[] = {&s1};\n    open_test_settle_listener(listener_sessions, _ZP_ARRAY_SIZE(listener_sessions));\n\n    open_test_task_t task;\n    open_test_async_open_t ctx;\n    open_test_start_async_open(&task, &ctx, c2, 0);\n    open_test_wait_for_async_open(&ctx, listener_sessions, _ZP_ARRAY_SIZE(listener_sessions), 7000);\n    ASSERT_OK(open_test_task_join(&task));\n    ASSERT_OK(ctx.ret);\n\n    z_owned_session_t *initial_sessions[] = {&s1, &ctx.session};\n    ASSERT_TRUE(\n        open_test_wait_for_peer_count(&ctx.session, 1, initial_sessions, _ZP_ARRAY_SIZE(initial_sessions), 1000));\n\n    ASSERT_OK(z_open(&s3, z_move(c3), NULL));\n    z_owned_session_t *late_listener_sessions[] = {&s1, &s3};\n    open_test_settle_listener(late_listener_sessions, _ZP_ARRAY_SIZE(late_listener_sessions));\n\n#if Z_FEATURE_MULTI_THREAD == 0\n    open_test_task_t spin_task;\n    open_test_async_spin_t spin_ctx;\n    open_test_start_async_spin(&spin_task, &spin_ctx, &ctx.session);\n#endif\n\n    z_owned_session_t *sessions[] = {&s1, &s3};\n    ASSERT_TRUE(open_test_wait_for_peer_count(&ctx.session, 2, sessions, _ZP_ARRAY_SIZE(sessions), 5000));\n#if Z_FEATURE_MULTI_THREAD == 0\n    open_test_stop_async_spin(&spin_task, &spin_ctx);\n#endif\n\n    z_drop(z_move(s3));\n    z_drop(z_move(ctx.session));\n    z_drop(z_move(s1));\n}\n#endif\n\n#if defined(Z_FEATURE_UNSTABLE_API)\nstatic void test_open_late_joining_endpoint(void) {\n    printf(\"Running test_open_late_joining_endpoint() ...\\n\");\n\n    z_owned_config_t c1;\n    z_owned_config_t c2;\n\n    z_config_default(&c1);\n    z_config_default(&c2);\n\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, OPEN_TEST_MT_LOCATOR_7);\n\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_KEY, OPEN_TEST_MT_LOCATOR_7);\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_CONNECT_TIMEOUT_KEY, \"5000\");\n\n    open_test_task_t task;\n    open_test_async_open_t ctx;\n    z_clock_t start = z_clock_now();\n    open_test_start_async_open(&task, &ctx, c2, 0);\n\n    z_sleep_ms(1000);\n    z_owned_session_t s1;\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    z_owned_session_t *listener_sessions[] = {&s1};\n    open_test_wait_for_async_open(&ctx, listener_sessions, _ZP_ARRAY_SIZE(listener_sessions), 5000);\n    unsigned long elapsed_ms = z_clock_elapsed_ms(&start);\n\n    ASSERT_OK(open_test_task_join(&task));\n    ASSERT_OK(ctx.ret);\n    ASSERT_TRUE(elapsed_ms >= 1000);\n\n    z_drop(z_move(ctx.session));\n    z_drop(z_move(s1));\n}\n#endif\n\nint main(void) {\n#if defined(Z_FEATURE_UNSTABLE_API)\n    test_open_timeout_single_locator();\n    test_open_client_connect_exit_on_failure_false_still_requires_transport();\n    test_open_invalid_timeout_value();\n    test_open_timeout_overflow_value();\n    test_open_invalid_bool_value();\n    test_open_rejects_negative_connect_timeout_below_minus_one();\n    test_open_rejects_negative_listen_timeout_below_minus_one();\n#endif\n    test_open_multiple_listen_locators_are_rejected();\n    test_open_peer_listen_succeeds();\n    test_open_peer_uses_next_connect_locator_for_primary_transport();\n\n#if Z_FEATURE_UNICAST_PEER == 1 && defined(Z_FEATURE_UNSTABLE_API)\n    test_open_timeout_partial_connectivity_exit_on_failure_false();\n    test_open_timeout_partial_connectivity_exit_on_failure_true();\n    test_open_peer_listen_failure_strict_fails_before_connect();\n    test_open_peer_listen_failure_can_fallback_to_connect();\n    test_open_pending_peer_progresses_after_partial_connectivity();\n#endif\n\n#if defined(Z_FEATURE_UNSTABLE_API)\n    test_open_late_joining_endpoint();\n#endif\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_perf_rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\ntypedef struct {\n    volatile unsigned long count;\n    unsigned long curr_len;\n    z_clock_t start;\n} z_stats_t;\n\nstatic z_stats_t test_stats;\nstatic volatile bool test_end;\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nvoid z_stats_stop(z_stats_t *stats) {\n    // Ignore default value\n    if (stats->curr_len == 0) {\n        return;\n    }\n    // Print values\n    unsigned long elapsed_ms = z_clock_elapsed_ms(&stats->start);\n    printf(\"End test for pkt len: %lu, msg nb: %lu, time ms: %lu\\n\", stats->curr_len, stats->count, elapsed_ms);\n    stats->count = 0;\n}\n\nvoid on_sample(z_loaned_sample_t *sample, void *context) {\n    z_stats_t *stats = (z_stats_t *)context;\n    z_owned_slice_t value;\n    z_bytes_to_slice(z_sample_payload(sample), &value);\n    unsigned long data_len = (unsigned long)z_slice_len(z_loan(value));\n\n    if (stats->curr_len != data_len) {\n        // End previous measurement\n        z_stats_stop(stats);\n        // Check for end packet\n        stats->curr_len = data_len;\n        if (data_len == 1) {\n            test_end = true;\n            return;\n        }\n        // Start new measurement\n        printf(\"Starting test for pkt len: %lu\\n\", stats->curr_len);\n        stats->start = z_clock_now();\n    }\n    z_drop(z_move(value));\n    stats->count++;\n}\n\nint main(int argc, char **argv) {\n    char *keyexpr = \"test/thr\";\n    const char *mode = NULL;\n    char *llocator = NULL;\n    char *clocator = NULL;\n    (void)argv;\n\n    // Check if peer or client mode\n    if (argc > 1) {\n        mode = \"peer\";\n        llocator = \"udp/224.0.0.224:7447#iface=lo\";\n    } else {\n        mode = \"client\";\n        clocator = \"tcp/127.0.0.1:7447\";\n    }\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (mode != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n    if (clocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    // Declare Subscriber/resource\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, on_sample, NULL, (void *)&test_stats);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, keyexpr);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to create subscriber.\\n\");\n        exit(-1);\n    }\n    // Listen until stopped\n    printf(\"Start listening.\\n\");\n    while (!test_end) {\n    }\n    // Wait for everything to settle\n    printf(\"End of test\\n\");\n    z_sleep_s(1);\n    // Clean up\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    exit(0);\n}\n#else\nint main(void) {\n    (void)test_stats;\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this test requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "tests/z_perf_tx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))\n#define TEST_DURATION_US 10000000\n\n#if Z_FEATURE_PUBLICATION == 1\nint send_packets(unsigned long pkt_len, z_owned_publisher_t *pub, uint8_t *value) {\n    z_clock_t test_start = z_clock_now();\n    unsigned long elapsed_us = 0;\n    while (elapsed_us < TEST_DURATION_US) {\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_from_buf(&payload, value, pkt_len, NULL, NULL);\n\n        z_publisher_put(z_loan(*pub), z_move(payload), NULL);\n        elapsed_us = z_clock_elapsed_us(&test_start);\n    }\n    return 0;\n}\n\nint main(int argc, char **argv) {\n    unsigned long len_array[] = {1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096,\n                                 2048,    1024,   512,    256,    128,   64,    32,    16,   8};  // Biggest value first\n    uint8_t *value = (uint8_t *)malloc(len_array[0]);\n    memset(value, 1, len_array[0]);\n    char *keyexpr = \"test/thr\";\n    const char *mode = NULL;\n    char *llocator = NULL;\n    char *clocator = NULL;\n    (void)argv;\n\n    // Check if peer or client mode\n    if (argc > 1) {\n        mode = \"peer\";\n        llocator = \"udp/224.0.0.224:7447#iface=lo\";\n    } else {\n        mode = \"client\";\n        clocator = \"tcp/127.0.0.1:7447\";\n    }\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (mode != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n    if (clocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        exit(-1);\n    }\n    // Declare publisher\n    z_owned_publisher_t pub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, keyexpr);\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(ke), NULL) < 0) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        exit(-1);\n    }\n    // Wait for joins\n    if (strcmp(mode, \"peer\") == 0) {\n        printf(\"Waiting for JOIN messages\\n\");\n        z_sleep_s(3);\n    }\n    // Send packets\n    for (size_t i = 0; i < ARRAY_SIZE(len_array); i++) {\n        printf(\"Start sending pkt len: %lu\\n\", len_array[i]);\n        if (send_packets(len_array[i], &pub, value) != 0) {\n            break;\n        }\n    }\n    // Send end packet\n    printf(\"Sending end pkt\\n\");\n    // Create payload\n    z_owned_bytes_t payload;\n    z_bytes_from_buf(&payload, value, 1, NULL, NULL);\n\n    z_publisher_put(z_loan(pub), z_move(payload), NULL);\n\n    // Clean up\n    z_drop(z_move(pub));\n    z_drop(z_move(s));\n    free(value);\n    exit(0);\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this test requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "tests/z_pqueue_test.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n\n#undef NDEBUG\n#include <assert.h>\n\n// ── Instantiate int min-heap, capacity 8 ─────────────────────────────────────\n\nstatic inline int intpq_cmp(const int *a, const int *b) { return *a - *b; }\n#define _ZP_PQUEUE_TEMPLATE_ELEM_TYPE int\n#define _ZP_PQUEUE_TEMPLATE_NAME intpq\n#define _ZP_PQUEUE_TEMPLATE_SIZE 8\n#define _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME intpq_cmp\n#include \"zenoh-pico/collections/pqueue_template.h\"\n\n// ── Instantiate int heap with context-carried comparator ─────────────────────\n// The context holds a multiplier: +1 → min-heap, -1 → max-heap.\n\ntypedef struct {\n    int multiplier;\n} intpq_cmp_ctx_t;\n\nstatic inline int intpq_with_ctx_cmp(const int *a, const int *b, const intpq_cmp_ctx_t *ctx) {\n    return ctx->multiplier * (*a - *b);\n}\n#define _ZP_PQUEUE_TEMPLATE_ELEM_TYPE int\n#define _ZP_PQUEUE_TEMPLATE_NAME intpq_with_ctx\n#define _ZP_PQUEUE_TEMPLATE_SIZE 8\n#define _ZP_PQUEUE_TEMPLATE_CMP_CTX_TYPE intpq_cmp_ctx_t\n#define _ZP_PQUEUE_TEMPLATE_ELEM_CMP_FN_NAME intpq_with_ctx_cmp\n#include \"zenoh-pico/collections/pqueue_template.h\"\n\n// ── Tests: context-free min-heap ─────────────────────────────────────────────\n\nstatic void test_new_is_empty(void) {\n    printf(\"Test: new queue is empty\\n\");\n    intpq_t pq = intpq_new();\n    assert(intpq_is_empty(&pq));\n    assert(intpq_size(&pq) == 0);\n    assert(intpq_peek(&pq) == NULL);\n    intpq_destroy(&pq);\n}\n\nstatic void test_push_pop_single(void) {\n    printf(\"Test: push then pop returns the same element\\n\");\n    intpq_t pq = intpq_new();\n    int v = 42;\n    assert(intpq_push(&pq, &v));\n    assert(intpq_size(&pq) == 1);\n    int out = 0;\n    assert(intpq_pop(&pq, &out));\n    assert(out == 42);\n    assert(intpq_is_empty(&pq));\n    intpq_destroy(&pq);\n}\n\nstatic void test_min_heap_order(void) {\n    printf(\"Test: pop returns elements in ascending order\\n\");\n    intpq_t pq = intpq_new();\n    int vals[] = {5, 1, 8, 3, 2, 7, 4, 6};\n    for (int i = 0; i < 8; i++) {\n        assert(intpq_push(&pq, &vals[i]));\n    }\n    assert(intpq_size(&pq) == 8);\n    int prev = -1;\n    for (int i = 0; i < 8; i++) {\n        int out = 0;\n        assert(intpq_pop(&pq, &out));\n        assert(out > prev);\n        prev = out;\n    }\n    assert(intpq_is_empty(&pq));\n    intpq_destroy(&pq);\n}\n\nstatic void test_peek_does_not_remove(void) {\n    printf(\"Test: peek returns min without removing it\\n\");\n    intpq_t pq = intpq_new();\n    int a = 10, b = 3, c = 7;\n    assert(intpq_push(&pq, &a));\n    assert(intpq_push(&pq, &b));\n    assert(intpq_push(&pq, &c));\n    int *top = intpq_peek(&pq);\n    assert(top != NULL && *top == 3);\n    assert(intpq_size(&pq) == 3);  // peek must not remove\n    intpq_destroy(&pq);\n}\n\nstatic void test_capacity_exceeded(void) {\n    printf(\"Test: push fails when capacity is full\\n\");\n    intpq_t pq = intpq_new();\n    for (int i = 0; i < 8; i++) {\n        assert(intpq_push(&pq, &i));\n    }\n    assert(intpq_size(&pq) == 8);\n    int extra = 99;\n    assert(!intpq_push(&pq, &extra));  // must fail\n    assert(intpq_size(&pq) == 8);\n    intpq_destroy(&pq);\n}\n\nstatic void test_pop_on_empty_returns_false(void) {\n    printf(\"Test: pop on empty queue returns false\\n\");\n    intpq_t pq = intpq_new();\n    int out = 0;\n    assert(!intpq_pop(&pq, &out));\n    intpq_destroy(&pq);\n}\n\nstatic void test_destroy_resets_size(void) {\n    printf(\"Test: destroy resets size to zero\\n\");\n    intpq_t pq = intpq_new();\n    int v = 1;\n    assert(intpq_push(&pq, &v));\n    intpq_destroy(&pq);\n    assert(intpq_size(&pq) == 0);\n    assert(intpq_is_empty(&pq));\n}\n\nstatic void test_duplicate_values(void) {\n    printf(\"Test: duplicate values are handled correctly\\n\");\n    intpq_t pq = intpq_new();\n    int vals[] = {3, 3, 1, 1, 2, 2};\n    for (int i = 0; i < 6; i++) {\n        assert(intpq_push(&pq, &vals[i]));\n    }\n    int out, prev = -1;\n    int count = 0;\n    while (intpq_pop(&pq, &out)) {\n        assert(out >= prev);\n        prev = out;\n        count++;\n    }\n    assert(count == 6);\n    intpq_destroy(&pq);\n}\n\nstatic void test_push_pop_interleaved(void) {\n    printf(\"Test: interleaved push and pop maintains heap property\\n\");\n    intpq_t pq = intpq_new();\n    // Push 3, pop min, push 1, pop min, etc.\n    int vals[] = {5, 3, 8, 1, 4};\n    int expected[] = {3, 1, 4};  // after: push 5,3 pop→3; push 8,1 pop→1; push 4 pop→4\n    int v;\n\n    v = 5;\n    intpq_push(&pq, &v);\n    v = 3;\n    intpq_push(&pq, &v);\n    int out = 0;\n    assert(intpq_pop(&pq, &out) && out == expected[0]);\n\n    v = 8;\n    intpq_push(&pq, &v);\n    v = 1;\n    intpq_push(&pq, &v);\n    assert(intpq_pop(&pq, &out) && out == expected[1]);\n\n    v = 4;\n    intpq_push(&pq, &v);\n    assert(intpq_pop(&pq, &out) && out == expected[2]);\n\n    (void)vals;\n    intpq_destroy(&pq);\n}\n\n// ── Tests: context-aware (max-heap via multiplier = -1) ──────────────────────\n\nstatic void test_ctx_max_heap_order(void) {\n    printf(\"Test (ctx): pop returns elements in descending order (max-heap)\\n\");\n    intpq_cmp_ctx_t ctx;\n    ctx.multiplier = -1;\n    intpq_with_ctx_t pq = intpq_with_ctx_new_with_ctx(&ctx);\n    int vals[] = {5, 1, 8, 3, 2, 7, 4, 6};\n    for (int i = 0; i < 8; i++) {\n        assert(intpq_with_ctx_push(&pq, &vals[i]));\n    }\n    int prev = 9, out = 0;\n    for (int i = 0; i < 8; i++) {\n        assert(intpq_with_ctx_pop(&pq, &out));\n        assert(out < prev);\n        prev = out;\n    }\n    assert(intpq_with_ctx_is_empty(&pq));\n    intpq_with_ctx_destroy(&pq);\n}\n\nstatic void test_ctx_new_zero_init(void) {\n    printf(\"Test (ctx): new() zero-initialises context pointer (min-heap behaviour with NULL ctx)\\n\");\n    // Context-free new() still works when CMP_CTX_TYPE is defined —\n    // the context pointer is NULL.  Since our compare never dereferences a\n    // NULL ctx (it uses the multiplier which is 0 → treats all elements as\n    // equal), the heap doesn't crash; we only verify it doesn't segfault and\n    // that size/empty behave correctly.\n    intpq_with_ctx_t pq = intpq_with_ctx_new();\n    assert(intpq_with_ctx_is_empty(&pq));\n    intpq_with_ctx_destroy(&pq);\n}\n\nstatic void test_ctx_set_ctx(void) {\n    printf(\"Test (ctx): set_ctx switches comparison context on existing queue\\n\");\n    intpq_cmp_ctx_t min_ctx;\n    min_ctx.multiplier = 1;\n    intpq_cmp_ctx_t max_ctx;\n    max_ctx.multiplier = -1;\n\n    // Start as min-heap\n    intpq_with_ctx_t pq = intpq_with_ctx_new_with_ctx(&min_ctx);\n    int vals[] = {4, 2, 6};\n    for (int i = 0; i < 3; i++) intpq_with_ctx_push(&pq, &vals[i]);\n\n    int out = 0;\n    assert(intpq_with_ctx_pop(&pq, &out) && out == 2);  // min first\n\n    // Drain remaining, switch to max-heap, reload\n    intpq_with_ctx_destroy(&pq);\n    intpq_with_ctx_set_ctx(&pq, &max_ctx);\n    for (int i = 0; i < 3; i++) intpq_with_ctx_push(&pq, &vals[i]);\n\n    assert(intpq_with_ctx_pop(&pq, &out) && out == 6);  // max first\n    intpq_with_ctx_destroy(&pq);\n}\n\nint main(void) {\n    // Context-free min-heap tests\n    test_new_is_empty();\n    test_push_pop_single();\n    test_min_heap_order();\n    test_peek_does_not_remove();\n    test_capacity_exceeded();\n    test_pop_on_empty_returns_false();\n    test_destroy_resets_size();\n    test_duplicate_values();\n    test_push_pop_interleaved();\n\n    // Context-aware tests\n    test_ctx_max_heap_order();\n    test_ctx_new_zero_init();\n    test_ctx_set_ctx();\n\n    printf(\"All pqueue tests passed.\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_refcount_test.c",
    "content": "//\n// Copyright (c) 2024 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/refcount.h\"\n#include \"zenoh-pico/system/common/platform.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define FOO_CLEARED_VALUE -1\n\ntypedef struct _dummy_t {\n    int *foo;\n} _dummy_t;\n\nvoid _dummy_clear(_dummy_t *val) {\n    if (val->foo != NULL) {\n        *val->foo = FOO_CLEARED_VALUE;\n    }\n    return;\n}\n\n_Z_REFCOUNT_DEFINE(_dummy, _dummy)\n\ntypedef struct {\n    size_t _strong_cnt;\n    size_t _weak_cnt;\n} _dummy_inner_rc_t;\n\nvoid test_rc_null(void) {\n    _dummy_rc_t drc = _dummy_rc_null();\n    assert(drc._cnt == NULL);\n    assert(drc._val == NULL);\n}\n\nvoid test_rc_size(void) { assert(_dummy_rc_size(NULL) == sizeof(_dummy_rc_t)); }\n\nvoid test_rc_drop(void) {\n    _dummy_rc_t drc = _dummy_rc_null();\n    assert(!_dummy_rc_drop(NULL));\n    assert(!_dummy_rc_drop(&drc));\n}\n\nvoid test_rc_new(void) {\n    int val_foo = 42;\n    _dummy_t *val = (_dummy_t *)z_malloc(sizeof(_dummy_t));\n    val->foo = &val_foo;\n    _dummy_rc_t drc = _dummy_rc_new(val);\n    assert(!_Z_RC_IS_NULL(&drc));\n    assert(_dummy_rc_strong_count(&drc) == 1);\n    assert(_dummy_rc_weak_count(&drc) == 0);\n    assert(*drc._val->foo == 42);\n    *drc._val->foo = 0;\n    assert(*val->foo == 0);\n    assert(_dummy_rc_drop(&drc));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_new_from_val(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc = _dummy_rc_new_from_val(&val);\n    assert(!_Z_RC_IS_NULL(&drc));\n    assert(_dummy_rc_strong_count(&drc) == 1);\n    assert(_dummy_rc_weak_count(&drc) == 0);\n    assert(*drc._val->foo == 42);\n    *drc._val->foo = 0;\n    assert(*val.foo == 0);\n    assert(_dummy_rc_drop(&drc));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_new_undefined(void) {\n    int val_foo = 42;\n    _dummy_rc_t drc = _dummy_rc_new_undefined();\n    assert(!_Z_RC_IS_NULL(&drc));\n    assert(_dummy_rc_strong_count(&drc) == 1);\n    assert(_dummy_rc_weak_count(&drc) == 0);\n    _Z_RC_IN_VAL(&drc)->foo = &val_foo;\n    assert(_dummy_rc_drop(&drc));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_clone(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    assert(_dummy_rc_strong_count(&drc1) == 1);\n    assert(_dummy_rc_weak_count(&drc1) == 0);\n\n    _dummy_rc_t drc2 = _dummy_rc_clone(&drc1);\n    assert(!_Z_RC_IS_NULL(&drc2));\n    assert(_dummy_rc_strong_count(&drc2) == 2);\n    assert(_dummy_rc_weak_count(&drc2) == 0);\n    assert(_dummy_rc_strong_count(&drc2) == _z_rc_strong_count(drc1._cnt));\n    assert(_dummy_rc_weak_count(&drc2) == 0);\n    assert(drc2._val->foo == drc1._val->foo);\n\n    assert(!_dummy_rc_drop(&drc1));\n    assert(_dummy_rc_strong_count(&drc2) == 1);\n    assert(_dummy_rc_weak_count(&drc2) == 0);\n    assert(*drc2._val->foo == 42);\n    assert(_dummy_rc_drop(&drc2));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_eq(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_rc_t drc2 = _dummy_rc_clone(&drc1);\n    assert(_dummy_rc_eq(&drc1, &drc2));\n    assert(!_dummy_rc_drop(&drc1));\n    assert(_dummy_rc_drop(&drc2));\n}\n\nvoid test_rc_clone_as_ptr(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_rc_t *drc2 = _dummy_rc_clone_as_ptr(&drc1);\n    assert(drc2->_val != NULL);\n    assert(!_Z_RC_IS_NULL(drc2));\n    assert(_dummy_rc_strong_count(drc2) == 2);\n    assert(_dummy_rc_weak_count(drc2) == 0);\n    assert(_dummy_rc_eq(&drc1, drc2));\n    assert(!_dummy_rc_drop(&drc1));\n    assert(_dummy_rc_drop(drc2));\n    z_free(drc2);\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_copy(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_rc_t drc2 = _dummy_rc_null();\n    assert(!_dummy_rc_eq(&drc1, &drc2));\n    _dummy_rc_copy(&drc2, &drc1);\n    assert(_dummy_rc_strong_count(&drc2) == 2);\n    assert(_dummy_rc_weak_count(&drc2) == 0);\n    assert(_dummy_rc_eq(&drc1, &drc2));\n    assert(!_dummy_rc_drop(&drc2));\n    assert(_dummy_rc_drop(&drc1));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_clone_as_weak(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_weak_t dwk1 = _dummy_rc_clone_as_weak(&drc1);\n    assert(!_Z_RC_IS_NULL(&dwk1));\n    assert(_dummy_weak_strong_count(&dwk1) == 1);\n    assert(_dummy_weak_weak_count(&dwk1) == 1);\n\n    assert(*dwk1._val->foo == 42);\n    assert(_dummy_rc_drop(&drc1));\n    assert(_dummy_weak_strong_count(&dwk1) == 0);\n    assert(_dummy_weak_weak_count(&dwk1) == 1);\n    assert(_dummy_weak_drop(&dwk1));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_rc_clone_as_weak_ptr(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_weak_t *dwk1 = _dummy_rc_clone_as_weak_ptr(&drc1);\n    assert(dwk1 != NULL);\n    assert(!_Z_RC_IS_NULL(dwk1));\n    assert(_dummy_weak_strong_count(dwk1) == 1);\n    assert(_dummy_weak_weak_count(dwk1) == 1);\n\n    assert(_dummy_rc_drop(&drc1));\n    assert(_dummy_weak_strong_count(dwk1) == 0);\n    assert(_dummy_weak_weak_count(dwk1) == 1);\n    assert(_dummy_weak_drop(dwk1));\n    z_free(dwk1);\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_weak_null(void) {\n    _dummy_weak_t dwk = _dummy_weak_null();\n    assert(dwk._val == NULL);\n    assert(dwk._cnt == NULL);\n}\n\nvoid test_weak_clone(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_weak_t dwk1 = _dummy_rc_clone_as_weak(&drc1);\n    assert(_dummy_weak_strong_count(&dwk1) == 1);\n    assert(_dummy_weak_weak_count(&dwk1) == 1);\n\n    _dummy_weak_t dwk2 = _dummy_weak_clone(&dwk1);\n    assert(_dummy_weak_strong_count(&dwk2) == 1);\n    assert(_dummy_weak_weak_count(&dwk2) == 2);\n\n    assert(_dummy_rc_drop(&drc1));\n    assert(_dummy_weak_strong_count(&dwk2) == 0);\n    assert(_dummy_weak_weak_count(&dwk2) == 2);\n    assert(val_foo == FOO_CLEARED_VALUE);\n\n    assert(_dummy_weak_eq(&dwk1, &dwk2));\n    assert(!_dummy_weak_drop(&dwk2));\n    assert(_dummy_weak_drop(&dwk1));\n}\n\nvoid test_weak_copy(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_weak_t dwk1 = _dummy_rc_clone_as_weak(&drc1);\n    _dummy_weak_t dwk2 = _dummy_weak_null();\n    assert(!_dummy_weak_eq(&dwk1, &dwk2));\n\n    _dummy_weak_copy(&dwk2, &dwk1);\n    assert(_dummy_weak_eq(&dwk1, &dwk2));\n    assert(_dummy_weak_strong_count(&dwk2) == 1);\n    assert(_dummy_weak_weak_count(&dwk2) == 2);\n\n    assert(!_dummy_weak_drop(&dwk1));\n    assert(!_dummy_weak_drop(&dwk2));\n    assert(_dummy_rc_drop(&drc1));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_weak_upgrade(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_weak_t dwk1 = _dummy_rc_clone_as_weak(&drc1);\n\n    // Valid upgrade\n    _dummy_rc_t drc2 = _dummy_weak_upgrade(&dwk1);\n    assert(!_Z_RC_IS_NULL(&drc2));\n    assert(_dummy_rc_strong_count(&drc2) == 2);\n    assert(_dummy_rc_weak_count(&drc2) == 1);\n    assert(!_dummy_rc_drop(&drc1));\n    assert(_dummy_rc_drop(&drc2));\n\n    // Failed upgrade\n    _dummy_rc_t drc3 = _dummy_weak_upgrade(&dwk1);\n    assert(_Z_RC_IS_NULL(&drc3));\n    assert(_dummy_weak_strong_count(&dwk1) == 0);\n    assert(_dummy_weak_weak_count(&dwk1) == 1);\n    assert(_dummy_weak_drop(&dwk1));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_overflow(void) {\n    _dummy_t val = {.foo = NULL};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    // Artificially set weak count to max value\n    _dummy_inner_rc_t *dcnt = (_dummy_inner_rc_t *)drc1._cnt;\n    dcnt->_strong_cnt = INT32_MAX;\n    dcnt->_weak_cnt = INT32_MAX;\n\n    _dummy_rc_t drc2 = _dummy_rc_clone(&drc1);\n    assert(_Z_RC_IS_NULL(&drc2));\n\n    _dummy_weak_t dwk1 = _dummy_rc_clone_as_weak(&drc1);\n    assert(_Z_RC_IS_NULL(&dwk1));\n\n    // Manual free to make asan happy, without long decresing\n    free(drc1._val);\n    free(drc1._cnt);\n}\n\nvoid test_decr(void) {\n    _dummy_t val = {.foo = NULL};\n    _dummy_rc_t drc1 = _dummy_rc_new_from_val(&val);\n    _dummy_rc_t drc2 = _dummy_rc_clone(&drc1);\n    assert(!_dummy_rc_decr(&drc2));\n    assert(_dummy_rc_decr(&drc1));\n    free(drc1._val);\n}\n\n_Z_SIMPLE_REFCOUNT_DEFINE(_dummy, _dummy)\n\nvoid test_simple_rc_null(void) {\n    _dummy_simple_rc_t drc = _dummy_simple_rc_null();\n    assert(drc._val == NULL);\n}\n\nvoid test_simple_rc_size(void) { assert(_dummy_simple_rc_size(NULL) == sizeof(_dummy_simple_rc_t)); }\n\nvoid test_simple_rc_drop(void) {\n    _dummy_simple_rc_t drc = _dummy_simple_rc_null();\n    assert(!_dummy_simple_rc_drop(&drc));\n}\n\nvoid test_simple_rc_new_from_val(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_simple_rc_t drc = _dummy_simple_rc_new_from_val(&val);\n    assert(!_dummy_simple_rc_is_null(&drc));\n    assert(_z_simple_rc_strong_count(drc._val) == 1);\n    assert(*_dummy_simple_rc_value(&drc)->foo == 42);\n    assert(_dummy_simple_rc_drop(&drc));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_simple_rc_clone(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_simple_rc_t drc1 = _dummy_simple_rc_new_from_val(&val);\n    assert(_z_simple_rc_strong_count(drc1._val) == 1);\n\n    _dummy_simple_rc_t drc2 = _dummy_simple_rc_clone(&drc1);\n    assert(!_dummy_simple_rc_is_null(&drc2));\n    assert(_z_simple_rc_strong_count(drc2._val) == 2);\n    assert(_z_simple_rc_strong_count(drc2._val) == _z_simple_rc_strong_count(drc1._val));\n    assert(_dummy_simple_rc_value(&drc2)->foo == _dummy_simple_rc_value(&drc1)->foo);\n\n    assert(!_dummy_simple_rc_drop(&drc1));\n    assert(_z_simple_rc_strong_count(drc2._val) == 1);\n    assert(*_dummy_simple_rc_value(&drc2)->foo == 42);\n    assert(_dummy_simple_rc_drop(&drc2));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_simple_rc_eq(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_simple_rc_t drc1 = _dummy_simple_rc_new_from_val(&val);\n    _dummy_simple_rc_t drc2 = _dummy_simple_rc_clone(&drc1);\n    assert(_dummy_simple_rc_eq(&drc1, &drc2));\n    assert(!_dummy_simple_rc_drop(&drc1));\n    assert(_dummy_simple_rc_drop(&drc2));\n}\n\nvoid test_simple_rc_clone_as_ptr(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_simple_rc_t drc1 = _dummy_simple_rc_new_from_val(&val);\n    _dummy_simple_rc_t *drc2 = _dummy_simple_rc_clone_as_ptr(&drc1);\n    assert(drc2->_val != NULL);\n    assert(!_dummy_simple_rc_is_null(drc2));\n    assert(_dummy_simple_rc_count(drc2) == 2);\n    assert(_dummy_simple_rc_eq(&drc1, drc2));\n    assert(!_dummy_simple_rc_drop(&drc1));\n    assert(_dummy_simple_rc_count(drc2) == 1);\n    assert(_dummy_simple_rc_drop(drc2));\n    z_free(drc2);\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_simple_rc_copy(void) {\n    int val_foo = 42;\n    _dummy_t val = {.foo = &val_foo};\n    _dummy_simple_rc_t drc1 = _dummy_simple_rc_new_from_val(&val);\n    _dummy_simple_rc_t drc2 = _dummy_simple_rc_null();\n    assert(!_dummy_simple_rc_eq(&drc1, &drc2));\n    _dummy_simple_rc_copy(&drc2, &drc1);\n    assert(_dummy_simple_rc_count(&drc2) == 2);\n    assert(_dummy_simple_rc_eq(&drc1, &drc2));\n    assert(!_dummy_simple_rc_drop(&drc2));\n    assert(_dummy_simple_rc_drop(&drc1));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nvoid test_simple_rc_decr(void) {\n    _dummy_t val = {.foo = NULL};\n    _dummy_simple_rc_t drc1 = _dummy_simple_rc_new_from_val(&val);\n    _dummy_simple_rc_t drc2 = _dummy_simple_rc_clone(&drc1);\n    assert(!_dummy_simple_rc_decr(&drc2));\n    assert(_dummy_simple_rc_decr(&drc1));\n    // free manualy, to make asan happy, because counter already zero\n    z_free(drc1._val);\n}\n\nvoid test_as_unsafe_ptr(void) {\n    _dummy_t *val = (_dummy_t *)z_malloc(sizeof(_dummy_t));\n    val->foo = NULL;\n    _dummy_rc_t drc = _dummy_rc_new(val);\n    _dummy_weak_t dweak = _dummy_rc_clone_as_weak(&drc);\n\n    assert(_dummy_weak_as_unsafe_ptr(&dweak) == val);\n\n    assert(_dummy_rc_drop(&drc));\n    assert(_dummy_weak_drop(&dweak));\n}\n\nvoid test_to_void(void) {\n    _dummy_t *val = (_dummy_t *)z_malloc(sizeof(_dummy_t));\n    int val_foo = 42;\n    val->foo = &val_foo;\n    _dummy_rc_t drc = _dummy_rc_new(val);\n    _z_void_rc_t void_rc = _dummy_rc_to_void(&drc);\n    assert(drc._cnt == NULL);\n    assert(drc._val == NULL);\n    assert(_z_void_rc_strong_count(&void_rc) == 1);\n    assert(val_foo == 42);\n    assert(_z_void_rc_drop(&void_rc));\n    assert(val_foo == FOO_CLEARED_VALUE);\n}\n\nint main(void) {\n    test_rc_null();\n    test_rc_size();\n    test_rc_drop();\n    test_rc_new();\n    test_rc_new_from_val();\n    test_rc_new_undefined();\n    test_rc_clone();\n    test_rc_eq();\n    test_rc_clone_as_ptr();\n    test_rc_copy();\n    test_rc_clone_as_weak();\n    test_rc_clone_as_weak_ptr();\n    test_weak_null();\n    test_weak_clone();\n    test_weak_copy();\n    test_weak_upgrade();\n    test_overflow();\n    test_decr();\n    test_as_unsafe_ptr();\n\n    test_simple_rc_null();\n    test_simple_rc_size();\n    test_simple_rc_drop();\n    test_simple_rc_new_from_val();\n    test_simple_rc_clone();\n    test_simple_rc_eq();\n    test_simple_rc_clone_as_ptr();\n    test_simple_rc_copy();\n    test_simple_rc_decr();\n    test_to_void();\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_sync_group_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#if Z_FEATURE_MULTI_THREAD == 1\n\ntypedef struct {\n    _z_sync_group_notifier_t notifier1;\n    _z_sync_group_notifier_t notifier2;\n    size_t val;\n} wait_task_arg_t;\n\nvoid* sync_group_task(void* arg) {\n    wait_task_arg_t* typed = (wait_task_arg_t*)arg;\n    z_sleep_s(3);\n    typed->val += 1;\n    _z_sync_group_notifier_drop(&typed->notifier1);\n    z_sleep_s(3);\n    typed->val += 1;\n    _z_sync_group_notifier_drop(&typed->notifier2);\n    return NULL;\n}\n\nvoid test_sync_group_wait(void) {\n    printf(\"test_sync_group_wait\\n\");\n    _z_sync_group_t g;\n    assert(_z_sync_group_create(&g) == _Z_RES_OK);\n    wait_task_arg_t arg;\n    arg.val = 0;\n    assert(_z_sync_group_create_notifier(&g, &arg.notifier1) == _Z_RES_OK);\n    assert(_z_sync_group_create_notifier(&g, &arg.notifier2) == _Z_RES_OK);\n    _z_task_t task;\n    _z_task_init(&task, NULL, sync_group_task, &arg);\n    assert(_z_sync_group_wait(&g) == _Z_RES_OK);\n    assert(arg.val == 2);\n    _z_sync_group_drop(&g);\n    _z_task_join(&task);\n}\n\nvoid test_sync_group_wait_deadline(void) {\n    printf(\"test_sync_group_wait_deadline\\n\");\n    _z_sync_group_t g;\n    assert(_z_sync_group_create(&g) == Z_OK);\n    wait_task_arg_t arg;\n    arg.val = 0;\n    assert(_z_sync_group_create_notifier(&g, &arg.notifier1) == Z_OK);\n    assert(_z_sync_group_create_notifier(&g, &arg.notifier2) == Z_OK);\n\n    _z_task_t task;\n    _z_task_init(&task, NULL, sync_group_task, &arg);\n\n    z_clock_t c = z_clock_now();\n    z_clock_advance_s(&c, 2);\n    assert(_z_sync_group_wait_deadline(&g, &c) == Z_ETIMEDOUT);\n    z_clock_advance_s(&c, 5);\n    assert(_z_sync_group_wait_deadline(&g, &c) == Z_OK);\n    assert(arg.val == 2);\n    _z_sync_group_drop(&g);\n    _z_task_join(&task);\n}\n\n#endif\nint main(void) {\n#if Z_FEATURE_MULTI_THREAD == 1\n    test_sync_group_wait();\n    test_sync_group_wait_deadline();\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_test_fragment_decode_error_transport_zbuf.c",
    "content": "//\n// Copyright (c) 2026 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"utils/assert_helpers.h\"\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/protocol/codec/transport.h\"\n#include \"zenoh-pico/transport/common/tx.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_FRAGMENTATION == 1 && \\\n    Z_FEATURE_MULTI_THREAD == 0\n\n#define MAX_READS 10\n\nz_result_t _z_transport_message_encode_override(_z_wbuf_t *wbf, const _z_transport_message_t *msg, bool *handled) {\n    z_result_t res = _Z_RES_OK;\n    if (_Z_MID(msg->_header) == _Z_MID_T_FRAGMENT) {\n        res = _z_fragment_encode(wbf, 0, &msg->_body._fragment);\n        if (res < 0) {\n            return res;\n        }\n        *handled = true;\n    }\n    return res;\n}\n\nstatic void dump_zbuf_state(const char *prefix, _z_zbuf_t *zbuf) {\n    printf(\"%s rpos=%d wpos=%d capacity=%d len=%d left=%d\\n\", prefix, (int)_z_zbuf_get_rpos(zbuf),\n           (int)_z_zbuf_get_wpos(zbuf), (int)_z_zbuf_capacity(zbuf), (int)_z_zbuf_len(zbuf),\n           (int)_z_zbuf_space_left(zbuf));\n}\n\n/**\n * Read until sample is received or error occurs.\n *\n * Returns:\n *   _Z_RES_OK if a sample was received\n *   Z_CHANNEL_NODATA if no sample was received and no read error occurred\n *   <0 on zp_read()/z_try_recv() failure\n */\nstatic z_result_t read_until_sample(const z_loaned_session_t *zs, const z_loaned_fifo_handler_sample_t *handler,\n                                    _z_zbuf_t *zbuf, int max_reads) {\n    z_result_t res = _Z_RES_OK;\n    for (int i = 0; i < max_reads; i++) {\n        res = zp_read(zs, NULL);\n        if (res < 0) {\n            printf(\"Failed to read from session: %d\\n\", res);\n            dump_zbuf_state(\"[read error zbuf]\", zbuf);\n            return res;\n        }\n\n        z_owned_sample_t sample;\n        res = z_try_recv(handler, &sample);\n        if (res == Z_CHANNEL_NODATA) {\n            printf(\"No sample received on read iteration %d.\\n\", i);\n            dump_zbuf_state(\"[recv no data zbuf]\", zbuf);\n        } else if (res == _Z_RES_OK) {\n            z_view_string_t keystr;\n            z_keyexpr_as_view_string(z_sample_keyexpr(z_loan(sample)), &keystr);\n            printf(\"[rx] Received packet on %.*s, len: %zu\\n\", (int)z_string_len(z_loan(keystr)),\n                   z_string_data(z_loan(keystr)), z_bytes_len(z_sample_payload(z_loan(sample))));\n            z_drop(z_move(sample));\n            dump_zbuf_state(\"[recv success zbuf]\", zbuf);\n            return res;\n        } else {\n            printf(\"Failed to receive sample: %d\\n\", res);\n            dump_zbuf_state(\"[recv error zbuf]\", zbuf);\n            return res;\n        }\n    }\n\n    return res;\n}\n\nstatic z_result_t publish_buf(const z_loaned_publisher_t *pub, uint8_t *value, size_t size) {\n    z_owned_bytes_t payload;\n    z_result_t res = z_bytes_from_buf(&payload, value, size, NULL, NULL);\n    if (res < 0) {\n        printf(\"Unable to create payload from buffer.\\n\");\n        return res;\n    }\n\n    res = z_publisher_put(pub, z_move(payload), NULL);\n    if (res < 0) {\n        printf(\"Failed to publish sample.\\n\");\n        return res;\n    }\n\n    return _Z_RES_OK;\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n\n    const char *keyexpr = \"test/zenoh-pico-single-thread-fragment\";\n    uint8_t *value = NULL;\n    size_t size = 3000;\n\n    value = z_malloc(size);\n    ASSERT_NOT_NULL(value);\n\n    for (size_t i = 0; i < size; i++) {\n        value[i] = (uint8_t)i;\n    }\n\n    z_owned_config_t c1, c2;\n    z_config_default(&c1);\n    z_config_default(&c2);\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(c1), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    zp_config_insert(z_loan_mut(c2), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n\n    z_owned_session_t s1, s2;\n    ASSERT_OK(z_open(&s1, z_move(c1), NULL));\n    ASSERT_OK(z_open(&s2, z_move(c2), NULL));\n\n    z_owned_closure_sample_t closure;\n    z_owned_fifo_handler_sample_t handler;\n    ASSERT_OK(z_fifo_channel_sample_new(&closure, &handler, 3));\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    ASSERT_OK(z_view_keyexpr_from_str(&ke, keyexpr));\n    ASSERT_OK(z_declare_subscriber(z_loan(s1), &sub, z_loan(ke), z_move(closure), NULL));\n\n    z_owned_publisher_t pub;\n    ASSERT_OK(z_declare_publisher(z_loan(s2), &pub, z_loan(ke), NULL));\n\n    z_sleep_s(1);\n\n    printf(\"[tx]: Sending valid packet on %s, len: %d\\n\", keyexpr, (int)size);\n    ASSERT_OK(publish_buf(z_loan(pub), value, size));\n\n    z_sleep_s(1);\n\n    _z_session_t *session = _Z_RC_IN_VAL(z_loan(s1));\n    _z_zbuf_t *zbuf = &session->_tp._transport._multicast._common._zbuf;\n\n    dump_zbuf_state(\"[initial zbuf]\", zbuf);\n\n    z_result_t res = read_until_sample(z_loan(s1), z_loan(handler), zbuf, MAX_READS);\n    ASSERT_OK(res);\n    dump_zbuf_state(\"[zbuf after sample]\", zbuf);\n    ASSERT_EQ_U32(_z_zbuf_get_rpos(zbuf), _z_zbuf_get_wpos(zbuf));\n\n    _z_transport_set_message_encode_override(_z_transport_message_encode_override);\n\n    printf(\"[tx]: Sending corrupted packet on %s, len: %d\\n\", keyexpr, (int)size);\n    ASSERT_OK(publish_buf(z_loan(pub), value, size));\n\n    z_sleep_s(1);\n\n    res = read_until_sample(z_loan(s1), z_loan(handler), zbuf, MAX_READS);\n    ASSERT_ERR(res, _Z_ERR_MESSAGE_TRANSPORT_UNKNOWN);\n    dump_zbuf_state(\"[zbuf after bad sample]\", zbuf);\n    ASSERT_EQ_U32(_z_zbuf_get_rpos(zbuf), _z_zbuf_get_wpos(zbuf));\n\n    z_drop(z_move(sub));\n    z_drop(z_move(handler));\n    z_drop(z_move(pub));\n    z_drop(z_move(s1));\n    z_drop(z_move(s2));\n    z_free(value);\n    return 0;\n}\n\n#else\n\nint main(void) {\n    printf(\n        \"Missing config token to build this test. This test requires: Z_FEATURE_SUBSCRIPTION=1, \"\n        \"Z_FEATURE_PUBLICATION=1, \"\n        \"Z_FEATURE_FRAGMENTATION=1 and Z_FEATURE_MULTI_THREAD=0\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_test_fragment_rx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\n#if Z_FEATURE_SUBSCRIPTION == 1\nvoid data_handler(z_loaned_sample_t *sample, void *ctx) {\n    (void)(ctx);\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    bool is_valid = true;\n    z_owned_slice_t value;\n    z_bytes_to_slice(z_sample_payload(sample), &value);\n    const uint8_t *data = z_slice_data(z_loan(value));\n    size_t data_len = z_slice_len(z_loan(value));\n    for (size_t i = 0; i < data_len; i++) {\n        if (data[i] != (uint8_t)i) {\n            is_valid = false;\n            break;\n        }\n    }\n    printf(\"[rx]: Received packet on %.*s, len: %d, validity: %d, qos {priority: %d, cong_ctrl: %d}\\n\",\n           (int)z_string_len(z_loan(keystr)), z_string_data(z_loan(keystr)), (int)data_len, is_valid,\n           z_sample_priority(sample), z_sample_congestion_control(sample));\n    z_drop(z_move(value));\n}\n\nint main(int argc, char **argv) {\n    const char *keyexpr = \"test/zenoh-pico-fragment\";\n    const char *mode = NULL;\n    char *llocator = NULL;\n    char *clocator = NULL;\n    (void)argv;\n\n    // Check if peer mode\n    if (argc > 1) {\n        mode = \"peer\";\n        llocator = \"udp/224.0.0.224:7447#iface=lo\";\n    } else {\n        mode = \"client\";\n        clocator = \"tcp/127.0.0.1:7447\";\n    }\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (mode != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n    if (clocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    // Declare subscriber\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, data_handler, NULL, NULL);\n    z_owned_subscriber_t sub;\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, keyexpr);\n    if (z_declare_subscriber(z_loan(s), &sub, z_loan(ke), z_move(callback), NULL) < 0) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return -1;\n    }\n    // Wait for termination\n    char c = '\\0';\n    while (c != 'q') {\n        fflush(stdin);\n        int ret = scanf(\"%c\", &c);\n        (void)ret;  // Remove unused result warning\n    }\n    // Clean up\n    z_drop(z_move(sub));\n    z_drop(z_move(s));\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this test requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "tests/z_test_fragment_tx.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_PUBLICATION == 1\nint main(int argc, char **argv) {\n    const char *keyexpr = \"test/zenoh-pico-fragment\";\n    const char *mode = NULL;\n    char *llocator = NULL;\n    char *clocator = NULL;\n    uint8_t *value = NULL;\n    size_t size = 10000;\n    (void)argv;\n\n    // Init value\n    value = malloc(size);\n    if (value == NULL) {\n        return -1;\n    }\n    for (size_t i = 0; i < size; i++) {\n        value[i] = (uint8_t)i;\n    }\n    // Check if peer or client mode\n    if (argc > 1) {\n        mode = \"peer\";\n        llocator = \"udp/224.0.0.224:7447#iface=lo\";\n    } else {\n        mode = \"client\";\n        clocator = \"tcp/127.0.0.1:7447\";\n    }\n    // Set config\n    z_owned_config_t config;\n    z_config_default(&config);\n    if (mode != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode);\n    }\n    if (llocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator);\n    }\n    if (clocator != NULL) {\n        zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator);\n    }\n    // Open session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) < 0) {\n        printf(\"Unable to open session!\\n\");\n        return -1;\n    }\n    // Wait for joins\n    if (strcmp(mode, \"peer\") == 0) {\n        z_sleep_s(3);\n    }\n    // Put data\n    z_view_keyexpr_t ke;\n    z_view_keyexpr_from_str(&ke, keyexpr);\n\n    z_put_options_t options;\n    z_put_options_default(&options);\n    options.priority = Z_PRIORITY_DATA_HIGH;\n    options.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n\n    for (int i = 0; i < 5; i++) {\n        // Create payload\n        z_owned_bytes_t payload;\n        z_bytes_from_buf(&payload, value, size, NULL, NULL);\n\n        printf(\"[tx]: Sending packet on %s, len: %d\\n\", keyexpr, (int)size);\n        if (z_put(z_loan(s), z_loan(ke), z_move(payload), &options) < 0) {\n            printf(\"Oh no! Put has failed...\\n\");\n            return -1;\n        }\n        z_sleep_s(1);\n    }\n    // Clean up\n    z_drop(z_move(s));\n    free(value);\n    return 0;\n}\n#else\nint main(void) {\n    printf(\"ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this test requires it.\\n\");\n    return -2;\n}\n#endif\n"
  },
  {
    "path": "tests/z_test_peer_multicast.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_QUERY == 1 && Z_FEATURE_QUERYABLE == 1 && \\\n    Z_FEATURE_MULTI_THREAD == 1 && Z_FEATURE_LOCAL_SUBSCRIBER == 0 && defined Z_FEATURE_UNSTABLE_API\ntypedef struct _node_ctx {\n    z_owned_config_t config;\n    const char *keyexpr_out;\n    int id;\n    int sub_msg_nb;\n    int qybl_msg_nb;\n} _node_ctx_t;\n\nconst char *keyexpr_in = \"test/**\";\nconst char *qybl_val = \"Queryable data\";\nconst char *pub_val = \"Publisher data\";\nconst int tx_nb = 5;\nconst int rx_nb = 15;\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    _node_ctx_t *node_ctx = (_node_ctx_t *)ctx;\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable %d] Received ('%.*s': '%.*s')\\n\", node_ctx->id, (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Reply value\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, qybl_val);\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n    node_ctx->qybl_msg_nb++;\n}\n\nvoid pub_handler(z_loaned_sample_t *sample, void *ctx) {\n    _node_ctx_t *node_ctx = (_node_ctx_t *)ctx;\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber %d] Received ('%.*s': '%.*s')\\n\", node_ctx->id, (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    node_ctx->sub_msg_nb++;\n}\n\nvoid *node_task(void *ptr) {\n    _node_ctx_t *ctx = (_node_ctx_t *)ptr;\n\n    // Open session\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(ctx->config), NULL) != Z_OK) {\n        printf(\"Unable to open session!\\n\");\n        return NULL;\n    }\n    // Create keyexprs\n    z_view_keyexpr_t sub_qybl_ke;\n    if (z_view_keyexpr_from_str(&sub_qybl_ke, keyexpr_in) != Z_OK) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr_in);\n        return NULL;\n    }\n    z_view_keyexpr_t pub_qry_ke;\n    if (z_view_keyexpr_from_str(&pub_qry_ke, ctx->keyexpr_out) < 0) {\n        printf(\"%s is not a valid key expression\\n\", ctx->keyexpr_out);\n        return NULL;\n    }\n    // Declare subscriber\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr_in);\n    z_owned_closure_sample_t sub_cb;\n    z_closure(&sub_cb, pub_handler, NULL, ctx);\n    if (z_declare_background_subscriber(z_loan(s), z_loan(sub_qybl_ke), z_move(sub_cb), NULL) != Z_OK) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return NULL;\n    }\n    // Declare queryable\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr_in);\n    z_owned_closure_query_t qybl_cb;\n    z_closure(&qybl_cb, query_handler, NULL, ctx);\n    if (z_declare_background_queryable(z_loan(s), z_loan(sub_qybl_ke), z_move(qybl_cb), NULL) != Z_OK) {\n        printf(\"Unable to create queryable.\\n\");\n        return NULL;\n    }\n    // Declare publisher\n    printf(\"Declaring publisher for '%s'...\\n\", ctx->keyexpr_out);\n    z_owned_publisher_t pub;\n    z_publisher_options_t pub_opts;\n    z_publisher_options_default(&pub_opts);\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    pub_opts.allowed_destination = Z_LOCALITY_REMOTE;\n#endif\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(pub_qry_ke), &pub_opts) != Z_OK) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return NULL;\n    }\n    // Declare querier\n    printf(\"Declaring Querier on '%s'...\\n\", ctx->keyexpr_out);\n    z_owned_querier_t querier;\n    z_querier_options_t qry_opts;\n    z_querier_options_default(&qry_opts);\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    qry_opts.allowed_destination = Z_LOCALITY_REMOTE;\n#endif\n    if (z_declare_querier(z_loan(s), &querier, z_loan(pub_qry_ke), &qry_opts) != Z_OK) {\n        printf(\"Unable to declare Querier for key expression!\\n\");\n        return NULL;\n    }\n    // Wait for other nodes to come online\n    z_sleep_s(5);\n    // Send a join\n    printf(\"Starting sending data\\n\");\n    // Publish data\n    char buf[256];\n    for (int idx = 0; idx < tx_nb; ++idx) {\n        z_sleep_s(1);\n        // Create payload\n        sprintf(buf, \"[%4d] %s\", idx, pub_val);\n        printf(\"[Publisher %d] Sending ('%s': '%s')...\\n\", ctx->id, ctx->keyexpr_out, buf);\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n        // Send data\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n    // Querier data\n    for (int idx = 0; idx < tx_nb; ++idx) {\n        z_sleep_s(1);\n        // Create payload\n        sprintf(buf, \"[%4d] %s\", idx, \"\");\n        printf(\"[Querier %d] Sending ('%s': '%s')...\\n\", ctx->id, ctx->keyexpr_out, buf);\n        // Query data\n        z_owned_fifo_handler_reply_t qry_handler;\n        z_owned_closure_reply_t qry_closure;\n        z_fifo_channel_reply_new(&qry_closure, &qry_handler, 16);\n        z_querier_get(z_loan(querier), NULL, z_move(qry_closure), NULL);\n        // Process received data\n        z_owned_reply_t reply;\n        for (z_result_t res = z_recv(z_loan(qry_handler), &reply); res == Z_OK;\n             res = z_recv(z_loan(qry_handler), &reply)) {\n            if (z_reply_is_ok(z_loan(reply))) {\n                const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n                z_view_string_t keystr;\n                z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n                z_owned_string_t replystr;\n                z_bytes_to_string(z_sample_payload(sample), &replystr);\n                printf(\">> [Query %d] Received ('%.*s': '%.*s')\\n\", ctx->id, (int)z_string_len(z_loan(keystr)),\n                       z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(replystr)),\n                       z_string_data(z_loan(replystr)));\n                z_drop(z_move(replystr));\n            }\n            z_drop(z_move(reply));\n        }\n        z_drop(z_move(qry_handler));\n    }\n    // Wait for sub & queryable data\n    z_sleep_s(5);\n    assert(ctx->sub_msg_nb >= rx_nb);\n    assert(ctx->qybl_msg_nb >= rx_nb);\n    // Clean up\n    z_drop(z_move(pub));\n    z_drop(z_move(querier));\n    z_drop(z_move(s));\n    return NULL;\n}\n\nstatic void test_packet_transmission(void) {\n    // Create node context\n    _node_ctx_t node_ctx_0 = {.keyexpr_out = \"test/A\", .id = 0, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    _node_ctx_t node_ctx_1 = {.keyexpr_out = \"test/B\", .id = 1, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    _node_ctx_t node_ctx_2 = {.keyexpr_out = \"test/C\", .id = 2, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    _node_ctx_t node_ctx_3 = {.keyexpr_out = \"test/D\", .id = 3, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    // Init config\n    z_config_default(&node_ctx_0.config);\n    z_config_default(&node_ctx_1.config);\n    z_config_default(&node_ctx_2.config);\n    z_config_default(&node_ctx_3.config);\n    // Fill config\n    zp_config_insert(z_loan_mut(node_ctx_0.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_0.config), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    zp_config_insert(z_loan_mut(node_ctx_1.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_1.config), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    zp_config_insert(z_loan_mut(node_ctx_2.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_2.config), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    zp_config_insert(z_loan_mut(node_ctx_3.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_3.config), Z_CONFIG_LISTEN_KEY, \"udp/224.0.0.224:7447#iface=lo\");\n    // Init threads in a staggered manner to let time for sockets to establish\n    _z_task_t task0, task1, task2, task3;\n    _z_task_init(&task0, NULL, node_task, &node_ctx_0);\n    z_sleep_ms(100);\n    _z_task_init(&task1, NULL, node_task, &node_ctx_1);\n    z_sleep_ms(100);\n    _z_task_init(&task2, NULL, node_task, &node_ctx_2);\n    z_sleep_ms(100);\n    _z_task_init(&task3, NULL, node_task, &node_ctx_3);\n    // Wait a bit\n    z_sleep_s(20);\n    // Clean up\n    _z_task_join(&task0);\n    _z_task_join(&task1);\n    _z_task_join(&task2);\n    _z_task_join(&task3);\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_packet_transmission();\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\n        \"Missing config token to build this test. This test requires: Z_FEATURE_SUBSCRIPTION, Z_FEATURE_PUBLICATION, \"\n        \"Z_FEATURE_QUERY, Z_FEATURE_QUERYABLE, Z_FEATURE_MULTI_THREAD and \"\n        \"Z_FEATURE_UNSTABLE_API (until querier becomes stable)\\n\");\n    printf(\"It also requires Z_FEATURE_LOCAL_SUBSCRIBER to be deactivated\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_test_peer_unicast.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_SUBSCRIPTION == 1 && Z_FEATURE_PUBLICATION == 1 && Z_FEATURE_QUERY == 1 && Z_FEATURE_QUERYABLE == 1 && \\\n    Z_FEATURE_MULTI_THREAD == 1 && Z_FEATURE_LOCAL_SUBSCRIBER == 0 && Z_FEATURE_UNICAST_PEER == 1 &&                 \\\n    defined Z_FEATURE_UNSTABLE_API\ntypedef struct _node_ctx {\n    z_owned_config_t config;\n    const char *keyexpr_out;\n    int id;\n    int sub_msg_nb;\n    int qybl_msg_nb;\n} _node_ctx_t;\n\nconst char *keyexpr_in = \"test/**\";\nconst char *qybl_val = \"Queryable data\";\nconst char *pub_val = \"Publisher data\";\nconst int tx_nb = 5;\nconst int rx_nb = 15;\n\nvoid query_handler(z_loaned_query_t *query, void *ctx) {\n    _node_ctx_t *node_ctx = (_node_ctx_t *)ctx;\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_query_keyexpr(query), &keystr);\n    z_view_string_t params;\n    z_query_parameters(query, &params);\n    printf(\" >> [Queryable %d] Received ('%.*s': '%.*s')\\n\", node_ctx->id, (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(params)), z_string_data(z_loan(params)));\n    // Reply value\n    z_owned_bytes_t reply_payload;\n    z_bytes_from_static_str(&reply_payload, qybl_val);\n    z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), NULL);\n    node_ctx->qybl_msg_nb++;\n}\n\nvoid pub_handler(z_loaned_sample_t *sample, void *ctx) {\n    _node_ctx_t *node_ctx = (_node_ctx_t *)ctx;\n    z_view_string_t keystr;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n    z_owned_string_t value;\n    z_bytes_to_string(z_sample_payload(sample), &value);\n    printf(\">> [Subscriber %d] Received ('%.*s': '%.*s')\\n\", node_ctx->id, (int)z_string_len(z_loan(keystr)),\n           z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(value)), z_string_data(z_loan(value)));\n    z_drop(z_move(value));\n    node_ctx->sub_msg_nb++;\n}\n\nvoid *node_task(void *ptr) {\n    _node_ctx_t *ctx = (_node_ctx_t *)ptr;\n\n    // Open session\n    printf(\"Opening session...\\n\");\n    z_owned_session_t s;\n    if (z_open(&s, z_move(ctx->config), NULL) != Z_OK) {\n        printf(\"Unable to open session!\\n\");\n        return NULL;\n    }\n    // Create keyexprs\n    z_view_keyexpr_t sub_qybl_ke;\n    if (z_view_keyexpr_from_str(&sub_qybl_ke, keyexpr_in) != Z_OK) {\n        printf(\"%s is not a valid key expression\\n\", keyexpr_in);\n        return NULL;\n    }\n    z_view_keyexpr_t pub_qry_ke;\n    if (z_view_keyexpr_from_str(&pub_qry_ke, ctx->keyexpr_out) < 0) {\n        printf(\"%s is not a valid key expression\\n\", ctx->keyexpr_out);\n        return NULL;\n    }\n    // Declare subscriber\n    printf(\"Declaring Subscriber on '%s'...\\n\", keyexpr_in);\n    z_owned_closure_sample_t sub_cb;\n    z_closure(&sub_cb, pub_handler, NULL, ctx);\n    if (z_declare_background_subscriber(z_loan(s), z_loan(sub_qybl_ke), z_move(sub_cb), NULL) != Z_OK) {\n        printf(\"Unable to declare subscriber.\\n\");\n        return NULL;\n    }\n    // Declare queryable\n    printf(\"Creating Queryable on '%s'...\\n\", keyexpr_in);\n    z_owned_closure_query_t qybl_cb;\n    z_closure(&qybl_cb, query_handler, NULL, ctx);\n    if (z_declare_background_queryable(z_loan(s), z_loan(sub_qybl_ke), z_move(qybl_cb), NULL) != Z_OK) {\n        printf(\"Unable to create queryable.\\n\");\n        return NULL;\n    }\n    // Declare publisher\n    printf(\"Declaring publisher for '%s'...\\n\", ctx->keyexpr_out);\n    z_owned_publisher_t pub;\n    z_publisher_options_t pub_opts;\n    z_publisher_options_default(&pub_opts);\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    pub_opts.allowed_destination = Z_LOCALITY_REMOTE;\n#endif\n    if (z_declare_publisher(z_loan(s), &pub, z_loan(pub_qry_ke), &pub_opts) != Z_OK) {\n        printf(\"Unable to declare publisher for key expression!\\n\");\n        return NULL;\n    }\n    // Declare querier\n    printf(\"Declaring Querier on '%s'...\\n\", ctx->keyexpr_out);\n    z_owned_querier_t querier;\n    z_querier_options_t qry_opts;\n    z_querier_options_default(&qry_opts);\n#if Z_FEATURE_LOCAL_QUERYABLE == 1\n    qry_opts.allowed_destination = Z_LOCALITY_REMOTE;\n#endif\n    if (z_declare_querier(z_loan(s), &querier, z_loan(pub_qry_ke), &qry_opts) != Z_OK) {\n        printf(\"Unable to declare Querier for key expression!\\n\");\n        return NULL;\n    }\n    // Wait for other nodes to come online\n    z_sleep_s(5);\n    printf(\"Starting sending data\\n\");\n    // Publish data\n    char buf[256];\n    for (int idx = 0; idx < tx_nb; ++idx) {\n        z_sleep_s(1);\n        // Create payload\n        sprintf(buf, \"[%4d] %s\", idx, pub_val);\n        printf(\"[Publisher %d] Sending ('%s': '%s')...\\n\", ctx->id, ctx->keyexpr_out, buf);\n        z_owned_bytes_t payload;\n        z_bytes_copy_from_str(&payload, buf);\n        // Send data\n        z_publisher_put(z_loan(pub), z_move(payload), NULL);\n    }\n    // Querier data\n    for (int idx = 0; idx < tx_nb; ++idx) {\n        z_sleep_s(1);\n        // Create payload\n        sprintf(buf, \"[%4d] %s\", idx, \"\");\n        printf(\"[Querier %d] Sending ('%s': '%s')...\\n\", ctx->id, ctx->keyexpr_out, buf);\n        // Query data\n        z_owned_fifo_handler_reply_t qry_handler;\n        z_owned_closure_reply_t qry_closure;\n        z_fifo_channel_reply_new(&qry_closure, &qry_handler, 16);\n        z_querier_get(z_loan(querier), NULL, z_move(qry_closure), NULL);\n        // Process received data\n        z_owned_reply_t reply;\n        for (z_result_t res = z_recv(z_loan(qry_handler), &reply); res == Z_OK;\n             res = z_recv(z_loan(qry_handler), &reply)) {\n            if (z_reply_is_ok(z_loan(reply))) {\n                const z_loaned_sample_t *sample = z_reply_ok(z_loan(reply));\n                z_view_string_t keystr;\n                z_keyexpr_as_view_string(z_sample_keyexpr(sample), &keystr);\n                z_owned_string_t replystr;\n                z_bytes_to_string(z_sample_payload(sample), &replystr);\n                printf(\">> [Query %d] Received ('%.*s': '%.*s')\\n\", ctx->id, (int)z_string_len(z_loan(keystr)),\n                       z_string_data(z_loan(keystr)), (int)z_string_len(z_loan(replystr)),\n                       z_string_data(z_loan(replystr)));\n                z_drop(z_move(replystr));\n            }\n            z_drop(z_move(reply));\n        }\n        z_drop(z_move(qry_handler));\n    }\n    // Wait for sub & queryable data\n    z_sleep_s(5);\n    printf(\"Node %d: Received %d subs, %d queries\\n\", ctx->id, ctx->sub_msg_nb, ctx->qybl_msg_nb);\n    assert(ctx->sub_msg_nb >= rx_nb);\n    assert(ctx->qybl_msg_nb >= rx_nb);\n    // Clean up\n    z_drop(z_move(pub));\n    z_drop(z_move(querier));\n    z_drop(z_move(s));\n    return NULL;\n}\n\nstatic void test_packet_transmission(void) {\n    // Create node context\n    _node_ctx_t node_ctx_0 = {.keyexpr_out = \"test/A\", .id = 0, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    _node_ctx_t node_ctx_1 = {.keyexpr_out = \"test/B\", .id = 1, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    _node_ctx_t node_ctx_2 = {.keyexpr_out = \"test/C\", .id = 2, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    _node_ctx_t node_ctx_3 = {.keyexpr_out = \"test/D\", .id = 3, .qybl_msg_nb = 0, .sub_msg_nb = 0};\n    // Init config\n    z_config_default(&node_ctx_0.config);\n    z_config_default(&node_ctx_1.config);\n    z_config_default(&node_ctx_2.config);\n    z_config_default(&node_ctx_3.config);\n    // Fill config\n    zp_config_insert(z_loan_mut(node_ctx_0.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_0.config), Z_CONFIG_LISTEN_KEY, \"tcp/127.0.0.1:7447\");\n    zp_config_insert(z_loan_mut(node_ctx_1.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_1.config), Z_CONFIG_LISTEN_KEY, \"tcp/127.0.0.1:7448\");\n    zp_config_insert(z_loan_mut(node_ctx_1.config), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7447\");\n    zp_config_insert(z_loan_mut(node_ctx_2.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_2.config), Z_CONFIG_LISTEN_KEY, \"tcp/127.0.0.1:7449\");\n    zp_config_insert(z_loan_mut(node_ctx_2.config), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7447\");\n    zp_config_insert(z_loan_mut(node_ctx_2.config), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7448\");\n    zp_config_insert(z_loan_mut(node_ctx_3.config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(node_ctx_3.config), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7447\");\n    zp_config_insert(z_loan_mut(node_ctx_3.config), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7448\");\n    zp_config_insert(z_loan_mut(node_ctx_3.config), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7449\");\n    // Init threads in a staggered manner to let time for sockets to establish\n    _z_task_t task0, task1, task2, task3;\n    _z_task_init(&task0, NULL, node_task, &node_ctx_0);\n    z_sleep_ms(100);\n    _z_task_init(&task1, NULL, node_task, &node_ctx_1);\n    z_sleep_ms(100);\n    _z_task_init(&task2, NULL, node_task, &node_ctx_2);\n    z_sleep_ms(100);\n    _z_task_init(&task3, NULL, node_task, &node_ctx_3);\n    // Wait a bit\n    z_sleep_s(30);\n    // Clean up\n    _z_task_join(&task0);\n    _z_task_join(&task1);\n    _z_task_join(&task2);\n    _z_task_join(&task3);\n}\n\nstatic bool test_peer_connection(void) {\n    // Init config\n    z_owned_config_t config;\n    z_config_default(&config);\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, \"tcp/127.0.0.1:7447\");\n    // Open main session\n    z_owned_session_t s;\n    if (z_open(&s, z_move(config), NULL) != Z_OK) {\n        printf(\"Unable to open main session!\\n\");\n        return false;\n    }\n    z_owned_session_t sess_array[Z_LISTEN_MAX_CONNECTION_NB + 1];\n    z_owned_config_t cfg_array[Z_LISTEN_MAX_CONNECTION_NB + 1];\n    // // Open max peers\n    for (int i = 0; i < Z_LISTEN_MAX_CONNECTION_NB; i++) {\n        z_config_default(&cfg_array[i]);\n        zp_config_insert(z_loan_mut(cfg_array[i]), Z_CONFIG_MODE_KEY, \"peer\");\n        zp_config_insert(z_loan_mut(cfg_array[i]), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7447\");\n        if (z_open(&sess_array[i], z_move(cfg_array[i]), NULL) != Z_OK) {\n            printf(\"Unable to open peer session!\\n\");\n            return false;\n        }\n        z_sleep_ms(100);\n    }\n    // Fail to open a new one\n    z_config_default(&cfg_array[Z_LISTEN_MAX_CONNECTION_NB]);\n    zp_config_insert(z_loan_mut(cfg_array[Z_LISTEN_MAX_CONNECTION_NB]), Z_CONFIG_MODE_KEY, \"peer\");\n    zp_config_insert(z_loan_mut(cfg_array[Z_LISTEN_MAX_CONNECTION_NB]), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7447\");\n    if (z_open(&sess_array[Z_LISTEN_MAX_CONNECTION_NB], z_move(cfg_array[Z_LISTEN_MAX_CONNECTION_NB]), NULL) == Z_OK) {\n        printf(\"Should not have been able to open this session\\n\");\n        return false;\n    }\n    // Close first session\n    z_drop(z_move(sess_array[0]));\n    z_sleep_ms(100);\n    // Alternate opening and closing first session a few times\n    for (int i = 0; i < 5; i++) {\n        z_config_default(&cfg_array[0]);\n        zp_config_insert(z_loan_mut(cfg_array[0]), Z_CONFIG_MODE_KEY, \"peer\");\n        zp_config_insert(z_loan_mut(cfg_array[0]), Z_CONFIG_CONNECT_KEY, \"tcp/127.0.0.1:7447\");\n        if (z_open(&sess_array[0], z_move(cfg_array[0]), NULL) != Z_OK) {\n            printf(\"Unable to open peer session!\\n\");\n            return false;\n        }\n        z_sleep_ms(100);\n        z_drop(z_move(sess_array[0]));\n        z_sleep_ms(100);\n    }\n    for (size_t i = 0; i < _ZP_ARRAY_SIZE(sess_array); i++) {\n        z_drop(z_move(sess_array[i]));\n    }\n    z_drop(z_move(s));\n    return true;\n}\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    test_packet_transmission();\n    printf(\"Test connections...\");\n    if (!test_peer_connection()) {\n        return -1;\n    }\n    printf(\" Ok\\n\");\n    return 0;\n}\n\n#else\n\nint main(int argc, char **argv) {\n    (void)argc;\n    (void)argv;\n    printf(\n        \"Missing config token to build this test. This test requires: Z_FEATURE_SUBSCRIPTION, Z_FEATURE_PUBLICATION, \"\n        \"Z_FEATURE_QUERY, Z_FEATURE_QUERYABLE, Z_FEATURE_MULTI_THREAD, Z_FEATURE_UNICAST_PEER and \"\n        \"Z_FEATURE_UNSTABLE_API (until querier becomes stable)\\n\");\n    printf(\"It also requires Z_FEATURE_LOCAL_SUBSCRIBER to be deactivated\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_tls_config_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <assert.h>\n#include <errno.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n\n#if Z_FEATURE_LINK_TLS == 1\n\n#include \"mbedtls/base64.h\"\n\nstatic const char SERVER_CA_PEM[] =\n    \"-----BEGIN CERTIFICATE-----\\n\"\n    \"MIIDSzCCAjOgAwIBAgIITcwv1N10nqEwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE\\n\"\n    \"AxMVbWluaWNhIHJvb3QgY2EgNGRjYzJmMCAXDTIzMDMwNjE2NDEwNloYDzIxMjMw\\n\"\n    \"MzA2MTY0MTA2WjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSA0ZGNjMmYwggEi\\n\"\n    \"MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2WUgN7NMlXIknew1cXiTWGmS0\\n\"\n    \"1T1EjcNNDAq7DqZ7/ZVXrjD47yxTt5EOiOXK/cINKNw4Zq/MKQvq9qu+Oax4lwiV\\n\"\n    \"Ha0i8ShGLSuYI1HBlXu4MmvdG+3/SjwYoGsGaShr0y/QGzD3cD+DQZg/RaaIPHlO\\n\"\n    \"MdmiUXxkMcy4qa0hFJ1imlJdq/6Tlx46X+0vRCh8nkekvOZR+t7Z5U4jn4XE54Kl\\n\"\n    \"0PiwcyX8vfDZ3epa/FSHZvVQieM/g5Yh9OjIKCkdWRg7tD0IEGsaW11tEPJ5SiQr\\n\"\n    \"mDqdRneMzZKqY0xC+QqXSvIlzpOjiu8PYQx7xugaUFE/npKRQdvh8ojHJMdNAgMB\\n\"\n    \"AAGjgYYwgYMwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr\\n\"\n    \"BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTX46+p+Po1npE6\\n\"\n    \"QLQ7mMI+83s6qDAfBgNVHSMEGDAWgBTX46+p+Po1npE6QLQ7mMI+83s6qDANBgkq\\n\"\n    \"hkiG9w0BAQsFAAOCAQEAaN0IvEC677PL/JXzMrXcyBV88IvimlYN0zCt48GYlhmx\\n\"\n    \"vL1YUDFLJEB7J+dyERGE5N6BKKDGblC4WiTFgDMLcHFsMGRc0v7zKPF1PSBwRYJi\\n\"\n    \"ubAmkwdunGG5pDPUYtTEDPXMlgClZ0YyqSFJMOqA4IzQg6exVjXtUxPqzxNhyC7S\\n\"\n    \"vlgUwPbX46uNi581a9+Ls2V3fg0ZnhkTSctYZHGZNeh0Nsf7Am8xdUDYG/bZcVef\\n\"\n    \"jbQ9gpChosdjF0Bgblo7HSUct/2Va+YlYwW+WFjJX8k4oN6ZU5W5xhdfO8Czmgwk\\n\"\n    \"US5kJ/+1M0uR8zUhZHL61FbsdPxEj+fYKrHv4woo+A==\\n\"\n    \"-----END CERTIFICATE-----\\n\";\n\nstatic const char SERVER_CERT_PEM[] =\n    \"-----BEGIN CERTIFICATE-----\\n\"\n    \"MIIDLjCCAhagAwIBAgIIW1mAtJWJAJYwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE\\n\"\n    \"AxMVbWluaWNhIHJvb3QgY2EgNGRjYzJmMCAXDTIzMDMwNjE2NDEwNloYDzIxMjMw\\n\"\n    \"MzA2MTY0MTA2WjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\\n\"\n    \"AQUAA4IBDwAwggEKAoIBAQCYMLJKooc+YRlKEMfeV09pX9myH34eUcUuT0fXS8lm\\n\"\n    \"PlZ/NW7mm5lDwa8EUg61WuXQv2ouQDptmIcdeb/w4RW93Xflkyng1Xbd91OwQBJd\\n\"\n    \"+8ZVBjzL7hSRk3QPDqx/CVBU/I1GmXKzb6cWzq1fTkOn1WLNXf21I6p7+N3qHLPF\\n\"\n    \"JQeoVq1HBBFcAjTgJnpyQNvRGLDuLTK+OsWEGib2U8qrgiRdkaBLkxGXSlGABlOo\\n\"\n    \"cQyW/zOhf4pwb2Z/JAge2mRW5IcexCPBWint8ydPsoJDds8j5+AyYCD6HUhHX0Ob\\n\"\n    \"Qkz73OW7f2PQhuTK2uzKy0Yz6lNFt2nuzaWC04wIW3T7AgMBAAGjdjB0MA4GA1Ud\\n\"\n    \"DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T\\n\"\n    \"AQH/BAIwADAfBgNVHSMEGDAWgBTX46+p+Po1npE6QLQ7mMI+83s6qDAUBgNVHREE\\n\"\n    \"DTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAAxrmQPG54ybKgMVliN8\\n\"\n    \"Mg5povSdPIVVnlU/HOVG9yxzAOav/xQP003M4wqpatWxI8tR1PcLuZf0EPmcdJgb\\n\"\n    \"tVl9nZMVZtveQnYMlU8PpkEVu56VM4Zr3rH9liPRlr0JEAXODdKw76kWKzmdqWZ/\\n\"\n    \"rzhup3Ek7iEX6T5j/cPUvTWtMD4VEK2I7fgoKSHIX8MIVzqM7cuboGWPtS3eRNXl\\n\"\n    \"MgvahA4TwLEXPEe+V1WAq6nSb4g2qSXWIDpIsy/O1WGS/zzRnKvXu9/9NkXWqZMl\\n\"\n    \"C1LSpiiQUaRSglOvYf/Zx6r+4BOS4OaaArwHkecZQqBSCcBLEAyb/FaaXdBowI0U\\n\"\n    \"PQ4=\\n\"\n    \"-----END CERTIFICATE-----\\n\";\n\nstatic const char SERVER_KEY_PEM[] =\n    \"-----BEGIN RSA PRIVATE KEY-----\\n\"\n    \"MIIEpAIBAAKCAQEAmDCySqKHPmEZShDH3ldPaV/Zsh9+HlHFLk9H10vJZj5WfzVu\\n\"\n    \"5puZQ8GvBFIOtVrl0L9qLkA6bZiHHXm/8OEVvd135ZMp4NV23fdTsEASXfvGVQY8\\n\"\n    \"y+4UkZN0Dw6sfwlQVPyNRplys2+nFs6tX05Dp9VizV39tSOqe/jd6hyzxSUHqFat\\n\"\n    \"RwQRXAI04CZ6ckDb0Riw7i0yvjrFhBom9lPKq4IkXZGgS5MRl0pRgAZTqHEMlv8z\\n\"\n    \"oX+KcG9mfyQIHtpkVuSHHsQjwVop7fMnT7KCQ3bPI+fgMmAg+h1IR19Dm0JM+9zl\\n\"\n    \"u39j0IbkytrsystGM+pTRbdp7s2lgtOMCFt0+wIDAQABAoIBADNTSO2uvlmlOXgn\\n\"\n    \"DKDJZTiuYKaXxFrJTOx/REUxg+x9XYJtLMeM9jVJnpKgceFrlFHAHDkY5BuN8xNX\\n\"\n    \"ugmsfz6W8BZ2eQsgMoRNIuYv1YHopUyLW/mSg1FNHzjsw/Pb2kGvIp4Kpgopv3oL\\n\"\n    \"naCkrmBtsHJ+Hk/2hUpl9cE8iMwVWcVevLzyHi98jNy1IDdIPhRtl0dhMiqC5MRr\\n\"\n    \"4gLJ5gNkLYX7xf3tw5Hmfk/bVNProqZXDIQVI7rFvItX586nvQ3LNQkmW/D2ShZf\\n\"\n    \"3FEqMu6EdA2Ycc4UZgAlQNGV0VBrWWVXizOQ+9gjLnBk3kJjqfigCU6NG94bTJ+H\\n\"\n    \"0YIhsGECgYEAwdSSyuMSOXgzZQ7Vv+GsNn/7ivi/H8eb/lDzksqS/JroA2ciAmHG\\n\"\n    \"2OF30eUJKRg+STqBTpOfXgS4QUa8QLSwBSnwcw6579x9bYGUhqD2Ypaw9uCnOukA\\n\"\n    \"CwwggZ9cDmF0tb5rYjqkW3bFPqkCnTGb0ylMFaYRhRDU20iG5t8PQckCgYEAyQEM\\n\"\n    \"KK18FLQUKivGrQgP5Ib6IC3myzlHGxDzfobXGpaQntFnHY7Cxp/6BBtmASzt9Jxu\\n\"\n    \"etnrevmzrbKqsLTJSg3ivbiq0YTLAJ1FsZrCp71dx49YR/5o9QFiq0nQoKnwUVeb\\n\"\n    \"/hrDjMAokNkjFL5vouXO711GSS6YyM4WzAKZAqMCgYEAhqGxaG06jmJ4SFx6ibIl\\n\"\n    \"nSFeRhQrJNbP+mCeHrrIR98NArgS/laN+Lz7LfaJW1r0gIa7pCmTi4l5thV80vDu\\n\"\n    \"RlfwJOr4qaucD4Du+mg5WxdSSdiXL6sBlarRtVdMaMy2dTqTegJDgShJLxHTt/3q\\n\"\n    \"P0yzBWJ5TtT3FG0XDqum/EkCgYAYNHwWWe3bQGQ9P9BI/fOL/YUZYu2sA1XAuKXZ\\n\"\n    \"0rsMhJ0dwvG76XkjGhitbe82rQZqsnvLZ3qn8HHmtOFBLkQfGtT3K8nGOUuI42eF\\n\"\n    \"H7HZKUCly2lCIizZdDVBkz4AWvaJlRc/3lE2Hd3Es6E52kTvROVKhdz06xuS8t5j\\n\"\n    \"6twqKQKBgQC01AeiWL6Rzo+yZNzVgbpeeDogaZz5dtmURDgCYH8yFX5eoCKLHfnI\\n\"\n    \"2nDIoqpaHY0LuX+dinuH+jP4tlyndbc2muXnHd9r0atytxA69ay3sSA5WFtfi4ef\\n\"\n    \"ESElGO6qXEA821RpQp+2+uhL90+iC294cPqlS5LDmvTMypVDHzrxPQ==\\n\"\n    \"-----END RSA PRIVATE KEY-----\\n\";\n\nstatic char *encode_base64_strdup(const char *input) {\n    if (input == NULL) {\n        return NULL;\n    }\n    size_t input_len = strnlen(input, 64 * 1024);\n    size_t output_len = 0;\n    int rc = mbedtls_base64_encode(NULL, 0, &output_len, (const unsigned char *)input, input_len);\n    assert(rc == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL);\n\n    unsigned char *buffer = (unsigned char *)malloc(output_len + 1);\n    assert(buffer != NULL);\n\n    rc = mbedtls_base64_encode(buffer, output_len, &output_len, (const unsigned char *)input, input_len);\n    if (rc != 0) {\n        fprintf(stderr, \"mbedtls_base64_encode(data) failed: %d\\n\", rc);\n        free(buffer);\n        return NULL;\n    }\n    buffer[output_len] = '\\0';\n    return (char *)buffer;\n}\n\nstatic volatile bool g_received = false;\n\nstatic void tls_sample_handler(z_loaned_sample_t *sample, void *ctx) {\n    const char *expected = (const char *)ctx;\n    // flawfinder: ignore[CWE-126]\n    size_t expected_len = expected ? strlen(expected) : 0;\n\n    z_owned_string_t payload;\n    if (z_bytes_to_string(z_sample_payload(sample), &payload) != Z_OK) {\n        fprintf(stderr, \"subscriber: failed to decode payload\\n\");\n        return;\n    }\n    size_t payload_len = z_string_len(z_loan(payload));\n    if (expected_len != payload_len || memcmp(expected, z_string_data(z_loan(payload)), expected_len) != 0) {\n        fprintf(stderr, \"subscriber: unexpected payload\\n\");\n        z_drop(z_move(payload));\n        return;\n    }\n\n    g_received = true;\n    z_drop(z_move(payload));\n}\n\nint main(void) {\n    char locator_buf[64];\n    snprintf(locator_buf, sizeof(locator_buf), \"tls/127.0.0.1:7447\");\n    const char *locator = locator_buf;\n    static const char *const keyexpr_str = \"test/tls/config\";\n    static const char *const payload_str = \"tls-config-ok\";\n\n    char *ca_base64 = encode_base64_strdup(SERVER_CA_PEM);\n    char *cert_base64 = encode_base64_strdup(SERVER_CERT_PEM);\n    char *key_base64 = encode_base64_strdup(SERVER_KEY_PEM);\n    if (ca_base64 == NULL || cert_base64 == NULL || key_base64 == NULL) {\n        fprintf(stderr, \"failed to prepare TLS credentials\\n\");\n        goto cleanup_buffers;\n    }\n\n    z_owned_config_t listen_cfg;\n    z_config_default(&listen_cfg);\n    zp_config_insert(z_loan_mut(listen_cfg), Z_CONFIG_MODE_KEY, Z_CONFIG_MODE_PEER);\n    zp_config_insert(z_loan_mut(listen_cfg), Z_CONFIG_LISTEN_KEY, locator);\n    zp_config_insert(z_loan_mut(listen_cfg), Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY, ca_base64);\n    zp_config_insert(z_loan_mut(listen_cfg), Z_CONFIG_TLS_LISTEN_CERTIFICATE_BASE64_KEY, cert_base64);\n    zp_config_insert(z_loan_mut(listen_cfg), Z_CONFIG_TLS_LISTEN_PRIVATE_KEY_BASE64_KEY, key_base64);\n\n    z_owned_session_t server;\n    z_result_t res = z_open(&server, z_move(listen_cfg), NULL);\n    if (res != Z_OK) {\n        fprintf(stderr, \"server z_open failed: %d\\n\", res);\n        return 1;\n    }\n    (void)z_sleep_ms(50);\n\n    z_view_keyexpr_t keyexpr;\n    if (z_view_keyexpr_from_str(&keyexpr, keyexpr_str) != Z_OK) {\n        fprintf(stderr, \"failed to create keyexpr view\\n\");\n        goto cleanup_server;\n    }\n\n    z_owned_closure_sample_t callback;\n    z_closure(&callback, tls_sample_handler, NULL, (void *)payload_str);\n    z_owned_subscriber_t subscriber;\n    z_internal_null(&subscriber);\n    z_subscriber_options_t sub_opts;\n    z_subscriber_options_default(&sub_opts);\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    sub_opts.allowed_origin = Z_LOCALITY_ANY;\n#endif\n    if (z_declare_subscriber(z_loan(server), &subscriber, z_loan(keyexpr), z_move(callback), &sub_opts) != Z_OK) {\n        fprintf(stderr, \"server: failed to declare subscriber\\n\");\n        goto cleanup_server;\n    }\n\n    z_owned_config_t connect_cfg;\n    z_config_default(&connect_cfg);\n    zp_config_insert(z_loan_mut(connect_cfg), Z_CONFIG_CONNECT_KEY, locator);\n    zp_config_insert(z_loan_mut(connect_cfg), Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY, ca_base64);\n    zp_config_insert(z_loan_mut(connect_cfg), Z_CONFIG_TLS_VERIFY_NAME_ON_CONNECT_KEY, \"false\");\n\n    z_owned_session_t client;\n    res = z_open(&client, z_move(connect_cfg), NULL);\n    if (res != Z_OK) {\n        fprintf(stderr, \"client z_open failed: %d\\n\", res);\n        return 1;\n    }\n    (void)z_sleep_ms(50);\n\n    z_owned_publisher_t publisher;\n    z_internal_null(&publisher);\n    z_publisher_options_t pub_opts;\n    z_publisher_options_default(&pub_opts);\n#if Z_FEATURE_LOCAL_SUBSCRIBER == 1\n    pub_opts.allowed_destination = Z_LOCALITY_ANY;\n#endif\n    if (z_declare_publisher(z_loan(client), &publisher, z_loan(keyexpr), &pub_opts) != Z_OK) {\n        fprintf(stderr, \"client: failed to declare publisher\\n\");\n        goto cleanup_client;\n    }\n\n    z_owned_bytes_t payload;\n    z_internal_null(&payload);\n    if (z_bytes_copy_from_str(&payload, payload_str) != Z_OK) {\n        fprintf(stderr, \"client: failed to build payload\\n\");\n        goto cleanup_pub;\n    }\n    if (z_publisher_put(z_loan(publisher), z_move(payload), NULL) != Z_OK) {\n        fprintf(stderr, \"client: publisher put failed\\n\");\n        goto cleanup_pub;\n    }\n\n    for (int i = 0; (i < 200) && !g_received; ++i) {\n        z_sleep_ms(10);\n    }\n    if (!g_received) {\n        fprintf(stderr, \"subscriber: did not receive payload\\n\");\n    }\n\ncleanup_pub:\n    if (z_internal_check(publisher)) {\n        z_drop(z_move(publisher));\n    }\ncleanup_client:\n    if (z_internal_check(subscriber)) {\n        z_drop(z_move(subscriber));\n    }\ncleanup_server:\n    z_session_drop(z_session_move(&client));\n    z_session_drop(z_session_move(&server));\n\ncleanup_buffers:\n    if (key_base64 != NULL) {\n        free(key_base64);\n    }\n    if (cert_base64 != NULL) {\n        free(cert_base64);\n    }\n    if (ca_base64 != NULL) {\n        free(ca_base64);\n    }\n    return g_received ? 0 : 1;\n}\n\n#else\n\nint main(void) {\n    printf(\"TLS feature not enabled, skipping test\\n\");\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/z_tls_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/collections/string.h\"\n#include \"zenoh-pico/link/config/tls.h\"\n#include \"zenoh-pico/utils/config.h\"\n#include \"zenoh-pico/utils/result.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nint main(void) {\n#if Z_FEATURE_LINK_TLS == 1\n    printf(\">>> Testing TLS config parsing...\\n\");\n\n    _z_str_intmap_t config;\n    _z_str_intmap_init(&config);\n\n    z_result_t res = _z_tls_config_from_str(&config, \"root_ca_certificate=/etc/ssl/ca.pem\");\n    assert(res == _Z_RES_OK);\n    assert(_z_str_intmap_len(&config) == 1);\n\n    char *ca_cert = _z_str_intmap_get(&config, TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY);\n    assert(ca_cert != NULL);\n    assert(_z_str_eq(ca_cert, \"/etc/ssl/ca.pem\") == true);\n    _z_str_intmap_clear(&config);\n\n    _z_str_intmap_init(&config);\n    res = _z_tls_config_from_str(&config,\n                                 \"root_ca_certificate=ca.pem;enable_mtls=1;connect_private_key=client.key;\"\n                                 \"connect_certificate=client.pem;verify_name_on_connect=0;\"\n                                 \"root_ca_certificate_base64=BASE64_CA;connect_private_key_base64=BASE64_KEY;\"\n                                 \"connect_certificate_base64=BASE64_CERT\");\n    assert(res == _Z_RES_OK);\n    assert(_z_str_intmap_len(&config) == 8);\n\n    ca_cert = _z_str_intmap_get(&config, TLS_CONFIG_ROOT_CA_CERTIFICATE_KEY);\n    assert(ca_cert != NULL);\n    assert(_z_str_eq(ca_cert, \"ca.pem\") == true);\n    char *enable = _z_str_intmap_get(&config, TLS_CONFIG_ENABLE_MTLS_KEY);\n    assert(enable != NULL);\n    assert(_z_str_eq(enable, \"1\") == true);\n    char *client_key = _z_str_intmap_get(&config, TLS_CONFIG_CONNECT_PRIVATE_KEY_KEY);\n    assert(client_key != NULL);\n    assert(_z_str_eq(client_key, \"client.key\") == true);\n    char *client_cert = _z_str_intmap_get(&config, TLS_CONFIG_CONNECT_CERTIFICATE_KEY);\n    assert(client_cert != NULL);\n    assert(_z_str_eq(client_cert, \"client.pem\") == true);\n    char *verify = _z_str_intmap_get(&config, TLS_CONFIG_VERIFY_NAME_ON_CONNECT_KEY);\n    assert(verify != NULL);\n    assert(_z_str_eq(verify, \"0\") == true);\n    char *ca_base64 = _z_str_intmap_get(&config, TLS_CONFIG_ROOT_CA_CERTIFICATE_BASE64_KEY);\n    assert(ca_base64 != NULL && _z_str_eq(ca_base64, \"BASE64_CA\") == true);\n    char *client_key_inline = _z_str_intmap_get(&config, TLS_CONFIG_CONNECT_PRIVATE_KEY_BASE64_KEY);\n    assert(client_key_inline != NULL && _z_str_eq(client_key_inline, \"BASE64_KEY\") == true);\n    _z_str_intmap_clear(&config);\n\n    _z_str_intmap_init(&config);\n    res = _z_tls_config_from_str(&config, \"\");\n    assert(res == _Z_RES_OK);\n    assert(_z_str_intmap_is_empty(&config) == true);\n    _z_str_intmap_clear(&config);\n\n    _z_config_t session_cfg;\n    _z_config_init(&session_cfg);\n    assert(_zp_config_insert(&session_cfg, Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY, \"/session/ca.pem\") == _Z_RES_OK);\n    assert(_zp_config_insert(&session_cfg, Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_BASE64_KEY, \"SESSION_CA\") == _Z_RES_OK);\n    assert(_zp_config_insert(&session_cfg, Z_CONFIG_TLS_ENABLE_MTLS_KEY, \"true\") == _Z_RES_OK);\n    assert(_zp_config_insert(&session_cfg, Z_CONFIG_TLS_CONNECT_CERTIFICATE_BASE64_KEY, \"SESSION_CERT\") == _Z_RES_OK);\n    assert(_z_str_eq(_z_config_get(&session_cfg, Z_CONFIG_TLS_ROOT_CA_CERTIFICATE_KEY), \"/session/ca.pem\"));\n    assert(_z_str_eq(_z_config_get(&session_cfg, Z_CONFIG_TLS_ENABLE_MTLS_KEY), \"true\"));\n    _z_config_clear(&session_cfg);\n#else\n    printf(\"TLS feature not enabled, skipping tests\\n\");\n#endif\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_utils_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <math.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico/utils/pointers.h\"\n#include \"zenoh-pico/utils/query_params.h\"\n#include \"zenoh-pico/utils/time_range.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\nstatic void test_query_params(void) {\n#define TEST_PARAMS(str, expected, n)                                 \\\n    {                                                                 \\\n        _z_str_se_t params = _z_bstrnew(str);                         \\\n                                                                      \\\n        for (int i = 0; i <= n; i++) {                                \\\n            _z_query_param_t param = _z_query_params_next(&params);   \\\n            if (i < n) {                                              \\\n                assert(param.key.start == expected[i].key.start);     \\\n                assert(param.key.end == expected[i].key.end);         \\\n                assert(param.value.start == expected[i].value.start); \\\n                assert(param.value.end == expected[i].value.end);     \\\n            } else {                                                  \\\n                assert(param.key.start == NULL);                      \\\n                assert(param.key.end == NULL);                        \\\n                assert(param.value.start == NULL);                    \\\n                assert(param.value.end == NULL);                      \\\n            }                                                         \\\n        }                                                             \\\n        assert(params.start == NULL);                                 \\\n        assert(params.end == NULL);                                   \\\n    }\n\n    const char *params1 = \"\";\n    const _z_query_param_t *params1_expected = NULL;\n    TEST_PARAMS(params1, params1_expected, 0);\n\n    const char *params2 = \"a=1\";\n    const _z_query_param_t params2_expected[] = {{\n        .key.start = params2,\n        .key.end = _z_cptr_char_offset(params2, 1),\n        .value.start = _z_cptr_char_offset(params2, 2),\n        .value.end = _z_cptr_char_offset(params2, 3),\n    }};\n    TEST_PARAMS(params2, params2_expected, 1);\n\n    const char *params3 = \"a=1;bee=string\";\n    const _z_query_param_t params3_expected[] = {{\n                                                     .key.start = params3,\n                                                     .key.end = _z_cptr_char_offset(params3, 1),\n                                                     .value.start = _z_cptr_char_offset(params3, 2),\n                                                     .value.end = _z_cptr_char_offset(params3, 3),\n                                                 },\n                                                 {\n                                                     .key.start = _z_cptr_char_offset(params3, 4),\n                                                     .key.end = _z_cptr_char_offset(params3, 7),\n                                                     .value.start = _z_cptr_char_offset(params3, 8),\n                                                     .value.end = _z_cptr_char_offset(params3, 14),\n                                                 }};\n    TEST_PARAMS(params3, params3_expected, 2);\n\n    const char *params4 = \";\";\n    const _z_query_param_t params4_expected[] = {{\n        .key.start = NULL,\n        .key.end = NULL,\n        .value.start = NULL,\n        .value.end = NULL,\n    }};\n    TEST_PARAMS(params4, params4_expected, 1);\n\n    const char *params5 = \"a\";\n    const _z_query_param_t params5_expected[] = {{\n        .key.start = params5,\n        .key.end = _z_cptr_char_offset(params5, 1),\n        .value.start = NULL,\n        .value.end = NULL,\n    }};\n    TEST_PARAMS(params5, params5_expected, 1);\n\n    const char *params6 = \"a=\";\n    const _z_query_param_t params6_expected[] = {{\n        .key.start = params6,\n        .key.end = _z_cptr_char_offset(params6, 1),\n        .value.start = NULL,\n        .value.end = NULL,\n    }};\n    TEST_PARAMS(params6, params6_expected, 1);\n}\n\nstatic bool compare_double_result(const double expected, const double result) {\n    static const double EPSILON = 1e-6;\n    return fabs(result - expected) < EPSILON;\n}\n\nstatic bool compare_time_range(const _z_time_range_t *a, const _z_time_range_t *b) {\n    return a->start.bound == b->start.bound && compare_double_result(a->start.now_offset, b->start.now_offset) &&\n           a->end.bound == b->end.bound && compare_double_result(a->end.now_offset, b->end.now_offset);\n}\n\nstatic void test_time_range_roundtrip(const char *input) {\n    _z_time_range_t parsed1 = {0}, parsed2 = {0};\n    char buf[128];\n\n    // SAFETY: input should be a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(input, strlen(input), &parsed1));\n    assert(_z_time_range_to_str(&parsed1, buf, sizeof(buf)));\n    // SAFETY: _z_time_range_to_str() creates a null-terminated string if successful.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(buf, strlen(buf), &parsed2));\n\n    printf(\"Round-trip: input='%s' → output='%s'\\n\", input, buf);\n\n    assert(compare_time_range(&parsed1, &parsed2));\n}\n\nstatic void test_time_range(void) {\n    _z_time_range_t result;\n    const char *range = \"\";\n\n    // Range tests\n    range = \"[..]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_UNBOUNDED);\n    assert(result.end.bound == _Z_TIME_BOUND_UNBOUNDED);\n    test_time_range_roundtrip(range);\n\n    range = \"[now()..now(5)]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(5.0, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now(-999.9u)..now(100.5ms)]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(-0.0009999, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.1005, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"]now(-87.6s)..now(1.5m)[\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_EXCLUSIVE);\n    assert(compare_double_result(-87.6, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_EXCLUSIVE);\n    assert(compare_double_result(90.0, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now(-24.5h)..now(6.75d)]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(-88200.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(583200.0, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now(-1.75w)..now()]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(-1058400.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    // Duration tests\n    range = \"[now();7.3]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(7.3, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();97.4u]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0000974, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();568.4ms]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.5684, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();9.4s]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(9.4, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();6.89m]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(413.4, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();1.567h]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(5641.2, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();2.7894d]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(241004.16, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    range = \"[now();5.9457w]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == true);\n    assert(result.start.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(0.0, result.start.now_offset));\n    assert(result.end.bound == _Z_TIME_BOUND_INCLUSIVE);\n    assert(compare_double_result(3595959.36, result.end.now_offset));\n    test_time_range_roundtrip(range);\n\n    // Error cases\n    range = \"\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == false);\n\n    range = \"[;]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == false);\n\n    range = \"[now();]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == false);\n\n    range = \"[now()..5.6]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == false);\n\n    range = \"[now();s]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == false);\n\n    range = \"[now();one]\";\n    // SAFETY: range is a null-terminated string.\n    // Flawfinder: ignore [CWE-126]\n    assert(_z_time_range_from_str(range, strlen(range), &result) == false);\n}\n\n#define STUB_SECS 1000u /*   16-Aug-1970 02:46:40 UTC in Unix time  */\n#define STUB_NANOS 0u\n\nstatic void test_time_range_contains_null_pointer(void) {\n    _z_ntp64_t t = _z_timestamp_ntp64_from_time(STUB_SECS, STUB_NANOS);\n    assert(_z_time_range_contains_at_time(NULL, 12345u, t) == false);\n}\n\nstatic void test_time_range_contains_unbounded_range(void) {\n    _z_time_range_t r = {.start = {.bound = _Z_TIME_BOUND_UNBOUNDED, .now_offset = 0},\n                         .end = {.bound = _Z_TIME_BOUND_UNBOUNDED, .now_offset = 0}};\n\n    _z_ntp64_t now = _z_timestamp_ntp64_from_time(STUB_SECS, STUB_NANOS);\n    _z_ntp64_t before = now - 42;\n    _z_ntp64_t after = now + 42;\n\n    assert(_z_time_range_contains_at_time(&r, before, now) == true);\n    assert(_z_time_range_contains_at_time(&r, now, now) == true);\n    assert(_z_time_range_contains_at_time(&r, after, now) == true);\n}\n\nstatic void test_time_range_contains_lower_bound_inclusive_exclusive(void) {\n    _z_time_range_t r = {.start = {.now_offset = 0}, .end = {.bound = _Z_TIME_BOUND_UNBOUNDED, .now_offset = 0}};\n\n    _z_ntp64_t now = _z_timestamp_ntp64_from_time(STUB_SECS, STUB_NANOS);\n    _z_ntp64_t before = now - 1;\n    _z_ntp64_t after = now + 1;\n\n    // Inclusive  [now .. +∞)\n    r.start.bound = _Z_TIME_BOUND_INCLUSIVE;\n    assert(_z_time_range_contains_at_time(&r, now, now) == true);\n    assert(_z_time_range_contains_at_time(&r, before, now) == false);\n    assert(_z_time_range_contains_at_time(&r, after, now) == true);\n\n    // Exclusive  ]now .. +∞)\n    r.start.bound = _Z_TIME_BOUND_EXCLUSIVE;\n    assert(_z_time_range_contains_at_time(&r, now, now) == false);\n    assert(_z_time_range_contains_at_time(&r, before, now) == false);\n    assert(_z_time_range_contains_at_time(&r, after, now) == true);\n}\n\nstatic void test_time_range_contains_upper_bound_inclusive_exclusive(void) {\n    _z_time_range_t r = {.start = {.bound = _Z_TIME_BOUND_UNBOUNDED, .now_offset = 0}, .end = {.now_offset = 0}};\n\n    _z_ntp64_t now = _z_timestamp_ntp64_from_time(STUB_SECS, STUB_NANOS);\n    _z_ntp64_t before = now - 1;\n    _z_ntp64_t after = now + 1;\n\n    // Inclusive  (-∞ .. now]\n    r.end.bound = _Z_TIME_BOUND_INCLUSIVE;\n    assert(_z_time_range_contains_at_time(&r, before, now) == true);\n    assert(_z_time_range_contains_at_time(&r, now, now) == true);\n    assert(_z_time_range_contains_at_time(&r, after, now) == false);\n\n    // Exclusive  (-∞ .. now[\n    r.end.bound = _Z_TIME_BOUND_EXCLUSIVE;\n    assert(_z_time_range_contains_at_time(&r, before, now) == true);\n    assert(_z_time_range_contains_at_time(&r, now, now) == false);\n    assert(_z_time_range_contains_at_time(&r, after, now) == false);\n}\n\nstatic void test_time_range_contains_fully_bounded_mixed(void) {\n    // [now-5  ..  now+5[   (inclusive start, exclusive end)\n    _z_time_range_t r = {.start = {.bound = _Z_TIME_BOUND_INCLUSIVE, .now_offset = -5},\n                         .end = {.bound = _Z_TIME_BOUND_EXCLUSIVE, .now_offset = 5}};\n\n    _z_ntp64_t now = _z_timestamp_ntp64_from_time(STUB_SECS, STUB_NANOS);\n\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, -6.0), now) == false);\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, -5.0), now) == true);  // Inclusive\n    assert(_z_time_range_contains_at_time(&r, now, now) == true);\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, 4.0), now) == true);\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, 5.0), now) == false);  // Exclusive\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, 6.0), now) == false);\n\n    // Swap bound types\n    r.start.bound = _Z_TIME_BOUND_EXCLUSIVE;\n    r.end.bound = _Z_TIME_BOUND_INCLUSIVE;\n\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, -6.0), now) == false);\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, -5.0), now) == false);  // Exclusive\n    assert(_z_time_range_contains_at_time(&r, now, now) == true);\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, 4.0), now) == true);\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, 5.0), now) == true);  // Inclusive\n    assert(_z_time_range_contains_at_time(&r, _z_time_range_resolve_offset(now, 6.0), now) == false);\n}\n\nint main(void) {\n    test_query_params();\n    test_time_range();\n    test_time_range_contains_null_pointer();\n    test_time_range_contains_unbounded_range();\n    test_time_range_contains_lower_bound_inclusive_exclusive();\n    test_time_range_contains_upper_bound_inclusive_exclusive();\n    test_time_range_contains_fully_bounded_mixed();\n    return 0;\n}\n"
  },
  {
    "path": "tests/z_wildcard_subscription_test.c",
    "content": "//\n// Copyright (c) 2025 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n\n//\n// Copyright (c) 2022 ZettaScale Technology\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n\n#include <assert.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zenoh-pico.h\"\n#include \"zenoh-pico/api/types.h\"\n#include \"zenoh-pico/collections/string.h\"\n\n#undef NDEBUG\n#include <assert.h>\n\n#define MSGS 10\n#define SLEEP 1\n#define TIMEOUT 15\n\nstatic const char *PUB_KE = \"test/wildcard\";\nstatic const char *SUB1_KE = \"*/wildcard\";\nstatic const char *SUB2_KE = \"**/wildcard\";\n\nvolatile unsigned int sub1_count = 0;\nvolatile unsigned int sub2_count = 0;\n\nstatic void sub_handler_1(z_loaned_sample_t *sample, void *arg) {\n    (void)arg;\n    z_owned_slice_t value;\n    z_bytes_to_slice(z_sample_payload(sample), &value);\n\n    // Both subscribers should see key \"test/wildcard\"\n    z_view_string_t k;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &k);\n    // Flawfinder: ignore [CWE-126]\n    assert(strncmp(z_string_data(z_loan(k)), PUB_KE, strlen(PUB_KE)) == 0);\n\n    sub1_count++;\n    z_drop(z_move(value));\n}\n\nstatic void sub_handler_2(z_loaned_sample_t *sample, void *arg) {\n    (void)arg;\n    z_owned_slice_t value;\n    z_bytes_to_slice(z_sample_payload(sample), &value);\n\n    z_view_string_t k;\n    z_keyexpr_as_view_string(z_sample_keyexpr(sample), &k);\n    // Flawfinder: ignore [CWE-126]\n    assert(strncmp(z_string_data(z_loan(k)), PUB_KE, strlen(PUB_KE)) == 0);\n\n    sub2_count++;\n    z_drop(z_move(value));\n}\n\nint main(int argc, char **argv) {\n    assert(argc == 2);\n\n    // --- Session 1: publisher ---\n    z_owned_config_t cfg1;\n    z_config_default(&cfg1);\n    zp_config_insert(z_loan_mut(cfg1), Z_CONFIG_CONNECT_KEY, argv[1]);\n\n    z_owned_session_t s_pub;\n    assert(z_open(&s_pub, z_move(cfg1), NULL) == Z_OK);\n    printf(\"Publisher session opened\\n\");\n    fflush(stdout);\n\n    // --- Session 2: subscribers ---\n    z_owned_config_t cfg2;\n    z_config_default(&cfg2);\n    zp_config_insert(z_loan_mut(cfg2), Z_CONFIG_CONNECT_KEY, argv[1]);\n\n    z_owned_session_t s_sub;\n    assert(z_open(&s_sub, z_move(cfg2), NULL) == Z_OK);\n    printf(\"Subscriber session opened\\n\");\n\n    z_sleep_s(SLEEP);\n\n    // Declare publisher keyexpr\n    z_view_keyexpr_t pub_ke;\n    assert(z_view_keyexpr_from_str(&pub_ke, PUB_KE) == Z_OK);\n\n    // Declare publisher\n    z_owned_publisher_t pub;\n    assert(z_declare_publisher(z_loan(s_pub), &pub, z_loan(pub_ke), NULL) == Z_OK);\n    printf(\"Declared publisher entity id=%zu\\n\", z_loan(pub)->_id);\n    fflush(stdout);\n\n    // Declare subscribers on separate session\n    z_view_keyexpr_t sub1_ke, sub2_ke;\n    assert(z_view_keyexpr_from_str(&sub1_ke, SUB1_KE) == Z_OK);\n    assert(z_view_keyexpr_from_str(&sub2_ke, SUB2_KE) == Z_OK);\n\n    z_owned_closure_sample_t c1, c2;\n    z_closure(&c1, sub_handler_1, NULL, NULL);\n    z_closure(&c2, sub_handler_2, NULL, NULL);\n\n    z_owned_subscriber_t sub1, sub2;\n    assert(z_declare_subscriber(z_loan(s_sub), &sub1, z_loan(sub1_ke), z_move(c1), NULL) == Z_OK);\n    printf(\"Declared subscriber on '%s'\\n\", SUB1_KE);\n    fflush(stdout);\n    assert(z_declare_subscriber(z_loan(s_sub), &sub2, z_loan(sub2_ke), z_move(c2), NULL) == Z_OK);\n    printf(\"Declared subscriber on '%s'\\n\", SUB2_KE);\n    fflush(stdout);\n\n    z_sleep_s(SLEEP);\n\n    // Publish messages\n    for (unsigned int i = 0; i < MSGS; i++) {\n        char buf[64];\n        int n = snprintf(buf, sizeof(buf), \"hello-%u\", i);\n\n        z_put_options_t opt;\n        z_put_options_default(&opt);\n        opt.congestion_control = Z_CONGESTION_CONTROL_BLOCK;\n\n        z_owned_bytes_t payload;\n        z_bytes_from_buf(&payload, (uint8_t *)buf, (size_t)n, NULL, NULL);\n\n        assert(z_put(z_loan(s_pub), z_loan(pub_ke), z_move(payload), &opt) == Z_OK);\n        printf(\"Published %s to %s\\n\", buf, PUB_KE);\n        fflush(stdout);\n    }\n\n    // Wait for both subscribers to receive all messages\n    z_clock_t start = z_clock_now();\n    while ((sub1_count < MSGS || sub2_count < MSGS) && z_clock_elapsed_s(&start) < TIMEOUT) {\n        printf(\"Waiting... sub1=%u/%u sub2=%u/%u\\n\", sub1_count, MSGS, sub2_count, MSGS);\n        fflush(stdout);\n        z_sleep_s(SLEEP);\n    }\n\n    printf(\"Final counts: sub1=%u, sub2=%u\\n\", sub1_count, sub2_count);\n    fflush(stdout);\n    assert(sub1_count == MSGS);\n    assert(sub2_count == MSGS);\n\n    // Cleanup: undeclare\n    z_drop(z_move(sub1));\n    z_drop(z_move(sub2));\n    z_drop(z_move(pub));\n    z_drop(z_move(s_pub));\n    z_drop(z_move(s_sub));\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/z_keyexpr_canonizer.c",
    "content": "//\n// Copyright (c) 2022 ZettaScale Technology\n//\n// This program and the accompanying materials are made available under the\n// terms of the Eclipse Public License 2.0 which is available at\n// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n// which is available at https://www.apache.org/licenses/LICENSE-2.0.\n//\n// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n//\n// Contributors:\n//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>\n//\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <zenoh-pico.h>\n\nint main(int argc, char **argv) {\n    if (argc < 2) {\n        printf(\"USAGE: ./z_keyexpr_canonizer <keyexpr_1> [keyexpr_2 .. keyexpr_N]\\n\");\n        printf(\"  Arguments:\\n\");\n        printf(\"    - Pass any number of key expressions as arguments to obtain their canon forms\");\n        return -1;\n    }\n\n    char *buffer = NULL;\n    for (int i = 1; i < argc; i++) {\n        size_t len = strlen(argv[i]);\n        buffer = realloc(buffer, len + 1);\n        strncpy(buffer, argv[i], len);\n        buffer[len] = '\\0';\n        zp_keyexpr_canon_status_t status = z_keyexpr_canonize(buffer, &len);\n\n        switch (status) {\n            case Z_KEYEXPR_CANON_SUCCESS:\n                printf(\"canon(%s) => %s\\r\\n\", argv[i], buffer);\n                break;\n\n            case Z_KEYEXPR_CANON_EMPTY_CHUNK:\n                printf(\n                    \"canon(%s) => Couldn't canonize `%s` because empty chunks are forbidden (as well as leading and \"\n                    \"trailing slashes)\\r\\n\",\n                    argv[i], argv[i]);\n                break;\n\n            case Z_KEYEXPR_CANON_STARS_IN_CHUNK:\n                printf(\n                    \"canon(%s) => Couldn't canonize `%s` because `*` is only legal when surrounded by `/` or preceded \"\n                    \"by `$`\\r\\n\",\n                    argv[i], argv[i]);\n                break;\n\n            case Z_KEYEXPR_CANON_DOLLAR_AFTER_DOLLAR_OR_STAR:\n                printf(\"Ccanon(%s) => ouldn't canonize `%s` because `*$` and `$$` are illegal patterns\\r\\n\", argv[i],\n                       argv[i]);\n                break;\n\n            case Z_KEYEXPR_CANON_CONTAINS_SHARP_OR_QMARK:\n                printf(\"canon(%s) => Couldn't canonize `%s` because `#` and `?` are illegal characters\\r\\n\", argv[i],\n                       argv[i]);\n                break;\n\n            case Z_KEYEXPR_CANON_CONTAINS_UNBOUND_DOLLAR:\n                printf(\"canon(%s) => Couldn't canonize `%s` because `$` may only be followed by `*`\\r\\n\", argv[i],\n                       argv[i]);\n                break;\n\n            default:\n                assert(false);\n                break;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "version.txt",
    "content": "1.9.0"
  },
  {
    "path": "zenohpico.pc.in",
    "content": "prefix=@CMAKE_INSTALL_PREFIX@\n\nName: @PROJECT_NAME@\nDescription: @CMAKE_PROJECT_DESCRIPTION@\nURL: @CMAKE_PROJECT_HOMEPAGE_URL@\nVersion: @PROJECT_VERSION@\nCflags: -I${prefix}/@CMAKE_INSTALL_INCLUDEDIR@\nLibs: -L${prefix}/@CMAKE_INSTALL_LIBDIR@ -lzenohpico@LIBNAME_POSTFIX@"
  },
  {
    "path": "zephyr/CMakeLists.txt",
    "content": "if(CONFIG_ZENOH_PICO)\n\nzephyr_compile_definitions(ZENOH_ZEPHYR)\nzephyr_include_directories(../include)\nzephyr_library()\n\nfunction(configure_zenoh_feature config)\n  string(REPLACE CONFIG_ZENOH_PICO Z_FEATURE feature ${config})\n  if(${config})\n    zephyr_compile_definitions(${feature}=1)\n  else()\n    zephyr_compile_definitions(${feature}=0)\n  endif()\nendfunction()\n\n\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_LINK_SERIAL)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_MULTI_THREAD)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_PUBLICATION)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_SUBSCRIPTION)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_QUERY)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_QUERYABLE)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_RAWETH_TRANSPORT)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_LINK_TCP)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_LINK_UDP_UNICAST)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_LINK_UDP_MULTICAST)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_SCOUTING)\nconfigure_zenoh_feature(CONFIG_ZENOH_PICO_LINK_WS)\n\n\nfile(GLOB_RECURSE Sources\n  \"../src/api/*.c\"\n  \"../src/collections/*.c\"\n  \"../src/link/*.c\"\n  \"../src/net/*.c\"\n  \"../src/protocol/*.c\"\n  \"../src/session/*.c\"\n  \"../src/transport/*.c\"\n  \"../src/utils/*.c\"\n  \"../src/system/common/*.c\"\n)\n\nfile (GLOB Sources_Zephyr \"../src/system/zephyr/*.c\")\nlist(APPEND Sources ${Sources_Zephyr})\nzephyr_library_sources(${Sources})\nendif()\n"
  },
  {
    "path": "zephyr/Kconfig.zenoh",
    "content": "config ZENOH_PICO\n\tbool \"Zenoh PICO library\"\n\thelp\n\t  Enable Zenoh pico support\n\nif ZENOH_PICO\n\nconfig ZENOH_PICO_LINK_SERIAL\n\tbool \"Serial Link\"\n\thelp\n\t  Use serial link\n\nconfig ZENOH_PICO_MULTI_THREAD\n\tbool \"Multithreading support\"\n\thelp\n\t  Multithreading support\n\nconfig ZENOH_PICO_PUBLICATION\n\tbool \"Publication Support\"\n\thelp\n\t  Publication support\n\nconfig ZENOH_PICO_SUBSCRIPTION\n\tbool \"Subscription Support\"\n\thelp\n\t  Subscription Support\n\nconfig ZENOH_PICO_QUERY\n\tbool \"Query Support\"\n\thelp\n\t  Query Support\n\nconfig ZENOH_PICO_QUERYABLE\n\tbool \"Queryable Support\"\n\thelp\n\t  Queryable Support\n\nconfig ZENOH_PICO_RAWETH_TRANSPORT\n\tbool \"Raw Ethernet Support\"\n\thelp\n\t  Raw Ethernet Support\n\nconfig ZENOH_PICO_LINK_TCP\n\tbool \"TCP Link\"\n\thelp\n\t  TCP Link\n\nconfig ZENOH_PICO_LINK_UDP_UNICAST\n\tbool \"UDP Unicast\"\n\thelp\n\t  UDP Unicast\n\nconfig ZENOH_PICO_LINK_UDP_MULTICAST\n\tbool \"UDP Multicast\"\n\thelp\n\t  UDP Multicast\n\nconfig ZENOH_PICO_SCOUTING\n\tbool \"Scouting UDP\"\n\thelp\n\t  Scouting UDP\n\nconfig ZENOH_PICO_LINK_WS\n\tbool \"WS Link\"\n\thelp\n\t  WS Link\n\nendif\n\n"
  },
  {
    "path": "zephyr/module.yml",
    "content": "name: zenoh-pico\nbuild:\n  cmake: zephyr/\n  kconfig: zephyr/Kconfig.zenoh\n"
  }
]